Česky   |  Deutsch   |  English   |  Español   |  Français   |  Indonesia   |  日本語   |  한글   |  Polski   |  Português (BR)   |  Türkçe   |  中文   |  正體中文   |  Your Language  
PlanetNetbeans
Planet NetBeans ist eine Sammlung aller NetBeans-relevanten Gedanken aus der ganzen Blogosphäre.
Feeds
[RSS 1.0 Feed] [RSS 2.0 Feed]
[FOAF Subscriptions] [OPML Subscriptions]
Feed Abonnenten

Powered by:    Planet

Last updated:
January 26, 2015 12:04 PM
All times are UTC

Sponsored by
sponsored by Oracle

visit NetBeans website
Java Getriebe » NetBeans - January 16, 2015 07:39 AM
NetBeans RCP und JavaFX (Tutorial) » Krolli’s Blog

Ich selber habe zwar noch nicht wirklich mit JavaFX gearbeitetet. Irgendwie fehlte das entsprechende Projekt dazu und privat habe ich leider nie die Ruhe gefunden mich mit dem Thema zu beschäftigen, leider. Michael Kroll hat in seinem Block ein kleines Tutorial geschrieben wie man JavaFX in einer NetBeans RCP Anwendung einbinden kann.

Java Getriebe » NetBeans - November 22, 2014 03:43 PM
GCC unter Windows in NetBeans

Die NetBeans IDE kann nicht nur Java sinnvoll verarbeiten. Sie war schon immer in der Lage auch andere Sprachen, insbesondere solche, die mit Java und seinen Werkzeugen nicht unbedingt etwas zu tun haben. Die aktuelle Version 8.0.1 zum Beispiel hat sich auf die Fahnen geschrieben besonders gut mit HTML und JavaScript zusammen zu arbeiten. Aber…

APIDesign - Blogs - June 02, 2014 07:49 AM
Podcast related to Japanese Translation

--JaroslavTulach 07:49, 2 June 2014 (UTC)

Java Getriebe » NetBeans - May 26, 2014 06:59 AM
TopComponentGroup mit Annotation

Für eins meiner Projekte hier in der WZL Getriebeabteilung wollte ich 2 TopComponents öffnen. Das geht am schönsten mit TopComponentGroups. Wer allerdings schon einmal eine TopComponentGroup erstellt hat, der wird mir sicherlich zustimmen, dass das Eintragen in die layer.xml eine sehr fehleranfällige Methode ist, da man sich relativ leicht vertippen kann. Nichtsdestotrotz habe ich es…

Java Getriebe » NetBeans - April 25, 2014 01:35 PM
NetBeans Training 2014 in Leipzig

Wir, die Matse-Azubis der Getriebeabteilung des WZL, Tobias Moers, Daniel Koll und Patrick Plum inklusive unserer Ausbilderin Annette Glindmeyer absolvierten vom 14-16. April 2014 das NetBeans Training in Leipzig. Unsere Trainer waren Geertjan Wielenga, Anton (Toni) Epple mit Unterstützung des Veranstalters Benno Markiewicz. Als wir in Leipzig ankamen, bestaunten wir die prachtvollen Gebäude vom Bundesverwaltungsgericht,…

Java Getriebe » NetBeans - March 02, 2014 05:12 PM
Debuggen von Annotation Prozessoren (Teil 2)

Ich habe vor einiger Zeit schon mal geschrieben, wie man seine eigenen Processor Implementierungen mit NetBeans debuggen kann. Durch Zufall bin ich neulich allerdings über einen anderen Hinweis gestolpert mit dem das ganze Prozedere deutlich einfacher wird und keine zweite IDE Instanz benötigt. Niemand geringere als der “Erfinder” von NetBeans selbst Jaroslav Tulach hat im…

Java Getriebe » NetBeans - August 21, 2013 09:02 AM
Java Scrapbook for NetBeans IDE – Geertjan’s Blog

Geertjan hat ein neues Plugin gebastelt: Java Scrapbook for NetBeans IDE. Quasi ein kleines “Notizbuch” für Java Quelltexte mit der netten Fähigkeit diesen Quellcode auch ausführen zu können. Der Clou dabei ist, dass man dafür keine Klasse oder Methode schrieben muss, sondern einfach nur die gewünschten Anweisungen. Das Feature kenne ich noch aus Eclipse Zeiten…

Java Getriebe » NetBeans - July 29, 2013 05:58 PM
Aufgabe: Zeige alle .properties eines Projekts an

Aufgabe: Erstelle ein NetBeans Modul mit dem alle .properties Dateien des aktuell ausgewählten Projekts in einem eigenen Fenster angezeigen werden können. Ich finde, dass diese Aufgabe sich ganz gut als Einstieg in die NetBeans Platform Programmierung eignen kann. Sie erfüllt einen Zweck und all zu schwer sollte sie nicht sein, zumindest wenn man sich in…

Java Getriebe » NetBeans - July 15, 2013 03:52 PM
@OnStart & @OnStop Geertjan’s Blog

Es ist zwar schon eine Weile her, dass die Funktion in NetBeans eingebaut wurde (mit Version 7.2) aber ich durfte sie aus gegebenen Anlass erst jetzt entdecken: @OnStart & @OnStop Geertjan’s Blog. In früheren Versionen von NetBeans musste man immer eine eigene Implementierung von ModuleInstall in seinem Modul registrieren welche dann während des Startprozesses der…

Java Getriebe » NetBeans - March 28, 2013 03:34 PM
Installation von MinGW für NetBeans

Auch wenn das hier eigentlich ein Java-Blog ist, so möchte ich trotzdem einmal zeigen, wie einfach man NetBeans auch für die C/C++ Entwicklung einrichten kann. Die Anleitung passt sogar in einen Tweet: Download sourceforge.net/projects/mingw…, unzip, call “bin\mingw-get.exe install sh g++ gfortran gdb msys-make”, set path, enjoy #NetBeans for C/C++ — Jens (@nigjo) 28. März 2013…

Java Getriebe » NetBeans - June 29, 2012 08:50 AM
Die NetBeans Laufzeitkonfiguration auf einen Blick

Geertjan hatte vor ein paar Tagen schon einen Artikel “Viewing the NetBeans Central Registry” in seinem Blog eingestellt in dem er mit einen mehr oder weniger Einzeiler das aktuelle “SystemFileSystem” anzeigen kann. Diese “Zentralen Einstellungen” (bzw “XML Layer File System”) ist DER Mechanismus der NetBeans Platform um die Modularität der RCP Anwendungen sicher zu stellen.…

Bernhard's Weblog - June 12, 2009 10:14 PM
Webtest wrapped as maven project

I have wrapped the canoo webtest project as a maven project. By default canoo webtest is shipped with ant script, only. My intention is to avoid downloading the webtest jars manually, but using the maven dependency, and downloading mechanism for downloading the webtest jars. The webtest jars are expressed as maven dependencies.

Directory Layout

The webtest maven project has following directory layout

etc/webtest
webtest resources except jars
lib
maven-ant-task jar
src/assembly
maven assembly for building a bin distribution of this project
src/dist
ant, and groovy scripts packed into the bin distribution
src/test/resource
webtestLog4j.properties log4j configuration
src/test/webtest
webtest scripts as ant, and groovy scripts
build.xml
ant script for running webtests using webtest dependencies defined in pom.xml
pom.xml
maven pom, goals for running webtest, and building bin distribution
build-maven-antrun.xml
ant script invoked from maven antrung plugin

Running Webtest

There are two ways to run webtest:

Launch mvn test, or run ant; both uses the webtest dependency expressed in the maven pom.xml.

"mvn test" uses internally maven antrun, and build-maven-antrun.xml to run the tests.

"ant" uses build.xml, and maven-ant-task jar for running the webtests.

Both ways store the webtest results in target/webtests-result.

Bin distribution

Running "mvn assebly:assembly" a zip file is created in the target directory. This zipfile stores all webtest jars in the directory lib. After unzipping the file, you can run the webtests by launching "ant".

Have fun!

Practical API Design - May 18, 2009 05:43 PM
API Podcast #2: Reentrancy

Listen to podcast #2: to learn about our take on Swing and its poor reentrancy. Find out what it may mean for your own API design and especially Runtime_Aspects_of_APIs that you create. Learn to fight with that problem by maximizing the declarative nature of your API. --JaroslavTulach 17:43, 18 May 2009 (UTC)

Practical API Design - May 12, 2009 07:50 PM
API PodCast #1

Listen to this: ! It is almost a year since we (me and Geertjan) started our regular API Design Tips podcasts. They used to be part of larger NetBeans podcasts, however recently I needed some promotion material for TheAPIBook and I decided to extract the API Tip parts. I am glad I can offer these sketches to you. Enjoy podcast #1. --JaroslavTulach 19:50, 12 May 2009 (UTC)

Bernhard's Weblog - April 20, 2009 06:34 PM
First Experience With Grape

This blog summarizes my first experiences with groovy's Grab annotation.

As I have downloaded groovy 1.6.1, I have become aware of the Grab annotation.

Using Grab

I defined a simple groovy script which shall use apache's commons-lang abbreviate method from org.apache.commons.lang.StringUtils#abbreviate.

Thus I defined a script, like:


import org.apache.commons.lang.StringUtils

@Grab(group='commons-lang', module='commons-lang', version='2.4')

def strings = ['Hello', 'Groovy', 'AVeryLongWord!', 'A simple sentence']
strings.each { String aString ->
    println "$aString: ${StringUtils.abbreviate(aString)}"
}
        
Sadly this script, did not work, I experienced following exception stack trace:

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed,
...\groovy\Grab1_1.groovy: 1: unable to resolve class org.apache.commons.lang.StringUtils
 @ line 1, column 1.
   import org.apache.commons.lang.StringUtils
   ^

1 error
        

Probably I have not read the doumentation close enough, put defining a method after the @Grab annotation, the problem, disappeared.

Thus the script becomes now:


import org.apache.commons.lang.StringUtils

@Grab(group='commons-lang', module='commons-lang', version='2.4')

def abbreviate(String s) {
    StringUtils.abbreviate( s, 10 )
}

def strings = ['Hello', 'Groovy', 'AVeryLongWord!', 'A simple sentence']
strings.each { String aString ->
    println "$aString: ${abbreviate(aString)}"
}
        

Running this script the commons-lang jar is downloaded, and the script prints:


Hello: Hello
Groovy: Groovy
AVeryLongWord!: AVeryLo...
A simple sentence: A simpl...
        

Reusing Maven Repository

I really like the @Grab feature, as it saves me from downloading additional jars manually. As I was using maven already, maven has downloaded some jars already into my local repository at the ~/.m2/repository directory. So I wonder if it is possible to tell grapes to reuse these jars.

The solution I use today, is reusing the maven jars from my local repository, grapes copies these jars over to the local grapes repository at ~/groovy/grapes. Thus this solution just saves me some bandwith and time, as accessing my local maven repository is surly faster than reaching out to the offical maven repositories at ibiblio.

The grapes documentation states that you can define the ivy settings by specifying ~/.groovy/grapeConfig.xml. So I created this file, which is by the way the default setting used by grapes:


<ivysettings>
  <settings defaultResolver="downloadGrapes"/>
  <resolvers>
    <chain name="downloadGrapes">
      <filesystem name="cachedGrapes">
        <ivy pattern="${user.home}/.groovy/grapes/[organisation]/[module]/ivy-[revision].xml"/>
        <artifact pattern="${user.home}/.groovy/grapes/[organisation]/[module]/[type]s/[artifact]-[revision].[ext]"/>
      </filesystem>
      <!-- todo add 'endorsed groovy extensions' resolver here -->

      <ibiblio name="codehaus" root="http://repository.codehaus.org/" m2compatible="true"/>
      <ibiblio name="ibiblio" m2compatible="true"/>
      <ibiblio name="java.net2" root="http://download.java.net/maven/2/" m2compatible="true"/>
    </chain>
  </resolvers>
</ivysettings>
        

Now I wonder how to add my local maven repository, I defined an addtion ibiblio entry, defining as root my local maven repository, so the grapeConfig.xml became:


<ivysettings>
  <settings defaultResolver="downloadGrapes"/>
  <resolvers>
    <chain name="downloadGrapes">
      <filesystem name="cachedGrapes">
        <ivy pattern="${user.home}/.groovy/grapes/[organisation]/[module]/ivy-[revision].xml"/>
        <artifact pattern="${user.home}/.groovy/grapes/[organisation]/[module]/[type]s/[artifact]-[revision].[ext]"/>
      </filesystem>
      <!-- todo add 'endorsed groovy extensions' resolver here -->

      <ibiblio name="local" root="file:${user.home}/.m2/repository/" m2compatible="true"/>

      <ibiblio name="codehaus" root="http://repository.codehaus.org/" m2compatible="true"/>
      <ibiblio name="ibiblio" m2compatible="true"/>
      <ibiblio name="java.net2" root="http://download.java.net/maven/2/" m2compatible="true"/>
    </chain>
  </resolvers>
</ivysettings>
        

By adding my local maven repository I'm able to reuse my local maven repository. You can add your local maven proxy, too by adding an additional ibiblio entry in the ~/.groovy/grapeConfig.xml file.

Have fun!

Bernhard's Weblog - February 24, 2009 11:13 PM
First experiences with jasperreports, ireport, and barcode

This blog summarizes my first experienced with iReport-nb-3.1.2.

As a first example I have created a report for the XML result of webtest.

ireport-webtest screenshot

Next I have created a report for the Junit XML.

ireport-junit screenshot

As I become familiar with jasperreport, and iReport, I want to evaluate, if it is possible to print a barcode with jasper-report. As I have downloaded jasperreports-3.1.4, too, there are two barcode samples in the demo folder. I run them standalone, and I wanted to view them in the iReport tool.

Especially the barcode folder shows a nice sample. I open the BarcodeReport.jrxml in the iReport application, but there are some classloader problems, as there are some sample specific classes needed for this sample.

As iReport allows to defined extra jars in the Options|iReport dialog, I add two jars there.

The first jar is the barbecue-1.5-beta1.jar from the barcode/lib directory. The second jar - I have created from the barcode/build/component classes.

Next I restart iReport, and after the restart the additional jars are active, and I'm now able to view the barcodes as defined by the BarcodeReport.jrxml.

ireport-barcode screenshot

Have fun!

Bernhard's Weblog - January 27, 2009 11:08 PM
Using unit-testing code using Netbeans' Repository class

This blog is about unit-testing using netbeans Repository. I'm using the solution described below on Netbeans 6.5.

In my netbeans plugin-project I have code like


        Repository r = Repository.getDefault();
        FileSystem fs = r.getDefaultFileSystem();
        FileObject root = fs.getRoot();
        FileObject baseFolder = FileUtil.createFolder(root, "nb-xpath/data");
        final String foName = "history.xml";
        FileObject historyFileObject = baseFolder.getFileObject(foName);
...
        File file = FileUtil.toFile(historyFileObject);

When you try to unit-test this code, the file instance is null.

Thus I read UsingFileSystemsMasterfs, and I installed the masterfs in the UnitTestLibary. By selecting "UnitTestLibraries|Add UnitTest Dependency", selecting "Show Non-API Modules, and searching for "masterfs", and selecting the Module "Master Filesystem".

The nbproject/project.xml results :


...
            </module-dependencies>
            <test-dependencies>
                <test-type>
                    <name>unit</name>
                    <test-dependency>
                        <code-name-base>org.netbeans.modules.masterfs</code-name-base>
                        <compile-dependency/>
                    </test-dependency>
                </test-type>
            </test-dependencies>
            <public-packages/>
...

But this does not help! The file instance is still null!

After examing the Repsitory sources, I came to the conclusion that if there is no Repository registered in META-INF/services, the MemoryFileSystem is used. Thus I need a way to register some repository class.

Thanks to InitializationOfDefaultLookup, MockServices can help.

I wrote a simple Repository implementation, and register it as Repository implementation to use:

The Repository implemenation for my test-case:


    public static final class MyRepositoryIOTempDir extends Repository {

        private static final long serialVersionUID = 20090127L;

        public MyRepositoryIOTempDir() {
            this(new LocalFileSystem());
        }

        private MyRepositoryIOTempDir(LocalFileSystem lfs) {
            super(lfs);
            // make the java.io.tmpdir the root of this lfs
            final String tmpDir = System.getProperty("java.io.tmpdir");
            assertNotNull(tmpDir);
            File rootFile = new File(tmpDir);
            assertTrue(rootFile != null);
            assertTrue(rootFile.canRead());
            assertTrue(rootFile.canWrite());
            assertTrue(rootFile.isDirectory());
            try {
                lfs.setRootDirectory(rootFile);
            } catch (Exception ex) {
                AssertionError ae = new AssertionError("Cannot set root directory");
                ae.initCause(ex);
                throw ae;
            }
        }
    }

My test-case setUp registers this class like:


    @Before
    public void setUp() {
        MockServices.setServices(MyRepositoryIOTempDir.class);
        // assert that for lookup(Repository.class) MyRepositoryIOTempDir is returned
        final Repository repositoryInstance = Lookup.getDefault().lookup(Repository.class);
        assertTrue(repositoryInstance instanceof MyRepositoryIOTempDir);
    }

Now my tests can run the above code, and the file instance is not null!

Now, that I removed the Master Filesystem dependency from the Unit Test Libraries, my test-cases still work, so it seems to me that when you use File instances retrieved via Repository, you don't need the masterfs test dependency, so far.

