Category Archives: nerd

The modern Java web app

I’m always looking for ways to streamline Java web app development. In case I haven’t spread the word to you, here’s the current set of technologies I’m liking:

  • Tapestry 5 – This is the framework I’m using, but I’m not saying it’s better than anything in particular, but I like some of the stuff they are doing.
  • Hibernate with annotations – I’ve been a big fan of hibernate for a long time, using the annotations seems to simplify the mapping process quite a bit.
  • Spring Hibernate integration – makes transaction/error handling way way easier in Hibernate. I am using HibernateDaoSupport as a base class. Tapestry 5 also has Spring integration, allowing you to inject the DAO’s right into your page classes
  • Maven 2 – So much easier than ant and dependency hell, once you get used to the paradigm shift. It might cause issues with your Eclipse tomcat integration, but I always found that to be flaky anyway. Use Jetty instead.
  • Maven Jetty plugin – Allows you to build/deploy your app with one command (mvn clean jetty:run). Much easier than dealing with some of the flakiness of tomcat deployment, and allows you to just run one of your apps at a time.

I am also looking into Spring Security, and hoping it will simplify authorization, and I’m doing some IDE evaluations to see if it’s time to ditch Eclipse.

IDE of the week: Netbeans 6.1

Happy Monday morning. After battling with Maven and the Tomcat plugin in Eclipse a bit last week, I have decided to try some alternative IDEs. I’ve heard good things about IntelliJ, and I think the Maven integration in Netbeans is supposed to be good. So, I’ve decided to give each of them a week of use and see if they can beat out Eclipse. This week is Netbeans 6.1. So far, I’ve spent a few minutes installing updates and reading up on the Maven support (you have to install a plugin through the plugin manager). Now that the plugin is installed, it automatically recognizes Maven projects when I check them out, so that is cool. Hopefully I can make it through the week without reverting to Eclipse.

Tapestry 5: First Impressions

My new group at ASU is loosely standardizing on Tapestry, so I’ve been spending some time learning it. We are officially using 4.1, I think, since it’s the latest official release, but I decided to go all rogue style and switch to 5.0 after spending some time on 4.1. From the noise on the web, it sounds like Tapestry gets completely rewritten for every new version, so 5.0 is pretty different from 4.1. Anyway, it seems much better, but there are still some weird problems. Here are some of the interesting things I’ve run into:

  • If you need to call some Tapestry page from an outside app with data, you can simulate Tapestry’s “activation/passivation” by building URL strings which will feed your onActivate method. They look like this: http://localhost:8080/app/page/param1/param2, where param1 and param2 will be passed in a List (not an array, as I found out the hard way) to onActivate. I’m not sure if this is the best way to do it.
  • If you loop through a list of items and want to be able to edit those items (like by having a checkbox), you pretty much need to set up a PrimaryKeyEncoder, otherwise it will serialize/deserialize stuff and all your changes will be lost. This was very hard to figure out.

So far I’m only moderately impressed. There seem to be too many assumptions that don’t fit the model of my first app very well, but we’ll see how it goes once I get better at it.

Getting tomcat to stop deleting your context xml files

I’ve been plagued with this annoying problem in tomcat for about a year, and it has been driving me crazy. I’ve looked through the code, joined the mailing list, etc. etc. The problem is when you have context xml files, such as /usr/local/tomcat/conf/Catalina/localhost/app.xml. Generally, you would use such files to set up JNDI data sources for database connections, but I also use them to set up configuration beans in order to keep environment-specific data outside of your application code (which I consider the whole war file to be). Anyway, tomcat seems to randomly delete those files when I change anything in the application files. I tried various configurations using war files, no war files, and war files in funny locations, and it happened to all of them.

I never did find out why it deletes the files, but I did find a solution, thanks to a user on the tomcat mailing list. All you have to do is turn off “autoDeploy” on the “Host”. Basically, you need to edit /usr/local/tomcat/conf/server.xml and change the xml element, so that it says autoDeploy=”false” instead of autoDeploy=”true”. And with that, all my problems are over.

Hibernate error reporting

Sometimes, Hibernate is really bad at error reporting. Today I added a NOT NULL constraint to a column in my database and ran my unit tests. Several failed with errors like this:

testAddInstructor(edu.asu.cem.test.dao.CourseDAOTest) Time elapsed: 0.009 sec <<
org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:92)
at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:87)
at org.hibernate.jdbc.AbstractBatcher.prepareBatchStatement(AbstractBatcher.java:222)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2229)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2665)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:60)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeInserts(ActionQueue.java:158)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:245)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:523)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:519)
at edu.asu.cem.test.dao.CourseDAOTest.setUp(CourseDAOTest.java:103)
at sun.reflect.GeneratedMethodAccessor6.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.junit.internal.runners.MethodRoadie.runBefores(MethodRoadie.java:122)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:86)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88)
at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:138)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:125)
at org.apache.maven.surefire.Surefire.run(Surefire.java:132)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:308)
at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:879)
Caused by: java.sql.BatchUpdateException: failed batch
at org.hsqldb.jdbc.jdbcStatement.executeBatch(Unknown Source)
at org.hsqldb.jdbc.jdbcPreparedStatement.executeBatch(Unknown Source)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
… 44 more

