Rants about Java and other internet technologies by Sam Pullara

JPA 2.0 with Criteria

(see: JSR 317 Persistently Improving)

I love the idea of adding a criteria API to JPA, the only thing I hope that they do differently than Hibernate is to implement that API in addition to string queries.  In Gauntlet we had issues where we wanted to use EJB-QL for selecting the right data and then a criteria-like API for applying security and filtering constraints on the query.  We ended up writing a criteria-like API that augmented the WHERE clause of the query to get the behavior that we needed (like described here).  For example, you could do this:

Query q = em.createQuery("SELECT p FROM Project p");
q.addExpression(Expression.notEqual("id", 2));

Or something like that. This would give you the best of both worlds, where you have the expressiveness of the textual query and the ability to further hone that query programmatically.

Macworld 2008 followup

Let’s see:

iPhone: failed to mention 1.1.4 update but the SDK is coming in Feb. The rest nope.  C

AppleTV/iTunes: Movie Rentals yes, missed buy on-iPhone support. AppleTV 2.0 — no computer required. Flickr + DVD + HD + Dolby 5.1, software upgrade! price drop! :) A

MacBook Air: “The World’s Thinnest Notebook” 0.16″ to 0.76″, 13.3″ screen, SSD option, 1.6/1.8 Core 2 Duo,  5 hours battery life, B

Blu-ray: Nothing. F

Monitors: Nothing. F

Other MacBooks: Nothing. F

Obviously the crazy prediction also didn’t make it, not even a wireless option for the Macbook Air…

Macworld 2008 predictions

UPDATE 1/13/08: This looks like confirmation of a new ultralight portable with some sort of wireless connectivity.

Might as well put up my predictions for what will be announced at Macworld this year. I think it will be a good one.

  • iMac, Mac Mini, Macbook and Macbook Pro lines upgraded to Penryn processors
    • Same prices, better specs
  • Ultra portable MacBook Pro ($2-3K)
    • 64G SSD drive standard (32G and 128G available), no DVD drive
    • 12″ OLED screen
    • 8-12 hour battery life
  • iPhone
    • SDK: Still WebKit-based but with native Javascript APIs for the phone
    • Better connectivity
    • Video recording
  • Monitors
    • Same panel as the new 30″ dell
    • Built-in iSights
    • Same prices
  • Blu-ray
    • Added as an option for MacPro and MacbookPro
    • Support for playing Blu-ray movies added to 10.5.2
  • AppleTV / iTunes
    • Movie rentals
    • Software upgrade for current devices
    • Possibly a new version with a blu-ray player

All these I consider relatively expected and if they don’t show up, some people will be disappointed. Now for the truly outrageous prediction:

APPLE WILL WIMAX ENABLE THEIR LAPTOPS AND IPHONE BY PLACING NODES IN THEIR APPLE STORES AND STARBUCKS.

That would be the most awesome thing ever and hopefully that is what is implied with “Something is in the air…”. The other possibility is just 3G enabled systems or both for those times when you are out of range :)

Using Groovy to make Maven2 more modular and readable

I started a very very small project this week to increase the usability of Maven 2. I find that although I love Maven as a back-end build processor, I kinda hate the XML configuration file and all the pain that goes with it. So rather than just simply complain, I will also do some token work to fix it. Inspired by Gant, this project attempts to use Groovy to make the creation of POM files easier, more readable, and modular. It will also allow best Maven POM practices to be put into libraries and reused rather than cut and pasted into a POM or painstakingly edited in a GUI. Further, for those who are more adventurous, you can add dynamism to your POM files.With graven (gvn), you can make use of the included standard library of Mavenisms and have this appear within your pom.groovy file:

 1     build {
 2         plugins {
 3             groovy()
 4         }
 5     }

For example, rather than add this to your POM file to make your Groovy code compile:

 1   <build>
 2     <plugins>
 3       <plugin>
 4         <artifactId>maven-antrun-plugin</artifactId>
 5         <executions>
 6           <execution>
 7             <id>compile</id>
 8             <phase>compile</phase>
 9             <configuration>
