<![CDATA[Ninth Avenue Software]]> http://www.rssboard.org/rss-specification <![CDATA[Tomcat 6 vs Tomcat 7 Threads]]>

The blue line is max threads, the green area is used threads. The same code is run on Tomcat 6 and Tomcat 7.

Read more...

]]>
http://www.ninthavenue.com.au/tomcat-6-vs-tomcat-7-threads http://www.ninthavenue.com.au/tomcat-6-vs-tomcat-7-threads Sun, 8 Apr 2012 11:04:42 +1000
<![CDATA[ServletRequest.setCharacterCoding() Ignored]]> Take a look at this block of servlet code and see if you can tell me what the output should be when I send x=éééé

Log.warning(Charset.defaultCharset().toString());
Log.warning(request.getCharacterEncoding());
Log.warning(request.getParameter("x"));
request.setCharacterEncoding("UTF-8");
Log.warning(request.getCharacterEncoding());
Log.warning(request.getParameter("x"));

Well, here is the output

UTF-8
null
éééé
UTF-8
éééé

Compare this code

Log.warning(Charset.defaultCharset());
Log.warning(request.getCharacterEncoding());
request.setCharacterEncoding("UTF-8");
Log.warning(request.getCharacterEncoding());
Log.warning(request.getParameter("x"));

Which gives us something more sensible:

UTF-8
null
UTF-8
éééé

Lesson of the day?

You can't change the request encoding after request.getParameter() has been called.

In my case a third-party filter was causing the damage, so I made a new filter at the top of the chain just to call request.setCharacterEncoding(). Note also that the default character encoding which I set with -Dfile.encoding=UTF-8 had no effect on the decoding of request parameters. Also, the form is POSTed with multipart/form-data and I added accept-charset to force the browser to send UTF-8:

<form method="post" enctype="multipart/form-data" accept-charset="UTF-8" >
  <input type="text" name="x"/>
  <input type="submit"/>
</form>

Read more...

]]>
http://www.ninthavenue.com.au/servletrequest-setcharactercoding-ignored http://www.ninthavenue.com.au/servletrequest-setcharactercoding-ignored Mon, 2 Apr 2012 15:57:59 +1000
<![CDATA[Upgrading To The Java EE 6 Web Profile]]> Here are my notes from our upgrade of the Sunburnt SEO software to the Java EE 6 Web Profile. Previously our stack was pretty similar to Java Web Profile, just with a lot more dependencies than is now necessary with EE 6.

We can now deploy to Glassfish 3.1 or a modified Tomcat 7.0, since we aren't using the EJB features of Java EE 6.

Code Changes

persistence.xml is now version 2.0

<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
             http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

web.xml is now version 3.0

<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="3.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

Remove vendor-specific JPA annotations.

  • //@Index
  • //@ForeignKey
  • //@ElementForeignKey
  • //@ContainerTable
  • //@PersistentMap
  • //import org.apache.openjpa

Read more...

]]>
http://www.ninthavenue.com.au/upgrading-to-the-java-ee-6-web-profile http://www.ninthavenue.com.au/upgrading-to-the-java-ee-6-web-profile Wed, 21 Mar 2012 13:21:45 +1000
<![CDATA[java.lang.ClassFormatError Exception With EclipseLink Static Weaving [SOLVED]]]> Here's an interesting exception that slapped me when I tried out using the EclipseLink static weaver on against a fresh Maven pom.xml for Java EE Web projects. The same exception occurs with the OpenJPA enhancer.

Executing tasks
     [java] Exception in thread "main" java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/persistence/ValidationMode
     [java] 	at java.lang.ClassLoader.defineClass1(Native Method)
     [java] 	at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
     [java] 	at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
     [java] 	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
     [java] 	at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
     [java] 	at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
     [java] 	at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
     [java] 	at java.security.AccessController.doPrivileged(Native Method)
     [java] 	at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
     [java] 	at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
     [java] 	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
     [java] 	at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
     [java] 	at org.apache.openjpa.persistence.PersistenceProductDerivation.configureBeanValidation(PersistenceProductDerivation.java:241)
     [java] 	at org.apache.openjpa.persistence.PersistenceProductDerivation.beforeConfigurationLoad(PersistenceProductDerivation.java:214)

