2011-08-11

IzPack standalone compiler: Custom langpacks

See my first post for a general introduction.

In this post, I discuss how to include custom langpacks in the installer when using the standalone-compiler.jar.

NOTE: The IzPack documentation talks about custom langpacks and how to reference them in your installation file. However, these langpacks are limited, and do not provide the ability to customize all the text strings used by an IzPack-based installer and uninstaller.

If you use the normal IzPack installation to create your installer, to customize the text strings for a given language, you edit/replace the appropriate XML file under bin/langpacks/installer of the IzPack installation. When creating an installer with IzPack, IzPack copies the files in that location into the the installer jar created, and if an uninstaller is created, they will be included in it also. Which files are copied is based upon the langpack setting(s) in your installation file.

For standalone-compiler.jar usage, all that is required is create the sub-tree bin/langpacks/installer in some directory, and place your customized language files in it.

If you are using the izpack ant task, just include the directory that contains the sub-tree in the classpath when defining the task, and you are good to go. For example:

<taskdef name="izpack"
classname="com.izforge.izpack.ant.IzPackTask">
<classpath>
<pathelement location="${project.build.rc-install}"/>
<pathelement location="${contrib.izpack.dir}/standalone-compiler.jar"/>
</classpath>
</taskdef>

In the above, ${project.build.rc-install} represents the pathname to the directory containing the bin/langpacks/installer sub-tree.

IzPack standalone compiler: Registering custom listeners

IzPack is an open source Java-based software installer. In a project I work on, I use it to create the installer for the project by using the standalone-compiler.jar, and things works pretty good.

One problem though is that for certain customizations tasks, the IzPack documentation is oriented in using an IzPack installation and its tree structure vs standalone-compiler.jar usage. This, post is the start of ways I have found to leverage the customization features of IzPack, but sticking with the standalone-compiler.jar.

Note, I'm working with IzPack 4.3.0, so no guarantees if the methods I describe are applicable to other versions.

In this first post, I figured out how to register a custom listener. In my case, I needed an uninstaller listener. The IzPack documentation for custom action discusses how to implement a listener, but the instructions, and previously noted, is based on working with a regular IzPack installation vs standalone-compiler.jar.

For standalone-compiler.jar, you still need create your listener class, and it must implement the appropriate interface. Since I needed an uninstall listener, I extended com.izforge.izpack.event.SimpleUninstallerListener. For sake of this blog post, my listener class is com.earlhood.izpack.MyUninstallListener.

I compile the class and jar it up in a file called MyInstallListener.jar.

In my IzPack installation file, I add the following tag within the
<listeners> element:
<listener uninstaller="MyUninstallListener"

jar="${path.to.dir.containing.my.jar}/MyUninstallListener.jar"/>

where ${path.to.dir.containing.my.jar} is the pathname to where the jar file is located.

IMPORTANT: The uninstaller attribute value must be the basename of the class. IzPack scans the jar file to find any .class entry whose basename matches this value. The package name is irrelevant for purposes of IzPack finding the .class file representing the listener.

NOTE: The jar attribute is undocumented. I discovered it when examining the IzPack source.

That is basically it. Of course, I have Ant build scripts to automate the entire build process and use the izpack ant task to create the project installer.

2011-04-18

Dynamically changing log4j levels in web application

Log4j is a popular logging library for Java, and I've been using it for many years.

One thing I have found handy, especially with web applications, is the ability to dynamically change the logging level (like to DEBUG) of any category (aka logger) in a running application. I can selectively choose which components I want to change w/o affecting the logging level of other components.

A long time ago, I wrote a servlet to provide this capability, but it requires registering in web.xml and it depends on some utility classes. Although this is generally sufficient, I'm recently working on a project where adding my own custom servlets to the application is awkward, but dropping in a JSP can be done easily. Plus, since servlet engines (e.g. Tomcat) generally support dropping in a JSP at any time, having a JSP allows setting of logging levels w/o having to modify an application's web descriptor.

As a quick hack, I created a JSP version of the servlet, one that is self-contained. The JSP may not be a good example of good JSP coding style since I wanted to spend minimal time in getting things to work. The JSP is self-contained, requiring no external dependencies except log4j.

The JSP can be downloaded from the following location:

http://www.earlhood.com/blogspot/files/log4j.jsp

The interface is simple, but it does the job. When started, it will list out all the logging categories that are currently defined, with each a link to an edit form to change its logging level.

If you need to set the logging level for a category not yet loaded, you can select any other category and then edit the Category field to the category name you desire before submitting the form.

Categories that have their level explicitly set will have the level rendered in bold. Categories that have an inherited value will have the applicable level rendered in italics.

2011-03-22

Detecting when DOM node comes into view with Dojo

Working on a project that uses dojo, the need arose to have the ability to automatically be notified when a DOM node comes into view in the browser window. For example, the node may below the fold, and when the page is scrolled, and the node comes into view, the application is notified.

Searching around, I came across this useful post:

http://www.dustindiaz.com/element-scroll-into-view/

However, the code uses YUI, while I needed something that works with dojo (v1.4). Also, what Mr. Diaz provides does not deal with resize events that can cause a node to become visible, or the case when the node is already visible (before any scroll or resize occurs).

So I wrote up a mini-library to provide something that works with dojo. A couple of the utility functions can probably be replaced if using a later version of dojo, but since I needed something to work with dojo 1.4, I could not use newer convenience functions to access window dimensions (like dojo.window.getBox).

Basic usage:
dojo.require('ewh.nodeview');
ewh.nodeview.connect(domNode, func, cdata);

domNode is the DOM node that you want monitored.
func is the function that is called when domNode comes into view.
cdata is an arbitrary object to pass into func when it is called.

Note: Some may say that call-data can be attached to func itself and/or use dojo.hitch(), but I wanted to provide an interface that was friendly to those who may not be familiar with such techniques.

When func is called, it is passed an object. The object contains the following properties:
  • node: The DOM node.
  • cdata: Callback object.
  • event: Associated event object, which can be undefined.
The function is only ever called once. Once called, the internal event hooks are disconnected. If for whatever reason the caller needs to be notified again for the node, they can call the connect method again for it.

Source code:
http://www.earlhood.com/blogspot/files/nodeview.js