10               <tasks>
11                 <taskdef name='groovyc' classname='org.codehaus.groovy.ant.Groovyc'>
12                   <classpath refid='maven.compile.classpath' />
13                 </taskdef>
14                 <mkdir dir='${project.build.outputDirectory}' />
15                 <groovyc destdir='${project.build.outputDirectory}' srcdir='${basedir}/src/main/groovy' listfiles='true'>
16                   <classpath refid='maven.compile.classpath' />
17                 </groovyc>
18               </tasks>
19             </configuration>
20             <goals>
21               <goal>run</goal>
22             </goals>
23           </execution>
24           <execution>
25             <id>test-compile</id>
26             <phase>test-compile</phase>
27             <configuration>
28               <tasks>
29                 <taskdef name='groovyc' classname='org.codehaus.groovy.ant.Groovyc'>
30                   <classpath refid='maven.compile.classpath' />
31                 </taskdef>
32                 <mkdir dir='${project.build.testOutputDirectory}' />
33                 <groovyc destdir='${project.build.testOutputDirectory}' srcdir='${basedir}/src/test/groovy' listfiles='true'>
34                   <classpath refid='maven.compile.classpath' />
35                 </groovyc>
36               </tasks>
37             </configuration>
38             <goals>
39               <goal>run</goal>
40             </goals>
41           </execution>
42         </executions>
43       </plugin>
44     </plugins>
45   </build>

Voilà. You can check out the complete project here. I’d love help creating the most complete standard library if anyone is interested.

My Current Config

Since I get asked a lot for advice about what kinds of electronics to buy, I am starting a new page on my site that tracks “my current config“. I’m limiting it to a small set of categories that I think include the most important purchases that people make. Am I leaving anything out? Should I also have software on there?

Generate JPA (or GORM) classes from your database for Java and Grails

Whether you start with the database or start with code, no one wants to do the other one. Certainly by the DRY principle it is a waste of time and potentially a place where you could introduce bugs into your code. Today Dave and I are releasing a command-line utility that will handle the case where you start with the database and want to use JPA to access it. There are other utilities that do this that are generally built into IDEs, however this one fills the niche for those that want to do it in a more automated fashion and don’t want to edit the actual generated code. In fact, we used a previous version of this tool at Gauntlet throughout the development process to keep our database and JPA classes in sync with one another.

Introducing… dbmapper:

Usage: com.moonspider.dbmap.GenerateConfig
  -type (-t) [String] The type to generate, either 'jpa' or 'gorm' (experimental) (jpa)
  -destinationDirectory (-d) [String] Destination directory
  -url [String] The url of the database
  -pkg (-package) [String] The target package ()
  -user (-u) [String] Database user (sa)
  -password (-p) [String] Database password ()
  -globalExtends (-extends) [String] Class for all Java classes to extend
  -globalImplements (-implements) [String] Class for all Java classes to implement
  -driver [String] Database drive class
  -extension (-ext) [String] File extension for the generated code (java)
  -hibernate [String] Generate hibernate.cfg.xml to this directory
  -jaxb [flag] Enable xml binding generation

By default, the tool has a number of rules built into it that I will call ‘best practices’ at least as far as we are concerned:

  1. Tables should have a primary key column named id and it should auto increment.
  2. Foreign keys should be named ${foreignTableName}_id and be specified in the database.
  3. Many-to-many join tables should be named ${tableName1}_${tableName2}.

If for some reason you want to break one of these rules you will need to dig into the configuration of dbmapper. On the JPA side there are a number of conventions that it uses:

  1. Class and property names are converted from _ separated to CamelCase.
  2. Many-to-one and one-to-one relationships are marked as eager.
  3. One-to-many and many-to-many relationships are marked as lazy.
  4. Relationship collections are suffixed with List rather than making them plural.

