Tuesday, April 30, 2013

Book Review: Gradle Effective Implementation Guide

Overview
The choice of build tools in the Java space has basically been Ant or Maven since the early days of Java.   Ant was the first tool to arrive and then Maven was created to help provide standardization, assuming you drank the Maven Kool-Aid, meaning that you could live with the standards set out by Maven.

Now a new build tool has arrived, Gradle.  Gradle adoption started slowly at first, but has definitely been picking up momentum as more and more projects migrate from either Ant or Maven over to Gradle. Gradle can't be ignored!

Gradle is built on top of the Groovy.  The tool provides a rich Domain Specific Language (DSL) based on Groovy. The DSL is the key component of Gradle.

Contents
  • Starting with Gradle, creating and working with build scripts 
  • Gradle for Java projects
  • Dependency management
  • Testing building and publishing artifacts
  • Multi-project builds
  • Gradle with Groovy and Scala
  • Maintaining code quality with tools like Checkstyle, PMD, FindBugs, JDepend, CodeNarc and the Sonar plugin - one of my favorite chapters since I recommend using code static analysis tools for improving code quality
  • Using Gradle with Continuous Integration - covers Jenkins, TeamCity and Bamboo
  • IDE support - provides excellent coverage of Eclipse and IntelliJ IDEA support
Pros
  • Very good reference guide
  • Sample source filled with a lot of complete examples
  • It's by Mr. Haki, creator of Groovy Goodness, Grails Goodness and of course, Gradle Goodness blog postings!
Cons
  • I started out running and verifying every example, but after submitting 6-7 errata for just the first chapter, I stopped running all of the examples and dropped back to just executing examples that peaked my interest.
  • The book contains only a single reference to Ant and no discussion on Gradle's integration with Ant.  In all fairness, Ant integration is not listed in the bullet points on the back of the book that shows "What you will learn", but I think that is a mistake.  Readers are going to be coming from either Ant or Maven and will be looking for help in migrating to Gradle or for help on how to do things in Gradle that they are already doing in Ant or Maven.
  • The book is 356 pages but a lot of pages are 'eaten up' by showing the output of all the example build scripts,  and screen shots from Chapter 11, Using Gradle with Continuous Integration and Chapter 12 IDE support.
Summary
The book is a very good reference for using Gradle and I would definitely recommend it for anyone interested in learning more about Gradle.

Gradle thoughts (not specific to the book)
This the second book I have read on Gradle.  I have read the User's Guide a couple times over the last two years in an attempt to get a firm grip on Gradle.  One of my challenges is that I don't get to use Gradle in my day job, just at night and on weekends.   This limited use seems to extend the learning curve, which I think for Gradle is larger/longer than other tools.

"Convention over configuration" is great for reducing the amount of code in projects, BUT somewhere the user needs to know where the conventions are defined.   I think one of the keys to learning Gradle is to get a firm grasp on the Gradle DSL.  Without a grasp on the DSL,  a new Gradle user just keeps wondering "Where are these properties/methods coming from?"

Monday, February 18, 2013

Minor Gotchas from migration to Java 7

