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/07/13

Finding duplicates in array of integer numbers

Some time ago I spotted job offer (polish) posted by a friend of mine. Marek initiated a start up company and now is looking for a new member of his team. The offer is very interesting because it contains a kind of "applicant sieve". :)

There is a task to do for a person who wants to apply - algorithm implemented in any language which solves the following problem:

Having integer numbers array of size N which contains values from range 1 to N, find if there are any duplicated values.

The problem is quite interesting because there are many possible solutions of different properties. Though I am not looking for a new job, I tried to solve the problem. Simple solutions are quite obvious, others which could be called "optimal" become much more complicated. When taking some restrictions into account like O(n) computational complexity, O(1) memory consumption and so on, the solution becomes strightforward. I wonder if it is possible to write an algorithm which will take all restrictions into account and will treat the input array as read-only structure. I tried to implement it, but I failed. :(

In order to achieve the goal I started with testing code. Having some different algorithms I decided to compare their "real life" effectiveness. As you probably know microbenchmarking is loosely connected with real life. :) Anyway writhing them is a good fun. I decided to put everything as open source project called finding-duplicates. I hope Marek won't be angry - the project is spoiling his offer. :) The task was posted some time ago, I hope he has employed someone already. I am quite surprised by the reactions this offer has caused when mentioned on Jacek Laskowski's blog. This is the reason I hope that some people could be interested in my project. I hope that all this buzz will sooner or later bring Marek more candidates. :)

If you have more "optimal" solution then one collected here, just send it to me, or better drop me a line and I will make you a member of this project. I wonder if I have collected all the possible categories of solutions. Special thantks to Adam Woźniak for his implementation. :)

With one additional assumption - array elements are less then N - it would be possible to use algorithm described here, and here. Probably it could be somehow adapted to Marek's problem. For example by adding "virtual" last element to the array. It should has the value less then N (it could be even random number) if we find duplicate and its value is the same as the last element value, then one more pass through the array would be required. Any ideas?

2008/06/26

Maven Integration for Eclipse and ClassNotFound exception

I have been using Maven Integration for Eclipse plugin for some time and I am very fond of it. It is awesome. I imagine there is no a single solution to the problem of bridging two java project meta-descriptors - maven's represented by pom.xml and eclipse's represented by artifacts like .classpath and .project. The way it is implemented in this plugin is just awesome.

There was only one problem I have encountered while using m2eclipse plugin. After upgrade to 0.9.4 release, my eclipse-maven projects stopped working with ClassNotFound exception when being run from eclipse as whether Applications or JUnit tests. It was caused by a change introduced in default eclipse output folders for maven projects. It use to be target-eclipse/classes and is target/classes now - just like standard maven output directory. There is a rationale behind this change.

In order to fix the problem just select a project and choose Maven > Update Project Configuration from context menu. I've spent some time trying to understand what is going on - probably some kind of warning should be shown in case of projects with legacy paths. I hope this entry could help someone having similar problem.

m2eclipse plugin is on a good way to become a project under eclipse umbrella, great.

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/04/08

Time Machine backups on SMB share

Finally I managed to perform network Time Machine backups.

Despite the fact that network Time Machine backups were advertised by Apple before Leopard launch, this functionality has been disabled just before the release. I don't want to speculate about true reasons behind this move. There are some rumors that it was because of new apple's Time Capsule product and an attempt to bind network backups of Mac OS X to this device. Could be partially, however problem seems to be technical, not economical.

Network TM backups are disabled by default, however turning this feature on is quite simple, it is enough to run in Terminal:

defaults write com.apple.systempreferences TMShowUnsupportedNetworkVolumes 1

In my case one more required step was to create sparse image bundle for the backup named in pattern

hostname_mac address without separators

, on the destination backup share.

(Update: you might be interested in precise command for creating sparse image bundle.)

This kind of backup use to be potentially unstable - there is an apple forum post regarding this issue. The problem seems to be fixed now with the latest TimeMachine and AirPort update. Probably this bug was an original rationale behind disabling network TM backups when the Leopard was released. Are there any more obstacles for network TM backups? If not - apple, please make network volumes appear in TM's drive chooser by default. Also the need of preparing sparse image bundle in order to make a backup seems to be too difficult for many Mac OS X users. Is it made for purpose? I believe there is still some technical issue behind. The only thing that worries me is backup instability. :(

2008/03/26

Gimp, XQuartz, Gtk+ for Mac OS X and OpenOffice Aqua on Leopard

I wanted to have gimp on my mac. As it was suggested on the Wilber loves apple site, I also installed XQuartz - X11.app improved comparing to version shipped with leopard. It works fine. With this little hack I was even able to get rid of the most annoying feature of some X11 apps running on Mac. :)

While browsing WLA forum I found information, that there is native OS X gtk port which allows to build almost fully useable gimp - very interesting.

Unfortunately after X11.app upgrade OpenOffice stopped working. :( It is still possible to run it with console, but not from the icon. Looking for the solution I found more interesting OS X resources:

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/13

Mac OS X apps I am using

I am still running tiger on my MacBook. Now I have no time, to put any effort in upgrading to leopard, however sooner or later I will do this. I am writing down the list of applications I am using on tiger, just to know what should I install on leopard. I don't want to perform an upgrade, rather install everything from scratch. Kind of Windows approach? Definitely - Mac OS X is Unix but definately not Unix of debian distro paradigm, with all the apt and aptitude goodies. Lets take MacPorts as an example. They are so messy in managing library dependencies. Some cyclic dependencies result in permanent grow of installed versions of the same library.

One thing I am sure - I will create small partition for Ubuntu, when installing leopard. I hope the same partition could be used by BootCamp and Parallels.

And here is the list:

  • Thunderbird
  • Eclipse
  • Firefox
  • Adium
  • Inkscape
  • Mplayer
  • Skype
  • last.fm
  • SQLDeveloper
  • SSHKeychain
  • Stickies
  • JDeveloper
  • Cisco VPN Client
  • Smultron
  • OpenOffice
  • MS Remote Desktop Connection
  • X11
  • TaskCoach
  • Lyx
  • Gimp
  • Amua
  • Chicken of the VNC
  • Cyberduck
  • Disk Inventory X
  • Google Earth
  • Google Notifier
  • iRed Lite
  • MacSaber :)
  • Reader Notifier
  • Second Life
  • Tinker Tool
  • UnRarX
  • Lingon
  • MacPorts
  • Deep Sleep - real hibernation istead of suspension, means no battery is consumed on powering the memory

Update: there is no need of using SSHKeychain anymore - leopard has this functionality built in and integrated with system keychain - great.

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");
 
}

}