jueves, 4 de agosto de 2011

Step by step: Executable WAR files

Have you ever executed Jenkins? One of the most valued features it packs is the embedded Winstone servlet container. It allows your favorite CI server to be launched without being deployed to a traditional server (say Tomcat) first. Unfortunately Winstone is not a viable choice for everybody, particulary if the app makes use of the latest servlet/JSP features. Fortunately there are other choices.

Jetty has always had a good reputation in this field. As of today Glassfish and Tomcat also offer solutions for this need. I'll focus on Jetty, basically because it's easy and it works. There are good articles around the net about the topic but no step by step tutorial so let's see all the tasks it takes one by one.

First of all, an executable WAR file is no different from an executable JAR file. That means that it needs an entry in the MANIFEST file that points to the class that will be launched. In this case, the main class has to start the server and deploy the very same WAR file.

The source of the class:

public final class Launcher {
   public static void main(String[] args) throws Exception {
      int port = Integer.parseInt(System.getProperty("port", "8080"));
      Server server = new Server(port);
      ProtectionDomain domain = Launcher.class.getProtectionDomain();
      URL location = domain.getCodeSource().getLocation();
      WebAppContext webapp = new WebAppContext();
      webapp.setContextPath("/");
      webapp.setWar(location.toExternalForm());
      server.setHandler(webapp);
      server.start();
      server.join();
   }
}

The above class was copypasted from here. All credit is due to the original author. It's a clever tweak over the official documentation to point to the WAR file location.

To compile, Maven needs to download the dependencies. Easy:

<dependency>
   <groupId>org.eclipse.jetty</groupId>
   <artifactId>jetty-server</artifactId>
   <version>7.3.0.v20110203</version>
   <scope>provided</scope>
</dependency>
<dependency>
   <groupId>org.eclipse.jetty</groupId>
   <artifactId>jetty-webapp</artifactId>
   <version>7.3.0.v20110203</version>
   <scope>provided</scope>
</dependency>

Notice the scope is set as provided. This will later be explained. For now the class compiles so the next step is to add the MANIFEST entry. This is usually done using the maven-jar-plugin so a WAR file will use the equivalent maven-war-plugin:

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-war-plugin</artifactId>
   <version>2.1-beta-1</version>
   <configuration>
      <archive>
         <manifest>
            <mainClass>Launcher</mainClass>
         </manifest>
      </archive>
   </configuration>
</plugin>

Right now the WAR file can be executed....but it will fail miserably. There are two problems, first the compiled class is located inside WEB-INF (as all classes in a WAR file) and second Jetty dependencies are not present in the classpath yet.

The next task is to move the Launcher class to the root of the WAR (classloading behaves the same as a JAR file). Maven can't do this easily so Ant to the rescue.

<plugin>
   <artifactId>maven-antrun-plugin</artifactId>
   <executions>
      <execution>
         <id>main-class-placement</id>
         <phase>prepare-package</phase>
         <configuration>
            <tasks>
               <move todir="${project.build.directory}/${project.artifactId}-${project.version}/">
                  <fileset dir="${project.build.directory}/classes/">
                     <include name="Launcher.class" />
                  </fileset>
               </move>
            </tasks>
         </configuration>
         <goals>
            <goal>run</goal>
         </goals>
      </execution>
   </executions>
</plugin>

The second task is to provide Jetty dependencies. Java does not support JARs-inside-JARs (or JARs-inside-WARs for the matter). The only option is to unzip the dependencies and again at the root of the WAR file (WEB-INF cannot be reached). Remember the scope of the Jetty dependencies from above! Another plugin will help with the task:

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-dependency-plugin</artifactId>
   <version>2.3
   <executions>
      <execution>
         <id>jetty-classpath</id>
         <phase>prepare-package</phase>
         <goals>
            <goal>unpack-dependencies</goal>
         </goals>
         <configuration>
            <includeGroupIds>org.eclipse.jetty,javax.servlet</includeGroupIds>
            <excludeArtifactIds>jsp-api,jstl</excludeArtifactIds>
            <outputDirectory>
               ${project.build.directory}/${project.artifactId}-${project.version}
            </outputDirectory>
         </configuration>
      </execution>
   </executions>
</plugin>

Right now the WAR can be executed using java -jar name_of_the_project.war. Unfortunately, the user would notice this on first access, it lacks JSP support throwing a 500 error. To add it another dependency has to be included. This dependency does not need to be unpacked, it's readed from WEB-INF/lib as any other library.

