Jetty, SSL, and Grails 1.0.5

I put together a few pieces of information from around the Internet today to allow the “grails run-app” command to run with a confidential transport guarantee.

“grails run-app-https” could be a viable option under some circumstances. Unfortunately it falls short of the happy-path support in most(?) Grails-aware IDEs. run-app-https also does not behave in the way that my deployed application does; specifically, it does not redirect traffic from the http port to the https port when confidential transport is requested.

Setting up a keystore
Instructions for generating a certificate that you can use for SSL in Jetty can be found at http://docs.codehaus.org/display/JETTY/How+to+configure+SSL. Similar instructions for Tomcat can be found at http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html.

In short, keytool – included in a JDK – can generate your certificate with:

%JAVA_HOME%\bin\keytool -genkey -alias jetty -keyalg RSA (Windows)

Note that the default certificate is valid for 3 months. If you would like to generate a certificate that lasts longer, add -validity to the command. If you decide to use a self-signed certificate, then when prompted to enter your first and last name during the certificate creation process, instead enter the hostname of your server. This is the name that browsers will compare to the website’s URL. If the name on the cert and the URL do not match browsers will display a security warning.

The certificate is created in your home directory, and as long as you are running the server (like through “grails run-app” at the command line, or through an IDE) that should be fine. If you are running the server as a service/daemon then you might need to copy it elsewhere or otherwise consider its applicability to the server environment.

Configuring Jetty
You can set up a jetty-env.xml file within Grails, which works fine for setting up datasources through JNDI, but it is meant to configure the Jetty WebAppContext rather than the Jetty Server. Grails does not provide a direct means for configuring the Jetty Server, but there is an indirect method using an event listener. You can find information about doing this in 4.3 Hooking into Events in the 1.0.x Grails reference documentation.

The Jetty API provides additional background for the actions contained in the following script. Adjust the password information as appropriate based on what you provided when you created the certificate.

eventConfigureJetty = { server ->
  println '==In USER_HOME/.grails/scripts/_Events.groovy - eventConfigureJetty...'
  c = server.getConnectors()
  assert c.length == 1
  c[0].confidentialPort = 8443
  ssl = new org.mortbay.jetty.security.SslSocketConnector()
  ssl.port = 8443
  ssl.maxIdleTime = 200000
  keystore = "${System.getProperty('user.home')}/.keystore"
  println "Using keystore ${keystore}"
  ssl.keystore = keystore
  ssl.password = 'password'
  ssl.keyPassword = 'password'
  server.addConnector(ssl)
  println '==eventConfigureJetty complete.'
}

This script should be located in your USER_HOME/.grails/scripts directory and named _Events.groovy. It is invoked during startup, so you should see the printlns once when Jetty is started. System.getProperty(‘user.home’) should resolve to your user ID, and cause the “.keystore” file in your home directory to be used. You can obviously adapt the script to your platform/keystore directory needs.

Java Advanced Imaging – merging tiff files with compression

This week has brought me to a conversion effort that involves merging tiff images. I wrote it using Groovy, but it is not difficult to see what is going on and convert it to Java if you want. My implementation is rather specific to my needs, so it always creates a tiff using LZW compression; being agile (in my mind if nowhere else), additional needs represents an opportunity for minor refactoring.

TIFFs are not supported out of the box, but installing 1.1 of JavaTM Advanced Imaging Image I/O Tools seems to provide the necessary support although in a platform dependent fashion.

This is the approach I took for enabling it within Windows using the CLASSPATH version as described in the installation instructions.

  • Ran it with the defaults
  • Copied clib_jiio.dll, clib_jiio_sse2.dll, and clib_jiio_util.dll from C:\Program Files\Sun Microsystems\JAI Image IO Tools 1.1\lib into %JAVA_HOME%/bin
  • Copied clibwrapper_jiio.jar and jai_imageio.jar from C:\Program Files\Sun Microsystems\JAI Image IO Tools 1.1\lib into %JAVA_HOME%/jre/lib/ext

This may or may not be notably different from downloading and installing with jai_imageio-1_1-lib-windows-i586-jre.exe. I am just suspicious of install scripts that do too much so I did it myself.

Well, here’s the code.

import javax.imageio.IIOImage
import javax.imageio.ImageIO
import static javax.imageio.ImageWriteParam.*

