Wednesday, April 25, 2007

Wicket and Guice

Are you sick of XML? I sure am. While I really like Spring Framework, I am sick of all the XML. Writing unit tests is hard enough, but how do you test XML? Some might argue that it isn't really code and doesn't need testing. Some might be wrong. What I want is a way to write code WITHOUT XML. Two interesting projects have caught my attention: * Wicket * Guice
Wicket - Home: "Welcome to Wicket With proper mark-up/logic separation, a POJO data model, and a refreshing lack of XML, Wicket makes developing web-apps in Java simple and enjoyable again. Swap the boilerplate, complex debugging and brittle code for powerful, reusable components written with plain Java and HTML. * Check the feature list * Read some Wicket buzz or some Wicket blogs * Find out why you should use Wicket * Check out some examples and see them in live action * Download Wicket 1.2.6 Wicket is released under the Apache License, Version 2.0 ."
Guice wholly embraces annotations and generics, thereby enabling you to wire together and test objects with less effort than ever before. Annotations finally free you from error-prone, refactoring-adverse string identifiers. In a nutshell: * Guice empowers dependency injection. * Guice cures tight coupling. * Guice enables simpler and faster testing at all levels. * Guice reduces boilerplate code. * Guice is type safe. * Guice externalizes configuration when appropriate. * Guice lets you compose your application of components which are truly independent. * Guice reports error messages as if they will be read by human beings. * Guice is the anti-static. * Guice is small and very fast.

Friday, April 13, 2007

Felipe Gaucho's Blog: The name is One, JavaONE !

I came across a JavaOne posting that has tips fo rthis attending and for getting the most out of JavaOne. Here is a sample. Be sure and go to the link and look over the comments. Felipe Gaucho's Blog: The name is One, JavaONE !: " # Talk to everyone you can. The people at J1 are for the most part friendly, outgoing and have great experience and tips to share. Just introduce yourself and ask what cool things they do. John Gage (on the years he's there), always makes it a point to remind attendees to talk to one another. If nothing else, you can say, “Dr. Gage told me to talk to you”, and go from there. Breakfast and lunch are great places to talk. Just find a table with some folks, plop down and fire away. Some folks won't be forthcoming, but most are great. Talk to folks in line too: there will be plenty of time for that. # Have a plan of what sessions/BOFs you want to go to. For each, have a backup session/BOF you are also interested in. Sometimes rooms are full and you can't get in, or the speaker is dull or not talking about what you expected. Don't be afraid to just get up and leave for your second choice. # The most comfortable seats are on the ends or front rows. The seats are pretty close together. Usually wall sockets for charging your laptop are on the sides of the room, but sometimes they're all taken. Depending on the room and/or number of attendees, wireless access may or may not be available/reliable. # Unless you want to really immerse yourself in one topic, don't go to sessions that are all on the same track. You'll find them repeating themselves, even though each will have some new material. Diversify and learn about stuff you never even thought about using. J1 is for discovering new stuff and broadening your knowledge. # Take something warm to wear. Some of the session rooms are cold enough to freeze hydrogen. # Make sure you make it to Birds-of-a-Feather sessions as well. For those coming from Europe, the BOFs can run late, but you can really get up close and personal with the actual developers and ask questions you can't get to in the bigger sessions. Be aware, some of the presenters aren't comfortable with that and will try to hide behind a prepared set of slides, but be polite and enthusiastic about what they're presenting. Most love having folks that appreciate the work they're doing. # Visit the pavilion to learn about specific products you're interested in, but also to learn about stuff you've never heard of that might make your job easier. Don't go just to get cool junk for your kids (something of which I've been guilty!). Some exhibitors have actual developers with the marketing folk. Be kind to them all. By the end, they've been standing and talking for three days and start getting ragged. # Make sure you visit some of San Francisco. A truly unique, physically beautiful and captivating city. (Don't be surprised by the number of panhandlers, though) Be prepared for lots of walking, some steep hills and weather that can range from cold and misty to gloriously sunny in a short time. So have layered clothing and comfortable shoes. # The conference food is okay, but don't expect the eating experience of your lifetime. Save that for the evening and the San Francisco restaurants. During lunch they'll have hot food, but also lunch bags with a sandwich (turkey, ham, beef or vegie), chips, cookie and a fruit, that you can grab and take to a session. # Don't buy books unless you feel like lugging them around and paying a little bit more than Bookpool. That being said, the bookstore has an awesome selection of the classics and the latest. Sometimes you can get free books from various pavilions. They'll also have authors available for book signings and chatting with. Josh Bloch will have a new book this year and I'm sure will be signing it. Also, go to any session he gives. # Most of all, just immerse yourself in the whole JavaOne experience. Be positive (even with the guards!), get as much sleep as you can, check out the vendor parties, the After Dark party, the beer, and most of all, learn all you can about what great and creative things people are doing and just enjoy the company of other Java enthusiasts and professionals. "

