Archive for February, 2012

How to run the Mojarra automated tests

26 February 2012

The JSF RI implementation Mojarra comes with a very extensive test suite. There are some instructions available on how to actually run those tests, such as the entry “How do I run the automated tests?” in the official FAQ and the document “TESTING_A_BUILD.txt” at the root of the Mojarra repository.

Both sets of instructions are not overly detailed and they don’t seem to be entirely up to date either. For instance, the entry in the FAQ states the following:

This target will cause the JSF API and implementation to be deployed to the GlassFish server
that is downloaded as part of the build process

This however doesn’t happen for testing JSF 2.x anymore (there was code that downloaded GlassFish V2 for JSF 1.x, but this can’t be used for 2.x).

The TESTING_A_BUILD.txt document mentions:

Be sure to install glassfish with a password on admin
make sure that password.txt is found in container.home

But how do we install glassfish with a password? If GlassFish is distributed as a .zip there is no install script, and the version with an installer also doesn’t offer any option to specify a password. I guess that there once was an option in the installer for this but it seems to have been removed since. Additionally, the password.txt in container.home appears to be not entirely correct.

After some trial & error I got the tests to run (more or less, read below). For my own reference and in the hope it’ll be useful to someone, I’m jotting the instructions down here.

Download GlassFish 3.1.1 from http://glassfish.java.net/downloads/3.1.1-final.html (I choose the zip archive).

Unzip GlassFish somewhere; we’ll call the resulting directory [glassfish home] below. This will look something like:

glassfish3 <--- [glassfish home]
    bin
    glassfish
    javadb
    mq
    pkg

The tests assume a password is being used, so we're now going to set one:

cd into [glassfish home]/bin and execute the following command:

./asadmin start-domain domain1

