Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

2011/04/26

Szczecin JUG meeting: Dependency Injection and Google Guice

Here are the details of this event (in Polish).

It is the first in a series of lectures/workshops covering practical aspects of Dependency Injection, Google Guice, GIN, and building GWT applications in the spirit of Model-view-presenter pattern.

2011/04/02

2011/01/31

Tadedon - solid ground for any Java application

Some time ago I started project called tadedon. The name is coined by my little son Alan (Polish), and I assume it is short, unique, and easy to remember.

The whole projects consists of several maven modules, which are intended to be flexible tools for solving common problems. Each module is built on top of library like Guice, GWT, commons-configuration, etc. Tadedon modules shouldn't be considered as extensions to these libraries, but rather as a thin layer of code which allows to use these libraries in special contexts. Here is an example of tadedon-guice-servlet-mock module which supports unit testing of Guice Servlet Modules without the need of real servlet container.

I have already released version 1.0. Now tadedon needs some attention - it should attract more users, and developers. Any contributions are welcome. Putting tadedon modules into maven central repository seems the most important goal right now.

2010/01/14

Unlocking Android - A Developers Guide

Thanks to Szczecin JUG I had opportunity to read Unlocking Android - A Developer's Guide. The title very accurately describes contents of this book. It is truly a developers guide, but also something more.

If you are reading this review, you probably already heard about Android? For sure this name does not only denote a bunch of mobile devices, nor it only refers to specific operating system. Android is one of the platforms provided by Google.

I found very interesting opinion somewhere on the web. The author concludes that Sun and Google both have three different Java editions. As Sun provides Enterprise Edition, Standard Edition and Micro Edition, Google offers Cloud Edition (Google App Engine for Java), Web Edition (Google Web Toolkit) and Mobile Edition (Android). Comparing Android to JavaMe is not completely fair. However such comparison shows how many possibilities Android platform provides in the field of development for mobile devices. From this perspective 'Unlocking Android' is not only a developers guide - it is a book about one of important Java editions. Software developed for mobile devices has it's very own specifics and Android platform offers special approach for addressing them. The book describes these topics to great extent also showing interesting comparison with other major mobile platforms.

Structure of the book is very convenient for the reader. However be prepared that it is more step-by-step guide then detailed reference of Android APIs. It starts with general concepts, and goes through detailed description of Eclipse based development environment, specifics of UI design, code examples of available APIs, and ends with core topics from the Hacking Android chapter. Each chapter contains a lot of diagrams and screenshots in addition to text and code fragments. The code examples are usually short, and possibly refer only to concept they are supposed to explain. However the sequence of involved machinery is described as deep as it matters - sometimes as deep as the level of Linux operating system internals below Dalvik virtual machine.

The whole Unlocking Android, it's structure and contents, is influenced by psychology of the end user of mobile device - the role of user's Intent as declaration of need. APIs which reference the real world have a real world illustrations - e.g. location API has picture of little globe describing latitude and longitude concepts. However I remember such picture from primary school, it seems very useful in this place. The consequence of such amount of information enclosed in one source (almost 400 pages) is that it could be hard to use it as a quick reference.

Unfortunately the Android Market and procedures of publishing the application are described very briefly. Android platform is evolving very quickly and I hope that book will be updated to include new features.

Who will benefit from reading Unlocking Android? I find it convenient and clear, but novice to software development could be confused. Authors assume that reader has experience in programming techniques, XML related topics, and Java in particular. Regardless of good IDE support the topic of development for mobile devices is quite complex. The requirements of good software design can interfere with the requirements of high performance and low memory footprint. It reminds me the time when I was coding in assembler :) . If you want to develop application on Android platform and have strong background in Java then the Unlocking Android will help you for sure.

2009/03/15

gwt-servlet-war project, no more annoying gwt-servlet in the classpath

