<?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-22201720</id><updated>2012-01-25T06:53:02.433-08:00</updated><category term='ssh'/><category term='Spring'/><category term='Messages'/><category term='arguments'/><category term='Liferay'/><category term='JSP'/><category term='ResourceBundleMessageSource'/><category term='Java'/><category term='Maven'/><title type='text'>Programmer's Cookbook</title><subtitle type='html'>Recipes for the practical programmer</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>21</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-22201720.post-5792481273987998574</id><published>2010-09-10T08:58:00.001-07:00</published><updated>2010-09-10T09:26:15.294-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Liferay'/><title type='text'>Liferay 6: Editing the dockbar</title><content type='html'>The dockbar is a Struts portlet, so it isn't something that you can control in a theme.  Instead, you can modify the JSP that the portlet view uses.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;View Files&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;/webapps/ROOT/html/portlet/dockbar/init.jsp&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;/webapps/ROOT/html/portlet/dockbar/view.jsp&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Whether or not to display the dockbar is controlled in the theme.  So in theory you could create your own portlet or vm file to display a completely custom dockbar.  The theme file &lt;span style="font-family: courier new;"&gt;portal_normal.vm&lt;/span&gt;, and in the default &lt;span style="font-family: courier new;"&gt;portal_normal.vm&lt;/span&gt; you will see this.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code"&gt;&lt;br /&gt;#if($is_signed_in)&lt;br /&gt;  #dockbar()&lt;br /&gt;#end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The dockbar portlet is referenced in the ROOT application (&lt;span style="font-family: courier new;"&gt;/webapps/ROOT/WEB-INF/&lt;/span&gt;) as portlet name/number &lt;span style="font-weight: bold;"&gt;145&lt;/span&gt;.  Snippets of these references are below.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;liberay-portlet.xml&lt;/span&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;portlet&gt;&lt;br /&gt;   &amp;lt;portlet-name&gt;145&amp;lt;/portlet-name&gt;&lt;br /&gt;   &amp;lt;icon&gt;/html/icons/default.png&amp;lt;/icon&gt;&lt;br /&gt;   &amp;lt;struts-path&gt;dockbar&amp;lt;/struts-path&gt;&lt;br /&gt;   &amp;lt;use-default-template&gt;false&amp;lt;/use-default-template&gt;&lt;br /&gt;   &amp;lt;show-portlet-access-denied&gt;false&amp;lt;/show-portlet-access-denied&gt;&lt;br /&gt;   &amp;lt;show-portlet-inactive&gt;false&amp;lt;/show-portlet-inactive&gt;&lt;br /&gt;   &amp;lt;private-request-attributes&gt;false&amp;lt;/private-request-attributes&gt;&lt;br /&gt;   &amp;lt;private-session-attributes&gt;false&amp;lt;/private-session-attributes&gt;&lt;br /&gt;   &amp;lt;render-weight&gt;50&amp;lt;/render-weight&gt;&lt;br /&gt;   &amp;lt;add-default-resource&gt;true&amp;lt;/add-default-resource&gt;&lt;br /&gt;   &amp;lt;system&gt;true&amp;lt;/system&gt;&lt;br /&gt;&amp;lt;/portlet&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;portlet-custom.xml&lt;/span&gt;&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;portlet&gt;&lt;br /&gt;   &amp;lt;portlet-name&gt;145&amp;lt;/portlet-name&gt;&lt;br /&gt;   &amp;lt;display-name&gt;Dockbar&amp;lt;/display-name&gt;&lt;br /&gt;   &amp;lt;portlet-class&gt;com.liferay.portlet.StrutsPortlet&amp;lt;/portlet-class&gt;&lt;br /&gt;   &amp;lt;init-param&gt;&lt;br /&gt;       &amp;lt;name&gt;view-action&amp;lt;/name&gt;&lt;br /&gt;       &amp;lt;value&gt;/dockbar/view&amp;lt;/value&gt;&lt;br /&gt;   &amp;lt;/init-param&gt;&lt;br /&gt;   &amp;lt;expiration-cache&gt;0&amp;lt;/expiration-cache&gt;&lt;br /&gt;   &amp;lt;supports&gt;&lt;br /&gt;       &amp;lt;mime-type&gt;text/html&amp;lt;/mime-type&gt;&lt;br /&gt;   &amp;lt;/supports&gt;&lt;br /&gt;   &amp;lt;resource-bundle&gt;com.liferay.portlet.StrutsResourceBundle&amp;lt;/resource-bundle&gt;&lt;br /&gt;   &amp;lt;security-role-ref&gt;&lt;br /&gt;       &amp;lt;role-name&gt;power-user&amp;lt;/role-name&gt;&lt;br /&gt;   &amp;lt;/security-role-ref&gt;&lt;br /&gt;   &amp;lt;security-role-ref&gt;&lt;br /&gt;       &amp;lt;role-name&gt;user&amp;lt;/role-name&gt;&lt;br /&gt;   &amp;lt;/security-role-ref&gt;&lt;br /&gt;&amp;lt;/portlet&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/22201720-5792481273987998574?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/5792481273987998574/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=5792481273987998574' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/5792481273987998574'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/5792481273987998574'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2010/09/liferay-6-editing-dockbar.html' title='Liferay 6: Editing the dockbar'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-8798192012517430867</id><published>2008-06-27T09:52:00.000-07:00</published><updated>2008-06-27T10:06:45.483-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JSP'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='arguments'/><category scheme='http://www.blogger.com/atom/ns#' term='ResourceBundleMessageSource'/><category scheme='http://www.blogger.com/atom/ns#' term='Messages'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><title type='text'>Spring + ResourceBundleMessageSource + Arguments</title><content type='html'>Recently I had a request to move some hard-coded error messages from the source files to an external properties file. At first I ran into some issues since we were using parameters, but spring's taglib allows for that so here goes:&lt;br /&gt;&lt;br /&gt;&lt;span&gt;Spring config&lt;/span&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt; &lt;/code&gt;&lt;code&gt; &amp;lt;property name="basename" value="com.harryfwong.shared.messages"&amp;gt;&lt;br /&gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;com/harryfwong/shared/messages.properties&lt;/span&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;error.testingParameters=Are you passing in Parameters: {0}, {1}?&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;displayError.jsp&lt;/span&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%&amp;gt;&lt;br /&gt;&amp;lt;spring:message code="error.testParameters" argumentseparator=";" arguments="param1;param2"&amp;gt;&lt;br /&gt;&amp;lt;/spring:message&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22201720-8798192012517430867?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/8798192012517430867/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=8798192012517430867' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/8798192012517430867'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/8798192012517430867'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2008/06/spring-resourcebundlemessagesource.html' title='Spring + ResourceBundleMessageSource + Arguments'/><author><name>Harry F Wong</name><uri>http://www.blogger.com/profile/10752388601585666932</uri><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>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-7644472562583386837</id><published>2008-06-13T07:47:00.000-07:00</published><updated>2008-06-13T07:58:47.778-07:00</updated><title type='text'>Parsing Comma Seperated Values (CSV) in Java</title><content type='html'>I suggest using &lt;a href="http://sourceforge.net/projects/javacsv/"&gt;Java CSV Library&lt;/a&gt;, it is very easy to use.  If you use Maven 2, you can use this to load it as a dependancy.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background#eee;border:solid 1px #999;margin:5px"&gt;&lt;br /&gt;&amp;lt;dependency&gt;&lt;br /&gt;  &amp;lt;groupId&gt;net.sourceforge.javacsv&amp;lt;/groupId&gt;&lt;br /&gt;  &amp;lt;artifactId&gt;javacsv&amp;lt;/artifactId&gt;&lt;br /&gt;  &amp;lt;version&gt;2.0&amp;lt;/version&gt;&lt;br /&gt;&amp;lt;/dependency&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The code below reads in a CSV file, parsing one line at a time, splitting each line into the &lt;code&gt;vals&lt;/code&gt; array. &lt;br /&gt;&lt;br /&gt;&lt;pre style="background#eee;border:solid 1px #999;margin:5px"&gt;&lt;br /&gt;CsvReader rdr = new CsvReader("simeFile.csv");&lt;br /&gt;while (rdr.readRecord()) {&lt;br /&gt;    String[] vals = rdr.getValues();&lt;br /&gt;    ...&lt;br /&gt;    System.out.println(vals.length);&lt;br /&gt;    // process here&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/22201720-7644472562583386837?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/7644472562583386837/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=7644472562583386837' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/7644472562583386837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/7644472562583386837'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2008/06/parsing-comma-seperated-values-csv-in.html' title='Parsing Comma Seperated Values (CSV) in Java'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-2634931265096095290</id><published>2008-06-13T07:38:00.001-07:00</published><updated>2008-06-13T07:43:56.204-07:00</updated><title type='text'>DB Schema for Spring-Security 2.0</title><content type='html'>Spring Security was only recently released, so the docs are fairly poor.  So if you have been looking everywhere for the DB schema to use with &amp;lt;jdbc-user-service/&gt;, look no further.&lt;br /&gt;&lt;br /&gt;Here are the generic table create statements.  The foreign-key columns are marked, which you can either ignore or translate them for your specific DB.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background:#eee;margin:5px;border:solid 1px #999"&gt;&lt;br /&gt;create table users (&lt;br /&gt;  username varchar(32) primary key,&lt;br /&gt;  password varchar(64) not null,&lt;br /&gt;  enabled bit not null&lt;br /&gt;)&lt;br /&gt; &lt;br /&gt;create table authorities (&lt;br /&gt;  username varchar(32) not null, [FK]&lt;br /&gt;  authority varchar(64) not null&lt;br /&gt;)&lt;br /&gt; &lt;br /&gt;create table groups (&lt;br /&gt;  id number(10) primary key,&lt;br /&gt;  group_name varchar(64)&lt;br /&gt;)&lt;br /&gt; &lt;br /&gt;create table group_members (&lt;br /&gt;  group_id number(10) not null, [FK]&lt;br /&gt;  username varchar(32) not null [FK]&lt;br /&gt;)&lt;br /&gt; &lt;br /&gt;create table group_authorities (&lt;br /&gt;  group_id number(10) not null, [FK]&lt;br /&gt;  authority varchar(64) not null&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/22201720-2634931265096095290?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/2634931265096095290/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=2634931265096095290' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/2634931265096095290'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/2634931265096095290'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2008/06/db-schema-for-spring-security-20.html' title='DB Schema for Spring-Security 2.0'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-4205886934967616676</id><published>2008-06-13T07:24:00.000-07:00</published><updated>2008-06-13T07:35:07.732-07:00</updated><title type='text'>Creating an MD5 dogest of a Java String</title><content type='html'>You can generate MD5's using Java's own MessageDigest class.  This class will generate the MD5 value as a set of bytes.  Typically this isn't what you want.  In most cases you will want to create a hex string from the bytes, so it looks something like this, "007868b95b02a639bed49adea41f266e".  You can rectify this by downloading the &lt;a href="http://commons.apache.org/codec/"&gt;commons-codec library&lt;/a&gt;, and running the bytes through the Hex class.&lt;br /&gt;&lt;br /&gt;The code below does just this.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background:#eee;padding5px;border:solid 1px #999"&gt;&lt;br /&gt;import java.security.MessageDigest;&lt;br /&gt;import import org.apache.commons.codec.binary.Hex;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;String myString = "The string to create a digest from";&lt;br /&gt;String md5String = null;&lt;br /&gt;&lt;br /&gt;try {&lt;br /&gt;  MessageDigest digest = MessageDigest.getInstance("MD5");&lt;br /&gt;  digest.update(myString.getBytes());&lt;br /&gt;  md5String = new String(Hex.encodeHex(digest.digest()));&lt;br /&gt;}&lt;br /&gt;catch (Exception e) {}&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/22201720-4205886934967616676?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/4205886934967616676/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=4205886934967616676' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/4205886934967616676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/4205886934967616676'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2008/06/creating-md5-dogest-of-java-string.html' title='Creating an MD5 dogest of a Java String'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-2323567817836631150</id><published>2007-12-16T12:53:00.000-08:00</published><updated>2007-12-16T12:57:11.847-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ssh'/><title type='text'>Setting up SSH keys</title><content type='html'>This is one of those things that I had an admin write up for me, and something I always always forget.  So I am posting here so that I don't lose it, and perhaps it will help someone else out.&lt;br /&gt;&lt;br /&gt;1. Go to your home directory&lt;br /&gt;&lt;br /&gt;2. Execute: ssh-keygen -t dsa&lt;br /&gt;&lt;br /&gt;This may take a minute or so to run.  Take defaults when prompted.&lt;br /&gt;&lt;br /&gt;  3. cd to ~/.ssh directory&lt;br /&gt;&lt;br /&gt;4. Copy id_dsa.pub to target ~/.ssh directory on target server with a temporary name (i.e.  .keys)&lt;br /&gt;&lt;br /&gt;5. On the target machine rename the temp file to "authorized_keys", but make sure that it doesn't already exist.&lt;br /&gt;&lt;br /&gt;6. Make sure that the file authorized_keys is chmod'ed to 600.&lt;br /&gt;&lt;br /&gt;7. Try it out&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22201720-2323567817836631150?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/2323567817836631150/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=2323567817836631150' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/2323567817836631150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/2323567817836631150'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2007/12/setting-up-ssh-keys.html' title='Setting up SSH keys'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-6795976354157355226</id><published>2007-10-01T17:16:00.000-07:00</published><updated>2007-10-01T17:39:07.255-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Maven'/><title type='text'>Creating a Maven 2 Plugin (Mojo)</title><content type='html'>Creating a new plugin (a.k.a. Mojo) is really dead simple, although the Maven site seems to make it complicated.&lt;br /&gt;&lt;br /&gt;Start by running Maven at the command line to create a new plugin project.  &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;mvn archetype:create \&lt;br /&gt;  -DgroupId=&lt;span style="font-weight:bold;"&gt;com.blogspot.progcookbook.mojo&lt;/span&gt; \&lt;br /&gt;  -DartifactId=&lt;span style="font-weight:bold;"&gt;maven-coolass-plugin&lt;/span&gt; \&lt;br /&gt;  -DarchetypeGroupId=org.apache.maven.archetypes \&lt;br /&gt;  -DarchetypeArtifactId=maven-archetype-mojo&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The groupId will typically be the same for all of your plugins.  I like to use my reverse domain name followed by ".mojo".  The artifactId naming is &lt;span style="font-style:italic;"&gt;very&lt;/span&gt; important.  &lt;span style="font-weight:bold;"&gt;Besure to use the format "maven-&amp;lt;PLUGIN_NAME&amp;gt;-plugin".&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The plugin name is used to execute individual goals.  So if my plugin is named "coolass" and the goal is "runit", then I would type "mvn coolass:runit" at the command line to execute the goal.&lt;br /&gt;&lt;br /&gt;After you run the command above, it will create a sample project with one class called MyMojo.java.  Rename it as needed and make a copy for each "goal" supported by your plugin.&lt;br /&gt;&lt;br /&gt;The goal name will need to be defined in XDoclet style tags just above the class name in the file.  Here is the class definition in the sample MyMojo.java file.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;/**&lt;br /&gt; * Goal which touches a timestamp file.&lt;br /&gt; *&lt;br /&gt; * &lt;span style="font-weight:bold;"&gt;@goal touch&lt;/span&gt;&lt;br /&gt; * &lt;br /&gt; * @phase process-sources&lt;br /&gt; */&lt;br /&gt;public class MyMojo&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Here the goal is "touch", so the way this works is that running "mvn coolass:touch" will run the execute() method in this class.  Rename the goal as needed.&lt;br /&gt;&lt;br /&gt;In the sample file you will see a single member variable named outputDirectory.  Note the XDoclet style annotation above it.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Location of the file.&lt;br /&gt;     * @parameter expression="${project.build.directory}"&lt;br /&gt;     * @required&lt;br /&gt;     */&lt;br /&gt;    private File outputDirectory;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The &lt;span style="font-weight:bold;"&gt;@parameter&lt;/span&gt; annotation makes this configurable in the pom.xml, and the expression defines the default value.  Add and remove parameters as needed, using &lt;span style="font-weight:bold;"&gt;@required&lt;/span&gt; when you want to force the issue.&lt;br /&gt;&lt;br /&gt;The last step is to install your new plugin in your local repository.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;mvn install&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;There are more details, but this is enough to get you up and running.  Check out the &lt;a href="http://maven.apache.org/plugin-developers/index.html"&gt;Maven Plugin Dev Center&lt;/a&gt; for more details.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22201720-6795976354157355226?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/6795976354157355226/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=6795976354157355226' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/6795976354157355226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/6795976354157355226'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2007/10/creating-maven-2-plugin-mojo.html' title='Creating a Maven 2 Plugin (Mojo)'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-1796648187936019875</id><published>2007-01-03T07:06:00.000-08:00</published><updated>2007-01-03T07:12:46.829-08:00</updated><title type='text'>Create tar files with date and time stamp</title><content type='html'>There are many different tools to deploy files or directories of files from server to server. There's tar, rsync, remote copy ... a bunch of things. Whichever method you use, it's in your best interests to make a backup.&lt;br /&gt;&lt;br /&gt;To help you keep track of the backups you make at any time, use "date" along with "tar" to create timestamped files:&lt;br /&gt;&lt;br /&gt;tar -cvfX filename_`date +%Y%m%d_%H%M%S`.tar *&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;example:&lt;br /&gt;&lt;br /&gt;#  find .&lt;br /&gt;./somedir&lt;br /&gt;./somedir/a.txt&lt;br /&gt;./b.txt&lt;br /&gt;./c.txt&lt;br /&gt;&lt;br /&gt;# tar -cvfX filename_`date +%Y%m%d_%H%M%S`.tar *&lt;br /&gt;a build.sh 0K&lt;br /&gt;a c.txt 0K&lt;br /&gt;a somedir/ 0K&lt;br /&gt;a somedir/a.txt 0K&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# ls *.tar&lt;br /&gt;filename_20070103_101105.tar&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Now, if you need to back out the tar file you explode you can just go get your previously dated version.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22201720-1796648187936019875?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/1796648187936019875/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=1796648187936019875' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/1796648187936019875'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/1796648187936019875'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2007/01/create-tar-files-with-date-and-time.html' title='Create tar files with date and time stamp'/><author><name>John Reynolds</name><uri>http://www.blogger.com/profile/18131901462608185325</uri><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-22201720.post-114537679566723913</id><published>2006-04-18T09:11:00.000-07:00</published><updated>2006-04-18T09:13:15.680-07:00</updated><title type='text'>Removing bad line breaks in text files</title><content type='html'>Have you ever opened up a text file in a VI editor and you see this character at the end of this line:  ^M&lt;br /&gt;&lt;br /&gt;For example...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;?xml version = &amp;quot;1.0&amp;quot; encoding = &amp;quot;windows-1252&amp;quot;?&amp;gt;^M&lt;br /&gt;&amp;lt;web-app&amp;gt;^M&lt;br /&gt;  &amp;lt;description&amp;gt;Empty web.xml file for Web Application&amp;lt;/description&amp;gt;^M&lt;br /&gt;  &amp;lt;context-param&amp;gt;^M&lt;br /&gt;    &amp;lt;param-name&amp;gt;DBUrl&amp;lt;/param-name&amp;gt;^M&lt;br /&gt;    &amp;lt;param-value&amp;gt;jdbc:oracle:thin:@ora:1521:ora&amp;lt;/param-value&amp;gt;^M&lt;br /&gt;  &amp;lt;/context-param&amp;gt;^M&lt;br /&gt;  &amp;lt;context-param&amp;gt;^M&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In many instances, these characters don’t cause a problem (e.g. your browser, an editor) but they do cause problems for CSV or XML files or anything that needs to be parsed, because they will not be validated correctly.&lt;br /&gt;&lt;br /&gt;They occur because some programs are not consistent in the way they insert the line breaks so you end up with some lines that have both a carrage return and a ^M and some lines that have a ^M and no carrage return. It is often encountered between editors on DOS and *nix. For example if you use a text editor on your windows machine, it may not produce line breaks the same way VI would produce them on a *nix server. I had heard one time that this can also happen when FTPing a file from your machine to a *nix server when using ASCII mode and that that the safest way is to zip up files and FTP as binary – but I couldn’t find anything to substantiate that.&lt;br /&gt;&lt;br /&gt;The solution to removing these in VI is to run the following substitution&lt;br /&gt;&lt;br /&gt;:s/^M//g&lt;br /&gt;&lt;br /&gt;***NOTE***: you have to enter the "^M" as "CTRL-V CTRL-M" and not "CARET M". This "^M" is a special character that needs special handling. The substitution above will remove all the ^M characters and replace them with nothing.&lt;br /&gt;&lt;br /&gt;Also, if you don’t want to use VI, you use shell + perl to remove these characters on from the command line. Again, you can’t cut/paste these commands because you need to type ^M as “CTRL-V CTRL-M” as described above.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;# recurse a directory, removing ^M from all files&lt;br /&gt;find . -type f -exec perl -pi -e &amp;quot;s/^M//g&amp;quot; {} \;&lt;br /&gt;&lt;br /&gt;# remove ^M from a specific file&lt;br /&gt;perl -pi -e &amp;quot;s/^M//g&amp;quot; somefile.txt&lt;br /&gt;&lt;br /&gt;# remove ^M from a bunch of files&lt;br /&gt;perl -pi -e &amp;quot;s/^M//g&amp;quot; */*.java *.txt&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/22201720-114537679566723913?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/114537679566723913/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=114537679566723913' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/114537679566723913'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/114537679566723913'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2006/04/removing-bad-line-breaks-in-text-files.html' title='Removing bad line breaks in text files'/><author><name>John Reynolds</name><uri>http://www.blogger.com/profile/18131901462608185325</uri><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-22201720.post-113984177821151460</id><published>2006-02-13T06:33:00.000-08:00</published><updated>2006-02-13T06:48:44.283-08:00</updated><title type='text'>Using ROWNUM Properly for Pagination</title><content type='html'>I learned a very interesting thing about Oracle's ROWNUM variable behaves and how it affects queries that have on ORDER BY clause.&lt;br /&gt;&lt;br /&gt;My goal was to create a Java Servlet that showed query results in a list format, with links to more pages of results and PREV and NEXT links - much like a search engine. For example, if there were 100 results, and 10 results per page, there would be PREV and NEXT links around links for the individual pages ( 1 2 3 4 5 6 7 8 9 10). Something we've all seen before.&lt;br /&gt;&lt;br /&gt;Not seeing any problem with Oracle's ROWNUM, my basic thinking was to pass a START and END to the Servlet, which would dynamically create my queries and they would basically look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;SELECT * from table where rownum between &amp;lt;START&amp;gt; and &amp;lt;END&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For example, the first page results query would be:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;SELECT * from table where rownum between 1 and 5&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The next page would be:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;SELECT * from table where rownum between 6 and 10&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and so on.&lt;br /&gt;&lt;br /&gt;What I didn't realize is that ROWNUM cannot be used this way because ROWNUM doesn't behave as you think it does, and it cannot be used reliably with any ORDER BY clause. See below&lt;br /&gt;&lt;br /&gt;Let's start by getting a known set of results, in this case there are 10 results for employees with last name "smith". Note the value of ROWNUM&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SQL&gt; select first_name, last_name, rownum &lt;br /&gt;        from employee &lt;br /&gt;        where last_name = 'SMITH';&lt;br /&gt;&lt;br /&gt;FIRST_NAME      LAST_NAME                          ROWNUM&lt;br /&gt;--------------- ------------------------------ ----------&lt;br /&gt;CLARA           SMITH                                 1&lt;br /&gt;DEBORAH         SMITH                                 2 &lt;br /&gt;GERTRUDE        SMITH                                 3 &lt;br /&gt;JEFF            SMITH                                 4 &lt;br /&gt;KEITH           SMITH                                 5 &lt;br /&gt;KENN            SMITH                                 6 &lt;br /&gt;MARK            SMITH                                 7 &lt;br /&gt;MARYLYNN        SMITH                                 8 &lt;br /&gt;MATTHEW         SMITH                                 9 &lt;br /&gt;NICOLE          SMITH                                10 &lt;br /&gt;&lt;br /&gt;10 rows selected.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt; &lt;br /&gt;Great! That looks fine ... 1 through 10, they're all in order. Let's try getting just the first 5 results.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SQL&gt; select first_name, last_name, rownum &lt;br /&gt;        from employee &lt;br /&gt;        where rownum between 1 and 5 and &lt;br /&gt;        last_name = 'SMITH';&lt;br /&gt;&lt;br /&gt;FIRST_NAME      LAST_NAME                          ROWNUM &lt;br /&gt;--------------- ------------------------------ ----------&lt;br /&gt;CLARA           SMITH                                 1 &lt;br /&gt;DEBORAH         SMITH                                 2 &lt;br /&gt;GERTRUDE        SMITH                                 3 &lt;br /&gt;JEFF            SMITH                                 4 &lt;br /&gt;KEITH           SMITH                                 5 &lt;br /&gt;&lt;br /&gt;5 rows selected.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Still looks good. In reality though, i want to be able to change how the results are sorted, so i create a dynamic ORDER BY clause. In this example, let me use LOCATION:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SQL&gt; select first_name, last_name, location, rownum &lt;br /&gt;from employee &lt;br /&gt;where last_name = 'SMITH' &lt;br /&gt;order by location;&lt;br /&gt;&lt;br /&gt;FIRST_NAME      LAST_NAME                    LOC     ROWNUM &lt;br /&gt;--------------- ---------------------------- ----- ---------- &lt;br /&gt;CLARA           SMITH                        211            1 &lt;br /&gt;JEFF            SMITH                        329            6 &lt;br /&gt;GERTRUDE        SMITH                        335            4 &lt;br /&gt;MARYLYNN        SMITH                        335            8 &lt;br /&gt;KEITH           SMITH                        348            5 &lt;br /&gt;MARK            SMITH                        349            7 &lt;br /&gt;MATTHEW         SMITH                        450            9 &lt;br /&gt;NICOLE          SMITH                        450           10 &lt;br /&gt;DEBORAH         SMITH                        813            3&lt;br /&gt;KENN            SMITH                        847            2 &lt;br /&gt;&lt;br /&gt;10 rows selected.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Holy cow! Why is my ROWNUM out of order? Anyway, let me see if my ROWNUM filtering clause still works for results 1 - 5. I should expect to see CLARA, JEFF, GERTRUDE, MARYLYNN, and KEITH as my results, in order.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;SQL&gt; select first_name, last_name, location, rownum &lt;br /&gt;from employee &lt;br /&gt;where rownum between 1 and 5 and &lt;br /&gt;  last_name = 'SMITH' &lt;br /&gt;order by location;&lt;br /&gt;&lt;br /&gt;FIRST_NAME      LAST_NAME                      LOC     ROWNUM&lt;br /&gt;--------------- ------------------------------ ----- ---------- &lt;br /&gt;CLARA           SMITH                        211            1 &lt;br /&gt;GERTRUDE        SMITH                        335            4 &lt;br /&gt;KEITH           SMITH                        348            5 &lt;br /&gt;DEBORAH         SMITH                        813            3 &lt;br /&gt;KENN            SMITH                        847            2 &lt;br /&gt;&lt;br /&gt;5 rows selected.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt; &lt;br /&gt;OH NO! This isn't going to work! From my research, ROWNUM is a value that is inherent to that row of data, and *not* a value that is computed on the fly. WHAT A BUMMER!&lt;br /&gt;&lt;br /&gt;From some more research, I found a trick that is 100% effective and does not have any performance impact. &lt;br /&gt;&lt;br /&gt;What you have to do is embed your original query with NO USE OF ROWNUM in 2 embedded SQL calls&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SQL&gt; select * from (&lt;br /&gt;       SELECT  x.*, rownum as r FROM (&lt;br /&gt;           select first_name, last_name, location, rownum &lt;br /&gt;         from employee &lt;br /&gt;         where last_name = 'SMITH' &lt;br /&gt;         order by location&lt;br /&gt;       ) x&lt;br /&gt;     )&lt;br /&gt;     where r between 1 AND 5;&lt;br /&gt;&lt;br /&gt;FIRST_NAME      LAST_NAME                      LOC     ROWNUM          R &lt;br /&gt;--------------- ------------------------------ ----- ---------- ---------- &lt;br /&gt;CLARA           SMITH                        211            1          1 &lt;br /&gt;JEFF            SMITH                        329            6          2 &lt;br /&gt;GERTRUDE        SMITH                        335            4          3 &lt;br /&gt;MARYLYNN        SMITH                        335            8          4 &lt;br /&gt;KEITH           SMITH                        348            5          5 &lt;br /&gt;&lt;br /&gt;5 rows selected.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;These are the results I expected in the first place when re-ordering by location.&lt;br /&gt;&lt;br /&gt;And as an aside, MYSQL offers the LIMIT BY clause which works with the behavior you'd expect, without having to jump through hoops to get the subset you want.&lt;br /&gt;&lt;br /&gt;Example:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;select first_name, last_name, location, rownum &lt;br /&gt;from employee &lt;br /&gt;where &lt;br /&gt;   rownum between 1 and 5 and &lt;br /&gt;   last_name = 'SMITH' &lt;br /&gt;LIMIT BY 1, 5 &lt;br /&gt;order by location;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt; &lt;br /&gt;This would return me exactly what I want.  Makes you wonder why ORACLE is so expensive and doesn't offer this seemingly intuitive functionality.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22201720-113984177821151460?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/113984177821151460/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=113984177821151460' title='19 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113984177821151460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113984177821151460'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2006/02/using-rownum-properly-for-pagination.html' title='Using ROWNUM Properly for Pagination'/><author><name>John Reynolds</name><uri>http://www.blogger.com/profile/18131901462608185325</uri><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>19</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-113983650777578627</id><published>2006-02-13T05:05:00.000-08:00</published><updated>2006-02-13T05:16:45.913-08:00</updated><title type='text'>Test Well-Formedness of XML with Perl</title><content type='html'>Sometimes you run into a problem where a tool that you are using reports an error with an XML file, but doesn't report the exact location.  When this happens you need to use some other tool to text the structure of the XML file, and report the exact location of the error.  When you don't have a tool available for this task, you can use Perl at the command line.&lt;br /&gt;&lt;br /&gt;This will read the file config.xml, and report any errors that it finds.  If no errors are found, it will return nothing.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; perl -MXML::Parser -e '$x = XML::Parser-&gt;new;$x-&gt;parsefile($ARGV[0])' config.xml&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Sample output of the command, reporting the error at the 6th character of line 36:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;mismatched tag at line 32, column 6, byte 1078&lt;br /&gt; at /usr/lib/perl5/vendor_perl/5.8/cygwin/XML/Parser.pm line 187&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This command takes it a little further.  Not only will it show the location of the error, but it will also print out debugging information for the parser, which may be useful on some cases. &lt;br /&gt;&lt;pre&gt;&lt;br /&gt; perl -MXML::Parser -e '$x = XML::Parser-&gt;new(Style=&gt;"Debug");$x-&gt;parsefile($ARGV[0])' config.xml&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/22201720-113983650777578627?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/113983650777578627/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=113983650777578627' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113983650777578627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113983650777578627'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2006/02/test-well-formedness-of-xml-with-perl.html' title='Test Well-Formedness of XML with Perl'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-113975443581661993</id><published>2006-02-12T06:22:00.000-08:00</published><updated>2006-02-13T04:37:58.996-08:00</updated><title type='text'>Get Shared Windows Network Resources with Perl</title><content type='html'>The following code can be run on Windows using &lt;a href="http://activestate.com/Products/ActivePerl/"&gt;ActiveState's Perl&lt;/a&gt;.  It will print data about each shared network resources on the machine.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;use Win32::NetResource qw(:DEFAULT GetSharedResources);&lt;br /&gt;&lt;br /&gt;if (GetSharedResources(my $resources, RESOURCETYPE_ANY,&lt;br /&gt;  {RemoteName =&gt; "\\\\" . Win32::NodeName()}))&lt;br /&gt;{&lt;br /&gt;  foreach my $href (@$resources) {&lt;br /&gt;    print "-----\n";&lt;br /&gt;    foreach (keys %$href) {&lt;br /&gt;      print "$_: $href-&gt;{$_}\n";&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Sample Output:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;C:\&gt;perl getresources.pl&lt;br /&gt;-----&lt;br /&gt;LocalName:&lt;br /&gt;Scope: 2&lt;br /&gt;DisplayType: 3&lt;br /&gt;Type: 1&lt;br /&gt;Provider: Microsoft Windows Network&lt;br /&gt;Usage: 1&lt;br /&gt;Comment:&lt;br /&gt;RemoteName: \\RHANSON\outgoing&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;See also: &lt;a href="http://aspn.activestate.com/ASPN/CodeDoc/libwin32/NetResource/NetResource.html"&gt;Perldoc for Win32::NetResource&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22201720-113975443581661993?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/113975443581661993/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=113975443581661993' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113975443581661993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113975443581661993'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2006/02/get-shared-windows-network-resources.html' title='Get Shared Windows Network Resources with Perl'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-113967738685804213</id><published>2006-02-11T08:46:00.000-08:00</published><updated>2006-02-11T09:05:49.976-08:00</updated><title type='text'>Replace Text In Multiple Files With Perl</title><content type='html'>You can use Perl at the command line (or even a short script) to make text replacements in a list of files.  The key is to use three of Perl's command line switches.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-i[extension] In place editing of files.&lt;br /&gt;-e 'code block' Evaluates the specified code.&lt;br /&gt;-p Loops over code for each argument, prints $_.&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;These three switches combined will open each file that is passed as an argument, execute your code for each line in the file, and replace the original file with the output of rhe code.  The -i switch takes an optional extension which it will use to create backups of the original (recommended!).&lt;br /&gt;&lt;br /&gt;Replace all occurences of "foo" with "bar"&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;perl -pi.bak -e 's/foo/bar/g' *&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Fix all &lt;span style="font-style:italic;"&gt;href&lt;/span&gt; attributes in all HTML files to use "http://www.foo.com" instead of "http://www.bar.com", recursively.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# broken into multiple lines for readability&lt;br /&gt;&lt;br /&gt;perl -pi.bak&lt;br /&gt;  -e 's!(href=(["']))http://www.foo.com\2!$1http://www.bar.com!g'&lt;br /&gt;  `find . -name \*.html`&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;See &lt;a href="http://perldoc.perl.org/perlrun.html"&gt;perldoc perlrun&lt;/a&gt; for more information on Perl's command line switches.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22201720-113967738685804213?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/113967738685804213/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=113967738685804213' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113967738685804213'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113967738685804213'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2006/02/replace-text-in-multiple-files-with.html' title='Replace Text In Multiple Files With Perl'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-113953458362021418</id><published>2006-02-09T17:20:00.000-08:00</published><updated>2006-02-09T17:23:03.623-08:00</updated><title type='text'>Text Wrapping Function for Java</title><content type='html'>Note that the Jakarta commons-lang package has similar functionality.  I would only use this were using commons-lang was not an option.&lt;br /&gt;&lt;br /&gt;This function takes a string value and a line length, and returns an array of lines. Lines are cut on word boundaries, where the word boundary is a space character.  Spaces are included as the last character of a word, so most lines will actually end with a space. This isn't too problematic, but will cause a word to wrap if that space pushes it past the max line length.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;String text = "this is a long line of text that needs to be wrapped";&lt;br /&gt;String [] lines = wrapText(text, 20);&lt;br /&gt;for (int i = 0; i &lt; lines.length; i++) {&lt;br /&gt;    System.out.println(lines[i]);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;static String [] wrapText (String text, int len)&lt;br /&gt;{&lt;br /&gt;  // return empty array for null text&lt;br /&gt;  if (text == null)&lt;br /&gt;  return new String [] {};&lt;br /&gt;&lt;br /&gt;  // return text if len is zero or less&lt;br /&gt;  if (len &lt;= 0)&lt;br /&gt;  return new String [] {text};&lt;br /&gt;&lt;br /&gt;  // return text if less than length&lt;br /&gt;  if (text.length() &lt;= len)&lt;br /&gt;  return new String [] {text};&lt;br /&gt;&lt;br /&gt;  char [] chars = text.toCharArray();&lt;br /&gt;  Vector lines = new Vector();&lt;br /&gt;  StringBuffer line = new StringBuffer();&lt;br /&gt;  StringBuffer word = new StringBuffer();&lt;br /&gt;&lt;br /&gt;  for (int i = 0; i &lt; chars.length; i++) {&lt;br /&gt;    word.append(chars[i]);&lt;br /&gt;&lt;br /&gt;    if (chars[i] == ' ') {&lt;br /&gt;      if ((line.length() + word.length()) &gt; len) {&lt;br /&gt;        lines.add(line.toString());&lt;br /&gt;        line.delete(0, line.length());&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      line.append(word);&lt;br /&gt;      word.delete(0, word.length());&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // handle any extra chars in current word&lt;br /&gt;  if (word.length() &gt; 0) {&lt;br /&gt;    if ((line.length() + word.length()) &gt; len) {&lt;br /&gt;      lines.add(line.toString());&lt;br /&gt;      line.delete(0, line.length());&lt;br /&gt;    }&lt;br /&gt;    line.append(word);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // handle extra line&lt;br /&gt;  if (line.length() &gt; 0) {&lt;br /&gt;    lines.add(line.toString());&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  String [] ret = new String[lines.size()];&lt;br /&gt;  int c = 0; // counter&lt;br /&gt;  for (Enumeration e = lines.elements(); e.hasMoreElements(); c++) {&lt;br /&gt;    ret[c] = (String) e.nextElement();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return ret;&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/22201720-113953458362021418?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/113953458362021418/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=113953458362021418' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113953458362021418'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113953458362021418'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2006/02/text-wrapping-function-for-java.html' title='Text Wrapping Function for Java'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-113953436116408841</id><published>2006-02-09T17:18:00.000-08:00</published><updated>2006-02-09T17:19:21.163-08:00</updated><title type='text'>Load XML File With JAXP</title><content type='html'>The following is a short example of loading a file using JAXP.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;import javax.xml.parsers.*;&lt;br /&gt;import org.xml.sax.*;&lt;br /&gt;import org.w3c.dom.*;&lt;br /&gt;&lt;br /&gt;public class Example {&lt;br /&gt;&lt;br /&gt;    static Document document;&lt;br /&gt;&lt;br /&gt;    public static void main (String[] ARGS) {&lt;br /&gt;        try {&lt;br /&gt;            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();&lt;br /&gt;            DocumentBuilder db = dbf.newDocumentBuilder();&lt;br /&gt;            document = db.parse("./BAKLO211.xml");&lt;br /&gt;        }&lt;br /&gt;        catch (Exception e) {&lt;br /&gt;            e.printStackTrace(System.err);&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/22201720-113953436116408841?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/113953436116408841/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=113953436116408841' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113953436116408841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113953436116408841'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2006/02/load-xml-file-with-jaxp.html' title='Load XML File With JAXP'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-113953426444280839</id><published>2006-02-09T17:16:00.000-08:00</published><updated>2006-02-09T17:17:44.443-08:00</updated><title type='text'>Loading XML File With Xerces</title><content type='html'>Here is a simple example of using Xerces to load an XML document into the DOM.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;import org.apache.xerces.parsers.*;&lt;br /&gt;import org.w3c.dom.traversal.*;&lt;br /&gt;import org.w3c.dom.*;&lt;br /&gt;&lt;br /&gt;public class Example {&lt;br /&gt;&lt;br /&gt;    static Document document;&lt;br /&gt;&lt;br /&gt;    public static void main (String[] ARGS) {&lt;br /&gt;        try {&lt;br /&gt;            DOMParser parser = new DOMParser();&lt;br /&gt;            parser.parse("./sample.xml");&lt;br /&gt;            document = parser.getDocument();&lt;br /&gt;        }&lt;br /&gt;        catch (Exception e) {&lt;br /&gt;            e.printStackTrace(System.err);&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/22201720-113953426444280839?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/113953426444280839/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=113953426444280839' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113953426444280839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113953426444280839'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2006/02/loading-xml-file-with-xerces.html' title='Loading XML File With Xerces'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-113953412699337333</id><published>2006-02-09T17:09:00.000-08:00</published><updated>2006-02-09T17:15:26.993-08:00</updated><title type='text'>Supress SQL*Plus Formatting</title><content type='html'>When you want to dump data using SQL*Plus to a file you can use the &lt;span style="font-style:italic;"&gt;spool&lt;/span&gt; command.  This also writes all of the special formatting, including column headers ever 10 lines or so.  Often you just want the data, and not the extra stuff.  The following is a set of SQL*Plus commands that I usually use to surpress all of the extra formatting, and set a column seperator.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;set newpage 0&lt;br /&gt;set space 0&lt;br /&gt;set linesize 80&lt;br /&gt;set pagesize 0&lt;br /&gt;set echo off&lt;br /&gt;set feedback off&lt;br /&gt;set heading off&lt;br /&gt;set colsep |&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/22201720-113953412699337333?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/113953412699337333/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=113953412699337333' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113953412699337333'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113953412699337333'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2006/02/supress-sqlplus-formatting.html' title='Supress SQL*Plus Formatting'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-113953034940515830</id><published>2006-02-09T16:08:00.000-08:00</published><updated>2006-02-09T16:19:14.343-08:00</updated><title type='text'>IsText and IsBinary Functions for VBScript</title><content type='html'>The following functions determine if a file is text or binary, returing a true or false value. The results are determined by reading the first 512 characters in the file, and if less than 1/3 of the characters &lt;span style="FONT-STYLE: italic"&gt;seem&lt;/span&gt; binary it is flagged as a text document. The algorythm comes from Perl's implementation of this function. A null character that is found will always indicates a binary file. Any character outside of the ASCII range 32-127 (except 8, 9(tab), 10(lf), 12, 13(cr), 27) are considered &lt;span style="FONT-STYLE: italic"&gt;binary-like&lt;/span&gt;.&amp;nbsp; This function will not properly handle UTF-8 encoded files.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;WScript.Echo(CStr(IsText("foo.xls")))&lt;br /&gt;WScript.Echo(CStr(IsBinary("foo.xls")))&lt;br /&gt;&lt;br /&gt;Function IsBinary(strCheckFileName)&lt;br /&gt;   IsBinary = Not IsText(strCheckFileName)&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function IsText(strCheckFileName)&lt;br /&gt;   Dim testFile, fileSpec, len, i, buf, char, odd&lt;br /&gt;&lt;br /&gt;   odd = 0&lt;br /&gt;&lt;br /&gt;   Set fso = CreateObject("Scripting.FileSystemObject")&lt;br /&gt;   On Error Resume Next&lt;br /&gt;   Set testFile = fso.OpenTextFile(strCheckFileName, 1, False, 0)&lt;br /&gt;&lt;br /&gt;   If Err.Number &lt;&gt; 0 Then&lt;br /&gt;      WScript.Echo "Unable to open file. Error: " &amp; Err.Description&lt;br /&gt;      Err.Clear&lt;br /&gt;      IsText = False&lt;br /&gt;      Exit Function&lt;br /&gt;   End If&lt;br /&gt; &lt;br /&gt;   Set fileSpec = fso.GetFile(strCheckFileName)&lt;br /&gt;   len = fileSpec.Size&lt;br /&gt;&lt;br /&gt;   ' read a max of 512 bytes&lt;br /&gt;   If (len &gt; 512) Then&lt;br /&gt;      len = 512&lt;br /&gt;   End If&lt;br /&gt;&lt;br /&gt;   buf = testFile.Read(len)&lt;br /&gt;&lt;br /&gt;   If Err.Number &lt;&gt; 0 Then&lt;br /&gt;      WScript.Echo "Unable to read file. Error: " &amp; Err.Description&lt;br /&gt;      Err.Clear&lt;br /&gt;      IsText = False&lt;br /&gt;      Exit Function&lt;br /&gt;   End If&lt;br /&gt;&lt;br /&gt;   For i = 1 To len&lt;br /&gt;      char = Asc(Mid(buf, i, 1))&lt;br /&gt;&lt;br /&gt;      If char = 0 Then&lt;br /&gt;         ' text can't contain nulls&lt;br /&gt;         odd = len&lt;br /&gt;         Exit For&lt;br /&gt;      ElseIf char &gt; 127 Then&lt;br /&gt;         odd = odd + 1&lt;br /&gt;      ElseIf char &lt; 32 _&lt;br /&gt;          And char &lt;&gt; 8 And char &lt;&gt; 9 And char &lt;&gt; 10 _&lt;br /&gt;          And char &lt;&gt; 12 And char &lt;&gt; 13 And char &lt;&gt; 27 Then&lt;br /&gt;         odd = odd + 1&lt;br /&gt;      End If&lt;br /&gt;   Next&lt;br /&gt;     &lt;br /&gt;   ' allow for up to 1/3 odd&lt;br /&gt;   If (odd * 3) &gt; len Then&lt;br /&gt;      IsText = False&lt;br /&gt;   Else&lt;br /&gt;      IsText = True&lt;br /&gt;   End If&lt;br /&gt;&lt;br /&gt;   testFile.Close&lt;br /&gt;   Set fso = Nothing&lt;br /&gt;End Function&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/22201720-113953034940515830?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/113953034940515830/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=113953034940515830' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113953034940515830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113953034940515830'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2006/02/istext-and-isbinary-functions-for.html' title='IsText and IsBinary Functions for VBScript'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-113952998974975845</id><published>2006-02-09T16:05:00.000-08:00</published><updated>2006-02-09T16:17:20.003-08:00</updated><title type='text'>Automate Perl Module Installation</title><content type='html'>This utility allows you to automate the installation of a set of Perl modules. List the modules in the @modules array and run the script. It uses the CPAN module to download and install the modules, as well as requisite modules.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;use CPAN;&lt;br /&gt;&lt;br /&gt;my @modules = qw(&lt;br /&gt;   HTML::Template&lt;br /&gt;   XML::EasyObj&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;# install needed modules&lt;br /&gt;for my $mod (@modules) {&lt;br /&gt;   print "Checking module '$mod' ...\n";&lt;br /&gt;   my $obj = CPAN::Shell-&gt;expand('Module',$mod);&lt;br /&gt;   $obj-&gt;install;&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/22201720-113952998974975845?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/113952998974975845/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=113952998974975845' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113952998974975845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113952998974975845'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2006/02/automate-perl-module-installation.html' title='Automate Perl Module Installation'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-113952971151200062</id><published>2006-02-09T15:57:00.000-08:00</published><updated>2006-02-09T16:17:40.530-08:00</updated><title type='text'>Print Outlook Email using Perl/OLE</title><content type='html'>This little code snippet is a short example of how Perl can be used to read mails in Outlook using the OLE interface. This particular example looks for a specific mailbox name, then seeks some sub folders by name, then prints out some information about the mails in that folder.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;use strict;&lt;br /&gt;use Win32::OLE;&lt;br /&gt;&lt;br /&gt;# use existing instance if Outlook is already running, or launce a new one&lt;br /&gt;my $ol;&lt;br /&gt;eval {$ol = Win32::OLE-&gt;GetActiveObject('Outlook.Application')};&lt;br /&gt;die "Outlook not installed" if $@;&lt;br /&gt;unless (defined $ol) {&lt;br /&gt;  $ol = Win32::OLE-&gt;new('Outlook.Application', sub {$_[0]-&gt;Quit;})&lt;br /&gt;    or die "Oops, cannot start Outlook";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;my $mailbox = seekFolder($ol-&gt;Session, 'Mailbox - Hanson, Robert');&lt;br /&gt;my $inbox = seekFolder($mailbox, 'Inbox');&lt;br /&gt;my $folder = seekFolder($inbox, 'Perl Class');&lt;br /&gt;&lt;br /&gt;for (my $i = 1; $i &lt;= $folder-&gt;Items-&gt;Count; $i++) {&lt;br /&gt;  print $folder-&gt;Items-&gt;Item($i)-&gt;SenderName . ":";&lt;br /&gt;  print $folder-&gt;Items-&gt;Item($i)-&gt;Subject . "\n";&lt;br /&gt;  print $folder-&gt;Items-&gt;Item($i)-&gt;Body . "\n";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;sub seekFolder {&lt;br /&gt;  my $obj = shift;&lt;br /&gt;  my $target = shift;&lt;br /&gt;&lt;br /&gt;  for (my $i = 1; $i &lt;= $obj-&gt;Folders-&gt;Count; $i++) {&lt;br /&gt;    if ( $obj-&gt;Folders-&gt;Item($i)-&gt;Name eq $target ) {&lt;br /&gt;      return $obj-&gt;Folders-&gt;Item($i);&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/22201720-113952971151200062?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/113952971151200062/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=113952971151200062' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113952971151200062'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113952971151200062'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2006/02/print-outlook-email-using-perlole.html' title='Print Outlook Email using Perl/OLE'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22201720.post-113950132932529229</id><published>2006-02-09T08:08:00.000-08:00</published><updated>2006-02-09T16:25:21.396-08:00</updated><title type='text'>Load XML file with JDOM</title><content type='html'>Here is a quick template for using the JDOM to load an XML file.&amp;nbsp; I like JDOM over other DOM models because it is easy to use, takes less code, and is easy to read once you are done.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;import java.io.File;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;import org.jdom.Document;&lt;br /&gt;import org.jdom.JDOMException;&lt;br /&gt;import org.jdom.input.SAXBuilder;&lt;br /&gt;&lt;br /&gt;public class SomeClass&lt;br /&gt;{&lt;br /&gt;   &lt;br /&gt;    public SomeMethod ()&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;        Document doc = null;&lt;br /&gt;&lt;br /&gt;        SAXBuilder sb = new SAXBuilder();&lt;br /&gt;&lt;br /&gt;        try {&lt;br /&gt;            doc = sb.build(new File("/path/to/some/file.xml"));&lt;br /&gt;        }&lt;br /&gt;        catch (JDOMException e) {&lt;br /&gt;            e.printStackTrace();&lt;br /&gt;        }&lt;br /&gt;        catch (IOException 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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22201720-113950132932529229?l=progcookbook.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progcookbook.blogspot.com/feeds/113950132932529229/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22201720&amp;postID=113950132932529229' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113950132932529229'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22201720/posts/default/113950132932529229'/><link rel='alternate' type='text/html' href='http://progcookbook.blogspot.com/2006/02/load-xml-file-with-jdom.html' title='Load XML file with JDOM'/><author><name>Robert Hanson</name><uri>http://www.blogger.com/profile/08140017560087576986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://home.ptd.net/~hanson/images/banner1.jpg'/></author><thr:total>1</thr:total></entry></feed>