I had made several changes since running the tests, so I had to think about what might be making a database call crash. Luckily, I was able to remember, but I have spent hours debugging these before. I wish the JDBC exception was floated to a higher point in the exception chain so it would be displayed. In this case, all I had to do was set a value for the fields that were no longer nullable.

Sakai and the App Builder plugin


So, I am trying to jump into Sakai development by writing a tool that can keep a log of email conversations between instructors and students. Since I’m new to Sakai, I will probably end up starting over a few times before I figure out the best way to develop. I decided, at the advice of a coworker to start using RSF and the App Builder plugin. So far, it’s pretty intimidating. I started by doing a full CRUD framework, since that is one of the options for the plugin. I think digesting RSF and the way they set up their Hibernate stuff at the same time is a bit much, so I’ve gone backwards to starting with their hello world app, which I’m going to try to convert into a number guessing game to give me a handle on session management, RSF, etc. It seems like there is a pretty serious lack of any tutorials that go beyond modifying the hello world to say something different. The whole video tutorial thing is pretty cool, so maybe I’ll make one if I get far enough along. But for now, I can recommend starting with hello world if you don’t know RSF already. I can also say that RSF looks pretty nice so far. Much simpler than JSF but some of the same good ideas.

Leopard terminal color rotate

I used to use this trick to rotate colors between terminal windows. When I upgraded to Leopard, the windows stopped being transparent, which sucked. I have finally come up with a solution that uses a different technique. You will need to create several terminal profiles for different color schemes. The cool thing about this way of doing it is that you can use different transparency settings for different colors. You should call the new profiles “rotate X” where X is a number. Then you install this script as /Users/alwold/setcolor.sh or some such thing:

#!/bin/sh
if [ -e ~/.lastterm ]; then
LAST_PROFILE=`cat ~/.lastterm`
fi
if [ “$LAST_PROFILE” == “” ]; then
LAST_PROFILE=1
else
LAST_PROFILE=$(($LAST_PROFILE+1))
fi
if [ “$LAST_PROFILE” == “6” ]; then
LAST_PROFILE=1
fi
echo tell application \”Terminal\” to set current settings of first window to settings set \”rotate $LAST_PROFILE\” |osascript
echo $LAST_PROFILE > ~/.lastterm

Finally, you need to call that script from your .profile (or you can just put the whole script in your .profile). Also, the script assumes you have rotate 1 – rotate 5. If your number of profiles is different, change the 6 accordingly.

Drupal 5.7 on Resin 3.1.4

So, in case you didn’t hear, Caucho has a component called Quercus built into their Resin product which is a pure Java PHP interpreter. With this product, it is claimed that one can achieve 4x performance gains with Drupal (phew…that was a lot of links). The concept of being able to call into Java code as well seems appealing to me. Although Drupal is now at version 6.0, I tried it with 5.7, since I know most modules work with 5.x, but I’m not sure about 6. Here’s a quick guide…

  1. Download Caucho Resin 3.1.4 (open source)
  2. Download Drupal 5.7
  3. Unzip Resin
  4. Put a copy of mysql JDBC driver in the lib directory under resin
  5. Put a copy of JavaMail mail.jar in the lib directory also
  6. Create mysql database for drupal and a user to access it
  7. Go into webapps under the resin directory
  8. Unzip drupal here
  9. Rename drupal-5.7 to drupal
  10. Create WEB-INF/resin-web.xml under the drupal directory:



    jdbc:mysql://localhost:3306/databasename
    username
    password








    index.php








  11. Modify drupal/sites/default/settings.php
    • Change database name
    • Change username/password
  12. Start resin (java -jar lib/resin.jar)
  13. Go to http://localhost:8080/drupal/install.php (you need to explicitly go to install.php, since drupal gets confused about the modified settings.php, but no data in the db)
  14. Your drupal should now be functional

Xen, HVM, and running out of memory

I think I’m in an uncommon situation, but I needed to set up lots of HVM (full virtualization) hosts on my Xen install, since the dom0 is a different distribution (debian) than the domU hosts (Fedora). With paravirtualization, the “balloon driver” takes care of memory allocation, I think. But in HVM mode, you actually have to have the amount of memory required by your VM available outside of dom0. If you don’t have enough, you get an error like this:

Error: Error creating domain: (12, ‘Cannot allocate memory’)

It took forever to figure this out, but the key is to limit dom0’s memory, so that you have enough for your VMs. The machine I’m working with has 16 gigs, so I limited dom0 to 1 gig by using this line in the menu.lst for grub:

kernel /xen-3.0.3-1-amd64.gz dom0_mem=1024M

Yours will probably look different, but the key is the dom0_mem parameter. Once you add that, you will have 15 gig left for allocating virtual machines.

Taking photos in Java with the Blackberry

According to this press release, RIM has released the APIs needed to take photos with the Blackberry camera in Java apps.  As far as I have figured out, they have enabled the API to start the camera app, but not an API to listen for new photos.  That isn’t particularly horrible, because you can use the File Connection API to open the Blackberry filesystem and monitor for new photos.  The only tricky part is knowing when the camera app has relinquished control back to your app, so you can start looking for the new photos.