All the GWT libraries are available in the central maven repositories now. There are 4 different jars for single platform (gwt-user, gwt-dev, gwt-dev with platform classifier (thus there is even more jars the 4) and gwt-servlet.

If you are developing gwt application which will be packaged as war, these libraries should be included in pom.xml with something like this:

 <dependencies>
   <dependency>
     <groupId>com.google.gwt</groupId>
     <artifactId>gwt-user</artifactId>
     <version>${gwtVersion}</version>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>com.google.gwt</groupId>
     <artifactId>gwt-dev</artifactId>
     <version>${gwtVersion}</version>
     <classifier>${platform}-libs</classifier>
     <type>zip</type>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>com.google.gwt</groupId>
     <artifactId>gwt-dev</artifactId>
     <version>${gwtVersion}</version>
     <classifier>${platform}</classifier>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>com.google.gwt</groupId>
     <artifactId>gwt-servlet</artifactId>
     <version>${gwtVersion}</version>
   </dependency>
 </dependencies>

GWT jars marked with provided will be available during development, but not packaged into war. This approach have only one drawback, core gwt classes are present in both - gwt-user, and gwt-servlet jar in the same time. In case of developing project in eclipse with m2eclipse plugin it leads to very annoying behavior (not finding sources, showing two candidate types with the same name, etc.).

I have created new gwt-servlet-war project to overcome this problem. The idea is very simple. Instead of the last gwt-servlet dependency from above example, one should put:

   <dependency>
     <groupId>pl.ncdc.gwt</groupId>
     <artifactId>gwt-servlet-war</artifactId>
     <version>${gwtVersion}</version>
     <type>war</type>
   </dependency>

After this change, war packaging will be supported by so called "war overlays" where wars specified as dependencies are merged into war being built.

And guess what gwt-servlet-war contains? Only gwt-servlet library in WEB-INF/lib. Thus project is in fact single pom.xml. Anyway It have to be packaged according to gwt versioning scheme.

If anyone have any idea how to set up maven repository on top of code.google.com's subversion, please contribute it to the project. Maybe I should promote this jar to be put in central maven repo, or rather suggest people responsible for putting gwt artifacts there to provide something of this kind along the line?

2009/02/03

Maven google code upload plugin

The project is located here.

Example setup (works well with my projects) looks like:

<plugin>
  <groupId>org.riedelcastro</groupId>
  <artifactId>maven-gcupload-plugin</artifactId>
  <version>1.0</version>
  <configuration>
    <uploads>
      <upload>
        <extensions>jar</extensions>
        <labels>Featured,Type-Archive,OpSys-All</labels>  
      </upload>
      <upload>
        <extensions>jar</extensions>
        <postfix>sources</postfix>
        <labels>Featured,Type-Source,OpSys-All</labels>
      </upload>
      <upload>
        <extensions>jar</extensions>
        <postfix>javadoc</postfix>
        <labels>Featured,Type-Docs,OpSys-All</labels>
      </upload>
    </uploads>
  </configuration>
</plugin>

The gcupload:gcupload maven target is added to our Hudson. We have differentia-javaica release build which takes care of everything - deploying jars to our Nexus as well as putting them to Google Code.

2009/02/02

Differentia Javaica

I started a new project called differentia-javaica. Here is the quote from the original description:

The aim of this project is to compare two java source codes and check if they are equal. It is not a simple diff. It uses ANTLR to construct two Abstract Source Trees for java types and eventually compare these trees. As a consequence white spaces and comments will not affect comparison. Reordering of elements in source code will be treated as difference though.

This kind of comparison is especially helpful when writing unit tests for java source code generators. When we have expected source code it is possible to check if it equals to generated source code.

We are writing some Java source code generators right now at NCDC and this tools is quite helpful in unit testing. Thus we want to share it with community.

2008/12/16

XML find and replace - xmlsed how to

Sed is a great tool when it comes to string replacement. With simple command like:

$ sed -i -e 's/log4j\.rootLogger=debug/log4j\.rootLogger=warn/' log4j.properties

, it will change appropriate value in log4j.properties file. It is especially useful in automatic scripts which customize configuration.

The problem I have encountered lately was connected with using sed for string replacement in xml files. I tried different regular expressions, and multi-line matching, and it was a real pain. I needed a kind of "xmlsed" in fact. Then I realized that even I don't know sed script syntax good enough, I know language which is tailored at manipulation of XML, which is XSLT. :)

For example when we have xml log4j configuration like this:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
  <appender name="console" class="org.apache.log4j.ConsoleAppender"> 
    <param name="Target" value="System.out"/>
    <layout class="org.apache.log4j.PatternLayout"> 
      <param name="ConversionPattern" value="%-5p %c{1} - %m%n"/> 
    </layout>
  </appender>

  <root>
    <priority value ="debug" />
    <appender-ref ref="console" />
  </root>
  
</log4j:configuration>
We have to prepare appropriate filtering xslt file:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:template match="root/priority/@value">
    <xsl:attribute name="value">warn</xsl:attribute>
  </xsl:template>

  <xsl:template match="@*|*">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="comment()">
     <xsl:copy />
  </xsl:template>

</xsl:stylesheet>

, and then call:

$ xsltproc -o log4j.xml filter.xsl log4j.xml 

The XSLT file could look a bit verbose, but in fact only first template match is specific. The rest will just copy xml from input to output. Using this technique we can also strip some attributes or semantically replace more structured XML fragments. And all of this without removing XML comments.

The only drawback is that DOCTYPE will not be preserved.

If you want to match specific attribute value:

  <xsl:template match="Connector/@port[.='8080']">
    <xsl:attribute name="port">8180</xsl:attribute>
  </xsl:template>

2008/11/29

Nexus on debian

Nexus is very cool Maven Repository Manager, and debian is as cool server OS platform. I tried to match them. There was some pain, however finally I succeeded :).