Matthew Smith: JDK Community Star

Sun has been opening the Java platform for some time now. With the Mustang release, the source code was made available and a process was provided for submitting bug fixes. About this same time we discovered an issue with the LDAP code that left connections open certain circumstances. Since I had access to the source code from Sun, I was able to find the problem and send a correction. For this I was "honored" at JavaOne in 2006 as a JDK Community Star for contributing a bug fix to Java. Click on Matthew Smith.

Communciating between JSR-168 portlets and the portal containter

The JSR-168 spec does not address the need for portlets and the portlet container to communicate. Sometimes an action taken by a portlet needs to be reflected in the navigation which is controlled by the container. Conversely, an action taken in the navigation will need to change the state of the portlets. The following information applies specifically to Vignette Application Portal but should apply to other portals like Pluto, Jetspeed2 and Liferay. Communicating from the portlets to the portal container. Add a parameter to PortletURL. Then there can be something (grid, secondary page or my personal choice, a servlet filter) that is listening for that parameter. Of course, the portlet will add a lot of nonsense to the name of the parameter so the receiver needs to look for something ending with the parameter name. The servlet filter can then place the required information into the session. Of course, you need to take reasonable security into account when deciding what to pass as a parameter. Communicating from the portal to a a portlet. Again, in a servlet filter, add the information that needs to be communicated to the portlets as a request attribute. The trick is that the name of the attribute must begin with "javax.servlet.". It will be visible in the RenderRequest and ActionRequest objects passed to the portlet. We are already doing this to pass things like Remote URL to the portlets. Note: For this to work the object being passed needs to be in the classpath and not just loaded in the WAR file. The reason is that the object is loaded by one classloader and then passed to another. You end up with ClassCastException.

Wednesday, April 11, 2007

Fun with Java Enums

Way back in Java 1.5, enum types were added to the Java spec. The idea is simple enough; create an object with a fixed set of valid values. The values are constant, like coins. Coins come in a fixed number of types (penny, nickel, dime, etc) and each type has a fixed value (1, 5, 10, ... ). An enum type allows you to do just that in your code:
public class Coins {
 enum Coin {
  PENNY(1),NICKEL(5),DIME(10),QUARTER(25);
  int value;
         Coin( int v ) { value = v; }
 }

 public static void main(String[] args) {
  System.out.println("A penny is worth: " + Coin.PENNY.value);
 }
}
A Coin enum type is declared and each possible type of Coin is given it's respective value. And the code prints just as you would expect:
A penny is worth: 1
Part of the assumption is that a penny is always a penny and always worth 1 cent. However, if we add the following lines of code to the main method, let's see what happens.
  Coin.PENNY.value = 1000;
  System.out.println("A penny is now worth: " + Coin.PENNY.value);
When the code is compiled and run again, what is the output? In case you were wondering, it does compile quite nicely.
A penny is worth: 1
A penny is now worth: 1000
Now that's the way all my investments should grow! Seriously, though, what is the problem? The problem is that the value, and any instance variables in an enum, are not magically immutable. The enum type does not do any special checking to ensure that the instances of the type (PENNY, NICKEL, ...) remain constant. Under the covers, the enum type is converted to a static class with static members for each of the declared possbile values like this:
static final class Coins$Coin extends Enum
{
          public static final Coins$Coin[] values()
            {
                return (Coins$Coin[])$VALUES.clone();
            }

            public static Coins$Coin valueOf(String s)
            {
                 return (Coins$Coin)Enum.valueOf(Coins$Coin, s);
            }

            public static final Coins$Coin PENNY;
            public static final Coins$Coin NICKEL;
            public static final Coins$Coin DIME;
            public static final Coins$Coin QUARTER;
            int value;
            private static final Coins$Coin $VALUES[];

            static 
            {
                PENNY = new Coins$Coin("PENNY", 0, 1);
                NICKEL = new Coins$Coin("NICKEL", 1, 5);
                DIME = new Coins$Coin("DIME", 2, 10);
                QUARTER = new Coins$Coin("QUARTER", 3, 25);
                $VALUES = (new Coins$Coin[] {
                    PENNY, NICKEL, DIME, QUARTER
                });
            }

            private Coins$Coin(String s, int i, int j)
            {
                super(s, i);
                value = j;
            }
}
Our value is given the same access modifiers in the generated class as it was given when we defined the enum. Meaning that the value is not able to be modified by any member of the same package.

The fix

The fix is fairly simple. Make the value instance variable final:
  final int value;
Now when the code that tries to modify the value is compiled, this error:
Coins.java:28: cannot assign a value to final variable value
                Coin.PENNY.value = 1000;
                          ^
