blob: 7b9e0d7f02a4c96610af44b2f82d697e1b118a30 [file] [log] [blame]
:_basedir:
:_imagesdir: images/
:notoc:
:notitle:
:grid: cols
:metadata:
[[index]]
== JDO Bytecode Enhancementanchor:JDO_Bytecode_Enhancement[]
JDO defines a byte-code enhancement process that provides for dirty
detection of fields. Before a class is used at runtime it is compiled
and then "enhanced" to implement the interface _PersistenceCapable_, and
optionally also _Detachable_.
We can demonstrate this by taking a sample class, and seeing it before
and after enhancement. We start with the following class
....
package org.apache.jdo.test;
public class A
{
long id;
String name;
B b;
public A(String name)
{
this.name = name;
}
public void setId(long id)
{
this.id = id;
}
public void setB(B b)
{
this.b = b;
}
public String getName()
{
return name;
}
public B getB()
{
return b;
}
public long getId()
{
return id;
}
public String toString()
{
return "A : id=" + id + " [" + name + "] b=\"" + b + "\"";
}
}
....
and require it to be _PersistenceCapable_ and _Detachable_. The
enhancement process needs to intercept all updates of the fields of the
class (id, name, b) as well as add on the necessary
_PersistenceCapable_, _Detachable_ methods. After "enhancement" it
becomes
....
package org.apache.jdo.test;
import java.util.BitSet;
import javax.jdo.JDODetachedFieldAccessException;
import javax.jdo.JDOFatalInternalException;
import javax.jdo.PersistenceManager;
import javax.jdo.identity.LongIdentity;
import javax.jdo.spi.Detachable;
import javax.jdo.spi.JDOImplHelper;
import javax.jdo.spi.JDOPermission;
import javax.jdo.spi.PersistenceCapable;
import javax.jdo.spi.StateManager;
public class A implements PersistenceCapable, Detachable
{
long id;
String name;
B b;
protected transient StateManager jdoStateManager;
protected transient byte jdoFlags;
protected Object[] jdoDetachedState;
private static final byte[] jdoFieldFlags;
private static final Class jdoPersistenceCapableSuperclass;
private static final Class[] jdoFieldTypes;
private static final String[] jdoFieldNames = __jdoFieldNamesInit();
private static final int jdoInheritedFieldCount;
static
{
jdoFieldTypes = __jdoFieldTypesInit();
jdoFieldFlags = __jdoFieldFlagsInit();
jdoInheritedFieldCount = __jdoGetInheritedFieldCount();
jdoPersistenceCapableSuperclass = __jdoPersistenceCapableSuperclassInit();
JDOImplHelper.registerClass(___jdo$loadClass("org.apache.jdo.test.A"),
jdoFieldNames, jdoFieldTypes,
jdoFieldFlags,
jdoPersistenceCapableSuperclass, new A());
}
public void setId(long id)
{
jdoSetid(this, id);
}
public void setB(B b)
{
jdoSetb(this, b);
}
public String getName()
{
return jdoGetname(this);
}
public B getB()
{
return jdoGetb(this);
}
public long getId()
{
return jdoGetid(this);
}
public String toString()
{
return new StringBuilder().append("A : id=").append(jdoGetid(this))
.append(" [").append(jdoGetname(this))
.append("] b=\"").append(jdoGetb(this))
.append("\"").toString();
}
public void jdoCopyKeyFieldsFromObjectId(PersistenceCapable.ObjectIdFieldConsumer fc, Object oid)
{
if (fc == null)
throw new IllegalArgumentException
("ObjectIdFieldConsumer is null");
if (!(oid instanceof LongIdentity))
throw new ClassCastException
("oid is not instanceof javax.jdo.identity.LongIdentity");
LongIdentity o = (LongIdentity) oid;
fc.storeLongField(1, o.getKey());
}
protected void jdoCopyKeyFieldsFromObjectId(Object oid)
{
if (!(oid instanceof LongIdentity))
throw new ClassCastException
("key class is not javax.jdo.identity.LongIdentity or null");
LongIdentity o = (LongIdentity) oid;
id = o.getKey();
}
public final void jdoCopyKeyFieldsToObjectId(Object oid)
{
throw new JDOFatalInternalException
("It's illegal to call jdoCopyKeyFieldsToObjectId for a class with Single Field Identity.");
}
public final void jdoCopyKeyFieldsToObjectId
(PersistenceCapable.ObjectIdFieldSupplier fs, Object oid) {
throw new JDOFatalInternalException
("It's illegal to call jdoCopyKeyFieldsToObjectId for a class with Single Field Identity.");
}
public final Object jdoGetObjectId()
{
if (jdoStateManager != null)
return jdoStateManager.getObjectId(this);
if (this.jdoIsDetached() != true)
return null;
return jdoDetachedState[0];
}
public final Object jdoGetVersion()
{
if (jdoStateManager != null)
return jdoStateManager.getVersion(this);
if (this.jdoIsDetached() != true)
return null;
return jdoDetachedState[1];
}
protected final void jdoPreSerialize()
{
if (jdoStateManager != null)
jdoStateManager.preSerialize(this);
}
public final PersistenceManager jdoGetPersistenceManager()
{
return (jdoStateManager != null
? jdoStateManager.getPersistenceManager(this) : null);
}
public final Object jdoGetTransactionalObjectId()
{
return (jdoStateManager != null
? jdoStateManager.getTransactionalObjectId(this) : null);
}
public final boolean jdoIsDeleted()
{
return (jdoStateManager != null ? jdoStateManager.isDeleted(this): false);
}
public final boolean jdoIsDirty()
{
if (jdoStateManager != null)
return jdoStateManager.isDirty(this);
if (this.jdoIsDetached() != true)
return false;
if (((BitSet) jdoDetachedState[3]).length() <= 0)
return false;
return true;
}
public final boolean jdoIsNew()
{
return jdoStateManager != null ? jdoStateManager.isNew(this) : false;
}
public final boolean jdoIsPersistent()
{
return (jdoStateManager != null ? jdoStateManager.isPersistent(this): false);
}
public final boolean jdoIsTransactional()
{
return (jdoStateManager != null ? jdoStateManager.isTransactional(this): false);
}
public final boolean jdoIsDetached()
{
if (jdoStateManager == null) {
if (jdoDetachedState == null)
return false;
return true;
}
return false;
}
public final void jdoMakeDirty(String fieldName)
{
if (jdoStateManager != null)
jdoStateManager.makeDirty(this, fieldName);
}
public final Object jdoNewObjectIdInstance()
{
return new LongIdentity(getClass(), id);
}
public final Object jdoNewObjectIdInstance(Object key)
{
if (key == null)
throw new IllegalArgumentException("key is null");
if (key instanceof String != true)
return new LongIdentity(this.getClass(), (Long) key);
return new LongIdentity(this.getClass(), (String) key);
}
public final void jdoProvideFields(int[] fieldId)
{
if (fieldId == null)
throw new IllegalArgumentException("argment is null");
int i = fieldId.length - 1;
if (i >= 0)
{
do
jdoProvideField(fieldId[i]);
while (--i >= 0);
}
}
public final void jdoReplaceFields(int[] fieldId)
{
if (fieldId == null)
throw new IllegalArgumentException("argument is null");
int i = fieldId.length;
if (i > 0)
{
int i_0_ = 0;
do
jdoReplaceField(fieldId[i_0_]);
while (++i_0_ < i);
}
}
public final void jdoReplaceFlags()
{
if (jdoStateManager != null)
{
A a = this;
a.jdoFlags = a.jdoStateManager.replacingFlags(this);
}
}
public final synchronized void jdoReplaceStateManager(StateManager stateManager)
{
if (jdoStateManager != null)
{
A a = this;
a.jdoStateManager = a.jdoStateManager.replacingStateManager(this, stateManager);
}
else
{
JDOImplHelper.checkAuthorizedStateManager(sm);
jdoStateManager = stateManager;
jdoFlags = (byte) 1;
}
}
public final synchronized void jdoReplaceDetachedState()
{
if (jdoStateManager == null)
throw new IllegalStateException("state manager is null");
A a = this;
a.jdoDetachedState = a.jdoStateManager.replacingDetachedState(this, jdoDetachedState);
}
public PersistenceCapable jdoNewInstance(StateManager sm)
{
A result = new A();
A a = result;
a.jdoFlags = (byte) 1;
a.jdoStateManager = sm;
return a;
}
public PersistenceCapable jdoNewInstance(StateManager sm, Object o)
{
A result = new A();
A a = result;
a.jdoFlags = (byte) 1;
a.jdoStateManager = sm;
result.jdoCopyKeyFieldsFromObjectId(o);
return a;
}
public void jdoReplaceField(int fieldIndex)
{
if (jdoStateManager == null)
throw new IllegalStateException("state manager is null");
switch (fieldIndex)
{
case 0:
{
A a = this;
a.b = (B) a.jdoStateManager.replacingObjectField(this, fieldIndex);
break;
}
case 1:
{
A a = this;
a.id = a.jdoStateManager.replacingLongField(this, fieldIndex);
break;
}
case 2:
{
A a = this;
a.name = a.jdoStateManager.replacingStringField(this, fieldIndex);
break;
}
default:
throw new IllegalArgumentException("out of field index :" + fieldIndex);
}
}
public void jdoProvideField(int fieldIndex)
{
if (jdoStateManager == null)
throw new IllegalStateException("state manager is null");
switch (fieldIndex)
{
case 0:
jdoStateManager.providedObjectField(this, fieldIndex, b);
break;
case 1:
jdoStateManager.providedLongField(this, fieldIndex, id);
break;
case 2:
jdoStateManager.providedStringField(this, fieldIndex, name);
break;
default:
throw new IllegalArgumentException("out of field index :" + fieldIndex);
}
}
protected final void jdoCopyField(A obj, int index)
{
switch (index)
{
case 0:
b = obj.b;
break;
case 1:
id = obj.id;
break;
case 2:
name = obj.name;
break;
default:
throw new IllegalArgumentException("out of field index :" + index);
}
}
public void jdoCopyFields(Object obj, int[] fieldNumbers)
{
if (jdoStateManager == null)
throw new IllegalStateException("state manager is null");
if (fieldNumbers == null)
throw new IllegalStateException("fieldNumbers is null");
if (obj instanceof A != true)
throw new IllegalArgumentException("object is not org.apache.jdo.test.A");
A me = (A) obj;
if (jdoStateManager != me.jdoStateManager)
throw new IllegalArgumentException("state manager unmatch");
int i = fieldNumbers.length - 1;
if (i >= 0)
{
do
jdoCopyField(me, fieldNumbers[i]);
while (--i >= 0);
}
}
private static final String[] __jdoFieldNamesInit()
{
return new String[] { "b", "id", "name" };
}
private static final Class[] __jdoFieldTypesInit()
{
return new Class[] { ___jdo$loadClass("org.apache.jdo.test.B"), Long.TYPE,
___jdo$loadClass("java.lang.String") };
}
private static final byte[] __jdoFieldFlagsInit()
{
return new byte[] { 10, 24, 21 };
}
protected static int __jdoGetInheritedFieldCount()
{
return 0;
}
protected static int jdoGetManagedFieldCount()
{
return 3;
}
private static Class __jdoPersistenceCapableSuperclassInit()
{
return null;
}
public static Class ___jdo$loadClass(String className)
{
try
{
return Class.forName(className);
}
catch (ClassNotFoundException e)
{
throw new NoClassDefFoundError(e.getMessage());
}
}
private Object jdoSuperClone()
throws CloneNotSupportedException
{
A o = (A) super.clone();
o.jdoFlags = (byte) 0;
o.jdoStateManager = null;
return o;
}
public A()
{
/* empty */
}
static void jdoSetb(A objPC, B b_m)
{
if (objPC.jdoStateManager == null)
objPC.b = b_m;
else
objPC.jdoStateManager.setObjectField(objPC, 0, objPC.b, b_m);
if (objPC.jdoIsDetached() == true)
((BitSet) objPC.jdoDetachedState[3]).set(0);
}
static B jdoGetb(A objPC)
{
if (objPC.jdoStateManager != null
&& !objPC.jdoStateManager.isLoaded(objPC, 0))
return (B) objPC.jdoStateManager.getObjectField(objPC, 0, objPC.b);
if (objPC.jdoIsDetached() != false
&& ((BitSet) objPC.jdoDetachedState[2]).get(0) != true
&& ((BitSet) objPC.jdoDetachedState[3]).get(0) != true)
throw new JDODetachedFieldAccessException
("You have just attempted to access field \"b\" yet this field was not detached when you detached the object. " +
"Either dont access this field, or detach the field when detaching the object.");
return objPC.b;
}
static void jdoSetid(A objPC, long id_n)
{
objPC.id = id_n;
}
static long jdoGetid(A objPC)
{
return objPC.id;
}
static void jdoSetname(A objPC, String name_c)
{
if (objPC.jdoFlags != 0 && objPC.jdoStateManager != null)
objPC.jdoStateManager.setStringField(objPC, 2, objPC.name, name_c);
else
{
objPC.name = name_c;
if (objPC.jdoIsDetached() == true)
((BitSet) objPC.jdoDetachedState[3]).set(2);
}
}
static String jdoGetname(A objPC)
{
if (objPC.jdoFlags > 0 && objPC.jdoStateManager != null && !objPC.jdoStateManager.isLoaded(objPC, 2))
return objPC.jdoStateManager.getStringField(objPC, 2, objPC.name);
if (objPC.jdoIsDetached() != false && ((BitSet) objPC.jdoDetachedState[2]).get(2) != true)
throw new JDODetachedFieldAccessException
("You have just attempted to access field \"name\" yet this field was not detached when you detached the object." +
"Either dont access this field, or detach the field when detaching the object.");
return objPC.name;
}
public A(String name)
{
jdoSetname(this, name);
}
}
....