Nexus is bundled as war now, thus the description is about installing it on tomcat.

In case of using debian etch (current stable), you may consider installing jdk 1.6 from backports. With jdk 1.6 you have to specify new JAVA_HOME=/usr/lib/jvm/java-6-sun in /etc/default/tomcat5.5.

Debian's tomcat has security manager turned on by default. Of course it could be easily disabled in /etc/default/tomcat5.5, however I feel safer when it is turned on :). Establishing security policy is not easy. My solution to the problem is based on work described in Mark Petrovic's article. I tweaked it a bit not to generate redundant rules. In case of nexus the resulting file looks as follows:

grant codeBase "file:${catalina.home}/bin/tomcat-juli.jar" {
    permission java.io.FilePermission "${catalina.base}/webapps/nexus/WEB-INF/classes/logging.properties", "read";
};

grant codeBase "file:${catalina.base}/webapps/nexus/WEB-INF/lib/-" {
    permission java.util.PropertyPermission "*", "read,write";
    permission java.io.FilePermission "/", "read";
    permission java.io.FilePermission "${catalina.base}/logs", "read";
    permission java.io.FilePermission "${catalina.base}/webapps/nexus/localhost/nexus/WEB-INF/plexus.properties", "read";
    permission java.io.FilePermission "${catalina.base}/webapps/nexus/localhost/nexus/WEB-INF/plexus.xml", "read";
    permission java.io.FilePermission "${catalina.base}/webapps/nexus/WEB-INF/log4j.properties", "read";
    permission java.io.FilePermission "${catalina.base}/temp", "read,write";
    permission java.io.FilePermission "${catalina.base}/temp/-", "read,write,delete";
    permission java.lang.RuntimePermission "defineClassInPackage.java.lang", "";
    permission java.lang.RuntimePermission "createClassLoader", "";
    permission java.lang.RuntimePermission "setContextClassLoader", "";
    permission java.lang.RuntimePermission "accessDeclaredMembers", "";
    permission java.lang.RuntimePermission "getenv.*", "";
    permission java.lang.RuntimePermission "accessClassInPackage.sun.misc", "";
    permission java.lang.RuntimePermission "accessClassInPackage.sun.reflect", "";
    permission java.lang.RuntimePermission "reflectionFactoryAccess", "";
    permission java.lang.RuntimePermission "getClassLoader", "";
    permission java.lang.RuntimePermission "modifyThread", "";
    permission java.io.FilePermission "${catalina.home}/sonatype-work", "read,write";
    permission java.io.FilePermission "${catalina.home}/sonatype-work/-", "read,write,delete";
    permission java.net.SocketPermission "*", "connect,resolve";
    permission java.lang.reflect.ReflectPermission "suppressAccessChecks", "";
    permission java.util.logging.LoggingPermission "control", "";
};