<dependency>
   <groupId>org.mortbay.jetty</groupId>
   <artifactId>jsp-2.1-glassfish</artifactId>
   <version>2.1.v20100127</version>
</dependency>

And that would be it! That would be it if the WAR doesn't need to be deployed to Tomcat any more. Yes, adding that last dependency breaks JSP support in the most used servlet container. Sad. That forces even more work to prepare everything. There's no good solution to this problem, if the JAR is downloaded and copied the WAR will not be deployable otherwise it won't have JSP support. The best workaround is to conditionally add the dependency if the desired outcome is a standalone, distributable, file (so the development process is not affected). In Maven this is achieved using a specific profile. What does it mean in the end? Two things, some refactoring in the POM file (so the specific tasks required by Jetty are relocated inside the profile) and starting the Maven process with the -P flag.

And finally we are there! If you need a complete working example I've comitted the changes to OSSMoney which was my original intent anyway (distributing something that end users could execute in their machines without any knowledge of the Java ecosystem).

viernes, 15 de julio de 2011

OSSMoney Milestone III

Today I'm going on vacation and hence I won't be working on the project for some time. I didn't want to leave without releasing something so I've packaged a WAR file and uploaded it to the repository (http://code.google.com/p/ossmoney/). I couldn't test it, even a little so I hope I didn't break anything important while adding some of the latest features. As always, in memory databases and no installer so it's meant for devs only.

Here's the list of changes since 0.2:
  • The user can now edit several important entities like accounts or transactions
  • Transactions can be deleted aswell
  • Partial investment support (buy, sell, interest, manual price updates) with imports from MS Money
  • The user can request a backup of the data in QIF format
  • Several new administration screens
  • Bug fixes galore
Known issues (I couldn't get them in time):
Wish list:
  • Some more reports (like spendings in a given category during some period)
  • Support other investment operations (though I personally don't use any more so...)
  • A better administration (better CRUD support for base entities like categories)
Anyway, OSSMoney 1.0 right now is nearly finished. I really hope for a September release. Enjoy!

viernes, 17 de junio de 2011

OSSMoney Milestone II achieved

I've been unable to progress as much as I would have liked with the project. Nonetheless, for the last couple of weeks I've been able to devote some time and improve things here and there. I've uploaded a new build to the project page. As always, it's not meant yet for end users but for fellow developers (in memory database and such things), just for evaluation, you know.

The list of changes for this version can be summarized in:
  • Credit card account support
  • QIF file import from MS Money (bank & CC accounts)
  • Dashboard ported to Dojox Charting
  • Bills & remainders
Things left for the (near) future:
  • Reporting
  • Investment accounts
  • Administration tasks (in particular allow edits)
And the always useful batch of screenshots:

The new dashboard
The account details page
Creating a new recurring bill
But try it for yourself and report issues or enhancement requests. Hope you enjoy it!

domingo, 6 de marzo de 2011

OSS money first developer build available

So after a month of development I finally have something to show beyond this screenshots:





The current build only works in Firefox AFAIK (I know it doesn't work in Chrome for sure). That's one of the cons of working with a beta of Dojo. Anyway, download it at http://code.google.com/p/ossmoney/downloads/list and try it. It uses an in-memory database and it hasn't been thoroughly tested (and it isn't very error friendly!) so this is not meant for end users. It's just a build for fellow developers (may be someone likes it and decides to contribute to the project).

To use it just deploy to Tomcat (or whatever), access http://localhost:8080/ossmoney-dev.build.29 (probably) and login with jose/jose or register a new user (the username requires more then three letters!).

After this one, I won't probably release any more binaries (till the final one) unless there's some interest in the project out there. After all, I can build my own version and preparing a release takes time (even one like this).

viernes, 18 de febrero de 2011

Introducing OSS Money

Do you like MS Money? I do. A lot. That's the main reason that saddened me when Microsoft decided to discontinue the product. There are several good free online alternatives but I don't like to trust my financial data to anybody but me and my bank. In the Open Source scene there's GNU Cash but...

During the last year I contributed very very little to the OSS scene (just some code to Gmaps4JSF actually) so I decided that I had an itch and may be I should take the opportunity to do something about it. So, without further delays, I've started a new project at Google Code, it's called OSS Money (tribute to the mentioned MS software), and it'll be an expense tracker and budget planner. Right now I've barely scratched the surface but I have something to share. Here's the desktop screen as of today (in Spanish with two currencies):



For those willing to help with the project, it's a multi-language Spring Roo application with a Dojo 1.6 frontend. Right now, I'm not going to provide binaries (very alpha status, feature wise) but checkout the code and let me know your impressions. Or open some issues if you have any ideas!

miércoles, 2 de febrero de 2011

Test driving Spring Roo..for real

I had the oportunity to evaluate Spring Roo some time ago but I didn't actually use it in a project till recently. Today, after hours and hours of heavy I wanted to share some thoughts about the tool.

First, it has some AWESOME features:

  • There's absolutely no way to create a project from scratch that packs a Spring context, Maven, a security solution, REST/MVC and persistence in less time. Everything is very well configured and just works, in a matter of seconds and four commands. Congrats here to the Roo team.

  • The @Configurable entities (ala Grails) are incredibly useful. Having an EntityManager injected in the model and predefined CRUD methods is invaluable.

I liked
  • The environment. Both, the command line tool and the STS plugin. IDE integration surprised me, it's well rounded.
So-so things I found:
  • As mentioned, Roo is fast when creating a new project. It comes at a price though as your commitment with the Spring stack is absolute. Of course, this may be a non-issue for many people as of today.
  • Roo values Convention over Configuration and in such spirit it makes a lot of assumptions..on your behalf. I've found some of them questionable. For example, in a tool so focused on persistence, why is the authentication provider configured in memory by default? Of course, it works out-of-the-box, but I'm pretty sure that 99.99% of the users will change that. Roo creates a login page for me, great but I was expecting a DB authenticator in there (and User and Role classes!)
  • Controller scaffolding...yeah. It works and it's fine. It's just that a real application may look like the generated pages...or not. If not, and that seems to be my case all the time, it's not worth the effort. For a rush...a good addition!
But there are things that are PLAIN WRONG:
  • Roo seems to take a reckless approach to programming. It's not what I would call an error friendly tool, not even by a far margin. Not that Roo fails by itself (seems quite robust in fact) but the user will undoubtedly do it. That's not actually an issue, everybody makes errors. The problem is how easily you can fix them. Any IDE basically provides an unlimited UNDO/REDO capability. Fixing something is a matter of pressing CRTL+Z in most cases.

    Things are not that easy with Roo, obviously because it lacks the UNDO command, but in more subtle ways aswell. The generated code cannot be touched (it will be overwritten time and again) and pretty much everything is generated (90% of the code is hidden to the user). And even if it could it would be a daunting task unless you're an expert in AspectJ syntax.

    Many many times, it's just better to delete the involved source files and restart the work. Do I have to mention how frustrating this can get? May be it's me, I'm so used to it that I don't really pay the due attention anymore but, lo and behold! check twice before clicking that Execute button with Roo
Will I give Roo the seal of approval then? I'm afraid I won't this time. Right now, it's a fantastic tool to create a project. And good for the advanced architect. But this is not a tool for neophits (a resounding no!) and still needs some work in key areas. But I won't ditch it. It's worked quite well for me! But before diving into Roo just check your knowledge with Spring and AOP in general. Otherwise, Roo will create you more headaches than it will solve.

jueves, 2 de diciembre de 2010

Escaping Spring EL

Months without blogging and finally today I've found a reason to write something! It's the first time Spring has failed me big time!!! And doing a trivial task to boot!!!

Let's recapitulate, I'm trying to inyect a simple String property in a bean. The value I have to inyect is: #{fwk:path('/')}. Simple, huh? Well, not so much it seems.

Can you spot the problem right there? I'll help you a little. Spring 3.0 includes an expression language. Fine...if it weren't for the fact that it uses #{} as the expression delimiter. Of course, that can cause a lot of trouble because:
  • It seems Spring lacks the ability to turn off the EL if you're not using it
  • It seems Spring lacks the ability to configure the pattern
  • It seems Spring lacks the ability to escape single quotes inside the expression
  • The documentation isn't stellar this time
In the end I was able to solve the problem. I'm showing you how, just inject this (it took me several approaches to find it so it's a little useful snippet I guess):

#{ '#{' }fwk:path('/')}

Great, isn't it? Elegant, clear, concise...wow! Now...c'mon!!! Am I missing something here?? Either I've lost my mojo (just this time) or SpringSource has some room for improvement! Please, prove me wrong.