After several years of pushing, we are finally starting to pull our application out of the dark ages  in terms of software levels and one of those steps is upgrading our Java version to Java 7. For the most part, this has been fairly painless, but there have been a couple surprises:
  • Test cases that had been running successfully for years started failing when we switched to Java 7.  It turns out that we had some test cases that depended on previous test cases within the same class.  This is bad on two fronts, 1) the test cases should each be independent and 2) the execution order of test cases within a test class is not guaranteed, although, up to now(before Java 7), the order was the order found in the source code.  I found this link that helped explain the inconsistent ordering I was seeing within Eclipse.  This is not a problem with Java 7 but rather with our test cases.   Just  something that cropped up when we started running with Java 7

  • Our Swing clients began throwing ClassCastExceptions, and this is code that has been in place for over 10 years, dating back to Java 1.4   Reading the javadocs helped explain the problem, but I decided to research a bit more to find out exactly why this was happening now.   We were adding entries to a TreeSet to hold forward and backward traversal keys for the FocusManager, putting KeyStroke objects into the TreeSet.   The javadoc clearly states that the objects put in the TreeSet (or TreeMap underneath) must be Comparable or you need to create the TreeSet with a Comparator for ordering the objects. We were doing neither,  and not getting exceptions.  Digging into the java source code,  I found that starting in Java 7, the TreeMap class has starting enforcing this 'requirement', where the earlier versions of the class had that code commented out, thus not really requiring the comparator.    The fix was easy, I created a KeyStrokeComparator and passed that to the TreeSet constructor.

  • I also noticed that our java jar signing had started logging a warning about the certificate not being valid.   Wanting to keep the build clean and not have these warnings, I did some searches and found several postings related to Java 7 and the removal of the MD2withRSA algorithm from the code signing certificates.   I worked with support from Verisign to help with the removal of that algorithm from our certificate chain and the warning went away!  Unfortunately, that was not the end of the code signing problems.   

  • Next, our web start clients would no longer start successfully, instead throwing an exception with the all-too-familiar  'not all jars signed with the same certificate' error message frequently encountered by web start programs, at least during development!  I've written another blog post about how to help debug through this and figured it was just 'one of the usual suspect jars' that we have problems with, but nope, that wasn't it.   Knowing that all this happened since the certificate was updated caused me to review all of our signed jars to look for clues.   All the jars had been signed with the same certificate, but the 3rd party jars were signed BEFORE the chain entry was remove, whereas our application code was signed as part of the build process, AFTER the certificate was changed.   This led me to believe that even though the jars were signed with the same certificate, that there must be some difference between the jars signed before and after the change to the certificate.   

  • When jars are signed,  entries are generated in the MANIFEST.MF file inside the jar, one entry for each class in the jar.  These entries contain the name of the class along with some signing algorithm information and after reviewing the MANIFEST.MF files,  I found the difference.  The 3rd party jars signed before the change included a SHA1-Digest entry for each class but our jars signed from the current build contained entries with SHA-256-Digest.   Re-signing all of our 3rd party jars with the updated certificate resolved most of the problems.   We had a minor problem in our re-signing process, where we over-wrote the existing MANIFEST.MF with our own generated version and this caused problems for a couple of jars that contained additional service provider information in the manifest file.
All in a days work!  Just Happy to be current on the Java level.  Next up, migrating to EJB3 and Hibernate 3 or 4.

Hope this helps!




Thursday, November 29, 2012

Grails & EJB2, my stumbling points

I have been 'playing' with Grails for a couple years now.  I say 'playing' because I don't get to use Grails for my day job.   My day job revolves around a Point-of-Sale (POS) and Back Office system with Web Start clients written using Swing and the server back-end uses EJB2.1 with Hibernate handling the persistence-layer.  Yeah, I know, nobody still uses EJB 2.1!  I have been pushing for some technical upgrades and hopefully that will happen this year, but that not want I want to talk about.

In the past, when I wanted to create a small work-related Grails project, I took what I saw as the easier way out.  I used the static mappings in the domain object to map tables and columns to fields in the domain object, and this works fine.  Recently, I decided to re-visit one of my small projects with the intention of using Grails as the front-end and using the existing EJBs to get access to server data.  Below is a list of my stumbling points along the way to getting this project working.   Only one of the points is EJB2 related but the others are all valid for a lot of current projects.

My stumbling points:
  1. resources.groovy bean definition: JndiObjectFactoryBean vs SimpleRemoteStatelessProxyFactoryBean
  2. LinkageError - referencing javax.management.MBeanServer
  3. Compile errors after removing Hibernate 
  4. BuildConfig.groovy 