On Mac OS X this may take a minute due to a reverse DNS lookup being attempted (there's a fix).

After GlassFish has started, execute the following command:

./asadmin change-admin-password

Press enter twice and enter adminadmin for the password as below:

Enter admin user name [default: admin]> (press enter)
Enter admin password> (press enter)
Enter new admin password> (enter adminadmin)
Enter new admin password again> (enter adminadmin)
Command change-admin-password executed successfully.

Most commands in the test suite that interact with GlassFish use a password file (--passwordfile option), but for some reason not all. For those an additional .asadminpass file is required to be in the home directory of the user as whom the tests are run. This can be created via the following command:

./asadmin login

Press enter once and again enter adminadmin for the password as below:

Enter admin user name [default: admin]> (press enter)
Enter admin password> (enter adminadmin)
Login information relevant to admin user name [admin]
for host [localhost] and admin port [4848] stored at
[/home/youruser/.asadminpass] successfully.
Make sure that this file remains protected.
Information stored in this file will be used by
asadmin commands to manage the associated domain.
Command login executed successfully.

You can shutdown the container now using the following command:

./asadmin stop-domain domain1

Mojarra has recently gone from being distributed as 2 jars to 1 jar. The Glassfish 3.1.1 that you downloaded still uses 2 jars. In the past the test code patched GlassFish, but probably in anticipation of GlassFish shipping with 1 jar this no longer happens. In the mean time, it's necessary to patch GlassFish yourself.

In [glassfish home]/glassfish/domains/domain1/config/default-web.xml and [glassfish home]/glassfish/lib/templates/default-web.xml remove the entries jsf-api.jar and jsf-impl.jar and replace them by a single javax.faces.jar. I.e.:

Replace

jsf-api.jar
jsp-impl.jar
jsf-impl.jar

With

javax.faces.jar
jsp-impl.jar

Make a backup of the resulting [glassfish home] directory now. The test suite occasionally corrupts GlassFish and you often need to restore a fresh version. In fact, to have reliable test results you might opt to use a fresh GlassFish for every test run.

The Mojarra tests depend a lot on Maven, so if haven't installed Maven then install it now. E.g. on Ubuntu:

sudo apt-get install maven2

(This is not needed on OS X, since it already comes with Maven)

Now we're ready to check out the Mojarra source code. I'll assume SVN knowledge here.

Check out: https://svn.java.net/svn/mojarra~svn/trunk

We'll rever to the directory where you checked out those sources as [source home] below. E.g.

 
Mojarra <--- [source home]
    jsf-api
    jsf-ri
    jsf-tools
    [...]
    password.txt
    build.properties.glassfish
    [...]

Prior to starting the tests, a few files need to be customized. First, put the following in [source home]/password.txt:

AS_ADMIN_PASSWORD=adminadmin

Now copy [source home]/build.properties.glassfish to [source home]/build.properties.

Set the following entries in the newly created [source home]/build.properties:

jsf.build.home=[source home]
container.name=glassfishV3.1_no_cluster
container.home=[glassfish home]/glassfish
halt.on.failure=no

For example:

jsf.build.home=/home/myuser/Mojarra
container.name=glassfishV3.1_no_cluster
container.home=/home/myuser/glassfish3/glassfish
halt.on.failure=no

If you haven't already set this up, define JAVA_HOME. This is typically not needed on OS X, but is needed on a e.g. a fresh Ubuntu installation. If you don't do this, Maven will let you think it can't find an artifact from a remote repository, while in fact it couldn't compile some source files.

Additionally set ANT_OPTS to allow more memory to be used. E.g. in Ubuntu (bash):

export JAVA_HOME=/opt/jdk1.6.0_31/
export PATH=/opt/jdk1.6.0_31/bin:$PATH
export ANT_OPTS='-Xms512m -Xmx786m -XX:MaxPermSize=786m'

Now we're *almost* ready to run the build and the test. Unfortunately the Mojarra trunk seems to have a circular dependency between the clean and main targets at the moment. To break this dependency, comment out two ant tasks in [source home]/jsf-test/build.xml (as of writing on line 119):

  1. <!-- ensure the api jar is deployed to the local maven repo -->
  2. <!-- COMMENT THIS OUT:
  3. <ant dir="${api.dir}" target="main">
  4.     <property name="skip.javadoc.jar"  value="true" />
  5. </ant>
  6. <ant dir="${api.dir}" target="mvn.deploy.snapshot.local">
  7.     <property name="skip.javadoc.jar"  value="true" />
  8. </ant>
  9. -->

Now cd to [source home] and execute the following command:

ant clean main

If you're lucky, the build will succeed without failures. Now undo the commenting in [source home]/jsf-test/build.xml, so the file will look like below again:

  1. <!-- ensure the api jar is deployed to the local maven repo -->
  2. <ant dir="${api.dir}" target="main">
  3.     <property name="skip.javadoc.jar"  value="true" />
  4. </ant>
  5. <ant dir="${api.dir}" target="mvn.deploy.snapshot.local">
  6.     <property name="skip.javadoc.jar"  value="true" />
  7. </ant>

cd to [source home] and execute the following command again:

ant clean main

If everything still went correctly, we can now run the tests. There are quite a lot of tests and running the suite till completion took 31 minutes on my 2.93Ghz i7 iMac and 48 minutes on an Ubuntu 11.10 installation running inside VirtualBox 4.1.8 on the same machine. The tests generate a whopping 1.6MB of logging, so if you want to scan it later you might want to divert it to a file:

ant test.with.container.refresh > ~/test.txt

If you want to follow the proceedings of the test run, you can use e.g. tail in a second terminal:

tail -f ~/test.txt

In my case, whatever I tried and however clean my system was, some tests were always failing. E.g. testFormOmittedTrinidad, TestLifecycleImpl, ScrumToysTestCase, AdminGuiTestCase.

Occasionally some tests don't honor the halt.on.failure=no setting that we did in the build.properties files. If this happens comment out the offending test. If you want to test your own changes to Mojarra, make sure to run the test suite a couple of times to get an idea of what tests are already failing for your system. I personally tried a couple of different machines and environments but none of them was able to pass all tests.

Finally, some extra information for Eclipse users. The tests can be run via Eclipse as well. If you initially check out the Mojarra project in Eclipse, you'll see a lot of errors. There are Eclipse project files, but they are obviously outdated (this is fixable, but I'll leave that for a next article). When working with Eclipse, you'll use Eclipse for editing the source code and for navigation (call references, navigate into and such). Even if the Eclipse project files are corrected, the actual compiler output will be thrown away.

