24 February 2006

MacBook Pro vs Dell Pentium M w/ Ubuntu Linux


Matt Raible documents his experience with unwrapping his new Duo Core MacBook Pro.

For grins, I decided to compare his performance measurements with my 10-month old Dell Inspiron 9300 laptop. Obviously this test is far from scientific. Anyway, here are my specs:

Dell Inspiron 9300
Intel Pentium M @ 2Ghz
2Gb RAM
60gb 7200 RPM HDD
Ubuntu Linux 5.10 w/ Kernel 2.6.12-10-686

This laptop cost less than $3K in April 2005. Here is the precise cpuinfo specs:
vendor_id : GenuineIntel
cpu family : 6
model : 13
model name : Intel(R) Pentium(R) M processor 2.00GHz
stepping : 8

And here are my results. Note: I ran each test 4 times.

ant clean package-web
16 seconds
14 seconds
13 seconds
13 seconds

ant setup test-all
1 minute 25 seconds
1 minute 21 seconds
1 minute 23 seconds
1 minute 23 seconds

His results on the new MacBook Pro were 12 seconds for the first test and 1 minute 28 seconds for the second test.

Conclusion? Its all about the file-system and cacheing. Running OS X or Linux greater improves file IO, 2 Gb RAM allows the OS to aggressively cache disk access and a 7200 RPM HDD offers substantial performance improvements when it does have to hit the disk.

In my opinion CPU and clock speed matters the least.

Here is how I reproduced his tests:
Prerequsite:
* Mysql installed and running;
* CATALINA_HOME environment variable pointing to Tomcat 5.5 installation

cvs -d :pserver:guest@cvs.dev.java.net:/cvs login
cvs -d :pserver:guest@cvs.dev.java.net:/cvs checkout appfuse
cd appfuse
ant clean package-web
ant clean package-web
ant clean package-web
ant clean package-web
ant setup test-all
ant setup test-all
ant setup test-all
ant setup test-all

09 February 2006

Maven2 and xdoclet and antrun

I found it very difficult to get the maven2 xdoclet plugin to generate my struts config xml file.

I first tried this

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>xdoclet-maven-plugin</artifactId>
<version>1.0-alpha-2</version>
<executions>
<execution>
<configuration>
<tasks>
<webdoclet destdir="target/generated-sources/xdoclet" mergedir="src/main/xdoclet" verbose="true">
<fileset dir="src/main/java"/>
<strutsconfigxml validatexml="true" version="1.1" destinationFile="struts-config.xml" />
</webdoclet>
</tasks>
</configuration>
<phase>generate-sources</phase>
<goals>
<goal>xdoclet</goal>
</goals>
</execution>
</executions>
</plugin>


which procedded to generate an empty struts-config.xml (well, it merged in my merge files but I had no actions or forms). It turns out that since my Forms and Actions inherit from a sub-class defined elsewhere, that class must be available in the classpath of the plugin. Unfortunately, there does not seem to be a way to modify a plugin's classpath.

I tried adding dependencies to the plugin, but none of that worked.

I tried the xdoclet2 maven2 plugin; it produced garbage struts-config.xml files; it seems to screw up the merge files.

I finally settled on using the antrun plugin to use the ant tasks. This allowed me to modify the webdoclet's classpath:

<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<configuration>
<tasks>
<taskdef name="webdoclet" classname="xdoclet.modules.web.WebDocletTask" classpathref="maven.compile.classpath" />
<webdoclet destdir="${project.build.directory}/generated-sources/xdoclet" mergedir="src/main/xdoclet" verbose="true">
<fileset dir="src/main/java" />
<strutsconfigxml validatexml="true" version="1.1" destinationFile="struts-config.xml" />
</webdoclet>
</tasks>
</configuration>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>

What do you know, it worked!

07 February 2006

Struts Menu - Velocity Rendering


Struts Menu Tag Library - Overview

I recently started using Struts-menu to replace a home-grown menu system. It works well, although there were a couple of small speedbumps along the way, mostly with the Velocity rendering:

  1. Velocity rendered didn't invoke my custom permissions adapter for all menu items; it only checked one level deep.

  2. The Velocity renderer modifies the application-scoped menu definition when checking permissions; thus if permissions are on a per-user (i.e. per-session) basis, each user trashes the other users' menus.

  3. I also found that I couldn't really define a menu that was a Struts action in another module; the menu always appended the current module to the generated link.


To solve (1) I modified the VelocityMenuDisplayer to recurse into all levels. I submitted a JIRA issue with a patch: http://issues.appfuse.org/browse/SM-2

To solve (2) I defined a Session-listener (very similar to MenuContextListener) that loaded the menu definition into session scope. The taglib is already coded to find the menu definition at the lowest scope, so it picked it up from there.

To solve (3) I added a "module" attribute to the menu and modified the taglib to compute the URL with the module (if any). I submitted a JIRA issue with a patch: http://issues.appfuse.org/browse/SM-1

Here is my session-scoped listener. There is a lot of duplication with the MenuContextListener class.


import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import net.sf.navigator.menu.MenuRepository;
import net.sf.navigator.util.LoadableResourceException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* Session listener for loading Struts-menu into session.
* <p>
* This is necessary since the Velocity displayer trashes the menu based on permissions.
* Thus we can't store it in application scope.
* </p>
* @author Tim Morrow
* @since Feb 6, 2006
*/
public class MenuSessionContextListener implements HttpSessionListener {

private static final Log log = LogFactory.getLog(MenuSessionContextListener.class);

private static final String DEFAULT_MENU_CONFIG_LOCATION = "/WEB-INF/menu-config.xml";

public void sessionCreated(HttpSessionEvent event) {

if (log.isDebugEnabled()) {
log.debug("Starting struts-menu initialization");
}

String menuConfig = DEFAULT_MENU_CONFIG_LOCATION;

// check for menuConfigLocation context-param
String override = event.getSession().getServletContext().getInitParameter("menuConfigLocation");
if (override != null) {
if (log.isDebugEnabled()) {
log.debug("using menuConfigLocation: " + override);
}
menuConfig = override;
}

MenuRepository repository = new MenuRepository();
repository.setLoadParam(menuConfig);
repository.setServletContext(event.getSession().getServletContext());

try {
repository.load();
event.getSession().setAttribute(MenuRepository.MENU_REPOSITORY_KEY, repository);

log.info("struts-menu successfully loaded into session scope from " + menuConfig);

} catch (LoadableResourceException lre) {
log.fatal("Failure initializing struts-menu: " + lre.getMessage());
}
}

public void sessionDestroyed(HttpSessionEvent event) {
event.getSession().removeAttribute(MenuRepository.MENU_REPOSITORY_KEY);
}

}


Usage is the same as the servlet context MenuContextListener:

<listener>
<listener-class>MenuSessionContextListener</listener-class>
</listener>