Have fun!

Practical API Design - December 12, 2008 09:06 AM
2009: The Year of Annotations

As I noted recently, I see the year 2009 as the year of annotations. The NetBeans project is about to rely on them more heavily. Finally! We've been waiting for that for ages, but finally we can compile with JDK 1.6 JavaC and we can use compile time annotation processors. As a result we can replace our layer based registrations with annotations and benefit from compile type checking, code completion, from having the registrations in the same place as the code that is being registered, etc. Also we can offer our API users simple looking annotations and let associated annotation processors do more advanced and more effective processing. As a result the developers have simple API to deal with, while actual registration hidden behind can be as effective as possible, even at the cost of complexity, but without compromises to reliability (as the complexity is kept in the processing infrastructure, not exposed to API users).

The other project related to annotations that we are likely to incorporate during 2009 is our extended use of Annotations for Software Defect Detection. This is heavily based on the JSR 305, yet until it is stable we do not want to expose such unstable API to users of our stable APIs (more on that in Chapter 10, in section Beware of Using Other APIs). As such we are going to create our own annotations (still recognizable by FindBugs and co.). The hope is that our annotation will stay compatible even if the underlaying JSR 305 slightly changes. Please find our current patch and comment here or in the issue 137437.

Last project that deals with annotations is developed by our editor hints guru Jan Lahoda - its aim is to bring complex refactoring to masses! How? Why? We have observed that using @Deprecated annotation is good hint to help your API users recognize that some part of your API is obsolete and shall no longer be used, however that in no way helps users of your API with converting their code to new, non-deprecated style. We have a solution: Use Code Transformation Annotations! Dear [API] writers, let's adopt these annotations and use them in your API! They are completely standalone (read more), lightweight and we are ready to incorporate feedback of everyone interested in the project. Indeed, my plan is to bring these easy to use and flexible refactorings to NetBeans soon, hopefully for version 7.0.

So these are my three annotation related projects. I find them quite exciting and I cannot wait to see them being used. Annotations are here to simplify life of API users and developers. As soon as we have them, we will have full right to call the year 2009 the year of annotations!

Listen to our podcast or download it.

Name (required):

Comment:

--JaroslavTulach 09:06, 12 December 2008 (UTC)

Bernhard's Weblog - October 28, 2008 11:15 PM
Xhtmlrenderer plus Groovy's SwingBuilder

Today I integrated groovy's SwingBuilder into xhtmlrenderer.

Xhtmlrenderer is a pure-Java library for rendering arbitrary well-formed XML (or XHTML) using CSS 2.1 for layout and formatting, output to Swing panels, PDF, and images.

I downloaded the release flyingsaucer-R7final, and integrated Groovy's SwingBuilder as object tag element. I used the ElementFactory, as outlined in the svg-demo delivered as xhtmlrenderer demo; now I can write groovy SwingBuilder scripts inside the XHTML page, like:


...
            </p>
            <h2>header.one.
            <div style="border: 1px solid red; margin: 15px; text-align: left;">
                <object type="text/groovy"><![CDATA[
import net.miginfocom.swing.MigLayout
import net.miginfocom.layout.LC
import net.miginfocom.layout.AC
import net.miginfocom.layout.CC

/**
 * A script expected to run in SwingBuilder#build
 *
 * It demonstrates defining the layout using LC, AC objects.
 */
final LC layC = new LC().fill().wrap();
final AC colC = new AC().align("right", 0).fill(1, 3).grow(100, 1, 3).align("right", 2).gap("15", 1);
final AC rowC = new AC().index(6).gap("15!").align("top").grow(100, 8);

final def migLayout = new MigLayout( layC, colC, rowC )
panel(layout: migLayout) {
    label("Last Name")
...

The resulting panel looks, like:

Well, that's just the first step, I still face some problems with layout the groovy panel, according its parent panel. You will notice the problem in the screenshot, as the grey area is smaller then the div's red border.
But maybe I'll find some time to solve this, too.


Have fun!

Bernhard's Weblog - October 05, 2008 03:00 AM
Webapplications using shared classloader

<p> The last week I was trying share a classloader among different web applications. </p> <p> So, first a short description of the problem described in this blog. <br> </p> <p><br> </p> <p>In the near future I will have to deal with a bunch of similar web-applications. The web-application may be grails applications, they may be appfuse-light web applications. So I assume that about ten web-applications shall be get deployed, on an application server, like oc4j (10.1.3), and jboss 4.2.2. <br> </p> <p><br> </p> <p> One simple option is to deploy each web application with the full range for needed jars. <br> </p> <p>For a very simple grails application that's about 17 MB. The same application without all the jars shrinks down to 254 KB. <br> </p> <p>For a simple appfuse-light web application the numbers are 15 MB, and 241 KB without the WEB-INF/lib jars. </p> <p><br> </p> <p>Thus I was trying to find a way to deploy the reduced-size web applications, instead of the full-blown web applications. <br> </p> <p>Beside deploying smaller-sized web applications, shall be faster, I'm hoping that the class-loader memory-consumption of each application is smaller. </p> <p><br> </p> <p>For OC4J I successfully defined a shared-classloader, and when deploying the shrinked web application, I defined that this application shall use already defined shared library. <br> </p> <p>The shared classloader definition in conf<span style="font-family: Courier New;">/server.</span>xml<span style="font-family: Courier New;"> </span>for grails-1.0.3 looks like this: </p> <pre><code> &lt;shared-library name="grails" version="1.0.3"&gt;<br> &lt;code-source path="ant-launcher.jar"/&gt;<br> &lt;code-source path="ant.jar"/&gt;<br> &lt;code-source path="antlr-2.7.6.jar"/&gt;<br> &lt;code-source path="cglib-nodep-2.1_3.jar"/&gt;<br> &lt;code-source path="commons-beanutils-1.7.0.jar"/&gt;<br> &lt;code-source path="commons-cli-1.0.jar"/&gt;<br> &lt;code-source path="commons-collections-3.2.jar"/&gt;<br> &lt;code-source path="commons-dbcp-1.2.1.jar"/&gt;<br> &lt;code-source path="commons-fileupload-1.1.1.jar"/&gt;<br> &lt;code-source path="commons-io-1.4.jar"/&gt;<br> &lt;code-source path="commons-lang-2.1.jar"/&gt;<br> &lt;code-source path="commons-logging-1.1.jar"/&gt;<br> &lt;code-source path="commons-pool-1.2.jar"/&gt;<br> &lt;code-source path="commons-validator-1.3.0.jar"/&gt;<br> &lt;code-source path="dom4j-1.6.1.jar"/&gt;<br> &lt;code-source path="ehcache-1.3.0.jar"/&gt;<br> &lt;code-source path="ejb3-persistence.jar"/&gt;<br> &lt;code-source path="grails-cli-1.0.3.jar"/&gt;<br> &lt;code-source path="grails-core-1.0.3.jar"/&gt;<br> &lt;code-source path="grails-crud-1.0.3.jar"/&gt;<br> &lt;code-source path="grails-gorm-1.0.3.jar"/&gt;<br> &lt;code-source path="grails-spring-1.0.3.jar"/&gt;<br> &lt;code-source path="grails-test-1.0.3.jar"/&gt;<br> &lt;code-source path="grails-web-1.0.3.jar"/&gt;<br> &lt;code-source path="grails-webflow-1.0.3.jar"/&gt;<br> &lt;code-source path="groovy-all-1.5.6.jar"/&gt;<br> &lt;code-source path="hibernate-annotations.jar"/&gt;<br> &lt;code-source path="hibernate-commons-annotations.jar"/&gt;<br> &lt;code-source path="hibernate3.jar"/&gt;<br> &lt;code-source path="hsqldb-1.8.0.5.jar"/&gt;<br> &lt;code-source path="jaxen-1.1-beta-11.jar"/&gt;<br> &lt;code-source path="jdbc2_0-stdext.jar"/&gt;<br> &lt;code-source path="jstl-2.4.jar"/&gt;<br> &lt;code-source path="jta.jar"/&gt;<br> &lt;code-source path="junit-3.8.2.jar"/&gt;<br> &lt;code-source path="log4j-1.2.15.jar"/&gt;<br> &lt;code-source path="ognl-2.6.9.jar"/&gt;<br> &lt;code-source path="oro-2.0.8.jar"/&gt;<br> &lt;code-source path="oscache-2.4.1.jar"/&gt;<br> &lt;code-source path="sitemesh-2.3.jar"/&gt;<br> &lt;code-source path="spring-2.5.4.jar"/&gt;<br> &lt;code-source path="spring-binding-2.0-m1.jar"/&gt;<br> &lt;code-source path="spring-test.jar"/&gt;<br> &lt;code-source path="spring-webflow-2.0-m1.jar"/&gt;<br> &lt;code-source path="spring-webmvc.jar"/&gt;<br> &lt;code-source path="standard-2.4.jar"/&gt;<br> &lt;code-source path="xercesImpl.jar"/&gt;<br> &lt;code-source path="xpp3_min-1.1.3.4.O.jar"/&gt;<br> &lt;code-source path="xstream-1.2.1.jar"/&gt;<br> &lt;/shared-library&gt;<br></code></pre> <p>For JBoss I deployed the grails applications inside a sar application. First I defined in the deployment directory a directory grails-1.0.3.sar. Inside this directory I created the file META-INF/jboss-service.xml, like:</p> <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br>&lt;!--<br> JBoss Grails 1.0.3<br> <br> $Id: jboss-service.xml 63100 2007-05-16 18:02:32Z bdecoste $<br>--&gt;<br>&lt;server&gt;<br> &lt;loader-repository&gt;<br> org.grails:archive=grails-1.0.3.sar<br> &lt;loader-repository-config&gt;java2ParentDelegation=false&lt;/loader-repository-config&gt;<br> &lt;/loader-repository&gt;<br>&lt;/server&gt;<br><br></code></pre> <p> Next I copied all the grails jars into the directory grails-1.0.3.sar. Moreover I created a directory named more-apps. I deployed the grails applications without the grail-1.0.3 distributed jars in the directory more-apps. </p> <p>Summing up the JBoss directory structure is </p><pre><code> ----grails-1.0.3.sar | ... more grails-1.0.3 jars | ejb3-persistence.jar | grails-cli-1.0.3.jar | grails-core-1.0.3.jar | grails-crud-1.0.3.jar | ... more grails-1.0.3 jars +---META-INF | jboss-service.xml \---more-apps grails-app-1.war ... more grails web applications </code></pre> <p> Both shared jar solutions for oc4j, and jboss worked for the grails-applications so far. <br></p><p><br></p><p>I'm not quite sure, if removing the jars from the the web applications, and creating some shared class loader does really improve either the memory-consumption, or the redeployment speed of the web applications. Do you have any similar ideas, or experiences, hosting a high number of web applications using the same jars? </p> <p><br></p><p>Have fun!</p>

Bernhard's Weblog - October 04, 2008 09:52 PM
Grails Deployment Issues

I experienced an interesting problem with a grails-application.

The operating team noticed me that the grails-web application, is not deployed, after a restart of the tomcat application server, and the db-server.
After inquiring the details about the restart sequence I came to the conclusion that following scenario happened:

  1. The machine hosting tomcat, and the db was rebooted
  2. The tomcat application server was restarted
  3. The grails-application tried to restart, but failed as the db was not up and running, yet
  4. The db was restarted

As the db was started after tomcat the grails was not started successfully inside of tomcat.

The operating team launched the tomcat-manager, and restarted the grails-application manually, and voila the grails-application started successfully.

Now I tried to find a solution that the operating team does not have to restart the grails-application manually.

This leads me to the question what db-accesses are performed by a grails-application, when the grails-application is started.

I come to the following two db-accesses:
  1. If now hibernate-dialect is specified explicitly, grails looks up the jdbc meta-data to find the database, to set the hibernate dialect
  2. Regardless of the hibernate dialect, grails accesses the jdbc meta-data again to set the lob-handler

Now if the grail-application shall succeed even if no db is available, you have to avoid these two db-access, as they surely fails if no db is available, yet.

You can avoid the first db-access by specifying the hibernate dialect, explicitly in the grails-app/conf/DataSource.groovy, like:
dataSource {
    pooled = true
    driverClassName = "org.hsqldb.jdbcDriver"
    username = "sa"
    password = ""

   dialect = 'org.hibernate.dialect.HSQLDialect'
}

The second db-access is hard-coded into grails org.codehaus.groovy.grails.orm.hibernate.support.SpringLobHandlerDetectorFactoryBean. To avoid this db-access you have to replace this class by your own class, and configure it as spring-bean in grails-app/conf/resource.xml, or grails-app/conf/resource.groovy.

I wrote a simple preconfigurable MySpringLobHandlerDetectorFactoryBean :

package org.mycompany.orm.hibernate.support;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.support.lob.DefaultLobHandler;
import org.springframework.jdbc.support.lob.LobHandler;
import org.springframework.jdbc.support.lob.OracleLobHandler;

/**
 * A simple LobHandler detector which does not access the dataSource for
 * detecting the appropriate LobHandler.
 * <p>
 * You must set the dbname explicitly, this has the advantage that no
 * db-access is needed at startup time. Hence the application starts even if
 * the database is not available at startup-time.
 * <p>
 * You this class by configuring a spring bean instance having the
 * id <code>lobHandlerDetector</code> in the grails spring configuration
 * <code>conf/spring/resources.xml</code>, like:
 * <code><pre>
 * <bean id="lobHandlerDetector" class="org.mycompany.orm.hibernate.support;.orm.hibernate.support.MySpringLobHandlerDetectorFactoryBean">
 * <property name="databaseProductName" value="Oracle"/>
 * </bean>
 * </pre></code>
 * @author HuberB1
 */
public class MySpringLobHandlerDetectorFactoryBean implements FactoryBean, InitializingBean {

    private final static Log log = LogFactory.getLog(MySpringLobHandlerDetectorFactoryBean.class);
    private static final String ORACLE_DB_NAME = "Oracle";
    private LobHandler lobHandler;
    private String databaseProductName;

    public void setDatabaseProductName(String databaseProductName) {
        this.databaseProductName = databaseProductName;
    }

    public Object getObject() throws Exception {
        return this.lobHandler;
    }

    public Class getObjectType() {
        return LobHandler.class;
    }

    public boolean isSingleton() {
        return true;
    }

    public void afterPropertiesSet() throws Exception {
        if (this.databaseProductName == null) {
            throw new IllegalStateException("DatabaseProductName is not set!");
        }

        final String dbName = this.databaseProductName;
        log.info("Using dbName " + dbName);

        if (ORACLE_DB_NAME.equals(dbName)) {
            this.lobHandler = new OracleLobHandler();
        } else {
            this.lobHandler = new DefaultLobHandler();
        }

    }
}

I added a bean configuration for an Oracle DB in conf/spring/resourcex.xml:

<bean id="lobHandlerDetector" class="org.mycompany.orm.hibernate.support;.orm.hibernate.support.MySpringLobHandlerDetectorFactoryBean">
<!--property name="databaseProductName" value="Other"/-->
<property name="databaseProductName" value="Oracle"/>
</bean>

Now with this simple MySpringLobHandlerDetectorFactoryBean, and specifying the hibernate dialect explicitly. The grails-application starts successfully even if no db is available. Of course the user will not be able to view any db-content, as long as the db is not available.

But the operating team does not have to fiddle around with any restart-sequence, and they don't have to restart the grails-application manually, neither.

Have fun!

Bernhard's Weblog - October 04, 2008 07:33 PM
EJB3-SpringBeanAutowiringInterceptor

<p> This blog is about using <code>org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor</code>. The spring 2.5.4 documentation states that this interceptor can be used for injecting spring-beans into ejb3 instances. </p> <p> My environment setup is: </p> <ul> <li>JVM 1.5 </li> <li>JBoss 4.2.2.GA </li> <li>Springframework 2.5.4 </li> </ul> <p> My first attempt was not very successful as I experienced some wired ClassLoader exceptions. I analysed the problem and came to the conclusion that the problem is that spring uses the thread context class loader by default. </p> <p> I must admit that I was not trying to inject the spring-beans into a simple stateless ejb, but into an mdb, triggered by the quartz resource adapter. The stacktrace goes like this: </p> <pre><code> 2008-05-20 17:40:20,423 ERROR [DefaultQuartzScheduler_Worker-6] org.quartz.core.JobRunShell : Job default.job.0.1211297867763 threw an unhandled Exception: java.lang.RuntimeException: org.springframework.beans.factory.access.BootstrapException: Unable to return specified BeanFactory instance: factory key [null], from group with resource name [classpath*:beanRefContext.xml]; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.springframework.beans.factory.BeanFactory] is defined: expected single bean but found 0 at org.jboss.ejb3.interceptor.LifecycleInterceptorHandler.postConstruct(LifecycleInterceptorHandler.java:113) at org.jboss.ejb3.EJBContainer.invokePostConstruct(EJBContainer.java:619) at org.jboss.ejb3.AbstractPool.create(AbstractPool.java:131) at org.jboss.ejb3.StrictMaxPool.get(StrictMaxPool.java:141) at org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:54) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101) at org.jboss.ejb3.mdb.MessagingContainer.localInvoke(MessagingContainer.java:249) at org.jboss.ejb3.mdb.inflow.MessageInflowLocalProxy.delivery(MessageInflowLocalProxy.java:268) at org.jboss.ejb3.mdb.inflow.MessageInflowLocalProxy.invoke(MessageInflowLocalProxy.java:138) at $Proxy84.execute(Unknown Source) at org.jboss.resource.adapter.quartz.inflow.QuartzJob.execute(QuartzJob.java:57) at org.quartz.core.JobRunShell.run(JobRunShell.java:203) at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:520) Caused by: org.springframework.beans.factory.access.BootstrapException: Unable to return specified BeanFactory instance: factory key [null], from group with resource name [classpath*:beanRefContext.xml]; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.springframework.beans.factory.BeanFactory] is defined: expected single bean but found 0 at org.springframework.beans.factory.access.SingletonBeanFactoryLocator.useBeanFactory(SingletonBeanFactoryLocator.java:410) at org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.getBeanFactoryReference(SpringBeanAutowiringInterceptor.java:139) at org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.getBeanFactory(SpringBeanAutowiringInterceptor.java:120) at org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.autowireBean(SpringBeanAutowiringInterceptor.java:100) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at org.jboss.ejb3.interceptor.LifecycleInvocationContextImpl.proceed(LifecycleInvocationContextImpl.java:131) at org.jboss.ejb3.interceptor.LifecycleInterceptorHandler.postConstruct(LifecycleInterceptorHandler.java:109) ... 12 more Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.springframework.beans.factory.BeanFactory] is defined: expected single bean but found 0 at org.springframework.beans.factory.BeanFactoryUtils.beanOfType(BeanFactoryUtils.java:379) at org.springframework.beans.factory.access.SingletonBeanFactoryLocator.useBeanFactory(SingletonBeanFactoryLocator.java:400) ... 21 more 2008-05-20 17:40:20,543 ERROR [DefaultQuartzScheduler_Worker-6] org.quartz.core.ErrorLogger : Job (default.job.0.1211297867763 threw an exception. org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: java.lang.RuntimeException: org.springframework.beans.factory.access.BootstrapException: Unable to return specified BeanFactory instance: factory key [null], from group with resource name [classpath*:beanRefContext.xml]; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.springframework.beans.factory.BeanFactory] is defined: expected single bean but found 0] at org.quartz.core.JobRunShell.run(JobRunShell.java:214) at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:520) * Nested Exception (Underlying Cause) --------------- java.lang.RuntimeException: org.springframework.beans.factory.access.BootstrapException: Unable to return specified BeanFactory instance: factory key [null], from group with resource name [classpath*:beanRefContext.xml]; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.springframework.beans.factory.BeanFactory] is defined: expected single bean but found 0 at org.jboss.ejb3.interceptor.LifecycleInterceptorHandler.postConstruct(LifecycleInterceptorHandler.java:113) at org.jboss.ejb3.EJBContainer.invokePostConstruct(EJBContainer.java:619) at org.jboss.ejb3.AbstractPool.create(AbstractPool.java:131) at org.jboss.ejb3.StrictMaxPool.get(StrictMaxPool.java:141) at org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:54) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101) at org.jboss.ejb3.mdb.MessagingContainer.localInvoke(MessagingContainer.java:249) at org.jboss.ejb3.mdb.inflow.MessageInflowLocalProxy.delivery(MessageInflowLocalProxy.java:268) at org.jboss.ejb3.mdb.inflow.MessageInflowLocalProxy.invoke(MessageInflowLocalProxy.java:138) at $Proxy84.execute(Unknown Source) at org.jboss.resource.adapter.quartz.inflow.QuartzJob.execute(QuartzJob.java:57) at org.quartz.core.JobRunShell.run(JobRunShell.java:203) at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:520) Caused by: org.springframework.beans.factory.access.BootstrapException: Unable to return specified BeanFactory instance: factory key [null], from group with resource name [classpath*:beanRefContext.xml]; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.springframework.beans.factory.BeanFactory] is defined: expected single bean but found 0 at org.springframework.beans.factory.access.SingletonBeanFactoryLocator.useBeanFactory(SingletonBeanFactoryLocator.java:410) at org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.getBeanFactoryReference(SpringBeanAutowiringInterceptor.java:139) at org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.getBeanFactory(SpringBeanAutowiringInterceptor.java:120) at org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.autowireBean(SpringBeanAutowiringInterceptor.java:100) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at org.jboss.ejb3.interceptor.LifecycleInvocationContextImpl.proceed(LifecycleInvocationContextImpl.java:131) at org.jboss.ejb3.interceptor.LifecycleInterceptorHandler.postConstruct(LifecycleInterceptorHandler.java:109) ... 12 more Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.springframework.beans.factory.BeanFactory] is defined: expected single bean but found 0 at org.springframework.beans.factory.BeanFactoryUtils.beanOfType(BeanFactoryUtils.java:379) at org.springframework.beans.factory.access.SingletonBeanFactoryLocator.useBeanFactory(SingletonBeanFactoryLocator.java:400) ... 21 more </code></pre> The quartz mdb is simply: <pre><code> ... @Interceptors(SpringBeanAutowiringInterceptor.class) public class MyQuartzJobMdb implements Job { protected static final long serialVersionUID = 20080515L; private static final Log log = LogFactory.getLog(Mc2GatherQuartzJobMdb.class); // @Autowired private transient GatherServiceIfc gatherService; ... </code></pre> <p> Note the <code>GatherServiceIfc gatherService</code>, that's the spring-bean which shall be injected. </p> <p> Strangely the SpringBeanAutowiringInterceptor works fine for a stateless EJB. In other words autowiring <code>GatherServiceIfc gatherService</code> in a stateless EJB works fine. </p> <p> If you examine the stack trace carefully, you will notice that the current thread is <code>[DefaultQuartzScheduler_Worker-6]</code>. As spring is using the current thread context loader, and the quartz thread does not know anything about the springframework classes, I thought about extending the <code>SpringBeanAutowiringInterceptor</code> the application classloader. Thus I extended the <code>SpringBeanAutowiringInterceptor</code> to </p> <pre><code> ... public class MySpringBeanAutowiringInterceptor extends SpringBeanAutowiringInterceptor { /** * Determine the BeanFactoryLocator to obtain the BeanFactoryReference from. * </code><p>The default implementation exposes Spring's default<br> * {@link ContextSingletonBeanFactoryLocator}.<br> * @param target the target bean to autowire<br> * @return the BeanFactoryLocator to use (never <code>null</code>)<br> * @see org.springframework.context.access.ContextSingletonBeanFactoryLocator#getInstance()<br> */<br> @Override<br> protected BeanFactoryLocator getBeanFactoryLocator(Object target) {<br> return MyContextSingletonBeanFactoryLocator.getInstance();<br> }<br>}<br></p></pre> Moreover I defined the <code>MyContextSingletonBeanFactoryLocator</code> as copy-paste from <code>ContextSingletonBeanFactoryLocator</code>, but defining: <pre><code> public class MyContextSingletonBeanFactoryLocator extends SingletonBeanFactoryLocator { ... /** * Overrides the default method to create definition object as an ApplicationContext * instead of the default BeanFactory. This does not affect what can actually * be loaded by that definition. * </code><p>The default implementation simply builds a<br> * {@link org.springframework.context.support.ClassPathXmlApplicationContext}.<br> */<br> @Override<br> protected BeanFactory createDefinition(String resourceLocation, String factoryKey) {<br> //return new ClassPathXmlApplicationContext(new String[]{resourceLocation}, false);<br> final ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext(new String[]{resourceLocation}, false);<br> final ClassLoader classLoader = this.getClass().getClassLoader();<br> cpxac.setClassLoader(classLoader);<br> return cpxac;<br> }<br>...<br></p></pre> <p> And finally using <code>MySpringBeanAutowiringInterceptor</code> like: </p> <pre><code> ... @Interceptors(MySpringBeanAutowiringInterceptor.class) public class MyQuartzJobMdb implements Job { </code></pre> <p> Using <code>MySpringBeanAutowiringInterceptor</code> in the quartz-mdb works, the spring-bean is injected successfully, maybe you reuse this approach on different application servers, too. </p> <p>Have fun!</p> <br>

Bernhard's Weblog - April 22, 2008 09:36 PM
Extending groovy's SwingBuilder2

In my previous blog i have sketched some ideas for extending SwingBuilder. Today I'd like to introduce a small extension.

SwingBuilder offers already an items attribute for the combobox. Sadly this attribute is missing for the list node.

But it is not too complicate to extend SwingBuilder to make the items attribute available for the list node, too.

Fist create a new factory using the already existing groovy.swing.factory.ComboBoxFactory as starting template:


package org.huberb.groovy.swing.factory

import javax.swing.JList

/**
 * Create a JList, and handle the optional items attribute.
 * 
 * @author HuberB1
 */
public class ListFactory extends AbstractFactory {
    
    public Object newInstance(FactoryBuilderSupport builder, Object name, Object value, Map attributes) throws InstantiationException, IllegalAccessException {
        FactoryBuilderSupport.checkValueIsNull(value, name);
        //TODO expand to allow the value arg to be items
        Object items = attributes.remove('items');
        if (items instanceof Vector) {
            return new JList((Vector) items);
        } else if (items instanceof List) {
            List list = (List) items;
            return new JList(list.toArray());
        } else if (items instanceof Object[]) {
            return new JList((Object[]) items);
        } else {
            return new JList();
        }
    }
}

Next you have to register this factory, In fact you are overriding the original list registration.


import groovy.swing.SwingBuilder
def swing = new SwingBuilder()
swing.registerFactory( "list", new ListFactory() )

Now you can use swing for building lists like:


def panel = swing.panel() {
  scrollPane() {
    list( items: ['A', 'B','C'] )
  }
}

Have fun!

Bernhard's Weblog - April 13, 2008 09:19 PM
Extending groovy's SwingBuilder

Groovy's SwingBuilder builds swing user interfaces. It is simple, and has some nice extension points.

SwingBuilder provides all the swing's components, like JButton, JTextField, JSpinner, etc. So what's missing?

By the time I'm using SwingBuilder I have missed following features:

  • Easy integration of internationalized text
  • Easy linking JLabel using the labelFor method, and mnemonics

In the following sections I will describe each feature and sketch the implementation.

Internationalized Text

Using internationalized text in SwingBuilder you have to provide the internationalized text like:


            ResourceBundle rb = ResourceBundle.getBundle( "foo.bar.Bundle" )
            swingBuilder.panel() {
              button( text: rb.getString('someKey') )
              label( text: rb.getString('someLabelKey' )
              ...
        

Beside typing rb.getString over, and over again, it fails with a MissingResourceException if the specified key is not found.

The solution I have implemented so far, defines the attributes i15dText, and i15dTitle for specifying the message key, and a new closure-name i15dMessageSource for defining the resource bundle

Thus the above snippet changes to:


            ResourceBundle rb = ResourceBundle.getBundle( "foo.bar.Bundle" )
            swingBuilder.panel() {
              i15dMessageSource( resourceBundle: 'foo.bar.Bundle' )
              button( i15dText: 'someKey' )
              label( i15dText: 'someLabelKey' )
              ...
        

I think this is quite an improvment, regarding readability. Moreover the i15d* attribute implementations return the key as-is if the key is not defined in the resource bundle.

The implementation of the i15dMessageSource is quite simple to store the specified resource bundle as builder variable named i15dMessageSource.

The i15d* attribute implementation peeks the resource bundle from the builder variable, and retrieves the message. In case of i15dText, the message is set as new text attribute; in case of i15dTitle, the message is stored as new title attribute.

Linking JLabel, and mnemonics

Swing's JLabel has a method setLabelFor(JComponent). The javadoc explains:

Set the component this is labelling. Can be null if this does not label a Component. If the displayedMnemonic property is set and the labelFor property is also set, the label will call the requestFocus method of the component specified by the labelFor property when the mnemonic is activated.

SwingBuilder makes it not that easy to use this feature

The snippet below defines the label first, and gives it an id, next id defines the textfield. Finally it links the label with the textfield, by using the defined ids.


            label( id: 'myLabel', text: 'XXX', displayedMnemonic: 'X' )
            textField( id: 'myTextField', columns: 15)
            myLabel.labelFor = myTextField
        

I think it would be easier to use a snippet like:


            labelForGroup {
                label( id: 'l0', i15dText: 'View1.firstName')
                textField( id: 'tf0' )
            }            
        

Alternativly if you use a layout manager like MigLayout you can even skip the explicit label definition at all:


            textField( i15dLabel: 'View.firstName' )
        

The labelForGroup creates a node-list as dummy node. All children nodes are added to this list. More the childern nodes are passed to the parent node of the labelForGroup node. The node-completion processing of the labelForGroup implementation links the first JLabel of the node-list with first non-JLabel of the node-list.

The implementation of the attributes i15dLabel, and label is registered via addAttributeDelegate. When the node is completed, the implementation creates a JLabel, setting the text, and it as label for the current node.

Finally the implementation of mnemonic processing is registered as addPostNodeCompletionDelegate. The implementation just strips off the '&' from the text of the created JLabel, or AbstractButton. Moreover it sets the mnemonic to the character following the stripped '&' character.

Summary

Reading the sources of groovy.swing.SwingBuilder, and groovy.util.FactoryBuilderSupport, have helped me to implement the above described features.

Extending groovy's SwingBuilder allows you to add new features, easily. My next exploring steps are creating a BeansBinding builder, and some simple templates generation for creating the view, and a binding from a given bean class.

Have fun!

Bernhard's Weblog - April 01, 2008 08:50 PM
NetBeans 6.1 Beta

Introduction

Netbeans 6.1 Beta is out, I have downloaded it, and I have given it a try. Especially the slow startup of the official Netbeans 6.0 disturbs me, so I was hoping this newer version starts more quickly.

Faaast

The startup time is now really faster. I really like that. Since I have installed Netbeans 6.1 Beta, I have never touched Netbeans 6.0 again. Now I'm really pleased.

Debugging Local Variables

Beside the startup speed I enjoyed another improvement. When I debug a program, now I can change variables of any wrapper classes, like Integer, Double, etc. In previous versions only the equivalent built-in types were modifiable, but not their wrapper-classes.

Thus now you are able to modify in the "Local Variable" window the vars like i1, d1, and l1.

Debug Window

In the version Netbeans 6.0 you have seen a dialog box, notifying "Can't assign primitive value to object".

You can check the Issue 125267. As you might notice I reported the issue, and it was fixed. Kudos to responsivness of the nb team member mentlicher!

I was very surprised that the netbeans team fixed this issue:

  • very fast
  • very uncomplicated

So if you have an issue, contact the mailing-lists, or enter an issue. It's really worth!

Groovy And Grails

I' m using grails in two projects successfully. So I'm very pleased about the new groovy and grails plugin. Although there are still some rough edges, I enjoy the syntax highlightning for the groovy, and gsp files.

You might want to give it a try, see the Groovy and Grails support in NetBeans and GlassFish, and News from Grailsland.

Fade Out

A cool feature is the fading-out of the status text in bottom left corner. I have rechecked that it is already available in the NetBeans 6.0, but I'd like to mention it here, too. Surley it's not very functional, but just cool!

Have fun!

Bernhard's Weblog - March 02, 2008 05:47 PM
Package Templates

Introduction

This weekend I have uploaded a new netbeans plugin, named package-templates .

The plugin offers some templates which generate a package hierarchy.

The idea is that you start creating your application package names, like org.{organization}.{application}, conventionally. Next you select one of the package templates, and the packages defined in the template are created.

Existing Naming conventions

The project directory structure is quite well defined. Starting from the project directory, Jakarta Apache, and Sun have conventions about the grand project layout, like put your built artifacts under the build directory, and store your source files in src, or src/java. Moreover maven guides you to using its project directory layout conventions, like put your sources under the src directory, and the built artifacts are put under the target directory.

Jumping to the java coding guidelines: The name of the packages, and of classes are defined in the Java Coding Guidelines. These kind of coding guidelines even talk about space versus tab. So the details how-to name classes, package, variables, are well defined, too.

But there is something missing...

Package templates

The package templates try to fill the gap between the project directory layout conventions, and the coding style guidelines, by offering a package hierarchy for some project types, like struts, spring-mvc, service-layer, etc.

I think it will be helpful if there is a convention how to name your packages across projects.

Technically, nearly trivial I hope that by using the package templates, the projects become recognizable, as the package names are reused across the projects.

I'd like to hear comments, about the idea, and suggestions about new project-type/package hierarchy conventions.

Have fun!

Bernhard's Weblog - February 25, 2008 12:03 AM
Wrapping Groovy Scripts As Executable Jar

Introduction

A co-worker asked me, what does CLOSE_WAIT in a netstat listing mean. There is a problem with a tomcat-instance showing a lot of CLOSE_WAIT socket states.

As I have not direct access to that tomcat-instance, I tried to reproduce this state locally. So I wrote I quick groovy script, which sets up a socket, and read only few bytes from the connection. The socket connections stays in the observer CLOSE_WAIT state, as observed in the problem environment.

Now, I want to run this groovy script not only locally, but distribute it to my colleague. As I don't want to force him to install groovy, I thought about compiling the groovy script, and generating an executable jar containing the groovy classes.

Wrapping Groovy Script

The script for compiling groovy, and creating an executable containing the groovy jar, the jakarta commons jars, and a manifest defining the script as main class is quite simple.

The script below uses CliBuilder for parsing command line options, and AntBuilder for groovy compiling, and jar generation.

GroovyWrapper.groovy


/*
 * Copyright 2002-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Wrap a script and groovy jars to an executable jar.
 */
def cli = new CliBuilder()
cli.h( longOpt: 'help', required: false, 'show usage information' )
cli.d( longOpt: 'destfile', argName: 'destfile', required: false, args: 1, 'jar destintation filename' )
cli.m( longOpt: 'mainclass', argName: 'mainclass', required: true, args: 1, 'fully qualified main class' )
cli.c( longOpt: 'groovyc', required: false, 'Run groovyc' )

//--------------------------------------------------------------------------
def opt = cli.parse(args)
if (!opt) { return }
if (opt.h) { 
  cli.usage(); 
  return 
}

def mainClass = opt.m
def scriptBase = mainClass.replace( '.', '/' )
def scriptFile = new File( scriptBase + '.groovy' )
if (!scriptFile.canRead()) {
   println "Cannot read script file: '${scriptFile}'"
   return 
}
def destFile = scriptBase + '.jar'
if (opt.d) {
  destFile = opt.d
}

//--------------------------------------------------------------------------
def ant = new AntBuilder()

if (opt.c) {
  ant.echo( "Compiling ${scriptFile}" )
  org.codehaus.groovy.tools.FileSystemCompiler.main( [ scriptFile ] as String[] )
}

def GROOVY_HOME = new File( System.getenv('GROOVY_HOME') )
if (!GROOVY_HOME.canRead()) {
  ant.echo( "Missing environment variable GROOVY_HOME: '${GROOVY_HOME}'" )
  return
}

// Build the executable jar, defining the script as main-class
ant.jar( destfile: destFile, compress: true ) {
  fileset( dir: '.', includes: scriptBase + '*.class' )

  zipgroupfileset( dir: GROOVY_HOME, includes: 'embeddable/groovy-all-*.jar' )
  zipgroupfileset( dir: GROOVY_HOME, includes: 'lib/commons*.jar' )
  // add more jars, depending on the script dependencies

  manifest {
    attribute( name: 'Main-Class', value: mainClass )
  }
}

ant.echo( "Run script using: \'java -jar ${destFile} ...\'" )

Using the script GroovyWrapper is simple, assuming you have a script HelloWorld.groovy. Then wrapping this script to HelloWorld.jar, use:


groovy GroovyWrapper -m HelloWorld -c

Having a jar named HelloWorld.jar, allows you to run the script HelloWorld, now simple as:


java -jar HelloWorld.jar

Have fun!

beaver's Weblog - February 04, 2008 06:10 PM
NUGM - Vortrag "Leichtgewichtige Java EE 5/6 Architekturen"

Letzte Woche hielt Adam Bien bei der NUGM einen sehr interessanten Vortrag über JAVA EE 5. Dieser fand in den Räumen der Firma "Genomatix" statt, wo sich mehr als 50 Leute einfanden.

Der aus der Nähe von München kommendene Redner outete sich als begeisterter NetBeans - User. Obendrein ist GlassFish seine bevorzugte Deployumgebung. Die browserbasierte Administratoroberfläche, die Möglichkeit auf der DOS - Ebene den Applikationsserver administieren zu können und das einfache Überwachen des Applikationsservers seien Pluspunkte, die bei anderen Applikationsserver nicht so zu finden seien.

Sein 3 - stündiger Vortrag befaßte sich mit fast allen JEE 5 - Themen. Angefangen mit J2EE über die Neuerungen, die die JEE 5 - Spezifikation mit sich bringt. Von den EJB 3 ging es zur JAVA Persistence Api ( JPA ). Hier gab er den Rat, JPA zu verwenden. Nur wenn das Projekt spezielle Anforderungen hätten, die JPA 1.0 nicht abdecken kann, ist es ratsam Hibernate oder TopLink Essentials zu verwenden. Auch Dependency Injection und Interceptoren wurden theoretisch angesprochen und wie bei den Themen davor mit Beispielen praktisch gezeigt. Fast zum Schluß wurde noch auf Fluent Interface eingegangen. In diesem Zusammenhang stellte er sein "RunAndBike" Projekt vor, was als Beispiel für eine JEE 5 - Anwendung dienen soll.

Zwischendurch gab es Wortmeldungen und Fragen, die auch sehr spezielle JEE 5 - Themen betraffen. Natürlich kamen auch Fragen, die auf solch einer Veranstaltung nicht fehlen durften. Hier eine kleine Auswahl: Was ist das beste Framework ? Ist Spring nicht viel besser als JEE 5 ? Die Verwendung eines Frameworks ist in vielen Fällen überflüssig, denn man kann mit ein wenig Mühe den gleichen Effekt auch mit JEE 5 - Bordmittel erreichen.  

Mein Fazit: Es war ein interessanter Abend, der für mich viel Neues zu Tage förderte, von dem ich bis dato noch nichts gehört habe.

Das nächste NUGM - Treffen findet im 27.März statt. Dann wird Sven Reimers zum Thema "SQE, das Software Quality Environment for NetBeans" sprechen.

Bernhard's Weblog - February 04, 2008 01:58 PM
JBoss/Tomcat CGI

Today I had the task to install a CGI-enabled web application which was installed on a Apache web server on JBoss 4.2.2. I took me some hours to get it right. Finally I manged it:

In short:

  • Create a directory for your application in JBoss' server instance deploy, like my-cgibin.war.
  • Create a my-cgibin.war/WEB-INF/web.xml declaring the cgi servlet, and the cgi servlet mapping, mapping *.cgi to the cgi servlet
  • Create a my-cgibin.war/WEB-INF/web.xml/context.xml allowing to use the cgi servlet

Using the above configuration all files like my-first.cgi are handled by the cgi servlet.

The WEB-INF/web.xml looks like:


<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
>
<description>Discmon</description>
<display-name>discmon</display-name>
<servlet>
<servlet-name>cgi</servlet-name>
<servlet-class>org.apache.catalina.servlets.CGIServlet</servlet-class>
<init-param>
<param-name>executable
<param-value>/usr/bin/perl</param-value>
</init-param>
<init-param>
<param-name>passShellEnvironment</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>6</param-value>
</init-param>
<init-param>
<param-name>cgiPathPrefix</param-name>
<!--param-value>WEB-INF/cgi</param-value-->
<param-value></param-value>
</init-param>
<load-on-startup>5</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>cgi</servlet-name>
<url-pattern>*.cgi</url-pattern>
</servlet-mapping>
</web-app>

The WEB-INF/context.xml looks like:


<Context debug="1" privileged="true">
</Context>

The servlet org.apache.catalina.servlets.CGIServlet is already part of deploy/jboss-web.deployer/jbossweb.jar, thus an extra cgiservlet.jar is not necessary, anymore.

As org.apache.catalina.servlets.CGIServlet is part of jbossweb.jar, the context.xml must define the privileged="true" attribute. If you don't define this attribute you will see some security exception.

Have fun!

beaver's Weblog - December 10, 2007 06:10 PM
NetBeans Day 2007 in Frankfurt

Letzte Woche machte der Netbeans - Tross in Frankfurt am Main Station. Die Organisatoren hatten extra einen großen Saal dafür vorgesehen in Erwartung zahlreicher Besucher und diese erfüllten sich auch. An die 150 Personen lauschten den Ausführungen der NetBeans - Leuten. Dass der Raum "Illusion" hieß, war sicherlich nur ein Zufall. Oder steckten da Anhänger des Sonnenverfinsterers dahinter und keiner hat es gemerkt ?

Bei der Registrierung bekam jeder eine NetBeans - CD in die Hand gedrückt. Was damit gemacht werden soll, ist ja wohl klar:


Please leave your NetBeans - CD unattended, your workmate would appreciate it.


Die CD enthielt zwar nur die Version 5.5.1, aber die aktuelle Version 6.0 ist auch über netbeans.org bestellbar.

Ein bißchen komisch war, dass zum Empfang keine Getränke gereicht wurden sind und so war ich genötigt die Kongresshalle wieder zu verlassen, um meine Koffeinsucht zu befriedigen.

Um 13 Uhr wurde der NetBeans Day von Martin Balin eröffnet. Danach stellte Roman Strobl den Teilnehmer die Neuerungen der Version 6 vor, die zufälligerweise am selben Tag das Betastadium verlassen hatte. Neu ist zum Beispiel, dass jedes Auftreten einer Variable im Editor farblich hinterlegt wird. Die Codevervollständigung für Annotationen ist auch hinzugekommen. Die "history" ermöglicht es einen, die gemachten Änderungen am Code nachvollziehen zu können. Es wird genau Bericht geführt, welche Änderungen am Code vorgenommen wurden sind und diese können gegebenenfalls wieder rückgängig gemacht werden.

Danach wurde CodeBeamer vorgestellt, welches Anfang des nächsten Jahres auf JavaForge gehostet wird. Dabei handelt es sich um ein Softwaresystem zur Versionsverwaltung von Dateien und angeschlossenem Wiki.

Der nächste Vortrag beschäftigte sich mit den integrierten Profiling - Werkzeugen. Anhand des Open Source Projekts "HTTPUnit" zeigte uns Jaroslav Bachorik, wie Speicherlecks und zeitintensive Prozeduren in größeren Projekten gefunden werden können. Dabei muß nicht das gesamte Projekt untersucht werden, sondern man kann sich bestimmte Bereiche im Code markieren, die dann genauer unter der Lupe genommen werden sollen.

Das nächste Vortrag von Roman Strobl befaßte sich mit "Rich Internet Applications". Hier wurde die neue Skriptsprache JavaFX vorgestellt. Anhand einer Anwendung, die Wettervorhersagen für verschiedene Orten anzeigte, wurde demonstriert, was JavaFX zu leisten vermag. Das JavaFX Script Plugin für NetBeans IDE 6.0 kann auf dieser Seite heruntergeladen werden. Auch die Hypethemen AJAX und JRuby durften natürlich nicht unerwähnt bleiben. Am Beispiel einer JMaki - Anwendung wurde gezeigt, wofür AJAX steht. Die Sortierreihenfolge einer Tabellenspalte der Beispielanwendung wurde verändert, ohne die Seite neu laden zu müssen. Das JMaki - Plugin gibt es hier. Natürlich wird auch Ruby on Rails unterstützt.

Die nächsten zwei Beträge kamen von deutschen Communitymitglieder. Sie befaßten sich ausschließlich mit der NetBeans - Plattform. So stellte Toni Epple seinen Visual Designer für Jasper-Berichte vor, der auf der NetBeans - Plattform aufbaut. Der zweite Community - Bericht kam von Sven Reimers. Er zeigt uns die Software "Software Quality Environment" ( SQE ). Es vereinigt verschiedene Programme wie "FindBugs" , "PMD", "CheckStyle" und "Lint4j" unter einem Dach. Diese haben alle das Ziel, die Softwarequalität von JAVA - Programmen zu verbessern. Überraschenderweise kamen viele Wortmeldungen und Fragen zum Thema "NetBeans RCP". Sie betraffen die Schwierigkeiten beim Erlernen der Netbeans - Plattform und wie wenig Material es zu diesem Thema gibt. So soll die Einarbeitung in diese Materie sehr schwierig sein. Bücher zu diesem Thema gibt es hier und hier.

Danach stellte Karol Harezlak das NetBeans Mobility Pack vor. Anhand einer kleinen Buchdatenbank wurden die Möglichkeiten der Mobility Edittion vorgestellt. Dies geschah nur mit Hilfe des "Visual Mobile" Designers, ohne selbst eine Zeile Code schreiben zu müssen. Ob das auch bei größeren Projekten funktioniert, sei dahingestellt.

Als Abschluss des NetBeans - Tages stellte Sang Shin jene NetBeans - Programme vor, die die Arbeit für die Erstellung einer service-orientierten Architektur erleichtern sollen.

Im Großen und Ganzen würde ich den NetBeans - Tag als gelungen bezeichnen. Vielleicht sieht man sich ja im nächsten Jahr wieder, um die neue NetBeans - Version 7 vorzustellen.

Bernhard's Weblog - November 15, 2007 09:19 AM
Logging Exceptions, Specifying logging filenames

A short blog about logging.

For whom, and for what do you write logging statements. I assume it is for

  • See what the application is doing
  • Understanding the state of the application in case of a problem

The primary audience reading the log statements are developers for reviewing the application.

Logging Exceptions

If you write a log statement in a catch exception block, do your self a favour, and don't write


...
catch (Exception ex) {
log.error( "Something weird has happened: '" + ex.getErrorMessage +"'")
}

This log statement just writes the error message of the exception. It does not write the name of the exception, and the stacktrace of the exception. If you are out of luck and the exception was created w/o a message you will get: Something weird has happened: ''.

Better write:


catch (Exception ex) {
  log.error( "Something weird has happened", ex );
}

Log4j is able to write a the name of the exception, the exception's error message, and stacktrace of the exception. These three information will help you tremendously in analyzing the problem.

In case you are using java util logging, use log.log( Level.ERROR, "Somethin weird has happened", ex );

Specifying log filename

I' m sure you know specifying the file name of the FileAppender in log4j, like:


log4j.appender.rollingDay.file=logs/my-application.log

The problem here is that the file name is a relative file. Thus if you start the application from - let's say - the root directory, the log file is written to /logs/my-application.log. I' m quit sure that this not what you wanted.

This situation happened to me, as tomcat was started on a UNIX machine from a start/stop script. You may try to fix this by using su - user-name ... but this will only change the current directory to the home-directory of the user 'user-name'.

Another solution would be to specify an absolute path in the log4j file definition like:


log4j.appender.rollingDay.file=/my-path-to-log-directory/logs/my-application.log

The drawback of this definition is, that you will have to adopt this for each deployment environment. If you have to support three deployment environments - development, test, and production - you have to adopt this definition three times.

Now log4j allows you to specify system-properties in the log4j definitions. If you are deploying your application using tomcat, there are at least following system-properties available: catalina.home catalina.base

Thus changing the definition to


log4j.appender.rollingDay.file=${catalina.base}/logs/sft-extended.log

You are defining the log file by an absolute path. That writes to the log directory of the catalina base instance.

Using the system-property user.home, the base path of the log file is the user's home directory.

If you are deploying you application on some other application server, there is no catalina.base system property, and you have to specify some other system-property.

A simple jsp page for showing all available system properties, try this jsp:


<html>
    <head>
        <title>System Properties</title>
        <style>
            body { padding: 4px; font-family: Tahoma, Arial, sans-serif; }
            table { border-collapse: collapse;  }
            th { border: 1px solid; }
            td { padding: 4px; border: 1px dotted; }
            tr:hover { background-color: #cccccc; }
        </style>
    </head>
    <body >
        <p>
            Table of available system properties:
        </p>
        <table >
            <thead>
                <tr><th>Name</th><th>Value</th>
            </thead>
            <tbody >
                <%
                java.util.Properties props = System.getProperties();
                java.util.Map sortedProps = new java.util.TreeMap(props);
                
                for (java.util.Iterator i = sortedProps.entrySet().iterator(); i.hasNext(); ) {
                    java.util.Map.Entry me = (java.util.Map.Entry)i.next();
                    String name = (String)me.getKey();
                    String value = (String)me.getValue();
                %>
                <tr>
                    <td ><%=name%></td>
                    <td ><%= value%></td></tr>
                <%
                }
                %>
            </tbody>
        </table>        
    </body>
</html>

Have fun!

Bernhard's Weblog - October 16, 2007 09:00 AM
My top netbeans plugins

Today I'd like to present my day-to-day top plugins from the Netbeans' Plugin Portal.

Copy and Paste History Module

This plugin gives you access to previous paste/copy content.
I use it to paste the previous copied text into my source files.

Copy FQN

This plugin copies the full qualified name of class to the clipboard.
I use it when I setup configuration files which wants the FQN of a class. Thus when editing web.xml, layer.xml, struts configurations, spring configurations manually, I use this plugin.

Path Tools

This plugin provides a nice integration with the OS explorer, and allows you to copy the path of a file to the clipboard.
I use it when I need to switch between netbeans and the OS explorer, or when I need the full path of some project files.

PMD - for Netbeans

This plugin integrates the PMD tool into netbeans.
I use this to detect programming error patterns. Especially if I'm not 100% accustomed to some java sources this module gives my some hint of possible "programming" errors. While I'm developing new code, or fixing bugs, I run this plugin. The result of this plugin helps me to detect programming errors, early.

FindBugs(TM) - Plugin

This plugin integrates the Findbugs tool into netbeans.
I use this to detect programming error patterns. Especially if I'm not 100% accustomed to some java sources this module gives my some hint of possible "programming" errors. I use this plugin for the same reason as I'm using the PMD plugin - early detection of programming errors.

I'd like to hear what's your favorite plugins!

Have fun!

Bernhard's Weblog - October 08, 2007 03:05 PM
Depend target in Netbeans

Using Netbeans you can extend the build.xml. 

Pre-Compile

Targets like "-pre-compile", and "-pre-test-compile" are invoked before compiling the java sources, and before compiling the test sources.

One of my favourite -pre-compile targets is including the depend target. Being an ant optional task, it is described in the ant documentation as:

The depend task works by determining which classes are out of date with respect to their source and then removing the class files of any other classes which depend on the out-of-date classes.

Including it the depend task is quite simple, as noted in the snippet below:

<target name="-pre-compile">
<depend srcdir="${src.dir}"
destdir="${build.classes.dir}"
cache="${build.dir}/depend/java"
closure="yes"/>
</target>

Having defined this -pre-compile target, classes being out-of-date are removed from the build/classes directory.

I use the depend target for sun's javac up to version 1.5, later versions, or javac versions by other vendors than Sun may have a built-in dependcy checking, making this pre-compile target obsolete.

Moreover as I' m using Netbeans 6.0 the depend task is added automatically, so there is no need for this extra depend task in the -pre-compile task. See FaqCompileDependency, and issuezilla entry.

Have fun!

Bernhard's Weblog - October 08, 2007 07:00 AM
Lenient Dates

As I read about design patterns, and design oriented architecture, I have the feeling that some simple problems just have simple solutions.

It's not always finding patterns, sometimes it's just the about using API methods the right way. (Is this a a pattern, too :-) ?)

As I' m developing a project, I have the requirement to parse a date as string, and reject any bad date string which does not conform to the defined date format.

Seems simple you use java.text.SimpleDateFormat, and parse the date String, like:


SimpleDateFormat sdf = new SimpleDateFormat( "ddMMyyyy" );
try {
  Date theDate = sdf.parse( "01022002" );
} catch (ParseException pex) {
  // Handle the bad date...
}

That's it?

No, not exactly dates like "010280" are parsed without throwing an exception. But there is the lenient option, which makes parsing more restrictive. Thus let's enable the lenient option.


SimpleDateFormat sdf = new SimpleDateFormat( "ddMMyyyy" );
sdf.setLenient(true);
try {
  Date theDate = sdf.parse( "01022002" );
} catch (ParseException pex) {
  // Handle the bad date...
}

That's it?

No, not exactly dates like "01022002XX" are parsed without throwing an ParseException. But there is the method parse(String s, ParsePosition p ) which returns the position of the last parsed character. Thus the parsing becomes:


SimpleDateFormat sdf = new SimpleDateFormat( "ddMMyyyy" );
sdf.setLenient(true);
try { 
  ParsePositon parsePosition = new ParsePosition(0); Date theDate =
  sdf.parse( dateAsString, parsePosition ); 
  if (parsePosition.getErrorIndex() != -1 || 
    parsePosition.getIndex() != dateAsString.length()) { 

    // handle the bad date... 
  }
} catch (ParseException pex) { 
  // handle the bad date...
}

The final version is really restrictive accepting only dates in the format 'ddMMyyyy'.

Am I sure that now only correct dates are parsed, and any invalid date throws an ParseException?
Pretty sure, I' m using JUnit to test the various date strings, and the behavior of my code, and I have read the javadoc of SimpleDateFormat twice.

Have fun!

Bernhard's Weblog - October 05, 2007 08:51 PM
My Preferences

I'm writing a little web access log analyzer. The parsing, and reading is done by a Groovy script I found here: Processing Server Logs. The GUI is written in plain java, using the Swing.

One aspect was not that clear to me when I started: Where do I store the preferences, like selected files? How to store the user input?

Using java.until.Properties is a bit tedious, java.until.Preferences seems to be promising. As I read more about Preferences, I have found one issue which I dislike: Preferences are stored in the registry under windows.

Well, I'm developing under windows, and I'm feeling  uncomfortable changing the windows registry. I' d prefer writing to a file. The Preferences API is ready for new implementations. Thus I implemented a Preferences writing to some simple properties file.

Using Preferences makes it really easy to store preferences, like the last window position, and dimensions, the selected directory of the JFileChooser, and the selected files.

So summing up, as I write now the preferences to a file, and not to the windows registry, I'm very happy with the Preferences API.

Reading more about java.util.Preferences:

Have fun!

Bernhard's Weblog - October 01, 2007 08:00 AM
Why I like spring framework

In my current project I experienced some arguments using the spring framework.

At the start of the project the application server of the project's web application was jboss application server 4.2.

As the web application shall connect to a remote web service, I implemented the web service client using JAX-WS.

Another resource I have to connect to is an LDAP server.

Both resources I encapsulated using the DAO pattern.

The benefits of the spring framework come clear during the development phase.

The ldap server were not always available. So I implemented a dummy ldap dao returning a fixed number of domain objects. Thus I was able to test other parts of the application even when the ldap server were not available.

At the last week during the development phase the jboss server was replaced by an sun application server 8.2. Thus I have to replace the JAX-WS client code by an JAX-RPC code. Again I implemented a JAX-RPC dao and injected it, using simply a different spring bean definition.

During this project I was very satisfied with my decision of using spring, and sticking to DAO design pattern.

Both decision were right in order to support : 

  • a clean layered software architecture using the DAO pattern
  • a flexible system environment, using different ways to access ldap, and web services

May be using factories, and simple configuration values would be possible too, but I think the spring-way is more flexible, and better.

Have fun!

Bernhard's Weblog - September 29, 2007 09:09 PM
Jboss Installation Instances

In my current project I have to implement a web application on jboss.

Downloading and installing jboss application server is quite easy. Just unzip it and launch run.bat.

I'm wondering if there is a way to run a jboss instance for each development project.

Tomcat distinguishes between the CATALINA_HOME, and CATALINA_BASE. This makes it easy to install tomcat once, and reuse the tomcat installation in several projects.

I was wondering if this is possible for jboss, too. Thus installing jboss once, and reuse this installation with minor project specific changes in the various projects.

Browsing the jboss wiki there is a solution for this, and adopted it at little bit:

The following start script uses the jboss installation at C:/all_projects/programme/jboss-4.2.0.GA. The project specific configurations are located in the project directory C:/all_projects/projects/my-project-dir/jboss/default2


@echo off
setlocal
@rem =========================================================================
set JBOSS_HOME_DIR=C:/all_projects/programme/jboss-4.2.0.GA
set JBOSS_HOME_URL=file:/%JBOSS_HOME_DIR%
set SERVER_HOME_DIR=C:/all_projects/projects/my-project-dir/jboss/default2
set SERVER_HOME_URL=file:/%SERVER_HOME_DIR%
@rem =========================================================================
set OPTIONS=
set OPTIONS=%OPTIONS% -Djboss.server.home.dir=%SERVER_HOME_DIR%
set OPTIONS=%OPTIONS% -Djboss.server.home.url=%SERVER_HOME_URL%
set OPTIONS=%OPTIONS% -Djboss.server.config.url=%SERVER_HOME_URL%/conf
@rem set OPTIONS=%OPTIONS% -Djboss.server.lib.url=%SERVER_HOME_URL%/lib
set OPTIONS=%OPTIONS% -Djboss.server.lib.url=%JBOSS_HOME_URL%/server/default/lib
set OPTIONS=%OPTIONS% -Djboss.server.log.dir=%SERVER_HOME_DIR%\log
set OPTIONS=%OPTIONS% -Djboss.server.temp.dir=%SERVER_HOME_DIR%\temp
set OPTIONS=%OPTIONS% -Djboss.server.data.dir=%SERVER_HOME_DIR%\data
@rem set OPTIONS=%OPTIONS% -Dhttp.proxyHost=127.0.0.1
@rem set OPTIONS=%OPTIONS% -Dhttp.proxyPort=8090
@rem set OPTIONS=%OPTIONS% -Dhttp.nonProxyHosts=localhost
@rem =========================================================================
set JAVA_OPTS=%JAVA_OPTS% -Xrunjdwp:transport=dt_shmem,server=y,suspend=n,address=jboss
@rem =========================================================================
echo %OPTIONS%
%JBOSS_HOME_DIR%\bin\run.bat %OPTIONS% -c default2 -b 127.0.0.1 %*

The start script reuses the jboss installation server/default/lib. All other configurations uses the project local directories. Especially the conf directory is defined as locally at %SERVER_HOME_URL%/conf.

The directory layout of the project local instance is:


C:/all_projects/projects/my-project-dir/jboss/default2:
+---conf
+---data
+---deploy-apps
+---log
+---temp
\---work

If you watch closely you notice that there is no deploy directory. Well I have adopted the jboss configuration in default2/conf, using the jboss installation default/deploy directory.


...
<attribute name="URLs">
${jboss.home.url}/server/default/deploy/,
deploy-apps/,
file:/C:/all_projects/projects/my-project-dir/build/my-project.war
</attribute>

Moreover I use the deploy-apps directory for project specific deployments, and the last file: definitions deploys the project web application.

If you wonder how I detected that the property name jboss.home.url is the right name, take a look at log/boot.log. There is a list of all system properties defined by jboss. Here a listing of jboss system properties:

Property name Property value
jboss.bind.address 127.0.0.1
jboss.home.dir C:\all_projects\programme\jboss-4.2.0.GA
jboss.home.url file:/C:/all_projects/programme/jboss-4.2.0.GA/
jboss.lib.url file:/C:/all_projects/programme/jboss-4.2.0.GA/lib/
jboss.server.config.url file:/C:/all_projects/projects/my-project-dir/jboss/default2/conf/
jboss.server.data.dir: C:/all_projects/projects/my-project-dir/jboss\default2\data
jboss.server.home.dir: C:/all_projects/projects/my-project-dir/jboss\default2
jboss.server.home.url: file:/C:/all_projects/projects/my-project-dir/jboss/default2/
jboss.server.lib.url: file:/C:/all_projects/programme/jboss-4.2.0.GA/server/default/lib/
jboss.server.log.dir: C:/all_projects/projects/my-project-dir/jboss\default2\log
jboss.server.name: default2
jboss.server.temp.dir: C:/all_projects/projects/my-project-dir/jboss\default2\temp
jbossmx.loader.repository.class: org.jboss.mx.loading.UnifiedLoaderRepository3
jgroups.bind_addr: 127.0.0.1

I'm quite happy with this setup:

  • Install jboss application server once
  • Reuse the jboss installation for each development project

So instead of copying jboss into each development project directory, I reuse the jboss installation all over my development projects.

Note: I tried to use linked directories on windows, and that did not work, so I came up with this solution.

Have fun!

Bernhard's Weblog - September 26, 2007 09:33 AM
XSLT-Filter PML

The last days I had to work with PML. PML (ParnerMarkupLanguage) is an XML dialect from vodafone.

PartnerML is a proprietary device-independent XML format defined by Vodafone.
The advantage of authoring in PartnerML is that you do not need to worry about authoring in separate markup languages or formatting your content for presentation on different classes of mobile devices. Simply markup your content in PartnerML, and VF will handle all the presentation to make your content part of the Vodafone live! experience.

In order to view the pml content you need either 

  • A PML browser
  • An engine which translates PML to WML, and a WML enabled browser, or handset.

All these options are not very appealing in a development environment. Thus I created an XSLT servlet filter, and an xsl-stylesheet converting PML to HTML.

Well, the xslt-stylesheet is not production-ready, but that's okay for me, as the transforming to HTML is just intended for the development environment. Thus I was able to view my pml pages in my normal web browser.

If you like this idea, here is the XSLT:


<?xml version="1.0" encoding="UTF-8" ?>
<!--
Document : pml2html.xsl
Created on : 24. April 2006, 23:26
Author : HuberB1
Description:
Purpose of transformation follows.
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"/>
<xsl:output encoding="UTF-8"/>
<xsl:param name="contextPath" select="''"/>
<xsl:param name="hrefPrefix" select="'/pml2html/PmlServlet'"/>
<xsl:template match="/">
<html>
<head>
<title>pml2html</title>
<link rel="stylesheet" href="{$contextPath}/resources/style/pml2html.css" type="text/css"/>
</head>
<body>
<div class="header">
<a href="{$contextPath}/">PML</a>
</div>
<xsl:apply-templates/>
<hr size="1" />
<div class="pmlCode" >
<pre>
<xsl:apply-templates select="." mode="verbose"/>
</pre>
</div>
<div class="footer">
<a href="{$contextPath}/">PML</a>
</div>
</body>
<xsl:copy-of select="."/>
</html>
</xsl:template>
<xsl:template match="TIMER">
<div class="timer">
<a>
<xsl:attribute name="href"><xsl:value-of select="@href"/></xsl:attribute>
<xsl:attribute name="title">tenthsOfSecond: <xsl:value-of select="@tenthsOfSecond"/></xsl:attribute>
TIMER
</a>
</div>
</xsl:template>
<xsl:template match="CONTAINER[@type='list']">
<div class="container">
<xsl:attribute name="title">container : <xsl:value-of select="@type"/></xsl:attribute>
<ul>
<xsl:apply-templates mode="list"/>
</ul>
</div>
</xsl:template>
<xsl:template match="CONTAINER">
<div class="container">
<xsl:attribute name="title">container : <xsl:value-of select="@type"/></xsl:attribute>
<xsl:call-template name="color">
<xsl:with-param name="color" select="@color"/>
</xsl:call-template>
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="LINK" mode="list">
<li class="link">
<a>
<xsl:attribute name="href">
<xsl:call-template name="href">
<xsl:with-param name="href" select="@href"/>
</xsl:call-template>
</xsl:attribute>
<xsl:attribute name="title">
<xsl:value-of select="@href"/>
</xsl:attribute>
<xsl:apply-templates/>
</a>
</li>
</xsl:template>
<xsl:template match="LINK">
<div class="link">
<a>
<xsl:attribute name="href">
<xsl:call-template name="href">
<xsl:with-param name="href" select="@href"/>
</xsl:call-template>
</xsl:attribute>
<xsl:attribute name="title">
<xsl:value-of select="@href"/>
</xsl:attribute>
<xsl:apply-templates/>
</a>
</div>
</xsl:template>
<xsl:template match="TITLE">
<h2><xsl:apply-templates/></h2>
</xsl:template>
<xsl:template match="TEXT">
<span class="text">
<xsl:call-template name="color">
<xsl:with-param name="color" select="@color"/>
</xsl:call-template>
<xsl:apply-templates/>
</span>
</xsl:template>
<xsl:template match="IMAGE">
<span class="image"><img >
<xsl:attribute name="src"><xsl:value-of select="@href"/></xsl:attribute>
<xsl:attribute name="title">
href: <xsl:value-of select="@href"/>,
preview: <xsl:value-of select="@preview"/>,
purchase-label: <xsl:value-of select="@purchase-label"/>,
service-id: <xsl:value-of select="@serviceid"/>
</xsl:attribute>
</img></span>
</xsl:template>
<xsl:template match="p">
<p>
<xsl:call-template name="align">
<xsl:with-param name="align"><xsl:value-of select="@align"/></xsl:with-param>
</xsl:call-template>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="br">
<br/>
</xsl:template>
<xsl:template match="hr">
<hr/>
</xsl:template>
<xsl:template match="b">
<b><xsl:apply-templates/></b>
</xsl:template>
<xsl:template match="i">
<i><xsl:apply-templates/></i>
</xsl:template>
<xsl:template match="u">
<u><xsl:apply-templates/></u>
</xsl:template>
<xsl:template match="big">
<font size="+1"><xsl:apply-templates/></font>
</xsl:template>
<xsl:template match="small">
<font size="-1"><xsl:apply-templates/></font>
</xsl:template>
<xsl:template match="color">
<font color="{@value}"><xsl:apply-templates/></font>
</xsl:template>
<xsl:template match="li" mode="list">
<li><xsl:apply-templates/></li>
</xsl:template>
<xsl:template match="FORM">
<xsl:variable name="submitValue" select="@submit_text"/>
<form class="form" method="POST">
<xsl:attribute name="action"><xsl:value-of select="@href"/></xsl:attribute>
<xsl:attribute name="title"><xsl:value-of select="@href"/></xsl:attribute>
<xsl:apply-templates/>
<xsl:choose>
<xsl:when test="@submit_text">
<input type="submit" value="{$submitValue}"/>
</xsl:when>
<xsl:otherwise>
<input type="submit" value="Go"/>
</xsl:otherwise>
</xsl:choose>
</form>
</xsl:template>
<xsl:template match="FIELD">
<input>
<xsl:attribute name="type"><xsl:value-of select="@type"/></xsl:attribute>
<xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
<xsl:if test="@value">
<xsl:attribute name="value"><xsl:value-of select="@value"/></xsl:attribute>
</xsl:if>
<xsl:if test="@default">
<xsl:attribute name="value"><xsl:value-of select="@default"/></xsl:attribute>
</xsl:if>
</input>
<br/>
</xsl:template>
<xsl:template match="SELECT">
<select>
<xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
<xsl:apply-templates/>
</select>
</xsl:template>
<xsl:template match="ITEM">
<option>
<xsl:attribute name="value"><xsl:value-of select="@value"/></xsl:attribute>
<xsl:if test="@checked">
<xsl:attribute name="selected"><xsl:value-of select="@checked"/></xsl:attribute>
</xsl:if>
<xsl:apply-templates/>
</option>
</xsl:template>
<xsl:template match="CHOICE-GROUP">
<div class="choiceGroup">
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="CHOICE">
<br/>
<xsl:variable name="choiceType" select="../@type"/>
<input type="{$choiceType}">
<xsl:attribute name="name"><xsl:value-of select="../@name"/></xsl:attribute>
<xsl:attribute name="value"><xsl:value-of select="@value"/></xsl:attribute>
<xsl:if test="@checked">
<xsl:attribute name="checked"><xsl:value-of select="@checked"/></xsl:attribute>
</xsl:if>
</input>
<xsl:apply-templates/>
<br/>
</xsl:template>
<xsl:template match="TABLE">
<table>
<xsl:attribute name="border">
<xsl:choose>
<xsl:when test="@border = 'true'">
1
</xsl:when>
<xsl:when test="@border = 'false'">
0
</xsl:when>
</xsl:choose>
</xsl:attribute>
<xsl:apply-templates/>
</table>
</xsl:template>
<xsl:template match="TR">
<tr>
<xsl:apply-templates/>
</tr>
</xsl:template>
<xsl:template match="TD">
<td>
<xsl:apply-templates/>
</td>
</xsl:template>
<xsl:template match="CAPTION">
<span><xsl:apply-templates/></span>
</xsl:template>
<xsl:template name="href">
<xsl:param name="href"/>
<xsl:value-of select="$href"/>
<!--xsl:choose>
<xsl:when test="starts-with($href, 'http:')">
<xsl:value-of select="$href"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$hrefPrefix"></xsl:value-of>/<xsl:value-of select="$href"/>
</xsl:otherwise>
</xsl:choose-->
</xsl:template>
<xsl:template name="color">
<xsl:param name="color"/>
<xsl:if test="$color">
<xsl:attribute name="style">color: <xsl:value-of select="$color"/></xsl:attribute>
</xsl:if>
</xsl:template>
<xsl:template name="align">
<xsl:param name="align"/>
<xsl:if test="$align">
<xsl:attribute name="align"><xsl:value-of select="$align"/></xsl:attribute>
</xsl:if>
</xsl:template>
<xsl:template match="*" mode="verbose">
<xsl:text>&lt;</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text> </xsl:text> <xsl:apply-templates select="@*" mode="verbose"/>
<xsl:text>&gt;</xsl:text>
<xsl:apply-templates mode="verbose"/>
<xsl:text>&lt;/</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>&gt;</xsl:text>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="@*" mode="verbose">
<xsl:value-of select="name()"/>
<xsl:text>="</xsl:text>
<xsl:value-of select="." />
<xsl:text>" </xsl:text> </xsl:template> </xsl:stylesheet>

Have fun!

beaver's Weblog - August 27, 2007 08:58 AM
JBOSS 4.2.x - Server in einem Visual Web Projekt ?

Mein kläglicher Versuch den JBOSS - Server 4.2.1 zu einer Visual Web - Anwendung zu bewegen, endete mit dem Fehler "Error configuring application listener of class com.sun.faces.config.ConfigureListener". Hier nun die Schritte, um trotzdem eine Visual Web - Anwendung deployen zu können, obwohl die 4.2.x - Versionen offiziell nicht unterstützt werden.

Hier die benötigte Software:

  • NetBeans 5.5.1 und JBOSS 4.2.x

Ich habe mir ein leeres "Visual Web Application" - Projekt angelegt. Damit nun das Projekt erfolgreich deployt werden kann, rufe ich mir die Projekteigenschaften auf. Unter "Build" finde ich den Unterpunkt "Packaging". Folgende Librarys gehören in das "WEB-INF/lib" - Verzeichnis:

  • Sun Web UI Components
  • JDBC Run-Time Support
  • Exception Handler
  • Theme
  • JSTL 1.1
  • JSF 1.1 Design-Time Support

Des Weiteren ist es nötig, einen Listener für Webanwendungen zu definieren. Dafür geht man in die Designansicht der web.xml, indem diese Datei doppelt angeklickt wird. Unter "Allgemein" oder "General" können Listener für Webanwendungen erstellt werden. Durch einen Klick auf "Hinzufügen" wird die Listener-Klasse abgefragt. In unserem Fall ist das die "com.sun.faces.config.ConfigureListener".

Nun sind alle Vorkehrungen getroffen, um unsere Anwendung erfolgreich deployen zu können. Fortan wird die JSF Library von Sun verwendet und nicht mehr die vom JBOSS - Server.

Bernhard's Weblog - July 12, 2007 10:52 PM
Groovy SwingBuilder FormLayout

Today I played around with Groovy SwingBuilder.

I thought that using JGoodies' FormLayout plus Groovy's SwingBuilder would be nice.

After reading the JForm reference guide, and extracting the FormLayout reference, as quick cheat sheet guide. I started using the FormLayout in Groovy.

It was not that easy for me, as I'm still learning Groovy. Finally I was able to create the panel as described in the JGoodies :: Tutorial :: Quick Start ::.

I had some problems porting the sample code to Groovy SwingBuilder:

  • Create a int[][] in Groovy for defining the JForm column groups
  • Adding the JForm separator widget into Groovy's SwingBuilder
  • Run the creation of the SwingBuilder, and the JFrame show method in the EDT

But I solved all these issues:

Groovy int[][]

The Groovy snippet layout.setColumnGroups([ [1,5] as int[], [3,7] as int[] ] as int[][]); creates exactly an int[][] array as expected by the setColumnGroups method

JForm separator

The Groovy snippet


// create instance of DefaultComponentFactory for creating separators
final def dcf = DefaultComponentFactory.getInstance()
creates the component factory, and the snippet

widget( widget: dcf.createSeparator('General'), constraints: cc.xyw(1, 1, 7))

inserts the JForm separator into the Groovy SwingBuilder.

EDT in Groovy

The blog groovy-verbosity-and-swing describes nicely, how to run code in the EDT using Groovy.

JForm Tutorial in Groovy

Finally the sample code using JForm in Groovy's SwingBuilder


import groovy.swing.SwingBuilder
import java.awt.BorderLayout as BL
import javax.swing.WindowConstants
import javax.swing.JFrame
import javax.swing.UIManager
import javax.swing.SwingUtilities

import com.jgoodies.forms.factories.Borders;
import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.factories.DefaultComponentFactory

class SampleMainSwing3 {
  JFrame frame;

  // nice helpers from http://shemnon.com/speling/2004/05/groovy-verbosity-and-swing.html
  static def invokeAndWait = { SwingUtilities.isEventDispatchThread() ? it() : SwingUtilitites.invokeAndWait(it); }
  static def invokeLater = { SwingUtilities.invokeLater(it) }
  static def invokeOutside = { SwingUtilities.isEventDispatchThread() ? Thread.start(it) : it() }

  static void main( String[] args ) {
    UIManager.setLookAndFeel(UIManager.systemLookAndFeelClassName)

    // run creation in EDT
    invokeLater {
            SampleMainSwing3 sms = new SampleMainSwing3();
            sms.frame.show()
    }
  }

  public SampleMainSwing3() {
    initComponents();
    this.frame.pack()
  }

  private void initComponents() {
    FormLayout layout = new FormLayout(
        "right:pref, 3dlu, pref:grow, 7dlu, right:pref, 3dlu, pref:grow", // columns
        "p, 3dlu, p, 3dlu, p, 9dlu, p, 3dlu, p, 3dlu, p");      // rows

    
    // Specify that columns 1 & 5 as well as 3 & 7 have equal widths.
    layout.setColumnGroups([ [1,5] as int[], [3,7] as int[] ] as int[][]);
    
    // Obtain a reusable constraints object to place components in the grid.
    final CellConstraints cc = new CellConstraints();

    // create instance of DefaultComponentFactory for creating separators
    final def dcf = DefaultComponentFactory.getInstance()

    def swingB = new SwingBuilder()
    this.frame = swingB.frame( title: 'Groovy FormLayout Swing GUI',
      defaultCloseOperation: WindowConstants.EXIT_ON_CLOSE) {
        panel( layout: layout, border: Borders.DIALOG_BORDER) {
            //
            // Add a titled separator to cell (1, 1) that spans 7 columns.
            //label("General",constraints: cc.xyw(1, 1, 7))
            widget( widget: dcf.createSeparator('General'), constraints: cc.xyw(1, 1, 7))
            label("Company",constraints: cc.xy (1, 3))
            textField("companyField",constraints: cc.xyw(3, 3, 5))
            label("Contact",constraints: cc.xy (1,  5))
            textField("contactField",constraints: cc.xyw(3, 5, 5))

            //label("Propeller",constraints: cc.xyw(1,  7, 7))
            widget( widget: dcf.createSeparator('Propeller'), constraints: cc.xyw(1,  7, 7))
            label("PTI [kW]",constraints: cc.xy (1,  9))
            textField("ptiField",constraints: cc.xy (3,  9))
            label("Power [kW]",constraints: cc.xy (5,  9))
            textField("powerField",constraints: cc.xy (7,  9))
            label("R [mm]",constraints: cc.xy (1, 11))
            textField("radiusField",constraints: cc.xy (3, 11))
            label("D [mm]",constraints: cc.xy (5, 11))
            textField("diameterField",constraints: cc.xy (7, 11))
        }
      }
    }
}

If you want to run this code, don't forget to make JForm jar available!

Have fun!

Bernhard's Weblog - July 04, 2007 08:40 PM
Grails domain object

As you have read about Grails, you can write domain objects in Groovy, and in Java.

You define the Groovy domain objects in grails-app/domain, the Java domain objects in src/java.

For the Java domain objects, you can either define an accompanying .hbm.xml hibernate mapping file, or you annotate the class, and properties using Java Persistence annotations. Moreover you have to reference the Java domain objects in the hibernate configuration file, stored as hibernate/hibernate.cfg.xml

Personally, I like the Java way more, as the hibernate mapping files, and the annotations allow me to have more control over the database configuration, like defining the sequence name used for saving the domain objects in the database.

The only disadvantage of using the Java domain objects, are the tedious getter/setter methods defined in the Java domain objects.
The IDE may help, and define shortcuts for defining these methods, quickly.

As I was thinking more about this problem I found another way to define domain objects:

You can define the domain objects using Groovy in the src/groovy directory.
Then define the .hbm.xml hibernate mapping file in the parallel src/java directory. If you have constraints, define the Groovy constraint file in the same directory as the hibernate configuration.

This works as the Groovy files in src/groovy are compiled before deployment, and are stored like the Java files in WEB-INF/classes directory.

The following files use this groovy/hbm way:

  • The Groovy domain object defined using Groovy src/groovy/org/huberb/bookapp/model2/Bike.groovy:

    package org.huberb.bookapp.model2
    import java.io.Serializable
    class Bike implements java.io.Serializable {
    protected final long serialVersionUID = 20070703L;
    Long id
    Long version
    String name
    String producer
    String type
    Integer age
    }
  • The hibernate mapping file for the Groovy domain object src/java/org/huberb/bookapp/model2/Bike.hbm.xml:

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
    <class name="org.huberb.bookapp.model2.Bike" table="bike">
    <id name="id" column="id" unsaved-value="null">
    <generator class="native">
    <param name="sequence">BIKE_SEQ
    </generator>
    </id>
    <version name="version" column="version" type="java.lang.Long"/>
    <property name="name" column="name"/>
    <property name="producer"/>
    <property name="type"/>
    <property name="age"/>
    </class>
    </hibernate-mapping>
  • The constraints for the Groovy domain object src/java/org/huberb/bookapp/model2/BikeConstraints.groovy:

    constraints = {
    name( blank: false )
    producer( blank: false)
    type( blank: false )
    age( blank:false, range: 1..20,)
    }

Have fun!

Bernhard's Weblog - July 04, 2007 04:53 PM
Grails validation message codes

I built a grail application, I added constraints, and everything worked fine. Next, I wanted to change the validation messages, and it took me some time to find the right message codes for the failed constraints.

First I found out that I'm not alone as there is already a Grails issue http://jira.codehaus.org/browse/GRAILS-1287 in this area.

More over in the wiki Validation+Reference a small paragraph for each constraint lists the message code, like

Error message code: className.propertyName.blank

In order to understand which message codes are available I produced the two tables, below, listing the message codes for the various constraints.
The table below lists the message codes which are allowed for the various constraints. As issue GRAILS-1287 is not closed, only the error code value is used by grails.

For your full understanding you might want to read the springframework documention, too: MessageSource.html MessageSourceResolvable.html#getCodes as Grails uses these classes for producing the failed validation messages.

String Constraints


  producer( 
    blank: false, 
    creditCard: true, 
    email: true, 
    inList: ["A"], 
    matches: "[A-Z]", 
    maxSize: 10, minSize: 10, 
    notEqual: "X", 
    nullable: false,
    url: true
)

Property [producer] of class [class org.huberb.bookapp.model2.Bike] with value [] is less than the minimum size of [10]

defaultMessageProperty [{0}] of class [{1}] with value [{2}] is less than the minimum size of [{3}]
error code bike.producer.minSize.notmet
error codes
  1. "bike.producer.minSize.error.org.huberb.bookapp.model2.Bike.producer"
  2. "bike.producer.minSize.error.producer"
  3. "bike.producer.minSize.error.java.lang.String"
  4. "bike.producer.minSize.error"
  5. "bike.producer.minSize.notmet.org.huberb.bookapp.model2.Bike.producer"
  6. "bike.producer.minSize.notmet.producer"
  7. "bike.producer.minSize.notmet.java.lang.String"
  8. "bike.producer.minSize.notmet"

Property [producer] of class [class org.huberb.bookapp.model2.Bike] cannot be blank

defaultMessageProperty [{0}] of class [{1}] cannot be blank
error codebike.producer.blank
error codes
  1. "bike.producer.blank.error.org.huberb.bookapp.model2.Bike.producer"
  2. "bike.producer.blank.error.producer"
  3. "bike.producer.blank.error.java.lang.String"
  4. "bike.producer.blank.error"
  5. "bike.producer.blank.org.huberb.bookapp.model2.Bike.producer"
  6. "bike.producer.blank.producer"
  7. "bike.producer.blank.java.lang.String"
  8. "bike.producer.blank"

Property [producer] of class [class org.huberb.bookapp.model2.Bike] with value [] does not match the required pattern [[A-Z]]

defaultMessageProperty [{0}] of class [{1}] with value [{2}] does not match the required pattern [{3}]
error code bike.producer.matches.invalid
error codes
  1. "bike.producer.matches.error.org.huberb.bookapp.model2.Bike.producer"
  2. "bike.producer.matches.error.producer"
  3. "bike.producer.matches.error.java.lang.String"
  4. "bike.producer.matches.error"
  5. "bike.producer.matches.invalid.org.huberb.bookapp.model2.Bike.producer"
  6. "bike.producer.matches.invalid.producer"
  7. "bike.producer.matches.invalid.java.lang.String"
  8. "bike.producer.matches.invalid"

Property [producer] of class [class org.huberb.bookapp.model2.Bike] with value [] is not contained within the list [[A]]

defaultMessageProperty [{0}] of class [{1}] with value [{2}] is not contained within the list [{3}]
error code bike.producer.not.inList
error codes
  1. "bike.producer.inList.error.org.huberb.bookapp.model2.Bike.producer"
  2. "bike.producer.inList.error.producer"
  3. "bike.producer.inList.error.java.lang.String"
  4. "bike.producer.inList.error"
  5. "bike.producer.not.inList.org.huberb.bookapp.model2.Bike.producer"
  6. "bike.producer.not.inList.producer"
  7. "bike.producer.not.inList.java.lang.String"
  8. "bike.producer.not.inList"

Property [producer] of class [class org.huberb.bookapp.model2.Bike] with value [] is not a valid URL

defaultMessageProperty [{0}] of class [{1}] with value [{2}] is not a valid URL
error code bike.producer.url.invalid
error codes
  1. "bike.producer.url.error.org.huberb.bookapp.model2.Bike.producer"
  2. "bike.producer.url.error.producer"
  3. "bike.producer.url.error.java.lang.String"
  4. "bike.producer.url.error"
  5. "bike.producer.url.invalid.org.huberb.bookapp.model2.Bike.producer"
  6. "bike.producer.url.invalid.producer"
  7. "bike.producer.url.invalid.java.lang.String"
  8. "bike.producer.url.invalid"

Property [producer] of class [class org.huberb.bookapp.model2.Bike] with value [] is not a valid e-mail address

defaultMessageProperty [{0}] of class [{1}] with value [{2}] is not a valid e-mail address
error code bike.producer.email.invalid
error codes
  1. "bike.producer.email.error.org.huberb.bookapp.model2.Bike.producer"
  2. "bike.producer.email.error.producer"
  3. "bike.producer.email.error.java.lang.String"
  4. "bike.producer.email.error"
  5. "bike.producer.email.invalid.org.huberb.bookapp.model2.Bike.producer"
  6. "bike.producer.email.invalid.producer"
  7. "bike.producer.email.invalid.java.lang.String"
  8. "bike.producer.email.invalid"

Property [producer] of class [class org.huberb.bookapp.model2.Bike] with value [] is not a valid credit card number

defaultMessageProperty [{0}] of class [{1}] with value [{2}] is not a valid credit card number
error code bike.producer.creditCard.invalid
error codes
  1. "bike.producer.creditCard.error.org.huberb.bookapp.model2.Bike.producer"
  2. "bike.producer.creditCard.error.producer"
  3. "bike.producer.creditCard.error.java.lang.String"
  4. "bike.producer.creditCard.error"
  5. "bike.producer.creditCard.invalid.org.huberb.bookapp.model2.Bike.producer"
  6. "bike.producer.creditCard.invalid.producer"
  7. "bike.producer.creditCard.invalid.java.lang.String"
  8. "bike.producer.creditCard.invalid"

Integer constraints


age( blank:false,
    min: 10,
    max: 20,
    range: 10..20,
    unique: true,
)

Property [age] of class [class org.huberb.bookapp.model2.Bike] with value [-7.777] is less than minimum value [10]

defaultMessageProperty [{0}] of class [{1}] with value [{2}] is less than minimum value [{3}]
error code bike.age.min.notmet
error codes
  1. "bike.age.min.error.org.huberb.bookapp.model2.Bike.age"
  2. "bike.age.min.error.age"
  3. "bike.age.min.error.java.lang.Integer"
  4. "bike.age.min.error"
  5. "bike.age.min.notmet.org.huberb.bookapp.model2.Bike.age"
  6. "bike.age.min.notmet.age"
  7. "bike.age.min.notmet.java.lang.Integer"
  8. "bike.age.min.notmet"

Property [age] of class [class org.huberb.bookapp.model2.Bike] with value [-7.777] does not fall within the valid range from [10] to [20]

defaultMessageProperty [{0}] of class [{1}] with value [{2}] does not fall within the valid range from [{3}] to [{4}]
error code bike.age.size.toosmall
error codes
  1. "bike.age.range.error.org.huberb.bookapp.model2.Bike.age"
  2. "bike.age.range.error.age"
  3. "bike.age.range.error.java.lang.Integer"
  4. "bike.age.range.error"
  5. "bike.age.size.toosmall.org.huberb.bookapp.model2.Bike.age"
  6. "bike.age.size.toosmall.age"
  7. "bike.age.size.toosmall.java.lang.Integer"
  8. "bike.age.size.toosmall"

Property [age] of class [class org.huberb.bookapp.model2.Bike] with value [7.777] does not fall within the valid range from [10] to [20]

defaultMessageProperty [{0}] of class [{1}] with value [{2}] does not fall within the valid range from [{3}] to [{4}]
error code bike.age.size.toobig
error codes
  1. "bike.age.range.error.org.huberb.bookapp.model2.Bike.age"
  2. "bike.age.range.error.age"
  3. "bike.age.range.error.java.lang.Integer"
  4. "bike.age.range.error"
  5. "bike.age.size.toobig.org.huberb.bookapp.model2.Bike.age"
  6. "bike.age.size.toobig.age"
  7. "bike.age.size.toobig.java.lang.Integer"
  8. "bike.age.size.toobig"

Property [age] of class [class org.huberb.bookapp.model2.Bike] with value [7.777] exceeds maximum value [20]

defaultMessageProperty [{0}] of class [{1}] with value [{2}] exceeds maximum value [{3}]
error code bike.age.max.exceeded
error codes
  1. "bike.age.max.error.org.huberb.bookapp.model2.Bike.age"
  2. "bike.age.max.error.age"
  3. "bike.age.max.error.java.lang.Integer"
  4. "bike.age.max.error"
  5. "bike.age.max.exceeded.org.huberb.bookapp.model2.Bike.age"
  6. "bike.age.max.exceeded.age"
  7. "bike.age.max.exceeded.java.lang.Integer"
  8. "bike.age.max.exceeded"

Have fun!

Bernhard's Weblog - June 05, 2007 09:33 PM
PMD custom ruleset (2)

As I have blogged about writing PMD rulesets, now there is a simple Netbeans module supporting you in writing PMD rulesets.

You can download the module from the Netbeans Plugin Central: nb-pmd-rulesets

Installation

The module itself does not require any special installation steps, beside the usual Netbeans module installation.

If you want to invoke the PMD designer tool from within this module, you need to specify the PMD installation directory in the module's options dialog.

Usage

This modules supports you in writing PMD ruleset xml files, by providing:

  1. a pmd ruleset xml template file
  2. a JavaHelp section describing all ruleset definition provided by PMD-3.9
  3. a xml catalog registry of the ruleset xml schema, and allowing you to validate ruleset xml file
  4. a menu entry for launching PMD's designer tool

Ruleset Template

A ruleset template is available via New File|PMD|PMD SimpleRuleset. You can use this template to start writing you own PMD rulesets.

Moreover you can store your own PMD ruleset templates in PMD template folder.

Ruleset JavaHelp

You can browse the rulesets delivered by PMD-3.9 in JavaHelp window, learning the already provided rules, and rulesets.

Ruleset XML Catalog

In the explorer tab Runtime the node DTD and XML Schema Catalogs|PMD Ruleset Catalog defines the ruleset schema definition (http://pmd.sf.net/ruleset/1.0.0).

By defining the ruleset schema, you can validate your ruleset xml files via the context menu entry Validate XML.

In Netbeans version 5.5.1 and above, xml code completion might work.

PMD's designer tool

The the main menu the entry Tools|PMD Designer launches PMD's ruleset designer. The designer helps you in writing proper xpath definitions.

Note: you have to specify the PMD's home directory before launching the designer, see the section below.

Options

You can find the option dialog by clicking the menu bar Tools|Options|Miscellaneous|PMD Ruleset.

The options dialog allows you to specify the home directory of the downloaded, and extracted PMD binary distribution.

The PMD's ruleset designer is launched by an internal ant script, defining the designer classpath as ${pmd.home}/lib/*.jar.

Have fun!

Bernhard's Weblog - May 28, 2007 07:41 AM
PMD custom ruleset

PMD is code analysis tool. PMD allows you to write custom rules. You can write rules in Java, or as XPath expressions.

There is already some documentation available, see:

This blog describes writing XPath expression rules, and loading them into the PMD netbeans module.

Rule definition

A rule definition file is an xml file, see Template Rule Snippet.

A single ruleset file can contain one more rules. The following ruleset is a ruleset definition I use:


<?xml version="1.0"?><ruleset name="Custom ruleset"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>
This ruleset checks my code for bad stuff.
</description>
<rule name="nbbundle-class-ref"
message="NbBundle Class reference"
class="net.sourceforge.pmd.rules.XPathRule"
>
<description>
Warns if NbBundle.getMessage references not this class
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//PrimaryExpression[
PrimaryPrefix/Name[@Image = 'NbBundle.getMessage'] and
PrimarySuffix//ReferenceType/ClassOrInterfaceType[@Image != /TypeDeclaration/ClassOrInterfaceDeclaration/@Image
]
]
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
package org.huberb.cpd;
public final class Foo {
public String getNameOkay() {
return NbBundle.getMessage(CpdAction.class, "CTL_CpdAction");
}
public String getNameNotOkay() {
return NbBundle.getMessage(Bar.class, "CTL_CpdAction");
} }
]]>
</example>
</rule>
<rule name="import-package"
message="Check package import"
class="net.sourceforge.pmd.rules.XPathRule"
>
<description>
Warn about importing specific packages.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//ImportDeclaration/Name[starts-with(@Image, $packageName)]
]]>
</value>
</property>
<property name="packageName" description="Invalid package prefix">
<value>'com.sun'</value>
</property>
</properties>
<example>
<![CDATA[
package org.huberb.beautifulday.dao;
import com.sun.java.util.jar.pack.PackerImpl;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
class Foo {
}
]]>
</example>
</rule>
<rule name="logger-creation"
message="Check creation of logger"
class="net.sourceforge.pmd.rules.XPathRule">
<description>
Check the creation of the logger.
A logger shall use this class, directly.
It shall not use another class, or the Foo.class.getName().
Use logCreation value 'LogFactory.getLog' for commons-logging,
use 'Logger.getLogger' for log4j. </description>
<priority>3</priority>
<properties>
<property name="xpath">
<value><![CDATA[
//PrimaryExpression[
PrimaryPrefix/Name[ends-with(@Image, $logCreation)] and (
PrimarySuffix//ReferenceType/ClassOrInterfaceType
[@Image != /TypeDeclaration/ClassOrInterfaceDeclaration/@Image]
or
PrimarySuffix//PrimarySuffix[@Image = 'getName']
)
]
]]>
</value>
</property>
<property name="logCreation" description="Log creation snippet, use 'LogFactory.getLog' for commons-logging, use 'Logger.getLogger' for log4j.
">
<value>LogFactory.getLog</value>
</property>
</properties>
<example>
<![CDATA[
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Foo {
static Log log = LogFactory(Foo.class);
static Log logDontUseGetName = LogFactory.getLog(Foo.class.getName());
static Log logDontUseAnotherClass = LogFactory.getLog(FooXX.class);
static Log logDontUseLiterals = org.apache.commons.logging.LogFactory.getLog("XX");
public void bar() {
log.debug("hello");
}
}
]]>
</example>
</rule>
</ruleset>