It turns out this obscure error is because the default Java EE jars do not contain any actual code. To fix it, change your Java EE dependencies from

    <!-- Java EE libraries -->
    <dependency>
      <groupId>javax</groupId>
      <artifactId>javaee-web-api</artifactId>
      <version>6.0</version>
      <scope>provided</scope>
    </dependency>

to

    <!-- default Jave EE jars don't include code necessary fo
         bytecode enhancement so we use these instead -->
    <dependency>
      <groupId>org.jboss.spec</groupId>
      <artifactId>jboss-javaee-6.0</artifactId>
      <version>1.0.0.Final</version>
      <type>pom</type>
      <scope>provided</scope>
    </dependency>

You will also need to add the JBoss repository to your pom.xml if you aren't already using it:

  <repositories>
    <repository>
      <id>repository.jboss.org-public</id>
      <name>JBoss repository</name>
      <url>https://repository.jboss.org/nexus/content/groups/public</url>
    </repository>
  </repositories>

Read more...

]]>
http://www.ninthavenue.com.au/java-lang-classformaterror-exception-with-eclipselink-static-weaving-solved http://www.ninthavenue.com.au/java-lang-classformaterror-exception-with-eclipselink-static-weaving-solved Mon, 19 Mar 2012 04:48:29 +1000
<![CDATA[java.lang.ClassNotFoundException: com.sun.el.lang.VariableMapperImpl [Fixed] for Glassfish JSF]]> Using Glassfish 3.1.2, JSF 2.1.x and Facelets with client side state saving, if you pass a bean reference by EL and try to dereference that expression you will get the following error:

Servlet.service() for servlet Faces Servlet threw exception
java.lang.ClassNotFoundException: com.sun.el.lang.VariableMapperImpl
	at org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1509)
	at org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1359)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:247)
	at com.sun.faces.renderkit.ApplicationObjectInputStream.resolveClass(ApplicationObjectInputStream.java:95)
	at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1574)
	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1731)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
	at com.sun.el.MethodExpressionImpl.readExternal(MethodExpressionImpl.java:320)
	at java.io.ObjectInputStream.readExternalData(ObjectInputStream.java:1791)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1750)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
	at com.sun.faces.facelets.el.TagMethodExpression.readExternal(TagMethodExpression.java:158)
	at java.io.ObjectInputStream.readExternalData(ObjectInputStream.java:1791)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1750)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
	at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1666)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1322)
	at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1666)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1322)
	at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1666)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1322)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
	at java.util.HashMap.readObject(HashMap.java:1030)
	at sun.reflect.GeneratedMethodAccessor264.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:974)
	at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1848)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1752)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
	at com.sun.faces.renderkit.ClientSideStateHelper.doGetState(ClientSideStateHelper.java:255)
	at com.sun.faces.renderkit.ClientSideStateHelper.getState(ClientSideStateHelper.java:198)
	at com.sun.faces.renderkit.ResponseStateManagerImpl.getState(ResponseStateManagerImpl.java:100)
	at com.sun.faces.application.view.StateManagementStrategyImpl.restoreView(StateManagementStrategyImpl.java:227)
	at com.sun.faces.application.StateManagerImpl.restoreView(StateManagerImpl.java:188)
	at com.sun.faces.application.view.ViewHandlingStrategy.restoreView(ViewHandlingStrategy.java:123)
	at com.sun.faces.application.view.FaceletViewHandlingStrategy.restoreView(FaceletViewHandlingStrategy.java:453)
	at com.sun.faces.application.view.MultiViewHandler.restoreView(MultiViewHandler.java:148)
	at javax.faces.application.ViewHandlerWrapper.restoreView(ViewHandlerWrapper.java:303)
	at javax.faces.application.ViewHandlerWrapper.restoreView(ViewHandlerWrapper.java:303)
	at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:192)
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
	at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:116)
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)

The workaround is to add el-ri.jar to your project. You can do it in maven like this:

    <dependency>
      <groupId>com.sun.el</groupId>
      <artifactId>el-ri</artifactId>
      <version>1.0</version>
      <scope>compile</scope>
    </dependency>