resources.groovy bean definitions:
When I decided to use the existing EJBs within Grails, I did some google searches to find the correct format for defining these beans within the resources.groovy file.  I found some examples that worked great if you were using EJB 3.x.  If you are using EJB 3.x, you reference the JndiObjectFactoryBean and this returns the remote service interface.  If your beans are actually EJB 2.1 and you use the JndiObjectFactory, you get back the 'home' interface, which has no business interface methods included.  Again, the problem is that I am using EJB 2.1.   Another couple google searches turned up Dave Klein's "Grails Integration Strategies" presentation and the answer was there on page 15.  For EJB 2.x, you need to use the SimpleRemoteStatelessProxyFactoryBean in order to get the remote service interface.   Spring's SimpleRemoteStatelessProxyFactoryBean handles retrieving the home interface, calling  PortableRemoteObject.narrow() and then calling create() in order to return a remote service interface for EJB 2.1.

resources.groovy for EJB 2.x

beans = {
    ejbJndi(org.springframework.jndi.JndiTemplate) {
        environment = [
            "java.naming.factory.initial" : "org.jnp.interfaces.NamingInitialContextFactory",
            "java.naming.provider.url" : "jnp://localhost:1099",
            "java.naming.security.principal" : "root",
            "java.naming.security.credentials" : "root"
        ]
    }
    environmentSvc(org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean) {
        jndiName = "ejb/EnvironmentService"
        businessInterface = "com.xxx.server.service.environment.EnvironmentService"
        jndiTemplate = ref("ejbJndi")
    }
    
}


resources.groovy for EJB 3.x