grant codeBase "file:${catalina.base}/webapps/nexus/WEB-INF/classes/-" {
    permission java.util.PropertyPermission "*", "read,write";
    permission java.io.FilePermission "${catalina.base}/webapps/nexus/localhost/nexus/WEB-INF/plexus.properties", "read";
    permission java.io.FilePermission "${catalina.base}/webapps/nexus/localhost/nexus/WEB-INF/plexus.xml", "read";
    permission java.io.FilePermission "${catalina.base}/webapps/nexus/WEB-INF/log4j.properties", "read";
    permission java.io.FilePermission "${catalina.home}/sonatype-work", "read,write";
    permission java.io.FilePermission "${catalina.home}/sonatype-work/-", "read,write,delete";
    permission java.lang.RuntimePermission "getenv.*", "";
    permission java.lang.RuntimePermission "defineClassInPackage.java.lang", "";
    permission java.lang.RuntimePermission "createClassLoader", "";
    permission java.lang.RuntimePermission "setContextClassLoader", "";
    permission java.lang.RuntimePermission "accessDeclaredMembers", "";
    permission java.lang.RuntimePermission "modifyThread", "";
    permission java.util.logging.LoggingPermission "control", "";
};

Copy these rules into 60nexus.policy file and place it in /etc/default/tomcat5.5. Restart of JVM is required to make these rules effective.

The line:

permission java.io.FilePermission "/", "read";

is redundant with other rules. The need of reading the whole filesystem seems to be a security flaw. I hope it will be eliminated in future nexus releases. I will fill the bug for this.

These security rules should work ok not only on debian, but also on any other system where tomcat is deployed. There are two system properties in use: catalina.home and catalina.base. This seems to be debian specific. In case of other systems catalina.home should be enough.

Nexus would create sonatype-work directory in user.home which is /usr/share/tomcat5.5 in case of debian. However with security manager we have to create it by ourselves.

host# mkdir /var/opt/sonatype-work
host# chown tomcat55:adm /var/opt/sonatype-work
host# ln -s /var/opt/sonatype-work /usr/share/tomcat5.5

The /var/opt/sonatype-work will become storage which should be backed up carefully when nexus is used not only as proxy, but also as local maven repository.

Now we can download the latest nexus from http://nexus.sonatype.org/using/download.html

Create logging.properties file with the following contents:

org.apache.juli.FileHandler.level = WARNING
java.util.logging.ConsoleHandler.level = WARNING

and put it into WEB-INF/classes inside the war.

Without this modification nexus would log every single HTTP request on console which would be redirected to catalina.out log file. To much verbose default logging seems to be another nexus bug.

Strip the version number from war file, stop tomcat with:

host# /etc/init.d/tomcat5.5 stop

Put nexus.war in /var/lib/tomcat5.5/webapps.

host# /etc/init.d/tomcat5.5 start

Nexus should be visible at http://debianhost:8180/nexus/

Upgradges should be as easy as putting new nexus war in webapps.

2008/09/13

GWT Module DTD

GWT modules are defined in special XML format. Developer of a new module has to maintain such file as well as module's java source code. Documentation of the GWT project explains each option which can be put in module descriptor, however one thing is missing there - reference to XML Schema or DTD.