class TiffProcessor {
  private def reader
  private def writer

  public TiffProcessor() {
    reader = ImageIO.getImageReadersByFormatName("tiff").next()
    writer = ImageIO.getImageWritersByFormatName("tiff").next()
    def params = writer.defaultWriteParam
    params.compressionMode = MODE_EXPLICIT
    params.compressionType = 'LZW'
  }

  public void mergeTiffs(def inputTiffs, def outputTiff) {
    def imageList = []
    inputTiffs.each { tiffIn ->
      imageList += readTiffImages(tiffIn)
    }
    writeTiffImage(imageList, outputTiff)
  }

  private def readTiffImages(def tiffIn) {
    def imageList = []
    def iis = ImageIO.createImageInputStream(new File(tiffIn))
    if (!iis) {
      throw new Exception("Input stream not created for ${tiffIn} - check file existence")
    }
    def i = 0
    try {
      reader.setInput(iis)
      try {
        while(true) {
          imageList << reader.readAll(i++, reader.getDefaultReadParam())
        }
      } catch (IndexOutOfBoundsException ex) {
        // Done
      }
      return imageList
    } finally {
      iis.close()
    }
  }

  private void writeTiffImage(def images, def tiffOut) {
    def ios = ImageIO.createImageOutputStream(new File(tiffOut))
    if (!ios) {
      throw new Exception("Output stream not created for ${tiffOut} - check path existence")
    }
    def i = 0
    try {
      writer.setOutput(ios)
      writer.write(images.remove(i++))

      images.each { iioImage ->
        writer.writeInsert(i++, iioImage, null)
      }
    } finally {
      ios.close()
    }
  }
}

Groovy SQL musings

Groovy SQL – or SQL using the groovy.sql.Sql class – has many benefits, but it has some notably unexpected behaviors as well.

GStrings and parameter markers
In order to create code that is protected from SQL injection a GString is treated differently than a String where a SQL statement is supplied to a groovy.sql.Sql method. In particular, if there is a variable embedded in a GString SQL statement it is stripped out and replaced with a parameter marker (“?”). The variable value is then supplied for the parameter (with a setXxx method of PreparedStatement) after the SQL statement with parameter markers is prepared under the covers.

Embedding variables in a GString SQL statement in places that a parameter marker is not valid will cause the statement preparation to fail. This tends to exhibit itself as something like:

java.sql.SQLException: [SQL0104] Token ? was not valid. Valid tokens: ( TABLE LATERAL .

It may raise an exception regarding invalid use of a parameter marker instead if it recognizes an attempt to use a parameter marker but the use is not supported. The following code demonstrates the first condition, where the schema and table name substitutions are replaced with parameter markers.

iSeries.eachRow(“””
select * from ${imageSchema}.${table}
“””) {
println it
}

This example is easily corrected by forcing it to a String like so.

iSeries.eachRow(“””
select * from ${imageSchema}.${table}
“””.toString()) {
println it
}

Unfortunately there does not seem to be any way to explicitly create a GString from a String, so combining a resolved GString with a substitutable GString for such purposes as the below SQL expression does not seem possible as the result remains stubbornly a String.

iSeries.eachRow(“””
select * from ${imageSchema}.${table}
“””.toString() +
“””
where exportfiletype = ${exportFileType}
“””) {
println it
}

Parameter markers – not really Groovy related
Where you have parameter markers, whether created by Groovy in response to a GString with variables or coded by hand, you can get into some ambiguous situations. It is not necessarily clear what the type of a value being substituted should be, and so you can end up with something like:

java.sql.SQLException: [SQL0417] Combination of parameter markers not valid.

One such situation might be:

iSeries.eachRow(“””
select * from efplusint.idmpolexp
where (exportfiletype is null and ? is null or exportfiletype = ?)
“””, [row.exportfiletype, row.exportfiletype]) {
println it
}

SQL gets upset because it does not know what the type of the parameter marker is that is testing for “is null”. Here the CAST expression can make SQL happy to do what you want.

iSeries.eachRow(“””
select * from efplusint.idmpolexp
where (exportfiletype is null and cast(? as varchar(30)) is null or exportfiletype = ?)
“””, [row.exportfiletype, row.exportfiletype]) {
println it
}