The ruleset has a unique name "Custom ruleset". The first description element describes the rules offered by this rule set.

The tag rule describes a single rule. 

The ruleset definition above defines three rules:

  • nbbundle-class-ref
  • import-package
  • logger-creation

Each rule has a name, and defines in the attribute class that it is an XML expression rule. Moreover the message attribute defines the message printed if the rules fails.

The XPath expression itself is defined in the property xpath as its property value. The final example tag describes an example for this rules.

For defining such an XPath rule, I recommend using PMD's designer tool. It is available in the PMD's distribution as bin/designer.bat, and bin/designer.sh.

Moreover if you extract the jar pmd-X.Y.jar you will find a lot of ruleset files, like:

  • rulesets/favorites.xml
  • rulesets/basic.xml"/>
  • rulesets/unusedcode.xml
  • rulesets/braces.xml
  • rulesets/design.xml
  • rulesets/strings.xml

You can use these rulesets as an exmple for your own writing. Moreover you might want to load these rulesets explicitly, like your own written rulesets.

Rule inclusion

So you have written a ruleset xml file. Now it's time to load this ruleset.

The PMD netbeans module offers in its options panel the ability to load external rulesets.

Goto Tools|Options|Miscellaneous|PMD|Manage rulesets... Click the button Add RuleSet, and select the ruleset xml file.

