<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7061894606829532334</id><updated>2011-11-27T16:52:09.386-08:00</updated><category term='eclipse aptana eclipsemonkey'/><category term='weblogic python jython wlst getopt cygwin'/><category term='java jar bash xpath cygwin'/><category term='java xpath xml'/><category term='java stringbuilder bytecode'/><title type='text'>David M. Karr's Blog</title><subtitle type='html'>I specialize in Java, JEE, WebLogic, web services, and Unix, with an ongoing interest in JavaScript and Ajax technologies.  I wrote the Struts-EL tag library, and I run the Seattle-area WebLogic User's Group.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://davidmichaelkarr.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://davidmichaelkarr.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>David Karr</name><uri>http://www.blogger.com/profile/17575148038635091341</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://3.bp.blogspot.com/_5xGV5soeRRE/SUV9OBbfxgI/AAAAAAAAAAM/9gAJOYaYXMg/S220/IMG_0139001web.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>9</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7061894606829532334.post-5264306004437825545</id><published>2010-10-09T12:38:00.000-07:00</published><updated>2010-10-14T10:18:50.355-07:00</updated><title type='text'>Keyboard Nirvana with Eclipse and Emacs+</title><content type='html'>&lt;h2&gt;Introduction&lt;/h2&gt;&lt;br /&gt;Before I say anything else, let me make one thing perfectly clear: You do not need to know anything about Emacs to get maximum value from the &lt;a href="http://www.mulgasoft.com/emacsplus"&gt;Emacs+&lt;/a&gt; plugin. You don’t have to be an Emacs user and you don’t have to know anything about Lisp. The Emacs+ plugin simply provides numerous functions that are very similar to their Emacs origins and that are very applicable to the Eclipse environment. To use them, you just execute the functions. Hopefully this will alleviate your fear that you’ll have to be an Emacs expert to make use of this.&lt;br /&gt;&lt;br /&gt;Now that that’s out of the way, some other issues we need to talk about are how to make your keyboard usage in Eclipse more efficient, whether you use Emacs+ or  not.&lt;br /&gt;&lt;br /&gt;One of those first steps is understanding and accepting that Eclipse lets you bind arbitrary key sequences to Eclipse functions. You’ll want to determine for yourself what are convenient key bindings, and which functions you want to be easier to get to, compared to others. I’ll go over this in more detail.&lt;br /&gt;&lt;br /&gt;If you accept that, you’ll probably come to the conclusion that you’ll be using the Control key a lot. An advanced corollary of that is that it’s perfectly reasonable to rearrange your keyboard keys so that it’s more convenient. I’m not suggesting that you use a Dvorak layout (if you do, you probably already have maximally optimized your environment), but there is a single simple change that will make your keyboard usage more convenient: getting rid of the useless CapsLock key and making it an additional Control key. I’ll talk more about this and cover a tool or two that helps with this.&lt;br /&gt;&lt;br /&gt;Once we have these foundational elements in place, we can talk about the Emacs+ Eclipse plugin, and then I’ll talk about a recent set of features in Emacs+ that allow you to record key sequences and store them as keyboard macros that you can then also bind to keys. I’ll close with an example of a keyboard macro that you might find useful.&lt;br /&gt;&lt;h2&gt;Binding key sequences to functions&lt;/h2&gt;&lt;br /&gt;If you go to the “General”-&gt;“Keys” section of the Eclipse preferences, you’ll see the page where you can view and change key bindings.  If you click on the “Binding” header and then scroll (way) down to the first command that has a non-empty binding, you’ll initially see commands that have “simple” bindings, like the first one that I see, which is “Alt+-” (alt-dash), which in my Eclipse is bound to “Show System Menu”.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_5xGV5soeRRE/TLD2MJfSKtI/AAAAAAAAAB8/u2pQTmFiORI/s1600/KeysPrefs.bmp"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 400px; height: 154px;" src="http://1.bp.blogspot.com/_5xGV5soeRRE/TLD2MJfSKtI/AAAAAAAAAB8/u2pQTmFiORI/s400/KeysPrefs.bmp" alt="" id="BLOGGER_PHOTO_ID_5526187431349594834" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;If you scroll further down, you might see the various “Debug” commands, like “Debug Java Application”, which is bound to “Alt+Shift+D, J”. This is essentially a two character sequence. The first character is “Alt+Shift+D” (pressing “d” while holding down “Alt” and “Shift”) and the second character is just “j”. There are several other multiple character bindings that begin with “Alt+Shift+D”. This works because there is no binding for the single character “Alt+Shift+D”. A character (or sequence of characters) that is used to begin a binding cannot itself be bound to a command.&lt;br /&gt;&lt;br /&gt;The other benefit of sorting this list by “Binding” is that you can see some “gaps” that show some character sequences that are not bound to commands. For instance, starting near the top of the non-empty bindings, I see that “Alt+A” is bound to “Terminal view insert” and “Alt+C” is bound to “Copy”, but there is no binding for “Alt+B”. That means you could bind a command to “Alt+B” without disturbing any other bindings.&lt;br /&gt;&lt;br /&gt;Also note the "When" column.  This specifies the editor or context that the binding is applicable to.  For instance, I mentioned that I have "Alt+C" bound to "Copy", but I also have the same key bound to "Execute Selected Text As One Statement".  The difference is that the former's "When" value is "In Windows", and the latter's is "Editing SQL".  So if you're in the SQL editor view, then Alt+C does one thing, but it executes "Copy" anywhere else.  If you define new bindings here, you'll probably want to set "When" to "In Windows", but you might find special cases where you'll want a different value here.&lt;br /&gt;&lt;br /&gt;You’ll want to spend a lot of time browsing through this list, sorting by “Binding” to find prefix keys and sequences that you think will be convenient for your custom bindings. My favorite key that begins several of my custom bindings is “Ctrl+;” (Control-semicolon). I don’t bind a command to that key, I use it as the first character in several two and three character sequences.&lt;br /&gt;&lt;br /&gt;Once you start binding commands that begin with a particular character, there is another convenient feature you can use that will remind you of the bindings you have that begin with that key. If you exit the Preferences dialog and then just press that key and wait a moment, you’ll see a popup dialog that shows the bindings that begin with that key. For instance, if you press “Alt+Shift+D” and wait a moment, you’ll see the popup that shows the binding for “Debug Java Application” and other related commands.&lt;br /&gt;&lt;h2&gt;Ctrl2Cap&lt;/h2&gt;&lt;br /&gt;Before I get into Emacs+, let’s first fix your keyboard to make extended use of the Control key more efficient and less painful.&lt;br /&gt;&lt;br /&gt;Let me illustrate the issue with a picture:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_5xGV5soeRRE/TLDK-dnBpUI/AAAAAAAAABc/PxkBnnwAdaE/s1600/function-key.jpg"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 275px; height: 183px;" src="http://1.bp.blogspot.com/_5xGV5soeRRE/TLDK-dnBpUI/AAAAAAAAABc/PxkBnnwAdaE/s320/function-key.jpg" alt="" id="BLOGGER_PHOTO_ID_5526139917232612674" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you have to press the Control key a zillion times a day, and this is your keyboard, how long will it take before your pinky falls off?&lt;br /&gt;Here’s a related question: How many times have you actually USED the CapsLock key?  Have you ever used it? Would you miss it if you didn’t have it anymore? If you never use it, why do you let it take up space on your keyboard?  Get rid of it!&lt;br /&gt;&lt;br /&gt;On my Ubuntu box, this ability is built into the interface, as I can change the “Ctrl key position” setting in my Preferences to “Make CapsLock an additional Ctrl”. There, it’s done.  No more CapsLock key.&lt;br /&gt;&lt;br /&gt;It's also very easy to do this on the Mac, just by adjusting the &lt;i&gt;Modifier Keys&lt;/i&gt; in the &lt;i&gt;Keyboard&lt;/i&gt; section of &lt;b&gt;System Preferences&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;On Windows it’s a tiny bit more difficult to do this. It’s not built into the default interface. Fortunately, there is a web site called &lt;a href="http://technet.microsoft.com/en-us/sysinternals/default.aspx"&gt;SysInternals&lt;/a&gt; (founded by Mark Russinovich and others) that provides a free tool that makes this easy to do. The utility is called &lt;a href="http://technet.microsoft.com/en-us/sysinternals/bb897578.aspx"&gt;Ctrl2Cap&lt;/a&gt;. It’s a very small utility. You download it and install it and restart, and now your CapsLock key is a Control key.&lt;br /&gt;&lt;br /&gt;By the way, there are numerous other Windows-based utilities and tools on the SysInternals site that you would probably find useful. I spend time exploring there from time to time. I use several of their tools every day.&lt;br /&gt;&lt;h2&gt;Emacs+&lt;/h2&gt;&lt;br /&gt;We now understand how to make our keyboard usage in Eclipse more efficient by binding key sequences to functions, and making those key sequences easier to type. Now let’s learn about the Emacs+ plugin, that provides many functions that you’ll want to bind to keys.&lt;br /&gt;&lt;br /&gt;The Emacs+ Eclipse plugin, written by Mark Feber, is one of the more popular plugins available on the Eclipse Marketplace.&lt;br /&gt;&lt;br /&gt;Here’s a short summary of Emacs+ taken from the first page of the Emacs+ documentation:&lt;br /&gt;&lt;br /&gt;“Emacs+ is designed to provide a more Emacs-like experience in the Eclipse text editors.  Included are enhancements for keyboard driven command execution and keyboard macros, Ctrl-u, keyboard text selection, Emacs style search and query/replace, a kill ring for deleted text, balanced expressions (s-expressions), keyboard driven editor window splitting, transpositions, case conversion commands and append line-comments in the Java editor.  In cases where the normal Emacs binding interferes with an Eclipse binding, the Emacs binding is preferred. “&lt;br /&gt;&lt;br /&gt;Note that the plugin is really in multiple parts. There is a “core” plugin, and then there is the “optional bindings” plugin. The latter is only useful if you set the "Scheme" setting in your "Keys" preferences to "Emacs+ Scheme" (referred to as "the Emacs binding"). You can install just the “core” plugin and not install the “optional bindings” plugin if you don't use the "Emacs+ Scheme".&lt;br /&gt;&lt;br /&gt;Also, if you're on the Mac, there is an additional plugin(s) that deals with the COMMAND key, if you're using the Emacs binding scheme.&lt;br /&gt;&lt;br /&gt;Just so it's clear, if you don't use the "Emacs+ scheme", you only need the "core" plugin.&lt;br /&gt;&lt;br /&gt;It’s helpful to read through the entire set of Emacs+ documentation to get a feel for what features it provides, and how to use them.&lt;br /&gt;&lt;br /&gt;One tidbit that I’ll mention: The “query-replace-regexp” Emacs+ function does something that the normal query/replace functionality in Eclipse doesn’t provide, which I’ll call “intelligent case replacement”.&lt;br /&gt;&lt;br /&gt;This function takes two regular expressions, for the “source” string and “replacement” string. This is normal so far. What’s different is that it will look at the actual pattern of characters in a particular occurrence of the “source” string and match the case of that occurrence into the replacement string.&lt;br /&gt;&lt;br /&gt;What does that mean? Let’s say that you ask to replace “foo” with “doSomething”. You start with a block like this:&lt;br /&gt;&lt;blockquote&gt;       getfoo&lt;br /&gt;      getFoo&lt;br /&gt;      FOO&lt;/blockquote&gt;&lt;br /&gt;When this replacement completes, you’ll have this:&lt;br /&gt;&lt;blockquote&gt;       getdoSomething&lt;br /&gt;      getDoSomething&lt;br /&gt;      DOSOMETHING&lt;/blockquote&gt;&lt;br /&gt;Is that something that would be useful to you?&lt;br /&gt;&lt;h3&gt;Emacs bindings or Eclipse bindings?&lt;/h3&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_5xGV5soeRRE/TLD4XN4jtII/AAAAAAAAACE/V3raTHtkbjY/s1600/RichardStallmanAtLaptop.jpg"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 244px; height: 206px;" src="http://2.bp.blogspot.com/_5xGV5soeRRE/TLD4XN4jtII/AAAAAAAAACE/V3raTHtkbjY/s320/RichardStallmanAtLaptop.jpg" alt="Richard Stallman at laptop" id="BLOGGER_PHOTO_ID_5526189820531160194" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I’ve personally been using various versions of Emacs for about 25 years (not quite as long as him).  I’ve been using Eclipse for about 5 of those years. When I’m using Emacs, I have a very effective set of bindings that I use to do the things I need to do. When I first installed the Emacs+ plugin, it was very easy for me to decide whether to install the “bindings” plugin. In fact, I did not. I prefer to work with the already defined conventions for Eclipse key bindings, and then add my own bindings that don’t conflict with those bindings.  I urge you to make your own conscious decision about this. If you decide to use your own bindings, keep that in mind while reading the Emacs+ documentation. Much of it refers to the default Emacs+ key bindings, which may differ from what you end up using.&lt;br /&gt;&lt;h3&gt;Keyboard Macros&lt;/h3&gt;&lt;br /&gt;Although I use many functions from Emacs+, one set of functionality that really provides a lot of promise is “keyboard macros”. In short, this gives me the ability to go into a mode where it starts to record keypresses (just keys, not mouse movement), press some keys, then “stop” recording. At that point, I have a keyboard macro that I can reexecute. More importantly, I can also give that macro a name, just like any other command name, and then I can bind a key sequence to that named macro. Even better, I can also save that macro to a file, and I can tell Eclipse to load that saved macro (or all of my saved macros) at startup.&lt;br /&gt;&lt;h3&gt;Setting up goto-next-search-occurrence&lt;/h3&gt;&lt;br /&gt;Now that we have all of these features in place, let’s go over an example of a useful keyboard macro, and how to define it and use it.&lt;br /&gt;&lt;br /&gt;I’m sure you use the “Search” view a great deal. You’re in the editor view and you either run a specific hand-entered search, or you search for references to the current function, or other possibilities. As soon as you run the search, the focus moves from the Editor view to the Search view. At this point, you could press “Ctrl+.” (control-period) to move to the first occurrence. When you do that, it changes the Editor view, but your focus is still in the Search view. If you have to get back to the Editor view at this point, you either use the mouse or you press the “f12” key, which is typically bound to “activate-editor”, which moves the focus to the Editor view.&lt;br /&gt;&lt;br /&gt;Now what do you do if you want to go to the next search occurrence?  You have to go BACK to the Search view and press “Ctrl+.” again.  This will go on and on.&lt;br /&gt;&lt;br /&gt;Wouldn’t it be better if you could press a key that would go to the next search occurrence, but leave you in the Editor view? Let’s see how we would do this.&lt;br /&gt;&lt;br /&gt;Before you define a keyboard macro for a sequence of operations, you need to make sure that you can actually execute all the operations in the sequence with just keypresses. Anything that requires a mouse operation can’t be recorded.&lt;br /&gt;&lt;br /&gt;In this case, there are really three operations. The first is putting the focus in the search view. The second is going to the next search occurrence. The third is putting the focus in the editor view. I already described the last two steps (“Ctrl+.” and “f12”). The first step is provided by the “Show View (View: Search)” command, which you can see in the “Keys” list in Preferences. In my environment, I’ve bound this command to “Ctrl+;, Ctrl+S”. This is “Control-semicolon” followed by “Control-s”. I can verify I can execute the entire sequence just by pressing these keys in order (“Ctrl+;, Ctrl+S”, then “Ctrl+.”, then “f12”).&lt;br /&gt;&lt;br /&gt;Now let’s record the keyboard macro. In my environment, I bound “kbd-macro-start” and “kbd-macro-end” to “Ctrl+[“ and “Ctrl+]” respectively. I thought those bindings were appropriate. So, while in the editor view I press “Ctrl+[“. It says “Start Kbd Macro” in the status line. I then press the key sequence I described in the previous paragraph. I then press “Ctrl+]” and it says “Kbd Macro defined” in the status line.&lt;br /&gt;&lt;br /&gt;Now I have a macro, but it doesn’t have a name. Let’s give it a name with the “name-last-kbd-macro” command. This is one command that I haven’t bound to any key at all. I don’t use it enough for that to be worthwhile for me. Fortunately, Emacs+ provides a way to directly execute commands without key bindings. This is done with the “execute-extended-command” command, which I have bound to “Alt+x” (just about the only command I’ve bound that has the same binding in Emacs+ as in my Emacs environment). Obviously, this is one command that you definitely have to have bound to a key if you want to execute it. After pressing “Alt+x”, I enter “name-last-kbd-macro” (actually, I just enter “nam” and press TAB, which completes it to “name-last-kbd-macro”, using another feature from Emacs, command completion).&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_5xGV5soeRRE/TLD50CwhZaI/AAAAAAAAACM/TF2CIAsVZQY/s1600/nameLastKbdMacro.bmp"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 303px; height: 26px;" src="http://4.bp.blogspot.com/_5xGV5soeRRE/TLD50CwhZaI/AAAAAAAAACM/TF2CIAsVZQY/s320/nameLastKbdMacro.bmp" alt="" id="BLOGGER_PHOTO_ID_5526191415272498594" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I press Enter and it asks me “Name for last kbd macro:”. I enter “goto-next-search-occurrence”.  At this point, you could manually execute “goto-next-search-occurrence” by entering it at the “Alt+X” prompt.&lt;br /&gt;&lt;br /&gt;Now is a time that you could bind this new command to a key or key sequence. I would have liked to find a somewhat mnemonic key sequence for this, but I ended up with just “Ctr+;, A”.&lt;br /&gt;&lt;br /&gt;Now I have a macro with a name, but it isn’t saved. In order to save macros, you should first go to the “Kbd Macros” section of the Emacs+ preferences page. You should set up a directory somewhere with a reasonable name.  I created a “EmacsPlusMacros” directory off of my home directory. Enter the path to that directory in the “Save/Load Kbd Macro Storage Directory” field. Set the “All” checkbox in the “Load Saved Kbd Macros on Startup?” section. Save these settings.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_5xGV5soeRRE/TLD1OtWGGNI/AAAAAAAAABs/l7pqNHwG7A8/s1600/KbdMacrosPrefsPage.bmp"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 320px; height: 220px;" src="http://3.bp.blogspot.com/_5xGV5soeRRE/TLD1OtWGGNI/AAAAAAAAABs/l7pqNHwG7A8/s320/KbdMacrosPrefsPage.bmp" alt="" id="BLOGGER_PHOTO_ID_5526186375822842066" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Now we can save the macro. Press “Alt+x” and enter “save-k” and press TAB to complete to “save-kbd-macro”. Press Enter and it will ask “Save Kbd Macro”. Enter “goto” and press TAB to complete to “goto-next-search-occurrence” (assuming you don’t have any other commands that begin with “goto”).&lt;br /&gt;&lt;br /&gt;Now everything is set up. Exit Eclipse and restart it. From the editor view, run a search for something. Press “Ctrl+;, A” (or whatever you bound “goto-next-search-occurrence” to). The editor view now shows the first occurrence, and your focus is still in the Editor view.&lt;br /&gt;&lt;h2&gt;Taking Macros to the Next Level&lt;/h2&gt;&lt;br /&gt;Now that you've defined a macro, along with a key binding for that macro, it's critical to realize that that key is just like any other. You can now define additional macros that compose that first macro as one of its steps.&lt;br /&gt;&lt;br /&gt;As a real-life example, I recently had a set of search results that represented a pattern that I needed to make changes to.  Remember again that the key bindings I specify here are &lt;b&gt;my&lt;/b&gt; bindings, which may be different from what you have.&lt;br /&gt;&lt;br /&gt;While in the editor view looking at the first search occurrence, I pressed the key to start recording a macro (Ctrl+[). I started the macro with the "Home" key because going to a search occurrence puts the cursor at the end of the search string on the line.  I then pressed the key I have bound to the Emacs+ "query-replace-regexp" function (Ctrl+;,R).  I entered the source string and the replacement string and pressed "." at the next prompt to do the one replacement and exit.  I then pressed "End" to go to the end of the line, then I pressed the key I bound to my "goto-next-search-occurrence" macro (Ctrl+;,A), then I ended the macro (Ctrl+]). The key to building a macro that steps through a list is to end the macro with the key that advances to the next entry.&lt;br /&gt;&lt;br /&gt;The macro I really defined actually did three different replacements at different points in the file, all of which I did just by pressing keys.&lt;br /&gt;&lt;br /&gt;At this point, I simply executed the macro with the "kbd-macro-call" function (Ctrl+\,E) as many times as necessary to step through all of my search occurrences.  When I got to the end of my search occurrences, I had numerous modified files, so I did a "Save All" from the menubar.&lt;br /&gt;&lt;br /&gt;I could have used the ability in Emacs+ to provide a "prefix argument" to any command, which is used to modify the behavior of the command.  When you provide a prefix argument to "kbd-macro-call", it treats it as an integer that represents the number of times to run the macro consecutively.  The function is called "universal-argument" (Ctrl+;,Ctrl+U).&lt;br /&gt;&lt;h2&gt;Wrap up&lt;/h2&gt;&lt;br /&gt;This set of practices and tools should be a big help to you and your abused wrist. Be sure to mark Emacs+ as a Favorite in the Eclipse Marketplace.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7061894606829532334-5264306004437825545?l=davidmichaelkarr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davidmichaelkarr.blogspot.com/feeds/5264306004437825545/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7061894606829532334&amp;postID=5264306004437825545' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/5264306004437825545'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/5264306004437825545'/><link rel='alternate' type='text/html' href='http://davidmichaelkarr.blogspot.com/2010/10/keyboard-nirvana-with-eclipse-and-emacs.html' title='Keyboard Nirvana with Eclipse and Emacs+'/><author><name>David Karr</name><uri>http://www.blogger.com/profile/17575148038635091341</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://3.bp.blogspot.com/_5xGV5soeRRE/SUV9OBbfxgI/AAAAAAAAAAM/9gAJOYaYXMg/S220/IMG_0139001web.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_5xGV5soeRRE/TLD2MJfSKtI/AAAAAAAAAB8/u2pQTmFiORI/s72-c/KeysPrefs.bmp' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7061894606829532334.post-7862153290404929778</id><published>2008-11-06T15:33:00.000-08:00</published><updated>2008-11-08T15:15:18.215-08:00</updated><title type='text'>Book Review: Clean Code: A Handbook of Agile Software Craftsmanship</title><content type='html'>I recently noticed (and quickly read) another book from the prolific writer Robert C. Martin, "Uncle Bob" to people who know him in the industry.  The book is titled &lt;span style="font-style:italic;"&gt;Clean Code: A Handbook of Agile Software Craftsmanship&lt;/span&gt;.  Although you see "Agile" in the title, it's not really a book about Agile Software Development, although it certainly describes practices that would occur while utilizing Agile techniques.  It's really much more about software craftsmanship and refactoring.  I'll tell you a little more about the book in this review.  Note that all of the examples are Java, but very little content in the book references anything past "core Java", except for perhaps some references to collection classes and concurrency (although the basics of concurrency are not really Java-specific), so a C#-er would still get a lot of benefit from this book.&lt;br /&gt;&lt;br /&gt;Note that although I really liked the theme and content of the book, I don't necessarily agree with everything he advises.  You shouldn't either, but you should do so for the right reasons.  You should never follow rules and guidelines if you don't know why you should do it, or what benefit it provides.  If you respect that strategy while reading this book, you will appreciate it for what it is, a very careful and thoughtful analysis of how to write clean code.&lt;br /&gt;&lt;br /&gt;What I'm reviewing is the online Safari version of the book, published August 1st, 2008.&lt;br /&gt;&lt;br /&gt;Although RCM has the sole author credit, several chapters say right at the beginning "by ...", with names like Tim Ottinger, Michael Feathers, James Grenning, Jeff Langr, Dr. Kevin Dean Wampler, and Brett L. Schuchert, so I imagine this is more of a collaborative work, although it does not detract from the theme or style of the book.&lt;br /&gt;&lt;br /&gt;The book has 17 chapters of content.  I usually don't consider appendices part of the content of the book, but this book has a very good appendix titled "Concurrency II", which is sort of a "sequel" to the earlier "Concurrency" chapter in the book.  I'll talk more about this appendix a little later.&lt;br /&gt;&lt;br /&gt;The first chapter of the book is titled "Clean Code", which really sets the theme for the entire book (it's in the title, of course).  Whether it's talking about good naming, formatting, coupling/cohesion, or testing, the object is to produce clean code, and to reap the benefits of such behavior.  This chapter reviews the basic principles of what "clean code" means without getting into code yet.&lt;br /&gt;&lt;br /&gt;The next chapter, "Meaningful Names" (by Tim Ottinger), covers one of the most important intangible skills required for effective software development, being capable enough in the English language (and typing, I suppose) to define names that effectively convey the true meaning and intent of a symbol, without requiring extensive comments to explain the meaning of the name (more about that anti-pattern later).  This is a fundamental skill required for writing clean code.&lt;br /&gt;&lt;br /&gt;Following this is the chapter called "Functions", which covers issues with function structure and high-level design goals, like "Do one thing" and "One level of abstraction" and issues that the function interface presents to clients of the function that can add or detract to the quality of the product.&lt;br /&gt;&lt;br /&gt;The next chapter, titled "Comments", presents a theme that I've felt very strongly about for a long time, in that bad comments are much worse than no comments, and good understandable code with no comments at all is a good thing.  The chapter explores various aspects of this.&lt;br /&gt;&lt;br /&gt;After this is the chapter titled "Formatting", which emphasizes that formatting is very important, but the actual specification of how code is formatted is less important than the consistency of code formatting within a development group.  Fortunately, modern tool and IDE support make it easier to set up and follow agreed-upon formatting guidelines.  This chapter also talks a bit about average file length, calling this "vertical formatting".&lt;br /&gt;&lt;br /&gt;The next chapter on "Objects and Data Structures" starts with points about proper interface abstraction.  It then makes an interesting point about the difference between objects and data structures, in that the latter exposes data, but no functions, and the former exposes functions, but no data.  In addition, it points out that between procedural code (using data structures) and object-oriented code, some changes are easier in procedural code, and others are easier in object-oriented code.  There is also discussion of the Law of Demeter, which helps to reduce coupling between modules.&lt;br /&gt;&lt;br /&gt;The "Exception Handling" chapter after this, by Michael Feathers, gives good advice on defining and using exceptions, and how to handle situations with "null" that can help reduce boilerplate special-case handlers.&lt;br /&gt;&lt;br /&gt;The following chapter, "Boundaries" by James Grenning, refers to things beyond the boundaries of our code and application, mostly third-party packages that we integrate our code with.  The most important point it makes is to insulate the rest of your code from fragility in that boundary by defining facades and interfaces that allow for changes past the boundaries to not adversely impact the rest of the application.&lt;br /&gt;&lt;br /&gt;Next, the "Unit Tests" chapter gets into lots of details about how to write clean tests, but the underlying point (emphasized in the conclusion) is that the code in your tests is just as important as the code being tested, and that clean and understandable tests need to be there as part of the complete package.&lt;br /&gt;&lt;br /&gt;After this is the "Classes" chapter, with (as opposed to "by") Jeff Langr, which brings up issues in class organization and structure that help to make the resulting classes easier to understand and more amenable to changes.&lt;br /&gt;&lt;br /&gt;Next is the "Systems" chapter, by Dr. Kevin Dean Wampler.  This chapter talks about some architecture issues above classes and functions.  For instance, it talks about using dependency injection or lazy initialization to separate the setup of a system from its execution.  Next, we get into separation of concerns and using proxies and aspect-orientation to implement cross-cutting concerns the right way.&lt;br /&gt;&lt;br /&gt;Following this is the "Emergence" chapter, by Jeff Langr.  This covers Kent Beck's four rules of "Simple Design", which the author believes contributes to the "emergence" of good design. When you read the information on the first principle, "Runs All the Tests", it really seems like it would be better named "Is Fully Testable". Whatever it's called, the section is clear on the importance of this. The next three principles, named "No Duplication", "Expressive", and "Minimal Classes and Methods" are introduced in the book by summarizing that all of these are achieved through the practice of careful refactoring, which may be an even more important lesson than the principles themselves.&lt;br /&gt;&lt;br /&gt;The next chapter, titled "Concurrency", by Brett L. Schuchert, is one of the longest chapters in the book, and deservedly so.  Code implementing concurrent algorithms can be extremely difficult to understand and maintain, if principles of clean coding are not observed. Even considering the length of this chapter, this is actually only the first of two chapters on concurrency. The second part is one of the appendices, as opposed to be being part of the regular content. Perhaps the authors felt it was getting too far out of scope, I don't know. The most important advice presented in this chapter is to use the "Single Responsibility Principle", particularly when you're considering writing code that implements both concurrency principles and business logic. This is where the "java.util.concurrent" package provides a lot of advantages, as it encapsulates the details of concurrency, allowing you to plug in POJOs that concern themselves only with business logic. This chapter also mentions an intriguing tool from IBM called "ConTest" that takes an aggressive approach with testing of concurrent code, by introspecting and instrumenting the code to accentuate concurrency vulnerabilities in the code. This is the first I've heard of this tool, but if and when I need to test concurrent code, I will definitely make use of it.&lt;br /&gt;&lt;br /&gt;The next chapter, "Successive Refinement" is the first of three chapters where we get to see much of the advice that came before being put to use.  These chapters present several "deep dives" into refactoring exercises with specific code samples (mostly taken from real code bases, some written by the author himself). The refactoring steps are very clear and detailed, although it sometimes even becomes hard to follow the detail. This would be a great situation to execute the same steps yourself with the original code base, not just to follow the details, but to help absorb the techniques into your common practices. As is normal in refactoring, some of the later steps were to rework code written in previous steps. Some of the examples mention the Clover code coverage tool, which the author uses to analyze the code coverage of his tests. The second of these three chapters even examines refactoring of JUnit tests, which emphasizes the fact that tests are just as important as the production code.&lt;br /&gt;&lt;br /&gt;The last regular content chapter of the book, "Smells and Heuristics", is essentially a dictionary of numerous principles referenced throughout the book. It is divided into sections titled "Comments", "Environment", "Functions", "General", "Java", "Names", and "Tests" (they were ordered alphabetically in the book, also). Each principle in each section is numbered, and the references to these principles throughout the book are abbreviated like "N4", being the fourth principle in the Names section. Although each reference to these principles explained why the principle was used, citing examples where applicable, this dictionary also has its own examples in each principle, further supporting the advice.&lt;br /&gt;&lt;br /&gt;As mentioned previously, Appendix A is titled "Concurrency II", by Brett L. Schuchert (again), and it really just explores more issues with concurrency. Curiously, comparing the content of the two chapters, this one explores some of the same concepts, but in more detail, and with more examples than the first chapter. This appendix is perhaps as long or longer than the first chapter on concurrency. This appendix also shows examples using generated bytecode, which helps to illustrate some of the issues a little better.&lt;br /&gt;&lt;br /&gt;All in all, a concise (it is only 464 pages, after all) book on refactoring and principles to achieve clean code. It's definitely a book you should read if this is important to you. Just read it with an open mind and you will learn the things you didn't know, strengthen the principles you were already familiar with, and perhaps learn to appreciate more the principles you follow that conflict with the author's advice (few, most likely).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7061894606829532334-7862153290404929778?l=davidmichaelkarr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davidmichaelkarr.blogspot.com/feeds/7862153290404929778/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7061894606829532334&amp;postID=7862153290404929778' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/7862153290404929778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/7862153290404929778'/><link rel='alternate' type='text/html' href='http://davidmichaelkarr.blogspot.com/2008/11/book-review-clean-code-handbook-of.html' title='Book Review: Clean Code: A Handbook of Agile Software Craftsmanship'/><author><name>David Karr</name><uri>http://www.blogger.com/profile/17575148038635091341</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://3.bp.blogspot.com/_5xGV5soeRRE/SUV9OBbfxgI/AAAAAAAAAAM/9gAJOYaYXMg/S220/IMG_0139001web.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7061894606829532334.post-4847094118504004990</id><published>2008-10-22T11:12:00.000-07:00</published><updated>2008-10-31T16:14:03.201-07:00</updated><title type='text'>Book Review:    Web Service Contract Design &amp; Versioning for SOA</title><content type='html'>My wife will see any movie starring Sean Connery, no questions asked, no review required.  I, on the other hand, will read anything Thomas Erl publishes, although I think I will at least limit that promise to the domain I've seen his work in, which is service-oriented architecture and web services.  In that domain, the books he has published are unique in their ability to sharply focus on the important and relevant details that I need to know about.  He has continued his outstanding work in the new book &lt;span style="font-style:italic;"&gt;Web Service Contract Design &amp; Versioning for SOA&lt;/span&gt;, published by Prentice-Hall in October of 2008.&lt;br /&gt;&lt;br /&gt;This book is different in one way from the other Thomas Erl books I've read.  Instead of just Thomas Erl in the credits, there are actually 9 different authors, with Thomas Erl being the "lead" author (I would assume).  I suppose this is somewhat understandable, as this is also the largest book in this series that I've read (718 pages of non-appendix content), so I won't apologize for the length of this review.  Considering the range of topics covered, I give them credit for being able to limit the scope of the book down to what they did, to let them focus strictly on issues with design of the web service contract. For instance, if the scope of the book was extended to give a good treatment of WS-Security, it would have expanded into areas that would detract from the main point of the book. As in the other purely SOA and web-service focused books in the series, this book carefully avoids talking about any implementations of these specifications (these are planned for later books), to continue the focus on the design of the contract.&lt;br /&gt;&lt;br /&gt;The book covers contract design and versioning, divided into three main content sections, although the third section on versioning is small compared to the two sections on contract design, which are divided by "fundamental" and "advanced" contract design.&lt;br /&gt;&lt;br /&gt;The book uses a fictional case study throughout the book to help us focus on making it "real".  These case study sidebars are sometimes quite detailed, covering design decisions and options that we'll probably have to make in our own services.&lt;br /&gt;&lt;br /&gt;The first section, "Fundamental Service Contract Design", starts with a foundation seen elsewhere in the "Principles" (&lt;span style="font-style:italic;"&gt;SOA - Principles of Service Design&lt;/span&gt;) and "Concepts" (&lt;span style="font-style:italic;"&gt;SOA - Concepts, Technology, and Design&lt;/span&gt;) books in the series. Most important here are the "design principles" (Abstraction, Loose Coupling, etc.) which contribute towards the specific goals and benefits of "service-oriented computing".&lt;br /&gt;&lt;br /&gt;This section continues with a chapter that breaks down the various pieces of a WSDL and explains their purposes and relationships, from a high level (no syntax yet). This chapter also introduces the fact that both WSDL 1.1 (what virtually all of us use now) and WSDL 2.0 (anyone out there?) will be covered in parallel in the book.  Each section that talks about an issue specific to one version will do the same for the other version. In most cases, this is done clearly to prevent confusion.  This chapter also introduces WS-Policy and WS-I, in general.&lt;br /&gt;&lt;br /&gt;This is followed by a concise chapter on namespaces and prefixes, and the various issues these present in this domain.  It goes into detail of why a namespace is a URI, and not a URL, but also covers in detail the tradeoffs for treating it like a URL.&lt;br /&gt;&lt;br /&gt;The next chapter gets into the syntax of XML Schema, going into depth with the details of defining types and messages.  I liked that some features of XML Schema are de-emphasized, or not even mentioned, if they tend to be problematic in real implementations. I learned about how the "elementFormDefault" attribute really works (whether local elements are assumed to be in the target namespace). I was misinformed about this previously. This chapter has a long case study sidebar using the ideas presented in the chapter.&lt;br /&gt;&lt;br /&gt;The next two chapters begin the fundamentals of WSDL design, down to the syntax level.  The two chapters are divided by "Abstract" and "Concrete" portions of the contract. Besides the syntax, these chapters cover several common conventions and recommendations for naming and structure, from the WS-I specification, and just from common sense.  These chapters focus on WSDL 1.1, but NOTE boxes are shown for places where WSDL 2.0 differs from 1.1.&lt;br /&gt;&lt;br /&gt;The short chapter that follows focuses directly on WSDL 2.0 and what new features it provides over WSDL 1.1, and what new options it presents.&lt;br /&gt;&lt;br /&gt;The next chapter begins detailed discussion of the first of two WS-I specifications focused on in this book, the WS-Policy specification.  It hints at the ability of the WS-Policy framework to extend the behaviors and semantics of many aspects of the contract, and to do this in a reusable way.&lt;br /&gt;&lt;br /&gt;The next chapter, the last chapter in the first section, opens up the SOAP envelope, covering the various parts, with mentions of variances between SOAP 1.1 and SOAP 1.2.  This chapter introduces the notion of how SOAP messages are represented while bouncing around the network, between SOAP intermediaries, and how information about the "role" of various nodes in the network are described, and which roles can or will process particular parts of the envelope.&lt;br /&gt;&lt;br /&gt;Now begins the second section, titled "Advanced Service Contract Design". This section, with eight chapters, covers advanced design aspects of XML Schema and WSDL, along with WS-Policy and WS-Addressing.  Each of these four topics is covered in two chapters each.  The first two chapters cover issues with flexibility and reusability, covering wildcards, "generic vs. specific" elements, include/import, key/keyref, and some other topics.  It concludes with the usual case study examination of applying these ideas.&lt;br /&gt;&lt;br /&gt;The next two chapters, on advanced WSDL design, focuses initially on issues of modularity and extension, then covers designing asynchronous operations utilizing WS-Addressing and WS-Policy, and WS-BPEL extensions to WSDL.  It then covers some miscellaneous topics mostly covering message dispatch challenges.  Note that one section discusses an example using both the "addressing wsdl" and "addressing metadata" specifications at the same time, which according to my human resources does not work, as they conflict with each other. The chapter continues with an interesting section on binding services to HTTP without SOAP.  The case study at the end of the chapter expands on this idea.&lt;br /&gt;&lt;br /&gt;The following two chapters fully explore WS-Policy and what you can do with it.  It's a small language, but it shows how it can provide very complex functionality by building on it, perhaps to the point where it could be hard to understand.  A case study example using WS-Security is quite complex.  The explanation of the difference between "wsp:Ignorable" and "wsp:Optional" is clear with a simple example.  The last of the two chapters focuses mostly on building custom policy assertions.  This demonstrates a lot of its subtle power, and how the use of it may expand as specifications and implementations advance over time.&lt;br /&gt;&lt;br /&gt;The last two chapters of this section fully explore WS-Addressing.  The simple use case of replacing the SOAPAction HTTP header with the "wsa:Action" SOAP header is barely the start of what you can do with it.  It presents so many unusual possibilities, like allowing WSDLs and messages to specify asynchronous messages and dynamic routing paths, along with additional metadata for each "endpoint reference" to get carried along to each endpoint.&lt;br /&gt;&lt;br /&gt;The last section of the book, with four chapters, covers the range of ideas in service contract versioning.  It goes through a "fundamentals" chapter that defines terms and basic issues, then a pair of chapters on WSDL and XML Schema versioning, and then an "Advanced" chapter (miscellaneous issues) to end the book.  Throughout this section, they assume that enterprises use a consistent versioning policy, but not necessarily the same between enterprises, so they classify the strategies as "strict", "flexible", and "loose", and each issue treatment explores how those strategies apply to the issue.&lt;br /&gt;&lt;br /&gt;Overall, I was pleased with the content and level of detail in the book.  Reading it motivated me to build some sample code in my primary application server, which led me down some very interesting paths and eventual discoveries.  Although this led me to discover one minor point where the book content was disputable (mixing two different addressing specs), it led me to appreciate even more how complex the landscape is, which is probably why Thomas Erl saw the need to share the writing load for this latest volume in his series.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7061894606829532334-4847094118504004990?l=davidmichaelkarr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davidmichaelkarr.blogspot.com/feeds/4847094118504004990/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7061894606829532334&amp;postID=4847094118504004990' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/4847094118504004990'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/4847094118504004990'/><link rel='alternate' type='text/html' href='http://davidmichaelkarr.blogspot.com/2008/10/book-review-web-service-contract-design.html' title='Book Review:    Web Service Contract Design &amp; Versioning for SOA'/><author><name>David Karr</name><uri>http://www.blogger.com/profile/17575148038635091341</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://3.bp.blogspot.com/_5xGV5soeRRE/SUV9OBbfxgI/AAAAAAAAAAM/9gAJOYaYXMg/S220/IMG_0139001web.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7061894606829532334.post-7020464209028456024</id><published>2008-10-16T09:44:00.000-07:00</published><updated>2008-10-16T10:23:44.626-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java xpath xml'/><title type='text'>Java class to test XPath queries in XML documents</title><content type='html'>Something we have to do more and more these days is run XPath queries on XML documents, either interactively or programatically.  Sometimes we need to test the queries we develop.  Eclipse has several plugins in various states of quality that can do this for you.  If none of them work well enough for you, you'll need a different approach.&lt;br /&gt;I'll show here a simple Java class that uses the &lt;span style="font-weight: bold;"&gt;javax.xml.xpath.XPath&lt;/span&gt; class and the &lt;a href="http://commons.apache.org/cli/"&gt;Apache Commons CLI&lt;/a&gt; package in barely 100 lines of code that you can wrap with a shell script to easily run XPath queries against arbitrary documents, and specifying arbitrary namespaces.&lt;br /&gt;&lt;h3&gt;Command-line usage&lt;/h3&gt;The "usage" string for the shell-script wrapper, "xpathfind", is the following:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;xpathfind -p filepath {-x xpath}+ {-n pfx:ns}*&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;This means that you supply a single file path to a document, along with one or more XPath strings, and zero or more prefix and namespace pairs.&lt;br /&gt;&lt;h3&gt;Example&lt;/h3&gt;Assuming we have the following "web.xml" file:&lt;br /&gt;&lt;blockquote&gt;&amp;lt;web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"&gt;&lt;br /&gt;  &amp;lt;display-name&gt;mdkcarousel&amp;lt;/display-name&gt;&lt;br /&gt;  &amp;lt;welcome-file-list&gt;&lt;br /&gt;    &amp;lt;welcome-file&gt;index.html&amp;lt;/welcome-file&gt;&lt;br /&gt;    &amp;lt;welcome-file&gt;index.htm&amp;lt;/welcome-file&gt;&lt;br /&gt;    &amp;lt;welcome-file&gt;index.jsp&amp;lt;/welcome-file&gt;&lt;br /&gt;    &amp;lt;welcome-file&gt;default.html&amp;lt;/welcome-file&gt;&lt;br /&gt;    &amp;lt;welcome-file&gt;default.htm&amp;lt;/welcome-file&gt;&lt;br /&gt;    &amp;lt;welcome-file&gt;default.jsp&amp;lt;/welcome-file&gt;&lt;br /&gt;  &amp;lt;/welcome-file-list&gt;&lt;br /&gt;  &amp;lt;filter id="abc"&gt;&lt;br /&gt;    &amp;lt;filter-name&gt;No Caching Filter&amp;lt;/filter-name&gt;&lt;br /&gt;    &amp;lt;filter-class&gt;carousel.NoCachingFilter&amp;lt;/filter-class&gt;&lt;br /&gt;  &amp;lt;/filter&gt;&lt;br /&gt;  &amp;lt;filter-mapping&gt;&lt;br /&gt;    &amp;lt;filter-name&gt;No Caching Filter&amp;lt;/filter-name&gt;&lt;br /&gt;    &amp;lt;url-pattern&gt;/*&amp;lt;/url-pattern&gt;&lt;br /&gt;  &amp;lt;/filter-mapping&gt;&lt;br /&gt;&amp;lt;/web-app&gt;&lt;/blockquote&gt;&lt;br /&gt;The following command line and resulting output shows some examples of what it can do:&lt;br /&gt;&lt;blockquote&gt;% xpathfind -p etc/web.xml -n ":http://java.sun.com/xml/ns/javaee" -x "//:welcome-file[following-sibling::*/text()='index.htm']" -x "//:filter-name/text()" -x "//:filter/@id"&lt;br /&gt;result = "index.html".&lt;br /&gt;result = "No Caching Filter".&lt;br /&gt;result = "abc".&lt;br /&gt;&lt;/blockquote&gt;This example demonstrates a common roadblock people run into when writing XPath strings, how to deal with the default namespace?  The idea is simply to register the namespace with a blank prefix value. In the actual XPath string, you have to specify the colon with no prefix, as opposed to leaving out the prefix.&lt;br /&gt;&lt;br /&gt;Now let's see how we do this.&lt;br /&gt;&lt;h3&gt;The Code&lt;/h3&gt;The XPathFind class I show here uses classes in package javax.xml.xpath for XPath processing, and package org.apache.commons.cli to process command-line arguments.  The associated MapNamespaceContext class implements the javax.xml.namespace.NamespaceContext interface, which is used by the javax.xml.xpath.XPath class to specify prefix and namespace pairs to use during the processing of XPath queries.  I'll list both of these classes without package or import statements for brevity. In practice, you should not use the default package.&lt;br /&gt;Also, the "xpathfind" shell script is a simple wrapper around "java" to call the class and pass the command-line arguments. This version is customized for Cygwin on Windows.  A version for "plain" Unix can easily be developed from this, and a Windows batch file is very straightforward to build (except for the annoyance of limited command-line arguments).&lt;br /&gt;&lt;h4&gt;XPathFind.java&lt;/h4&gt;&lt;blockquote&gt;&lt;pre&gt;public class XPathFind&lt;br /&gt;{&lt;br /&gt;    public static void main(String[] args)&lt;br /&gt;    {&lt;br /&gt;        Option  pathOption  = new Option("p", "path", true, "Path to XML file");&lt;br /&gt;        pathOption.setRequired(true);&lt;br /&gt;        &lt;br /&gt;        Option  xpathOption = new Option("x", "xpath", true, "XPath expression to search for");&lt;br /&gt;        xpathOption.setRequired(true);&lt;br /&gt;        xpathOption.setArgs(Option.UNLIMITED_VALUES);&lt;br /&gt;        &lt;br /&gt;        Option  namespaceOption = new Option("n", "namespace", true, "prefix:namespace to use in xpath");&lt;br /&gt;        namespaceOption.setArgs(Option.UNLIMITED_VALUES);&lt;br /&gt;&lt;br /&gt;        Options options = new Options();&lt;br /&gt;        options.addOption(pathOption);&lt;br /&gt;        options.addOption(xpathOption);&lt;br /&gt;        options.addOption(namespaceOption);&lt;br /&gt;&lt;br /&gt;        CommandLineParser   parser  = new PosixParser();&lt;br /&gt;        &lt;br /&gt;        try&lt;br /&gt;        {&lt;br /&gt;            CommandLine line    = parser.parse(options, args);&lt;br /&gt;            &lt;br /&gt;            String      filePath    = line.getOptionValue("p");&lt;br /&gt;            String[]    xpaths      = line.getOptionValues("x");&lt;br /&gt;            String[]    namespaces  = line.getOptionValues("n");&lt;br /&gt;            &lt;br /&gt;            File    file    = new File(filePath);&lt;br /&gt;            if (!file.exists() || !file.canRead() || !file.isFile())&lt;br /&gt;            {&lt;br /&gt;                System.out.println("File \"" + filePath + "\" is not a readable file.");&lt;br /&gt;                usage(options);&lt;br /&gt;                System.exit(1);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            go(filePath, xpaths, namespaces);&lt;br /&gt;        }&lt;br /&gt;        catch (MissingOptionException ex)&lt;br /&gt;        {&lt;br /&gt;            usage(options);&lt;br /&gt;            System.exit(1);&lt;br /&gt;        }&lt;br /&gt;        catch (ParseException ex)&lt;br /&gt;        {&lt;br /&gt;            ex.printStackTrace();&lt;br /&gt;            System.exit(1);&lt;br /&gt;        }&lt;br /&gt;        catch (Exception ex)&lt;br /&gt;        {&lt;br /&gt;            ex.printStackTrace();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    private static void go(String filePath, String[] xpaths, String[] namespaces)&lt;br /&gt;        throws FileNotFoundException, ParserConfigurationException, IOException, SAXException&lt;br /&gt;    {&lt;br /&gt;        DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();&lt;br /&gt;        domFactory.setNamespaceAware(true); // never forget this!&lt;br /&gt;        DocumentBuilder builder = domFactory.newDocumentBuilder();&lt;br /&gt;        Document doc = builder.parse(filePath);&lt;br /&gt;&lt;br /&gt;        XPathFactory    xpathFactory    = XPathFactory.newInstance();&lt;br /&gt;        XPath   xpath   = xpathFactory.newXPath();&lt;br /&gt;        if ((namespaces != null) &amp;&amp; (namespaces.length &gt; 0))&lt;br /&gt;            xpath.setNamespaceContext(new MapNamespaceContext(namespaces));&lt;br /&gt;        &lt;br /&gt;        for (String xpathStr: xpaths)&lt;br /&gt;        {&lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;                XPathExpression xpathExpr   = xpath.compile(xpathStr);&lt;br /&gt;                &lt;br /&gt;                String  result  = xpathExpr.evaluate(doc);&lt;br /&gt;                System.out.println("result = \"" + result + "\".");&lt;br /&gt;            }&lt;br /&gt;            catch (XPathExpressionException ex)&lt;br /&gt;            {&lt;br /&gt;                System.out.println("Xpath \"" + xpathStr + "\" was invalid: " +&lt;br /&gt;                                   ex.getCause().getMessage());&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    private static void usage(Options options)&lt;br /&gt;    {&lt;br /&gt;        HelpFormatter   formatter   = new HelpFormatter();&lt;br /&gt;        formatter.printHelp("xpathfind -p filepath {-x xpath}+ {-n pfx:ns}*", options);&lt;br /&gt;        System.out.println("Can specify one or more \"-x\" options, and zero or more \"-n\" options.");&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;h4&gt;MapNamespaceContext.java&lt;/h4&gt;&lt;blockquote&gt;&lt;pre&gt;public class MapNamespaceContext implements NamespaceContext&lt;br /&gt;{&lt;br /&gt;    private Map&lt;String, String&gt; uriMap      = new HashMap&lt;String, String&gt;();&lt;br /&gt;    private Map&lt;String, String&gt; prefixMap   = new HashMap&lt;String, String&gt;();&lt;br /&gt;    &lt;br /&gt;    public MapNamespaceContext(Map&lt;String, String&gt; uriMap)&lt;br /&gt;    {&lt;br /&gt;        this.uriMap = uriMap;&lt;br /&gt;        &lt;br /&gt;        for (String key: uriMap.keySet())&lt;br /&gt;            prefixMap.put(uriMap.get(key), key);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public MapNamespaceContext(String[] colonPairs)&lt;br /&gt;    {&lt;br /&gt;        uriMap  = new HashMap&lt;String, String&gt;();&lt;br /&gt;        &lt;br /&gt;        for (String colonPair: colonPairs)&lt;br /&gt;        {&lt;br /&gt;            int colonIndex  = colonPair.indexOf(':');&lt;br /&gt;            uriMap.put(colonPair.substring(0, colonIndex).trim(),&lt;br /&gt;                       colonPair.substring(colonIndex + 1));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        for (String key: uriMap.keySet())&lt;br /&gt;            prefixMap.put(uriMap.get(key), key);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public String getNamespaceURI(String prefix)&lt;br /&gt;    { return (uriMap.get(prefix)); }&lt;br /&gt;&lt;br /&gt;    public String getPrefix(String namespaceURI)&lt;br /&gt;    { return (prefixMap.get(namespaceURI)); }&lt;br /&gt;&lt;br /&gt;    public Iterator getPrefixes(String namespaceURI)&lt;br /&gt;    { return (null); }&lt;br /&gt;}&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;h4&gt;xpathfind&lt;/h4&gt;&lt;blockquote&gt;&lt;pre&gt;#! /bin/bash&lt;br /&gt;export JAVA_HOME=$(cygpath -u "$XPATHFIND_JAVA_HOME")&lt;br /&gt;export PATH="$JAVA_HOME/bin:$PATH"&lt;br /&gt;&lt;br /&gt;java -classpath "$XPATHFIND_HOME/lib/commons-cli-1.1.jar;$XPATHFIND_HOME/build/classes" xpathfind.XPathFind "$@"&lt;/pre&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7061894606829532334-7020464209028456024?l=davidmichaelkarr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davidmichaelkarr.blogspot.com/feeds/7020464209028456024/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7061894606829532334&amp;postID=7020464209028456024' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/7020464209028456024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/7020464209028456024'/><link rel='alternate' type='text/html' href='http://davidmichaelkarr.blogspot.com/2008/10/java-class-to-test-xpath-queries-in-xml.html' title='Java class to test XPath queries in XML documents'/><author><name>David Karr</name><uri>http://www.blogger.com/profile/17575148038635091341</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://3.bp.blogspot.com/_5xGV5soeRRE/SUV9OBbfxgI/AAAAAAAAAAM/9gAJOYaYXMg/S220/IMG_0139001web.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7061894606829532334.post-2224068421107040950</id><published>2008-10-08T09:08:00.000-07:00</published><updated>2008-10-08T09:59:28.503-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eclipse aptana eclipsemonkey'/><title type='text'>Reformat generated getters/setters with Eclipse Monkey (Aptana Scripting)</title><content type='html'>I write Java code with Eclipse every day, and I find it to be an indispensable tool.  However, I still find situations where I drop back to Emacs for things that Eclipse is just not flexible enough for.  For instance, although the code formatting options in Eclipse are very thorough, there is at least one situation where I prefer to override what it generates for me.&lt;br /&gt;&lt;br /&gt;Before I go any further, I'd like to point out that it doesn't matter if you agree with the formatting preference I'm going to describe. I'm not saying that to be difficult, I'm just saying that the facilities I want to describe to you will allow you to implement your own formatting preferences, or your own custom scripting, whatever you want.  My formatting preference is just an example of something you could do.&lt;br /&gt;&lt;br /&gt;What I'm going to describe is part of the &lt;a href="http://www.aptana.com"&gt;Aptana&lt;/a&gt; Studio plugin for Eclipse. The facility is called "Eclipse Monkey", although the Eclipse project for this appears to be obsolete, and this is now totally under the Aptana domain.  It's now generically called "Aptana Scripting". You can read about this (still with the "Eclipse Monkey" name) &lt;a href="http://www.aptana.com/docs/index.php/About_Eclipse_Monkey"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The tool is inspired by the Mozilla Greasemonkey facility.  It allows you to write and execute JavaScript in Eclipse that operates on the "object model" in Eclipse.  The Eclipse Monkey site has examples, and when you install the Aptana plugin, you'll see lots of examples you can view in the "Scripts" view.  The bad news is that the documentation for this tool leaves a great deal to be desired.  You can do some useful things just by copying code from examples, but there's no obvious place to get information on the APIs you're using in that code.  The transition from "Eclipse Monkey" to "Aptana Scripting" happened recently, so hopefully Aptana will make more of this information available.&lt;br /&gt;&lt;br /&gt;The example I'm going to show you will reformat the generated code for the "Generate Getters/Setters" operation to reflect my preference.  I prefer to format getters/setters in a very compact form, with each method on a single line, although my general bracing and spacing preferences are very different from this.&lt;br /&gt;&lt;br /&gt;After installing the Aptana plugin, create a simple Java project.  Create a folder at the root of the project called "scripts".  In that folder, place the following script, calling it "formatGettersSetters.js" (or whatever you want to call it):&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;/*&lt;br /&gt; * Reformat the result of "Generate Getters/Setters" so each method is on a single&lt;br /&gt; * line.  For instance, if the generated code was this:&lt;br /&gt; * &lt;br /&gt; *    public String getStuff()&lt;br /&gt; *    {&lt;br /&gt; *        return stuff;&lt;br /&gt; *    }&lt;br /&gt; *    public void setStuff(String stuff)&lt;br /&gt; *    {&lt;br /&gt; *        this.stuff = stuff;&lt;br /&gt; *    }&lt;br /&gt; *&lt;br /&gt; * The script will produce this:&lt;br /&gt; *&lt;br /&gt; *    public String getStuff() { return stuff; }&lt;br /&gt; *    public void setStuff(String stuff) { this.stuff = stuff; }&lt;br /&gt; *&lt;br /&gt; * Menu: Java &gt; Format Getters/Setters&lt;br /&gt; * Kudos: David Karr&lt;br /&gt; * Key:M3+INSERT&lt;br /&gt; * License: EPL 1.0&lt;br /&gt; * DOM: http://download.eclipse.org/technology/dash/update/org.eclipse.eclipsemonkey.lang.javascript&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;function main()&lt;br /&gt;{&lt;br /&gt;    var sourceEditor = editors.activeEditor;&lt;br /&gt;    // make sure we have an editor&lt;br /&gt;    if (sourceEditor === undefined) &lt;br /&gt;    {&lt;br /&gt;        valid = false;&lt;br /&gt;        showError("No active editor");&lt;br /&gt;    }&lt;br /&gt;    else &lt;br /&gt;    {&lt;br /&gt;        var range = sourceEditor.selectionRange;&lt;br /&gt;        var offset = range.startingOffset;&lt;br /&gt;        var deleteLength = range.endingOffset - range.startingOffset;&lt;br /&gt;        var source = sourceEditor.source;&lt;br /&gt;        &lt;br /&gt;        var selection = source.substring(range.startingOffset, range.endingOffset);&lt;br /&gt;        // Find spaces between right paren and left brace&lt;br /&gt;        var regex   = /\)[ \r\t\f\n]*{/gm;&lt;br /&gt;        selection   = selection.replace(regex, ') {');&lt;br /&gt;        // Find spaces between left brace and first non-space&lt;br /&gt;        regex       = /{[ \r\t\f\n]*/gm;&lt;br /&gt;        selection   = selection.replace(regex, '{ ');&lt;br /&gt;        // Find spaces between last non-space and right-brace&lt;br /&gt;        regex       = /[ \r\t\f\n]*}/gm;&lt;br /&gt;        selection   = selection.replace(regex, ' }');&lt;br /&gt;        sourceEditor.applyEdit(offset, deleteLength, selection);&lt;br /&gt;        sourceEditor.selectAndReveal(offset, selection.length);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;Now, create a new Java class in your project.  In the class, define three (for example) instance variables.  Then, execute the "Generate Getters and Setters..." option from the Eclipse menu, however you like to do it.  I use the keyboard shortcut, which is "Alt-Shift-s, r".  Then do "Select All" (Alt-a) and click OK.&lt;br /&gt;&lt;br /&gt;At this point, the generated getters/setters have been inserted into the editor, and the inserted region is selected.  Without changing the selection, from the menubar select "Scripts", then "Java", then "Format Getters/Setters".  This will replace the generated region with a reformatted version of it, with each method on a single line.&lt;br /&gt;&lt;br /&gt;Again, this is just an example of the kinds of things you can do with this tool.  As Aptana does more work on refining the tool and producing more documentation, this tool will become even more useful.  For example, one facility that is available, but which I need more information about, is the ability to have scripts execute automatically when certain events occur, without having to manually execute them.  It's possible that this reformatting script could be executed automatically after completion of the "Generate Getters/Setters" operation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7061894606829532334-2224068421107040950?l=davidmichaelkarr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davidmichaelkarr.blogspot.com/feeds/2224068421107040950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7061894606829532334&amp;postID=2224068421107040950' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/2224068421107040950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/2224068421107040950'/><link rel='alternate' type='text/html' href='http://davidmichaelkarr.blogspot.com/2008/10/reformat-generated-getterssetters-with.html' title='Reformat generated getters/setters with Eclipse Monkey (Aptana Scripting)'/><author><name>David Karr</name><uri>http://www.blogger.com/profile/17575148038635091341</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://3.bp.blogspot.com/_5xGV5soeRRE/SUV9OBbfxgI/AAAAAAAAAAM/9gAJOYaYXMg/S220/IMG_0139001web.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7061894606829532334.post-5678078906863921346</id><published>2008-10-07T09:07:00.000-07:00</published><updated>2008-10-07T10:19:02.982-07:00</updated><title type='text'>Book Review: Effective Java (2nd Edition)</title><content type='html'>This edition of &lt;a href="http://www3.addall.com/New/compare.cgi?dispCurr=USD&amp;id=40472&amp;isbn=0321356683&amp;location=10000&amp;thetime=20081007090831&amp;author=&amp;title=&amp;state=WA"&gt;&lt;span style="font-style:italic;"&gt;Effective Java&lt;/span&gt;&lt;/a&gt; was released over 4 months ago, which means by now there are likely 8 zillion reviews of it.  Nevertheless, I'd like to present my thoughts on this book.&lt;br /&gt;&lt;br /&gt;As a very experienced Java programmer, I was somewhat reluctant to pick up this book, as I thought there wasn't much more I could learn from a book like this.  I was wrong.  I'd say most of the advised items were not new to me, but it's always good to see a concise reminder of base principles and "Effective Java", as it were.  However, there were also numerous items that were very much new to me, and were very enlightening.  In the "I've got to find something wrong with it" department, I found one advice which although completely correct, could lead some people astray because of some details it left out (&lt;a href="http://davidmichaelkarr.blogspot.com/2008/10/stringbuilder-is-not-always-faster-than.html"&gt;http://davidmichaelkarr.blogspot.com/2008/10/stringbuilder-is-not-always-faster-than.html&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;The book is divided into eleven chapters, divided by subject area, like "Creating and Destroying Objects", "Methods Common to All Objects", "Generics", "Concurrency", and "Serialization", and others.  This edition is well revised from the first edition (published in 2001).  It not only added new chapters relevant to features new in Java 5, it revised items where the advice clearly needed to change, and it even removed some items that had become obsolete.&lt;br /&gt;&lt;br /&gt;Many of the advices are a single page, but many of them go into great detail.  Item 8, "Obey the general contract when overriding equals", is 12 pages long and covers everything you need to know about correctly implementing the "equals" method for logical equality.  This item only barely mentions the "hashcode" method, usually discussed at the same time, as it covers it thoroughly in the very next item.&lt;br /&gt;&lt;br /&gt;The most surprising content (to me) was in the last chapter, on Serialization.  The effort required to ensure secure, reliable, and maintainable serialization was mostly lost on me before reading this.  This chapter not only went into great detail on how to resolve most serialization issues, but it also showed many examples of nefarious code that could be used to compromise serialization code that was not secure.&lt;br /&gt;&lt;br /&gt;In short, I would recommend this book to any intermediate to advanced Java programmer. You are certain to gain a better appreciation for the details of producing better and more effective code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7061894606829532334-5678078906863921346?l=davidmichaelkarr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davidmichaelkarr.blogspot.com/feeds/5678078906863921346/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7061894606829532334&amp;postID=5678078906863921346' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/5678078906863921346'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/5678078906863921346'/><link rel='alternate' type='text/html' href='http://davidmichaelkarr.blogspot.com/2008/10/book-review-effective-java-2nd-edition.html' title='Book Review: Effective Java (2nd Edition)'/><author><name>David Karr</name><uri>http://www.blogger.com/profile/17575148038635091341</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://3.bp.blogspot.com/_5xGV5soeRRE/SUV9OBbfxgI/AAAAAAAAAAM/9gAJOYaYXMg/S220/IMG_0139001web.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7061894606829532334.post-6440221200922800975</id><published>2008-10-05T15:52:00.000-07:00</published><updated>2008-10-05T16:52:45.070-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java stringbuilder bytecode'/><title type='text'>StringBuilder is NOT always faster than string concatenation</title><content type='html'>While reading through &lt;span style="font-style:italic;"&gt;Effective Java, 2nd Edition&lt;/span&gt; (which I will publish a positive book review for when I'm finished), I noticed one piece of advice which is correct, but which I realized can deceive some people into doing something inadvisable.&lt;br /&gt;&lt;br /&gt;The advice is "&lt;span style="font-weight:bold;"&gt;Item 51: Beware the performance of string concatenation&lt;/span&gt;".  This clearly points out the key to the problem, which is that if you end up creating lots of strings in a loop, it will be slow. This is as opposed to simply appending existing strings to an existing StringBuilder object, which will be much more efficient.  I'm fine with all that.&lt;br /&gt;&lt;br /&gt;My problem with this section is that it doesn't clearly point out that ordinary string concatenation actually uses StringBuilder under the covers.  That's right.  It works exactly the same way as StringBuilder, because that's how it's implemented.&lt;br /&gt;&lt;br /&gt;If you're not convinced, we can look at two very simple Java classes, and we'll use a nice Bytecode visualization plugin for Eclipse called "Bytecode Outline" (&lt;a href="http://andrei.gmxhome.de/bytecode/index.html"&gt;&lt;/a&gt;) which will show you that they truly are doing the same thing.&lt;br /&gt;&lt;br /&gt;The two sample classes are this:&lt;br /&gt;&lt;pre name="code" class="java"&gt;package stringbuilder;&lt;br /&gt;public class UsesPlus&lt;br /&gt;{&lt;br /&gt;    public static void main(String[] args)&lt;br /&gt;    {&lt;br /&gt;        String[] values = { "abc", "def", "ghi" };&lt;br /&gt;        System.out.println("string[" +&lt;br /&gt;                           values[0] + ":" +&lt;br /&gt;                           values[1] + ":" +&lt;br /&gt;                           values[2] + "]");&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;And:&lt;br /&gt;&lt;pre name="code" class="java"&gt;package stringbuilder;&lt;br /&gt;public class UsesStringBuilder&lt;br /&gt;{&lt;br /&gt;    public static void main(String[] args)&lt;br /&gt;    {&lt;br /&gt;        String[] values = { "abc", "def", "ghi" };&lt;br /&gt;        System.out.println((new StringBuilder("string[")).&lt;br /&gt;                           append(values[0]).append(":").&lt;br /&gt;                           append(values[1]).append(":").&lt;br /&gt;                           append(values[2]).append("]").&lt;br /&gt;                           toString());&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;After installing the Bytecode Outline plugin, the best way to visualize the difference is to select both classes in the Package Explorer, then right-click and select "Compare With" and then "Each Other Bytecode". This really just generates the bytecode for both and then gives you an ordinary text comparison view to compare them.  For now, I'll just present for you a meaningful excerpt of the bytecode for each.  Both of these samples start with loading the "string[" string and continuing to the "toString()" call.&lt;br /&gt;&lt;br /&gt;Here's the relevant bytecode for "UsesPlus.java" (both samples show long lines wrapped with "\" for viewability):&lt;br /&gt;&lt;pre name="code" class="java"&gt;    LDC "string["&lt;br /&gt;    INVOKESPECIAL java/lang/StringBuilder.\&lt;br /&gt;&lt;init&gt;(Ljava/lang/String;)V&lt;br /&gt;   L2 (22)&lt;br /&gt;    LINENUMBER 10 L2&lt;br /&gt;    ALOAD 1&lt;br /&gt;    ICONST_0&lt;br /&gt;    AALOAD&lt;br /&gt;    INVOKEVIRTUAL java/lang/StringBuilder.\&lt;br /&gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;&lt;br /&gt;    LDC ":"&lt;br /&gt;    INVOKEVIRTUAL java/lang/StringBuilder.\&lt;br /&gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;&lt;/pre&gt;&lt;br /&gt;Here's the similar block for "UsesStringBuilder.java":&lt;br /&gt;&lt;pre name="code" class="java"&gt;    LDC "string["&lt;br /&gt;    INVOKESPECIAL java/lang/StringBuilder.\&lt;br /&gt;&lt;init&gt;(Ljava/lang/String;)V&lt;br /&gt;    ALOAD 1&lt;br /&gt;    ICONST_0&lt;br /&gt;    AALOAD&lt;br /&gt;    INVOKEVIRTUAL java/lang/StringBuilder.\&lt;br /&gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;&lt;br /&gt;    LDC ":"&lt;br /&gt;    INVOKEVIRTUAL java/lang/StringBuilder.\&lt;br /&gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Notice that they are almost completely the same.&lt;br /&gt;&lt;br /&gt;The moral here is, don't apply good advice in the wrong places.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7061894606829532334-6440221200922800975?l=davidmichaelkarr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davidmichaelkarr.blogspot.com/feeds/6440221200922800975/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7061894606829532334&amp;postID=6440221200922800975' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/6440221200922800975'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/6440221200922800975'/><link rel='alternate' type='text/html' href='http://davidmichaelkarr.blogspot.com/2008/10/stringbuilder-is-not-always-faster-than.html' title='StringBuilder is NOT always faster than string concatenation'/><author><name>David Karr</name><uri>http://www.blogger.com/profile/17575148038635091341</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://3.bp.blogspot.com/_5xGV5soeRRE/SUV9OBbfxgI/AAAAAAAAAAM/9gAJOYaYXMg/S220/IMG_0139001web.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7061894606829532334.post-7698045102796714735</id><published>2008-10-02T07:14:00.000-07:00</published><updated>2008-10-02T08:16:32.014-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='weblogic python jython wlst getopt cygwin'/><title type='text'>Make WLST scripts more flexible with Python's Getopt</title><content type='html'>My impression is that the audience of people who are learning and using the WebLogic Scripting Tool are not experienced Python programmers (I'm not, either).  That's unfortunate, because Python (and Jython) have a lot of capabilities that can enhance your WLST scripts.&lt;br /&gt;&lt;br /&gt;A natural "first script" in WLST probably hardcodes all the values that you might pass as command-line parameters in an ordinary shell script or Java class.  Doing that limits the flexibility of your script, forcing you to modify it each time you need to change it's behavior slightly.&lt;br /&gt;&lt;br /&gt;The solution is to use the Python &lt;a href="http://docs.python.org/library/getopt.html"&gt;getopt&lt;/a&gt; module, which works similarly to the feature available in Unix shell scripts. It also adds "long options", which the Perl getopt module provides.&lt;br /&gt;&lt;br /&gt;For instance, the following is the beginning of a sample script that might be used to create a JMS module in a domain.  Instead of hardcoding the parameters into the script, they're expected to be passed in on the command line. If any errors occur while gathering the command-line arguments, the "usage()" method is called, and the script exits.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;span style="font-family:courier new;"&gt;import sys&lt;br /&gt;import os&lt;br /&gt;from java.lang import System&lt;br /&gt;&lt;br /&gt;import getopt&lt;br /&gt;&lt;br /&gt;def usage():&lt;br /&gt;    print "Usage:"&lt;br /&gt;    print "createJMSModule [-n] -u user -c credential -h host -p port -s serverName -m moduleName [-d subDeploymentName] -j jmsServerName"&lt;br /&gt;&lt;br /&gt;try:&lt;br /&gt;    opts, args    = getopt.getopt(sys.argv[1:], "nu:c:h:p:s:m:d:j:",&lt;br /&gt;                                  ["user=", "credential=", "host=", "port=",&lt;br /&gt;                                   "targetServerName=", "moduleName=",&lt;br /&gt;                                   "subDeploymentName=", "jmsServerName="])&lt;br /&gt;except getopt.GetoptError, err:&lt;br /&gt;    print str(err)&lt;br /&gt;    usage()&lt;br /&gt;    sys.exit(2)&lt;br /&gt;&lt;br /&gt;reallyDoIt  = true&lt;br /&gt;user        = ''&lt;br /&gt;credential  = ''&lt;br /&gt;host        = ''&lt;br /&gt;port        = ''&lt;br /&gt;targetServerName  = ''&lt;br /&gt;moduleName  = ''&lt;br /&gt;subDeploymentName   = 'DeployToJMSServer'&lt;br /&gt;jmsServerName   = ''&lt;br /&gt;&lt;br /&gt;for opt, arg in opts:&lt;br /&gt;    if opt == "-n":&lt;br /&gt;        reallyDoIt  = false&lt;br /&gt;    elif opt == "-u":&lt;br /&gt;        user        = arg&lt;br /&gt;    elif opt == "-c":&lt;br /&gt;        credential  = arg&lt;br /&gt;    elif opt == "-h":&lt;br /&gt;        host        = arg&lt;br /&gt;    elif opt == "-p":&lt;br /&gt;        port        = arg&lt;br /&gt;    elif opt == "-s":&lt;br /&gt;        targetServerName  = arg&lt;br /&gt;    elif opt == "-m":&lt;br /&gt;        moduleName  = arg&lt;br /&gt;    elif opt == "-d":&lt;br /&gt;        subDeploymentName   = arg&lt;br /&gt;    elif opt == "-j":&lt;br /&gt;        jmsServerName   = arg&lt;br /&gt;        &lt;br /&gt;if user == "":&lt;br /&gt;    print "Missing \"-u user\" parameter."&lt;br /&gt;    usage()&lt;br /&gt;    sys.exit(2)&lt;br /&gt;elif credential == "":&lt;br /&gt;    print "Missing \"-c credential\" parameter."&lt;br /&gt;    usage()&lt;br /&gt;    sys.exit(2)&lt;br /&gt;elif host == "":&lt;br /&gt;    print "Missing \"-h host\" parameter."&lt;br /&gt;    usage()&lt;br /&gt;    sys.exit(2)&lt;br /&gt;elif port == "":&lt;br /&gt;    print "Missing \"-p port\" parameter."&lt;br /&gt;    usage()&lt;br /&gt;    sys.exit(2)&lt;br /&gt;elif targetServerName == "":&lt;br /&gt;    print "Missing \"-s serverName\" parameter."&lt;br /&gt;    usage()&lt;br /&gt;    sys.exit(2)&lt;br /&gt;elif moduleName == "":&lt;br /&gt;    print "Missing \"-m moduleName\" parameter."&lt;br /&gt;    usage()&lt;br /&gt;    sys.exit(2)&lt;br /&gt;elif jmsServerName == "":&lt;br /&gt;    print "Missing \"-j jmsServerName\" parameter."&lt;br /&gt;    usage()&lt;br /&gt;    sys.exit(2)&lt;br /&gt;&lt;br /&gt;print "Got all the required parameters"&lt;/span&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Calling WLST scripts from the shell requires actually calling the "wlst" application, and passing your script, and the additional command line parameters, as arguments to "wlst".  For instance, this is the skeleton of a Bash script file (use &lt;a href="http://www.cygwin.com/"&gt;Cygwin&lt;/a&gt; on Windows) that could be used to call this script.  I assume that WEBLOGIC_HOME points to your WebLogic installation (like "c:/bea/weblogic92") and WLST_SCRIPTS_HOME points to your repository of scripts for execution.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;span style="font-family:courier new;"&gt;#! /bin/bash&lt;br /&gt;$WEBLOGIC_HOME/common/bin/wlst.cmd $WLST_SCRIPTS_HOME/src/samplegetopt.py "$@"&lt;/span&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;This would produce output like this (output in versions besides 9.2.2 might vary slightly):&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;span style="font-family:courier new;"&gt;% ./samplegetopt -n -u weblogic -c password -h somehost.somenet.com -p 8001 -s joe -m blow -j jmsserver&lt;br /&gt;&lt;br /&gt;CLASSPATH=C:\bea\...&lt;br /&gt;&lt;br /&gt;PATH=C:\bea\...&lt;br /&gt;&lt;br /&gt;Your environment has been set.&lt;br /&gt;&lt;br /&gt;CLASSPATH=C:\bea\...&lt;br /&gt;&lt;br /&gt;Initializing WebLogic Scripting Tool (WLST) ...&lt;br /&gt;&lt;br /&gt;Welcome to WebLogic Server Administration Scripting Shell&lt;br /&gt;&lt;br /&gt;Type help() for help on available commands&lt;br /&gt;&lt;br /&gt;Got all the required parameters&lt;/span&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7061894606829532334-7698045102796714735?l=davidmichaelkarr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davidmichaelkarr.blogspot.com/feeds/7698045102796714735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7061894606829532334&amp;postID=7698045102796714735' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/7698045102796714735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/7698045102796714735'/><link rel='alternate' type='text/html' href='http://davidmichaelkarr.blogspot.com/2008/10/make-wlst-scripts-more-flexible-with.html' title='Make WLST scripts more flexible with Python&apos;s Getopt'/><author><name>David Karr</name><uri>http://www.blogger.com/profile/17575148038635091341</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://3.bp.blogspot.com/_5xGV5soeRRE/SUV9OBbfxgI/AAAAAAAAAAM/9gAJOYaYXMg/S220/IMG_0139001web.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7061894606829532334.post-5380000254720044484</id><published>2008-09-27T13:03:00.000-07:00</published><updated>2010-01-21T09:54:13.063-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java jar bash xpath cygwin'/><title type='text'>Jarsearch: Bash script to search for class name substrings in archive files</title><content type='html'>How often have you had to figure out which of numerous jars (or zips) in numerous directories has a particular class (or other kind of file), so you can copy it, reference it, or open it for inspection?&lt;br /&gt;&lt;br /&gt;I long ago tired of struggling through this, so I wrote a simple Bash (runs on Unix or Cygwin) script that facilitates this, and is easy to integrate into an "&lt;span style="font-weight: bold; font-family:courier new;"&gt;xargs&lt;/span&gt;" pipe.&lt;br /&gt;&lt;br /&gt;The script is called "&lt;span style="font-weight: bold; font-family:courier new;"&gt;jarsearch&lt;/span&gt;". It takes at least two parameters, and two options. The first expected parameter is a search string.  The second expected parameter is a path to an archive file that "&lt;span style="font-weight: bold; font-family:courier new;"&gt;jar&lt;/span&gt;" can understand. Additional parameters are additional file paths. It also takes optional flags "&lt;span style="font-weight: bold; font-family:courier new;"&gt;-l&lt;/span&gt;" (just list the archives it was found in) and "&lt;span style="font-weight: bold; font-family:courier new;"&gt;-i&lt;/span&gt;" (ignore case in comparisons).&lt;br /&gt;&lt;br /&gt;Here are some examples of its usage:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;span style="font-family:courier new;"&gt;% jarsearch Delivery *.jar&lt;br /&gt;File dsn.jar:&lt;br /&gt;  3506 Wed Oct 17 11:06:06 PDT 2007 com/sun/mail/dsn/DeliveryStatus.class&lt;br /&gt;&lt;br /&gt;% jarsearch SAXParse apache-ant-1.7.0/lib/*.jar&lt;br /&gt;File apache-ant-1.7.0/lib/xercesImpl.jar:&lt;br /&gt;    45 Wed Sep 13 22:13:54 PDT 2006 META-INF/services/javax.xml.parsers.SAXParserFactory&lt;br /&gt;  2701 Wed Sep 13 22:16:12 PDT 2006 org/apache/xerces/jaxp/SAXParserFactoryImpl.class&lt;br /&gt;  5760 Wed Sep 13 22:16:12 PDT 2006 org/apache/xerces/jaxp/SAXParserImpl$JAXPSAXParser.class&lt;br /&gt;  7748 Wed Sep 13 22:16:12 PDT 2006 org/apache/xerces/jaxp/SAXParserImpl.class&lt;br /&gt;   564 Wed Sep 13 22:16:06 PDT 2006 org/apache/xerces/parsers/AbstractSAXParser$1.class&lt;br /&gt;   564 Wed Sep 13 22:16:06 PDT 2006 org/apache/xerces/parsers/AbstractSAXParser$2.class&lt;br /&gt;  2500 Wed Sep 13 22:16:06 PDT 2006 org/apache/xerces/parsers/AbstractSAXParser$AttributesProxy.class&lt;br /&gt;  1009 Wed Sep 13 22:16:06 PDT 2006 org/apache/xerces/parsers/AbstractSAXParser$LocatorProxy.class&lt;br /&gt; 18424 Wed Sep 13 22:16:06 PDT 2006 org/apache/xerces/parsers/AbstractSAXParser.class&lt;br /&gt;  1710 Wed Sep 13 22:16:06 PDT 2006 org/apache/xerces/parsers/SAXParser.class&lt;br /&gt;File apache-ant-1.7.0/lib/xml-apis.jar:&lt;br /&gt;  3896 Sat Feb 25 11:28:32 PST 2006 javax/xml/parsers/SAXParser.class&lt;br /&gt;  2483 Sat Feb 25 11:28:32 PST 2006 javax/xml/parsers/SAXParserFactory.class&lt;br /&gt;  1287 Sat Feb 25 11:28:32 PST 2006 org/xml/sax/SAXParseException.class&lt;br /&gt;&lt;br /&gt;% find apache-* castor-* -name "*.jar" | xargs -n100 jarsearch javax.xml.parsers.SAXParser.class&lt;br /&gt;File apache-ant-1.7.0/lib/xml-apis.jar:&lt;br /&gt;  3896 Sat Feb 25 11:28:32 PST 2006 javax/xml/parsers/SAXParser.class&lt;br /&gt;File castor-0.9.6/lib/xerces-J_1.4.0.jar:&lt;br /&gt;  3518 Tue May 22 17:21:10 PDT 2001 javax/xml/parsers/SAXParser.class&lt;br /&gt;File castor-0.9.7/lib/xerces-J_1.4.0.jar:&lt;br /&gt;  3518 Tue May 22 17:21:10 PDT 2001 javax/xml/parsers/SAXParser.class&lt;/span&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;And following this is the entire "&lt;span style="font-weight: bold; font-family:courier new;"&gt;jarsearch&lt;/span&gt;" script. Put this in your &lt;span style="font-weight: bold; font-family:courier new;"&gt;$HOME/bin&lt;/span&gt; and set the execute bit ("&lt;span style="font-weight: bold; font-family:courier new;"&gt;chmod +x $HOME/bin/jarsearch&lt;/span&gt;").&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;span style="font-family:courier new;"&gt;#! /bin/bash&lt;br /&gt;listflag=0&lt;br /&gt;ignorecase=0&lt;br /&gt;while getopts li opt&lt;br /&gt;do&lt;br /&gt;    case $opt in&lt;br /&gt;    l) listflag=1;;&lt;br /&gt;    i) ignorecase=1;;&lt;br /&gt;    esac&lt;br /&gt;done&lt;br /&gt;shift `expr $OPTIND - 1`&lt;br /&gt;sstring="$1"&lt;br /&gt;shift&lt;br /&gt;&lt;br /&gt;casestr=""&lt;br /&gt;if [ "$ignorecase" == 1 ]; then&lt;br /&gt;    casestr="-i"&lt;br /&gt;fi&lt;br /&gt;&lt;br /&gt;# (copied from "ant")&lt;br /&gt;# OS specific support.  $var _must_ be set to either true or false.&lt;br /&gt;cygwin=false;&lt;br /&gt;darwin=false;&lt;br /&gt;case "`uname`" in&lt;br /&gt;  CYGWIN*) cygwin=true ;;&lt;br /&gt;  Darwin*) darwin=true&lt;br /&gt;           if [ -z "$JAVA_HOME" ] ; then&lt;br /&gt;             JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Home&lt;br /&gt;           fi&lt;br /&gt;           ;;&lt;br /&gt;esac&lt;br /&gt;&lt;br /&gt;tmpfile=${TMPDIR:-/tmp}/js.$$&lt;br /&gt;trap '/bin/rm -f $tmpfile; exit 1' 1 2 3 15&lt;br /&gt;for fn in "$@"; do&lt;br /&gt;    if $cygwin; then&lt;br /&gt;        fn="$(cygpath -m $fn)"&lt;br /&gt;    fi&lt;br /&gt;    jar tvf "$(echo $fn)" | 2&gt;&amp;1 grep $casestr "$sstring" &gt; $tmpfile&lt;br /&gt;    if [ -s $tmpfile ]; then&lt;br /&gt;        if [ "$listflag" == 1 ]; then&lt;br /&gt;            echo $fn&lt;br /&gt;        else&lt;br /&gt;          echo File $fn\:&lt;br /&gt;            cat $tmpfile&lt;br /&gt;        fi&lt;br /&gt;    fi&lt;br /&gt;done&lt;br /&gt;/bin/rm -f $tmpfile&lt;/span&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7061894606829532334-5380000254720044484?l=davidmichaelkarr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://davidmichaelkarr.blogspot.com/feeds/5380000254720044484/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7061894606829532334&amp;postID=5380000254720044484' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/5380000254720044484'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7061894606829532334/posts/default/5380000254720044484'/><link rel='alternate' type='text/html' href='http://davidmichaelkarr.blogspot.com/2008/09/jarsearch-bash-script-to-search-for.html' title='Jarsearch: Bash script to search for class name substrings in archive files'/><author><name>David Karr</name><uri>http://www.blogger.com/profile/17575148038635091341</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://3.bp.blogspot.com/_5xGV5soeRRE/SUV9OBbfxgI/AAAAAAAAAAM/9gAJOYaYXMg/S220/IMG_0139001web.jpg'/></author><thr:total>0</thr:total></entry></feed>
