2009-09-25

Using Gradle to deploy to Glassfish

As mentioned before, I've used Gradle for my build in my latest project. I started to get tired of logging on to the admin console to deploy the WAR file so it was time to look at Glassfish & Gradle in combination.

Glassfish 2.1 includes some ANT tasks which is a wrapper to the asadmin command line tools. Using ANT tasks from Gradle is really simple - even those who aren't part of the main ANT distribution.

I started out with checking if the machine has an environment variable pointing to the glassfish install directory:

gfHome = System.getenv('GLASSFISH_HOME')
logger.info("Glassfish home: " + gfHome)
if (gfHome == null || gfHome.length() <= 0)
{
msg = "No GLASSFISH_HOME in environment variable. Please set GLASSFISH_HOME to glassfish installation directory"
logger.error(msg)
throw new RuntimeException(msg)
}
This will throw an error and the build script will fail if the environment variable GLASSFISH_HOME isn't set. If this succeeds I need to define the task by using ANT's taskdef from Gradle.

ant.taskdef(name: 'gfDeploy',
classname: 'org.apache.tools.ant.taskdefs.optional.sun.appserv.DeployTask') {
classpath {
fileset(dir: gfHome + File.separator + 'lib') {
include(name: '*.jar')
}
}
}
I use the lib directory of the Glassfish install directory and add all jar files to the classpath.

In order to use the deploy task, I need a password file which contains the password for the admin user. I've added a file called dev.passfile in the project directory and it contains a singel line:

AS_ADMIN_PASSWORD=adminadmin
Then the only thing which is missing is calling the task:

ant.gfdeploy(file: war.archivePath.path, name: project.name, contextroot: project.name,
upload: 'true', precompilejsp: 'false', asinstalldir: gfHome) {
server(host: 'mydevserver', port: '40048', user: 'admin', passwordfile: 'dev.passfile')
}
As you see I can reference the war file with the war.archivePath.path. This is a handy shortcut to reference the generated WAR file. Also used the project.name as the context root which avoids the version number in the URL.

Since I need to define an undeploy tasks also I can use the power of Groovy and separate out the commen part as a method. For instance I need to check for GLASSFISH_HOME environment variable for each task I define so I put this in a separate method:

def getGlassfishHomeDir()
{
gfHome = System.getenv('GLASSFISH_HOME')
logger.info("Glassfish home: " + gfHome)
if (gfHome == null || gfHome.length() <= 0)
{
msg = "No GLASSFISH_HOME in environment variable. Please set GLASSFISH_HOME to glassfish installation directory"
logger.error(msg)
throw new RuntimeException(msg)
}
return gfHome
}
This can then be called from every gradle tasks.

Smooth :-)

2009-07-10

GWT and AES decryption

I’ve been working on a simple GWT application which had to decrypt some content in the browser. The requirement was that this should happen in the browser – as close to the end user as possible.

The first solution I considered was to use Java code which then would be generated into JavaScript with the GWT compiler. I couldn’t use the built in support in Java since these classes isn’t supported by the GWT compiler, but I thought I might find an implementation which could be used. After some research I found this comment and the specifically the first point:

virtually all crypto libraries out there,… to asymmetric 
(RSA, DSA, 'public/private keypairs') rely heavily on register
looping; the idea that the maximum value an integer field will
hold + 1 'loops around' silently to the minimum value.

javascript numbers do not behave that way (they upgrade
themselves silently to doubles) - and GWT's 'ints', for
reasons of speed, aren't objectified stuff that
software-matically does integer math, they are just translated
to javascript numbers. Hence this looping never occurs, and all

those libraries get confused, and they don't work. You're FAR
FAR better off finding a proper chunk of code designed for
javascript specifically, and wrapping that using JSNI.

This certainly made me look the other way which was to embed JavaScript implementation of the AES algorithm. We had some requirements to the algorithm implementation:


  • Support for 256 bit key lengths

  • Support for salt

  • Cipher Block Chaining

  • Support for initialization vector

  • Handle PKCS-7 padding

After some trial with several implementations we finally got the pidCrypt library working with the content encrypted by our WPF .NET client. It is hosted on SourceForge and the team has been really responsive to questions regarding challenges that I experienced.

In order to get this to work with GWT I had to do the following:

Add the JavaScript to the project

I added the following JavaScript files pidcrypt.js, pidcrypt_util.js, aes_core.js, aes_cbc.js and md5.js to the project (src/main/webapp).