1 error
Problem solved. Right? Well, not so fast. For primitive types, yes. But for descendants of Object, maybe not. What if instead of an int, value was something like a Map. You could then do Coin.PENNY.value.put("bad key", "bad value") and the compiler would be perfectly happy with it. To fix the problem, ensure that the Map is unmodifiable or immutable
public class Coins
{
 enum Coin {
  PENNY(1),NICKEL(5),DIME(10),QUARTER(25);
  
  final Map value;

  Coin( int v ) { 
   Map newValue = new HashMap();
   newValue.put( "cents", v );
   value = Collections.unmodifiableMap( newValue );
  }
 }

 public static void main(String[] args) {
  System.out.println("A penny is worth: " +    
                       Coin.PENNY.value.get("cents"));
 }
}

Summary

While the compiler will ensure that the enum types are immutable, it is the responsibility of the developer to ensure that any instance variables added to the enum are also immutable. This means the instance variable needs to be final AND the type of the instance variable must itself be immutable.

Friday, April 6, 2007

Java One 2007

I will attending Java One this year. Here is how you can contact me. Join Me at the 2007 JavaOne Conference Event Connect Tool!

Thursday, April 5, 2007

Elusive unit test error

We are using Spring Framework 1.2 and Weblogic 8.1.4. On occasion, I will get this error when running a unit test that uses JdbcTemplate. If I re-run the test with no modifications, the test completes fine. I wish I knew why. If you have an idea, post in the comments. UPDATE: The problem seems to be that Foglight/Performasure is installed on the server and is doing something with the JDBC getConnection response. The options seems to be
  1. Put the client jar for Performasure in my test classpath. I do not know if the license allows for that.
  2. Remove it from the server.
I'll leave it as an exercise for the reader to decide.
java.lang.NoClassDefFoundError: com/sitraka/pas/agent/plugin/instrumentor/method/JdbcDriverInstrumentor$JdbcImplementation
at java.lang.ClassLoader.defineClass0(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:502)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:123)
at weblogic.utils.classloaders.GenericClassLoader.findLocalClass(GenericClassLoader.java:480)
at weblogic.utils.classloaders.GenericClassLoader.findClass(GenericClassLoader.java:182)
at java.lang.ClassLoader.loadClass(ClassLoader.java:299)
at java.lang.ClassLoader.loadClass(ClassLoader.java:255)
at weblogic.utils.classloaders.GenericClassLoader.loadClass(GenericClassLoader.java:224)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:315)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:217)
at weblogic.j2ee.ApplicationManager.loadFromNetwork(ApplicationManager.java:652)
at weblogic.j2ee.ApplicationManager.loadClass(ApplicationManager.java:322)
at weblogic.j2ee.ApplicationManager.loadClass(ApplicationManager.java:258)
at weblogic.j2ee.ApplicationManager.loadClass(ApplicationManager.java:253)
at weblogic.rmi.internal.ClientRuntimeDescriptor.computeInterfaces(ClientRuntimeDescriptor.java:254)
at weblogic.rmi.internal.ClientRuntimeDescriptor.intern(ClientRuntimeDescriptor.java:140)
at weblogic.rmi.internal.StubInfo.readObject(StubInfo.java:124)
at sun.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:824)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1746)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1646)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1274)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1845)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1769)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1646)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1274)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:324)
at weblogic.common.internal.ChunkedObjectInputStream.readObject(ChunkedObjectInputStream.java:120)
at weblogic.rjvm.MsgAbbrevInputStream.readObject(MsgAbbrevInputStream.java:120)
at weblogic.rmi.internal.ObjectIO.readObject(ObjectIO.java:56)
at weblogic.rjvm.ResponseImpl.unmarshalReturn(ResponseImpl.java:164)
at weblogic.rmi.cluster.ReplicaAwareRemoteRef.invoke(ReplicaAwareRemoteRef.java:293)
at weblogic.rmi.cluster.ReplicaAwareRemoteRef.invoke(ReplicaAwareRemoteRef.java:247)
at weblogic.jdbc.common.internal.RmiDataSource_814_WLStub.getConnection(Unknown Source)
at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111)
at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:462)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:528)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:561)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:579)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:589)
at com.ihc.provider.domain.ProviderImpl.findProviderForId(ProviderImpl.java:401)
at com.ihc.provider.domain.ProviderImpl.findProvider(ProviderImpl.java:383)
at com.ihc.phc.user.UserServiceImpl.addProviderInfo(UserServiceImpl.java:249)
at com.ihc.phc.user.UserServiceImpl.getMessagingDoctors(UserServiceImpl.java:231)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:335)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:181)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:148)
at com.ihc.phc.util.CacheInterceptor.invoke(CacheInterceptor.java:37)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:176)
at $Proxy13.getMessagingDoctors(Unknown Source)
at com.ihc.phc.test.user.TestUserServiceImpl.testGetMessagingDoctors(TestUserServiceImpl.java:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:128)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)