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!

Tuesday, February 16, 2010

Serializing parts of your Java Bean to AMF

I found a good example of how to serialize a Java object to AMF using BlazeDS here http://javadevelopmentforthemasses.blogspot.com/2008/08/amf-serialization-from-java-to-flex-and.html

But what happens if I don't want to serialize my model objects?
Suppose my entity has internalId, name and value fields and I only want to send the name and value fields.

According to BlazeDS developer guide I can solve this by setting fields as transient or implementing the Externalizable interface.

I can't set my internalId field as transient, nor do I want to implement Externalizable, which I would have to update every time I change my model object.
This can be solved using the PropertyProxyRegistry in the BlazeDS framework.

Let's define a new annotation - AMFTransient - this annotation will mark which fields should not be serialized.
package amf;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value={ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AmfTransient
{
}

Now write our own new BeanProxy
package amf;

import java.lang.reflect.Field;
import java.util.List;

import flex.messaging.io.BeanProxy;

@SuppressWarnings("serial")
public class TransientAwareBeanProxy extends BeanProxy
{
 @SuppressWarnings("unchecked")
 @Override
 public List getPropertyNames( Object instance )
 {
  List propertyNames = super.getPropertyNames( instance );
  
  // find which fields where marked as transient and remove them
  Class c = instance.getClass();
  for ( Field field : c.getDeclaredFields() )
  {
   if ( field.isAnnotationPresent( AmfTransient.class ) )
   {
    propertyNames.remove( field.getName() );
   }
  }
  
  return propertyNames;
 }
}

Finally we have to register our Proxy in bootstrap code (each application probably does this differently)

PropertyProxyRegistry.getRegistry().register( Object.class, new TransientAwareBeanProxy() );

Finally, let's put it all together with our AMF serializer and Main class

package amf;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf3Input;
import flex.messaging.io.amf.Amf3Output;

public class AmfSerializer
{
 public void toAmf( Object source, OutputStream os ) throws IOException
 {
  Amf3Output amf3Output = new Amf3Output( getSerializationContext() );
  amf3Output.setOutputStream( os );
  amf3Output.writeObject( source );
  amf3Output.flush();
  amf3Output.close();  
 }
 
 @SuppressWarnings("unchecked")
 public  T fromAmf( byte[] amf ) throws ClassNotFoundException, IOException
{
InputStream bIn = new ByteArrayInputStream( amf );
Amf3Input amf3Input = new Amf3Input( getSerializationContext() );
amf3Input.setInputStream( bIn );
return (T) amf3Input.readObject();
}

private SerializationContext getSerializationContext()
{
// Let the framework create the object and set the thread local variable
SerializationContext context = SerializationContext.getSerializationContext();
// set flags on the serialization context here
return context;
}
}

package amf;

import java.io.ByteArrayOutputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import flex.messaging.io.PropertyProxyRegistry;

public class Main
{
 public static void main( String[] args ) throws java.lang.Exception
 {
  // by default send objects to the transient aware proxy
  // you should set this in your bootstrap code
  // ff you don't want certain classes to use this proxy set the BeanProxy explicitly for them
  PropertyProxyRegistry.getRegistry().register( Object.class, new TransientAwareBeanProxy() );

  B toAmf = new B( "bid" );
  toAmf.as.put( "a1", new A( 11, "aid1" ) );
  toAmf.as.put( "a2", new A( 12, "aid2" ) );
  
  ByteArrayOutputStream bout = new ByteArrayOutputStream();
  AmfSerializer serializer = new AmfSerializer();
  serializer.toAmf( toAmf, bout );
  byte[] amf = bout.toByteArray();
  
  B fromAmf = serializer.fromAmf( amf );
  
  System.out.println( "this should be null: " + fromAmf.d );
  System.out.println( "this should be null: " + ((A)(fromAmf.as.values().toArray()[0])).id );
  System.out.println( "this should be a number: " + ((A)(fromAmf.as.values().toArray()[0])).i );
 }
 
 public static class A { 
  @AmfTransient public String id;
  private Integer i;
  
  public A() {} // required for desrializing AMF 

  public A( Integer i, String str ) {
   this.i = i;
   this.id = str;
  }
  public void setI( Integer i ) {
   this.i = i;
  }
  public Integer getI() {
   return i;
  }
  
  public boolean equals( Object obj ) {
   A tmp = (A)obj;
   return id.equals( tmp.id );
  }  
  public int hashCode() {
   return id.hashCode();
  }
 }
 
 public static class B {  
  @AmfTransient public Date d;
  public String id;
  public Map as = new HashMap();

  public B() {} // required for desrializing AMF

  public B( String id ) {
   this.id = id;
   d = new Date();
  }

  public boolean equals( Object obj ) {
   B tmp = (B)obj;
   return id.equals( tmp.id );
  }
  public int hashCode() {
   return id.hashCode();
  }
 }
}

Thursday, December 3, 2009

Configuring an Axis2 client

I am using Axis2 (version 1.4) for performing SOAP requests.
A customer came up with a requirement to set the HTTP client to use a proxy.

I found the property I need to change in axis2 configuration in the axis2 documentation but I couldn't find documentation on where to place these configuration elements, only some obscure references to axis2.xml.

I configured Axis2 logging to get a better clue of what is used, using commons-logging and setting the log4j.properties to output everything (level ALL).
In the log I understood where Axis2 get the configuration from – it reads it from org/apache/axis2/deployment/axis2_default.xml
I found this file inside axis2-kernel-1.2.jar.
I extracted the file and configured a proxy for the "http" transportSender elements. Then I put the modified file in the classpath and this time the HTTP request went through my proxy.

Great, problem solved, but can I change the location of the file?

I started reading the code in http://grepcode.com (very useful, having all the sources online).
You can set the name and location of the configuration file using JVM properties, if you don’t do so then the default is used.
The JVM property "axis2.repo" is used to set the repository, and "axis2.xml" is used to set the configuration file name.
If you set the repository and not the file name then the expected file name is "axis2.xml".
See http://grepcode.com/file/repo1.maven.org/maven2/org.apache.axis2/axis2-kernel/1.4/org/apache/axis2/deployment/FileSystemConfigurator.java#FileSystemConfigurator.%3Cinit%3E%28java.lang.String,java.lang.String%29

Finally, if the JVM properties are not set then the default configuration resource is used org/apache/axis2/deployment/axis2_default.xml, see
http://grepcode.com/file/repo1.maven.org/maven2/org.apache.axis2/axis2-kernel/1.4/org/apache/axis2/deployment/FileSystemConfigurator.java#FileSystemConfigurator.getAxisConfiguration%28%29

Oded

Tuesday, November 3, 2009

How to run an external processes from a Java program

A QA engineers recently asked for my help invoking an external process from a Java program.
I told him "use java.lang.Runtime.exec" (link opens in a new tab).
It's been a long time since I used it, the opportunity rarely rises.
He struggled with the API, and couldn't understand how to write the output of the process to his Java console.
So I took a longer look in the API and sent this back as an example:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class ProcessRunner {

public static void main( String[] args ) throws Exception {
execute( "cmd.exe /c dir" );
execute( "cmd.exe /c java1" );
execute( "java -version" );
execute( "java -versiond" );
}

public static void execute( String cmd ) throws Exception {
Process p = Runtime.getRuntime().exec( cmd );

OutputReader stdout = new OutputReader( p.getInputStream() );
Thread t1 = new Thread( stdout );
t1.start();

OutputReader stderr = new OutputReader( p.getErrorStream() );
Thread t2 = new Thread( stderr );
t2.start();

int status = p.waitFor();
System.out.println( "status " + status );
System.out.println();
}

private static class OutputReader implements Runnable {
InputStream is;
public OutputReader( InputStream is ) {
this.is = is;
}

public void run() {
BufferedReader reader = new BufferedReader( new InputStreamReader( is ) );
try {
String line = null;
while ( ( line = reader.readLine() ) != null ) {
System.out.println( line );
}
} catch ( IOException e ) {
e.printStackTrace();
}
try
{
reader.close();
}
catch ( IOException e )
{
e.printStackTrace();
}
}
}
}

Looks cumbersome, but then many mundane operations in Java feel the same (e.g. read from a file).

Wednesday, October 21, 2009

Using Spring LDAP to authenticate a user and verify group membership in Active Directory

Today I needed to authenticate a user and verify he belongs to a specific group in one step (in Active Directory).
I am using Spring LDAP, Spring Security 2.0.4.
After a few hours of trial and error I understood the meaning of the "searchFilter" in FilterBasedLdapUserSearch.
I can verify the sAMAccountName and the group membership using the filter like this:

FilterBasedLdapUserSearch search = new FilterBasedLdapUserSearch(
"OU=Users,DC=mycompany,DC=com",
"(&(objectCategory=user)(objectClass=person)(sAMAccountName={0})" +
"(memberof:=CN=MyGroup,OU=Users,DC=mycompany,DC=com)" +
")", ctx );