Monday, December 08, 2003
My Blog has Moved...
My blog has moved over to WordPress
Saturday, August 02, 2003
More on Drive Cleanliness...
I blogged a couple of weeks back on setting up automated nightly defrags on WinXP.
The other day, as drive space was getting a little tight for my comfort, I ran the excellent utility JDiskReport from JGoodies to see just where all my drivespace was allocated and made an alarming discovery.
It seems that when I go through my normal work pattern of "start Jboss/Jetty, then hot-deploy, re-hot-deploy, re-hot-deploy (etc)...", it leaves behind expanded war-file directories in my c:\Documents and Settings\<username>\Local Settings\temp directory (NOTE: Local Settings is a hidden folder - so you have to have your view options set correctly to see it). The directories have the name pattern : Jetty_0_0_0_0_<PortNumber>__<WarName> (where <PortNumber> and <WarName> are your respective jetty listening port and war names).
I just got a new machine about a month and a half back, and in that time I had already accumulated about 1.2 GB worth of temporary files in such a manner (I go throught the, change/build/hot-deploy cycle many times a day).
Anyway - I decided to update my automated nightly defrag task to cleanup this stuff too. Here's the updated version - USE WITH CAUTION - the options I'm passing to DEL and RMDIR are equivalent to "do this recursively and don't prompt me whether I really want to delete all this stuff". The %TEMP% environment variable should expand to C:\Documents and Settings\<username>\Local Settings\temp directory by default. You might want to test this manually from the command prompt a few times just to make sure you've typed it in correctly :
::--- recursively remove all files in the temp directory, without :: prompting, then recursively remove all directories below the :: temp directory, without prompting del /F /S /Q "%TEMP%\*" > c:\temp\Defrag_CleanOutTemp.txt 2>&1 rmdir /S /Q "%TEMP%" >> c:\temp\Defrag_CleanOutTemp.txt 2>&1 ::--- defrag your local drives defrag /v /f c: > c:\temp\Defrag_C.txt 2>&1 defrag /v /f d: > c:\temp\Defrag_D.txt 2>&1
Saturday, July 05, 2003
Precompiling JSP's under JBoss/Jetty 3.2.1...
First, a high-level rundown of the process :
- Using Jasper (a JSP compiler), we'll transform the JSP's into .java files (servlets).
- Jasper will also spit out a web.xml fragment with servlet definitions and mappings for each of the above generated servlets.
- We'll use the ant jspc task to make the previous two bullets a little easier.
- We'll compile the .java files into .class files and then copy them into the WEB-INF/classes directory of the WAR
- We'll insert the web.xml fragment generated by Jasper into your normal web.xml file (at a very specific place).
- build your war as normal
<target name="dist" depends="compile"> <!-- copy required libs to WEB-INF/lib--> <copy todir="${dir.webinf}/lib"> <fileset dir="${dir.thirdpartytools.struts}/lib"/> <fileset dir="${dir.thirdpartytools.jstl}/lib"/> <fileset dir="${dir.search}/dist/lib" includes="${jar.name.search-domain}, ${jar.name.search-services}"/> </copy> <!-- copy classes we built earlier to WEB-INF/classes --> <copy todir="${dir.webinf}/classes"> <fileset dir="${classes}"/> </copy> <!-- copy the tld's we're using to WEB-INF/tld --> <copy todir="${dir.webinf}/tld"> <fileset dir="${dir.thirdpartytools.struts}/tld" includes="*.tld"/> <fileset dir="${dir.thirdpartytools.jstl}/tld" includes="*.tld"/> <fileset dir="${dir.config}/tld" includes="*.tld"/> </copy> <!-- these two properties are the generated web.xml fragment, and the resulting merged xml--> <property name="jspc.webxml.fragment" value="${dir.jspc.temp}/jspc-web-xml-fragment.xml"/> <property name="jspc.webxml.merged" value="${dir.jspc.temp}/merged-web.xml"/> <path id="jspc.classpath"> <path refid="cp.jspc"/> <path refid="cp.jboss"/> <path refid="cp.webclient-thirdparty.tools"/> <path refid="build.classpath"/> <fileset dir="${classes}"/> <fileset dir="${dir.webinf}/lib" includes="*.jar"/> </path> <!-- JSP -> .java --> <jspc srcdir="${dir.docroot}" destdir="${dir.jspc.gensrc}" verbose="9" classpathref="jspc.classpath" webinc="${jspc.webxml.fragment}"> <include name="**/*.jsp"/> </jspc> <!-- .java -> .class --> <javac deprecation="${deprecation.javac}" fork="${fork.javac}" source="${source}" debug="${debug}" srcdir="${dir.jspc.gensrc}" destdir="${dir.webinf}/classes" classpathref="jspc.classpath"/> <!-- merge the jspc generated web.xml fragment with the real web.xml--> <loadfile property="jspc.webxml.fragment.contents" srcFile="${jspc.webxml.fragment}"/> <copy file="${dir.webinf}/web.xml" tofile="${jspc.webxml.merged}"/> <replace file="${jspc.webxml.merged}"> <replacefilter token="<!-- @JSPC-INSERT-HERE@ -->" value="${jspc.webxml.fragment.contents}"/> </replace> <!-- Now war everything up --> <war destfile="${dist}/lib/${jar.name.epcportal-presentation}" webxml="${jspc.webxml.merged}"> <fileset dir="${dir.docroot}"/> <classes dir="${classes}"/> <classes dir="${dir.property.file}"> <include name="**/*.properties"/> </classes> </war> </target>
<property name="dir.jspc.temp" value="${dist}/tmp/jspc"/> <property name="dir.jspc.gensrc" value="${dir.jspc.temp}/gensrc"/>
<path id="cp.jspc"> <pathelement location="${jboss.home}/server/default/deploy/jbossweb-jetty.sar/jasper-compiler.jar"/> <pathelement location="${jboss.home}/server/default/deploy/jbossweb-jetty.sar/jasper-runtime.jar"/> <pathelement location="${ant_home}/lib/ant.jar"/> </path>
<!-- @JSPC-INSERT-HERE@ -->
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN' 'http://java.sun.com/dtd/web-app_2_3.dtd'> <web-app> <!-- Struts Action Servlet Configuration --> <servlet> <servlet-name>action</servlet-name> <servlet-class>org.apache.struts.action.ActionServlet</servlet-class> <init-param> <param-name>application</param-name> <param-value>ApplicationResources</param-value> </init-param> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>detail</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>validate</param-name> <param-value>true</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <!-- JSP-PRECOMPILER INSERTION POINT, DO NOT REMOVE, MODIFY OR MOVE THE FOLLOWING LINE--> <!-- @JSPC-INSERT-HERE@ --> <!-- Action Servlet Mapping --> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <!-- The Welcome File List --> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <error-page> <error-code>404</error-code> <location>/error404.jsp</location> </error-page> <error-page> <error-code>400</error-code> <location>/error400.jsp</location> </error-page> <error-page> <error-code>401</error-code> <location>/error401.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/error500.jsp</location> </error-page> <!-- Struts Tag Library Descriptors --> <taglib> <taglib-uri>/tags/struts-bean</taglib-uri> <taglib-location>/WEB-INF/tld/struts-bean.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/struts-html</taglib-uri> <taglib-location>/WEB-INF/tld/struts-html.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/struts-logic</taglib-uri> <taglib-location>/WEB-INF/tld/struts-logic.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/struts-nested</taglib-uri> <taglib-location>/WEB-INF/tld/struts-nested.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/struts-tiles</taglib-uri> <taglib-location>/WEB-INF/tld/struts-tiles.tld</taglib-location> </taglib> <!-- JSTL --> <taglib> <taglib-uri>/tags/jstl-c</taglib-uri> <taglib-location>/WEB-INF/tld/c.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/jstl-c-rt</taglib-uri> <taglib-location>/WEB-INF/tld/c-rt.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/jstl-fmt</taglib-uri> <taglib-location>/WEB-INF/tld/fmt.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/jstl-fmt-rt</taglib-uri> <taglib-location>/WEB-INF/tld/fmt-rt.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/jstl-x</taglib-uri> <taglib-location>/WEB-INF/tld/x.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/x-rt</taglib-uri> <taglib-location>/WEB-INF/tld/x-rt.tld</taglib-location> </taglib> <!-- Project Specific Tag Libs --> <taglib> <taglib-uri>/tags/epc</taglib-uri> <taglib-location>/WEB-INF/tld/epc.tld</taglib-location> </taglib> </web-app>
- The ant jspc task and jasper are VERY sensitive to the directory structure of your webapp. To get jasper to work, I had to make our pre-war directory structure pretty much exactly like the war archive structure. In other words, I had to make sure that the directory at task execution time was exactly like it would be in when looking at it in the war - all the classes that were destined to be in WEB-INF/classes were already there, all the libs which were destined to be in WEB-INF/lib were already there, all the TLD's were in their final destination (somewhere under WEB-INF), the web.xml file was already in WEB-INF, etc. This might seem obvious, but the ant <war> task will let you leave libs and classes in various directories and then bind them together into the appropriate archive with nested <lib> and <classes> tags
- Make sure you have at least Ant 1.5.3 (latest version of the ant jspc task)
Wednesday, June 25, 2003
Automated nightly defrags on Windows XP...
I’ve noticed that when I’m doing development, the D drive gets fragmented very quickly (even in one days time). After a full day's coding, I usually manage to create 1000 or so fragmented files (even when the machine has been completely defragged the day before). This is after doing full rebuilds, re-installations of the appserver (we have an ant target to completely wipe out our Jboss directory and re-install it), pulls from CVS, etc..
Anyway – you can setup Windows built in defrag tool to run on a recurring basis. Here’s how :
Create a batch file (e.g. c:\bin\DefragLocalDrives.cmd) with the contents similar to the following (customize to your local drive structure):
defrag /v /f c: > d:\temp\Defrag_C.txt defrag /v /f d: > d:\temp\Defrag_D.txt
I set mine up to run every morning at 4:30 AM. At first I thought this would be overkill, but I’ve noticed that when doing development I always have some fragmentation, even after only a day’s use.
That’s it…
UPDATE - As Lance Lavandowska kindly pointed out - this only works on XP (defrag.exe is not present on Win2k installations)
Monday, June 23, 2003
CruiseControl version 2.2.1 is out...
http://sourceforge.net/project/shownotes.php?release_id=167306
We're using 2.0.2 on my current project and we love it. It takes a bit of maintenance and troubleshooting here and there (especially as the size of the project and number of tools grows), but it is definitely worth the investment to set your projects up in this.
Mozilla: Helpful Quick Reference Sidebars for Developers...
- HTML 4.01
- CSS 2
- Javascript (Reference and Guide)
- XSLT
Saturday, June 14, 2003
Experiences migrating from JBoss 3.0.4 -> JBoss 3.2.1...
Here are the things that caused problems :
1. Some of the JBoss client jars were reorganized / renamed (e.g. jaas.jar -> jboss-jaas.jar, jmx-rmi-adaptor.sar -> jmx-adaptor-plugin.jar). We have a Swing client (launched through webstart) and a web based client. For the webstat app, we have to sign all the jars (and list all the jars in the webstart JNLP file) so anytime these change, it causes a little bit of pain.
2. There are new jars required for the client (e.g. jboss-transaction-client.jar).
3. Had all manner of problems getting our oracle datasource to work. In 3.0.4 we were using an oracle-service.xml file to do this, I got multiple wierd errors trying to use this same deployment file in 3.2.1. I finally ended up having to go with an oracle-ds.xml file (which, I must admit is much simpler).
4. From what I could see, anything which was a compliance warning in JBoss 3.0.4 is pretty much guaranteed to be an error in 3.2.1. Granted - we should've fixed the warnings a long time back... These are silly things like a method on an EJB interface forgetting the RemoteException in its throws clause, etc.
5. It looks like they implemented cusom tag pooling starting with JBoss/Jetty 3.2.1... It was always my understanding that the servlet container would call release() on each TagHandler instance for custom tags before it re-used them, but I guess that was a slight misunderstanding of the spec. The actual behavior exhibited here is that the container will eventually call release() on the custom tag, but not between usages. I had to rearrange some of the "reset to default values" logic in a few custom tags to get around this (not too hard to fix once I figured out what was going on).
6. The move broke our WebStart client for IE users... Our webstart JNLP file is generated from a JSP file (pretty common). The mime type is set very early on for this file to be of type "application/x-java-jnlp-file", but for some reason, when we switched to JBoss 3.2.1, anytime an IE user clicked on our webstart link, it would popup the download dialog and ask the user where they wanted to save the local file. After a bit of consternation, I was able to get around the problem by defining a servlet mapping which makes IE thinks its really hitting a JNLP file for the webstart link (when in reality its still hitting the JSP).
<!-- HACK: This entry is only present to make IE treat the resulting HTTP response as a JNLP file instead of a JSP file. --> <servlet> <servlet-name>FakeJNLP-IE-Workaround</servlet-name> <description>our dynamically generated JNLP file (generated by this JSP)</description> <jsp-file>/FsxWebStart.jsp</jsp-file> </servlet> <servlet-mapping> <servlet-name>FakeJNLP-IE-Workaround</servlet-name> <url-pattern>/FsxWebStart.jnlp</url-pattern> </servlet-mapping>
Sunday, June 01, 2003
Similarities between the Matrix Reloaded and the Wheel of Time (minor spoilers)
Finally got a chance to see Matrix Reloaded about a week ago.
Is it just me or are there a lot of overlapping themes in Matrix Reloaded and Robert Jordan's Wheel of Time Series ...? For example :
First similarity - the whole concept of the recurring, cyclic struggle between the savior and the bad guys (according to the Architect, Neo is the 6th Anomaly - the 6th "One"). This concept of a repeating cycle is a very overt theme in the Wheel of Time series. The first chapter in each of the 10 WOT books starts off with the same passage (something like this) :
"The Wheel of time turns, and Ages come and pass, leaving memories that become legend. Legend fades to myth, and even myth is long forgotten when the Age that gave it birth comes again." In the Matrix, Neo is "The One". In the WOT, Rand is "The Dragon Reborn". Both were foretold through prophecy to essentially save the world. The concept of a Messiah character is very common theme in literature, but the part which is a little too similar to me, is the concept of the cycle repeating itself over and over. Neo is not the first "One". Rand is not the first "Dragon". They are both destined to fullfil their role in the enternal, recurring struggle between good and evil, and unless something breaks the cycle, the same struggle will be repeated by a future Messiah character some time later.
Second similarity - Agent Smith is Padain Fain. Smith started out as an agent, but something happened to him at the end of M1 that turned him into "something much more than an agent". He is a renegade from the other baddies in the Matrix world, and he is obsessed with Neo. Padain Fain started out as a Darkfriend. He was given special powers by the Dark One to become his "hound" (his sole purpose was hunt down the reborn Dragon). Then Fain became something much more through his Shadar Logoth ordeal (he's now some wierd mixture of Padain Fain, Mordeth and something else). Fain is now a renegade from the Dark One (and has been ordered killed by the Forsaken and/or the DO). Fain is definitely obsessed with Rand. Fain is nutso about his Dagger - I found it funny that the human character Smith possessed was also a little nutso about his knife (cutting his own hand, etc).
Other similarities - The Matrix and the Pattern...?
All in all, I enjoyed the movie... Can't wait for Revolutions...
Saturday, May 31, 2003
Good tool for Debugging IE Dom...
http://www.cheztabor.com/IEDocMon
It basically does the same thing for IE as the Dom Inspector does for Mozilla. Very useful for debugging, or just looking at how someone's web-page is structured.
Monday, May 19, 2003
Nice Little Article on Black Box Testing for WebApps with HttpUnit
Thursday, March 06, 2003
Maslow's Hierarchy of Needs: Food, Shelter, RAM...
Why Dell decided to cap the C810's at 512MB of RAM I will never understand. I would gladly shell out the required funds to buy a gig of RAM if the damn thing would take it.
The things I need running to do development on my current project.
- IDEA
- JBOSS/Jetty
- Oracle 9i
- Javac (when building/executing tests)
RAM = GOODOh well, at least my lack of RAM predicament gives me plenty of time to write blogs in notepad while I'm waiting around for a test to complete...
Speaking of - I really like the XP Remote Desktop Connection facility (its built on top of Terminal Server). Its much more like setting your display in X-Windows than Microsoft's previous support (e.g. NetMeeting). One of the things I really love about my laptop is the crisp 1600x1200 display. With Remote Desktop Connection I can login to a server with a crappy video card and still run at 1600x1200 (way cool). I know you could do this a decade or more ago on Unix, but hey - at least MS is improving :)
Wednesday, March 05, 2003
Keep IDEA from Hanging for significant periods of time while doing GC...
I posted this to their bug tracking forum and got some helpful responses. Looks like you can add the following option to the IDEA/bin/idea.lax file to help with this problem (turns on concurrent GC) :
lax.nl.java.option.additional=-XX:+UseConcMarkSweepGCThe full thread is here if anyone's interested :
http://www.intellij.net/tracker/idea/viewSCR?publicId=9910
Monday, March 03, 2003
Wish I had a JavaScript IDE...
Speaking of handy tools for web development, checkout Mozilla's built-in DOM Inspector. It basically has three panes. One shows a real, rendered web page, one shows the DOM tree for that web page, and another shows all DOM attributes of the currently selected node in the DOM Tree.
As you select different nodes in the DOM tree, the corresponding visual portion of the web page flashes. This is really great for analyzing some of the more sophisticated web sites out there.
Saturday, February 15, 2003
Nasty Webstart Classloader Bug Revisited...
public class UncaughtAwtExceptionHandler { public static void installAsUncaughtAwtExceptionHandler() { System.setProperty("sun.awt.exception.handler", UncaughtAwtExceptionHandler.class.getName() ); } public UncaughtAwtExceptionHandler() { } public void handle (Throwable ex) { // log the error... } }Now anytime an uncaught exception bubbles all the way to the top of the AWT-EventQueue thread, the handle method on UncaughtAwtExceptionHandler is called (and the AWT-EventQueue thread does not exit). The only constraints on one of these classes is that they must have a public, zero argument constructor and a method which matches the handle method signature (void return type, Throwable as the single parameter). I found this property by looking at the source for the AWT class EventDispatchThread (good thing they ship JDK's with the source). There is a comment on a private method which cautions that this property will one day go away when better API support for uncaught exceptions is provided (I believe this is scheduled for JDK 1.5). One other solution I explored while trying to solve this was defining a custom ThreadGroup in the main of the program, and creating a new main thread with the correct ClassLoader. Then I let the original webstart thread "end", while I started up our application in the newly created thread. You can override ThreadGroup's uncaughtException method to get a notification anytime a thread in that ThreadGroup dies (I was going to try to use this hook to send a runnable to the awt event queue via the SwingUtilities.invokeLater method that would reset the classloader in the new thread). Nonetheless, I could never quite get it to work the way I wanted (couldn't get the AWT-EventQueue to belong to my ThreadGroup in a Webstart application). I looked a thte source and it looks like the awt's dispatch thread uses the ThreadGroup and ClassLoader of the first thread that causes it to do anything (and I think WebStart was doing some awt stuff before our program even started). Anyway, it was around that time that I stumbled upon the property above, and I thought that would be a more foolproof solution (keep the event queue thread from dying in the first place). I really hope they fix this bug in the next version of WebStart (I'm suprised they haven't done it already).
Thursday, February 13, 2003
Travel Lightly...
Here’s an excerpt from Scott Ambler’s Agile site (http://www.agilemodeling.com/principles.htm) that I thought reiterated the same point :
"Travel Light. Every artifact that you create, and then decide to keep, will need to be maintained over time. If you decide to keep seven models, then whenever a change occurs (a new/updated requirement, a new approach is taken by your team, a new technology is adopted, ...) you will need to consider the impact of that change on all seven models and then act accordingly. If you decide to keep only three models then you clearly have less work to perform to support the same change, making you more agile because you are traveling lighter. Similarly, the more complex/detailed your models are, the more likely it is that any given change will be harder to accomplish (the individual model is "heavier" and is therefore more of a burden to maintain). Every time you decide to keep a model you trade-off agility for the convenience of having that information available to your team in an abstract manner (hence potentially enhancing communication within your team as well as with project stakeholders). Never underestimate the seriousness of this trade-off. Someone trekking across the desert will benefit from a map, a hat, good boots, and a canteen of water they likely won't make it if they burden themselves with hundreds of gallons of water, a pack full of every piece of survival gear imaginable, and a collection of books about the desert. Similarly, a development team that decides to develop and maintain a detailed requirements document, a detailed collection of analysis models, a detailed collection of architectural models, and a detailed collection of design models will quickly discover they are spending the majority of their time updating documents instead of writing source code."