package org.jboss.ejb.plugins;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Collection;
import java.util.Collections;
import javax.ejb.EJBException;
import org.jboss.ejb.Container;
import org.jboss.ejb.EntityEnterpriseContext;
import org.jboss.ejb.EntityPersistenceStore;
import org.jboss.ejb.EntityContainer;
import org.jboss.ejb.GenericEntityObjectFactory;
import org.jboss.metadata.EntityMetaData;
import org.jboss.system.ServiceMBeanSupport;
public class CMPInMemoryPersistenceManager
extends ServiceMBeanSupport
implements EntityPersistenceStore
{
protected EntityContainer con;
protected HashMap beans;
protected Field idField;
protected Method isModified;
public CMPInMemoryPersistenceManager ()
{
}
public void setContainer (final Container con)
{
this.con = (EntityContainer)con;
}
protected void createService() throws Exception
{
boolean debug = log.isDebugEnabled();
this.beans = new HashMap(1000);
String ejbName = con.getBeanMetaData ().getEjbName ();
idField = con.getBeanClass ().getField ("id");
if (debug) log.debug("Using id field: " + idField);
try
{
isModified = con.getBeanClass().getMethod("isModified", new Class[0]);
if (!isModified.getReturnType().equals(Boolean.TYPE)) {
isModified = null; log.warn("Found isModified method, but return type is not boolean; ignoring");
}
else {
if (debug) log.debug("Using isModified method: " + isModified);
}
}
catch (NoSuchMethodException ignored) {}
}
protected void stopService() throws Exception
{
this.beans.clear();
}
public Object createBeanClassInstance () throws Exception
{
return con.getBeanClass ().newInstance ();
}
public void initEntity (EntityEnterpriseContext ctx)
{
Object instance = ctx.getInstance ();
Class ejbClass = instance.getClass ();
Field cmpField;
Class cmpFieldType;
EntityMetaData metaData = (EntityMetaData)con.getBeanMetaData ();
Iterator i= metaData.getCMPFields ();
while(i.hasNext ())
{
try
{
cmpField = ejbClass.getField ((String)i.next ());
cmpFieldType = cmpField.getType ();
if (cmpFieldType.equals (boolean.class))
{
cmpField.setBoolean (instance,false);
}
else if (cmpFieldType.equals (byte.class))
{
cmpField.setByte (instance,(byte)0);
}
else if (cmpFieldType.equals (int.class))
{
cmpField.setInt (instance,0);
}
else if (cmpFieldType.equals (long.class))
{
cmpField.setLong (instance,0L);
}
else if (cmpFieldType.equals (short.class))
{
cmpField.setShort (instance,(short)0);
}
else if (cmpFieldType.equals (char.class))
{
cmpField.setChar (instance,'\u0000');
}
else if (cmpFieldType.equals (double.class))
{
cmpField.setDouble (instance,0d);
}
else if (cmpFieldType.equals (float.class))
{
cmpField.setFloat (instance,0f);
}
else
{
cmpField.set (instance,null);
}
}
catch (NoSuchFieldException e)
{
}
catch (Exception e)
{
throw new EJBException (e);
}
}
}
public Object createEntity (Method m, Object[] args, EntityEnterpriseContext ctx) throws Exception
{
try
{
Object id = idField.get (ctx.getInstance ());
if (this.beans.containsKey (id))
throw new javax.ejb.DuplicateKeyException ("Already exists: "+id);
storeEntity (id, ctx.getInstance ());
return id;
}
catch (IllegalAccessException e)
{
throw new javax.ejb.CreateException ("Could not create entity: "+e);
}
}
public Object postCreateEntity(final Method m,
final Object[] args,
final EntityEnterpriseContext ctx)
throws Exception
{
return null;
}
public Object findEntity (Method finderMethod, Object[] args, EntityEnterpriseContext instance, GenericEntityObjectFactory factory)
throws Exception
{
if (finderMethod.getName ().equals ("findByPrimaryKey"))
{
if (!this.beans.containsKey (args[0]))
throw new javax.ejb.FinderException (args[0]+" does not exist");
return factory.getEntityEJBObject(args[0]);
}
return null;
}
public Collection findEntities(final Method finderMethod,
final Object[] args,
final EntityEnterpriseContext instance,
GenericEntityObjectFactory factory)
throws Exception
{
if (finderMethod.getName ().equals ("findAll"))
{
return GenericEntityObjectFactory.UTIL.getEntityCollection(factory, this.beans.keySet());
}
else
{
return Collections.EMPTY_LIST;
}
}
public void activateEntity (EntityEnterpriseContext instance)
{
}
public void loadEntity (EntityEnterpriseContext ctx)
{
try
{
java.io.ObjectInputStream in = new CMPObjectInputStream
(new java.io.ByteArrayInputStream ((byte[])this.beans.get (ctx.getId ())));
Object obj = ctx.getInstance ();
Field[] f = obj.getClass ().getFields ();
for (int i = 0; i < f.length; i++)
{
f[i].set (obj, in.readObject ());
}
in.close ();
}
catch (Exception e)
{
throw new EJBException ("Load failed", e);
}
}
public boolean isStoreRequired (EntityEnterpriseContext ctx) throws Exception
{
if(isModified == null)
{
return true;
}
Boolean modified = (Boolean) isModified.invoke (ctx.getInstance (), new Object[0]);
return modified.booleanValue ();
}
public boolean isModified(EntityEnterpriseContext ctx) throws Exception
{
return isStoreRequired(ctx);
}
public void storeEntity (EntityEnterpriseContext ctx)
{
storeEntity (ctx.getId (), ctx.getInstance ());
}
public void passivateEntity (EntityEnterpriseContext instance)
{
}
public void removeEntity (EntityEnterpriseContext ctx) throws javax.ejb.RemoveException
{
if (this.beans.remove (ctx.getId ()) == null)
throw new javax.ejb.RemoveException ("Could not remove bean:" + ctx.getId ());
}
protected void storeEntity (Object id, Object obj)
{
try
{
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream ();
java.io.ObjectOutputStream out = new CMPObjectOutputStream (baos);
try {
Field[] f = obj.getClass ().getFields ();
for (int i = 0; i < f.length; i++)
{
out.writeObject (f[i].get (obj));
}
}
finally {
out.close();
}
this.beans.put (id, baos.toByteArray ());
}
catch (Exception e)
{
throw new EJBException ("Store failed", e);
}
}
static class CMPObjectOutputStream extends java.io.ObjectOutputStream
{
public CMPObjectOutputStream (java.io.OutputStream out) throws IOException
{
super (out);
enableReplaceObject (true);
}
protected Object replaceObject (Object obj)
throws IOException
{
if (obj instanceof javax.ejb.EJBObject)
return ((javax.ejb.EJBObject)obj).getHandle ();
return obj;
}
}
static class CMPObjectInputStream extends java.io.ObjectInputStream
{
public CMPObjectInputStream (java.io.InputStream in) throws IOException
{
super (in);
enableResolveObject (true);
}
protected Object resolveObject (Object obj)
throws IOException
{
if (obj instanceof javax.ejb.Handle)
return ((javax.ejb.Handle)obj).getEJBObject ();
return obj;
}
}
}