The problem is tracked by the JAVASERVERFACES-1828 bug.

Read more...

]]>
http://www.ninthavenue.com.au/java-lang-classnotfoundexception-com-sun-el-lang-variablemapperimpl-fixed-for-glassfish-jsf http://www.ninthavenue.com.au/java-lang-classnotfoundexception-com-sun-el-lang-variablemapperimpl-fixed-for-glassfish-jsf Sun, 18 Mar 2012 17:34:35 +1000
<![CDATA[Change J2EE Version Of Netbeans Maven Project]]> For Maven projects, Netbeans determines the J2EE version shown in the project properties by looking at the version of web.xml:

  • web.xml 2.4 -> J2EE 1.4
  • web.xml 2.5 -> J2EE 1.5
  • web.xml 3.0 -> J2EE 1.6

You have to restart Netbeans to see the changes.

Read more...

]]>
http://www.ninthavenue.com.au/change-j2ee-version-of-netbeans-maven-project http://www.ninthavenue.com.au/change-j2ee-version-of-netbeans-maven-project Fri, 16 Mar 2012 18:07:39 +1000
<![CDATA[WTF Triple Negative!]]> Check out this JPA parameter:

<exclude-unlisted-classes>false</exclude-unlisted-classes>

Now see if you can tell me if it includes my listed classes.

Read more...

]]>
http://www.ninthavenue.com.au/wtf-triple-negative http://www.ninthavenue.com.au/wtf-triple-negative Fri, 16 Mar 2012 16:44:24 +1000
<![CDATA[How To Show Negative Numbers Using Brackets With NumberFormatter In Java]]> If you want to use parentheses around your negative numbers, you can do it in Java like this:

NumberFormat formatter = NumberFormat.getCurrencyInstance(locale);
if (formatter instanceof DecimalFormat) {
    DecimalFormat f = (DecimalFormat) formatter;
    f.setNegativePrefix("(" + f.getPositivePrefix());
    f.setNegativeSuffix(")");
}
String output = formatter.format(value);

This snippet will retain the localised currency formatting set by NumberFormat.

Read more...

]]>
http://www.ninthavenue.com.au/how-to-show-negative-numbers-using-brackets-with-numberformatter-in-java http://www.ninthavenue.com.au/how-to-show-negative-numbers-using-brackets-with-numberformatter-in-java Thu, 15 Mar 2012 08:46:54 +1000
<![CDATA[How To Check If The Software Keyboard Is Shown In Android]]> Here is a method to detect if the soft keyboard is visible on the screen in Android. All the other methods I have seen test the height of screen elements to guess whether it is displayed. This doesn't work for keyboards like WifiKeyboard which is an invisible keyboard.

This method uses the callback result of InputMethodManager.showSoftInput() to determine if the keyboard status changed. This is suitable for me because I need to call showSoftInput() anyway if the keyboard is not shown. The result from the operation needs to be polled because it is asynchronous. This example only polls 500 milliseconds and assumes that anything longer than that is caused by the keyboard being loaded and rendered.

Here is how the code is used:

// try to show the keyboard and capture the result
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
IMMResult result = new IMMResult();
imm.showSoftInput(editText, 0, result);

// if keyboard doesn't change, handle the keypress
int res = result.getResult();
if (res == InputMethodManager.RESULT_UNCHANGED_SHOWN ||
        res == InputMethodManager.RESULT_UNCHANGED_HIDDEN) {
    showTags();
}

Read more...

]]>
http://www.ninthavenue.com.au/how-to-check-if-the-software-keyboard-is-shown-in-android http://www.ninthavenue.com.au/how-to-check-if-the-software-keyboard-is-shown-in-android Tue, 21 Feb 2012 10:11:44 +1000
<![CDATA[How To Move A Node In Nested Sets With SQL]]> Moving nodes in nested sets is a complex operation. There were a few solutions on Stack Overflow for moving a node under a given parent, however this doesn't let you select the position of the node amongst it's siblings.

This solution lets you move a node to any position in the tree, with just a single input parameter - the new left position (newpos) of the node.