To start the ant build via Eclipse, do the following:

Right click on build.xml, click Run As -> Ant Build… Go to the JRE tab and under VM arguments add the following:

-Xms512m -Xmx786m -XX:MaxPermSize=786m

On the same dialog go to the Environment tab and set JAVA_HOME to your installed JDK, e.g.
variable JAVA_HOME, Value /opt/jdk1.6.0_31 (this is not specifically needed on OS X or if you've already set JAVA_HOME globally for your system).

Go to the Targets tab and deselect everything. Then first select clean and then main. The target execution order in the bottom left corner of the dialog should list them in the right order. Having followed the instructions outlined above for command line ant (commenting out entries in [source home]/jsf-test/build.xml) now click Run. Follow the same instructions for restoring the file and again click Run. Finally, deselect both targets and select the test.with.container.refresh target.

Arjan Tijms

Eclipse 3.7 SR2 released!

24 February 2012

With once again an amazing release accuracy, today Eclipse Indigo Service Release 2, aka Eclipse 3.7.2 has been released.

In the core packages, some 89 bugs have been fixed.

Important projects that are part of the release train were updated as well, for instance WTP was updated from 3.3.1 to 3.3.2 (a fact not mentioned yet on the WTP homepage, but it can be found here). WTP 3.3.2 fixes no less than 112 bugs.

My personal favorite bug that has been fixed is 100% CPU for long time in ASTUtils.createCompilationUnit. Just having a fairly innocent page in your workspace would completely hang the CPU for minutes or more.

For the next version of Eclipse we’re supposedly going to get to see the 4.x line by default on the downloads page, so this might well be the last 3.x version that’s prominently featured on said page. Time will tell of course.

For now, Eclipse 3.7.2 can thus be downloaded from the usual place at http://eclipse.org/downloads and the general release notes can be found at http://www.eclipse.org/eclipse/development/readme_eclipse_3.7.2.html

Arjan Tijms

Passing null to the model in JSF

8 February 2012

The problem

JSF allows you to bind an input component to a model bean via a so-called value binding. A notorious major headache is that a null is automatically coerced into a zero (0) when the bounded property is of type Integer or Long. This behavior only seems to rarely be the required one. A number of other types are coerced as well, e.g. in case of Boolean it’s coerced to Boolean.FALSE.

Finding a solution

Although coercing is a literal interpretation of the spec, it seems that basically only Tomcat that implements this somewhat peculiar behavior. They have a setting to turn this off:

-Dorg.apache.el.parser.COERCE_TO_ZERO=false

See e.g. jsf: integer property binded to a inputtext in UI is set to zero on submit

If you’re in a position to use this option, don’t read further and use it.

If you can’t use this option (you have e.g. a big system, lots of testing needed) and a null is needed at only a few places, another option is required. One possibility, that I will describe here, is based on a value-changed listener and a custom tag handler. What we do is breaking up the existing value binding of the input component in a base part and a property part, and then setting a null directly via the Apache BeanUtils library.

The following shows a TagHandler implementation that does this breaking up and installs a value-changed listener on the parent component:

  1. public class MinusOneToNullConverter extends TagHandler {
  2.  
  3.     private static final Class<?>[] VALUECHANGE_LISTENER_ZEROARG_SIG = new Class[] {};
  4.     private static final String LISTENER_EL = "#{minusOneToNullListener.processValueChange(component, %s, '%s')}";
  5.  
  6.     public MinusOneToNullConverter(TagConfig config) {
  7.         super(config);
  8.     }
  9.  
  10.     @Override
  11.     public void apply(FaceletContext ctx, UIComponent parent) throws IOException {
  12.  
  13.         String expression = parent.getValueExpression("value").getExpressionString();
  14.         if (expression.contains(".")) {
  15.             String base = expression.substring(2, expression.lastIndexOf('.'));
  16.             String property = expression.substring(expression.lastIndexOf('.') + 1, expression.length() - 1);
  17.  
  18.             ExpressionFactory expressionFactory = ctx.getExpressionFactory();
  19.  
  20.             ((EditableValueHolder) parent).addValueChangeListener(
  21.                 new MethodExpressionValueChangeListener(expressionFactory.createMethodExpression(ctx, 
  22.                     String.format(LISTENER_EL, base, property),
  23.                     Void.class, VALUECHANGE_LISTENER_ZEROARG_SIG)
  24.             ));
  25.         }
  26.     }
  27. }

Note that the EL expression uses ‘component’ as the first parameter for the processValueChange method. This is an implicit EL object that refers to the current component being processed, which is in the case of this tag the parent component. Implementation wise it’s important to use the FaceletContext as the ELContext, instead of grabbing it from the FacesContext, when creating the method expression. Otherwise the context of the method expression would not be entirely correct and things like <ui:param>s will not be resolved.

The following shows the value-changed listener that will be installed:

  1. @ManagedBean
  2. public class MinusOneToNullListener {
  3.  
  4.     public void processValueChange(UIInput component, Object object, String property) throws AbortProcessingException {
  5.  
  6.         if (component.getValue() != null && component.getValue().toString().equals("-1")) {
  7.             component.resetValue();
  8.             try {
  9.                 PropertyUtils.setProperty(object, property, null);
  10.             }
  11.             catch (IllegalAccessException e) {
  12.                 throw new AbortProcessingException(e);
  13.             }
  14.             catch (InvocationTargetException e) {
  15.                 throw new AbortProcessingException(e);
  16.             }
  17.             catch (NoSuchMethodException e) {
  18.                 throw new AbortProcessingException(e);
  19.             }
  20.         }        
  21.     }
  22. }

As can be seen, the listener uses the input component to check if the value submitted was “-1”. The string representation is used here to be compatible with different types, although there are of course some other possibilities here. The listener will then reset the value of the component, so JSF will not attempt later on to push the -1 to our model object. Finally, bean utils is used to set the actual null value.

In this example, we used -1 to encode the desire for null. Other options might be feasible as well, such as the empty string or perhaps even null itself.

Before using this all, there is the tedious but mandatory registration of the tag handler in a *-taglib.xml file:

  1. <tag>
  2.     <tag-name>minusOneToNullConverter</tag-name>
  3.     <handler-class>com.example.MinusOneToNullConverter</handler-class>
  4. </tag>

Using the ‘converter’

After doing the above, we’re now ready to use this on a Facelet, e.g. :

  1. <h:selectOneMenu value="#{someBean.value}">
  2.     <my:minusOneToNullConverter />
  3.     <f:selectItem itemLabel="ALL" itemValue="-1" />
  4.     <f:selectItems value="#{data.somethings}" var="something" itemLabel="#{something.label}" itemValue="#{something.key}" />
  5. </h:selectOneMenu>

Any other alternatives?

Once again, if on Tomcat, -Dorg.apache.el.parser.COERCE_TO_ZERO=false should be your first choice. If you use an application server that isn’t based on Tomcat, you also probably don’t need this. There’s a spec proposal open that asks to change this behavior, but despite a large amount of votes it hasn’t seen any activity for a long time.

Hopefully the hacky workaround presented here is helpful to someone.

Arjan Tijms

css.php best counter