beans = {
    ejbJndi(org.springframework.jndi.JndiTemplate) {
        environment = [
            "java.naming.factory.initial" : "org.jnp.interfaces.NamingInitialContextFactory",
            "java.naming.provider.url" : "jnp://localhost:1099",
            "java.naming.security.principal" : "root",
            "java.naming.security.credentials" : "root"
        ]
    }
    processService(org.springframework.jndi.JndiObjectFactoryBean) {
    jndiName = "ejb/ProcessService"
    jndiTemplate = ref("ejbJndi")
    
}


Linkage Error:
The next step was to compile and run the application, but I kept getting these 'Linkage Errors' shown below. Again, after sufficient google searches, I found a couple different postings with the same issue.   I am using JBoss as my application server and using the JBoss jars within Grails.  This problem appears to be a duplication of classes on the classpath between Tomcat and JBoss in the JMX area. According to the postings, there are (at least) two options:
  1. delete Tomcat and install Jetty, which I did and it worked great!
  2. deploy a war to Tomcat.  Apparently this problem only happens in the development environment and deploying your application as a war side steps this problem.

Below is an example of the LinkageError

c:\dev\groovy\hv>grails run-app
| Compiling 113 source files
Note: C:\Users\mmiller\.grails\2.1.0\projects\hv\plugins\cache-1.0.0\src\java\grails\plugin\cache\web\GenericResponseWrapper.java uses or oerrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
| Running Grails application
| Error Failed to initialize component [StandardServer[-1]] (NOTE: Stack trace has been filtered. Use --verbose to see entire trace.)
org.apache.catalina.LifecycleException: Failed to initialize component [StandardServer[-1]]
        at org.grails.plugins.tomcat.InlineExplodedTomcatServer.doStart(InlineExplodedTomcatServer.groovy:137)
        at org.grails.plugins.tomcat.TomcatServer.start(TomcatServer.groovy:102)
        at _GrailsRun_groovy$_run_closure5_closure12.doCall(_GrailsRun_groovy:176)
        at _GrailsRun_groovy$_run_closure5.doCall(_GrailsRun_groovy:153)
        at _GrailsRun_groovy.runInline(_GrailsRun_groovy:121)
        at _GrailsRun_groovy$_run_closure1.doCall(_GrailsRun_groovy:67)
        at RunApp$_run_closure1.doCall(RunApp.groovy:33)
Caused by: java.lang.LinkageError: loader constraint violation: loader (instance of ) previously initiated loading for a differnt type with name "javax/management/MBeanServer"
        ... 7 more
| Error Server failed to start: org.apache.catalina.LifecycleException: Failed to initialize component [StandardServer[-1]]

Compile errors after removing Hibernate:
After getting Jetty installed, I was ready to run the app and get things going. Nope, more errors - now I can't compile because something can not find org.hibernate.cfg.Configuration!   I am working on Grails 2.1.0 and starting in that release, the database migration plugin depends on Hibernate, so if you are going to remove Hibernate, you also need to remove the database migration plugin.   Easy fix - edit BuildConfig.groovy to remove the database migration plugin and re-run.  Below is a copy of both the short error version and the longer version, which used --stacktrace to get a full stacktrace.


c:\dev\groovy\hv>grails run-app
| Uninstalled plugin [tomcat]
| Uninstalled plugin [hibernate]
| Compiling 113 source files.
| Error Fatal error during compilation org.apache.tools.ant.BuildException: java.lang.NoClassDefFoundError: org/hibernate/cfg/Configuration
(Use --stacktrace to see the full trace)


c:\dev\groovy\hv>grails --stacktrace run-app
| Compiling 113 source files.
| Error Fatal error during compilation org.apache.tools.ant.BuildException: java.lang.NoClassDefFoundError: org/hibernate/cfg/Configuration
(NOTE: Stack trace has been filtered. Use --verbose to see entire trace.)
java.lang.NoClassDefFoundError: org/hibernate/cfg/Configuration
        at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
        at org.codehaus.gant.GantBuilder.invokeMethod(GantBuilder.java:99)
        at _GrailsCompile_groovy$_run_closure3_closure8_closure9.doCall(_GrailsCompile_groovy:62)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at _GrailsCompile_groovy$_run_closure3_closure8_closure9.doCall(_GrailsCompile_groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at java_util_concurrent_Callable$call.call(Unknown Source)
        at _GrailsCompile_groovy.withCompilationErrorHandling(_GrailsCompile_groovy:69)
        at _GrailsCompile_groovy.this$4$withCompilationErrorHandling(_GrailsCompile_groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
        at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:168)
        at _GrailsCompile_groovy$_run_closure3_closure8.doCall(_GrailsCompile_groovy:61)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at _GrailsCompile_groovy$_run_closure3_closure8.doCall(_GrailsCompile_groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
        at _GrailsCompile_groovy$_run_closure3.doCall(_GrailsCompile_groovy:58)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
        at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16_closure18.doCall(GantBinding.groovy:185)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16_closure18.doCall(GantBinding.groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at java_util_concurrent_Callable$call.call(Unknown Source)
        at org.codehaus.gant.GantBinding.withTargetEvent(GantBinding.groovy:90)
        at org.codehaus.gant.GantBinding.this$4$withTargetEvent(GantBinding.groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16.doCall(GantBinding.groovy:185)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16.doCall(GantBinding.groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantMetaClass.processClosure(GantMetaClass.java:81)
        at org.codehaus.gant.GantMetaClass.processArgument(GantMetaClass.java:95)
        at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:128)
        at _GrailsCompile_groovy$_run_closure2.doCall(_GrailsCompile_groovy:45)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
        at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16_closure18.doCall(GantBinding.groovy:185)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16_closure18.doCall(GantBinding.groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at java_util_concurrent_Callable$call.call(Unknown Source)
        at org.codehaus.gant.GantBinding.withTargetEvent(GantBinding.groovy:90)
        at org.codehaus.gant.GantBinding.this$4$withTargetEvent(GantBinding.groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16.doCall(GantBinding.groovy:185)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16.doCall(GantBinding.groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
        at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:168)
        at _GrailsPackage_groovy$_run_closure2_closure9.doCall(_GrailsPackage_groovy:45)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at _GrailsPackage_groovy$_run_closure2_closure9.doCall(_GrailsPackage_groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
        at _GrailsPackage_groovy$_run_closure2.doCall(_GrailsPackage_groovy:44)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
        at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16_closure18.doCall(GantBinding.groovy:185)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16_closure18.doCall(GantBinding.groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at java_util_concurrent_Callable$call.call(Unknown Source)
        at org.codehaus.gant.GantBinding.withTargetEvent(GantBinding.groovy:90)
        at org.codehaus.gant.GantBinding.this$4$withTargetEvent(GantBinding.groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16.doCall(GantBinding.groovy:185)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16.doCall(GantBinding.groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantMetaClass.processClosure(GantMetaClass.java:81)
        at org.codehaus.gant.GantMetaClass.processArgument(GantMetaClass.java:95)
        at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:128)
        at RunApp$_run_closure1.doCall(RunApp.groovy:28)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantMetaClass.invokeMethod(GantMetaClass.java:133)
        at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16_closure18.doCall(GantBinding.groovy:185)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16_closure18.doCall(GantBinding.groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at java_util_concurrent_Callable$call.call(Unknown Source)
        at org.codehaus.gant.GantBinding.withTargetEvent(GantBinding.groovy:90)
        at org.codehaus.gant.GantBinding.this$4$withTargetEvent(GantBinding.groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16.doCall(GantBinding.groovy:185)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at org.codehaus.gant.GantBinding$_initializeGantBinding_closure5_closure16.doCall(GantBinding.groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at java_util_concurrent_Callable$call.call(Unknown Source)
        at gant.Gant$_dispatch_closure5.doCall(Gant.groovy:381)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at gant.Gant$_dispatch_closure7.doCall(Gant.groovy:415)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at gant.Gant$_dispatch_closure7.doCall(Gant.groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at java_util_concurrent_Callable$call.call(Unknown Source)
        at gant.Gant.withBuildListeners(Gant.groovy:427)
        at gant.Gant.this$2$withBuildListeners(Gant.groovy)
        at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown Source)
        at gant.Gant.dispatch(Gant.groovy:415)
        at gant.Gant.this$2$dispatch(Gant.groovy)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at gant.Gant.invokeMethod(Gant.groovy)
        at gant.Gant.executeTargets(Gant.groovy:591)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at gant.Gant.executeTargets(Gant.groovy:590)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
        at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
Caused by: java.lang.ClassNotFoundException: org.hibernate.cfg.Configuration
        ... 123 more
| Error Fatal error during compilation org.apache.tools.ant.BuildException: java.lang.NoClassDefFoundError: org/hibernate/cfg/Configuration



Minor mention:
Starting in Grails 2.x,  BuildConfig.groovy plays a bigger role in dependency resolution.  I read in some forum postings that modifying BuildConfig.groovy was now the preferred way of handling plugins rather than using the command line 'grails install-plugin ' or 'grails uninstall-plugin '.   My problem was that I was starting with a Grails project that was originally created with Grails 1.3.7 and BuildConfig.groovy had not been updated with all the plugins.  I had to use a combination of the command line (grails uninstall-plugin)  plus edits to BuildConfig.groovy to resolve my problems.  

Final Thoughts:
The problems documented above were mainly my fault and not that of Grails!  I am just documenting them to possibly help anyone trying the same type of integration.  Maybe this will save them some time and frustration!

Hope this helps!

Tuesday, August 28, 2012

Resolving the "Not all jars signed with same certificate" issue

Almost a year ago I wrote posting on how to resolve the "Not all jars signed with the same certificate" problem encountered from time to time with signed Web Start applications.   My solution at that time was to use a short Groovy script to show each jar and a list of the certificates the jar was signed with.  For those familiar with Groovy, that's still my suggestion.

Recently one of our customer service folks was fighting this same problem at a customer site.  To make matters worse, they were not familiar with Groovy, so using my previous script was not an option.   I decided to bite the bullet and write the Java equivalent.

Below is my Java-equivalent of the Groovy script.  The code is saved as the JarSigners project at GitHub.


package util;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

/**
 *  Show which jars are signed with which code signing certificates
 */
public class JarSigners {

 private String folderName;
 private Map> map;
 private Set certs;
 
 public JarSigners(String folderName) {
  this.folderName = folderName;
  map = new HashMap>();
  certs = new HashSet();
 }
 
 public void listJarSigners() throws ZipException, IOException {
  File dir = new File(folderName);
  FilenameFilter filter = new FilenameFilter() {
      public boolean accept(File dir, String name) {
          return name.endsWith(".jar");
      }
  };
  String[] files = dir.list(filter);
  System.out.println("Found "+files.length+" files in folder: "+folderName);
  for (String fileName : files) {
   checkJarForCertificate(fileName);
  }
  System.out.println("Certificates used to sign the jars: "+certs);
  if (certs.size() > 1) {
   System.out.println("WARNING: More that one certificate shows up in the jars!");
  }
  System.out.println("Details jar->certificate: "+map);
 }
 
 private void checkJarForCertificate(String fileName) throws ZipException, IOException {
  File jar = new File(folderName, fileName);
  ZipFile zip = new ZipFile(jar);
  //System.out.println("Processing "+fileName);
  for (Enumeration entries = zip.entries(); entries.hasMoreElements();) {
         // Get the entry name
         String zipEntryName = ((ZipEntry)entries.nextElement()).getName();
         if (zipEntryName.endsWith(".RSA")) {
          if (!certs.contains(zipEntryName)) {
           certs.add(zipEntryName);
          }
          if (map.containsKey(fileName)) {
           List list = map.get(zipEntryName);
           list.add(zipEntryName);
          } else {
           List list = new ArrayList();
           list.add(zipEntryName);
           map.put(fileName, list);
          }
         }
     }
  zip.close();
  
 }

 /**
  * @param args
  * @throws IOException 
  * @throws ZipException 
  */
 public static void main(String[] args) throws ZipException, IOException {
  if (args.length != 1) {
   System.out.println("Invalid invocation: you must pass a folder name");
   return;
  }
  JarSigners js = new JarSigners(args[0]);
  js.listJarSigners();
  System.out.println("Done!");
 }

}


Hope this helps!

Thursday, August 23, 2012

Auto-completion for email addresses in Swing


Recently we added the ability to send Electronic Receipts from our Point-of-Sale product at work.   One of the requirements was to enhance the user interface around the capture of email addresses.   We were just using a standard JTextField to capture the value.  Specifically, we were looking to make the entry of the email address easier by way of auto-completion, much like a lot of ajax-enabled fields in web applications.


I didn't want to re-invent the wheel and felt certain that I could something to get me started with the help of Google!   After a couple searches, I found a great starting point for the new code.  Samuel Sjöberg's auto-completion was extremely close to what I wanted.   Rather than auto-completing a person's name, I wanted to provide auto-completion for the part of the email address after the "@".    I also modified the code a bit to read the auto-completion candidates from a properties file.  This allows you to provide a properties file containing some of the most common email addresses.   Below is a copy of a sample properties file.

#################################################################################
# Commonly used Email Addresses                            
#                                                          
# This file will be read when the component starts up      
# and used to create an ArrayList of names to be used 
# for auto-completion of email addresses entered into 
# fields that assign the EmailAddressAutoCompletionDocument                      # to the field.  
#
# For better performance, put the most commonly used/encountered
# email addresses at the top of the list.
#
#################################################################################

 hotmail=hotmail.com
 gmail=gmail.com
 yahoo=yahoo.com
 verizon=verizon.net
 comcast=comcast.net
 aol=aol.com
 outlook=outlook.com
 mail=mail.com
 bigstring=bigstring.com
 shortmail=shortmail.com
 lycos=lycos.com
 excite=excite.com
 zoho=zohomail.com
 zzn=zzn.com

Below is the interesting part of the auto-completion of the email address field. First, I included a check for a max length of 255 to prevent too much data for our database columns. Next, we check for an "@" sign entered.  If no @ sign, add the text.  There is also a check to prevent a second @ from being added to the field.  Once we get past that, its time to call the completion service looking for a match on the email address. If a match is found, we add the rest of the string to the text box and select the part of the address that wasn't actually entered by the user.

 public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
        if (str == null || str.length() == 0) {
            return;
        }

        // check for max length first
        if (str == null || ((str.length() + getLength() > maxLength) && maxLength > 0))
   return;
        
        String text = getText(0, offs);        // Current text.
        int atSignIdx = text.indexOf(AT_SIGN); // 1st @ sign
        if (atSignIdx != -1 && offs > atSignIdx) {
         String fullText = text+str;
         //prevent entry of 2nd @ sign
         if (fullText.indexOf(AT_SIGN, atSignIdx+1) != -1) {
          return;
         }
         String address = fullText.substring(fullText.indexOf(AT_SIGN)+1);
         String completion = complete(address);
         int length = offs + str.length();
         if (completion != null && text.length() > 0) {
                super.insertString(offs, completion.substring(address.length()-1), a);
                documentOwner.select(length, getLength());
         } else {
          super.insertString(offs, str, a);
         }
        } else {
            super.insertString(offs, str, a);
        }
    }

I also added automatic validation of the full address by providing a regular expression to match against and then assigned a KeyListener to help implement the validation with color coding.   As the user types an email address, the foreground color is red and then when the email address is complete, either through auto-completion of the address portion or just typing, the foreground color is changed to green for a valid address.

Thanks to Samuel for posting his code.  My updated version can be found at GitHub.

Hope this helps!

Monday, August 13, 2012

Book Review: MongoDB in Action

Overview
 I am a big fan of Manning Publications books and so when it came time to do some personal research on NoSQL, I started with the Manning website to what books they had that covered the topic.  I didn't really have any specific requirements, like document model vs key value pairs vs graph database.  I just wanted something fairly current and covering one of the main players in the area.

I found this book on the website and the publication date (2012) helped ensure that I was getting was something current and not a couple years old.  The other nice surprise was the size of the book.  For anyone that's read an 'In Action' book from Manning, you know they generally tend to be fairly large, on the scale of 300-400 page or more.   This book weighs in at 278 pages and that includes 5 appendices!

Contents
The book is broken down into 3 parts:

  1. Getting Started, which covers about 50 pages talking about MongoDB at a high-level, the core server, tools, replication, the JavaScript shell and writing programs and using drivers to interact with the database.
  2. Application Development in MongoDB covers principles of schema design, MongoDB databases, collections, Mongo's query language, updates atomic operations and deletes.
  3. MongoDB Mastery covers index and query optimization, replication, sharding and deployment. 
Summary
An excellent book by Kyle Banker and yet another excellent book from the folks at Manning Publications.  I blew through the first two parts of the book, eager to learn more about NoSQL and MongoDB.  The author does an excellent job explaining concepts within MongoDB and backs up his statements with the reasons why things are done the way they are.

It took a bit longer for me to get through part 3 of the book, no fault of the author or book.  Since this was really my own personal research and there is no way I will be implementing MongoDB or NoSQL at my day job, other than maybe some small personal tools/utilities, the topics of replication and sharding just didn't have the same appeal as learning about the core server, the query language and schema design!

Overall, I would recommend this book to anyone interested in learning about MongoDB.




Monday, July 16, 2012

GDK vs JDK

A lot of folks new to Groovy quickly ask the question, "What's is the GDK?" or "What's the difference between the GDK and the JDK?"

If you take a look thru the GDK documentation, you will see that the GDK acts like an extension to the Java JDK.  New methods are added to the GDK help remove the ceremony and allow Groovy code to be short and concise.  Think of it as a big decorator pattern!   Slight clarification: the JDK is used to build the GDK and referenced by the GDK but it is NOT part of the GDK and not shipped with the GDK.

Maybe a picture will help.  You can see some of the new GDK methods added to the Java classes below.


Hope this helps!