Fundamentally there are three steps:

  1. Create new space for the subtree.
  2. Move the subtree into this space.
  3. Remove the old space vacated by the subtree.

In psuedo-sql, it looks like this:

    /**
     *  -- create new space for subtree
     *  UPDATE tags SET lpos = lpos + :width WHERE lpos >= :newpos
     *  UPDATE tags SET rpos = rpos + :width WHERE rpos >= :newpos
     * 
     *  -- move subtree into new space
     *  UPDATE tags SET lpos = lpos + :distance, rpos = rpos + :distance
     *           WHERE lpos >= :tmppos AND rpos < :tmppos + :width
     * 
     *  -- remove old space vacated by subtree
     *  UPDATE tags SET lpos = lpos - :width WHERE lpos > :oldrpos
     *  UPDATE tags SET rpos = rpos - :width WHERE rpos > :oldrpos
     */

Read more...

]]>
http://www.ninthavenue.com.au/how-to-move-a-node-in-nested-sets-with-sql http://www.ninthavenue.com.au/how-to-move-a-node-in-nested-sets-with-sql Sun, 8 Jan 2012 15:35:39 +1000
<![CDATA[Android ORM / JPA]]> Coming from the server-side, I find it hard to live without ORM (Object-Relational Mapping) such as JPA. Now that I've started writing Android Apps, I set about finding a JPA ORM tool for Android.

Here is a comparison of the tools I found that do ORM and are lightweight enough for use with Android.

Annotations DB Ops Size License Docs Age
OrmLite JPA or custom DAO or Entity 200kb Open docs 1yr
ORMAN JPA-like Entity 170kb Apache2 wiki 2yrs
greenDAO N/A Codegen DAO or Entity <100kb Apache2 docs
ActiveAndroid JPA-like Entity $20 wiki
AndrORM None docs 1yr

"DB Ops" refers to how database operations such as persist() and update() are handled. Normally either by a DAO (data access object) or by the entity themselves.

Handling Large Data Sets

Performance counts - especially since I need to handle large data sets. I don't want to load 3000 records into memory at once when the device only has room to display 10 at a time. Native Android supplies a Cursor to interate large data sets, and some ORM tools provide their own method too.

greenDAO has Query.lazyList() and OrmLite has DAO.iterator(Query) to do this, however Android adapters do not bind to an iterator so a custom adapter would need to be written in any case. There is a thread online that discusses this, however I think I can rig up a something similar to my LazyList for JPA to make this happen.

Verdict

I've started my project with OrmLite because it is the most mature. Lazy loading query results will need some custom code, but in the long run I think it will be better than polluting my code with column names and SQL hacks.

greenDAO was a good candidate from the performance perspective, but really I want to write my Entities myself so I can add the methods that I need.

Read more...

]]>
http://www.ninthavenue.com.au/android-orm-jpa http://www.ninthavenue.com.au/android-orm-jpa Mon, 19 Dec 2011 06:01:48 +1000
<![CDATA[Alt-Tab Shortcuts Broken In Ubuntu Lucid With XModMap]]> I use xmodmap to turn caps-lock into an extra modifier for special keys and shortcuts. Since upgrading finally to Ubuntu Lucid 10.04 LTS, I've had a problem with the Caps-Lock modifier key (Mode_switch) getting stuck when I accidentally press the Shift key. When I get it unstuck by pressing the same combination of Caps, Shift and one of my special keys, all my X-Windows shortcuts like Alt-Tab and Function keys stop working.

It's freaking annoying, however I finally found a workaround in Red Hat Bug 513815 and Bug 508434...

$ setxkbmap -layout jp

This resets your keyboard to it's original state. In my case the layout is japanese. You will probably want 'us' for US keyboards. Now you can reapply your xmodmap settings:

$ xmodmap ~/.xmodmaprc

It's still flaky, but it gets me back on the road.

Read more...

]]>
http://www.ninthavenue.com.au/alt-tab-shortcuts-broken-in-ubuntu-lucid-with-xmodmap http://www.ninthavenue.com.au/alt-tab-shortcuts-broken-in-ubuntu-lucid-with-xmodmap Thu, 15 Dec 2011 06:52:35 +1000