Sunday, March 21, 2010

Howto use Play! + Spring + your own properties file

For those of you who don't know Play!, Play! is a framework for developing Web applications in Java, without the adhering to the JEE specifications. It makes many things easier.

For example, Play! has a Spring integration module for effortless integration of your application with Spring.



Today I added my own properties file to my Spring-powered Play! app.

It sounds very simple, just add the following lines to your
application-context.xml:

   


and use it in your beans:

   ${myapp.somekey}


However, when you run your application you get the error:
Invalid bean definition with name 'a' defined in resource loaded
through SAX InputSource: Could not resolve placeholder
'myapp.somekey'
.

I spent some time trying to figure this out. Urrrghhhh.

Finally, I understood why this happens and how to avoid it.


The Play! Spring module uses a GenericApplicationContext and
problematically adds a PropertyPlaceholderConfigurer to it, allowing
you to substitute place holders with values in your application.conf
file. (I am not sure this feature is documented anywhere)

Now, when Spring invokes
AbstractApplicationContext.invokeBeanFactoryPostProcessors() it
invokes Play's PropertyPlaceholderConfigurer, which tries to convert $
{myapp.somekey}
as well.
Since it can't find ${myapp.somekey} in application.conf the exception
is thrown.

The way to "fool" the PropertyPlaceholderConfigurer Play! adds is to
override your application's place holder prefix and suffix.
This can be done in your application-context.xml file, for example:

   
   #[
   ]



   #[myapp.somekey]

Now your application can read properties from any properties file you
want.

Sunday, March 14, 2010

Dependency Injection and JPA

Consider the following classes


These are POJOs and also JPA entities.
Note that ShortPerson has a (transient) Ladder dependency.
When the JPA EntityManager loads the ShortPerson instances it does not supply the Ladder objects, thus when invoking the getObjectFromTopShelf() method on the short person object will fail.

I haven't found a best-practice on how to inject my dependencies.

I could write code in the ShortPerson constructor that "pulls" the dependency from the container, but that adds a dependency on the container, which must be initialized properly
before I create my ShortPerson instance.

So it should probably be done in the DAO, but how? Only one of my classes has the setLadder() method.