Make those JavaScripts available to the GWT applicaiton

I had to declare the scripts in my GWT application configuration:

<script src="pidcrypt.js" />
<script src="pidcrypt_util.js"/>
<script src="md5.js" />
<script src="aes_core.js" />
<script src="aes_cbc.js" />
Wrap those JavaScript calls with native methods

In order to call those JavaScripts from my "regular Java code" (the Java code which gets compiled to JavaScript), I had to wrap the JavaScript calls with native methods:

public static native String Decrypt(String encryptedText, String key)
/*-{
var aes = new $wnd.pidCrypt.AES.CBC();
var iv = '4857487548754874587549889898';

aes.initByValues(encryptedText, key, iv, {nBits:256, A0_PAD:false});

return aes.decrypt();
}-*/;

With this in place, I was able to decrypt some of the content which our .NET client had encrypted.

2009-07-03

Building GWT application with Gradle

I wanted to check out Gradle in a small GWT application that we build for a very specific purpose. The Gradle version I've used is 0.61. Gradle has a plugin concept, but I haven't seen any GWT plugin for Gradle. The setup ended up being rather easy.

I defined a task which used ANT's Java task:

task gwtCompile << {
created = (new File(gwtBuildDir)).mkdirs()
ant.java(classname:'com.google.gwt.dev.Compiler', failOnError: 'true', fork: 'true') {
jvmarg(value: '-Xmx184M')
arg(line: '-war ' + gwtBuildDir)
arg(line: '-logLevel INFO')
arg(line: '-style PRETTY')
arg(value: 'me.trond.app.MyApp')
classpath {
pathElement(location: srcRootName + '/' + srcDirNames[0])
pathElement(path: configurations.compile.asPath)
pathElement(path: configurations.gwtCompile.asPath)
}
}
}


If you look at the classpath elements I've included a special configuration called gwtCompile. I had to define my own configuration:

configurations {
gwtCompile
}


This also had to be reflected in the dependencies:

dependencies {
...
gwtCompile (
[group: 'com.google.gwt', name: 'gwt-user', version: '1.6.4'],
[group: 'com.google.gwt', name: 'gwt-dev', version: '1.6.4', classifier: 'windows']
)
}


Since I use the war plugin for gradle I had to make sure that gwtCompile task got called before packaging up the war file:

war.dependsOn gwtCompile


Also ensured that the result of the gwtCompile got included in the war file:

war {
//Adds the JavaScript and resources compiled by the GWT compiler
fileSet(dir: file(gwtBuildDir) )
}

2009-01-29

Glassfish: starting node agents in clustered setup fails with ExceptionInInitializerError

We're starting to use glassfish as our application server. The major reason going from Tomcat was that we needed more fully-fledged appserver with JMS functionality. We have had some issues regarding configuring glassfish - especially for cluster support.

I started with a fresh glassfish 2.1 install and headed for a clustered setup. I've seen a few blog post regarding this which made it look simple enough. So I started out with the following commands:


lib/ant/bin/ant -f setup-cluster.xml -Ddomain.name=myDomain -Dadmin.user=admin
-Dadmin.password=password -Dmaster.password=password
bin/asadmin start-domain myDomain
bin/asadmin create-node-agent --host localhost --port 4848 --user admin
--passwordfile /home/glassfish/passfile agentOnFirst
bin/asadmin create-cluster --host localhost --port 4848 --user admin
--passwordfile /home/glassfish/passfile myCluster
bin/asadmin create-instance --host localhost --port 4848 --user admin
--passwordfile /home/glassfish/passfile --nodeagent agentOnFirst --cluster
myCluster instance1


The passfile contained

AS_ADMIN_PASSWORD=password
AS_ADMIN_MASTERPASSWORD=password


Which is what I issued to the setup-cluster.xml ANT build script. When I tried to run the node-agent I got an ExceptionInInitializerError. I tried many different combination - like supplying password when requested instead of providing this as parameters, but it still seems to fail.

I was not able to get the node-agent to start until I tried without changing the admin/master password. If I rather just used the standard passwords, the nodeagent started just fine. Here the commands:


lib/ant/bin/ant -f setup-cluster.xml -Ddomain.name=myDomain
bin/asadmin start-domain myDomain
bin/asadmin create-node-agent --host localhost --port 4848 --savemasterpassword agentOnFirst
bin/asadmin create-cluster --host localhost --port 4848 myCluster
bin/asadmin create-instance --host localhost --port 4848 --nodeagent agentOnFirst --cluster myCluster instance1
bin/asadmin start-node-agent agentOnFirst


I've reported this as a bug as I still consider the original commands or variants of them to be correct.

2008-12-11

Wanted to utilize explorers "New" submenu in an application for both XP and Vista - read this then

Microsoft changed the way to create new files from XP to Vista and the support for this in .NET on Vista vs. XP is rather poor. It took some research to figure how to find the correct files.

In Windows Explorer a user can right-click, choose new and then the user gets presented with a list of different files to create. We have an application which needs to have this functionality available to the user. Windows stores information on how to create these files in the registry. Under a ShellNew key there are some options set up. You can read more about this in this book.

Basically there are four different ways to create a new file:
  1. NullFile
    This means that you can create a new file without worrying about the content in the file. A good example is a .txt file. You just create a new file with the correct extension and you are good to go.
  2. Data
    This means you create a new file, but you have to flush some special content into the file which is stored in the registry. A good example is using .rtf where there are som special data in the beginning of the file.
  3. Command
    Have not tried this one since there isn't a requirement to support this kind of file. Windows have "Briefcase" as a command. Do you need it - you're on your own ;)
  4. FileName
    In this scenario you get a filename from the registry which acts as a template. You then have to make a copy of the template to a new file with the filename you want. Here's were all the fun begins.
On WinXP you could use following method in .NET to find the folder where the templates are located:


string templateFolder = Environment.GetFolderPath(Environment.SpecialFolder.Templates)


In WinXP you get the following directory as a result: "C:\Documents and Settings\Templates". Here are all the templates stored. All you had to do was to copy the templates into the desired location and you were good to go.

In Vista you get the following directory: "C:\users\AppData\Roaming\Microsoft\Windows\Templates". The directory exists, but there's no content in it. Bummer! After some research I found this blogpost which lead to success. Looking into "C:\Windows\ShellNew" gives me template files for all Office documents and OpenOffice documents. Finally a directory where I actually find templates!!!

2008-01-29

unixGeek.equals(financialGeek) == true

According to amazon.co.uk:

We recommend: Standard & Poor's Dictionary of Financial Terms (Standard & Poor's)

by Virginia B. Morris
http://www.amazon.co.uk/dp/1933569042/ref=pe_ar_x3

RRP: £9.99
Price: £9.49
You Save: £0.50 (5%)

Recommended because you purchased or rated:
* The Art of Unix Programming (Addison-Wesley Professional Computing Series)

2007-04-10

Nutch experience

I've experimented a bit with Nutch and the project is both ambitious and potentially important for the open source/Java space. I'm using Nutch to index the file server at work where most of our documents are stored. This index gets used by our intranet which is a Confluence site. The Nutch generated index is used to show related documents on our intranet site. If the viewed page in confluence is a page describing a software architecture document, the confluence plugin will show all related documents from the Nutch index. I'm also planning to create a simple search dialog to do explicit search towards the index.

I think the project has great potential, but still needs some work. My biggest complaint towards Nutch is around configuration. This is both how you configure Nutch, but also the way the code is structured.

Nutch has a concept of default values and site/setup specific values. So if you need to override something for each setup (which you always have to), you must edit the nutch-site.xml. There's the default values which is called nutch-default.xml. I think that Nutch should have "good defaults" and move the whole nutch-default.xml file into the jar file. This way - the user don't have to know about it, but still is able to alter and view it by extracting it from the jar file.

The other part that I'm not to happy about is the number of configuration files. There's the Hadoop configuration, regex-urlfilter.txt, craw-urlfilter.txt and a lot of others. This should be cleaned up so that these configurations could be consolidated so that the user don't have to know about all of these files. Personally I would like to have ONE file to configure and I don't see any reason why this shouldn't be possible. One way to reduce the problem with these configuration settings, is to provide a GUI client which generates the appropriate configuration files.

The other part is the way the code is for the configuration part. First of, I would really like to have in interface for configuration because the current implementation has to many assumption about where to find the configuration files for Hadoop. It's expected to be available in the classpath/classloader. This might be an issue if you have complex classloader hierarchies. Personally I think that the project should consider Common Configuration, but at least start using interfaces so anyone can provide an alternative implementation.