Talking about my stuff

September 1, 2011

Groovy with Gradle and Artifactory

Filed under: Uncategorized — agoodspeed @ 9:11 pm

I am trying to change my Ant builds to Gradle for various reasons. Gradle has a lot of advantages (just ask Hans Dockter if you don’t agree :-) ), so I did not want to simply convert my Ant builds or run them wrapped by Gradle. I wanted to do it right.

Well, I’m not sure whether I have or not, but I have learned a lot that could be helpful to others, or even to me when I get separated from this effort by some other distraction and have to come back to it.

For reference, I am using Groovy 1.7.5 and Gradle 1.0-milestone-1. Gradle 1.0-milestone-3 is currently available and hopefully 1.0 will be released soon so that I can go live with a real release. Unfortunately milestone 3 (and 2) has issues running on AIX which is my build environment (http://issues.gradle.org/browse/GRADLE-1479).

Dependency Management

We were not using dependency management which had us traveling down the road to jar hell, so this is one area that I had to come to terms with. I did not know much about it, and really do not still, but I got something working that appears to take care of my needs; hopefully that giddy feeling will last at least a little while.

Artifactory

Artifactory seemed to be a popular product to get started with, due in no small part to the fact that it has a free (“Open Source”) version; I am running Artifactory 2.3.4. There is also a plugin for Gradle which is helpful; I am using version 2.0.6+ (a snapshot build) of that, which fixes several problems I ran into (https://issues.jfrog.org/jira/browse/GAP-93, https://issues.jfrog.org/jira/browse/GAP-103). For completeness, I also inspired https://issues.jfrog.org/jira/browse/RTFACT-4329.

Out of the box Artifactory has a number of repositories defined. The repositories are of three different kinds – local, remote, and virtual; I’m not fired up about these names but that is what Artifactory calls them so I might as well too.

  • A local repository holds artifacts that you control, whether they are your code potentially published there by your build(s), or they are someone else’s code that you need to manage yourself.
  • A remote repository is related to some other accessible repository (such as Maven Central) and caches artifacts from the related repository when they are requested.
  • A virtual repository is a grouping of local and/or remote repositories that can be read from as one, essentially defining a new namespace that spans several others.
Local Repositories

There are six that come defined with Artifactory, but since I only use two I will mostly limit my discussion to them. Note that local repositories are really the only ones you can deploy artifacts to.

  • libs-release-local is where I publish my artifacts. So as part of my Gradle build I want to put significant resulting artifacts here.
  • ext-release-local is where I deploy artifacts that are provided by someone else but for which there is no existing remote repository I can use to resolve them. For me that is (so far) only the DB2 driver jar file, as I could not find a repository out there that I could retrieve it from.

There is also a plugins-release-local repository whose use is not immediately obvious to me. And for each of these “-release-local” repositories there is a “-snapshot-local” repository, which is presumably used for sticking nightly builds or similar “snapshots” that are supported but need to be isolated from approved releases. The difference is the setting of “Handle Releases” and “Handle Snapshots” in the repository settings.

Okay, so I use these two local repositories. I bet it would be useful to know how you get stuff into them!

  • libs-release-local receives releases through my Gradle build when the artifactoryPublish task is run. I will go into more depth later in this post, but for now it is worth noting that this is a task introduced by the Artifactory plugin in its “publish” closure.
  • ext-release-local receives artifacts most directly using the “Deploy” tab of the Artifactory console – http://{host}[:{port}]/artifactory/webapp/deployartifact.html. When you select the artifact and press “Upload!” you then select the local repository you want to receive it (ext-release-local for me) and then give it the target path you want to use for it under that repository. Note that if you select “Deploy as Maven Artifact” the target path will not be editable, but will be determined by the entries you make for the various Maven attributes. When you are done press “Deploy Artifact” and it should return with a message indicating that it was deployed successfully and the path to the deployed artifact.

If you did not deploy it as a Maven Artifact and have a POM deployed or generated for it you will need to go through the same process to deploy the configuration file, such as an Ivy XML file.

Remote Repositories

Remote repositories are at the heart of dependency management. If a repository already exists with the dependency you have (and most do) then you just need to make the reference to it and you have a proxy to it in Artifactory. It is a proxy in that it should be empty initially; when you retrieve a dependency Artifactory brings it down into the remote repository cache (if it is not there already) and then hands it to you.

Every remote repository automatically gets a second name space, so where you have the “repo1″ remote repository you also have the “repo1-cache” repository. The latter can only be used for retrieval; it will not cause something that is not already in the cache to be downloaded. A reference to the former will cause the artifact(s) to be brought down to the cache.

It is worth noting that a remote repository can be flagged as “Offline” which prevents the main name space from attempting to download artifacts not already in the cache. This represents an additional level of potential control for what gets into the repository. To me it is crazy to let stuff come into the cache from a remote repository without control, so I expect remote repositories to be offline under normal conditions.

Maven and Ivy

Much of my pain was related to mixing repository types. I quickly realized than almost everything in the way of a remote repository uses Maven. However Maven is one of the restrictive elements that Gradle is intended to liberate you from, so I had no interest in adopting it myself and preferred to use Ivy for artifacts under my control. At the same time I do not want my build to be concerned about how the (remote) repository is organized.

Experts readily advised that this is no problem using Artifactory. What took quite a while longer was to find out that it is no problem if you are using Artifactory Pro Version; it is a big problem if you are running the Open Source version as I was. So at this point I am nearing the end of my evaluation period for the Pro Version and am daunted by what I have yet to try that I will need in order to replace all of my builds with Gradle while using Artifactory.

With the Pro Version Artifactory includes the “Repository Layouts” add-on, which allows a request in one form to be mapped to a different form based on the underlying local or remote repository layout. So for my local repositories I use the “gradle-default” layout – effectively Ivy – and for my remote (Maven) repositories I use the “maven-2-default” layout (or whatever is required). This seems to get me to the promised land.

One thing to note though is that the UI does not allow you to change the Repository Layout for an existing repository. This makes some sense if there are artifacts in the repository, at least in a form that conflicts with the new layout, but for me that was not the case; it is very confusing since the default repositories seem comprehensive as long as you want to use Maven, yet using Maven is dubious if you have a choice in the matter.

The “safe” option is to set up new repositories effectively replacing the default ones only with a different layout; I availed myself to the “dangerous” option of going into Admin -> Advanced -> Config Descriptor and modifying the <repoLayoutRef> elements for those repositories. It seemed to work fine, which was kind of novel in my experience to this point.

Gradle

I set up a simple test project, largely because Artifactory support kept asking for one to demonstrate the various bugs I was running into. It is called gradleart to represent the attempt to use Gradle with Artifactory. The project (such that it is) is written in Groovy.

gradleart

There is only one class in the project proper, and that is the very simple com.mydomain.gradle.NothingMuch.groovy located under src/groovy in the project.

package com.mydomain.gradle

import org.apache.log4j.*
import com.ibm.db2.jcc.DB2Driver

class NothingMuch {
  static {
    Logger.getLogger("NothingMuch").log(Priority.FATAL, "Just saying.")
    println "Just said, 'Just saying.'"
    DB2Driver.newInstance()
  }
}

In addition there is only one test class, and that is the very simple com.mydomain.tests.gradle.NothingMuchTests.groovy located under test/groovy in the project.

package com.mydomain.tests.gradle

import com.mydomain.gradle.NothingMuch

class NothingMuchTests extends GroovyTestCase {
  void testClassLoad() {
    try {
      NothingMuch.classLoader.loadClass('com.mydomain.gradle.NothingMuch')
    } catch (Throwable t) {
      assert false, "Failed to load class com.mydomain.gradle.NothingMuch with Throwable ${t}"
    }
  }
}

This leads to the build.gradle file.

apply plugin: 'groovy'
apply plugin: 'artifactory'

// "name" is not settable in the build script, so assert that it has the correct value instead.
// This actually gets set in settings.gradle as:
// rootProject.name = 'gradleart'
assert name == 'gradleart'

// The generated artifact is part of the "com.mydomain" group (or "organisation").
group = 'com.mydomain'

artifactory {

  contextUrl = 'http://artifactory.mydomain.com/artifactory'

  publish {
    repository {
      repoKey = 'libs-release-local'
      // The publishuser and publishpassword authentication credentials are set in gradle.properties.
      //    publishuser=someuser
      //    publishpassword=somepassword
      username = publishuser
      password = publishpassword
      ivy {
        ivyLayout = '[organization]/[module]/ivy-[revision].xml'
        artifactLayout = '[organization]/[module]/[revision]/[module]-[revision](-[classifier]).[ext]'
        mavenCompatible = false
      }
    }
    defaults {
      publishPom = false
    }
  }
  resolve {
    repository {
      repoKey = 'libs-release'
      ivy {
        ivyLayout = '[organization]/[module]/ivy-[revision].xml'
        artifactLayout = '[organization]/[module]/[revision]/[module]-[revision](-[classifier]).[ext]'
        mavenCompatible = false
      }
    }
  }
}

dependencies {
  groovy group: 'org.codehaus.groovy', name: 'groovy-all', version: '1.7.5'
  compile group: 'junit', name: 'junit', version: '4.8.1'
  compile group: 'log4j', name: 'log4j', version: '1.2.15'
  compile group: 'com.ibm', name: 'db2jcc', version: '9'
}

sourceSets {
  main {
    groovy {
      srcDir 'src/groovy'
    }
  }
  test {
    groovy {
      srcDir 'test/groovy'
    }
  }
}

uploadArchives {
  doFirst {
    assert version && version != 'unspecified', "Version not specified. Specify as:\n\tgradle -Pversion=1.0 [task]\n"
  }
  uploadDescriptor = true
}

January 31, 2011

Groovy, Java 6, and Classpath Wildcards

Filed under: Uncategorized — agoodspeed @ 3:19 pm

Java 6 introduced the capability of selecting all jar files in a directory for the classpath rather than having to list every jar file. With Groovy 1.7.1, Groovy caught up with this capability…sort of.

(It is a little odd to me that Groovy had to catch up to this in the first place actually; it seems like Groovy might have addressed this syntactic simplification in the spirit of doing the right thing before Java did.)

Starting with the Java 6 syntax, wilcard support is simply “*” following a directory reference, like “./lib/*”. So when running Groovy you might do this.

groovy -classpath "../batch.jar;../lib/*;." testClasspath

Note that the wildcard needs to be in quotes on Unix or the shell will take over exploding it. This does not work at all on Windows though. Just about anything you try along this line results in:

The syntax of the command is incorrect.

To avoid this error in Windows you must not put anything but the wildcard entry in the classpath and eliminate the quotes. This makes it a very limited solution at best.

groovy -classpath ../lib/* testClasspath

All of these Windows problems tie to the processing of the classpath by startGroovy.bat. While I do not have a solution to that, it seems to be avoidable by setting the CLASSPATH environment variable rather than trying to pass it into the groovy script.

set CLASSPATH=../batch.jar;../lib/*;.
groovy testClasspath

Why You Should Never Set GROOVY_HOME

Filed under: Uncategorized — agoodspeed @ 1:02 pm

I have half a dozen books on Groovy and spend much of my time on the Groovy web site, so it was a big surprise to me when I found out that setting the GROOVY_HOME system environment variable is a really bad idea. Everything I ever read said:

  1. Install
  2. Set GROOVY_HOME
  3. Optionally add the Groovy bin directory to your system path

(And actually from my recent thread on the Groovy user email list, this has been modified on the web site to suggest setting GROOVY_HOME is optional, but there is no real indication of what the tradeoffs are.)

If you ever need to run multiple versions of Groovy (as I did recently while in the process of upgrading Groovy to the version used by my upgraded Grails version) having GROOVY_HOME set is a real detriment. As it happens, when you run a script out of the Groovy bin directory it will set GROOVY_HOME based on where the script is that you are running only if GROOVY_HOME is not already set. If you set it and then run Groovy from a different version you are likely to get some classloader error because of the mismatch.

Exception in thread "main" java.lang.NoClassDefFoundError: org/codehaus/groovy/tools/GroovyStarter
Caused by: java.lang.ClassNotFoundException: org.codehaus.groovy.tools.GroovyStarter
        at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:276)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)

So it is only likely to cause you pain if you set GROOVY_HOME, unless you are intentionally trying to run the script of one version with the guts of another, or the internal Groovy mechanism for setting it is misbehaving somehow.

December 10, 2010

Grails 1.3.5 Tomcat plugin and JNDI environment variables

Filed under: Uncategorized — agoodspeed @ 3:51 am

We have a number of environment variables in our web applications that control how our applications behave. For instance, there is a variable that is dsplayed at the top of the pages (outside of production) that identifies what instance you are in.

When we deploy our war file into a Tomcat instance this is controlled by the conf/context.xml file like so.

<Environment name="appServerInstance" value="My server" type="java.lang.String" override="false"/>

In Grails applications using Jetty (the Jetty plugin) this is easy to control in the web-app/WEB-INF/jetty.xml file like so.

<Configure>
...
  <New id="appServerInstance" class="org.mortbay.jetty.plus.naming.EnvEntry">
    <Arg></Arg>
    <Arg type="java.lang.String">appServerInstance</Arg>
    <Arg type="java.lang.String">My server</Arg>
    <Arg type="boolean">true</Arg>
  </New>
...
</Configure>

Now that Grails uses Tomcat I have been looking for a way to control this in development mode – when using grails run-app from the command line.

The plugin documents a way of handling resource tags using grails.naming.entries in Config.groovy. After repeated attempts and some debugging it became clear that it would not handle environment tags. It is not too difficult to modify the plugin to accommodate environment (env-entry) tags however.

Cutting to the chase, JNDI resources are represented by instances of org.apache.catalina.deploy.ContextResource in the Tomcat naming resources, and these are handled by the plugin. JNDI environments are represented by instances of org.apache.catalina.deploy.ContextEnvironment, and these are not handled by the plugin.

Within the plugin directory (./plugins/tomcat-1.3.5 in my case) under directory src/groovy/org/grails/tomcat you will find TomcatServer.groovy. This is the class that gets things rolling, and the preStart() method is where the grails.naming.entries property is processed. It looked like this when I started.

private preStart() {
  eventListener?.event("ConfigureTomcat", [tomcat])
  def jndiEntries = grailsConfig?.grails?.naming?.entries
  
  if(jndiEntries instanceof Map) {
    jndiEntries.each { name, resCfg ->
      if(resCfg) {
        if (!resCfg["type"]) {
          throw new IllegalArgumentException("Must supply a resource type for JNDI configuration")
        }
        def res = loadInstance('org.apache.catalina.deploy.ContextResource')
        res.name = name
        res.type = resCfg.remove("type")
        res.auth = resCfg.remove("auth")
        res.description = resCfg.remove("description")
        res.scope = resCfg.remove("scope")
        // now it's only the custom properties left in the Map...
        resCfg.each {key, value ->
          res.setProperty (key, value)
        }

        context.namingResources.addResource res
      }
    }
  }
}

It expects a Map that looks something like this.

grails.naming.entries = [
  "jdbc/ArtDB": [
    type: "javax.sql.DataSource",
    auth: "Container",
    description: "Art data source",
    url: "jdbc:db2://myserver:12345/MyDB",
    username: "auser",
    password: "apassword",
    driverClassName: "com.ibm.db2.jcc.DB2Driver"
  ],
  "jms/bananas": [
    type: "org.apache.activemq.command.ActiveMQTopic",
    description: "Fruit salad",
    factory: "org.apache.activemq.jndi.JNDIReferenceFactory",
    physicalName: "bananas"

  ]
]

My thought was that, since there are multiple types of naming resources each needing to be treated differently, why not support maps by type? So my propsed Config.groovy might contain this.

grails.naming.entries = [
  "resources" : [
    "jdbc/ArtDB": [
      type: "javax.sql.DataSource",
      auth: "Container",
      description: "Art data source",
      url: "jdbc:db2://myserver:12345/MyDB",
      username: "auser",
      password: "apassword",
      driverClassName: "com.ibm.db2.jcc.DB2Driver"
    ],
    "jms/bananas": [
      type: "org.apache.activemq.command.ActiveMQTopic",
      description: "Fruit salad",
      factory: "org.apache.activemq.jndi.JNDIReferenceFactory",
      physicalName: "bananas"

    ]
  ],
  "environments" : [
    "appServerInstance": [
      type: "java.lang.String",
      value: "My server",
      override: "false"
    ]
  ]
]

I thought it would be nice to support the original style that considers everything a JNDI resource too, and I was able to accomplish this as long as none of them are named the same as my expected resource type names (“resources” and “environments” in my implementation). After figuring out what was needed, modifying the code was not a big deal. Here is what I ended up with as a replacement for the old preStart method.

private preStart() {
  eventListener?.event("ConfigureTomcat", [tomcat])  
  def jndiEntries = grailsConfig?.grails?.naming?.entries
  
  if(jndiEntries instanceof Map) {
    def envs = jndiEntries.remove('environments')
    if (envs instanceof Map) {
      envs.each { name, cfg ->
        if (cfg) {
          addEnvironment(name, cfg)
        }
      }
    }
    def ress = jndiEntries.remove('resources')
    if (ress instanceof Map) {
      ress.each { name, cfg ->
        if (cfg) {
          addResource(name, cfg)
        }
      }
    }
    jndiEntries.each { name, cfg ->
      if(cfg) {
        addResource(name, cfg)
      }
    }
  }
}

private addEnvironment(name, envCfg) {
  if (!envCfg["type"]) {
    throw new IllegalArgumentException("Must supply a environment type for JNDI configuration")
  }
  def env = loadInstance('org.apache.catalina.deploy.ContextEnvironment')
  env.name = name
  env.type = envCfg.type
  env.description = envCfg.description
  env.override = envCfg.override as boolean
  env.value = envCfg.value
  
  context.namingResources.addEnvironment env
}

private addResource(name, resCfg) {
  if (!resCfg["type"]) {
    throw new IllegalArgumentException("Must supply a resource type for JNDI configuration")
  }
  def res = loadInstance('org.apache.catalina.deploy.ContextResource')
  res.name = name
  res.auth = resCfg.remove("auth")
  res.scope = resCfg.remove("scope")
  res.type = resCfg.remove("type")
  res.description = resCfg.remove("description")
  // now it's only the custom properties left in the Map...
  resCfg.each {key, value ->
    res.setProperty (key, value)
  }
  
  context.namingResources.addResource res
}

There is room for improvement (it could be DRYer for sure) but it works and I have already spent too much time figuring this much out. I hope someone else finds this useful.

It was surprising to me that no one seemed to be missing this capability and that there was no readily available help out there regarding it.

December 7, 2010

Grails 1.3.5 log4j DSL

Filed under: Uncategorized — agoodspeed @ 4:55 pm

I could find very little in the way of straight forward and informative examples of how to do basic log4j configuration in the Grails Config.groovy file. Since this is not something that I tend to revisit very often it is needlessly involved whenever I do have to go there. This represents my attempt to fill that general need of mine, and perhaps someone else will find it useful too.

The most basic configuration you can have would be this.

log4j = {
}

Let’s fill in what that represents. You get a stdout appender to the console for free. If you were to define it you would have approximately this.

log4j = {
  appenders {
    console name:'stdout', layout:pattern(conversionPattern: '%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %p %c{2} - %m%n')
  }
}

The conversion pattern conforms to org.apache.log4j.PatternLayout. To make this appender a default appender explicitly and log at the “error” (or greater) level you would have something like this.

log4j = {
  appenders {
    console name:'stdout', layout:pattern(conversionPattern: '%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %p %c{2} - %m%n')
  }

  root {
    error 'stdout'
  }
}

So now we have the approximate equivalent of the first example. The next component comes into play when you want a category – by convention the equivalent of a package – treated differently than other stuff. For me, it is when I want to see informational or debugging messages related to some, or possibly all, of my code. Now I can decide to log that at a different level than my default (or root) logger.

log4j = {
  appenders {
    console name:'stdout', layout:pattern(conversionPattern: '%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %p %c{2} - %m%n')
  }

  root {
    error 'stdout'
  }

  debug 'com.mydomain'
}

At this point everything that starts with com.mydomain that is logged at the level of debug or greater will get sent to my default appender, stdout. Of course everything that is at error or greater will be sent to my default appender too, just as before. So what if I want a different appender – not a stdout appender?

Well, we can define stdout to be any appender that we want! Just as we can define the pattern layout that we want, we can define the type of appender that we want.

log4j = {
  appenders {
    rollingFile name:'stdout', maxFileSize:"50MB", maxBackupIndex:100,file:"./logs/${appName}_app.log",{
        layout:pattern(
          conversionPattern: '%d{yyyy-MM-dd HH:mm:ss.SSS} | %p | %c | %t | %m | %x%n'
        )
    }
  }

  root {
    error 'stdout'
  }

  debug 'com.mydomain'
}

Of course we might be better off not calling our appender stdout if we want it to be something considerably different – that convention over configuration thing. How about:

log4j = {
  appenders {
    rollingFile name:'logile', maxFileSize:'50MB', maxBackupIndex:100,file:"./logs/${appName}_app.log",{
        layout:pattern(
          conversionPattern: '%d{yyyy-MM-dd HH:mm:ss.SSS} | %p | %c | %t | %m | %x%n'
        )
    }
  }

  root {
    error 'logfile'
  }

  debug 'com.mydomain'
}

This makes logfile our default appender. Of course we can have multiple appenders too. Unless you override stdout you have that automatically. So the prior example has both stdout and logfile. You can have them both as default appenders like so.

log4j = {
  appenders {
    rollingFile name:'logile', maxFileSize:'50MB', maxBackupIndex:100,file:"./logs/${appName}_app.log",{
        layout:pattern(
          conversionPattern: '%d{yyyy-MM-dd HH:mm:ss.SSS} | %p | %c | %t | %m | %x%n'
        )
    }
  }

  root {
    error 'logfile', 'stdout'
  }

  debug 'com.mydomain'
}

Now they both receive the default logging output. What if I want only debugging to go to logfile, and both errors and debugging to go to stdout? Well, default appenders get everything by default, so we don’t want logfile as a default appender but rather a named appender.

log4j = {
  appenders {
    rollingFile name:'logile', maxFileSize:'50MB', maxBackupIndex:100,file:"./logs/${appName}_app.log",{
        layout:pattern(
          conversionPattern: '%d{yyyy-MM-dd HH:mm:ss.SSS} | %p | %c | %t | %m | %x%n'
        )
    }
  }

  root {
    error 'stdout'
  }

  debug logfile: 'com.mydomain'
}

It is valid to name a default appender here but it will result in the appender being written to twice, once due to the explicit reference and once as the default. If you want to write to the named appender only – not to any default appenders – then you need to specify no additivity.

log4j = {
  appenders {
    rollingFile name:'logile', maxFileSize:'50MB', maxBackupIndex:100,file:"./logs/${appName}_app.log",{
        layout:pattern(
          conversionPattern: '%d{yyyy-MM-dd HH:mm:ss.SSS} | %p | %c | %t | %m | %x%n'
        )
    }
  }

  root {
    error 'stdout'
  }

  debug logfile: 'com.mydomain', additivity: false
}

You can supply a list of packages instead of repeating a line for each.

log4j = {
  appenders {
    rollingFile name:'logile', maxFileSize:'50MB', maxBackupIndex:100,file:"./logs/${appName}_app.log",{
        layout:pattern(
          conversionPattern: '%d{yyyy-MM-dd HH:mm:ss.SSS} | %p | %c | %t | %m | %x%n'
        )
    }
  }

  root {
    error 'stdout'
  }

  debug logfile: ['com.mydomain.one','com.mydomain.two'], additivity: false
}

Since ultimately you are setting up (and resolving) logging attributes for a package, the resolution of the logger must be unambiguous. Consequently if you set up the same package multiple times the last one wins for setting the level. So although the following logs to both appenders as you wold expect, it logs to them both as debug.

log4j = {
  appenders {
    rollingFile name:'logile1', maxFileSize:'50MB', maxBackupIndex:100,file:"./logs/${appName}_app1.log",{
        layout:pattern(
          conversionPattern: '%d{yyyy-MM-dd HH:mm:ss.SSS} | %p | %c | %t | %m | %x%n'
        )
    }
    rollingFile name:'logile2', maxFileSize:'50MB', maxBackupIndex:100,file:"./logs/${appName}_app2.log",{
        layout:pattern(
          conversionPattern: '%d{yyyy-MM-dd HH:mm:ss.SSS} | %p | %c | %t | %m | %x%n'
        )
    }
  }

  root {
    error 'stdout'
  }

  error logfile1: 'com.mydomain', additivity: false
  debug logfile2: 'com.mydomain', additivity: false
}

October 29, 2010

Groovy SQL and pseudo Map behavior

Filed under: Uncategorized — agoodspeed @ 7:19 pm

Groovy SQL is a wonderful tool but some of its details are not always obvious from casual inspection – at least circa 1.5.6. (See http://6by9.wordpress.com/2009/05/01/groovy-sql-musings.) One of these is how the Map behavior does not quite match a HashMap.

First it is important to realize whether you are working with a groovy.sql.GroovyResultSet or a groovy.sql.GroovyRowResult, because GroovyResultSet is functionally just delegating property retrieval to the underlying java.sql.ResultSet while the GroovyRowResult actually implements the java.util.Map interface. These are two very different implementations into a very similar syntax.

So which one are you dealing with?

To get a GroovyResultSet user sql.eachRow. To get a GroovyRowResult use sql.firstRow or you can get a List with sql.rows.

It is not really related to the topic, but you can also get the java.sql.ResultSet if you would like with sql.query.

The difference in Map behavior is highlighted when you try something like:

sql.eachRow("""
...
""") { row ->
println row.noColumnNamedThis
}

This uses a GroovyResultSet and will give you an SqlException appropriate to the underlying database. In DB2 it looks like this.

Exception thrown: com.ibm.db2.jcc.a.SqlException: [jcc][10150][10300][3.51.90] Invalid parameter: Unknown column name noColumnNamedThis. ERRORCODE=-4460, SQLSTATE=null

If you use a GroovyRowResult you get something slightly different.

def rows = sql.rows("""
...
""")
rows.each { row ->
println row.noColumnNamedThis
}

Now it will give you MissingPropertyException rather than an SqlException.

Exception thrown: groovy.lang.MissingPropertyException: No such property: noColumnNamedThis for class: groovy.sql.GroovyRowResult

If you want it to behave like a HashMap, one approach is to just turn it into one. I’m not saying this is the best way to do so, but to provide an example:

def rows = sql.rows("""
...
""")
rows.each { row ->
def rowMap = [:]
row.keySet().each { column ->
rowMap[column] = row[column]
}
println rowMap.noColumnNamedThis
}

This will nicely return null for each row as a good Map should.

July 21, 2010

Groovy solution to the static class name problem

Filed under: Uncategorized — agoodspeed @ 9:23 pm

If you have ever done logging where you want to establish the logger based on the class name, you have probably ended up doing something dodgy, like coding a String into each class essentially documenting the class name. This works until you mistype it, or worse, forget to change it from wherever you copied it from.

The Java solution usually looks like:

private static final String className = "foo.Bar";
private static Logger log = Logger.getLogger(className);

Groovy lets you reference “this” within a static context and returns the Class object for it. It seems like that would solve this problem, and it does, but you have to be careful.

At least in my version of Groovy (still at 1.5.6 I’m afraid) the parser is not smart enough to resolve something like:

private static final String className = this.name

Here it backs off of the Groovy static use of “this” and complains about name being a missing property. Using a method invocation – getName() – is somewhat better. It will work in place of the above, but if you try to reference either from within a static method (like main) the compile will fail with something like:

<code>Non-static variable ‘this’ cannot be referenced from the static method main.</code>

So to use this effectively in a static context it is useful to put it into something with a name that is not a reserved word. Here is a solution that works for me.

private static final Class thisClass = this
private static final String thisClassName = thisClass.name
private static Logger log = Logger.getLogger(thisClassName)

I hope this helps someone with similar desires.

May 18, 2010

Serializing and Deserializing Groovy Beans with XML

Filed under: Uncategorized — agoodspeed @ 3:22 pm

I was looking for a way to serialize and deserialize some Groovy Beans to/from XML in a groovy way. Using a MarkupBuilder seemed like the groovy way to go, but it turned out to be far more painful than using a Java library – XStream in my implementation – to support this capability. This post recounts my effort.

This is the interface I wanted  to support.

public interface Xmlable {
  String toXml() {}
  Xmlable fromXml(String xml) {}
}

toXml should produce the XML form for the object, and fromXml should return a populated object such that:

assertEquals xmlable.toXml(), new Xmlable().fromXml(xmlable.toXml()).toXml()

I ended up with a fairly involved (and incomplete) abstract class supporting this interface for use in the targetted Groovy Beans.

public abstract class XmlValue implements Xmlable {
  String toXml() {
    return new StreamingMarkupBuilder().bind(getValue())
  }

  Xmlable fromXml(String xml) {
    return fromXml(new XmlParser().parseText(xml))
  }

  protected abstract Closure getValue() {}

  protected abstract Xmlable fromXml(Node node) {}

  protected Closure add(element) {
    if (getProperty(element) == null)
      return {}
    if (element.size() > 1)
      return {
        "${element[0].toUpperCase()}${element[1..-1]}"(getProperty(element))
      }
    return {"${element[0].toUpperCase()}"(getProperty(element))}
  }

  protected String addBean(Xmlable bean) {
    if (bean == null)
      return ''
    return bean.toXml()
  }

  protected static Xmlable asXmlable(NodeList list, Xmlable bean) {
    if (list == null || list.size() == 0) {
      return null
    }
    assert list.size() == 1
    assert bean != null
    return bean.fromXml(list[0])
  }

  protected static Xmlable asXmlable(Node node, Xmlable bean) {
    return asXmlable((NodeList) node.value(), bean)
  }

  protected static List asXmlableList(NodeList list, Xmlable bean) {
    def returnList = []
    if (list?.size()) {
      Xmlable x
      list.each {xmlable ->
        x = asXmlable(xmlable, bean)
        if (x)
          returnList << x
      }
    }
    return returnList
  }

  protected static Integer asInteger(NodeList attribute) {
    if (attribute == null || attribute.size() == 0) {
      return null
    }
    return new Integer("0${attribute.text()}")
  }

  protected static Short asShort(NodeList attribute) {
    if (attribute == null || attribute.size() == 0) {
      return null
    }
    return new Short("0${attribute.text()}")
  }

  protected static String asString(NodeList attribute) {
    if (attribute == null || attribute.size() == 0) {
      return null
    }
    return attribute.text()
  }

  protected static Date asDate(NodeList attribute) {
    if (attribute == null || attribute.size() == 0) {
      return null
    }
    return DateUtil.toDate(attribute.text(), 'EEE MMM d HH:mm:ss z yyyy')
  }
}

This works reasonably well, but it requires adding methods for deserializing whatever types get serialized into the body of the elements – Integer, Short, String, and Date so for in the above. I also wanted to differentiate between a null value (no element) and an empty element (like for an empty String). An implementation might look like this.

public class SomeValue extends XmlValue {
  Integer someInteger
  String someString
  Date someDate
  Short someShort

  SecondValue someXmlValue
  List<ThirdValue> someXmlValueList

  SomeValue() {}

  protected Closure getValue() {
    return {
      SomeValue() {
        unescaped << add('someInteger')
        unescaped << add('someString')
        unescaped << add('someDate')
        unescaped << add('someShort')
        unescaped << addBean(someXmlValue)
        SomeXmlValueList() {
          someXmlValueList?.each() {listValue ->
            unescaped << addBean(listValue)
          }
        }
      }
    }
  }

  protected Xmlable fromXml(Node node) {
    someInteger = asInteger(node.SomeInteger)
    someString = asString(node.SomeString)
    someDate = asDate(node.SomeDate)
    someShort = asShort(node.SomeShort)
    someXmlValue = asXmlable(node.SomeXmlValue, new SecondValue())
    someXmlValueList = asXmlableList(node.SomeXmlValueList, new ThirdValue())
    return this
  }
}

Beyond the sheer bulk of the implementation, disadvantages include the difficulty of applying it to an existing Groovy Bean that already extends some base class.

XStream handles most of the troublesome aspects of this job much more agreeably. The implementation becomes:

String toXml() {
  XStream xstream = new XStream()
  return xstream.toXML(this)
}

Xmlable fromXml(String xml) {
  XStream xstream = new XStream()
  return xstream.fromXML(xml)
}

The toXml implementation creates a pretty-printed String, but that is easily overcome by using a CompactWriter and the marshal method.

String toXml() {
  XStream xstream = new XStream()
  StringWriter sw = new StringWriter()
  xstream.marshal(this, new CompactWriter(sw))
  return sw.toString()
}

Last, you might want to impose your own mapping rules. My desire was to have element names as capitalized versions of the property such that the “someInteger” property above would be serialized to the “SomeInteger” element. Here is an example of a custom Mapper.

public class SomeMapper extends MapperWrapper {

  public SomeMapper(Mapper wrapped) {
    super(wrapped)
  }

  public String serializedMember(Class type, String memberName) {
    if (memberName.startsWith("_")) {
      // _blah -> blah
      assert memberName > 1
      memberName = memberName[1..-1]
    }
    memberName = memberName[0].toUpperCase() +
            (memberName.size() > 1 ? memberName[1..-1] : '')
    return super.serializedMember(type, memberName)
  }

  public String realMember(Class type, String serialized) {
    String fieldName = super.realMember(type, serialized);
    fieldName = fieldName[0].toLowerCase() +
            (fieldName.size() > 1 ? fieldName[1..-1] : '')
    // Luckily the CachingMapper will ensure this is only ever
    // called once per field per class.
    if (isDeclaredField(type, "_${fieldName}")) {
      fieldName = "_" + fieldName
    }
    return fieldName
  }

  private static boolean isDeclaredField(Class type, String fieldName) {
    // Not very efficient or elegant.
    try {
      type.getDeclaredField(fieldName)
      return true
    } catch (NoSuchFieldException e) {
      return false
    }
  }
}

To make use of it you now need to introduce your own XStream implementation, as below, and instantiate it instead of XStream.

public class SomeXStream extends XStream {
  protected MapperWrapper wrapMapper(MapperWrapper next) {
    return new SomeMapper(next)
  }
}

One frustration that I had, and did not find a palatable solution to given time constraints, was the ability to serialize a class as an unqualified (no package prepended) element and then to deserialize it naturally. My interface should support this since the fromXml method is not static and must therefore have an instance of the target class supplied and available for unmarshalling the XML into. I could not find a convenient hook into the code for accomplishing this, so I am making do with the element name of the outermost class being qualified by the package. Overriding methods in the custom Mapper is where something like this would be done.

public String serializedClass(Class type) {
  return type.getName().replaceFirst(".*\\.", "")
}

public Class realClass(String elementName) {
  try {
    if (elementName.charAt(0) != '[') {
      return classLoader.loadClass(elementName);
    } else if (elementName.endsWith(";")) {
      return Class.forName(elementName.toString(), false, classLoader);
    } else {
      return Class.forName(elementName.toString());
    }
  } catch (ClassNotFoundException e) {
    throw new CannotResolveClassException(elementName + " : " + e.getMessage());
  }
}

February 9, 2010

Jetty, JNDI, and data sources

Filed under: Uncategorized — agoodspeed @ 1:30 pm

I have a need to access some arbitrary databases defined using JNDI from within my Grails application. These are databases in addition to the one defined for the environment in DataSource.groovy.

I define them in my server configuration (context.xml for tomcat) and look them up from the Grails application myself. This works great using tomcat. When I try to define multiple data sources within Jetty (so that IntelliJ and grails run-app, etc. will work with them) they do not seem to be there, although my defined Grails environment JNDI data source is there – no problem.

The exception ends up looking like this. (This is on new InitialContext().lookup("java:comp/env/jdbc/AnotherDB").)

javax.naming.NameNotFoundException; remaining name ‘AnotherDB’
    at org.mortbay.naming.NamingContext.lookup(NamingContext.java:578)
    at org.mortbay.naming.NamingContext.lookup(NamingContext.java:665)
    at org.mortbay.naming.NamingContext.lookup(NamingContext.java:665)
    at org.mortbay.naming.NamingContext.lookup(NamingContext.java:665)
    at org.mortbay.naming.NamingContext.lookup(NamingContext.java:680)
    at org.mortbay.naming.java.javaRootURLContext.lookup(javaRootURLContext.java:112)
    at javax.naming.InitialContext.lookup(InitialContext.java:392)
[snip]

My jetty-env.xml looks like:

[snip]
    <New id=”GrailsDB” class=”org.mortbay.jetty.plus.naming.Resource”>
      <Arg>jdbc/GrailsDB</Arg>
      <Arg>
        <New class=”org.apache.commons.dbcp.BasicDataSource”>
           <Set name=”driverClassName”>com.ibm.db2.jcc.DB2Driver</Set>
           <Set name=”url”>jdbc:db2://dbserver:1/grailsdb</Set>
           <Set name=”username”>me</Set>
           <Set name=”password”>mypwd</Set>
        </New>
      </Arg>
    </New>
    <New id=”AnotherDB” class=”org.mortbay.jetty.plus.naming.Resource”>
      <Arg>jdbc/AnotherDB</Arg>
      <Arg>
        <New class=”org.apache.commons.dbcp.BasicDataSource”>
           <Set name=”driverClassName”>com.ibm.db2.jcc.DB2Driver</Set>
           <Set name=”url”>jdbc:db2://dbserver:3/anotherdb</Set>
           <Set name=”username”>me</Set>
           <Set name=”password”>mypwd</Set>
        </New>
      </Arg>
    </New>[snip]

GrailsDB is available without a problem.

The trick is to realize/remember that Jetty insists on having a resource-ref in the web.xml file; without it the data source never gets bound to the context (I think) with Jetty. So to get my lookup to start finding the AnotherDB data source I make sure I have this in my web.xml file.

  <resource-ref>
    <description>Another database connection</description>
    <res-ref-name>jdbc/AnotherDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>

In case you have not done so already, you can get the Grails web.xml file placed under the src/templates/war directory of your project by running the grails install-templates command so that you can modify it as needed.

June 18, 2009

Tomcat/Jetty, DBCP, and Stale Connections

Filed under: Uncategorized — agoodspeed @ 7:10 pm

In developing applications using Grails we were running into exceptions each morning when users try to access them. The ultimate manifestation was something like:

errors.GrailsExceptionResolver org.springframework.dao.DataAccessResourceFailureException: could not execute query;
nested exception is org.hibernate.exception.JDBCConnectionException: could not execute query
org.codehaus.groovy.runtime.InvokerInvocationException: org.springframework.dao.DataAccessResourceFailureException: could not execute query;
nested exception is org.hibernate.exception.JDBCConnectionException: could not execute query

In DB2 the low-level exception was:

Caused by: com.ibm.db2.jcc.a.sm: [jcc][t4][2030][11211][3.51.90]
A communication error occurred during operations on the connection's underlying socket, socket input stream, or socket output stream.
Error location: T4Agent.sendRequest().  Message: Connection reset by peer: socket write error. ERRORCODE=-4499, SQLSTATE=08001

This was wrapping a java.net.SocketException.

The underlying cause is that we sever all connections to the database for a nightly backup and the applications did not find out about it until they tried to run a query against a stale connection. As it happens though, Tomcat and Jetty (and probably many others) both use Apache Commons DBCP for connection pooling and there are configuration settings that can mitigate this problem; they are documented here – http://commons.apache.org/dbcp/configuration.html.

The settings we are trying in order to remedy the problem are:

    validationQuery="select 1 from sysibm.sysdummy1"
    testWhileIdle="true"
    timeBetweenEvictionRunsMillis="600000"

We are also starting out with these settings which are not particularly related, but might be of interest to some.

    initialSize="4"
    maxActive="100"
    maxIdle="8"
    minIdle="2"
    maxWait="2000"
    removeAbandoned="true"
    logAbandoned="true"
Next Page »

Theme: Rubric. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.