Again, these are adjustable through a configuration file that I suggest that you never use unless absolutely necessary. The most typical use case for the configuration file is when a database identifier conflicts with an identifier used in Java or Grails. In this case you can either configure dbmapper or change your database. DBMapper is designed to work well with the dbmigrate utility and in fact I recommend you use them together for the most leverage. It is great to be able to add a new migration, execute the migration, generate new classes and see exactly the effect that your database change has on the domain model.

The default functionality is also available directly from Grails. On the command-line simply type:

grails install-plugin dbmapper

This will contact the plugin repository and install the latest dbmapper plugin directly into your Grails application. Assuming that you have configured your database in the normal fashion for Grails you can then generate domain classes directly from that connection with a single command:

grails generate-domain-classes

Assuming that is successful you will find all of your domain classes in the grails-app/domain directory and also a hibernate configuration file in your grails-app/conf/hibernate directory. You should then be able to use tasks likes generate-all to create views and controllers for each of your domain classes.

There is also experimental support for creating GORM classes instead of JPA classes, however this really is experimental at this time and I suggest that you only try it if you are interested in fixing it. GORM doesn’t seem to have the flexibility dbmapper needs quite yet.

Another feature of dbmapper is the ability to create JAXB annotations on the JPA classes so the objects can be read from and written to XML in addition to the database. The dbmapper framework itself is designed to be reasonably extensible. By adding another template you can extend it to generate mappings to other persistence frameworks.

Parallels vs VMWare vs Bootcamp vs Codeweavers Crossover Office revisited

I have reviewed these products in the past but I think they have rev’d enough times to make it worth my while to revisit them and see how far they have come. As a reminder, lets again review a couple of use cases that you might have:

  1. Native Microsoft Office (any version) support
  2. Latest Microsoft Office
  3. Microsoft Vista
  4. Games
  5. IE7

Again with the ideal requirements:

  1. Runs applications at full speed
  2. Executes them in such a way as they appear to be native applications
  3. Does not require a Window license

The simplest answer is to use Crossover Office to run applications that work with it, as when it works it satisfies the ideal requirements and then use Bootcamp when you absolutely have to have a true Windows machine. Crossover Office is now robust enough to run Outlook 2003 pretty well along with some older games like Counter Strike: Source though it doesn’t have support for the very latest software. There are cases that are in-between, for example you might not need full speed but you do need full compatibility, then either Parallels or VMWare Fusion ought to work for you, like when you want to run IE7 to view a website. If you are doing anything that requires high non-graphics speed and also high-compatibility like developing software, either VMWare or Bootcamp would be your best bet. VMWare allows you to use more than 1 processor and it out benchmarks Parallels. On the other hand, Parallels is a nicer application and its Coherence-mode (integrates Windows applications into the Mac desktop experience) is better than VMWare’s Unity mode. Neither VMWare nor Parallels run highly graphical twitch games to my satisfaction. Here is a little table to help you make your decision:

  • Crossover Office 6.2
    • When it works its the best option
    • Fast, well integrated, runs some games
    • Only option that doesn’t require a Windows license
    • According to CodeWeavers, will work even better under Leopard
  • Bootcamp
    • It is just Windows
    • Mac’s are really good Windows machines
  • Parallels Desktop 3.o (build 5160)
    • Easier to use than VMWare Fusion
    • Coherence is very mature
    • Does not really run games well
  • VMWare Fusion 1.0 (build 51348)
    • Faster than Parallels
    • Unity is OK
    • Lot’s of compatible VMWare appliances
    • Not much luck running games on it

Have any questions about the options? Since I have a license to all of them and use them all for various purposes I would be happy to answer any specific questions about the products.

Track Subversion (SVN) changes with an RSS feed

I was a bit annoyed the other day that some of the Subversion repositories out there don’t have a way to send a notification to interested parties when a new change is made.  There are a few other services on the web that claim to do this but when I went looking I didn’t have much luck using any of them.  Since I am not one to shrink from a challenge that can’t be solved by a little bit of coding I threw a new Subversion feed service together in a couple of hours.  About a quarter of that was spent trying to get the CSS on the homepage right.