Appropriate DTD has been submitted some time ago, and you can find it here. In order to use it in your own modules just add this DOCTYPE to your module xml file :

<!DOCTYPE module SYSTEM "http://google-web-toolkit.googlecode.com/svn/releases/1.5/distro-source/core/src/gwt-module.dtd">

2008/06/18

Eclipse Ganymede - rejoicing in virility

Origins of the meme

The phrase "rejoicing in virility" is translated etymology of term ganymede. Ganymedes was the most handsome among mortals - a mythical hero of ancient Greek cluture.

Term ganymede is associated with some memes - probably quite selfish ones. As long as they are referred in this post and as they are understood by readers of this post I assume the last statement being proved. :) In evolution of culture some old memes die, some other are born, some other gain a new life.

Memes of ancient Greek culture often influence birth of new memes and then persist somehow within new ideas. Soon after Galileo discovered moons of Jupiter, one of them was named Ganymede.

A new meme associated with term Ganymede has been born recently. I suppose it's life will be relatively short (about year), although very intensive. For sure it will cause creation of new memes.

If I was asked some time ago what eclipse is, I would not have much problem with the answer - another Java IDE. Now eclipse is much more. We can call it a platform for hosting different development components. Every day connotations of the term eclipse grow like branches of a big tree.

As eclipse is astronomical term, the ganymede used for naming software follows this convention. If I was asked what this Ganymede is I would say: it is an attempt to steer some specific evolutionary process associated with software development. An attempt to stop this evolution for a while. An attempt to match different software projects in the shape they interoperate the best. There is a reason the platform is called ecosystem.

It is not the first time that Eclipse Foundation freezes the evolution at some specific stage. It is called "simultaneous releases" and so far we had two previous releases of this kind also named after moons of Jupiter - Calisto and Europa.

This introduction was long and boring. :) What really interest me as [not-so-]pragmatic programmer, and probably interests you who is reading this post right now, is a comparison between Ganymede and Europa.

Downloading

Ganymede could be downloaded from a new site. What is nice here - special link for downloading Linux AMD64 version. Finding proper version for this platform was a pain in the past. I have downloaded Mac OS X version numbered as RC3.

Launching

I have checked that the Mac OS X version comes with eclipse.ini file adjusted for more realistic usage scenario

-Xms40m
-Xmx512m
-XX:MaxPermSize=256m

Good, I won't have to tweak it by hand. It was probably fixed also in the latest Europa bundles, but for sure not in the initial ones.

During eclipse start I spotted new splash screen, quite interesting to see what else could be arranged with the same conceptual graphical elements and the same color scheme.

My workspace seems to be upgraded quite smoothly. From the first sight I cannot see anything new in eclipse appearance. Although generally being liberal I tend to be conservative on some topics. One of them is look and behavior of tools I am using and I got use to. It is not about software only. It could be about hammer or screwdriver, any extension of human body or human mind. :)

Installing plugins

Although version Eclipse IDE for Java EE Developers provides quite comprehensive development environment there are still some missing futures I use on day to day basis.

Installation of eclipse plugins has been completely redesigned. Now it is simpler and clearer and works without much ambiguity as it use to be. New option of Automatic Updates was added to general eclipse preferences, nice. However there seems to be some software update related bug in RC3, eclipse is trying to install the same upgrades forever. Fortunately when I came back to eclipse.org there was RC4 release available which upgrades without any problem.

I see only one drawback comparing to previous Software Updates functionality. Selecting plugin to install will not show brief description. The description could be find in General Information after right clicking and choosing Properties.

Ganymede comes with dozens of new features comparing to Europa. Some of them I have been using already however specifying Update Site manually. Now these releases are synchronized available from predefined sources. I will just name things important to me:

  • Remot System Explorer (included by default in Java EE bundle)
  • SVN Team Provider
  • Usage Data Collector (included by default)

The last feature is quite interesting:

The Usage Data Collector collects information about how individuals are using the Eclipse platform. This information is periodically uploaded to servers hosted by The Eclipse Foundation (though this is configurable). The intent is to use this data to help committers and organizations better understand how developers are using Eclipse.

Target Users of the Data:

  • Users of Eclipse
  • Committers working on Eclipse projects
  • ISVs and organization creating Eclipse based software
  • Enterprise IT departments that make extensive use of Eclipse Foundation
  • Academic researchers that want to study how developer work Data to Be Collected

Captured data is associated with a user through a combination of workstation and workspace ids that are automatically generated by the collector. This identification is not tied to any personal information about the user.

The usage data monitors:

  • Start up and shutdown times of a workspace
  • What is being used and when (timestamp), including
    1. Loaded bundles
    2. Commands accessed via keyboard shortcuts
    3. Actions invoked via menus or toolbars
    4. Perspective changes
    5. View usage
    6. Editor usage

Where possible, the usage data collector also capture the symbolic name and version of the bundle contributing the command/action/perspective/view/editor.

This functionality reminds me Debian Popularity Contents. Did I say something about evolution. It is definitely a kind of convergence.

Subversive plugin is now part of the distribution. Unfortunately it still depends on connectors provided by Polarion. I added:

http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-site/

to my Update Sites, nice feature here (or rather lack of annoyance :) ) - I am not longer forced to provide Site Name - just URL.

I installed SVNKit 1.1.7.

Now it is a time for Maven Integration Plugin plugin, I installed:

  • Maven Integration for Eclipse
  • Maven POM XML Editor
  • Maven: The Definitive Guide book

BTW there is a proposal to create Eclipse Integration for Apache Maven (IAM) under the umbrella of the Eclipse Foundation, great.

I installed additional plugins without any problem:

And now a little bit about new features I can see from the first sight:

New features and other remarks

Unfortunately the most annoying bug (at least for Mac OS X users) of the latest Europa updates remains in Ganymede (I suppose it is connected with SWT). :(

I can see italics text in case of attributes shown in XML editor, interesting.

While browsing available views and perspectives I spotted some interesting things I hadn't tried.

  • Palette - I suppose it is available to support diagram editin
  • Snippets - something new
  • Templates - looks like new interface to the old functionality
  • TCP/IP Monitor - it is from Debug Perspective, great I hope it will replace external sniffer for debugging networking code
  • JPA related views
  • Execution Plan in SQL Development perspective

That's all for now. I hope to write more when I will start using these new features. So far ganymede looks very promising and interesting.

Conclusion

Valueable memes never die. :) Eclipse Foundation is quite good in spreading own memes. It is very interesting to see what kind of "social engineering" is used in order to attract mass attention for products of open source movement . Firefox is a perfect example with todays Download Day 2008.

2008/06/17

Calling method of anonymous class

I though that it is an axiom of Java language specification - one cannot call new method defined in anonymous class outside the scope of this class. I was wrong. :)

public class AnonymousClassMethod {

  public static void main(String[] args) {
    (new Object() {
      void foo() {
        System.out.println("foo");
      }
    }).foo();
  }
}

This code just prints foo

But what is the purpose of such construct. Here is simple example which came to my mind:

public class Caller {

  public static void main(String[] args) {
    System.out.println((new Subject()).getCallerClass());
  }

}
public class Subject {

  public Class getCallerClass() {
    return (new SecurityManager() {
      Class getCallerClass() {
        return getClassContext()[1];
      }
    }).getCallerClass();
  }

}

Crazybob has another example.

2008/06/12

Building GWT module library in maven

GWT module library should be prepared according to specific convention. The part of module source code which is compiled from Java into Java Script, resides in org.foo.module.client package by default. GWT compiler will use Java sources, not compiled Java bytecode, thus it is important to include "client side" sources inside module library jar file. Building proper jar requires some modification to project's standard pom.xml file:

<resources>
  <resource>
    <directory>src/main/java</directory>
      <includes>
        <include>**/client/**</include>
        <include>**/public/**</include>
        <include>**/*.gwt.xml</include>
      </includes>
    </resource>
</resources>

2008/06/07

Sharing GWT project

The Google Web Toolkit distribution comes with very handy tools for seeding new projects. The drawback of this utility is that produced project stub will reference local GWT distribution directory. In case of homogenous development environment like every developer using windows machine, some common convention of keeping GWT distribution on C:\gwt-windows-x.y.z could be introduced. There is still problem when new GWT is released, because path to GWT home is hardcoded in project configuration.

I want to propose a solution based on some eclipse configuration, which will not only ease GWT upgrades, but also allows developers working on different operating systems to share GWT projects. Here is a quick how to:

In eclipse preferences add Classpath Variable named GWT_HOME, and point it to your GWT distribution directory.

Run GWT project creation scripts as usual:

$ projectCreator -eclipse foo-project
$ applicationCreator -eclipse foo-project org.foo.client.FooApp

Edit .classpath and replace:

<classpathentry kind="lib" path="/foo/bar/gwt-mac-x.y.z/gwt-user.jar"/>

with:

<classpathentry kind="var" path="GWT_HOME/gwt-user.jar"/>

Now in eclipse:

  • choose Open Run Dialog
  • select FooApp Java Application
  • go to Classpath tab
  • from User Entries remove reference to gwt-dev-platform.jar
  • click Advanced...
  • choose Add Classpath Variables
  • select GWT_HOME and Extend... to gwt-dev-platform.jar

The FooApp launch configuration should work now. However as you can see it is still platform dependent. To overcome this just duplicate FooApp Java Application twice in Run Dialog, every time renaming it according to destination platform. It should be something like:

  • FooApp-win
  • FooApp-linux
  • FooApp-mac

Each of above launch configurations should have GWT_HOME/gwt-dev-platform.jar in User Entries where platform should be set according to launch configuration suffix.

That's all. You can share the project in your source code repository and enjoy abstract configuration which is not limited to your environment.

Just remember to add -XstartOnFirstThread VM argument in case of mac launch configuration.

2008/03/25

On logging when the control is inverted

Log4j - obtaining logger

How to use log4j in our own code? The answer seems obvious - just initialize static logger instance at the beginning of every class which needs to log something:

import org.apache.log4j.Logger;

public class Foo {

  private static final Logger LOG = Logger.getLogger(Foo.class);

}

This idiom is in fact common convention. Benefits are obvious as well:

  • logging could be set up similarly in many different classes
  • it is initialized as early as possible when the class itself is initialized.
  • duplication of loggers among different instances of the same class is avoided.
  • we have some consistent naming convention (class name) regarding these different loggers of our application

What do I mean by the last point? Quick look at the source code of the Logger class reveals, that there is no "magic" involved, when JVM is calling Logger.getLogger(Foo.class) static method. It is an equivalent of Logger.getLogger(Foo.class.getName()) code snippet which means, that providing class name we are just providing logger name (category).

However the standard approach of using log4j is IMO not appropriate in every situation. Especially server side applications which consist of some interacting components or services could have logging configured better. The approach I want to recommend can be summarized by one sentence:

Class should have provided a logger instead of obtaining the logger itself

Now I will try to explain it.

Subclass - choosing right logger

Lets assume we have some class derived from Foo class:

/**
 * Public interface of abstract monitoring facility.
 */
