| :_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); |
| } |
| } |
| .... |
| |