If it gets any use at all (besides me) I might add some additional features to track which projects are being watched the most and other interesting features of the repositories.  If you have any great ideas you can hand them over to me in the comments :)

Agile database schema migration tool for Java

Update: Grails Migration Plugin Forum

About a month into building Gauntlet we found ourselves in a situation where it was impossible for us to keep our development databases up to date with the latest changes to the schema. We were sending around emails telling each other what changes need to be made alongside our check-ins. In order to get around this problem I spent a few hours building a rudimentary database schema migration tool. When you made a change to the database schema you would have to build a DDL file that would make the change and then update the version numbers for the Gauntlet software and within the database. A few short months later and I discovered that we had built something very much like ‘rake migrate’ from Ruby on Rails — in fact it was almost exactly the same except that ours worked at runtime rather than only from the command-line. Fast forward a couple years later and I no longer own the Gauntlet source code, so yesterday I set out to rebuild the schema migration tool from scratch .

The basic concept is very simple. The first time your program connects to its database it calls the schema migration code to make sure that the code and the database are at the same version so that you are always using data objects and queries that match the schema that is present in the database. When you make the call you need to pass the tool all the details about the database that you are connecting to, the place to find and classes or scripts to do the migration, and the current version of the client. Then, if the database version is less than the client version, the migration tool systematically searches for first database type specific DDL classes/scripts then generic versions, executing them in turn to migrate the schema forward until the database version and the client version match. If it encounters a case where the client version is less than the database version it has no recourse but to fail. As a bonus, it also offers a version 0 transition where it will bootstrap you from a completely empty database to your initial schema.

For instance, lets say in version 1 of your database you have the following table:

mysql> describe event;
+---------------+---------------+------+-----+-------------------+----------------+
| Field         | Type          | Null | Key | Default           | Extra          |
+---------------+---------------+------+-----+-------------------+----------------+
| id            | bigint(20)    | NO   | PRI | NULL              | auto_increment |
| time          | timestamp     | NO   |     | CURRENT_TIMESTAMP |                |
| z             | bigint(20)    | NO   | MUL |                   |                |
| ip_address    | int(11)       | YES  |     | NULL              |                |
| user_agent_id | int(11)       | YES  |     | NULL              |                |
| referrer      | varchar(256)  | YES  |     | NULL              |                |
+---------------+---------------+------+-----+-------------------+----------------+

Then you decide that you want to change the name of the referrer field to url. In order to do that you would create a new migration script that updates the field name and the database version:

ALTER TABLE event CHANGE referrer (url varchar(256));
UPDATE db_version SET version = 2;

You would name that script migrate1.sql and put it in the mysql specific database migration scripts. You would also then update the client version to 2 as well. Once that was done anyone who uses the new client code against their database will automatically get the schema changes required for the client to work with the database. This drastically cuts down on the amount of communication that needs to occur in typical database development situations. You can find the project that implements this db schema migration here. It has one dependency that is included with the project, my cli-parser .

Using the Yahoo! Mail SOAP API 1.1 from Java’s JAX-WS 2.1

On YDN they have samples and documentation on how to use the Yahoo! Mail SOAP API from Axis2. I’m not a big fan of that method so I went ahead and used JAX-WS to do my dirty work. As an example, I will build an RSS feed of the users unread messages.
First get JAX-WS 2.1.x or possibly just JDK 1.6 (though I did all my testing with the former and JDK 1.5). Since its easiest to work with typed APIs we are first going to generate the classes needed to talk to the the Yahoo! Mail web service. From their site, we find that the latest WSDL URL. To generate the API from the WSDL we use the ‘wsimport’ command from JAX-WS like this:

wsimport.sh -extension -s src -p com.yahoo.mail http://mail.yahooapis.com/ws/mail/v1.1/wsdl