public interface MonitoringService {
 
//some methods } /** * Base class with some implementation stubs */ public abstract class AbstractMonitoringService implements MonitoringService {   //common code which does logging } /** * Specialized filesystem monitoring facility. */ public class FilesystemMonitoringService extends AbstractMonitoringService {   //specific code which does logging } /** * Specialized database monitoring facility. */ public class DatabaseMonitoringService extends AbstractMonitoringService {   //specific code which does logging }

The logger name should be the same for FileSystemMonitoringService even when logging is performed on the level of AbstractMonitoringService class. Analogously in case of DatabaseMonitoringService. It smoothly points us at the next problem with "traditional" log4j logging approach.

The same class, different logger

Sometimes having different loggers for different instances of the same class is extremely useful. Lets imagine that we have two instances of DatabaseMonitoringService component in our application, each one configured to monitor different database. With traditional log4j approach we will have only one logger, and only one "category" for them. How to differentiate which is logging what?

Where the solution comes from?

I use to work with Apache's avalon framework - the base code for whole bunch of early Java IoC/Dependency Injection containers. The project seems quite dead now, however I still find some aspects of avalon's design interesting. Especially unique dependency injection handling allowing lazy and background component activation and component pools, different component life cycles, component selectors, and last but not least - the way logging was supported within container and its components.

In avalon obtaining logger is just a matter of implementing enableLogging method of the LogEnabled interface. Then a container is responsible of injecting appropriate logger via this method.

The solution does not suffer from the problems described above. However as I sad the avalon project is dead and development of the excalibur project, which have been taking care of avalon's heritage for some time, is quite inactive.

I no longer believe in Dependency Injection techniques introduced in avalon. The main problem is, that developers are forced to use some special interfaces to build their components. They cannot use POJOs. I strongly believe in constructor based DI - the possibility of assigning some service provided as component dependency to some field, and declaring this field as final. It is the most logical DI solution to me.

The solution - logger passed in constructor

In order to solve all the issues with logging which are described above, I want to propose new idiom for logging (not only log4j logging).

public class Foo {

  private final Logger logger;

  public Foo(Logger logger) {
    this.logger = logger;
  }

}

In case of abstract classes the logger field should be declared as protected. In the specific implementation, a logger instance should be also injected via constructor, and then passed to underlaying abstract class.

public abstract class AbstractMonitoringService implements MonitoringService {

  protected final Logger logger;

  public AbstractMonitoringService(Logger logger) {
    this.logger = logger
  }

}

public class FilesystemMonitoringService extends AbstractMonitoringService {

  public FilesystemMonitoringService(Logger logger) {
    super(logger);
  }

}

The only problem now is how to force specific container to pass logger as a constructor dependency? I made such small container myself. I hope to publish it on open license soon (although being very small it has much more unique features). I hope it is possible to use this "logging approach" with different IoC containers like Spring or Pico Container? I hope to get some comments from people who could verify this. :)

2008/02/19

JIRA with security manager

We have tried many issue/bug tracking systems so far: scarab, mantis, bugzilla, trac, just to name a few. Personally I really like the last one with very nice wiki syntax, and a lot of plugins. Trac would be my issue tracker of choice for open source projects, however for the company like NCDC it is not sufficient. This is the reason why we bought JIRA.

JIRA deploys quite nicely in many different containers. Unfortunately not in standard debian's tomcat which has security manager turned on. We spent some time trying to figure out which permissions are required. I thought being very smart performing remote debugging of tomcat instance with JIRA deployed. I just set breakpoints in all the constructors of SecurityException. :)

Eventually I came across java.security.debug property. :)

There is appropriate issue on JIRA's JIRA :) I posted our established solution policy file in this ticket. I hope it will be covered by documentation one day.

I discovered another issue after messing with configuration a little bit more.

2008/02/01

Java2Html converter

In the future I will post some java source codes here. Thus I am testing Java2Html converter. There is eclipse plugin as well. Here is an example of generated html:

/*
* Copyright (c) Xemantic
*/
package foo;

/**
* Test class.
*
<p>
* Created on Feb 1, 2008
*
*
@author Kazimierz Pogoda
*
@version $Id$
*/
public class Foo {

 
/**
   * Test static field.
   */
 
public static final String STATIC_FIELD = "42";

 
/**
   * Test method
   */
 
public void bar() {
   
System.out.println("Hello world");
 
}

}