Now your ruleset is loaded.

You can check the loaded rules via Tools|Options|Miscellaneous|PMD|Manage rulesets...|Manage Rules

If you load the ruleset above you shall see the three rules: nbbundle-class-ref, import-package, and logger-creation.

Now, you run can PMD, and your own defined rulesets are taken into account.

Have fun!

Bernhard's Weblog - May 23, 2007 10:30 PM
Find Keys

Find The Keys

My last two projects used I18N resource bundles for defining international messages. As the projects proceeded messages were added, messages were removed.

At one point of time I had the task to remove all the unused messages from the resource bundles.

Searching, searching...

It was a bit tedious to find, and grep through the sources. I must admit, I'm neither a perl- nor a awk guru to define a super simple script for doing this job.

So this was the time, I had the idea to write a Netbeans module doing this job. Today I have a super simple module, extracting the implementation partially from netbeans contrib bundelizer.

Now I can extract the properties keys, and find the usage of these keys in java, jsp, or any other files of the project:

Thus my module writes simply to the Output, key:used-in-file1,used-in-file2,...:


DateCalculatorPanel.deleteButton.text: DateCalculatorPanel.form,DateCalculatorPanel.java
DateCalculatorPanel.header.title: DateCalculatorPanel.form,DateCalculatorPanel.java
DateCalculatorPanel.resultXTitledSeparator.title: DateCalculatorPanel.form,DateCalculatorPanel.java
DateCalculatorPanel.storeButton.text: DateCalculatorPanel.form,DateCalculatorPanel.java
DateCalculatorPanel.restoreButton.text: DateCalculatorPanel.form,DateCalculatorPanel.java
DateCalculatorPanel.dateStartLabel.text: DateCalculatorPanel.form,DateCalculatorPanel.java
DateCalculatorFrame.title: DateCalculatorFrame.form,DateCalculatorFrame.java
DateCalculatorPanel.calculateDiffButton.text: DateCalculatorPanel.form,DateCalculatorPanel.java
DateCalculatorPanel.header.description: DateCalculatorPanel.form,DateCalculatorPanel.java
DateCalculatorPanel.dateEndLabel.text: DateCalculatorPanel.form,DateCalculatorPanel.java