The key command line option there is the ‘-extension’ option as the Yahoo! Mail WSDL has a few things that by default would get named the same thing by the schema compiler. By using Sun’s extensions we can automatically rename them rather than making our own binding. This will generate 120+ classes representing each part of the complex API along with some special classes like ObjectFactory. This gives us the foundation for accessing Y! Mail but there are still a few quirks that we need to understand. Normally when you use JAX-WS you would simply access the web service using the main Ymws class that was generated like this:

             // Instantiate the SOAP proxy
             Ymws service = new Ymws();
             YmwsPortType stub = service.getYmws();

Then you would be able to make calls on that stub directly like this:

            UserData userData = stub.getUserData();

You’d find though if you tried to do this that you would not be authenticated with the service nor would there be anyway to select what user for which you are making this call. Yahoo! Mail’s web services have their own authentication scheme that is built on Yahoo’s BBAuth — a 3rd party authentication system. In order to make use of BBAuth you will need to register your application with Yahoo. Make sure that you use a publicly available URL for your application and also select the third option at the bottom: “Yahoo! Mail (via BBAuth) with Read/Write access” so that you will be able to use this application ID to access the Y! Mail API. Once you have registered you will be asked to authenticate your URL by placing a special file at the root of the domain of your URL. This means you needs write access to the root of the web server so don’t attempt this on a domain that you don’t control in that way. After this is complete you continue to the success page where it provides you with your application ID (appid) and your shared secret (secret). These will be required for you to access the Y! Mail APIs on behalf of Y! users.

The core of the way BBAuth works is for you to redirect to their server when you want to authenticate a user and then they send back the token that is required to access Y! as that user to the registered application URL. Here is the code that we can use to generate the URL required to get authenticated:

             long ts = date.getTime() / 1000;
             String uri;
             uri = "/WSLogin/V1/wslogin?send_userhash=1&appid=" + URLEncoder.encode(appid, "UTF-8") + "&ts=" + ts;
             MessageDigest md;
             md = MessageDigest.getInstance("md5");
             String sig = new BigInteger(1, md.digest((uri + secret).getBytes())).toString(16);
             return LOGIN_URL + uri + "&sig=" + sig;

Essentially this code creates a URI with our appid and signs it with the secret which is then used to create a URL that includes the signature. This ensures that only someone with the secret can work on behalf of the application that we registered. Once the user is authenticated you will receive a callback at the registered URL that includes the information passed here plus a token that can be used to retrieve a WSSID and cookie that can then be used to construct authenticated web service requests. There is an additional login URL parameter that you can pass called appdata that will be returned to you when Y! redirects the user back to your application. The token that is returned is generally good for 2 weeks of authenticated access. The send_userhash=1 option tells Yahoo to return to us a unique identifier tied to your application id that will always be the same so you can use it to tie back to a particular user in your application.

Now that we have gotten the token back from Yahoo we can get our WSSID and Cookie. Included with the Yahoo! Mail sample code they have an inner class called BrowserBasedAuthManager. We’ll just use that rather than rewrite it but basically it does something similar to the code above and retrieves the two values from an XML document returned from a URL:

             // Instantiate the auth manager and set it up with the date, application ID,
             // shared secret and the user token.
             BrowserBasedAuthManager authManager = new BrowserBasedAuthManager(date, appid, secret, token);

These two values, wssid and cookie, are then needed to construct our web service requests. JAX-WS doesn’t expose this functionality directly in the API but instead allows you to set various properties on the request context:

         Map<String, Object> requestContext = ((BindingProvider) stub).getRequestContext();
         requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
                 "http://mail.yahooapis.com/ws/mail/v1.1/soap?appid=" +
                         URLEncoder.encode(appid, "UTF-8") + "&wssid=" +
                         URLEncoder.encode(authManager.getWssid(), "UTF-8"));
         Map<String, List<String>> cookies = new HashMap<String, List<String>>();
         cookies.put("Cookie", Arrays.asList(authManager.getCookie()));
         requestContext.put(MessageContext.HTTP_REQUEST_HEADERS, cookies);

