<?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-4951797399507549351</id><updated>2012-02-15T23:48:01.243-08:00</updated><category term='MacBook'/><category term='SQL'/><category term='TFTP'/><category term='HTTPS'/><category term='Regular Expressions'/><category term='Selenium'/><category term='PL/SQL'/><category term='File Parsing'/><category term='Security'/><category term='Oracle'/><category term='Acegi'/><category term='Spring Security'/><category term='sed'/><category term='FTPS'/><category term='Testing'/><category term='HTTP'/><category term='Swing'/><category term='Charts'/><category term='Collections'/><category term='FTP'/><category term='BeanShell'/><category term='Mac'/><category term='Swing Builder'/><category term='Grails'/><category term='Spring'/><category term='JUnit'/><category term='Flatworm'/><category term='Merge'/><category term='JFreeChart'/><category term='SSH'/><category term='Graphs'/><category term='Subversion'/><category term='SFTP'/><category term='Diff'/><category term='Java'/><category term='SCP'/><category term='OSX'/><category term='Groovy'/><category term='Google'/><category term='TELNET'/><category term='Blogging'/><category term='Regex'/><category term='Reflection'/><category term='iPhone'/><category term='Firefox'/><category term='Linux'/><category term='SQL Developer'/><category term='Ubuntu'/><category term='JAXME'/><category term='Flat Files'/><category term='SSHTools'/><title type='text'>Confessions of a Java Programmer</title><subtitle type='html'>A guide on solving common programming problems using Java, Groovy, Grails, SQL, PL/SQL, Oracle, Spring, and other technologies.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://javaconfessions.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>34</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-3580882558344777411</id><published>2010-07-12T00:01:00.000-07:00</published><updated>2010-07-12T00:01:02.012-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Selenium'/><category scheme='http://www.blogger.com/atom/ns#' term='JUnit'/><title type='text'>Advanced Web Application Test Development Using Selenium IDE</title><content type='html'>&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=javaconfe-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=0131482394&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt;In my last &lt;a href="http://javaconfessions.com/2010/07/selenium-is-suite-of-tools-to-automate.html"&gt;post&lt;/a&gt; I covered creating a basic Selenium test using the Selenium IDE and exporting tests to JUnit for execution through Selenium RC. Now, we're going to cover the more advanced aspects of using Selenium IDE to create advanced test cases for your we application.&lt;br /&gt;&lt;br /&gt;The easiest way to generate tests, is too perform the actions in your browser and allow the Selenium IDE to populate automatically. In all honesty, this will handle 99% of the features you want to test. But there are times when the browser integrated features aren't enough to test everything and you have to get your hands a little dirty.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Assert the Title Attribute of an Image&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;For our first example, we're going to verify the title attribute of an image. One of my favorite sites is &lt;a href="http://www.xkcd.com/"&gt;XKCD&lt;/a&gt; and the comics always have a funny image title that is part of the comic. The first thing we're going to do is browse over to &lt;a href="http://www.xkcd.com/756/"&gt;http://www.xkcd.com/756/&lt;/a&gt;. If you hold the mouse over the image, you will see the title text appear, which says: "&lt;i&gt;News networks giving a greater voice to viewers because the social web is so popular are like a chef on the Titanic who, seeing the looming iceberg and fleeing customers, figures ice is the future and starts making snow cones.&lt;/i&gt;"&lt;br /&gt;&lt;br /&gt;Let's fire up the Selenium IDE by opening Tools &amp;gt; Selenium IDE. Set the base URL to http://www.xkcd.com. Now if you'll right click on the comic, then go to &lt;i&gt;Show all available commands &amp;gt; assertElementPresent //img[@alt='Public Opinion']&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;The assertElementPresent command allows you to specify an element exists using locators. We're going to cover locators next. Switch over to the Selenium IDE and select the assertElementCommand we just created. In the target text box, change the &lt;i&gt;@alt='Public Opinion'&lt;/i&gt; value to &lt;i&gt;@title&lt;/i&gt;=&lt;i&gt;News networks giving a greater voice to viewers because the social  web is so popular are like a chef on the Titanic who, seeing the looming  iceberg and fleeing customers, figures ice is the future and starts  making snow cones&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_YtgHTKRckOQ/TDD61UJrDcI/AAAAAAAAAmY/Bo-jISgtSvM/s1600/20100704-CaptureIt-Picture-2.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="200" src="http://3.bp.blogspot.com/_YtgHTKRckOQ/TDD61UJrDcI/AAAAAAAAAmY/Bo-jISgtSvM/s200/20100704-CaptureIt-Picture-2.png" width="153" /&gt;&lt;/a&gt;&lt;/div&gt;This means that we are going to locate the image based on the title attribute rather than the alt attribute. Now your test should look like my test in the screenshot. Run the test now by clicking on the green triangle withe three bars and the test should pass. We now have a test that ensures the title text for this particular web comic is what we think it should be.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Selenium Element Locators&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Element locators within Selenium allow you to specify which element on a page is the target of a given command. There are three default locators for Selenium that don't require you to specify what type of locator you are using:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;DOM&lt;/b&gt;&lt;br /&gt;Locators starting with "document" will use the DOM Locator.&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;XPATH&lt;/b&gt;&lt;br /&gt;Locators that start with "//" will use the XPATH locator to find a given element.&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Identifier&lt;/b&gt;&lt;br /&gt;Locators that start with anything other than "document", "//", or a valid locator type, will default to using the identifier strategy. When using the identifier strategy, the first element with a matching id attribute will be selected. If no matching id is found, then Selenium will use the first element with a matching name attribute.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-3580882558344777411?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/3580882558344777411/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=3580882558344777411' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/3580882558344777411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/3580882558344777411'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2010/07/advanced-web-application-test.html' title='Advanced Web Application Test Development Using Selenium IDE'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_YtgHTKRckOQ/TDD61UJrDcI/AAAAAAAAAmY/Bo-jISgtSvM/s72-c/20100704-CaptureIt-Picture-2.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-7989923884829298368</id><published>2010-07-03T13:01:00.000-07:00</published><updated>2010-07-04T08:56:13.686-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Selenium'/><category scheme='http://www.blogger.com/atom/ns#' term='JUnit'/><title type='text'>Web Application Testing with Selenium and JUnit</title><content type='html'>&lt;a href="http://seleniumhq.org/"&gt;Selenium&lt;/a&gt; is a suite of tools to automate web app testing.  Selenium is very flexible and integrates with many testing &lt;a href="http://seleniumhq.org/about/platforms.html#testing-frameworks"&gt;frameworks&lt;/a&gt; and &lt;a href="http://seleniumhq.org/about/platforms.html#programming-languages"&gt;languages&lt;/a&gt; as well as running within many &lt;a href="http://seleniumhq.org/about/platforms.html#operating-systems"&gt;operating systems&lt;/a&gt; and &lt;a href="http://seleniumhq.org/about/platforms.html#browsers"&gt;browsers&lt;/a&gt;. The three major parts that make up Selenium are: &lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Selenium IDE&lt;/span&gt;&lt;br /&gt;Integrates into Firefox as an add-on to allow you to generate tests that can then be exported out to other formats for automated testing setups. This post will cover using the Selenium IDE to generate tests to be used with JUnit.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Selenium Remote Control&lt;/span&gt;&lt;br /&gt;Runs the test generated by the IDE on various platforms and browsers allowing for robust automated testing of your web application. Selenium RC will be lightly covered in this post, but will be covered in more depth in a later post.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Selenium Grid&lt;/span&gt;&lt;br /&gt;Builds upon Selenium RC and allows you to distribute your tests across multiple servers for parallel execution.  Selenium Grid will be covered in a later post.&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-weight: bold;"&gt;Creating your First Test with Selenium IDE&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=javaconfe-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=1932394850&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt;The first thing you'll need to do is install the Selenium IDE add on into Firefox by going to &lt;a href="http://seleniumhq.org/download/"&gt;http://seleniumhq.org/download/&lt;/a&gt;. Once the Selenium IDE has been installed, you'll have to restart Firefox and you'll be ready to begin creating tests.&lt;br /&gt;&lt;br /&gt;Start Firefox and click on Tools &amp;gt; Selenium IDE to open the IDE so you can begin creating a new test.  Click the record button inside of the Selenium IDE dialog, the red circle button, then you can begin performing the actions that will make up your test.  This process is pretty much just browsing to the application that will be testing and being specifying what should be tested.&lt;br /&gt;&lt;br /&gt;For our first example, we're going to use the Selenium IDE to build a basic test that asserts the title is correctly set for http://javaconfessions.com.  We want to verify not only that the title is set correctly in the head of the document, but we want to make sure the title is showing properly at the top of the page.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_YtgHTKRckOQ/TC-lpcu1mxI/AAAAAAAAAls/5rhT7eD33FQ/s1600/20100703-CaptureIt-Picture-2.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5489788602293787410" src="http://4.bp.blogspot.com/_YtgHTKRckOQ/TC-lpcu1mxI/AAAAAAAAAls/5rhT7eD33FQ/s200/20100703-CaptureIt-Picture-2.png" style="cursor: pointer; float: right; height: 140px; margin: 0pt 0pt 10px 10px; width: 200px;" /&gt;&lt;/a&gt;Ensure that we have clicked the record button, the red circle button, then in the browser go to http://javaconfessions.com. Once the page loads, right click anywhere on the page and hover your mouse over the last item in the context menu which will be "Show all available commands."&lt;br /&gt;&lt;br /&gt;Once the flyout menu appears, click the "assertTitle Confessions of a Java Programmer" menu item. You will see this command populate into the Selenium IDE. This command will assert that the title inside the head of the main HTML page reads "Confessions of a Java Programmer."&lt;br /&gt;&lt;br /&gt;Now that we've tested to ensure the title in the head tag is correct, we're going assert the title also shows up on the top of the page. This time, select the header text at the top of the page that reads "Confessions of a Java Programmer." Right click and once again hover over the "Show all available commands" menu item, then click the "assertText //div[@id='header-inner']/div[1]/h1  Confessions of a Java Programmer" menu item.  This command will assert that the top of the page reads "Confessions of a Java Programmer."&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Running the Test in the Selenium IDE&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a href="http://3.bp.blogspot.com/_YtgHTKRckOQ/TC-qhGTB5tI/AAAAAAAAAl0/vj2vzsU9KSc/s1600/20100703-CaptureIt-Picture-4.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5489793956390758098" src="http://3.bp.blogspot.com/_YtgHTKRckOQ/TC-qhGTB5tI/AAAAAAAAAl0/vj2vzsU9KSc/s200/20100703-CaptureIt-Picture-4.png" style="cursor: pointer; float: left; height: 200px; margin: 0pt 10px 10px 0pt; width: 154px;" /&gt;&lt;/a&gt;Now that we've gone through the process to setup a basic test, we're going to run it in the Selenium IDE in order to show that it works the way we think it should. To execute the test in the Selenium IDE, click the button that has the green triangle with three bars to execute the entire test.&lt;br /&gt;&lt;br /&gt;The browser will go through all of the actions defined in the test and it will pass. If there is a failure, you will see a red message in the output at the bottom and then you know you need to rework your test to ensure you are getting accurate results.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Exporting the Test for JUnit&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Now that we have built the basic test in the Selenium IDE, we can export our test for use in a JUnit Test Case. In the Selenium IDE go to File &amp;gt; Export Test Case As &amp;gt; Java ( JUnit ) - Selenium RC. Name the file JavaConfessionsTestCase.java.&lt;br /&gt;&lt;br /&gt;Open up the newly generated test file and change the package for the class if you desire. By default the test class will be created with a package of com.example.tests.  After you are done editing the file close it and copy it into the appropriate package in your project's testing directory.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Running the Test&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now we need to download Selenium RC from &lt;a href="http://seleniumhq.org/download/"&gt;http://seleniumhq.org/download/&lt;/a&gt;. Unzip the newly downloaded file and copy out the file named selenium-java-client-driver.jar out of the selenium-java-client-driver-1.0.1 directory to your testing environment's class path.&lt;br /&gt;&lt;br /&gt;The next step is to copy out the selenium-server.jar out of the selenium-server-1.0.3 directory to a permanent spot on your testing environment server. This file can be put anywhere, as it will be ran as a service in order to allow Selenium testing from JUnit classes.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_YtgHTKRckOQ/TDCL01PgqMI/AAAAAAAAAmI/N1Jgp-EcAU4/s1600/20100704-CaptureIt-Picture.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5490041685526227138" src="http://2.bp.blogspot.com/_YtgHTKRckOQ/TDCL01PgqMI/AAAAAAAAAmI/N1Jgp-EcAU4/s200/20100704-CaptureIt-Picture.png" style="cursor: pointer; float: right; height: 56px; margin: 0pt 0pt 10px 10px; width: 200px;" /&gt;&lt;/a&gt;Before executing our JUnit test we need to start the Selenium RC server. Open a command prompt and change into the directory where you stored the selenium-server.jar file. Then start the Selenium RC server by typing &lt;span style="font-style: italic;"&gt;java -jar selenium-server.jar.&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;a href="http://1.bp.blogspot.com/_YtgHTKRckOQ/TDCT3f9BpMI/AAAAAAAAAmQ/sdWgVga5h8Q/s1600/20100704-CaptureIt-Picture-1.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5490050527444182210" src="http://1.bp.blogspot.com/_YtgHTKRckOQ/TDCT3f9BpMI/AAAAAAAAAmQ/sdWgVga5h8Q/s200/20100704-CaptureIt-Picture-1.png" style="cursor: pointer; float: left; height: 121px; margin: 0pt 10px 10px 0pt; width: 200px;" /&gt;&lt;/a&gt;With the Selenium RC server now running , you can execute your Selenium JUnit test just like you normally run JUnit tests.&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;&lt;/span&gt;In the screenshot, you can see the results from executing the Selenium test in IntelliJ IDEA.&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;&lt;/span&gt;In the next post, I will demonstrate how to create more complex Selenium tests.&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-7989923884829298368?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/7989923884829298368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=7989923884829298368' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/7989923884829298368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/7989923884829298368'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2010/07/selenium-is-suite-of-tools-to-automate.html' title='Web Application Testing with Selenium and JUnit'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_YtgHTKRckOQ/TC-lpcu1mxI/AAAAAAAAAls/5rhT7eD33FQ/s72-c/20100703-CaptureIt-Picture-2.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-4017034446943676829</id><published>2010-02-11T15:39:00.001-08:00</published><updated>2010-07-04T08:54:38.743-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Swing'/><category scheme='http://www.blogger.com/atom/ns#' term='Groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='Swing Builder'/><title type='text'>Add Rows to Groovy's Swing Builder DefaultTableModel</title><content type='html'>If you've had an opportunity to mess around with Groovy's &lt;a href="http://groovy.codehaus.org/Swing+Builder" id="usas" title="Swing Builder"&gt;Swing Builder&lt;/a&gt;, you may have noticed that the table model used for tables is not the standard &lt;a href="http://java.sun.com/javase/6/docs/api/javax/swing/table/DefaultTableModel.html" id="pijm" title="javax.swing.table.DefaultTableModel"&gt;javax.swing.table.DefaultTableModel&lt;/a&gt;, but is an instance of &lt;a href="http://groovy.codehaus.org/api/groovy/model/DefaultTableModel.html" id="upl3" title="groovy.model.DefaultTableModel"&gt;groovy.model.DefaultTableModel&lt;/a&gt;.  Java's implementation of the DefaultTableModel has an &lt;a href="http://java.sun.com/javase/6/docs/api/javax/swing/table/DefaultTableModel.html#addRow%28java.lang.Object[]%29" id="zu7q" title="addRow()"&gt;addRow()&lt;/a&gt; method that allows the addition of new rows, however Groovy's implementation does not.&lt;br /&gt;&lt;br /&gt;This left me, and many others, wondering how to go about adding a new row to Groovy's DefaultTableModel object.  After looking over the Groovy API, I have come up with the solution below.  Enjoy:&lt;br /&gt;&lt;br /&gt;&lt;pre class="groovy"&gt;import groovy.swing.SwingBuilder&lt;br /&gt;&lt;br /&gt;def swing = new SwingBuilder()&lt;br /&gt;def tableData = [ [firstName: "Bob", lastName: "Stevens"], [firstName: "Lucy", lastName: "House"] ]&lt;br /&gt;def myTable = swing.table(){&lt;br /&gt;tableModel( list:tableData ){&lt;br /&gt;propertyColumn( header:"First Name", propertyName:"firstName" )&lt;br /&gt;propertyColumn( header:"Last Name", propertyName:"lastName" )&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Let's add a new row to the table&lt;br /&gt;def rows = myTable.getModel().getRowsModel().getValue()&lt;br /&gt;rows.add( [ firstName: "Reese", lastName: "Smith" ] )&lt;br /&gt;myTable.getModel().getRowsModel().setValue( rows )&lt;br /&gt;myTable.getModel().fireTableDataChanged()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=javaconfe-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=1932394842&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt;This example will add a new row to the end of the table and then redraw the JTable so the new row will show up. The function &lt;a href="http://groovy.codehaus.org/api/groovy/model/DefaultTableModel.html#getRowsModel%28%29" id="gmk7" title="getRowsModel()"&gt;getRowsModel()&lt;/a&gt; returns the &lt;a href="http://groovy.codehaus.org/api/groovy/model/ValueModel.html" id="pmsa" title="ValueModel"&gt;ValueModel&lt;/a&gt; which allows you to manipulate the data within the table.  The value set within the ValueModel will be a list of the rows in the table and you can add rows by calling &lt;i&gt;add( rowData )&lt;/i&gt; or specify an index with &lt;i&gt;add( index, rowData )&lt;/i&gt; to allow you to insert data at a specific spot in the list.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-4017034446943676829?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/4017034446943676829/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=4017034446943676829' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/4017034446943676829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/4017034446943676829'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2010/02/add-rows-to-groovy-swingbuilder.html' title='Add Rows to Groovy&amp;#39;s Swing Builder DefaultTableModel'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-5694984999895261403</id><published>2010-02-02T04:52:00.001-08:00</published><updated>2010-07-05T17:22:00.332-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSX'/><category scheme='http://www.blogger.com/atom/ns#' term='MacBook'/><title type='text'>Fix Slow Charter DNS Lookups by Using OpenDNS</title><content type='html'>&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=javaconfe-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=0764516833&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt;I have been having issues with DNS resolution being extremely slow with Charter Communications Internet on my Macbook.  I tried &lt;a href="http://javaconfessions.com/2010/01/fixing-slow-internet-browsing-when.html"&gt;disabling IP v6&lt;/a&gt; in Firefox and that seemed to work for a little while, but eventually my DNS lookups slowed down again.  Frustrated, I began looking for ways to not use Charter's DNS servers.&lt;br /&gt;&lt;br /&gt;I found out about &lt;a href="http://www.opendns.com/"&gt;OpenDNS&lt;/a&gt; after googling a little bit.  I opened up a free account and switched my router over to their DNS servers.  Low and behold, my Internet speed is blazing again on my Macbook.  So, if you're having issues with slow DNS lookups on OSX and Charter is your ISP, give &lt;a href="http://www.opendns.com/"&gt;OpenDNS&lt;/a&gt; a try.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-5694984999895261403?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/5694984999895261403/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=5694984999895261403' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/5694984999895261403'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/5694984999895261403'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2010/02/fix-slow-charter-dns-lookups-by-using.html' title='Fix Slow Charter DNS Lookups by Using OpenDNS'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-3415441900118742471</id><published>2010-01-21T07:25:00.001-08:00</published><updated>2010-07-04T09:19:57.146-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Subversion'/><category scheme='http://www.blogger.com/atom/ns#' term='Mac'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='MacBook'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='Diff'/><title type='text'>SmartSVN Blows the other Subversion Clients out of the Water</title><content type='html'>&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=javaconfe-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=0596510330&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt;I was a developer in a Window's environment for many years and have had a few years of experience with TortoiseSVN.  Once I switched to Ubuntu a while back, I strugged to find a suitable replacement for TortoiseSVN in Linux.  I tried a few different solutions including RapidSVN and KDESVN.  Neither of those even came close to the ease of use and stability of TortoiseSVN.&lt;br /&gt;&lt;br /&gt;A friend who develops on OS X had mentioned that he uses SmartSVN and that it is available for Linux also.  As a matter of fact, you can run SmartSVN under Windows, OS X, Linux, and even OS/2 Warp.&lt;br /&gt;&lt;br /&gt;So I downloaded it and ran through the 30 day professional version trial.  At the end of the trial I immediately paid the fee for the professional version.  I know what you're all thinking.  This sucker paid $79.00 for a Subversion client when there are a billion free ones available.  I gladly paid the fee and say with great confidence that there is nothing out there that even comes close to what SmartSVN can do for you.&lt;br /&gt;&lt;br /&gt;Even if I was still developing in a Windows environment and could still use TortoiseSVN, I would have paid the fee to use SmartSVN.  TortoiseSVN does not even come close to the level of productivity I can accomplish under SmartSVN.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Merge Single Revisions Across Branches&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I work in an environment with many different branches.  At any given time I have to work on the trunk and two or three branches.   If there is a change that needs to go into the trunk and possibly one or two branches, it is a time consuming process to get the changes everywhere they need to be.&lt;br /&gt;&lt;br /&gt;Assuming I am using TortoiseSVN, I'll have to commit the changes to the trunk.  Then using a diff tool, merge the changes I made from the trunk to the branch.  It is all very manual and error prone.  TortoiseSVN does offer a merging tool, &lt;strike&gt;but this is only to merge the entire branch, not single revisions or files&lt;/strike&gt; but it is uselessly complicated in my opinion.  You can read more about TortoiseSVN's merging functionality &lt;a href="http://tortoisesvn.net/docs/nightly/TortoiseSVN_en/ch05s17.html"&gt;here&lt;/a&gt;.&lt;br /&gt;Using SmartSVN, this same task is so simple.  After you have commited your trunk changes, switch over to the branch where you wish to merge these changes to.  Right click on your trunk commit in the transactions pane and click merge.  This will merge the changes from that revision into your working copy of the branch.  After that, simply commit to the branch.&lt;br /&gt;If you only want to merge one or two files from a given commit, you can do that too.  The amount of time this saves is huge when you don't have to manually merge these changes across branches.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Conclusion&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;The capability to merge single revisions across branches is huge, but there are still many other features that separate SmartSVN from the pack.  For more detailed information on SmartSVN, check out their site at:  &lt;a href="http://www.syntevo.com/smartsvn/index.html" id="o.qu" title="http://www.syntevo.com/smartsvn/index.html"&gt;http://www.syntevo.com/smartsvn/index.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Also, just for the record, I'm not affiliated with Syntevo or receiving any compensation for this post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-3415441900118742471?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/3415441900118742471/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=3415441900118742471' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/3415441900118742471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/3415441900118742471'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2010/01/smartsvn-blows-other-subversion-clients.html' title='SmartSVN Blows the other Subversion Clients out of the Water'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-3572371053057589097</id><published>2010-01-21T06:26:00.000-08:00</published><updated>2010-07-04T08:58:07.641-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Regular Expressions'/><category scheme='http://www.blogger.com/atom/ns#' term='Regex'/><title type='text'>Test your Java Regular Expressions ( REGEX ) Online</title><content type='html'>&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=javaconfe-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=0596520689&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt;If you've ever worked with regular expressions using the java.util.regex package in Java, you know it can be a slow process to thoroughly test your regular expression. I recently found a website that allows you to test your regex using the java.util.regex package and actually provides detailed feedback.&lt;br /&gt;Using fileformat.com's &lt;a href="http://www.fileformat.info/tool/regex.htm"&gt;Regular Expression Test Page&lt;/a&gt;, you can run test data through Java's regex engine and see the Matcher's output methods such as matches(), replaceFirst(), replaceAll(), lookingAt(), and find().  It will also show you the groups your regular expression creates.&lt;br /&gt;&lt;br /&gt;The next time you are writing some fancy regular expressions for use in the java.util.regex package, make sure you use this handy tool for testing your regex in Java.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-3572371053057589097?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/3572371053057589097/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=3572371053057589097' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/3572371053057589097'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/3572371053057589097'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2010/01/test-your-java-regular-expressions.html' title='Test your Java Regular Expressions ( REGEX ) Online'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-2335034648089540604</id><published>2010-01-13T19:08:00.000-08:00</published><updated>2010-02-11T19:34:10.526-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSX'/><category scheme='http://www.blogger.com/atom/ns#' term='Mac'/><category scheme='http://www.blogger.com/atom/ns#' term='MacBook'/><category scheme='http://www.blogger.com/atom/ns#' term='Firefox'/><title type='text'>Fixing Slow Internet Browsing when using Firefox on Mac OSX</title><content type='html'>If you're using Firefox on your Mac and having issues with slow web browsing, it may be due to the fact that Firefox is attempting to do IPV6 DNS lookups.  The main symptom for this problem is that every time you attempt to browse to a new page, the status in the bottom left corner says "&lt;span style="font-style: italic;"&gt;Locating whatever website...&lt;/span&gt;" and it takes a few seconds before the page starts to load.  However, once you get to the page, browsing speeds up.&lt;br /&gt;&lt;br /&gt;The problem is that Firefox attempts to resolve IPV6 addresses first then attempts to resolve IPV4 addresses by default.  If your ISP's DNS server does not support IPV6, this will cause a delay.  Fortunately, the good people at Mozilla gave us a way to change this setting.&lt;br /&gt;&lt;br /&gt;To fix this, you can disable IPV6 in Firefox by following the steps below:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Open Firefox, type &lt;span style="font-weight: bold;"&gt;about:config&lt;/span&gt; in the address bar and hit enter.&lt;/li&gt;&lt;li&gt;You'll receive a warning, click the button that says "&lt;span style="font-style: italic;"&gt;I'll be careful, I promise!&lt;/span&gt;"&lt;/li&gt;&lt;li&gt;Find the preference named &lt;span style="font-weight: bold;"&gt;network.dns.disableIPV6&lt;/span&gt; and double click it to set it to true.&lt;/li&gt;&lt;li&gt;Restart Firefox&lt;/li&gt;&lt;/ol&gt;Now your browsing should speed up because Firefox will now only attempt to resolve addresses in IPV6 format.  For more information about this issue check out &lt;a href="http://kb.mozillazine.org/Network.dns.disableIPv6"&gt;http://kb.mozillazine.org/Network.dns.disableIPv6&lt;/a&gt;. &lt;p/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-2335034648089540604?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/2335034648089540604/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=2335034648089540604' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/2335034648089540604'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/2335034648089540604'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2010/01/fixing-slow-internet-browsing-when.html' title='Fixing Slow Internet Browsing when using Firefox on Mac OSX'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-1181698321878892518</id><published>2010-01-11T17:14:00.001-08:00</published><updated>2010-07-04T09:07:20.326-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Spring Security'/><category scheme='http://www.blogger.com/atom/ns#' term='Security'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='Acegi'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='Grails'/><title type='text'>Securing Grails: Salting Passwords using the ReflectionSaltSource</title><content type='html'>I'm a Grails newbie, however I have been using Spring Security for quite some time.  One of the features I really like about Spring Security is the capability to provide either a system wide salt or reflection salt source for more secure password hashing.&lt;br /&gt;&lt;br /&gt;As I was getting started on a Grails project, I was impressed with how easily the Acegi Spring Security plugin integrated with my project.  However, after adding a few users with the same password, I realized the passwords were not being salted with user properties because all of the hashes were the same.&lt;br /&gt;&lt;br /&gt;In order to add a Spring ReflectionSaltSource to our Grails authenticationDao, we'll need to start by declaring the salt source in our resources.groovy file.&lt;br /&gt;&lt;br /&gt;&lt;pre class="groovy" name="code"&gt;import org.springframework.security.providers.dao.salt.ReflectionSaltSource&lt;br /&gt;&lt;br /&gt;beans = {&lt;br /&gt;&lt;br /&gt;    saltSource( ReflectionSaltSource ) {&lt;br /&gt;        userPropertyToUse = "username"&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&amp;nbsp;&lt;/pre&gt;&lt;br /&gt;The code above creates a saltSource bean that we can use for dependency injection throughout our Grails project.  The next step we need to take is to inject our ReflectionSaltSource into the daoAuthenticationProvider.  I chose to do this within the bootstrap.groovy file.  Below is a sample of my BootStrap.groovy.&lt;br /&gt;&lt;br /&gt;&lt;pre class="groovy"&gt;class BootStrap {&lt;br /&gt;&lt;br /&gt;     def daoAuthenticationProvider&lt;br /&gt;     def saltSource&lt;br /&gt;&lt;br /&gt;     def init = { servletContext -&amp;gt;&lt;br /&gt;&lt;br /&gt;          daoAuthenticationProvider.saltSource = saltSource&lt;br /&gt;&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     def destroy = {}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We have now setup Acegi authentication to use our ReflectionSaltSource using the username property.  However, one more gotcha remains.  If you generated the RegistrationController using the Acegi plugin, you'll need to change how it encodes passwords for new users.  Otherwise, it will continue to encode passwords the old way and authentication will never succeed.&lt;br /&gt;&lt;br /&gt;&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=javaconfe-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=1933988932&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt;In the RegistrationController, you'll see where it is calling on the authenticateService.encodePassword method to encode new passwords.  Simply change that call to use the daoAuthenticationProvider's passwordEncoder like so:&lt;br /&gt;&lt;br /&gt;&lt;pre class="groovy"&gt;daoAuthenticationProvider.passwordEncoder.encodePassword( passwd, username )&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now all of your users' password hashes will be salted with their username.  Keep in mind, that you can't allow users to change their usernames otherwise, they will not be able to login.  This simple step makes your Grails application more secure as intruders will not easily be able to identify common password hashes if they get access to your database.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-1181698321878892518?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/1181698321878892518/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=1181698321878892518' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/1181698321878892518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/1181698321878892518'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2010/01/securing-grails-salting-passwords-using.html' title='Securing Grails: Salting Passwords using the ReflectionSaltSource'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-3130638704381578941</id><published>2009-06-18T17:41:00.001-07:00</published><updated>2010-07-04T09:11:39.827-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PL/SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title type='text'>Optimizing Oracle Inserts with FORALL</title><content type='html'>&lt;iframe src="http://rcm.amazon.com/e/cm?t=javaconfe-20&amp;o=1&amp;p=8&amp;l=bpl&amp;asins=0596514107&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;m=amazon&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr" style="align:left;padding-top:5px;width:131px;height:245px;padding-right:10px;"align="left" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;I was recently faced with a daunting task of processing approximately 300,000 records for an insert into a denormalized table in an Oracle 10g database for historical reporting. The table that was the starting point had no records that had been modified, however all of the tables the table was related to had many modifications on all records. The project required me to go through every record in the starting table and then reconstruct all of the related rows to their historical value at the time the base records were inserted. &lt;br /&gt;&lt;br /&gt;My initial go around at the task involved writing stored procedures that retrieved historical values for a given primary key and date value.&amp;nbsp; By digging through the historical values from audit tables, I was able to determine the value for the given row at the given date. &lt;br /&gt;&lt;br /&gt;After writing the necessary stored procedures to grab historical values from the related tables, I wrote a PL/SQL block to loop through all of the base records and then grab the historical values into rowtype variables and performed the inserts. The initial run of the script worked perfectly however it took approximately 7 hours and 15 minutes to run averaging about 11.5 records per second.&lt;br /&gt;&lt;br /&gt;While this run time was acceptable to the requirements, I knew there had to be a better way to accomplish the task with a faster run time. Knowing the benefits of Oracle's forall, I converted all of my PL/SQL stored procedures that retrieved historical values to views so I could boil the inserts down to one SQL statement. Then I converted my PL/SQL for loop to a forall with the one insert statement. &lt;br /&gt;&lt;br /&gt;My new and improved script ran in 6 hours even and averaged 13.9 records per second, a saving of &lt;b&gt;20%&lt;/b&gt;. The next time you are looking to cut some time from a time consuming data insert, try out the forall query. You can learn more about forall at &lt;a title="Oracle's website" href="http://www.oracle.com/technology/oramag/oracle/04-jan/o14tech_plsql.html" id="jkt5"&gt;Oracle's website&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-3130638704381578941?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/3130638704381578941/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=3130638704381578941' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/3130638704381578941'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/3130638704381578941'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2009/06/optimizing-oracle-inserts-with-forall.html' title='Optimizing Oracle Inserts with FORALL'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-1963588285951949765</id><published>2009-04-04T13:44:00.001-07:00</published><updated>2010-07-04T07:24:24.631-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='File Parsing'/><category scheme='http://www.blogger.com/atom/ns#' term='Flatworm'/><category scheme='http://www.blogger.com/atom/ns#' term='Flat Files'/><title type='text'>Writing flat files in Java with Flatworm</title><content type='html'>I previously wrote about &lt;a title="how to parse and read flat files in Java using Flatworm" href="http://javaconfessions.com/2009/02/how-to-read-and-parse-flat-files-in.html" id="isz0"&gt;how to parse and read flat files in Java using Flatworm&lt;/a&gt;. In this post, I'll show you how you can write flat files with Flatworm. The benefit to using the Flatworm library for flat file creation is that you can use the exact same file descriptor document you use to parse a particular format. The developer doesn't have to concern themselves with the details of the file layout and can focus on the data going into the file.&lt;br /&gt;&lt;p&gt;&lt;b&gt;Writing Using Our Previous Example&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;Let's revisit the sample data format we used when we explored how to parse and read flat files with Flatworm.&lt;br /&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;table class="" id="az-g" border="1" bordercolor="#000000" cellpadding="3" cellspacing="0" height="127" width="302"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="20%"&gt;&lt;b&gt;Name&lt;/b&gt;&lt;/td&gt;&lt;td width="20%"&gt;&lt;b&gt;Start&lt;/b&gt;&lt;/td&gt;&lt;td width="20%"&gt;&lt;b&gt;End&lt;/b&gt;&lt;/td&gt;&lt;td width="20%"&gt;&lt;b&gt;Length&lt;/b&gt;&lt;/td&gt;&lt;td width="20%"&gt;&lt;b&gt;Type&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="20%"&gt;Type&lt;/td&gt;&lt;td width="20%"&gt;1&lt;/td&gt;&lt;td width="20%"&gt;2&lt;/td&gt;&lt;td width="20%"&gt;2&lt;/td&gt;&lt;td width="20%"&gt;Char&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="20%"&gt;First&lt;/td&gt;&lt;td width="20%"&gt;3&lt;/td&gt;&lt;td width="20%"&gt;27&lt;/td&gt;&lt;td width="20%"&gt;25&lt;/td&gt;&lt;td width="20%"&gt;Char&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="20%"&gt;Middle&lt;/td&gt;&lt;td width="20%"&gt;28&lt;/td&gt;&lt;td width="20%"&gt;52&lt;/td&gt;&lt;td width="20%"&gt;25&lt;/td&gt;&lt;td width="20%"&gt;Char&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="20%"&gt;Last&lt;/td&gt;&lt;td width="20%"&gt;53&lt;/td&gt;&lt;td width="20%"&gt;77&lt;/td&gt;&lt;td width="20%"&gt;25&lt;/td&gt;&lt;td width="20%"&gt;Char&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="20%"&gt;Acct. ID&lt;/td&gt;&lt;td width="20%"&gt;78&lt;/td&gt;&lt;td width="20%"&gt;92&lt;/td&gt;&lt;td width="20%"&gt;15&lt;/td&gt;&lt;td width="20%"&gt;Char&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;Below is the sample flat file we will be writing.&lt;br /&gt;&lt;pre&gt;CDJOHN                     MARK                     DOE                      111111111111111&lt;br /&gt;CDPAUL                     RICHARD                  STEPHENS                 222222222222222&lt;br /&gt;CDRINGO                    JACK                     ERICSON                  333333333333333  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now that we know the file format of our flat file and we have some&lt;br /&gt;sample data to parse we'll need to create an XML document describing&lt;br /&gt;our file format for Flatworm.&lt;br /&gt;&lt;br /&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;?xml version="1.0" encoding="ISO-8859-1"?&amp;gt;&lt;br /&gt;&amp;lt;!--&amp;lt;!DOCTYPE file-format SYSTEM "http://www.blackbear.com/dtds/flatworm-data-description_1_0.dtd"&amp;gt;--&amp;gt;&lt;br /&gt;&amp;lt;file-format&amp;gt;&lt;br /&gt;  &amp;lt;converter name="char" class="com.blackbear.flatworm.converters.CoreConverters" method="convertChar" return-type="java.lang.String"/&amp;gt;&lt;br /&gt;  &amp;lt;record name="clientData"&amp;gt;&lt;br /&gt;      &amp;lt;record-ident&amp;gt;&lt;br /&gt;          &amp;lt;field-ident field-start="0" field-length="2"&amp;gt;&lt;br /&gt;              &amp;lt;match-string&amp;gt;CD&amp;lt;/match-string&amp;gt;&lt;br /&gt;          &amp;lt;/field-ident&amp;gt;&lt;br /&gt;      &amp;lt;/record-ident&amp;gt;&lt;br /&gt;      &amp;lt;record-definition&amp;gt;&lt;br /&gt;          &amp;lt;bean name="client" class="org.javaconfessions.sample.Client"/&amp;gt;&lt;br /&gt;          &amp;lt;line&amp;gt;&lt;br /&gt;              &amp;lt;record-element length="2"/&amp;gt;&lt;br /&gt;              &amp;lt;record-element length="25" beanref="client.firstName" type="char"&amp;gt;&lt;br /&gt;                  &amp;lt;conversion-option name="justify" value="left"/&amp;gt;&lt;br /&gt;                  &amp;lt;conversion-option name="pad-character" value=" "/&amp;gt;&lt;br /&gt;              &amp;lt;/record-element&amp;gt;&lt;br /&gt;              &amp;lt;record-element length="25" beanref="client.middleName" type="char"&amp;gt;&lt;br /&gt;                  &amp;lt;conversion-option name="justify" value="left"/&amp;gt;&lt;br /&gt;              &amp;lt;/record-element&amp;gt;&lt;br /&gt;              &amp;lt;record-element length="25" beanref="client.lastName" type="char"&amp;gt;&lt;br /&gt;                  &amp;lt;conversion-option name="justify" value="left"/&amp;gt;&lt;br /&gt;              &amp;lt;/record-element&amp;gt;&lt;br /&gt;              &amp;lt;record-element length="15" beanref="client.accountId" type="char"&amp;gt;&lt;br /&gt;                  &amp;lt;conversion-option name="justify" value="left"/&amp;gt;&lt;br /&gt;              &amp;lt;/record-element&amp;gt;&lt;br /&gt;          &amp;lt;/line&amp;gt;&lt;br /&gt;      &amp;lt;/record-definition&amp;gt;&lt;br /&gt;  &amp;lt;/record&amp;gt;&lt;br /&gt;&amp;lt;/file-format&amp;gt;&lt;/pre&gt;&lt;b&gt;Closer Look at the Descriptor File&lt;/b&gt;&lt;br /&gt;&lt;p&gt;Looking further at the XML descriptor file, you can see it is rather simple to describe our file format for Flatworm. The &lt;i&gt;record&lt;/i&gt; tag is the beginning of describing our client data records. Within the &lt;i&gt;record &lt;/i&gt;tag, we have our &lt;i&gt;record-ident&lt;/i&gt;&lt;br /&gt;tag. This is so Flatworm knows how to identify the types of records in&lt;br /&gt;a flat file. Most flat file formats have different types of records&lt;br /&gt;including header, footer, detail, batch headers, batch footers, etc.&lt;br /&gt;This mechanism allows Flatworm to parse out all of these different&lt;br /&gt;record types from the same file. The &lt;i&gt;field-ident&lt;/i&gt; tag gives the specifics on how to identify the record. &lt;i&gt;Field-start&lt;/i&gt; and &lt;i&gt;field-length&lt;/i&gt; identifies what to test to identify the record type. Within the &lt;i&gt;match-string &lt;/i&gt;tags&lt;br /&gt;is where the text that would be used to identify this record as a&lt;br /&gt;clientData record. In the descriptor above, we have described&lt;br /&gt;clientData records as starting with the characters CD.&lt;br /&gt;&lt;/p&gt;The next section of the record description is the &lt;i&gt;record-definition &lt;/i&gt;tag.&lt;br /&gt;This is where we actually map out each record element to a bean&lt;br /&gt;property for Flatworm. This section of the document starts with a &lt;i&gt;bean&lt;/i&gt; definition that tells Flatworm which Java class to use when parsing this record type. The &lt;i&gt;record-element&lt;/i&gt; tags setup where each field in the record is located, the data type, and where to plug it into the Java bean during parsing.&lt;br /&gt;&lt;p&gt;Here is the source code for my Client bean.&lt;br /&gt;&lt;/p&gt;&lt;pre class="java" name="code"&gt;package org.javaconfessions.sample;&lt;br /&gt;&lt;br /&gt;public class Client {&lt;br /&gt;&lt;br /&gt; private String firstName;&lt;br /&gt; private String middleName;&lt;br /&gt; private String lastName;&lt;br /&gt; private String accountId;&lt;br /&gt;&lt;br /&gt; public String getFirstName() {&lt;br /&gt;     return firstName;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setFirstName(String pFirstName) {&lt;br /&gt;     firstName = pFirstName;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public String getMiddleName() {&lt;br /&gt;     return middleName;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setMiddleName(String pMiddleName) {&lt;br /&gt;     middleName = pMiddleName;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public String getLastName() {&lt;br /&gt;     return lastName;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setLastName(String pLastName) {&lt;br /&gt;     lastName = pLastName;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public String getAccountId() {&lt;br /&gt;     return accountId;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setAccountId(String pAccountId) {&lt;br /&gt;     accountId = pAccountId;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; @Override&lt;br /&gt; public String toString() {&lt;br /&gt;     return "First Name: " + firstName + "\nMiddleName: " + middleName&lt;br /&gt;             + "\nLastName: " + lastName + "\nAccount ID: " + accountId&lt;br /&gt;             + "\n";&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Now that we have described the data model for our project, below is a sample class that populates a couple of Client beans and then has Flatworm write out the data in our specified file format.&lt;br /&gt;&lt;pre class="java" name="code"&gt;package org.javaconfessions.sample;&lt;br /&gt;&lt;br /&gt;import com.blackbear.flatworm.FileCreator;&lt;br /&gt;&lt;br /&gt;public class ClientDataWriter {&lt;br /&gt;&lt;br /&gt; public static void main(String[] args) {&lt;br /&gt;     FileCreator fileCreator = null;&lt;br /&gt;     try {&lt;br /&gt;         fileCreator = new FileCreator(args[0], args[1]);&lt;br /&gt;         fileCreator.open();&lt;br /&gt;         fileCreator.setRecordSeperator("\n");&lt;br /&gt;         Client client = new Client();&lt;br /&gt;         fileCreator.setBean("client", client);&lt;br /&gt;         client.setFirstName("JOHN");&lt;br /&gt;         client.setMiddleName("MARK");&lt;br /&gt;         client.setLastName("DOE");&lt;br /&gt;         client.setAccountId("111111111111111");&lt;br /&gt;         fileCreator.write("clientData");&lt;br /&gt;         client.setFirstName("PAUL");&lt;br /&gt;         client.setMiddleName("RICHARD");&lt;br /&gt;         client.setLastName("STEPHENS");&lt;br /&gt;         client.setAccountId("222222222222222");&lt;br /&gt;         fileCreator.write("clientData");&lt;br /&gt;         client.setFirstName("RINGO");&lt;br /&gt;         client.setMiddleName("JACK");&lt;br /&gt;         client.setLastName("ERICSON");&lt;br /&gt;         client.setAccountId("333333333333333");&lt;br /&gt;         fileCreator.write("clientData");&lt;br /&gt;     } catch (Exception e) {&lt;br /&gt;         e.printStackTrace();&lt;br /&gt;     } finally {&lt;br /&gt;         try{&lt;br /&gt;             fileCreator.close();&lt;br /&gt;         } catch( Exception e ) {&lt;br /&gt;             e.printStackTrace();&lt;br /&gt;         }&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;A Closer Look at ClientDataWriter.java&lt;/b&gt;&lt;br /&gt;&lt;p&gt;Looking at the sample code above, we can see that first we are creating a FileCreator object using parameters passed in.  The first parameter given is the path to our Descriptor XML Document and the second parameter will be the location where the data file should be written.  Next we call the open() method on the FileCreator object to open our file. The next call sets the record separator for our data file which in this case is a new line.&lt;br /&gt;&lt;br /&gt;After getting our FileCreator object setup, we instantiate a Client bean. After instantiating our Client bean, we call setBean() on the FileCreator to tell the FileCreator about our Client bean and what type of bean it is. Notice that "client" is the name of our bean in the descriptor file. The next part is pretty self explanatory, we setup our first client record, then call fileCreator.write() passing in the type of record we want to write, in this case a "clientData" record. Then we repeat for the second and third records.&lt;br /&gt;&lt;br /&gt;After writing out the records, we call the close() method on the FileCreator to close out the data file.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Gotcha&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;The Flatworm FileCreator will always put the record identifiers at the beginning of the record in the flat file. This doesn't always work because sometimes, you may have a situation where the record identifier in the middle of the record. I have a patch for the FileCreator below if you want to change this in the source. If you apply this patch, you will need to setup the record identifier portion of the bean description with the default values, in our case here "CD". However, you will have to do this for all constant data types in your file format that aren't specified in your bean or your file format will be incorrect.&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;Index: src/com/blackbear/flatworm/FileCreator.java&lt;br /&gt;--- src/com/blackbear/flatworm/FileCreator.java Base (1.3)&lt;br /&gt;+++ src/com/blackbear/flatworm/FileCreator.java Locally Modified (Based On 1.3)&lt;br /&gt;@@ -212,12 +212,12 @@&lt;br /&gt;// record-ident contain what is considered hard-coded data&lt;br /&gt;// for the output line, these can be used to uniquely identify&lt;br /&gt;// lines for parsers. We need to write them out.&lt;br /&gt;- Vector recIdents = record.getFieldIdentMatchStrings();&lt;br /&gt;+ /*Vector recIdents = record.getFieldIdentMatchStrings();&lt;br /&gt;for (Iterator itRecIdents = recIdents.iterator(); itRecIdents.hasNext();)&lt;br /&gt;{&lt;br /&gt;String id = (String) itRecIdents.next();&lt;br /&gt;bufOut.write(id + delimit);&lt;br /&gt;- }&lt;br /&gt;+ }*/&lt;br /&gt;&lt;br /&gt;// Iterate over record-element items&lt;br /&gt;Vector recElements = line.getRecordElements(); &lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-1963588285951949765?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/1963588285951949765/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=1963588285951949765' title='22 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/1963588285951949765'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/1963588285951949765'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2009/04/writing-flat-files-in-java-with.html' title='Writing flat files in Java with Flatworm'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>22</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-5345648405180793214</id><published>2009-02-21T14:52:00.001-08:00</published><updated>2010-07-05T17:20:37.245-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Flatworm'/><title type='text'>How to read and parse flat files in Java</title><content type='html'>Parsing files and their formats can be pretty painful no matter what programming language you are using. One open source project, &lt;a href="http://flatworm.sourceforge.net/" id="w_2q" title="Flatworm"&gt;Flatworm&lt;/a&gt;, looks to make reading, parsing, and writing files, much easier in Java. You define the file format in XML and Flatworm will break out the records into Java beans for you. You can read large files, file formats that have multiple-line records, and any other flat file format in existence today with this Java API.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Simple Example&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;Let's look at a simple example where we need to parse out a flat file into Java objects for processing.  In our example we will need to parse client data using the file format below.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;table border="1" bordercolor="#000000" cellpadding="3" cellspacing="0" class="" height="127" id="az-g" style="width: 302px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width="20%"&gt;&lt;b&gt;Name&lt;/b&gt;&lt;/td&gt;&lt;td width="20%"&gt;&lt;b&gt;Start&lt;/b&gt;&lt;/td&gt;&lt;td width="20%"&gt;&lt;b&gt;End&lt;/b&gt;&lt;/td&gt;&lt;td width="20%"&gt;&lt;b&gt;Length&lt;/b&gt;&lt;/td&gt;&lt;td width="20%"&gt;&lt;b&gt;Type&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="20%"&gt;Type&lt;/td&gt;&lt;td width="20%"&gt;1&lt;/td&gt;&lt;td width="20%"&gt;2&lt;/td&gt;&lt;td width="20%"&gt;2&lt;/td&gt;&lt;td width="20%"&gt;Char&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="20%"&gt;First&lt;/td&gt;&lt;td width="20%"&gt;3&lt;/td&gt;&lt;td width="20%"&gt;27&lt;/td&gt;&lt;td width="20%"&gt;25&lt;/td&gt;&lt;td width="20%"&gt;Char&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="20%"&gt;Middle&lt;/td&gt;&lt;td width="20%"&gt;28&lt;/td&gt;&lt;td width="20%"&gt;52&lt;/td&gt;&lt;td width="20%"&gt;25&lt;/td&gt;&lt;td width="20%"&gt;Char&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="20%"&gt;Last&lt;/td&gt;&lt;td width="20%"&gt;53&lt;/td&gt;&lt;td width="20%"&gt;77&lt;/td&gt;&lt;td width="20%"&gt;25&lt;/td&gt;&lt;td width="20%"&gt;Char&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="20%"&gt;Acct. ID&lt;/td&gt;&lt;td width="20%"&gt;78&lt;/td&gt;&lt;td width="20%"&gt;92&lt;/td&gt;&lt;td width="20%"&gt;15&lt;/td&gt;&lt;td width="20%"&gt;Char&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;Below is the sample flat file we will be parsing.&lt;br /&gt;&lt;pre&gt;CDJOHN                     MARK                     DOE                      111111111111111&lt;br /&gt;CDPAUL                     RICHARD                  STEPHENS                 222222222222222&lt;br /&gt;CDRINGO                    JACK                     ERICSON                  333333333333333&lt;br /&gt;&lt;/pre&gt;Now that we know the file format of our flat file and we have some sample data to parse we'll need to create an XML document describing our file format for Flatworm.&lt;br /&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;?xml version="1.0" encoding="ISO-8859-1"?&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE file-format SYSTEM "http://www.blackbear.com/dtds/flatworm-data-description_1_0.dtd"&amp;gt;&lt;br /&gt;&amp;lt;file-format&amp;gt;&lt;br /&gt;&amp;lt;converter name="char" class="com.blackbear.flatworm.converters.CoreConverters" method="convertChar" return-type="java.lang.String"/&amp;gt;&lt;br /&gt;&amp;lt;record name="clientData"&amp;gt;&lt;br /&gt;&amp;lt;record-ident&amp;gt;&lt;br /&gt;&amp;lt;field-ident field-start="0" field-length="2"&amp;gt;&lt;br /&gt;&amp;lt;match-string&amp;gt;CD&amp;lt;/match-string&amp;gt;&lt;br /&gt;&amp;lt;/field-ident&amp;gt;&lt;br /&gt;&amp;lt;/record-ident&amp;gt;&lt;br /&gt;&amp;lt;record-definition&amp;gt;&lt;br /&gt;&amp;lt;bean name="client" class="org.javaconfessions.sample.Client"/&amp;gt;&lt;br /&gt;&amp;lt;line&amp;gt;&lt;br /&gt;&amp;lt;record-element length="2"/&amp;gt;&lt;br /&gt;&amp;lt;record-element length="25" beanref="client.firstName" type="char"&amp;gt;&lt;br /&gt;&amp;lt;conversion-option name="justify" value="left"/&amp;gt;&lt;br /&gt;&amp;lt;/record-element&amp;gt;&lt;br /&gt;&amp;lt;record-element length="25" beanref="client.middleName" type="char"&amp;gt;&lt;br /&gt;&amp;lt;conversion-option name="justify" value="left"/&amp;gt;&lt;br /&gt;&amp;lt;/record-element&amp;gt;&lt;br /&gt;&amp;lt;record-element length="25" beanref="client.lastName" type="char"&amp;gt;&lt;br /&gt;&amp;lt;conversion-option name="justify" value="left"/&amp;gt;&lt;br /&gt;&amp;lt;/record-element&amp;gt;&lt;br /&gt;&amp;lt;record-element length="15" beanref="client.accountId" type="char"&amp;gt;&lt;br /&gt;&amp;lt;conversion-option name="justify" value="left"/&amp;gt;&lt;br /&gt;&amp;lt;/record-element&amp;gt;&lt;br /&gt;&amp;lt;/line&amp;gt;&lt;br /&gt;&amp;lt;/record-definition&amp;gt;&lt;br /&gt;&amp;lt;/record&amp;gt;&lt;br /&gt;&amp;lt;/file-format&amp;gt;&lt;/pre&gt;&lt;b&gt;Closer Look at the Descriptor File&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&amp;lt;file-format&amp;gt;&lt;/i&gt; - This tag is required and serves as the root node of our descriptor file.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&amp;lt;converter&amp;gt;&lt;/i&gt; - This tag is used to declare new converters to be used by the flatworm parser.&lt;br /&gt;&lt;br /&gt;&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=javaconfe-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=0071591060&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt;Looking further at the XML descriptor file, you can see it is rather simple to describe our file format for Flatworm. The &lt;i&gt;record&lt;/i&gt; tag is the beginning of describing our client data records. Within the &lt;i&gt;record &lt;/i&gt;tag, we have our &lt;i&gt;record-ident&lt;/i&gt; tag. This is so Flatworm knows how to identify the types of records in a flat file. Most flat file formats have different types of records including header, footer, detail, batch headers, batch footers, etc. This mechanism allows Flatworm to parse out all of these different record types from the same file. The &lt;i&gt;field-ident&lt;/i&gt; tag gives the specifics on how to identify the record. &lt;i&gt;Field-start&lt;/i&gt; and &lt;i&gt;field-length&lt;/i&gt; identifies what to test to identify the record type. Within the &lt;i&gt;match-string &lt;/i&gt;tags is where the text that would be used to identify this record as a clientData record. In the descriptor above, we have described clientData records as starting with the characters CD.&lt;br /&gt;&lt;br /&gt;The next section of the record description is the &lt;i&gt;record-definition &lt;/i&gt;tag. This is where we actually map out each record element to a bean property for Flatworm. This section of the document starts with a &lt;i&gt;bean&lt;/i&gt; definition that tells Flatworm which Java class to use when parsing this record type. The &lt;i&gt;record-element&lt;/i&gt; tags setup where each field in the record is located, the data type, and where to plug it into the Java bean during parsing.&lt;br /&gt;&lt;br /&gt;Here is the source code for my Client bean.&lt;br /&gt;&lt;pre class="java" name="code"&gt;package org.javaconfessions.sample;&lt;br /&gt;&lt;br /&gt;public class Client {&lt;br /&gt;&lt;br /&gt;private String firstName;&lt;br /&gt;private String middleName;&lt;br /&gt;private String lastName;&lt;br /&gt;private String accountId;&lt;br /&gt;&lt;br /&gt;public String getFirstName() {&lt;br /&gt;return firstName;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setFirstName(String pFirstName) {&lt;br /&gt;firstName = pFirstName;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String getMiddleName() {&lt;br /&gt;return middleName;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setMiddleName(String pMiddleName) {&lt;br /&gt;middleName = pMiddleName;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String getLastName() {&lt;br /&gt;return lastName;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setLastName(String pLastName) {&lt;br /&gt;lastName = pLastName;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String getAccountId() {&lt;br /&gt;return accountId;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void setAccountId(String pAccountId) {&lt;br /&gt;accountId = pAccountId;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String toString() {&lt;br /&gt;return "First Name: " + firstName + "\nMiddleName: " + middleName&lt;br /&gt;+ "\nLastName: " + lastName + "\nAccount ID: " + accountId&lt;br /&gt;+ "\n";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Now that we have all of our data model code setup, the step is to write the code that will be responsible for populating our Java bean with the parsed data. I have posted a simple parsing Class below that will parse the flat file using Flatworm, and print each item out to the console.&lt;br /&gt;&lt;pre class="java" name="code"&gt;package org.javaconfessions.sample;&lt;br /&gt;&lt;br /&gt;import com.blackbear.flatworm.ConfigurationReader;&lt;br /&gt;import com.blackbear.flatworm.FileFormat;&lt;br /&gt;import com.blackbear.flatworm.MatchedRecord;&lt;br /&gt;import java.io.BufferedReader;&lt;br /&gt;import java.io.FileInputStream;&lt;br /&gt;import java.io.InputStream;&lt;br /&gt;import java.io.InputStreamReader;&lt;br /&gt;import java.util.logging.Level;&lt;br /&gt;import java.util.logging.Logger;&lt;br /&gt;&lt;br /&gt;public class ClientDataParser {&lt;br /&gt;&lt;br /&gt;public static void main(String[] args) {&lt;br /&gt;ConfigurationReader parser = new ConfigurationReader();&lt;br /&gt;try {&lt;br /&gt;FileFormat ff = parser.loadConfigurationFile(args[0]);&lt;br /&gt;InputStream in = new FileInputStream( args[1] );&lt;br /&gt;BufferedReader bufIn = new BufferedReader( new InputStreamReader( in ) );&lt;br /&gt;MatchedRecord results;&lt;br /&gt;while( ( results = ff.getNextRecord(bufIn)) != null ) {&lt;br /&gt;System.out.println( results.getBean("client") );&lt;br /&gt;}&lt;br /&gt;} catch (Exception ex) {&lt;br /&gt;Logger.getLogger(ClientDataParser.class.getName()).log(Level.SEVERE, null, ex);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Now after compiling, we just need to execute &lt;i&gt;java ClientDataParser /path/to/format.xml /path/to/datafile.txt &lt;/i&gt;and you should get the following output:&lt;br /&gt;&lt;pre&gt;First Name: JOHN&lt;br /&gt;MiddleName: MARK&lt;br /&gt;LastName: DOE&lt;br /&gt;Account ID: 111111111111111&lt;br /&gt;&lt;br /&gt;First Name: PAUL&lt;br /&gt;MiddleName: RICHARD&lt;br /&gt;LastName: STEPHENS&lt;br /&gt;Account ID: 222222222222222&lt;br /&gt;&lt;br /&gt;First Name: RINGO&lt;br /&gt;MiddleName: JACK&lt;br /&gt;LastName: ERICSON&lt;br /&gt;Account ID: 333333333333333&lt;/pre&gt;&lt;b&gt;Summary&lt;br /&gt;&lt;/b&gt;Now you have an idea of how Flatworm works to simplify parsing flat files.  Next learn how to &lt;a href="http://javaconfessions.com/2009/04/writing-flat-files-in-java-with.html"&gt;write flat files using Flatworm&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-5345648405180793214?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/5345648405180793214/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=5345648405180793214' title='15 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/5345648405180793214'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/5345648405180793214'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2009/02/how-to-read-and-parse-flat-files-in.html' title='How to read and parse flat files in Java'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-8950491357793930385</id><published>2009-02-04T18:46:00.001-08:00</published><updated>2010-07-04T09:17:49.338-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSX'/><category scheme='http://www.blogger.com/atom/ns#' term='Mac'/><category scheme='http://www.blogger.com/atom/ns#' term='MacBook'/><title type='text'>Switching from Windows to a Macbook</title><content type='html'>&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=javaconfe-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=0596153287&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt;I have never owned a Mac before and recently made the&amp;nbsp; plunge into the Mac world&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=javaconfe-20&amp;amp;l=btl&amp;amp;camp=213689&amp;amp;creative=392969&amp;amp;o=1&amp;amp;a=0596804253" style="border: medium none ! important; margin: 0px ! important; padding: 0px ! important;" width="1" /&gt;.&amp;nbsp; I recently purchased the new aluminum case macbook and I have to say as a long time Windows user it is an amazing device. However, there are some differences that take some used to getting used to and I wanted to help out others who may be diving into the Mac world for the first time.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Common Keyboard Shortcuts&lt;/b&gt;&lt;br /&gt;The first thing you'll notice on your new macbook is that the keyboard is different and therefore some of your well known Windows keyboard shortcuts are useless. For most common functions, you can simply replace the Ctrl with the Command key. The table below gives a simple illustration. &lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;table border="1" bordercolor="#666666" cellpadding="3" cellspacing="0" class="" id="wnw."&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;" width="33%"&gt;&lt;b&gt;Function&lt;/b&gt;&lt;/td&gt;&lt;td style="text-align: center;" width="33%"&gt;&lt;b&gt;Windows&lt;/b&gt;&lt;/td&gt;&lt;td style="text-align: center;" width="33%"&gt;&lt;b&gt;Mac&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="33%"&gt;Copy&lt;/td&gt;&lt;td width="33%"&gt;Ctrl-C&lt;/td&gt;&lt;td width="33%"&gt;Command-C&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="33%"&gt;Cut&lt;/td&gt;&lt;td width="33%"&gt;Ctrl-X&lt;/td&gt;&lt;td width="33%"&gt;Command-X&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="33%"&gt;Paste&lt;/td&gt;&lt;td width="33%"&gt;Ctrl-V&lt;/td&gt;&lt;td width="33%"&gt;Command-V&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;Not So Obvious Keyboard Operations&lt;/b&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;You'll notice that there are some keys missing on your new macbook. When you started using it, you may have said, "Why does my backspace say delete, and by the way, where is the delete key?" Well, this table answers those questions.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;br /&gt;&lt;div&gt;&lt;table border="1" bordercolor="#666666" cellpadding="3" cellspacing="0" class="" id="ojxf"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;" width="33%"&gt;&lt;b&gt;Function&lt;/b&gt;&lt;/td&gt;&lt;td style="text-align: center;" width="33%"&gt;&lt;b&gt;Windows&lt;/b&gt;&lt;/td&gt;&lt;td style="text-align: center;" width="33%"&gt;&lt;b&gt;Mac&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Move to the Next Page (Page Down)&lt;/td&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Page-Dn&lt;/td&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Fn-Down Arrow&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Move to the Previous Page (Page Up)&lt;/td&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Page-Up&lt;/td&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Fn-Up Arrow&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width="33%"&gt;&lt;span style="font-weight: normal;"&gt;Move to the End of the current line&lt;/span&gt;&lt;/td&gt;&lt;td width="33%"&gt;&lt;span style="font-weight: normal;"&gt;End&lt;/span&gt;&lt;/td&gt;&lt;td width="33%"&gt;&lt;span style="font-weight: normal;"&gt;Command-Right Arrow&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Move to the Beginning of the Current Line&lt;/td&gt;&lt;td width="33%"&gt;&lt;span style="font-weight: normal;"&gt;Home&lt;/span&gt;&lt;/td&gt;&lt;td width="33%"&gt;&lt;span style="font-weight: normal;"&gt;Command-Left Arrow&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Move to the End of a Document&lt;/td&gt;&lt;td width="33%"&gt;&lt;span style="font-weight: normal;"&gt;Cntrl-End&lt;/span&gt;&lt;/td&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Command-Down Arrow&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Move to the Beginning of a Document&lt;/td&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Cntrl-Home&lt;/td&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Command-Up Arrow&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Delete Text to the right of the cursor.&lt;/td&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Delete&lt;/td&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Fn-Delete&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Find Next&lt;/td&gt;&lt;td style="font-weight: normal;" width="33%"&gt;F3&lt;/td&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Command-G&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Switch Running Applications&lt;/td&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Alt-Tab&lt;/td&gt;&lt;td style="font-weight: normal;" width="33%"&gt;Command-Tab&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;b&gt;&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-8950491357793930385?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/8950491357793930385/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=8950491357793930385' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/8950491357793930385'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/8950491357793930385'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2009/02/switching-from-windows-to-macbook.html' title='Switching from Windows to a Macbook'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-4258744917754791703</id><published>2008-12-22T20:11:00.001-08:00</published><updated>2010-02-11T19:36:30.248-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Blogging'/><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><title type='text'>Publishing to Blogger with Google Docs</title><content type='html'>When I first started publishing to Blogger, I was extremely disappointed with the WYSIWG editor. Simple tasks such as inserting tables or images take a lot of time and you have to usually wind up writing HTML code to do it right. I have been looking for a better solution to do my blogging. &lt;br&gt;&lt;br&gt;&lt;b&gt;Google Docs&lt;br&gt;&lt;/b&gt;I recently took &lt;a title="Google Docs" href="http://docs.google.com" id="wbcs"&gt;Google Docs&lt;/a&gt; out for a test drive and was impressed with how easy it was to write rich text documents through a web page. You can easily make format changes, build tables, and insert images. Google Docs also allows you to create presentations and spreadsheets. &lt;br&gt;&lt;br&gt;&lt;b&gt;Posting to Blogger with Google Docs&lt;/b&gt;&lt;br&gt;While working on a test document, I noticed there is a share button on the top right hand corner of the page. When you click the Share button, there are a couple of options available. If you select Publish as Web Page, you will presented with an option to Post to Blog. There will also be a link there so that you can setup your blog account settings.&amp;nbsp; Once your Blogger account settings are saved in Google Docs, you can now easily post documents from Google Docs to your Blogger blog. Give it a try, I have been using this setup for a few weeks now and I have to say that it is the best way I have found to create Blogger posts. &lt;p/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-4258744917754791703?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/4258744917754791703/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=4258744917754791703' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/4258744917754791703'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/4258744917754791703'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/12/publishing-to-blogger-with-google-docs.html' title='Publishing to Blogger with Google Docs'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-1844645182996333112</id><published>2008-12-22T18:45:00.001-08:00</published><updated>2010-07-04T07:42:27.784-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Merge'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='Diff'/><title type='text'>Meld: Open Source diff and merge tool for Linux</title><content type='html'>When I chose to move over to Linux from Windows on my development computer, I had to find an alternative diff and merge tool as I had been using TortoiseSVN for this functionality. That's when I found about &lt;b&gt;&lt;a href="http://meld.sourceforge.net/" id="bv:_" title="Meld"&gt;Meld&lt;/a&gt;&lt;/b&gt; and I have been pleasantly surprised by this simple yet powerful diff tool.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Easy Installation&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;Since Meld is in the Ubuntu package archives, you can easily install it by opening Applications &amp;gt; Add/Remove. When Add/Remove opens, search for Meld and select to install &lt;i&gt;Meld Diff Viewer&lt;/i&gt;.  From the command line, you can also install Meld through apt with the following command:  &lt;i&gt;sudo apt-get install meld&lt;/i&gt;&lt;a href="http://docs.google.com/File?id=dfdr86r_19hn83qkgg_b" id="zoyl" target="_blank"&gt;&lt;img src="http://docs.google.com/File?id=dfdr86r_19hn83qkgg_b" style="margin: 1em 1em 0pt 0pt; width: 320px; height: 251.72px; float: left;" /&gt;&lt;/a&gt;&lt;b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In Place Editing&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;The main feature that has blown me away with Meld is the capability to edit files while you are comparing them.  Not only can you do normal merge operations with files you are comparing, but you can actually edit the files as though they are in a text editor and Meld does realtime comparisons as you do this.  This really comes in handy in all sorts of situations.&lt;br /&gt;&lt;br /&gt;You can see in the image that while comparing the two files, I decided to throw in some extra text into file2 and it immediately updated the comparison.  Of course if I want to move the change over to file1 all I have to do is click the black arrow and it will update file1.  This is a very powerful feature and really saves time when you need to be able to make changes in a hurry to multiple files.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Easy Integration with RapidSVN&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;If you miss the file comparison feature found in TortoiseSVN under Windows, you can setup Meld to be your file comparison tool under RapidSVN in Linux. In RapidSVN, click on &lt;i&gt;View&lt;/i&gt; from the menu bar and select &lt;i&gt;Preferences&lt;/i&gt;. Once the Preferences Menu opens, click on the Diff Tool tab, type &lt;i&gt;meld &lt;/i&gt;in the command text box and click &lt;i&gt;OK&lt;/i&gt;. Now when you choose to diff files from within RapidSVN, it will use Meld to compare files.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Integration with Nautilus&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://docs.google.com/File?id=dfdr86r_20gtttg7ft_b" id="ekgs" target="_blank"&gt;&lt;img src="http://docs.google.com/File?id=dfdr86r_20gtttg7ft_b" style="margin: 1em 0pt 0pt 1em; width: 320px; height: 299.747px; float: right;" /&gt;&lt;/a&gt;For more siplicity, you can setup Nautilus so that Meld shows up in the right-click menu when you select two or more files. In order to do this, you'll need to install the Nautilus Actions Configuration application. Open up Applications &amp;gt; Add/Remove. When Add/Remove opens search for Nautilus Actions Configuration and install it. Once installed, go to System &amp;gt; Preferences &amp;gt; Nautilus Actions Configuration.  Once it loads, click the Add button.&lt;br /&gt; &lt;ol&gt;&lt;li&gt;Set the Label to Meld. This is the text that will show up when you right click.&lt;br /&gt; &lt;/li&gt;&lt;br /&gt; &lt;li&gt;Set the Icon to wherever your Meld icon image file is.  Mine is located at /usr/share/pixmaps/meld.png.&lt;br /&gt; &lt;/li&gt;&lt;br /&gt; &lt;li&gt;Set the path to meld&lt;br /&gt; &lt;/li&gt;&lt;br /&gt; &lt;li&gt;Set the parameters to %M. If you look at the legend, this will pass in a space-separated list of the selected files/folders with their full paths.&lt;br /&gt; &lt;/li&gt;&lt;br /&gt; &lt;li&gt;Click the Conditions tab.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Set Filenames to * and check the Match Case check box.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Set Mimetypes to */*&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Select the &lt;i&gt;Both&lt;/i&gt; radio button and check the &lt;i&gt;Appears if selection has multiple files or folders &lt;/i&gt;check box under "Appears if selection contains."&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Click OK&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Now when you select two files in Nautilus and right click, you will have a menu item called Meld that will allow you to compare the files.  Nice...&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-1844645182996333112?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/1844645182996333112/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=1844645182996333112' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/1844645182996333112'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/1844645182996333112'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/12/meld-open-source-diff-and-merge-tool.html' title='Meld: Open Source diff and merge tool for Linux'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-8706616725000465665</id><published>2008-12-18T16:31:00.001-08:00</published><updated>2008-12-18T16:41:12.541-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iPhone'/><title type='text'>Pandora for the iPhone</title><content type='html'>I have been using another awesome app for the iPhone which is Pandora.&amp;nbsp; It is just like the &lt;a title="Pandora Internet Radio" href="http://www.pandora.com" id="mv4z"&gt;Pandora Internet Radio&lt;/a&gt; in that you type in a band or song name and it builds a radio station around your entry.&amp;nbsp; You can add radio stations to the app by adding band names and once you have more than one band name, you can do a quick mix which is essentially a mesh of all of the radio stations you have built.&amp;nbsp; This is a really nice app that makes owning the iPhone even better.&amp;nbsp; I listen to this while I'm at work, at the gym, or even while I'm just cleaning the house.&amp;nbsp; It also includes the capability to rate songs that are played so that it can fine tune the types of music you will enjoy.&amp;nbsp; As the iPhone is the first Apple product I have ever owned, I am definitely not a fanboy, but I may be soon.&lt;br&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-8706616725000465665?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/8706616725000465665/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=8706616725000465665' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/8706616725000465665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/8706616725000465665'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/12/pandora-for-iphone.html' title='Pandora for the iPhone'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-270633122463418247</id><published>2008-12-18T13:04:00.001-08:00</published><updated>2010-07-04T09:23:18.388-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title type='text'>How to search for a percent (%) sign in a like query</title><content type='html'>The percent (%) sign in a SQL LIKE query is used as a wildcard.  If you need to look for text containing a percent (%) sign, then you'll have to use an escape character to specify that the SQL database should look for an actual percent sign.  The query below is an example of how to do this:&lt;br /&gt;&lt;pre class="sql" name="code"&gt;SELECT * FROM my_table WHERE some_column LIKE '%\%%' ESCAPE '\';&lt;/pre&gt;&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=javaconfe-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=0596009763&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt;The query above defines the backslash as an escape character so that it will search for any row that has a percent sign in some_column.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-270633122463418247?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/270633122463418247/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=270633122463418247' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/270633122463418247'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/270633122463418247'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/12/how-to-search-for-text-containing.html' title='How to search for a percent (%) sign in a like query'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-2363510630874732887</id><published>2008-12-17T00:04:00.000-08:00</published><updated>2010-07-04T07:50:04.850-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='JFreeChart'/><category scheme='http://www.blogger.com/atom/ns#' term='Graphs'/><category scheme='http://www.blogger.com/atom/ns#' term='Charts'/><title type='text'>Generate Charts and Graphs in Java Using JFreeChart</title><content type='html'>I was recently looking for an open source charting and graphing API for Java when I came across &lt;a href="http://www.jfree.org/jfreechart/"&gt;JFreeChart&lt;/a&gt;. They describe JFreeChart as &lt;i&gt;a free 100% Java chart library that makes it easy for developers to display professional quality charts in their applications&lt;/i&gt;.&lt;br /&gt;&lt;p&gt;One of the first things I noticed was that there is very little to no documentation on how to use JFreeChart and I am assuming that is because they sell their &lt;a href="http://www.jfree.org/jfreechart/devguide.html"&gt;Developer's Guide&lt;/a&gt; to support the project. While that is definitely a good way to support their project, it makes it hard for people to test out the API. So, hopefully, I can help you get started with using JFreeChart. I &lt;strong&gt;strongly encourage&lt;/strong&gt; purchasing the Developer's Guide if you plan on using JFreeChart in your projects.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;A Simple Line Chart&lt;/strong&gt;&lt;br /&gt;We'll take a look at a simple dataset that would be used in a basic line graph using JFreeChart. Our datasets will represent the number of visitors counted at local parks over a 7 day period.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;table style="margin-right: 10px;" align="left" border="1" cellpadding="3" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th colspan="2"&gt;Park 1&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;&lt;strong&gt;Day&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;Number of Visitors&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;10&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;12&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;11&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;39&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;33&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table border="1" cellpadding="3" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th colspan="2"&gt;Park 2&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;&lt;strong&gt;Day&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;Number of Visitors&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;23&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;18&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;52&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;66&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;83&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;We are going to create a graph using the dataset above with the JFreeChart API. The sample class below will show how to generate a line graph using the data above.&lt;br /&gt;&lt;/p&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;package org.javaconfessions.sample;&lt;br /&gt;import org.jfree.chart.ChartFactory;&lt;br /&gt;import org.jfree.chart.JFreeChart;&lt;br /&gt;import org.jfree.chart.plot.PlotOrientation;&lt;br /&gt;import org.jfree.data.xy.XYSeries;&lt;br /&gt;import org.jfree.data.xy.XYSeriesCollection;&lt;br /&gt;import org.jfree.chart.ChartUtilities;&lt;br /&gt;&lt;br /&gt;import java.io.File;&lt;br /&gt;import java.io.FileOutputStream;&lt;br /&gt;&lt;br /&gt;class XYChartSample {&lt;br /&gt;&lt;br /&gt;public void buildChart() throws Exception {&lt;br /&gt;&lt;br /&gt;   XYSeriesCollection dataset = new XYSeriesCollection();&lt;br /&gt;   XYSeries xySeries = new XYSeries( "Park 1" );&lt;br /&gt;   xySeries.add( 1, 10 );&lt;br /&gt;   xySeries.add( 2, 4 );&lt;br /&gt;   xySeries.add( 3, 6 );&lt;br /&gt;   xySeries.add( 4, 12 );&lt;br /&gt;   xySeries.add( 5, 11 );&lt;br /&gt;   xySeries.add( 6, 29 );&lt;br /&gt;   xySeries.add( 7, 33 );&lt;br /&gt;&lt;br /&gt;   XYSeries xySeries2 = new XYSeries( "Park 2" );&lt;br /&gt;   xySeries2.add( 1, 23 );&lt;br /&gt;   xySeries2.add( 2, 15 );&lt;br /&gt;   xySeries2.add( 3, 18 );&lt;br /&gt;   xySeries2.add( 4, 5 );&lt;br /&gt;   xySeries2.add( 5, 52 );&lt;br /&gt;   xySeries2.add( 6, 66 );&lt;br /&gt;   xySeries2.add( 7, 83 );&lt;br /&gt;&lt;br /&gt;   dataset.addSeries( xySeries );&lt;br /&gt;   dataset.addSeries( xySeries2 );&lt;br /&gt;&lt;br /&gt;   JFreeChart chart = ChartFactory.createXYLineChart( "Park Chart",&lt;br /&gt;                                                      "Day",&lt;br /&gt;                                                      "# of Visitors",&lt;br /&gt;                                                      dataset,&lt;br /&gt;                                                      PlotOrientation.VERTICAL,&lt;br /&gt;                                                      true,&lt;br /&gt;                                                      false,&lt;br /&gt;                                                      false );&lt;br /&gt;&lt;br /&gt;   FileOutputStream out = new FileOutputStream( new File( "parkchart.png" ) );&lt;br /&gt;   ChartUtilities.writeChartAsPNG( out, chart, 400, 200 );&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;This is just a basic example of how you can generate charts using JFreeChart. You can see at the end I also show an example of another useful feature found in JFreeChart, the capability to write out charts as images. In this example, I wrote out the chart as a PNG file. Here is an example of how that chart would look if you ran the code above.&lt;br /&gt;&lt;p&gt;&lt;img src="http://i387.photobucket.com/albums/oo314/mikalveli/parkchart.png" /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-2363510630874732887?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/2363510630874732887/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=2363510630874732887' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/2363510630874732887'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/2363510630874732887'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/10/generate-charts-and-graphs-in-java.html' title='Generate Charts and Graphs in Java Using JFreeChart'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-7219632037656252945</id><published>2008-10-28T09:11:00.000-07:00</published><updated>2010-07-04T07:44:53.590-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Developer'/><category scheme='http://www.blogger.com/atom/ns#' term='PL/SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Better Performance with Oracle SQL Developer in Ubuntu Linux</title><content type='html'>Having switched to Ubuntu recently on my work machine I have been hooking up to our databases using Oracle's SQL Developer. One major issue that I have had is that sometimes SQL Developer would get hung while attempting to the databases.  The connecting status dialog would pop up, but it would never actually connect.&lt;br /&gt;&lt;p&gt;It would usually be solved by restarting SQL Developer a few times, but it got to be rather annoying. I decided to devote a little time to trying to find a solution for this little annoyance and I believe I may have cured my SQL Developer connection woes by changing to the OCI/Thick JDBC Driver.&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;In SQL Developer go to Tools &gt; Preferences to open the Preferences menu.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Expand the Database section and click Advanced Parameters.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Then check the box labeled "Use OCI/Thick driver".&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Restart SQL Developer&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-7219632037656252945?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/7219632037656252945/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=7219632037656252945' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/7219632037656252945'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/7219632037656252945'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/10/better-performance-with-oracle-sql.html' title='Better Performance with Oracle SQL Developer in Ubuntu Linux'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-3352148438526370200</id><published>2008-10-11T04:33:00.000-07:00</published><updated>2010-07-04T07:47:09.200-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Invalid Mount Options Error When Mounting External Hard Drive in Ubuntu Linux</title><content type='html'>Being a recent convert to Ubuntu Linux, I ran into a problem that others may have experienced.  When I plugged in my usb external hard drive I received an Invalid Mount Options error.  I found a lot of information on the forums, but nothing was working.  However, I discovered that Ubuntu was basically attempting to mount my FAT32 external hard drive as a CD-ROM.  In order to fix this problem you need to edit /etc/fstab and comment out the line below by putting a # at the beginning of the line:&lt;br /&gt;&lt;pre&gt;/dev/sdb1       /media/cdrom0   udf,iso9660 user,noauto,exec,utf8 0       0&lt;br /&gt;&lt;/pre&gt;The line should look like this after the edit:&lt;br /&gt;&lt;pre&gt;#/dev/sdb1       /media/cdrom0   udf,iso9660 user,noauto,exec,utf8 0       0&lt;br /&gt;&lt;/pre&gt;After this change, voila, the drive mounts as desired.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-3352148438526370200?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/3352148438526370200/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=3352148438526370200' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/3352148438526370200'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/3352148438526370200'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/10/invalid-mount-options-error-when.html' title='Invalid Mount Options Error When Mounting External Hard Drive in Ubuntu Linux'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-624386816564649950</id><published>2008-09-28T10:16:00.000-07:00</published><updated>2008-12-17T15:18:25.951-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Convert Between Base 10, Base 62, Base 36, Base 16, Base 8, Base 2 in Java</title><content type='html'>I've already written how you can &lt;a href="http://javaconfessions.blogspot.com/2008/09/convert-between-base-10-and-base-62-in.html"&gt;Convert Between Base 10 and Base 62 in PL/SQL&lt;/a&gt;, and in this post I'll show you how to convert between base 10 and base 62 in Java.  Well, actually you can pretty much convert between anything you want using the Java utility class below.  Enjoy!&lt;br /&gt;&lt;p/&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;package org.javaconfessions.baseconverter;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public class BaseConverterUtil {&lt;br /&gt;&lt;br /&gt;    private static final String baseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";&lt;br /&gt;&lt;br /&gt;    public static String toBase62( int decimalNumber ) {&lt;br /&gt;        return fromDecimalToOtherBase( 62, decimalNumber );&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static String toBase36( int decimalNumber ) {&lt;br /&gt;        return fromDecimalToOtherBase( 36, decimalNumber );&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static String toBase16( int decimalNumber ) {&lt;br /&gt;        return fromDecimalToOtherBase( 16, decimalNumber );&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static String toBase8( int decimalNumber ) {&lt;br /&gt;        return fromDecimalToOtherBase( 8, decimalNumber );&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static String toBase2( int decimalNumber ) {&lt;br /&gt;        return fromDecimalToOtherBase( 2, decimalNumber );&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static int fromBase62( String base62Number ) {&lt;br /&gt;        return fromOtherBaseToDecimal( 62, base62Number );&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static int fromBase36( String base36Number ) {&lt;br /&gt;        return fromOtherBaseToDecimal( 36, base36Number );&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static int fromBase16( String base16Number ) {&lt;br /&gt;        return fromOtherBaseToDecimal( 16, base16Number );&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static int fromBase8( String base8Number ) {&lt;br /&gt;        return fromOtherBaseToDecimal( 8, base8Number );&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static int fromBase2( String base2Number ) {&lt;br /&gt;        return fromOtherBaseToDecimal( 2, base2Number );&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private static String fromDecimalToOtherBase ( int base, int decimalNumber ) {&lt;br /&gt;        String tempVal = decimalNumber == 0 ? "0" : "";&lt;br /&gt;        int mod = 0;&lt;br /&gt;&lt;br /&gt;        while( decimalNumber != 0 ) {&lt;br /&gt;            mod = decimalNumber % base;&lt;br /&gt;            tempVal = baseDigits.substring( mod, mod + 1 ) + tempVal;&lt;br /&gt;            decimalNumber = decimalNumber / base;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        return tempVal;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private static int fromOtherBaseToDecimal( int base, String number ) {&lt;br /&gt;        int iterator = number.length();&lt;br /&gt;        int returnValue = 0;&lt;br /&gt;        int multiplier = 1;&lt;br /&gt;&lt;br /&gt;        while( iterator &gt; 0 ) {&lt;br /&gt;            returnValue = returnValue + ( baseDigits.indexOf( number.substring( iterator - 1, iterator ) ) * multiplier );&lt;br /&gt;            multiplier = multiplier * base;&lt;br /&gt;            --iterator;&lt;br /&gt;        }&lt;br /&gt;        return returnValue;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-624386816564649950?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/624386816564649950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=624386816564649950' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/624386816564649950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/624386816564649950'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/09/convert-between-base-10-and-base-62-in_28.html' title='Convert Between Base 10, Base 62, Base 36, Base 16, Base 8, Base 2 in Java'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-6151431157667214220</id><published>2008-09-27T08:20:00.001-07:00</published><updated>2008-12-16T21:09:15.632-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='SSH'/><category scheme='http://www.blogger.com/atom/ns#' term='SSHTools'/><title type='text'>Part Three - SSH Channels</title><content type='html'>&lt;span style="font-family:Verdana,Arial,Helvetica,sans-serif;"&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;We need to understand the SSH channel process in order to continue,    so what are channels? All terminal sessions, forwarded connections, etc. are    channels. Either side may open a channel and multiple channels are multiplexed    into a single connection. Channels are flow-controlled, that is no data may    be sent to a channel until a message is received to indicate that window space    is available.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;Channels can be whatever you want them to be, there are many    channel types already defined within the SSH protocol specification, such as    the 'session' or 'tcpip-forward' channels. These are the mechanism that provide    the transport for your session and port forwarding data.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;When you want to open a channel you send a request to the SSH    server, the server will then either respond to that request with a confirmation    or failure message. Your channel is identified by a name, for instance lets    say we want to create a channel to echo information back to the client, we would    call the channel "echo@3sp.com";. You should always name your channel    using the name@domain syntax.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;J2SSH provides a mechanism for developing custom channels, the    com.sshtools.j2ssh.connection package contains a number of classes to help you.    First the Channel class is the abstract base for all channels. Lets take a look    at its abstract methods, the first method is self explainitory, it returns the    name/type of the channel.&lt;/span&gt;&lt;/p&gt; &lt;/span&gt;  &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;public String getChannelType() {&lt;br /&gt;return "echo@3sp.com";&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; &lt;/blockquote&gt; &lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;p&gt;The next two methods  provide the settings for the flow control. The values returned by the following  mehtods set the boundary for the window space. The channel will never provide  more window space than the maximum and will increase window space automatically  (back up to the maximum) when the minimum is reached. &lt;/p&gt; &lt;/span&gt;  &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;protected int getMinimumWindowSpace() {&lt;br /&gt;return 1024;&lt;br /&gt;}&lt;br /&gt;protected int getMaximumWindowSpace() {&lt;br /&gt;return 65535;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;The maximum packet    size setting is the maximum amount of data that the remote side can send in    one single packet. This value should not exceed the maximum window space.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;    &lt;pre name="code" class="java"&gt;protected int getMaximumPacketSize() {&lt;br /&gt;return 32768;&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;When a request is made to    open a channel, the client can send some data with the open request so that    the server may process the request based on additional information. Your channel    should return this information (if any) in the getChannelOpenData method, if    there is no data simply return null.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;    &lt;pre name="code" class="java"&gt;public byte[] getChannelOpenData() {&lt;br /&gt;return null;&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;When the server confirms    that the channel is open it can also provide data in response to the channel    open information. It does so by returning this information in the getChannelConfirmationData    method. Again if no data is required to be sent to the remote side simply return    null.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;public byte[] getChannelConfirmationData() {&lt;br /&gt;return null;&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Once the channel    has been opened, the channel mechanism calls the channels onChannelOpen method.    You should not perform any expensive processing in this method since it will    lock up the protocol and you will not be able to send data. &lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;protected void onChannelOpen() throws java.io.IOException {&lt;br /&gt;/** Your channel is open so do stuff if you want **/&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Once the channel    is open you can send data using the channels sendChannelData method, this type    of data is received by the channel with the following method.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;protected void onChannelData(SshMsgChannelData msg) throws java.io.IOException {&lt;br /&gt;// Channel data has arrived, process it!&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;There is also an    extended data channel which can be used, the extended data has a type field    which can be used to identify different application defined data types. This    is received with the onChannelExtData method and sent with sendChannelExtData.&lt;/span&gt;&lt;/p&gt;    &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;protected void onChannelExtData(SshMsgChannelExtendedData msg) throws java.io.IOException {&lt;br /&gt;/**@todo Implement this com.sshtools.j2ssh.connection.Channel abstract method*/&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;There is also a    request mechanism seperate to the channel data which can be used. This provides    named based requests. For example in our echo channel we could have a request    to turn echo on and off. Requests are recieved with the onChannelRequet method    and sent with sendChannelRequest.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;protected void onChannelRequest(String requestname, boolean wantreply, byte[] requestdata)&lt;br /&gt;throws java.io.IOException {&lt;br /&gt;/**@todo Implement this com.sshtools.j2ssh.connection.Channel abstract method*/&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;When you no longer    wish to send data you can set the local side to EOF by using setLocalEOF. When    the remote server sends EOF the onChannelEOF method is called.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;protected void onChannelEOF() throws java.io.IOException {&lt;br /&gt;/**@todo Implement this com.sshtools.j2ssh.connection.Channel abstract method*/&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Finally, to close the channel    you can use the close method. When the channel is closed by either side the    onChannelClose method is called.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;protected void onChannelClose() throws java.io.IOException {&lt;br /&gt;/**@todo Implement this com.sshtools.j2ssh.connection.Channel abstract method*/&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;!--pagebreak--&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Ok so now we know the basic    structure how do we implement our channel and use it from either side of the    connection? Heres our server side channel implelentation. This simply returns    any data sent to it if echo is on.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;public class EchoChannel extends Channel {&lt;br /&gt;&lt;br /&gt;boolean echo = true;&lt;br /&gt;&lt;br /&gt;public EchoChannel() {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String getChannelType() {&lt;br /&gt; return "echo@3sp.com";;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected void onChannelRequest(String requestname, boolean wantreply, byte[]&lt;br /&gt;              requestdata) throws java.io.IOException {&lt;br /&gt;  if(requestname.equals("echo-off@3sp.com";)) {&lt;br /&gt;    echo = false;&lt;br /&gt;    if(wantreply)&lt;br /&gt;       connection.sendChannelRequestSuccess(this);&lt;br /&gt;    return;&lt;br /&gt;   } else if(requestname.equals("echo-on@3sp.com";)) {&lt;br /&gt;    echo = true;&lt;br /&gt;    if(wantreply)&lt;br /&gt;      connection.sendChannelRequestSuccess(this);&lt;br /&gt;    return;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  if(wantreply)&lt;br /&gt;    connection.sendChannelRequestFailure(this);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected void onChannelExtData(SshMsgChannelExtendedData msg) throws java.io.IOException {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected void onChannelData(SshMsgChannelData msg) throws java.io.IOException {&lt;br /&gt; if(echo)&lt;br /&gt;  sendChannelData(msg.getChannelData());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected int getMaximumPacketSize() {&lt;br /&gt;return 32768;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected void onChannelEOF() throws java.io.IOException {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected void onChannelClose() throws java.io.IOException {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public byte[] getChannelOpenData() {&lt;br /&gt;return null;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected int getMinimumWindowSpace() {&lt;br /&gt;return 1024;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected int getMaximumWindowSpace() {&lt;br /&gt;return 65535;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected void onChannelOpen() throws java.io.IOException {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public byte[] getChannelConfirmationData() {&lt;br /&gt;return null;&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Now we need to    configure the server to accept the channel and create an instance of our EchoChannel    when a request is made. To do this we will need to create a ChannelFactory that    can create the channel, this is a simple interface&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;public interface ChannelFactory {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public Channel createChannel(String channelType, byte[] requestData)&lt;br /&gt;    throws InvalidChannelException;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;So lets create an EchoChannelFactory    implementation&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;public class EchoChannelFactory implements ChannelFactory {&lt;br /&gt;&lt;br /&gt; public Channel createChannel(String channelType, byte[] requestData)&lt;br /&gt;       throws InvalidChannelException {&lt;br /&gt;  &lt;br /&gt;     if(channelType.equals("echo@3sp.com";)) {&lt;br /&gt;       return new EchoChannel();&lt;br /&gt;     }&lt;br /&gt;   &lt;br /&gt;     throw new InvalidChannelException("Only echo channels allowed by this factory");&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;So now were ready    to configure the server. In my previous articles you will remember we implemented    the configureServices method of the SshServer? To allow this channel to be opened,    we simply add the following line to the configureServices implementation&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;pre name="code" class="java"&gt;connection.addChannelFactory("echo@3sp.com";, new EchoChannelFactory());&lt;/pre&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Your server should now be    configured to support your channel. So lets look at how to invoke the channel    from the client.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;First we need to create    a client side implementation of the channel, but we need it to be simpler with    a set of IOStreams perhaps??? Well the hard work is already done for you, take    a look at the IOChannel class. This provides an InputStream and OutputStream    for the channels data. Heres the implementation, it has less methods to implement    since the channel data is now handled by the parent class.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;public class EchoChannelClient extends IOChannel {&lt;br /&gt;&lt;br /&gt;public EchoChannelClient() {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public String getChannelType() {&lt;br /&gt;  return "echo@3sp.com";;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected void onChannelRequest(String requestname,&lt;br /&gt;                                 boolean wantreply,&lt;br /&gt;          byte[] data) throws java.io.IOException {&lt;br /&gt;  if(wantreply)&lt;br /&gt;    connection.sendChannelRequestFailure(this);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected int getMaximumPacketSize() {&lt;br /&gt; return 32768;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public byte[] getChannelOpenData() {&lt;br /&gt;  return null;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected int getMinimumWindowSpace() {&lt;br /&gt;  return 1024;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected void onChannelOpen() throws java.io.IOException {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected int getMaximumWindowSpace() {&lt;br /&gt;  return 65535;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public byte[] getChannelConfirmationData() {&lt;br /&gt;  return null;&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;We need to add    a method for turning the echo on and off.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;public void setEcho(boolean echo) throws java.io.IOException {&lt;br /&gt;if(echo)&lt;br /&gt;  connection.sendChannelRequest(this, "echo-on@3sp.com";, false, null);&lt;br /&gt;else&lt;br /&gt;  connection.sendChannelRequest(this, "echo-off@3sp.com";, false, null);&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Now were ready    to go since any data we write to the channels outputstream, which we obtain    by using getOutputStream will be returned to the InputStream if echo is on.&lt;/span&gt;&lt;/p&gt; &lt;p&gt; &lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;To use the channel using    an SshClient instance simply&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;EchoChannelClient echo = new EchoChannelClient();&lt;br /&gt;&lt;br /&gt;if(ssh.openChannel(echo)) {&lt;br /&gt;// Channel is open&lt;br /&gt;echo.getOutputStream().write("hello world!".getBytes());&lt;br /&gt;&lt;br /&gt;// Read it back from the inputstream&lt;br /&gt;byte[] buf = new byte[32];&lt;br /&gt;echo.getInputStream().read(buf);&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; So of course your    requirements are probably much more complex, if you want the server to handle    IOStreams you can use the IOChannel instead of the Channel, in the end its up    to you....... with a little imagination ;-) &lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-6151431157667214220?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/6151431157667214220/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=6151431157667214220' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/6151431157667214220'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/6151431157667214220'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/09/part-three-ssh-channels.html' title='Part Three - SSH Channels'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-8874041907662823229</id><published>2008-09-27T08:18:00.001-07:00</published><updated>2010-02-11T19:38:51.922-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='SSH'/><category scheme='http://www.blogger.com/atom/ns#' term='SSHTools'/><title type='text'>Part Two - Building an SSH server to provide your applications services.</title><content type='html'>&lt;span style="font-family:Verdana,Arial,Helvetica,sans-serif;"&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;In the previous part of this article I showed you how to secure    your client-application server by using J2SSH to create an embeded tunnel to    an SSH server installed on the same host as your server. Whilst the tunnel is    secure it does not provide access to the strong public key authentication that    SSH provides. In this article we take no prisoners, were going to implement    an SSH server and transfer your existing application server functionality into    the SSH server itself so that your application can take advantage of public    key authentication and other SSH services such as SFTP. &lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;em&gt;&lt;strong&gt;Starting the basic framework server&lt;/strong&gt;&lt;/em&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;First things first, even before you think about how to get your        existing application functionality into the SSH server, you need to get the        server itself running and accepting each connection and authenticating the user.  Make sure you have the source version of J2SSH since we're going copy the &lt;code&gt;com.sshtools.daemon.SshDaemon&lt;/code&gt; source code to create your server. &lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;If you examine this class you will see that          it has a main method and so we're going to use this class to configure, start          and stop your server.Lets not worry about what the SshDaemon is doing right now,          lets just make sure we can start and stop the server. You may have noticed that          the main method allows a couple of command line arguments -start and -stop.          No guessing for what these do! Before we start the server there are a couple          of configuration items we need to attend to. First of all the server needs a    public key to identify itself to clients. &lt;/span&gt;&lt;span style="font-size:85%;"&gt;Generate a key pair using the J2SSH    command line utility ssh-keygen.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;code&gt;¢ ssh-keygen.bat -t dsa -b 1024 server_host_key&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;When prompted to enter a passprase simply press return and confirm            that you do not want to encrypt the private key, server host keys cannot be      encrypted since there is no where to store the passphrase! &lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;Copy the host key into the J2SSH conf directory, whilst you're              in there open up the server configuration file &lt;em&gt;server.xml&lt;/em&gt; and I'll take you              over some of the other options. Make sure that there is a &lt;serverhostkey&gt; element whose PrivateKeyFile attribute is pointing to the private key file you      have just generated. &lt;/serverhostkey&gt;&lt;/span&gt;&lt;code&gt;&lt;serverhostkey privatekeyfile="server_host_key"&gt;&lt;/serverhostkey&gt;&lt;/code&gt;&lt;/p&gt; &lt;p&gt; &lt;span class="pn-normal"&gt;&lt;span style="font-family:Verdana,Arial,Helvetica,sans-serif;"&gt;&lt;code&gt;&lt;serverhostkey privatekeyfile="server_host_key"&gt;&lt;/serverhostkey&gt;&lt;/code&gt;&lt;/span&gt;&lt;/span&gt; &lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;Next make sure that the &lt;code&gt;&lt;port&gt;&lt;/port&gt;&lt;/code&gt; element is                  set to the port you wish your server to bind, if you have another SSH server            running you might want to change this to a non standard port for now.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;Finally the &lt;code&gt;&lt;commandport&gt;&lt;/commandport&gt;&lt;/code&gt;    &lt;span class="pn-normal"&gt;&lt;span style="font-family:Verdana,Arial,Helvetica,sans-serif;"&gt;&lt;span style="font-size:85%;"&gt;&lt;code&gt;&lt;commandport&gt;&lt;/commandport&gt;&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; element is the                    local port which the server listens for commands, there is only one command              currently implemented and that is stop. &lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;You should now be able to start the server by executing the    SshDaemon class, you will need to set the sshtools.home System property to point    to the root installation directory of J2SSH. This will be used to find the XMl    configuration files. Once you have the server running (remember to pass in the    -start option on the command line) it should accept connections, but if you    connect and try to authenticate it will fail because there is no authentication    provider installed. So that's our next step.&lt;/span&gt;&lt;/p&gt; &lt;/span&gt; &lt;!--pagebreak--&gt; &lt;span style="font-family:Verdana,Arial,Helvetica,sans-serif;"&gt;  &lt;strong&gt;&lt;span style="font-size:85%;"&gt;&lt;em&gt;Creating an authentication provider&lt;/em&gt;&lt;/span&gt;  &lt;/strong&gt;  &lt;p&gt;&lt;span style="font-size:85%;"&gt;The authentication provider allows you to define how users are    authenticated when they connect to the SSH server. Your application may already    have a mechanism for this, perhaps by searching a database table, or an encrypted    password file. In any case you will want to transfer this process to the authentication    provider, since I cannot help you on that front, I will show you how to implement    a basic mechanism and explain the methods you are required to provide. To get    things moving perhaps you should just implement this with me to see how the    process fits together.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;The abstract &lt;code&gt;NativeAuthenticationProvider&lt;/code&gt; is where    we start, we are going to extend this class to implement an authentication provider    that examines the user name and logs them into the system. For simplicity we    will hard code this in this example.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;pre name="code" class="java"&gt;class MyAuthenticationProvider extends NativeAuthenticationProvider {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;Now lets look at the methods we need to implement, first there    is &lt;code&gt;getHomeDirectory&lt;/code&gt;. This should return the home directory of the    user whose username is passed as a parameter into the method. This will be used    for public key configuration and also servers as the default directory for the    SFTP server that the framework will provide.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;pre name="code" class="java"&gt;public String getHomeDirectory(String username)&lt;br /&gt;       throws IOException {&lt;br /&gt;return "/home/users/martianx";&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;There are two &lt;code&gt;logonUser&lt;/code&gt; methods that we need to    implement next, the first provides a username and password which should be checked.    If the account exists and the password is correct you should perform any processing    that would log the user into the system and return true to indicate that the    logon was a success. Optionally you can throw a password change exception if    the users password has expired (more about that later).&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;public boolean logonUser(String username,&lt;br /&gt;                      String password)&lt;br /&gt;  throws PasswordChangeException,&lt;br /&gt;         IOException {&lt;br /&gt;&lt;br /&gt;return username.equals("martianx")&lt;br /&gt;         &amp;amp;&amp;amp; password.equals("foo"));&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;The second &lt;code&gt;logonUser&lt;/code&gt; method only provides the username.    This is called when a user log's into the system using public key authentication.    When the method is called the server has already verified the identity of the    user through their public key so you should automatically log the user in without    restriction.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;pre name="code" class="java"&gt;public boolean logonUser(String username) throws IOException {&lt;br /&gt;&lt;br /&gt;return true; // This is for public key authentication and will only&lt;br /&gt;            // be called once a key has been verified&lt;br /&gt; &lt;br /&gt;} &lt;/pre&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;The &lt;code&gt;logoff&lt;/code&gt; User method simply should log the user    out of the system, performing any necersary processing that your application    server requires. In our example we will do nothing&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;pre name="code" class="java"&gt;public void logoffUser() throws IOException {&lt;br /&gt;// do nothing yet&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;Finally the &lt;code&gt;changePassword&lt;/code&gt; method is called if    you had previously had thrown a &lt;code&gt;PasswordChangeException&lt;/code&gt; from the    &lt;code&gt;logonUser&lt;/code&gt; method. This method should change the password and return    its success (or failure). Our example will return false since we do not support    password change yet.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;public boolean changePassword(String username,&lt;br /&gt;                           String oldpassword,&lt;br /&gt;                           String newpassword) {&lt;br /&gt;return false;   // We dont support this yet&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;So that's the authentication provider implemented, you should    have a good idea about how to go about integrating your servers authentication    mechanism now? But first we need to have a look at this provider in action,    so the next step is to configure the server to load the provider at startup.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;em&gt;The platform configuration file&lt;/em&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;The providers are configured in a platform configuration file.    The actual name of the file should be set to your application's name, but an    example is provided in the J2SSH distribution and its called &lt;code&gt;platform.xml&lt;/code&gt;.    Lets copy the file and create &lt;code&gt;myplatform.xml &lt;/code&gt;and configure it for    our new authentication provider.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;In the file locate the &lt;code&gt;&lt;nativeauthenticationprovider&gt;&lt;/nativeauthenticationprovider&gt;&lt;/code&gt;    element and enter the FQN of the authentication implementation we just created.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;code&gt;&lt;nativeauthenticationprovider&gt; &lt;span class="pn-normal"&gt;&lt;span style="font-family:Verdana,Arial,Helvetica,sans-serif;"&gt;&lt;code&gt;&lt;nativeauthenticationprovider&gt;com.myplatform.MyAuthenticationProvider&lt;/nativeauthenticationprovider&gt;&lt;/code&gt;&lt;/span&gt;&lt;/span&gt; &lt;/nativeauthenticationprovider&gt;&lt;/code&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;Save the file and before we start the server we need to make    sure that the server will load the provider by setting a VM parameter, use&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;code&gt;-Dsshtools.platform=myplatform.xml&lt;/code&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt; Now start the server and try to connect using a standard SSH    client and the authentication information we set in our example. The connection    will still fail but you should get prompted for autehntication information and    see an error message, for example using Putty as a client will probably show    a pty refused message. This is actually a success since the pty is only requested    once authentication has succeeded.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;The next step is to remove this error message and were going    to acheive that by creating a &lt;code&gt;NativeProcessProvider&lt;/code&gt;.&lt;/span&gt;&lt;/p&gt; &lt;/span&gt; &lt;!--pagebreak--&gt; &lt;span style="font-family:Verdana,Arial,Helvetica,sans-serif;"&gt;  &lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;em&gt;&lt;strong&gt;Creating a NavtiveProcessProvider&lt;/strong&gt;&lt;/em&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;The NativeProcessProvider allows the server to provide shell    access and other session based services such as command execution. But you don't    want a terminal I hear you say? Well that's fine but since your using the SSH    framework your going to have to provide one, and you never know what you might    be able to do in the future with a little imagination. For example one of the    things I like to do is to provide terminal access to user accounts for self    serve account maintenance, allowing them to login using a standard SSH client    and change their password account details. It's always a good idea to allow    some form of access into your application server that any standard client can    access. What if your out of the office and really need to log in to change something,    but don't have your laptop, connect using the SSHTerm applet and your connected    again!&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;So what we are going to implement today is a basic terminal    that outputs the message "This server does not provide shell access"    and then disconnects. Let's start by declaring our class which extends &lt;code&gt;NativeProcessProvider&lt;/code&gt;&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;public class UnsupportedShellProcess extends NativeProcessProvider {&lt;br /&gt;private static String message = "This server does not provide shell access";&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;An instance of this class will be created for each session that    is created, the process is required to provide the standard set of IO streams    stdin, stdout and stderr. We will simply use a dynamic buffer class that J2SSH    (which is similar to Piped streams) that will allow us to output something from    the other end of the stream which will be read by the connected client. &lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;    &lt;pre name="code" class="java"&gt;&lt;br /&gt;import com.sshtools.j2ssh.io.DynamicBuffer;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;DynamicBuffer stdin = new DynamicBuffer();&lt;br /&gt;DynamicBuffer stderr = new DynamicBuffer();&lt;br /&gt;DynamicBuffer stdout = new DynamicBuffer();&lt;br /&gt;&lt;br /&gt;public InputStream getInputStream() throws IOException {&lt;br /&gt;return stdin.getInputStream();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public OutputStream getOutputStream() throws IOException {&lt;br /&gt;return stdout.getOutputStream();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public InputStream getStderrInputStream() {&lt;br /&gt;return stderr.getInputStream();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;When a command or shell is executed, the framework first requests    that your provider create the process by calling the &lt;code&gt;createProcess&lt;/code&gt;    method, this method should initialize your provider with command and environment    provided BUT NOT start the command. The framework will then start it sepeartley    with a call to &lt;code&gt;start&lt;/code&gt;. Since were writing a basic implementation    we dont need to setup the process so were ust going to return true to indicate    that the command is reading to start.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;public boolean createProcess(String command,&lt;br /&gt;                          Map environment)&lt;br /&gt;      throws IOException {&lt;br /&gt;&lt;br /&gt;// Of course this could be used to provide a wealth of features&lt;br /&gt;// according to the executed command and the environment&lt;br /&gt;return true;&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt; Now when the process is started we output our message&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;pre name="code" class="java"&gt;public void start() throws IOException {&lt;br /&gt;stdin.getOutputStream().write(message.getBytes());&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Next the process    is required to provide a default terminal provider, this is used in place of    a command when the user requests to start a shell and so will be the command    argument when &lt;code&gt;createProcess&lt;/code&gt; is called, were not going to read this    so just supply any string.&lt;/span&gt;&lt;/p&gt;  &lt;blockquote&gt;&lt;pre name="code" class="java"&gt;public String getDefaultTerminalProvider() {&lt;br /&gt;return "UnsupportShell";&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;  &lt;p&gt;&lt;span style="font-size:85%;"&gt;The client may request a pseudo terminal, again this is for    a more advanced implementation than we need so in order to make sure that no    client bombs out because we don't allocate one, we implement these methods to    show we support and have allocated a terminal.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;pre name="code" class="java"&gt;public boolean supportsPseudoTerminal(String term) {&lt;br /&gt; return true;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;public boolean allocatePseudoTerminal(String term,&lt;br /&gt;                                   int cols,&lt;br /&gt;                                   int rows,&lt;br /&gt;                                   int width,&lt;br /&gt;                                   int height,&lt;br /&gt;                                   String modes) {&lt;br /&gt;return true;&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;The kill method should end the process, we will simply close all the buffers&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;public void kill() {&lt;br /&gt;try {&lt;br /&gt; stdin.close();&lt;br /&gt;}&lt;br /&gt;catch (IOException ex) {&lt;br /&gt;}&lt;br /&gt;try {&lt;br /&gt; stdout.close();&lt;br /&gt;}&lt;br /&gt;catch (Exception ex1) {&lt;br /&gt;}&lt;br /&gt;try {&lt;br /&gt; stderr.close();&lt;br /&gt;}&lt;br /&gt;catch (Exception ex2) {&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;We need to provide the server with an evaluation on the process    to determine whether its still active. We will return active whilst the whole    message has not been read&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;public boolean stillActive() {&lt;br /&gt;try {&lt;br /&gt; return stdin.getInputStream().available() &gt; 0;&lt;br /&gt;}&lt;br /&gt;catch (IOException ex) {&lt;br /&gt; return false;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;Finally this method should wait for the process to complete    and then return the exit code. We are already planning on deprecating this method    to provide a callback method but since its still here we need to implemenet    it even if it is rather a crude implementation. We will simple wait for the    message to be read and then return.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;public int waitForExitCode() {&lt;br /&gt;try {&lt;br /&gt; while (stdin.getInputStream().available() &gt; 0) {&lt;br /&gt;   try {&lt;br /&gt;     Thread.sleep(1000); // Crude but necersary&lt;br /&gt;   }&lt;br /&gt;   catch (InterruptedException ex) {&lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;catch (IOException ex1) {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;As you can see quite an easy implementation, when a connection    is made that requests a shell or to execute a command the command will simply    write out the message and once the message has been read the process will close.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;To configure this in the platform configuration file you should    set the &lt;nativeprocessprovider&gt; element to point to your class implementation.    If you run your server now and connect, you should no longer see the pty error    message but instead should see the following text followed by a disconnect.&lt;/nativeprocessprovider&gt;&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;code&gt;"This server does not provide shell access"&lt;/code&gt;&lt;/blockquote&gt; &lt;/span&gt; &lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Now you should have  a working SSH server which also provides SFTP access to your users. In the final  part of this article I will show you how to implement an SSH channel and configure  your client and server so that they directly talk to each other through SSH.&lt;/span&gt;&lt;p/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-8874041907662823229?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/8874041907662823229/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=8874041907662823229' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/8874041907662823229'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/8874041907662823229'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/09/part-two-building-ssh-server-to-provide.html' title='Part Two - Building an SSH server to provide your applications services.'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-32232975834746840</id><published>2008-09-27T08:17:00.001-07:00</published><updated>2010-02-11T19:39:44.084-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='SSH'/><category scheme='http://www.blogger.com/atom/ns#' term='SSHTools'/><title type='text'>Part 1  - Securing your client-server application with J2SSH</title><content type='html'>&lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Using J2SSH is    a great way to secure and enhance your insecure client-server application (or    improve an SSL based one). Now it certainly would be a great idea at this point    to spend some time evaluating the different methods of securing an applications    communication, I could waste pages explaining about SSL or teaching you how    to write your proprietary encryption process, but that's not why were here is    it? And it's certainly not why I am here! You're here because you know SSH,    you use it everyday to access every other computer your work on, or at least    you should! You're here because SSH provides strong encryption, integrity checking    and public key authentication of both the client and the server; the thing is    you want your client-server application to provide that too, so that's what    were going to do today. &lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;This tutorial assumes    you have a working knowledge of SSH clients and servers. Most importantly you    should understand the concept of SSH port forwarding. In this series of articles    we will discuss two ways to secure your client-server application&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;em&gt;&lt;strong&gt;1.    Secure existing applications by channelling the TCPIP data through a secure    tunnel to an SSH server installed on the same machine as your application server&lt;/strong&gt;&lt;/em&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;You may have already    used standard SSH port forwarding to setup a secure tunnel to transport your    connection, but maintaining both the SSH client and SSH server in addition to    your own client and server is not a realistic proposition. &lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;The quickest way    to secure your application with J2SSH is to use this very process, but instead    of maintaining an SSH client, you can use J2SSH directly within your client    code.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;em&gt;&lt;strong&gt;2.    Build an SSH server to provide your applications services.&lt;/strong&gt;&lt;/em&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;J2SSH comes with    a set of daemon classes that enable the creation of a custom SSH server in no    time! The SSH server itself is already preconfigured to accept connections so    the main framework is already available. Your responsibility firstly will be    to develop an authentication provider to plug into your existing applications    authentication mechanism, and secondly to provide a channel implementation that    replaces your applications socket communication. There are of course a few more    details but it could not be much simpler! &lt;/span&gt;&lt;/p&gt; &lt;!--pagebreak--&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;br /&gt; &lt;span style=";font-family:Times New Roman,Times,serif;font-size:130%;"  &gt;Securing existing applications by    channelling TCPIP data through a secure tunnel&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;This method essentially    forwards your client-server communication through a secure tunnel just as if    you had setup standard port forwarding between your client host and the server.    The difference is that J2SSH does not require the installation of an SSH client,    instead it allows your client application to connect to the SSH server directly    and instruct the server where to forward the data to thus removing the configuration    nightmare of using port forwarding. &lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;strong&gt;&lt;em&gt;Setup    an SSH server on the same host as your application server&lt;/em&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;First thing we    need to do is to install an SSH server on the same host as your application    server. That's up to you I'm afraid, we cannot help you out there. Once you    have the server installed create an account on the host for your client application,    J2SSH will need to authenticate to the SSH server, so it's a good idea to have    an account for the application, and since we don't want to be putting passwords    into the code we will also want a private key without a passphrase.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Configure your    applications account with the public key and test the connection; you should    be able to connect without any prompting. Finally, setup your application server    to listen on the local loopback address. This will ensure that clients cannot    connect directly.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;strong&gt;&lt;em&gt;Replace    your existing client socket connection with an SSH connection using J2SSH&lt;/em&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Now that we have    a server installed, a private key for your application to authenticate with    and your application server running, we can now turn to the client code changes.    We need to replace your existing connection code with the following process&lt;/span&gt;&lt;/p&gt; &lt;ol&gt;&lt;li&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Create a connection      to the SSH server&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; Authenticate      using the client applications public key&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; Create a tunnel      to your application server&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; Start your      own communication using the tunnel's IO streams&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;br /&gt; Creating the connection is straight forward, you will obviously need to take    into account integrating this code into your own client but the connection procedure    is as follows&lt;/span&gt;&lt;/p&gt; &lt;code&gt; &lt;/code&gt;&lt;blockquote&gt;import com.sshtools.j2ssh.SshClient;&lt;br /&gt;&lt;br /&gt; public SshClient createConnection() {&lt;br /&gt;&lt;blockquote&gt;// Make a client connection SshClient&lt;br /&gt;     ssh = new SshClient();&lt;br /&gt; // Connect to the host&lt;br /&gt; ssh.connect("your-applications-host"); &lt;/blockquote&gt;   } &lt;/blockquote&gt;  &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;   If you run the above code you will notice that the user is prompted in the console    to verify the host key of the server. Its probably going to be a good idea to    override this default behaviour since not everyone will see the console output.    There are a couple of methods available, you could use a different HostKeyVerification    implementation, for example the DialogHostKeyVerification will prompt the user    using a dialog, and there is also IgnoreHostKeyVerification which simply ignores    the process. For now we will use this, since were sure that the server is correct,    however when you deploy your client to production environments its wise to replace    this with either the dialog verification or your own custom implementation.    &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Lets import the    new verification process&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;code&gt;import com.sshtools.j2ssh.transport.IgnoreHostKeyVerification;&lt;/code&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;   and change the connect call&lt;/span&gt;&lt;/p&gt;   &lt;blockquote&gt;&lt;code&gt;ssh.connect("your-applications-host", new IgnoreHostKeyVerification());&lt;/code&gt;&lt;/blockquote&gt; &lt;!--pagebreak--&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; Now we can connect    to the SSH server, and the next step is to authenticate using our newly generated    private key. First we need to open the private key file, this can be done with     the following code.&lt;/span&gt;&lt;/p&gt;      &lt;blockquote&gt;&lt;code&gt;import com.sshtools.j2ssh.transport.authentication.SshPrivateKeyFile;&lt;br /&gt;&lt;br /&gt; ....&lt;br /&gt;&lt;br /&gt; // Open up the private key file&lt;br /&gt; SshPrivateKeyFile file =&lt;br /&gt; SshPrivateKeyFile.parse(new File("filename"));&lt;/code&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;br /&gt; This provides us with a copy of the file in memory, since we don't have a passphrase    on the key we can simply add the key to a new instance of the PublicKeyAuthenticationClient    which we are going to use to authenticate with.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;code&gt;import com.sshtools.j2ssh.authentication.PublicKeyAuthenticationClient;&lt;br /&gt;&lt;br /&gt;.....&lt;br /&gt;&lt;br /&gt;PublicKeyAuthenticationClient    pk = new PublicKeyAuthenticationClient();&lt;br /&gt; Pk.setUsername("username");&lt;br /&gt; Pk.setKey(file.toPrivateKey(null));&lt;/code&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Now that the key    is loaded into the authentication instance, we can authenticate.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;code&gt;if(ssh.autenticate(pk)==    AuthenticationProtocolState.COMPLETED) {&lt;br /&gt;&lt;/code&gt;&lt;blockquote&gt;// Authentication Complete&lt;/blockquote&gt; }&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Now that we have    successfully authenticated, were ready to create the secure tunnel for your    application. To do this we are going to create a local forwarding channel, local    forwarding is initiated by the client where by remote forwarding is initiated    by the server. This forwarding channel will provide a set of IO streams for    your client application to use in place of the Sockets IO streams. &lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;code&gt;import com.sshtools.j2ssh.forwarding.ForwardingIOChannel;&lt;br /&gt;&lt;br /&gt; .....&lt;br /&gt;&lt;br /&gt; ForwardingIOChannel channel = new ForwardingIOChannel(   &lt;/code&gt;&lt;blockquote&gt; ForwardingIOChannel.LOCAL_FORWARDING_CHANNEL,&lt;br /&gt;   "127.0.0.1",&lt;br /&gt;     10022,&lt;br /&gt;     "myhost",&lt;br /&gt;   10022); &lt;/blockquote&gt;   &lt;/blockquote&gt;  &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;We now have a channel    ready so lets waste no more time and open it&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;code&gt;if(ssh.openChannel(channel))    {   &lt;/code&gt;&lt;blockquote&gt;// Channel is opened and can be used&lt;br /&gt; channel.getOutputStream("START".getBytes());&lt;br /&gt; ....&lt;/blockquote&gt;   }&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; Once the channel    is open, you can use its IO streams in place of your Socket, your application    should not require any changes.&lt;/span&gt;&lt;/p&gt; &lt;!--pagebreak--&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;strong&gt;&lt;em&gt;The    advantages and disadvantages of using a secure tunnel&lt;/em&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;The main advantage    of this method is that it's a quick fix for an insecure application. By forwarding    the traffic through an embedded SSH tunnel your application's data is now secure.    However, your server has no access to the strong authentication that the SSH    server provides and you still need to maintain a separate SSH server and authentication    details for your client application. Of course these can be minimized by embedding    a private key into your client application but that in itself a potential    security flaw. What you need is to have your server support SSH connections    directly. &lt;/span&gt;&lt;/p&gt; &lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;In the next part    of this series, I will show you how to build your own SSH server using the J2SSH    daemon classes. Be prepared though as its not something you're going to be able    to plug-in to your existing server, instead we will build an SSH server capable    of supporting your applications proprietary protocol.&lt;/span&gt;&lt;p/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-32232975834746840?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/32232975834746840/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=32232975834746840' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/32232975834746840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/32232975834746840'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/09/part-1-securing-your-client-server.html' title='Part 1  - Securing your client-server application with J2SSH'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-1125776454797233631</id><published>2008-09-05T08:34:00.000-07:00</published><updated>2010-07-04T07:48:57.520-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PL/SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><title type='text'>Convert Between Base 10 and Base 62 in PL/SQL</title><content type='html'>There are many reasons why you may find yourself needing to convert a value back and forth between base 10, base 62, base 36, hexadecimal or whatever. I found myself in a similar situation where I had to generate a unique id entries in a data file, yet I only had two characters where I could put this value. Since this file could possibly have up to 3,000 entries in it, I was not going to be able to just use numbers since that only gives me 10 x 10 = 100 possible values ( 0 to 99 ).&lt;br /&gt;&lt;p&gt;However, if I were to translate a sequential decimal ( base 10 ) number to base 62, I now have 62 x 62 = 3,844 possible values ( 0 - zz ). Now obviously for base 62, the value will be case sensitive. If you can't guarantee case sensitivity, then you'll have to use base 36.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Convert from Base 10 to Base 62 in PL/SQL&lt;/b&gt;&lt;/p&gt; &lt;pre name="code" class="sql"&gt;CREATE OR REPLACE FUNCTION f_to_base62( a_number_to_convert INTEGER ) RETURN VARCHAR2 IS&lt;br /&gt;  &lt;br /&gt; v_modulo INTEGER;&lt;br /&gt; v_temp_int INTEGER := a_number_to_convert;&lt;br /&gt; v_temp_val VARCHAR2(256);&lt;br /&gt; v_temp_char VARCHAR2(1);&lt;br /&gt; c_base62_digits CONSTANT VARCHAR2(62) := '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';&lt;br /&gt;&lt;br /&gt;BEGIN&lt;br /&gt;&lt;br /&gt; IF ( a_number_to_convert = 0 ) THEN&lt;br /&gt;   v_temp_val := '0';&lt;br /&gt; END IF;&lt;br /&gt;      &lt;br /&gt; WHILE ( v_temp_int &lt;&gt; 0 ) LOOP&lt;br /&gt;   v_modulo := v_temp_int MOD 62;&lt;br /&gt;   v_temp_char := SUBSTR( c_base62_digits, v_modulo + 1, 1 );&lt;br /&gt;   v_temp_val := v_temp_char || v_temp_val;&lt;br /&gt;   v_temp_int := floor(v_temp_int / 62);&lt;br /&gt; END LOOP;&lt;br /&gt;&lt;br /&gt; RETURN v_temp_val;&lt;br /&gt;&lt;br /&gt;END;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Convert from Base 62 to Base 10 in PL/SQL&lt;/b&gt;&lt;br /&gt;&lt;pre name="code" class="sql"&gt;CREATE OR REPLACE FUNCTION f_from_base62( a_value_to_convert VARCHAR2 ) RETURN INTEGER IS&lt;br /&gt;&lt;br /&gt; v_iterator INTEGER;&lt;br /&gt; v_length INTEGER;&lt;br /&gt; v_temp_char VARCHAR2(1);&lt;br /&gt; v_temp_int INTEGER;&lt;br /&gt; v_return_value INTEGER := 0;&lt;br /&gt; v_multiplier INTEGER := 1;&lt;br /&gt; v_temp_convert_val VARCHAR2(256) := a_value_to_convert;&lt;br /&gt; c_base62_digits CONSTANT VARCHAR2(62) := '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';&lt;br /&gt;&lt;br /&gt;BEGIN&lt;br /&gt;&lt;br /&gt; v_length := length( v_temp_convert_val );&lt;br /&gt; v_iterator := v_length;&lt;br /&gt; WHILE ( v_iterator &gt; 0 ) LOOP&lt;br /&gt;   v_temp_char := SUBSTR( v_temp_convert_val, v_iterator, 1 );&lt;br /&gt;   v_temp_int := INSTR( c_base62_digits, v_temp_char ) -  1;&lt;br /&gt;   v_return_value := v_return_value + ( v_temp_int * v_multiplier );&lt;br /&gt;   v_multiplier := v_multiplier * 62;&lt;br /&gt;   v_iterator := v_iterator - 1;&lt;br /&gt; END LOOP;&lt;br /&gt;&lt;br /&gt; RETURN v_return_value;&lt;br /&gt;&lt;br /&gt;END;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-1125776454797233631?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/1125776454797233631/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=1125776454797233631' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/1125776454797233631'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/1125776454797233631'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/09/convert-between-base-10-and-base-62-in.html' title='Convert Between Base 10 and Base 62 in PL/SQL'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-576121002595653034</id><published>2008-09-03T04:02:00.000-07:00</published><updated>2008-12-17T16:13:44.407-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='SSH'/><category scheme='http://www.blogger.com/atom/ns#' term='SSHTools'/><title type='text'>Getting Started with J2SSH</title><content type='html'>&lt;p&gt; &lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;The first thing    you will probably want to do is to connect to an SSH server using J2SSH. This    is a fairly&lt;br /&gt;straightforward procedure using the SshClient class. This class provides access    for connecting, authenticating&lt;br /&gt;and starting a session channel, which enables you to execute commands or start    the users shell.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;code&gt; import com.sshtools.j2ssh.SshClient;   &lt;/code&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;First of all prepare    your application, in this section we will guide you through the basics so for    now just a simple&lt;br /&gt;try/catch inside the static main method.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;import java.io.BufferedReader;&lt;br /&gt;import java.io.InputStream;&lt;br /&gt;import java.io.InputStreamReader;&lt;br /&gt;import java.io.OutputStream;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public class SshExample() {&lt;br /&gt;// A buffered reader so we can request information from the user&lt;br /&gt;private static BufferedReader reader =&lt;br /&gt;     new BufferedReader(new InputStreamReader(System.in));&lt;br /&gt;&lt;br /&gt;public static void main(String args[]) {&lt;br /&gt; try {&lt;br /&gt;   // Further code will be added here&lt;br /&gt;&lt;br /&gt;} catch(Exception e) {&lt;br /&gt;   e.printStackTrace();&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;The next few sections    will guide you through making the initial connection, authenticating the user    and executing&lt;br /&gt;a command or starting the users shell for a simple console based SSH application.&lt;/span&gt;&lt;/p&gt;   &lt;!--pagebreak--&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;br /&gt;&lt;em&gt;&lt;strong&gt;Making the initial connection&lt;/strong&gt;&lt;/em&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; To create an SshClient    instance import the class into your implementation class file and use the following    code&lt;br /&gt;to connect to an SSH server on the standard port 22.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;SshClient ssh&lt;br /&gt;= new SshClient();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;System.out.print("Host to connect: ");&lt;br /&gt;&lt;br /&gt;String hostname = reader.readLine();&lt;br /&gt;&lt;br /&gt;ssh.connect(hostname);&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; When the client    connects to the server, the server supplies its public key for the client to    verify. You will see&lt;br /&gt;that calling the &lt;code&gt;connect&lt;/code&gt; method prompts the user within the console    to verify the key:&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;code&gt;The host firestar    is currently unknown to the system&lt;br /&gt;The host key fingerprint is: 1028: 69 54 9c 49 e5 92 59 40 5 66 c5 2e 9d 86    af ed&lt;br /&gt;Do you want to allow this host key? [Yes|No|Always]:&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; In the default    implementation of the &lt;code&gt;connect&lt;/code&gt; method, J2SSH reads the &lt;em&gt;$HOME/.ssh/known_hosts&lt;/em&gt;    file to determines to which hosts connections&lt;br /&gt;may be allowed. This is provided by the class ConsoleKnownHostsKeyVerification    and the&lt;br /&gt;default behavior can be emulated by the following code:&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;&lt;br /&gt;import com.sshtools.j2ssh.transport.ConsoleKnownHostsKeyVerification;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ssh.connect("firestar", new ConsoleKnownHostsKeyVerification());&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;When the connect    method returns, the protocol has been negotiated and key exchange has taken    place, leaving the connection ready for authenticating the user. &lt;/span&gt;&lt;/p&gt; &lt;!--pagebreak--&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;strong&gt;&lt;em&gt;Authenticating    the user&lt;/em&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Once the connection    has been completed the user is required to provide a set of credentials for    authentication.&lt;br /&gt;All client side authentication methods are implemented using the abstract class:&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;code&gt;import com.sshtools.j2ssh.authentication.SshAuthenticationClient.&lt;/code&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; To perform authentication,    the SshClient class provides the following method:&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;code&gt;public int authenticate(SshAuthenticationClient    auth);&lt;/code&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;There are currently    five authentication methods implemented by J2SSH, 'password', 'publickey', 'keyboard-interactive'    and 'hostbased'. With an extra agent authentication method that performs public    key authentication using the J2SSH key agent.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; &lt;em&gt;&lt;strong&gt;Password    Authentication&lt;/strong&gt;&lt;/em&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; Password authentication    is ideal for first time users as it requires no additional configuration within    the SSH&lt;br /&gt;client or server. The user simply supplies his username and password to the    client which is then transmitted over&lt;br /&gt;the encrypted connection to the server. The server then checks that the given    password is acceptable to the native&lt;br /&gt;password-authentication mechanism of the host operating system and returns the    result to the client.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;J2SSH implements    the 'password' authentication method with the following class:&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;code&gt;import com.sshtools.j2ssh.authentication.PasswordAuthenticationClient&lt;/code&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; Using the password    authentication method is straight forward; create an instance of the PasswordAuthentication&lt;br /&gt;class, set the username and password and pass to the SshClient to complete the    authentication.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt; /**&lt;br /&gt;* Create a PasswordAuthenticationClient instance, set the properties&lt;br /&gt;* and pass to the SessionClient to authenticate&lt;br /&gt;*/&lt;br /&gt;PasswordAuthenticationClient pwd = new PasswordAuthenticationClient();&lt;br /&gt;&lt;br /&gt;System.out.print("Username: ");&lt;br /&gt;String username = reader.readLine();&lt;br /&gt;auth.setUsername(username);&lt;br /&gt;&lt;br /&gt;System.out.print("Password: ");&lt;br /&gt;String password = reader.readLine();&lt;br /&gt;auth.setPassword(password);&lt;br /&gt;&lt;br /&gt;int result = ssh.authenticate(pwd);&lt;br /&gt;&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;strong&gt;&lt;em&gt;The    Authentication Result&lt;/em&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; When the authentication    method completes it returns the result of the authentication. This integer value    can be any&lt;br /&gt;of the following three values defined in the class:&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;import com.sshtools.j2ssh.authentication.AuthenticationProtocolState;&lt;br /&gt;..&lt;br /&gt;..&lt;br /&gt;if(result==AuthenticationProtocolState.FAILED)&lt;br /&gt;  System.out.println("The authentication failed");&lt;br /&gt;&lt;br /&gt;if(result==AuthenticationProtocolState.PARTIAL)&lt;br /&gt;  System.out.println("The authentication succeeded but another"&lt;br /&gt;                  + "authentication is required");&lt;br /&gt;&lt;br /&gt;if(result==AuthenticationProtocolState.COMPLETE)&lt;br /&gt;  System.out.println("The authentication is complete");&lt;/pre&gt; &lt;/blockquote&gt; &lt;!--pagebreak--&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;strong&gt;&lt;em&gt;Retrieving    the available authentication Methods&lt;/em&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; It is possible    at any time after the connection has been established and before authentication    has been completed to request a list of authentication methods that can be used.    The getAvailableAuthMethods method returns a list of authentication method names.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;code&gt;public List getAvailableAuthMethods(String    username);&lt;/code&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; &lt;em&gt;It should    be noted that the SSH specification allows the server to return authentication    methods that are not valid&lt;br /&gt;for the user.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;strong&gt;&lt;em&gt;Prompting    the User for Authentication Details?&lt;/em&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; Each SshAuthenticationClient    implementation can optionally be set a prompt interface which allows the user    to&lt;br /&gt;be prompted for the information once the authenticate method has been invoked.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;public interface SshAuthenticationPrompt {&lt;br /&gt;public boolean showPrompt(SshAuthenticationClient instance)&lt;br /&gt;                           throws AuthenticationProtocolException;&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; The showPrompt    method is called if the authentication instance is not ready to authenticate.    The methods is called and the developer should verify the instance of the SshAuthenticationClient    to make sure that it is compatible with the prompt (for example you cannot perform    public key authentication&lt;br /&gt;with a password prompt!). The user should then be duly prompted for the information    and the instance set with the user's information. Once&lt;br /&gt;complete, the prompt returns true to indicate that the user successfully entered    correct information.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; There are several    prompts provided in the J2SSH common packages that provide useful Swing based    dialogs to&lt;br /&gt;prompt the user.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;&lt;br /&gt;import com.sshtools.common.authentication.PasswordAuthenticationDialog;&lt;br /&gt;&lt;br /&gt;/***&lt;br /&gt;* Create a PasswordAuthenticationDialog instance and call the&lt;br /&gt;* showAuthenticationMethod so the user can graphically&lt;br /&gt;* enter their username and password&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;PasswordAuthenticationClient pwd =&lt;br /&gt;         new PasswordAuthenticationClient();&lt;br /&gt;&lt;br /&gt;PasswordAuthenticationDialog dialog =&lt;br /&gt;         new PasswordAuthenticationDialog(parent);&lt;br /&gt;&lt;br /&gt;pwd.setAuthenticationPrompt(dialog);&lt;br /&gt;&lt;br /&gt;int result;&lt;br /&gt;result = ssh.authenticate(pwd);&lt;br /&gt;&lt;/pre&gt; &lt;/blockquote&gt; &lt;!--pagebreak--&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;strong&gt;&lt;em&gt;Using    a session channel to execute a command or start the users shell&lt;/em&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; Once the user    is authenticated you will probably want to do something such as execute a command    or start the users shell. The SSH protocol provides multiplexed channels over    a single connection and the session channel is one of the channels defined by    the SSH protocol. The session channel allows the client to execute a single    command on the remote host and to communicate with the process by sending and    receiving data. The J2SSH SessionChannelClient implements this channel and we    will use this to execute a basic "ls" command.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;The session channel provides    an inputstream and outputstream for reading/writing, but before we can do this    we need to setup the channel for our command. First we open the channel itself    by calling the SshClient method:&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;   &lt;pre name="code" class="java"&gt;&lt;br /&gt;SessionChannelClient session = ssh.openSessionChannel();&lt;/pre&gt; &lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; Now that we have    a session instance we need to configure it for our command, there are several    options that can be set before we invoke one of the methods that will start    the session.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;em&gt;Setting Environment    Variables&lt;br /&gt;&lt;/em&gt;The SSH protocol provides a method to set an environment variable for the    processes environment, the protocol also leaves the actual implementation of    this down the server implementation, and in our experience most servers do not    allow for this for security reasons. However the method is available since its    defined in the protocol specification, so your free to try to use it, but beware    the variable may not be set!&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;code&gt; public boolean    setEnvironmentVariable(String name, String value);&lt;/code&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;em&gt;Requesting    a Pseudo Terminal&lt;/em&gt;&lt;br /&gt;A pseudo terminal is a device that imitates a terminal. Rather than being connected    to an actual terminal, a pseudo-terminal (or pty) is connected to a process.    If the command you are executing is expecting a terminal (such as a shell command)    you can request that a pseudo terminal be attached to the process by calling    the requestPseudoTerminal method.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;code&gt; public boolean    requestPseudoTerminal(String term, int cols, int rows, int width, int height,    String modes);&lt;/code&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;em&gt;Invoking a    command&lt;br /&gt;&lt;/em&gt;After the above operations have been performed you can then request that    the session either start the user's shell, execute a specific command or start    an SSH subsystem (such as SFTP). You should not invoke a subsystem unless you    are able to read/write the subsystem protocol, there are many additional utilities    within J2SSH that provide for the available subsystems.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;To start the users    default shell use:&lt;/span&gt;&lt;/p&gt;   &lt;blockquote&gt;   &lt;code&gt;public boolean startShell();&lt;/code&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Or to execute a    specific command use:&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;code&gt;public boolean    executeCommand(String command);&lt;/code&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;em&gt;An important    note to remember is that this does not execute a shell command. You cannot for    instance issue the command executeCommand("dir")" on the Windows    Operating system as this is a shell command, instead use "cmd.exe /C dir".    This method executes a binary executable and so should be used to execute any    program other than the users shell.&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;   &lt;!--pagebreak--&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; &lt;strong&gt;&lt;em&gt;Handling    Session Data&lt;/em&gt;&lt;/strong&gt;&lt;br /&gt;Once the session has been configured and a command or shell has been started,    you can begin to&lt;br /&gt;transfer data to and from the remote computer using the sessions IO streams.    These streams provide you with a&lt;br /&gt;standardized interface for reading and writing the data.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;em&gt; The Session    Channel's OutputStream&lt;/em&gt;&lt;br /&gt;The format of writing data varies according to how you configured the session,    for example if you executed the&lt;br /&gt;users shell then the data should be written as if the user had entered the commands    interactively.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;/** Writing to the session OutputStream */&lt;br /&gt;OutputStream out = session.getOutputStream();&lt;br /&gt;String cmd = "ls\n";&lt;br /&gt;out.write(cmd.getBytes());&lt;/pre&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; &lt;em&gt; The Session    Channel's InputStream&lt;/em&gt;&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;pre name="code" class="java"&gt;/**&lt;br /&gt;* Reading from the session InputStream&lt;br /&gt;*/&lt;br /&gt;InputStream in = session.getInputStream();&lt;br /&gt;byte buffer[] = new byte[255];&lt;br /&gt;int read;&lt;br /&gt;while((read = in.read(buffer)) &gt; 0) {&lt;br /&gt;String out = new String(buffer, 0, read);&lt;br /&gt;System.out.println(out);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; &lt;em&gt;Reading from    stderr&lt;/em&gt;&lt;br /&gt;The session also provides the stderr data provided by the remote session. Again    an InputStream is provided.&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;code&gt; public InputStream    session.getStderrInputStream();&lt;br /&gt;&lt;/code&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;&lt;strong&gt;&lt;em&gt;Closing    the Session&lt;/em&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;The session can    be closed using the following method:&lt;/span&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;code&gt; public void close();&lt;/code&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;em&gt;&lt;strong&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;Disconnecting&lt;/span&gt;&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; The connection    can be terminated by either side. To terminate the connection call the SshClient    method:&lt;/span&gt;&lt;/p&gt;   &lt;blockquote&gt;&lt;code&gt;   public void disconnect();&lt;/code&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt; &lt;em&gt;&lt;strong&gt;A    word on executing multiple commands&lt;/strong&gt;&lt;/em&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;So we can now execute    a single command on the remote server, but what's that I hear you say? I want    to execute more than one command? Well if you cast your mind back I told you    that the SSH protocol provides multiplexed channels over a single connection,    so executing another command is as simple as executing the first, just create    a new instance of the SessionChannelClient for every command you want to execute.    You can execute them simultaneously or one after another, but always create    a new session (since the session is closed when the command finishes and the    protocol does not allow for re-using of a session to execute another command).    &lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;There is a drawback    to this in that the process environment is not passed on from one session to    another, so you cannot for example execute a command to change directory and    then another to execute a script in that directory, since the change directory    is lost when the session closes and the new command starts back in the default    working directory. Of course you could always put the cd command into the script?    Or use the shell to execute both commands. This subject is certainly a bit more    advanced so I will leave it for another day and pencil in a new article to discuss    all the alternatives for executing multiple commands. &lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style=";font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;This concludes    our getting started tutorial, you should now have a basic working knowledge    of how to connect, authenticate and execute commands using J2SSH. &lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-576121002595653034?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/576121002595653034/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=576121002595653034' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/576121002595653034'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/576121002595653034'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/09/getting-started-with-j2ssh.html' title='Getting Started with J2SSH'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-3097751297188899266</id><published>2008-08-31T09:02:00.000-07:00</published><updated>2010-07-04T07:52:43.222-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='TFTP'/><category scheme='http://www.blogger.com/atom/ns#' term='SCP'/><category scheme='http://www.blogger.com/atom/ns#' term='FTP'/><category scheme='http://www.blogger.com/atom/ns#' term='HTTP'/><category scheme='http://www.blogger.com/atom/ns#' term='TELNET'/><category scheme='http://www.blogger.com/atom/ns#' term='HTTPS'/><category scheme='http://www.blogger.com/atom/ns#' term='FTPS'/><category scheme='http://www.blogger.com/atom/ns#' term='SFTP'/><title type='text'>Automate Data Transfer and Web Actions Using cURL</title><content type='html'>If you have ever had the need to automate some action such as transferring files using a secure protocol such as SFTP, or if you have ever thought that it would be nice to automate some sort of web action, you need to know about cURL. According to their &lt;a href="http://curl.haxx.se/"&gt;website&lt;/a&gt;:&lt;blockquote&gt;&lt;i&gt;curl is a command line tool for transferring files with URL syntax, supporting FTP, FTPS, HTTP, HTTPS, SCP, SFTP, TFTP, TELNET, DICT, LDAP, LDAPS and FILE. curl supports SSL certificates, HTTP POST, HTTP PUT, FTP uploading, HTTP form based upload, proxies, cookies, user+password authentication (Basic, Digest, NTLM, Negotiate, kerberos...), file transfer resume, proxy tunneling and a busload of other &lt;a href="http://curl.haxx.se/docs/features.html"&gt;useful tricks&lt;/a&gt;.&lt;/i&gt;&lt;/blockquote&gt;I have actually used cURL in a few projects now and I am very impressed with it's rich set of features and reliability to automate tasks. I won't go over every possible use for curl, but I'll show one example of how I have used cURL in a past project.&lt;br /&gt;&lt;p&gt;I recently setup a text messaging alert using Google's SMS system and Microsoft Outlook. Based on certain types of messages, Outlook will kick off a batch file, that contains one command:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;curl -d mobile_user_id="555-555-1234" -d carrier="ATT" -d text="TEXT MESSAGE DATA"&lt;br /&gt;-d gl="US" -d hl="en" -d client="navclient-ffsms" -d from="" -d source="" -d c="1"&lt;br /&gt;http://www.google.com/sendtophone&lt;br /&gt;&lt;/pre&gt;In the command above, all of the -d parameters are post parameters that will be sent to the Google SMS site and they are fairly self explanatory. After the parameters, we have the URL http://www.google.com/sendtophone which is where the Google SMS form is located.&lt;br /&gt;&lt;p&gt;If you are looking for other ways to use cURL, check out their &lt;a href="http://curl.hoxt.com/docs/manual.html"&gt;manual&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-3097751297188899266?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/3097751297188899266/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=3097751297188899266' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/3097751297188899266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/3097751297188899266'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/08/automate-data-transfer-and-web-actions.html' title='Automate Data Transfer and Web Actions Using cURL'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-7032734373694710869</id><published>2008-08-30T16:53:00.000-07:00</published><updated>2010-07-04T07:54:35.346-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PL/SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title type='text'>PL/SQL MERGE Query ( UPSERT )</title><content type='html'>One of my recent findings about PL/SQL is the MERGE query, also known as an UPSERT. This is exactly what it sounds like, an INSERT and UPDATE all in one block of code. This can be really useful and can really reduce the amount of code you have to write to perform certain operations. On top of reducing the amount of code, it can really make your code more readable and easier to maintain.&lt;br /&gt;&lt;p&gt;&lt;b&gt;Basic MERGE Syntax&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;pre name="code" class="sql"&gt;MERGE INTO destination_table&lt;br /&gt;USING (SELECT key_column, value_column FROM source_table)&lt;br /&gt;ON (destination_table.key_column = source_table.key_column)&lt;br /&gt;WHEN MATCHED THEN&lt;br /&gt; UPDATE SET destination_table.value_column = source_table.value_column&lt;br /&gt;WHEN NOT MATCHED THEN&lt;br /&gt; INSERT (destination_table.key_column, destination_table.value_column)&lt;br /&gt; VALUES (source_table.key_column, destination_table.value_column);&lt;br /&gt;&lt;/pre&gt;Looking at the basic syntax above, you get an idea of how the MERGE query works.  You can make this as basic or as complicated as you would like. Of course, you can use JOINS, VIEWS, etc. in either the source or destination queries.  You can leave off either of the WHEN MATCHED THEN or WHEN NOT MATCHED THEN blocks if you don't want to perform operations in those certain situations.&lt;br /&gt;&lt;p&gt;Let's take a look at an example scenario where the MERGE query could be used. In our example, we have two tables. In one table, we maintain a list of widgets and in another table we keep the properties for those widgets. The tables with some sample data is listed below.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;table style="text-align: left; margin-right: 10px; margin-bottom: 10px; width: 217px; height: 85px;" align="left" border="1" cellpadding="2" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;ID&lt;/span&gt;&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;WIDGET&lt;/span&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;td&gt;Super Widget&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;2&lt;/td&gt;&lt;td&gt;Awesome Widget&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table style="text-align: left; margin-right: 10px; margin-bottom: 10px; width: 400px; height: 110px;" border="1" cellpadding="2" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;WIDGET_ID&lt;/span&gt;&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;PROP_NAME&lt;/span&gt;&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;PROP_VALUE&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;td style="text-align: center;"&gt;COLOR&lt;/td&gt;&lt;td style="text-align: center;"&gt;GREEN&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;td style="text-align: center;"&gt;SIZE&lt;/td&gt;&lt;td style="text-align: center;"&gt;LARGE&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;2&lt;/td&gt;&lt;td style="text-align: center;"&gt;SIZE&lt;/td&gt;&lt;td style="text-align: center;"&gt;MEDIUM&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;In our WIDGET table, we have two widgets.  The Awesome Widget and the Super Widget.  In our WIDGET_PROPERTY table, we have two properties for the Awesome Widget, size and color.  We only have one property for the Super Widget, which is size. Management has decided that all widgets will now come in the color blue. So we need to have a color property for all widgets and the value must be blue.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;This could get pretty complicated since some of the widgets already have a color property and we can't add another color property to a given widget. So a simple INSERT won't work unless we delete all color properties first, which isn't very efficient, especially if there is a lot of data.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;We could use an UPDATE query for the ones that already exist, but not all widgets have a color property, so this will still not solve that problem. With a MERGE query, we can solve this problem with a single statment in PL/SQL. Here is the PL/SQL code we would use to handle this situation.&lt;br /&gt;&lt;/p&gt;&lt;pre name="code" class="sql"&gt;MERGE INTO WIDGET_PROPERTY DESTINATION&lt;br /&gt;USING ( SELECT WIDGET.ID, 'COLOR' AS PROP_NAME FROM WIDGET ) SOURCE&lt;br /&gt;ON ( DESTINATION.WIDGET_ID = SOURCE.ID AND&lt;br /&gt;    DESTINATION.PROP_NAME = SOURCE.PROP_NAME )&lt;br /&gt;WHEN MATCHED THEN&lt;br /&gt;  UPDATE SET DESTINATION.PROP_VALUE = 'BLUE'&lt;br /&gt;WHEN NOT MATCHED THEN&lt;br /&gt;  INSERT ( DESTINATION.WIDGET_ID, DESTINATION.PROP_NAME, DESTINATION.PROP_VALUE )&lt;br /&gt;  VALUES( SOURCE.ID, SOURCE.PROP_NAME, 'BLUE' );&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-7032734373694710869?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/7032734373694710869/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=7032734373694710869' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/7032734373694710869'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/7032734373694710869'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/08/plsql-merge-query-upsert.html' title='PL/SQL MERGE Query ( UPSERT )'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-455217112512492333</id><published>2008-08-29T16:42:00.000-07:00</published><updated>2010-07-04T07:55:44.774-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PL/SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Collections'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><title type='text'>Associative Arrays: Hashtables for PL/SQL</title><content type='html'>I have been developing software in Java most of my career, but recently my job has required me to take on more projects using Oracle's PL/SQL. Being a Java programmer, I am very well versed in the various collections that are available from the Java API. One collection I find myself using a lot is the Hashtable and recently during a PL/SQL project, I had an algorithm that would be served nicely by such a data structure.&lt;br /&gt;&lt;p&gt;That's when I found out about Associative Arrays in PL/SQL. An associative array is a key-value pair that we can use in very much the same fashion we would use the Hashtable type in Java. In this post I'll show you how to declare a PL/SQL associative array, assign values to the array, then how to access those values. Then I'll go over how to iterate over the PL/SQL associative array.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Declaring, Assigning, and Accessing Associative Arrays&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;pre name="code" class="sql"&gt;DECLARE&lt;br /&gt;&lt;br /&gt;  -- Declare our array type to be keyed on 5 byte varchar and hold values of 256 byte varchar.&lt;br /&gt;  TYPE zip_city_type IS TABLE OF VARCHAR2(256) INDEX BY VARCHAR2(5);&lt;br /&gt;  -- Declare our actual associative array using our new data type.&lt;br /&gt;  zip_city_array zip_city_type;&lt;br /&gt;&lt;br /&gt;BEGIN&lt;br /&gt;&lt;br /&gt;  -- Let's add some values to our array.&lt;br /&gt;  zip_city_array('80201') := 'DENVER, CO';  -- Adds entry for zip code 80201&lt;br /&gt;  zip_city_array('48201') := 'DETROIT, MI';&lt;br /&gt;&lt;br /&gt;  -- Print out the values from our associative array.&lt;br /&gt;  dbms_output.put_line( 'Zip code 80201 is in ' || zip_city_array('80201') );&lt;br /&gt;  dbms_output.put_line( 'Zip code 48201 is in ' || zip_city_array('48201') );&lt;br /&gt;&lt;br /&gt;END;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Iterating Through an Associative Array&lt;/b&gt;&lt;br /&gt;&lt;p&gt;You will come across situations where you need to iterate through all of the elements in your associative array and you want to do so efficiently. Let's take a look at how we would accomplish iterating through the array we declared above.&lt;/p&gt;&lt;pre name="code" class="sql"&gt;DECLARE&lt;br /&gt;&lt;br /&gt;  -- Declare our array type to be keyed on 5 byte varchar and hold values of 256 byte varchar.&lt;br /&gt;  TYPE zip_city_type IS TABLE OF VARCHAR2(256) INDEX BY VARCHAR2(5);&lt;br /&gt;  -- Declare our actual associative array using our new data type.&lt;br /&gt;  zip_city_array zip_city_type;&lt;br /&gt;  zip VARCHAR2(5);&lt;br /&gt;&lt;br /&gt;BEGIN&lt;br /&gt;&lt;br /&gt;  -- Let's add some values to our array.&lt;br /&gt;  zip_city_array('80201') := 'DENVER, CO';  -- Adds entry for zip code 80201&lt;br /&gt;  zip_city_array('48201') := 'DETROIT, MI';&lt;br /&gt;&lt;br /&gt;  -- Assign the first key in our array to zip.&lt;br /&gt;  zip := zip_city_array.FIRST;  &lt;br /&gt; &lt;br /&gt;  -- Loop through the array while our key is null.&lt;br /&gt;  WHILE zip IS NOT NULL LOOP&lt;br /&gt;     dbms_output.put_line( zip || ' = ' || zip_city_array(zip) );&lt;br /&gt;     zip := zip_city_array.NEXT( zip );&lt;br /&gt;  END LOOP;  &lt;br /&gt;&lt;br /&gt;END;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-455217112512492333?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/455217112512492333/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=455217112512492333' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/455217112512492333'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/455217112512492333'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/08/associative-arrays-hashtables-for-plsql.html' title='Associative Arrays: Hashtables for PL/SQL'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-6122269935594507050</id><published>2008-08-25T16:46:00.000-07:00</published><updated>2010-07-04T07:57:02.710-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='JAXME'/><category scheme='http://www.blogger.com/atom/ns#' term='Reflection'/><title type='text'>Java Source Reflection with JaxMe JavaSource</title><content type='html'>Alright, it may not happen very often that you need to be able to use reflection on your Java source code, but its nice to know there is a framework that can help you out.  Apache's &lt;a href="http://ws.apache.org/jaxme/js/index.html"&gt;JaxMe JavaSource&lt;/a&gt; framework is a framework that can be used for generating Java source files.&lt;br /&gt;&lt;p&gt;I personally found myself working on a project that had to be capable of integrating our source code with another vendor's source code, both of which changed frequently. I was able to use the JaxMe JavaSource framework to verify that all necessary methods had been implemented on our subclasses, and if they hadn't, I was able to stub them out quickly and easily so that it didn't break the build everytime a base class was modified.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;For more information on how to use the JaxMe JavaSource framework and in particular the source code reflection portion of the framework, go &lt;a href="http://ws.apache.org/jaxme/js/jparser.html"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-6122269935594507050?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/6122269935594507050/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=6122269935594507050' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/6122269935594507050'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/6122269935594507050'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/08/using-reflection-on-java-source-code.html' title='Java Source Reflection with JaxMe JavaSource'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-3283269724617327832</id><published>2008-08-24T05:23:00.000-07:00</published><updated>2008-12-17T16:21:36.505-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='BeanShell'/><title type='text'>Introducing BeanShell: A Java Source Interpreter</title><content type='html'>If you haven't ever checked out BeanShell before, I would highly suggest you mosey on over to &lt;a href="http://www.beanshell.org/"&gt;www.beanshell.org&lt;/a&gt; and take a look. They describe BeanShell as a small, free, embeddable Java source interpreter with object scripting language features, written in Java.&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;Essentially, it is a way to run Java source code as an interpreted script. Along with supporting the full Java syntax, it adds a few other nice scripting features such as loosely typed variables. Some of the benefits of such an application include rapid prototyping, rules engines, configuration, testing, embedded systems, and even Java education.&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;Also, if your application is using Spring, you can even inject BeanShell scripts into your Spring beans. They provide a quick and easy tutorial to get you up and running with BeanShell &lt;a href="http://www.beanshell.org/manual/quickstart.html"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-3283269724617327832?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/3283269724617327832/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=3283269724617327832' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/3283269724617327832'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/3283269724617327832'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/08/introducing-beanshell-java-source.html' title='Introducing BeanShell: A Java Source Interpreter'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-7035181644130964683</id><published>2008-08-23T18:54:00.000-07:00</published><updated>2008-12-17T16:25:32.423-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='BeanShell'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><title type='text'>Injecting BeanShell Scripts into a Spring Bean</title><content type='html'>One really neat feature about Spring that you don't hear very much about is the ability to inject scripting into a Spring bean. This is very powerful functionality that allows you to add dynamic logic into your application and even has the ability to reload the script at a set interval enabling you to make code changes on the fly without rebuilding. There are currently three scripting languages that you can use with this feature and they are Groove, Ruby, and BeanShell. This post will focus on injecting a BeanShell script into a Spring bean.&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;We are going to take a look at a situation in which we are going to implement various rules for calculating invoice amounts for ACME Consulting Company's clients. Some of ACME's clients pay a set monthly fee that entitles them to a given number of hours of service, then they pay an hourly rate for any hours over the set amount. They also have some clients that only pay an hourly fee for service and don't have a monthly contract setup.&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;For this situation, we are going to setup two invoice calculation rules, one for calculating invoice amounts for our monthly contracts, and one that only calculates invoices for our hourly contracts.&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;Before we take a look at the code, you'll need to add the BeanShell library to your class path which can be downloaded from &lt;a href="http://www.beanshell.org"&gt;www.beanshell.org&lt;/a&gt;.&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;First, we'll create a Java class called InvoiceData that will hold all of the information our rules will need to calculate the invoice amounts:&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;package com.billing.invoice;&lt;br /&gt;&lt;br /&gt;import java.math.BigDecimal;&lt;br /&gt;&lt;br /&gt;public class InvoiceData {&lt;br /&gt;&lt;br /&gt;   private int hoursWorked;&lt;br /&gt;   private int hoursEntitled;&lt;br /&gt;   private BigDecimal monthlyRate;&lt;br /&gt;   private BigDecimal hourlyRate;&lt;br /&gt;&lt;br /&gt;   public void setHoursWorked( int hours ) {&lt;br /&gt;        hoursWorked = hours;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void setHoursEntitled( int hours ) {&lt;br /&gt;        hoursEntitled = hours;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void setMonthlyRate( BigDecimal rate ) {&lt;br /&gt;        monthlyRate = rate;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void setHourlyRate( BigDecimal rate ) {&lt;br /&gt;        hourlyRate = rate;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public int getHoursWorked() {&lt;br /&gt;        return hoursWorked;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public int getHoursEntitled() {&lt;br /&gt;        return hoursEntitled;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public BigDecimal getMonthlyRate() {&lt;br /&gt;        return monthlyRate;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public BigDecimal getHourlyRate() {&lt;br /&gt;        return hourlyRate;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;This is your basic plain old java object (POJO) that will hold the properties we will need to calculate the total invoice amount.&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;Next, we'll create a Java interface called InvoiceCalculationRule:&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;package com.billing.invoice.rules;&lt;br /&gt;&lt;br /&gt;import java.math.BigDecimal;&lt;br /&gt;import com.billing.invoice.InvoiceData;&lt;br /&gt;&lt;br /&gt;public interface InvoiceCalculationRule {&lt;br /&gt;&lt;br /&gt;   public BigDecimal calculate( InvoiceData invoiceData );&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;This interface contains only one method named calculate, that accepts an invoiceData object. This interface will be used to perform our invoice calculations. The actual implementations are coming up next and they are our BeanShell scripts.&lt;br /&gt;&lt;br /&gt;Now we are ready to build our rule classes. These will be BeanShell scripts, but the syntax is exactly the same as Java which is another reason BeanShell is a great option; no need to learn a different language to implement scripting.&lt;br /&gt;&lt;br /&gt;Our first rule, MonthlyContractsInvoiceCalculationRule will calculate invoices for our monthly contracts:&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;import java.math.BigDecimal;&lt;br /&gt;import com.billing.invoice.InvoiceData;&lt;br /&gt;&lt;br /&gt;public BigDecimal calculate( InvoiceData invoiceData ) {&lt;br /&gt;&lt;br /&gt;   int chargeableHours = invoiceData.getHoursWorked() - invoiceData.getHoursEntitled();&lt;br /&gt;   BigDecimal chargeableHoursAmount = new BigDecimal( 0 );&lt;br /&gt;   BigDecimal invoiceAmount = new BigDecimal( 0 );&lt;br /&gt;&lt;br /&gt;   if ( chargeableHours &gt; 0 ) {&lt;br /&gt;        chargeableHoursAmount = invoiceData.getHourlyRate().multiply( new BigDecimal( chargeableHours ) );&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   invoiceAmount = chargeableHoursAmount.add( invoiceData.getMonthlyRate() );&lt;br /&gt;&lt;br /&gt;   return invoiceAmount;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;Our second rule, HourlyContractsInvoiceCalculationRule will calculate invoices for our hourly contracts:&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;import java.math.BigDecimal;&lt;br /&gt;import com.billing.invoice.InvoiceData;&lt;br /&gt;&lt;br /&gt;public BigDecimal calculate( InvoiceData invoiceData ) {&lt;br /&gt;&lt;br /&gt;   BigDecimal invoiceAmount = invoiceData.getHourlyRate().multiply(&lt;br /&gt;        new BigDecimal( invoiceData.getHoursWorked() ) );&lt;br /&gt;&lt;br /&gt;   return invoiceAmount;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;Now that we have all of our classes setup, we need to work on our Spring configuration file so that we can actually retrieve our rules when we need them.  Here's an example of what our configuration file would look like:&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;beans xmlns="http://www.springframework.org/schema/beans"&lt;br /&gt;    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;    xmlns:lang="http://www.springframework.org/schema/lang"&lt;br /&gt;    xsi:schemaLocation="http://www.springframework.org/schema/beans&lt;br /&gt;         http://www.springframework.org/schema/beans/spring-beans-2.0.xsd    &lt;br /&gt;         http://www.springframework.org/schema/lang&lt;br /&gt;         http://www.springframework.org/schema/lang/spring-lang-2.0.xsd"&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;lang:bsh id="hourlyContractsInvoiceCalculationRule"&lt;br /&gt;         script-source="classpath:com/billing/invoice/rules/HourlyContractsInvoiceCalculationRule.bsh"&lt;br /&gt;         script-interfaces="com.billing.invoice.rules.InvoiceCalculationRule"&lt;br /&gt;         refresh-check-delay="60000" /&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;lang:bsh id="monthlyContractsInvoiceCalculationRule"&lt;br /&gt;         script-source="classpath:com/billing/invoice/rules/MonthlyContractsInvoiceCalculationRule.bsh"&lt;br /&gt;         script-interfaces="com.billing.invoice.rules.InvoiceCalculationRule"&lt;br /&gt;         refresh-check-delay="60000" /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;We have everything in place and we are ready to tie it all together. For this example, I am just writing up a quick test, so it isn't a realistic class, but it will give you an idea of how to use our new rules.&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;package com.billing.invoice;&lt;br /&gt;&lt;br /&gt;import com.billing.invoice.rules.InvoiceCalculationRule;&lt;br /&gt;&lt;br /&gt;import java.math.BigDecimal;&lt;br /&gt;import java.math.RoundingMode;&lt;br /&gt;&lt;br /&gt;import org.springframework.context.ApplicationContext;&lt;br /&gt;import org.springframework.context.support.ClassPathXmlApplicationContext;&lt;br /&gt;&lt;br /&gt;public class RuleTestMain {&lt;br /&gt;&lt;br /&gt;     public static void main( String [] args ) {&lt;br /&gt;&lt;br /&gt;          ApplicationContext context = new ClassPathXmlApplicationContext( "spring.xml" );&lt;br /&gt;          InvoiceData invoiceOne = new InvoiceData();&lt;br /&gt;          InvoiceData invoiceTwo = new InvoiceData();&lt;br /&gt;&lt;br /&gt;          invoiceOne.setHoursWorked( 40 );&lt;br /&gt;          invoiceOne.setHoursEntitled( 30 );&lt;br /&gt;          invoiceOne.setMonthlyRate( new BigDecimal( 1500 ) );&lt;br /&gt;          invoiceOne.setHourlyRate( new BigDecimal( 44.25 ) );&lt;br /&gt;&lt;br /&gt;          InvoiceCalculationRule monthlyRule =&lt;br /&gt;               ( InvoiceCalculationRule ) context.getBean( "monthlyContractsInvoiceCalculationRule" );&lt;br /&gt;&lt;br /&gt;          System.out.println( "Monthly Invoice Amount: $" + monthlyRule.calculate( invoiceOne ).setScale( 2, RoundingMode.HALF_UP ) );&lt;br /&gt;&lt;br /&gt;          invoiceTwo.setHoursWorked( 40 );&lt;br /&gt;          invoiceTwo.setHourlyRate( new BigDecimal( 52.25 ) );&lt;br /&gt;&lt;br /&gt;          InvoiceCalculationRule hourlyRule =&lt;br /&gt;               ( InvoiceCalculationRule ) context.getBean( "hourlyContractsInvoiceCalculationRule" );&lt;br /&gt;&lt;br /&gt;          System.out.println( "Hourly Invoice Amount: $" + hourlyRule.calculate( invoiceTwo ).setScale( 2, RoundingMode.HALF_UP ) );&lt;br /&gt;&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p /&gt;&lt;br /&gt;When we run this code, we will be calculating the first invoice using the monthly rule, then the second invoice will be calculated using the hourly rule. The great thing is, that if we decide we need to change one of these rules, we can actually update the scripts and it will be automatically reloaded every minute and will become active without having to rebuild the application.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-7035181644130964683?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/7035181644130964683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=7035181644130964683' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/7035181644130964683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/7035181644130964683'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/08/injecting-beanshell-scripts-into-spring.html' title='Injecting BeanShell Scripts into a Spring Bean'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-5045535945045241959</id><published>2008-08-23T17:29:00.000-07:00</published><updated>2008-12-17T16:29:09.843-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PL/SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title type='text'>The often unappreciated MINUS SQL query</title><content type='html'>&lt;p&gt;There are times when you need to verify that a given record is associated with all of a given type of records. In this post, I'll be going over the MINUS statement and show you a practical use for this often under used functionality of SQL.&lt;/p&gt;&lt;p&gt;For this example we'll be looking at customer data for an online application. ACME paper in has unleashed a new paper sales website. They allow the employees of the company to which they sale paper to have access to various sections of their website. In order to have more granular control, they control access the sections at both the user level and the company level. In order for a user to have access to a section, they must both have access at the company level and at the user level. Let's take a look at our tables to get a better idea of what we are dealing with.&lt;/p&gt;&lt;table  style="text-align: left; margin-right: 10px; margin-bottom: 10px; width: 217px; height: 60px;" align="left" border="1" cellpadding="2" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;ID&lt;/span&gt;&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;COMPANY_NAME&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;td&gt;Awesome Corp.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table style="text-align: left; margin-right: 10px; margin-bottom: 10px; width: 217px; height: 85px;" border="1" cellpadding="2" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;ID&lt;/span&gt;&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;USERNAME&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;td&gt;jdoe&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;2&lt;/td&gt;&lt;td&gt;bsmith&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table style="text-align: left; margin-bottom: 10px; margin-right: 10px; width: 217px; height: 85px;" border="1" align="left" cellpadding="2" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;ID&lt;/span&gt;&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;SECTION_NAME&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;td&gt;Main&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;2&lt;/td&gt;&lt;td&gt;Special&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table style="text-align: left; width: 217px; height: 85px; margin-right: 10px; margin-bottom: 10px;" border="1" cellpadding="2" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;COMP_ID&lt;/span&gt;&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;USER_ID&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;td style="text-align: center;"&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table style="text-align: left; margin-bottom: 10px; margin-right: 10px; width: 217px; height: 85px;" align="left" border="1" cellpadding="2" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;COMP_ID&lt;/span&gt;&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;SECT_ID&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;td style="text-align: center;"&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table style="text-align: left; margin-bottom: 10px; width: 217px; height: 112px;" border="1" cellpadding="2" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;USER_ID&lt;/span&gt;&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;SECT_ID&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;td style="text-align: center;"&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;2&lt;/td&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;The first table (COMPANY) shows the companies that ACME does business with. The second table (USER) shows the users that are using the new online sales site. The third table (SECTION) shows the various sections that are available on the online sales site. The fourth table (COMPANYUSERJOIN) links the users to the various companies. The fifth table (COMPANYSECTIONJOIN) gives company access to the various sections. The sixth table (USERSECTIONJOIN) gives user access to the various sections.&lt;/p&gt;&lt;p&gt;Management has requested a report of all of the users that don't have access to all of the sections that their company has access to. In comes MINUS to save the day. Minus will return only the rows that are not in both queries. Just like UNION, the data types in both SQL queries must be the same. Let's take a look at the query that will return the data we are looking for.&lt;/p&gt;&lt;pre name="code" class="sql"&gt;SELECT SECTION.ID, USER.USERNAME FROM USER&lt;br&gt;JOIN COMPANYUSERJOIN ON COMPANYUSERJOIN.USER_ID = USER.ID&lt;br&gt;JOIN COMPANYSECTIONJOIN ON COMPANYSECTIONJOIN.COMP_ID = COMPANYUSERJOIN.COMP_ID&lt;br&gt;JOIN SECTION ON SECTION.ID = COMPANYSECTIONJOIN.SECT_ID&lt;br&gt;MINUS&lt;br&gt;SELECT SECTION.ID, USER.USERNAME FROM USER&lt;br&gt;JOIN USERSECTIONJOIN ON USERSECTIONJOIN.USER_ID = USER.ID&lt;br&gt;&lt;/pre&gt;&lt;p&gt;Looking at the SQL query above, we can see in the first section that we are selecting the section id and the username by joining the section table through what the corporation will have access to. This will return all of the usernames for the corporations, along with all of the section ids the corporation has access to. Then we have &lt;span style="font-style: italic;"&gt;minus&lt;/span&gt; before the second part of the query. In the second part of the SQL query, we are returning the section ids and usernames based on what section each user actually has access to.&lt;/p&gt;&lt;p&gt;The &lt;span style="font-style: italic;"&gt;minus&lt;/span&gt; will compare these two SQL queries and remove duplicate records. This will return two types of records. The first type of record returned will be the sections that a company has access to, but that a given user has not been given access to. The second type of record that will be returned will be sections that a user has access to, but that a given corporation does not. &amp;nbsp;For our exercise, we will assume that a given user can't be given access to a section without the company also having access.&lt;/p&gt;&lt;p&gt;Using the example data above, this query will return a section id of 2 and username of bsmith. This means that bsmith is part of a company that has access to section 2, but bsmith does not have access to this section. We then write up our report for management, cut out of work early, and go grab a cold beer or two with some friends. Thanks to the SQL MINUS query.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-5045535945045241959?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/5045535945045241959/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=5045535945045241959' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/5045535945045241959'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/5045535945045241959'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/08/often-unappreciated-minus-sql-query.html' title='The often unappreciated MINUS SQL query'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-2166426339908175752</id><published>2008-08-23T08:45:00.000-07:00</published><updated>2008-12-17T16:31:38.945-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Regular Expressions'/><category scheme='http://www.blogger.com/atom/ns#' term='Regex'/><category scheme='http://www.blogger.com/atom/ns#' term='sed'/><title type='text'>Delete multiple lines in a text file using regular expressions and sed</title><content type='html'>I recently found myself in quite a predicament. I had a very large flat file in a specific format and I needed to delete certain record types. Now, obviously this is very easy with regular expressions if the records are only on one line. However, that was not the case. &amp;nbsp;The record types I needed to remove took up multiple lines. &amp;nbsp;Below is an example of the type of record I needed to delete (however since the file spec is proprietary I have changed the actual values):&lt;pre&gt;START PAYMENT_RECORD&lt;br&gt;123456789          80000   JOHN    DOE    BANK OF ANYWHERE USA    123 ANY STREET  ANYTOWN USA    &lt;br&gt;END PAYMENT_RECORD&lt;br&gt;&lt;br&gt;&lt;/pre&gt;However with sed, you can still do a multiple line search and delete from a file with the following command: &amp;nbsp;&lt;br&gt;&lt;pre&gt;sed '/pattern/{N;N;N;d}' filename &amp;nbsp;&lt;br&gt;&lt;br&gt;&lt;/pre&gt;So using the sed command in my particular record example, I accomplished this task with &lt;span style="font-style: italic;"&gt;&lt;br&gt;&lt;br&gt;&lt;/span&gt;&lt;pre&gt;sed '/^START PAYMENT_RECORD/{N;N;N;d}' payment_data_file.txt&lt;br&gt;&lt;br&gt;&lt;/pre&gt;This command tells sed to find the text &lt;span style="font-style: italic;"&gt;START PAYMENT_RECORD&lt;/span&gt; at the beginning of the line, then delete that line and the next two lines. &amp;nbsp;The &lt;span style="font-style: italic;"&gt;N&lt;/span&gt; portion is the number of lines to be removed, and the &lt;span style="font-style: italic;"&gt;d&lt;/span&gt; portion tells sed to delete the data matching the pattern.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-2166426339908175752?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/2166426339908175752/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=2166426339908175752' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/2166426339908175752'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/2166426339908175752'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/08/delete-multiple-lines-using-regular.html' title='Delete multiple lines in a text file using regular expressions and sed'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4951797399507549351.post-2174595971154809345</id><published>2008-08-21T10:14:00.001-07:00</published><updated>2008-08-23T08:19:41.585-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PL/SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Collections'/><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><title type='text'>Check if a value is in a PL/SQL collection using MEMBER OF</title><content type='html'>&lt;p&gt;You may find yourself working with a collection in PL/SQL and think to yourself, "Wow, it sure would be great if I could do a quick search of this collection to see if it contains a specific value." Well, never fear, cause I'm going to show you how to do just that using MEMBER OF.&lt;/p&gt;&lt;table style="text-align: left; width: 171px; height: 228px; margin-right: 10px; margin-bottom: 10px;" align="left" border="1" cellpadding="2" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;ID&lt;/span&gt;&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;NAME&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;td&gt;Black&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;2&lt;/td&gt;&lt;td&gt;Brown&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;3&lt;/td&gt;&lt;td&gt;Blue&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;4&lt;/td&gt;&lt;td&gt;Green&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;5&lt;/td&gt;&lt;td&gt;Orange&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;6&lt;/td&gt;&lt;td&gt;Red&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;7&lt;/td&gt;&lt;td&gt;Purple&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;8&lt;/td&gt;&lt;td&gt;Yellow&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Let's say that you have the names of the eight basic colors (according to Crayola) in a lookup table called LKBASICCOLORS that has only two columns, ID and NAME.&lt;/p&gt;&lt;p&gt;In our situation, we want to verify that a given color name is one of our eight basic colors. There are numerous ways to do this in PL/SQL, including hard coding these color names into our code. While in this situation that wouldn't be such a bad idea, but in the real world, values tend to change often and nobody wants to be the poor schmuck that gets to go back through all of the PL/SQL looking for hard coded values. By using member of, you can actually look up these values on the fly, load them into a collection, and verify that our given color is a basic color.&lt;/p&gt;&lt;p&gt;&lt;span xmlns=""&gt;&lt;br /&gt;&lt;pre&gt;DECLARE&lt;br&gt;&lt;br&gt; v_color_white varchar2(10) := 'White;&lt;br&gt; v_color_purple varchar2(10) := 'Purple';&lt;br&gt;&lt;br&gt; TYPE lkbasiccolor_names IS TABLE OF VARCHAR2(20);&lt;br&gt; v_color_names lkbasiccolor_names;&lt;br&gt;&lt;br&gt;BEGIN&lt;br&gt;&lt;br&gt; SELECT NAME BULK COLLECT INTO v_color_names FROM LKBASICCOLORS;&lt;br&gt;&lt;br&gt; IF v_color_white MEMBER OF v_color_names THEN&lt;br&gt; dbms_output.put_line('White is a basic color');&lt;br&gt; ELSE&lt;br&gt; dbms_output.put_line('White is not a basic color');&lt;br&gt; END;&lt;br&gt;&lt;br&gt; IF v_color_purple MEMBER OF v_color_names THEN&lt;br&gt; dbms_output.put_line('Purple is a basic color');&lt;br&gt; ELSE&lt;br&gt; dbms_output.put_line('Purple is not a basic color');&lt;br&gt; END;&lt;br&gt;&lt;br&gt;END;&lt;br&gt;&lt;br&gt;&lt;/pre&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Now let's take a look at what's going on in the sample above. In the DECLARE, we declare two color name variables. Then we define our collection type as a table of varchar2 values. We move on and declare our actual collection as v_color_names as the collection type of lkbasiccolor_names. &lt;/p&gt;&lt;p&gt;In the first line of the BEGIN section, we load all of our color names into our v_color_names collection. The first test we try is to see if the color white is a member of our v_color_names collection. Since it isn't, it will fall into the else and print out that White is not a basic color. In the next block, since Purple is in our basic color list, it should print Purple is a basic color.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4951797399507549351-2174595971154809345?l=javaconfessions.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaconfessions.com/feeds/2174595971154809345/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4951797399507549351&amp;postID=2174595971154809345' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/2174595971154809345'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4951797399507549351/posts/default/2174595971154809345'/><link rel='alternate' type='text/html' href='http://javaconfessions.com/2008/08/searching-elements-of-collection-in.html' title='Check if a value is in a PL/SQL collection using MEMBER OF'/><author><name>Michael</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