In some other project the keys errors.invalid.filterByColumnStatus, and errors.byte are not used anymore as no files are listed on the right side.


errors.session: DRForm.java,DGRForm.java
label.field.filterM: df.jspf,ov.java
errors.invalid.filterByColumnStatus: -
errors.byte: -
label.filter.status.released: df.jspf,dob_jsp.java

Not used is maybe not quite exact, these keys are not found. If you have used the commons validator project, you might notice that errors.byte is defined there. So be cautious when removing the keys; the matching is not exact, just a hint.

Next Steps

I'd like to polish this module a bit.

I think this kind of modules have some potential, as coding by convention becomes more, and more convenience. And a lot of code depends on each other only by the correct usage of String constants.

Think about property names: Instead of extracting the search pattern from a property file, extract the search pattern from some a java file, and find that usage.

As netbeans is offering already some find/search classes in the project utilities/search. It would be nice if these classes get a public offical/API. This might ease to write more maintaince/find/search/usage modules, like the one I described above, see [Issue 104592] Reuse search from other modules.

Moreover if JavaScripting NetBeans will be available one day scripting the find-search shall be probably possible, too, won't it?

Have fun!

Bernhard's Weblog - May 04, 2007 11:49 PM
Build Script For Grails Application

Today I created a simple ant build script, which invokes the grails command directly. I use this script instead of the default build.xml provided by grails.