The first property allows us to change the actual endpoint of the web service call to include the WSSID that we got from our authentication request. The second call allows us to set cookies on the HTTP request that is used to make the specific call. Together these will give us the access we need in order to use the stub securely. Actually making use of the API is quite easy now that we are authenticated. For instance, we can trivially discover whether or not the user is a Y! Mail Plus subscriber and has access to the full API functionality (non-premium users can’t get the contents of messages for instance):

         UserData userData = stub.getUserData();
         boolean isPremium = userData.getUserFeaturePref().isIsPremium() 

Here is the code to pull all the unread messages from a folder:

         // List out up to 100 new messages in the folder
         ListMessages lm = new ListMessages();
         Flag flag = new Flag();
         flag.setIsRead(FALSE);
         lm.setFilterBy(of.createListMessagesFilterBy(flag));
         lm.setFid(folder.getFid());
         lm.setNumInfo(BigInteger.valueOf(NUM_MESSAGES));
         ListMessagesResponse lmResp = stub.listMessages(lm);
         return lmResp.getMessageInfo();

Notice how we use the ObjectFactory to create the filterBy element. Whenever you see a reference like JAXBElement<Flag> in the API you will likely want to use one of the convenience APIs within ObjectFactory to create the argument.

Now lets get to our RSS feed of unread messages example. To create our RSS feeds we could have just written out the feed directly but instead I’m going to use ROME as we might want to extend the example to a real application later. ROME has one dependency, JDOM-1.0 so we will have to get that as well. We can encapsulate the application into a single servlet that serves both the authentication feed and the mail feed. Here is the core servlet method:

        try {
             String token = httpServletRequest.getParameter("token");
             if (token == null) {
                 // If there is no token we are not authenticated
                 throw new AuthException("No token");
             }
             // Current date, needed for many API calls
             Date date = new Date();
             // Instantiate the SOAP proxy
             Ymws service = new Ymws();
             YmwsPortType stub = service.getYmws();
             // Instantiate the auth manager and set it up with the date, application ID,
             // shared secret and the user token.
             BrowserBasedAuthManager authManager = new BrowserBasedAuthManager(date, appid, secret, token);
             // Set up the web service call
             setupWebServiceCall(authManager, stub);
              // Create the feed
             SyndFeed sf = createFeed(date);
             // Go and get the list of folders and pull out the inbox
             Fid inbox = getInbox(stub);
             if (inbox != null) {
                 List<MessageInfo> messages = listUnreadMessagesInFolder(stub, inbox);
                 List<SyndEntry> entries = new ArrayList<SyndEntry>();
                 for (MessageInfo message : messages) {
                     SyndEntry se = createEntry(message);
                     entries.add(se);
                 }
                 sf.setEntries(entries);
             }
             writeFeed(httpServletResponse, sf);
         } catch (AuthException e) {
             unauthorizedFeedResponse(httpServletResponse);
         } 

This code should be fairly self-explantory and it builds on all the work that we have done so far. The only new things are the actual calls into the Y! Mail API that retrieve the messages from Y! Mail, converts them into an RSS 2.0 feed, and writes that feed to the wire. There are a couple of issues with this code that we don’t address, like generating a permanent URL for the user to use. Right now whenever their authentication is reset (at least every 2 weeks) they will have to get a new feed URL from the application.

Throughout these simple examples there are opportunities for optimization. Many of the pieces of data can be cached for some amount of time and regenerated later like the token, the wssid and the cookie when the user fails to authenticate. The user hash can, of course, be used forever as a unique identifier for the user. Other opportunities for optimization include the ability to multiply dispatch requests to the API using batchExecute. Our example is an unoptimized version so that you can see how everything works before its made more complicated through the optimization process.

Here is a link to the full application, the source code is under WEB-INF/src. You will need to configure the web.xml with your own appid and secret but otherwise it should run in a standard JEE Servlet 2.4 container out of the box.

YUI-Mainstream Theme by Buzzdroid.com

 Premium Wordrpess Theme