My solution is a combination of pulling the dependencies but from a runtime object.
Have another object (let's call it injector) know all of the possible dependencies of the various Person objects, and have each object pull it's own dependency from the injector.




So now Person has an empty implementation for inject() and ShortPerson can pull its ladder implementation from the injector, still decoupling ShortPerson from the dependency injection framework.
After the DAO loads the entities and before returning them to the client it invokes the inject() method for each instance.

The DAO itself can have the injector implementation injected into it during instantiation.

List persons = em.createQuery( "from Person" ).getResultList();
for ( Object object : entlist )
{
   Person person = (Person)object;
   person.inject( injector );
}

Sunday, March 7, 2010

Serializing Google Protocol Buffer to Blazeds AMF

What are these technologies and how can I use them?
Protocol buffers are a flexible, efficient, automated mechanism for serializing structured data.
You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages.
read more

Action Message Format (AMF) is a binary format used to serialize ActionScript objects. It is used primarily to exchange data between an Adobe Flash application and a remote service, usually over the internet.
read more

BlazeDS is the server-based Java remoting and web messaging technology.
read more

OK. I read this and I am intrigued. How can I use these technologies together?

You start by defining your Protocol Buffer data structure and generate the matching Java classes.
Now you need to serialize your data structure to AMF using BlazeDS. Simple as that.

But wait, I read here that
For Java objects that BlazeDS does not handle implicitly, values found in public bean properties with get/set methods and public variables are sent to the client as properties on an Object. Private properties, constants, static properties, and read-only properties, and so on, are not serialized.
My generated data structures don't have setters, they use the Builder pattern. How can I tell BlazeDS what to serialize? I don't want to hack the code generation process and add implement my data structures as Externalizable.

You need to register your own PropertyProxy in the PropertyProxyRegistry.

I wrote a property proxy to help you out:
package amf;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import com.google.protobuf.Descriptors;
import com.google.protobuf.GeneratedMessage;
import com.google.protobuf.Message;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor.JavaType;

import flex.messaging.io.ArrayCollection;
import flex.messaging.io.ArrayList;
import flex.messaging.io.BeanProxy;

/**
 * This is an implementation of the blazeds PropertyProxy for Google Protocol Buffers.
 */
@SuppressWarnings("unchecked")
public class GoogleProtocolBufferProxy extends BeanProxy
{
 private static ConcurrentHashMap propertiesCache = new ConcurrentHashMap();

private static final long serialVersionUID = -2175023450177522134L;

/**
* @see flex.messaging.io.PropertyProxy#getPropertyNames(java.lang.Object)
*/
public List getPropertyNames( Object instance )
{
List propertyNames = propertiesCache.get( instance.getClass() );
if ( propertyNames != null )
{
return propertyNames;
}

if ( instance instanceof Descriptors.EnumValueDescriptor )
{
Descriptors.EnumValueDescriptor enumValueDescriptor = (Descriptors.EnumValueDescriptor)instance;
String enumName = enumValueDescriptor.getType().getName();
return Collections.singletonList( enumName ); // an enum descriptor has a single enum value
}
else if ( instance instanceof GeneratedMessage )
{
// use GPB reflection to figure out the proprety names
GeneratedMessage message = (GeneratedMessage)instance;
List fields = message.getDescriptorForType().getFields();
propertyNames = new ArrayList( fields.size() );
for ( FieldDescriptor field : fields )
{
propertyNames.add( field.getName() );
}

propertiesCache.put( instance.getClass(), propertyNames );

return propertyNames;
}
else
{
throw new IllegalArgumentException( "Can only serialize GPB objects, not " + instance.getClass() );
}

}

/**
* @see flex.messaging.io.BeanProxy#getValue(java.lang.Object, java.lang.String)
*/
public Object getValue( Object instance, String propertyName )
{
if ( instance instanceof Descriptors.EnumValueDescriptor )
{
Descriptors.EnumValueDescriptor enumValueDescriptor = (Descriptors.EnumValueDescriptor)instance;
String enumValue = enumValueDescriptor.getName();
return enumValue;
}
if ( instance instanceof GeneratedMessage )
{
// use GPB reflection to figure out the proprety names
GeneratedMessage message = (GeneratedMessage)instance;
FieldDescriptor field = message.getDescriptorForType().findFieldByName( propertyName );
Object value = message.getField( field );
return value;
}
else
{
throw new IllegalArgumentException( "Can only serialize GPB objects, not " + instance.getClass() );
}
}

/**
* @see flex.messaging.io.AbstractProxy#createInstance(java.lang.String)
*/
public Object createInstance( String className )
{
if ( Descriptors.EnumValueDescriptor.class.getName().equals( className ) )
{
return new StringBuilder(); // use a StringBuilder to hold the value of the enum
}
try
{
Class clz = Class.forName( className );
Method newBuilderMethod = clz.getDeclaredMethod( "newBuilder", new Class[] {} );
newBuilderMethod.setAccessible( true );
Message.Builder builder = (Message.Builder)newBuilderMethod.invoke( null );
return builder;
}
catch ( ClassNotFoundException e )
{
throw new IllegalArgumentException( e );
}
catch ( NoSuchMethodException e )
{
throw new IllegalArgumentException( e );
}
catch ( InvocationTargetException e )
{
throw new IllegalArgumentException( e );
}
catch ( IllegalAccessException e )
{
throw new IllegalArgumentException( e );
}
catch ( SecurityException e )
{
throw new RuntimeException( e );
}
}

/**
* @see flex.messaging.io.BeanProxy#setValue(java.lang.Object, java.lang.String, java.lang.Object)
*/
public void setValue( Object instance, String propertyName, Object value )
{
if ( instance instanceof StringBuilder ) // this instance is an enum
{
StringBuilder builder = (StringBuilder)instance;
builder.append( value ); // save the enum value
}
else if ( instance instanceof Message.Builder ) // note the input is a message builder, not a message
{
Message.Builder builder = (Message.Builder)instance;
FieldDescriptor field = builder.getDescriptorForType().findFieldByName( propertyName );
if ( value instanceof Double )
{
Double dbl = (Double)value;
Object realValue = dbl;
// ActionScript Number is desrialized to Java Double 
// Java Double, Long, Float, are serialized to ActionScript Number
// here is the place to desrialized wisely
if ( field.getJavaType().equals( JavaType.LONG ) )
{
realValue = new Long( dbl.longValue() );
}
else if ( field.getJavaType().equals( JavaType.FLOAT ) )
{
realValue = new Float( dbl.floatValue() );
}
builder.setField( field, realValue );
}
else if ( field.getJavaType().equals( JavaType.ENUM ) && value instanceof StringBuilder ) // if this is an enum for which we saved the value set the correct enum value
{
EnumValueDescriptor enumValueDescriptor = field.getEnumType().findValueByName( String.valueOf( value ) );
builder.setField( field, enumValueDescriptor );
}
else if ( field.getJavaType().equals( JavaType.ENUM ) && value instanceof ArrayCollection ) // if this is an enum for which we saved the value set the correct enum value
{
ArrayCollection enumCollection = (ArrayCollection)value;
Iterator enumValuesIterator = enumCollection.iterator();
while ( enumValuesIterator.hasNext() )
{
StringBuilder enumValueBuilder = (StringBuilder)enumValuesIterator.next();
EnumValueDescriptor enumValueDescriptor = field.getEnumType().findValueByName( String.valueOf( enumValueBuilder ) );
builder.addRepeatedField( field, enumValueDescriptor );
}
}
else
{
builder.setField( field, value );
}
}
else
{
throw new IllegalArgumentException( "Can only serialize GPB objects, not " + instance.getClass() );
}
}

/**
* @see flex.messaging.io.AbstractProxy#instanceComplete(java.lang.Object)
*/
public Object instanceComplete( Object instance )
{
if ( instance instanceof StringBuilder )
{
return instance; // return the same string builder which holds the enum value
}
else if ( instance instanceof Message.Builder ) // note the input is a message builder, not a message
{
Message.Builder builder = (Message.Builder)instance;
return builder.build();
}
else
{
throw new IllegalArgumentException( "Can only serialize GPB objects, not " + instance.getClass() );
}
}

}

In your unit test don't forget to setup the registry. in JUnit it looks like this

@BeforeClass
public static void setup()
{
 PropertyProxyRegistry.getRegistry().register( GeneratedMessage.class, new GoogleProtocolBufferProxy() );
 PropertyProxyRegistry.getRegistry().register( Descriptors.EnumValueDescriptor.class, new GoogleProtocolBufferProxy() );
}

Happy serializing!