Grails Project Build

My ant build script helps me to invoke the various grails commands from inside the Netbeans IDE.
Instead of switching to the command line I can now launch an ant target for compiling, running the grails application, etc.

I'm using this ant build script for Grails version 0.4.2, and 0.5.

If you want to use this script too, adopt the property grails.home to your Grails installation directory.

Grail Project Ant Script

Below the ant script I'm using instead of the default Grails build.xml:


<project name="hibernate-weblog" default="test">

    <property name="grails.home" value="C:\all_projects\programme\grails-0.5"/>
    <property name="grails.bin" value="${grails.home}/bin"/>
    <condition property="grails" value="${grails.bin}/grails.bat">
        <os family="windows"/>
    </condition>
    <property name="grails" value="${grails.bin}/grails" />

    <macrodef name="grails">
        <attribute name="command" default="help"/>

        <sequential>
            <exec executable="${grails}" failonerror="true">
                <arg value="@{command}"/>
                <env key="GRAILS_HOME" value="${grails.home}"/>
            </exec>
        </sequential>
    </macrodef>
    
    <macrodef name="grails2">
        <attribute name="groovyStarter" default="org.codehaus.groovy.tools.GroovyStarter"/>
        <attribute name="grailsScriptRunner" default="org.codehaus.groovy.grails.cli.GrailsScriptRunner"/>
        
        <attribute name="command" default="help"/>
        <sequential>
            <java fork="true" 
            classname="@{groovyStarter}"
            dir="${basedir}"
            >
                <env key="GRAILS_HOME" value="${grails.home}"/>

                <sysproperty key="grails.home" value="${grails.home}"/>
                <sysproperty key="groovy.starter.conf" value="${grails.home}/conf/groovy-starter.conf"/>
                <sysproperty key="tools.jar" value="C:\Program Files\Java\jdk1.5.0_09\lib\tools.jar"/>
                
                <classpath>
                    <pathelement location="${grails.home}/lib/groovy-starter.jar"/>
                </classpath>
                
                <arg line="--main org.codehaus.groovy.grails.cli.GrailsScriptRunner"/>
                <arg line="--conf ${grails.home}\conf\groovy-starter.conf"/>
                <arg line="--classpath ${grails.home}/lib/groovy-starter.jar;."/>

                <arg value="@{command}"/>
            </java>
            
        </sequential>
    </macrodef>

    <!-- =================================
          target: clean
         ================================= -->
    <target name="clean" description="--> Cleans a Grails application">
        <grails2 command="clean"/>
    </target>
    <target name="test" description="--> Run a Grails applications unit tests">
        <grails2 command="test-app"/>
    </target>
    <target name="compile" description="--> Compile a Grails application">
        <grails2 command="compile"/>
    </target>
    <target name="package" description="--> Package a Grails application">
        <grails2 command="package"/>
    </target>
    <target name="run-app" description="--> Runs Grails web application">
        <grails2 command="run-app"/>
    </target>
    
    <target name="grails" description="--> Run grails">
        <input defaultvalue="help" message="grails command" addproperty="grails-command"/>
        <grails2 command="${grails-command}"/>
    </target>
    
    <target name="grails2" description="--> Runs grails ">
        <input defaultvalue="help" 
          message="grails command" 
          addproperty="grails-command"
          validargs="help,clean,compile,package,war,
          ---,
create-controller,
create-domain-class,
create-job,
create-plugin,
create-script,
create-service,
create-tag-lib,
create-test-suite,
---,
generate-all,
generate-controller,
generate-views,
generate-webtest,
          "
          />
        <grails2 command="${grails-command}"/>
    </target>
    
</project>

Using the Build Script

I use this build script by associating the project menu items, like:

Menu itemTarget
Buildcompile
Cleanclean
Deploypackage
Runrun-app

For creating a controller I use the grails2 target. This target lets you select the grails command from a drop down box.

For example running the create-controller, I launch the target grail2, and I select create-controller from the drop down box. I enter the name of the controller in Ant Input line, at the bottom of the output tab.

I only use the grails command line when I initially create a grails project. In this case I still have to launch grails create-app

Summary

For me this build script helps me to stay inside the Netbeans IDE even when I want to launch some grails command.
I hope you find this Ant script useful, and it helps in using Grails.

Have fun!

Bernhard's Weblog - April 30, 2007 04:27 PM
Grails First Impression

Today, I started playing with Grails 0.4.2 .

My plan was to reuse some already existing Hibernate domain objects.
I'm really impressed, it works just fine, reusing the good old Hibernate java domain objects.

Step by Step

I did a step by step approach:

  1. Created a new grails project, using grails create-app {the-project-name}
  2. Copied over the domain objects, and .hbm.xml files into grails-app/src/java
  3. Created a file hibernate/hibernate.cfg.xml, adding the hbm.xml files
  4. Created a controller in grails-app/controller for each domain object

The controller is just as simple as :


import org.huberb.tmo.model.Holiday

class HolidayController {
  // define the domain class
  def scaffold = Holiday.class
}

Moreover I defined constraints files, named like the domain classes having the prefix Constraints, like HolidayConstraints.groovy:


constraints = {
  name( blank: false, matches:"[A-Za-z ]+" )
  month( range: 0..11 )
  day( range: 1..31 )
}

Well, that's it.

Moreover I changed the main.gsp, and index.jsp for changing the look-and-feel, and added a datasource connection to an Oracle database instead of the pre-configured hsqldb.

Summary

I' m really impressed, that's that easy to created simple CRUD applications with Grails.
Moreover I think it's very good desing decision of Grails to reuse Hibernate, and Spring, as hand-coding I would probably choose the same technology.

Some wink demo of the built-application:

Have fun!

Bernhard's Weblog - March 17, 2007 10:43 AM
JBoss Rules 3.0 First Impression

Last week I started reading about JBoss Rules. So I gave it a try.

Impression

I like the conceptual idea of JBoss Rules (Drools 3.0) replacing clumsy/netsted if/else statements by a cleaner rules definition.

In some of my projects I was very unhappy with long if/else statement sequences.

The rules language is quite simple. The documentation is also good. For understanding the concepts I made a hard-copy, and read it.

Today I'm still not quite sure if I have understood the whole rules concept completly, but perhaps on my next projects, let's see...

I'm still not 100% sure that maintaing the rules is easier that mainting java-business rules.

Examples

Some articles on ONJava describe Drools 2.0. I took the StockOffer example as base for my examples.

Moreover a simplicification of a ScoreCard calculation was the base for another example.

You can webstart these applications from http://members.aon.at/bhuber14/#webstart .

Have fun!

Bernhard's Weblog - March 02, 2007 10:45 PM
JarAnalyzer Netbeans Module 2

As I was using the JarAnalyzer module, analyzing jars containing Java 5.0 generics, I noticed that the generated intermediate XML contains bad xml content, like


...
<Package>com.unisys.at.vab.Pair<Lcom.unisys.at.vab.domain</Package>
<Package>com.unisys.at.vab.Pair<Lcom.unisys.at.vab.support</Package>
...

In a perfect world this shall be:


<Package>com.unisys.at.vab.Pair&lt;Lcom.unisys.at.vab.domain</Package>
<Package>com.unisys.at.vab.Pair&lt;Lcom.unisys.at.vab.support</Package>

The reason is simple: I was using a simple PrintWriter to generate the XML. Some better solutions are presented here.

I have choosen the (5) - JAXP + SAX + Serialization to servlet output stream : JDK 1.4 compliant - solution. The fixed module is downloadable from here.

Have fun!

Bernhard's Weblog - February 20, 2007 04:43 PM
JarAnalyzer Netbeans Module

A friend of mine asked my if I know some tool which visualizes the package dependencies of jar files.

First I was not aware of any tool displaying this kind of information on a jar level.

Well, after some searching I found JarAnalyzer.

JarAnalyer analyzes jar files; it creates a metric, and a dependcy of the jar files; it generates XML output. An XSLT reenders XML to HTML. Moreover you can generate DOT files; a dot file can be used with GraphViz (www.graphviz.org) to create a visual representation.

The command line UI, and even the ant task provided by JarAnalyzer is a bit tedious if you want to see the jar dependendies in a real ad-hoc way.

As I have a jdepend Netbeans module at hand, I decided to reuse these classes, and create a jar analyzer Netbeans module.

Usage

You can now select one or more individual jar files in an explorer view (Projects, Files, or Favorites) and analyze the jar archives by selecting the menu item JarAnalyzer from the menu Build|JarAnalyzer.

Moreover you can select an entire directory, and all jar files of the directory are analyzed.

Options

An option menu is available, too. Select Tools|Options|Miscellaneous|JarAnalyzer. The options allows you to specifiy:

  • Packages ignored by JarAnalyzer
  • Jar archives ignored by JarAnalyzer
  • XSLT for transforming XML to HTML

Note: You can create, and select your own XSLT by storing the XSLT file in the directory {netbeans.userdir}/config/jaranalyzer/xslt.

Help

The module JarAnalyzer has its own help documentation available, see Help|Help Contents|JarAnalyzer.

You can download the netbeans module form here.

Have fun!

Bernhard's Weblog - January 29, 2007 10:58 PM
Update Codecs Easy

Now, the little codec tool available as pure applet , and as webstart applet allows to choose the charset.

As I was working the last two months with ldap I have added this feature. It helps to encode, and decode using a selected charset.

LDAP stores non-ascii characters as UTF-8 Base64 encoded, thus using the codec Base64, and the charset UTF-8, I was able to view the ldap output provided by ldapsearch in a human-readable way.

Have fun!

Bernhard's Weblog - January 21, 2007 07:50 PM
Update Speeding up GC

A status update regarding Speeding up GC.

Original Setting

Originally following JVM settings were used: -Xmx2g -XX:NewRatio=2....

These settings for an application server revealed that the JVM was spending a lot of time in the gc during parsing XML documents as large as 60 MB. Note: The XML documents were read using an DOM parser.

Improved Setting

By setting -Xmx2g -XX:NewSize=64m -XX:NewMaxSize=64m ... the performance were improved dramatically.

The parsing time of these large XML documents were acceptable.

Conclusion

My explanation for the improvements is that the gc algorithm using the initial settings spend a lot of time in copying objects from the young generation to the old generation heap segment.
By using the improved settings these copy-over disappeared, and the total time the JVM spent in the gc was reduced.

Have fun!

Bernhard's Weblog - December 29, 2006 08:54 PM
GC heap calculation

As I was learning more about the internal heap segements, and the gc options, I was thinking about a little tool doing the basic calculation of the various heap segements.

Introduction

If you define following parameters:

  • Maximum Heap Size (max) - maximum available memory available as heap
  • Permanent Heap Size (perm) - size of the permanent heap, used by classes
  • NewRatio (nr) - ratio between tenure (tenure), and young (young) heap segement
  • SurvivorRatio (sr) - ratio between survivor space (ss), and eden space (es)

You can calculate the heap segements, using following calculus:

max = perm + app
app = tenure + young
young = 2* ss + es

tenure/nr = young
es/(2*ss) = sr

Tools

Using the calculus about you can create following spreadsheet

  1. App := max - perm
  2. Young := App/(nr+1)
  3. Tenure := (App*nr) / (nr +1), or Tenure = App - Young
  4. ss := Young / (sr +2)
  5. es := Young - 2 * ss

Alternativly I have build a simple java applet using the formulas, above and using jakarta-commons library jexl, and napkinlaf.

The applet is available as Browser applet, and Webstart applet.

Conclusion

Calculating the real heap segment size, is not always easy, and simple, be sure to read the JVM gc documentation, and use tools to help you calculating the heap segments sizes, depending on the JVM GC option settings.

Have fun!

Bernhard's Weblog - December 29, 2006 08:46 PM
Speeding up GC

Last week I was called to survey the garbage collector settings of an J2EE application.

As I had not very deep knowledge of the possible garbage collector internal working, and the available options, I was "googling" the internet; see the resource section below, if you want to read the basics of the gc working, and options.

Problem Inception Phase

A J2EE application was set into production, the web based UI for that application slowed down enourmously.
The UI was not usable, as the response time for the application was not in the range of seconds, but in the range of minutes.

Analyzing Phase

The operating team enabled (-XX:-PrintGC) a Sun's JVM options for logging the gc actions.

Analyzing the gc output, the gc takes about 5 seconds. A simple gc (non-full gc) takes about 5 seconds! That's a bit too long, reasonable values would be about 1 seconds.

The maximum heap size was set to 2 GB, so from my point of view there should be enough memory available. I even had the idea may be it's too much memory.

Now the application itself has some special requirements. Business rules are defined as XML, and stored in the database. The XML rules are stored as BLOBs, and are parsed by the application.

The XML documents are as large as 60 MB(!). Moreover the XML documents are parsed via DOM.

As it is not possible to change the internals of the application, switching from DOM to a more performant XML parsing, we had to adopt the gc settings for that requirements.

I was not able to change the gc settings, but from my point of view reading such big documents via DOM, and having bad gc options might be the cause of the application slowdown.

Conclusion Phase

Well, I cannot yet present any definite conclusion, as the performance of the application has not been solved, yet.

Resources

  • http://java.sun.com/j2se/1.5.0/docs/guide/vm/gc-ergonomics.html
  • http://java.sun.com/docs/hotspot/PerformanceFAQ.html
  • http://java.sun.com/docs/hotspot/VMOptions.html,
  • http://www.javaworld.com/javaworld/jw-01-2002/jw-0111-hotspotgc.html
  • http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp

Have fun!

Bernhard's Weblog - December 26, 2006 09:53 AM
EJB3 Interceptors

This week I was learning about EJB3, and its new interceptors.

Introduction

EJB3 interceptors allow you to intercept any exposed business method.

The method is marked via the annotation @AroundInvoke to be an interceptor method. You can add the interceptor directly into the ejb implemenation class, or add the interceptor method to an interceptor class, and attaching the interceptor class by using the annotation @Interceptor, and @Interceptors to the ejb implementation class.

In AOP an interceptor method is named an advice, and the class containing an adivce is called an aspect.

In the tutorials I read so far there were only examples like counting the number of invocations, or profiling the invocation time of the business method.

So form my point of view these examples show that it is easy to add system level functionality to business methods very easily.

If you want to know how long does your business method take just add an interceptor retrieve the current time before the business method invocation, and after the business method, and output the difference.

Well, I was thinking more about does it make sense to add business logic into the interceptor.

I must admit that I'm very cautious externalizing business functionality. It leaves a bad taste that business functionality depends on proper configuration. Making the business functionality parameterizable via external configuration that's another issue.

Banking Example

As I was involved in some banking projects; I reviewed these projects, asking myself how can I take use of interceptors in these projects?

In these projects the business requirements were before executing the core-business method log the incoming data, validate the incoming data. After running the core-business method we have to log the results, and validate the results.

You see from me description using the words before, and after these before- and after-tasks may end-up into an interceptor.

The interceptor invokes the before tasks before preceeding to the business method, and invokes the after tasks after the business method.

Using normal OOP strategy pattern, you can encapsulate the before- and after-tasks and reusing the interceptor for a number of business methods.

JMX Example

Beside the pure business methods often there was a requirement to deaktivate only certain functionality of the whole application.

Surely you can undeploy the whole application on an application server, but for a fine-grained deactivation you have to put some simple logic into each business method, like "Shall I run, or am I deactivated?".

For this kind of requirement I was thinking about using an JMX service, which is queried before the business method. If the JMX service answers with "yes", the interceptor continues otherwise some exception is thrown, and the business method is not called.

Conclusion

Well, so far I don't have the luxury to test my ideas directly using ejb3 interceptors.

But reviewing the old projects a lot of tedious before- and after task invocation would have been unneccessary. Moreover using annotation my original concerns were lifted as the configuration is still directly in the java sources, and not externalized to some xml configuration. (Of course you can do that using ejb deployment descriptor, but in this case I don't see much use, as the deployer has more chance to make something wrong than configuring the business methods right).

Have fun!

Bernhard's Weblog - December 26, 2006 09:31 AM
Webservice client

Last week I have to inquiry a problem accessing webservices.

Problem Inception Phase

In a project we have implemented a bunch of webservices.

If you call an operation of a webservice sometimes another webservice operation is executed. For example calling operation A of webservice WS1, in reality operation B of WS1 is executed.

Analyzing Phase

All the operations which are not invoked correctly share the same number of arguments, and the arguments share the type of arguments.

So for example operation A has he signature String A( String argA1, String argA2 ), and operation B has the signature String B( String argB2, String argB2 ), too.

On the server side we used first XFire 1.2.1, and upgraded to XFire 1.2.2. Upgrading to the version XFire 1.2.2 did not help, the problem did not disappear.

Analyzing the SOAP document, and the XFire configuration put some light into the problem:

The webservice were configured using the settings:


<property name="style" value="document" /&rt;
<property name="use" value="literal" /&rt;

After changing the configuration to :


<property name="style" value="wrapped" /&rt;
<property name="use" value="literal" /&rt;

The problem disappeared. I assume that using this configuration the SOAP document is clear enough about which operation shall be invoked.

Conclusion Phase

Well, I must admit that I still don't understand it fully why using the style=document the correct operation is not invoked. I assumme that the XFire is missing some hint invoking the right operation.

The tool soapUI has helped me tremendously, you can download it from here.

Have fun!

Bernhard's Weblog - December 05, 2006 05:13 PM
UnknownHostException Parsing XML

Today I have seen the exception java.net.UnknownHostException: www.some-host.com when an XML document, received from a backendsystem, is unmarshalled by Castor.

Problem Inception Phase

The problem appears not regularly, only from time to time.
The exception is very annoying, especially the business process terminates, and the user will see the message "Operation failed, try again later".

Analyzing Phase

My first question was who tries to connect to which host?

The application itself does surly not try to connect to the unknown host.

The stack trace revealed, that in the xml document there must be  some reference to the unknown host.

I checked the xml document, but it contained pure date, except in the xml intro, there was a DOCTYPE definition specifying the host.
The doctype definition was something like:

<!DOCTYPE root-element PUBLIC "some-public-id"
"http://www.some-host.com/some-dtd.dtd">

Now, I have found the cause of this problem.

The host might become unavailable some times, this will make the parsing of the document fail, and the user will see the annoying message "...try again later".

But how can I solve this problem? Is there some way to tell the SAX parser which is used by Castor to ignore the DOCUMENTTYPE statement, or make connecting to the host unnecessary?

In short, yes.

Create a simple class implementing EntityResolver, I used following class:


package org.huberb.support;

import java.io.StringReader;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;

/**
* Implement an entity resolver, always resolving to an empty entity definition.
*/
public class NoOpEntityResolver implements EntityResolver {
public static NoOpEntityResolver getNoOpEntityResolver() {
return NO_OP_ENTITY_RESOLVER;
}
private static final NoOpEntityResolver NO_OP_ENTITY_RESOLVER = new NoOpEntityResolver();

/** Creates a new instance of NoOpEntityResolver */
private NoOpEntityResolver() {
}
public InputSource resolveEntity(String publicId, String systemId) {
return new InputSource(new StringReader(""));
}
}

Finally I set this entity resolver to the unmarshaller using:


// create unmarshaller
...
unmarshaller.setEntityResolver(NoOpEntityResolver.getNoOpEntityResolver);
// start unmarshalling
...

Conclusion Phase

The problem was quite tricky, but after checking the stack trace, and the xml document the cause of the problem become clear.

As a side effect the parsing, and unmarshalling of the XML document is now much faster, as connecting to the remote host for validating the XML document is prohibited now.

You might want to reread the javadoc of the interface org.xml.sax.EntityResolver, in order to understand the full contract of EntityResolver.

Note: Another more solution would be to deliver the DTD from the EntityResolver, either literally or be loading it from the classpath.

Have fun!

Bernhard's Weblog - November 16, 2006 11:39 PM
Codecs Easy

Some years ago I had to process emails in a j2ee application. Emails were coming from different mail-clients.
At this time I came in touch with different encodings used in the mail-body, and in the mail headers.

It was not always easy to handle all different encoding possibilities, but the project team managed it.

At this time a little tool displaying the different encodings would be very handy.

Now jakarta commons hosts the codec project which implements the various encodings.

Well, if you need to check the encodings, and decodings an applet tool might help you:

The codec applet tool just let's you enter some text, and calculates the encoded/decoded text.

As simple as it is, it would have helped in that project quite a bit...

Have fun!

Bernhard's Weblog - November 13, 2006 09:22 PM
Irretrievable CVS password

Last week I have forgotten my CVS password.

After searching a bit I found a simple java implementations of the scramble and unscramble algorithms used by CVS.

If you have a similar questions, you might want to try this applet, which may answer your cvs password questions.

Note: The applet requires Java 1.5, or higher.

Have fun!

Bernhard's Weblog - November 13, 2006 08:48 PM
To cheat with illusions

Another story solving a tricky problems, today it’s about the subtle differences between test environment and production environment.

Problem Inception Phase

The testing team reports that they experience a strange problem; they have tried to setup a browser configuration as configured in the production environment in the test environment, but failed.

Being more specific it’s about the IE configuration for an Active-X component.

In the production environment the Active-X component is just executed, in the test environment the user is asked if he really wants to execute an Active-X component from a not trusted site.

So they added the web site containing the Active-X component to the trusted web sites in the test-environment, and everything works fine.

But, but, that’s not the setting as it is in the production environment; in the production environment no additional settings defining trusted sites are necessary.

That’s the situation when I was called.

Analyzing Phase

So what do you do in this situation?

First it took me quit a while to understand what are the environment setup on the production side, and on the testing side.

Next I was very confused, and I didn’t have any clue how to solve their problem.

Then I slowly started to put up hypothesis. One of my best hypotheses regarding the test-environment was:

"The configuration you made is exactly the behavior we are seeing. The program (the IE browser) behaves exactly the way you have configured it."

From now on we switched your investigations from the test-environment to the production environment, and tried to find the misbehavior there.

Finally we found the cause of the problem, the trusted sites of the production environment was not properly delivered to all client machines. Although the trusted sites were removed from the repository definitions, at the client machines they were still seen as trusted sites.

Conclusion Phase

It took us two hours to find the cause of the problem.

What’s the conclusion of this activity?

  • Don’t assume that the environment is as you might think.
  • Always try to find hard facts supporting your assumptions. Even if your are sure you don't need additional evidence since it's absolutly obvious.
  • Always verify your assumptions.
  • Ask some persons which are not involved, yet. Especially if you already have invested a lot of time, already.

Have fun!