summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBrian S. O'Neill <bronee@gmail.com>2008-12-18 20:58:00 +0000
committerBrian S. O'Neill <bronee@gmail.com>2008-12-18 20:58:00 +0000
commitb66fb3db6951b2b6d3ace72ca3e197c7c2048e86 (patch)
treee5d9c0c6819f01b8917dcfb8884e07a3c8a9567b /src
parentc8133fcabf7a28b40f6bc8e4e4df8baf156b2f0a (diff)
Fixes for excessive class generation and memory usage when opening multiple repositories.
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/amazon/carbonado/layout/Layout.java43
-rw-r--r--src/main/java/com/amazon/carbonado/raw/GenericStorableCodec.java122
-rw-r--r--src/main/java/com/amazon/carbonado/raw/RawSupport.java14
-rw-r--r--src/main/java/com/amazon/carbonado/raw/StorableCodec.java14
-rw-r--r--src/main/java/com/amazon/carbonado/repo/indexed/IndexEntryGenerator.java23
-rw-r--r--src/main/java/com/amazon/carbonado/repo/sleepycat/BDBStorage.java11
-rw-r--r--src/main/java/com/amazon/carbonado/synthetic/SyntheticStorableReferenceAccess.java152
-rw-r--r--src/main/java/com/amazon/carbonado/synthetic/SyntheticStorableReferenceBuilder.java110
8 files changed, 338 insertions, 151 deletions
diff --git a/src/main/java/com/amazon/carbonado/layout/Layout.java b/src/main/java/com/amazon/carbonado/layout/Layout.java
index ca50172..b6c6c0d 100644
--- a/src/main/java/com/amazon/carbonado/layout/Layout.java
+++ b/src/main/java/com/amazon/carbonado/layout/Layout.java
@@ -394,6 +394,49 @@ public class Layout {
return reconstructed;
}
+ @Override
+ public int hashCode() {
+ long id = getLayoutID();
+ return ((int) id) ^ (int) (id >> 32);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof Layout) {
+ Layout other = (Layout) obj;
+ try {
+ return mStoredLayout.equals(other.mStoredLayout) && equalLayouts(other);
+ } catch (FetchException e) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder b = new StringBuilder();
+ b.append("Layout {type=").append(getStorableTypeName());
+ b.append(", generation=").append(getGeneration());
+ b.append(", properties={");
+ try {
+ List<LayoutProperty> props = getAllProperties();
+ for (int i=0; i<props.size(); i++) {
+ if (i > 0) {
+ b.append(", ");
+ }
+ b.append(props.get(i));
+ }
+ } catch (FetchException e) {
+ b.append(e.toString());
+ }
+ b.append("}}");
+ return b.toString();
+ }
+
/**
* Returns true if the given layout matches this one. Layout ID,
* generation, and creation info is not considered in the comparison.
diff --git a/src/main/java/com/amazon/carbonado/raw/GenericStorableCodec.java b/src/main/java/com/amazon/carbonado/raw/GenericStorableCodec.java
index dd43515..4506bc1 100644
--- a/src/main/java/com/amazon/carbonado/raw/GenericStorableCodec.java
+++ b/src/main/java/com/amazon/carbonado/raw/GenericStorableCodec.java
@@ -18,7 +18,6 @@
package com.amazon.carbonado.raw;
-import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Map;
@@ -51,6 +50,8 @@ import com.amazon.carbonado.info.StorableProperty;
import com.amazon.carbonado.layout.Layout;
import com.amazon.carbonado.gen.CodeBuilderUtil;
+import com.amazon.carbonado.gen.StorableGenerator;
+import com.amazon.carbonado.gen.TriggerSupport;
import com.amazon.carbonado.util.ThrowUnchecked;
import com.amazon.carbonado.util.QuickConstructorGenerator;
@@ -64,10 +65,8 @@ import com.amazon.carbonado.util.QuickConstructorGenerator;
*/
public class GenericStorableCodec<S extends Storable> implements StorableCodec<S> {
private static final String BLANK_KEY_FIELD_NAME = "blankKey$";
- private static final String CODEC_FIELD_NAME = "codec$";
- private static final String ASSIGN_CODEC_METHOD_NAME = "assignCodec$";
- // Maps GenericEncodingStrategy instances to GenericStorableCodec instances.
+ // Maps GenericEncodingStrategy instances to Storable classes.
private static final Map cCache = new SoftValuedHashMap();
/**
@@ -100,7 +99,8 @@ public class GenericStorableCodec<S extends Storable> implements StorableCodec<S
}
return new GenericStorableCodec<S>
- (factory,
+ (key,
+ factory,
encodingStrategy.getType(),
storableImpl,
encodingStrategy,
@@ -128,30 +128,10 @@ public class GenericStorableCodec<S extends Storable> implements StorableCodec<S
// Declare some types.
final TypeDesc storableType = TypeDesc.forClass(Storable.class);
+ final TypeDesc triggerSupportType = TypeDesc.forClass(TriggerSupport.class);
final TypeDesc rawSupportType = TypeDesc.forClass(RawSupport.class);
final TypeDesc byteArrayType = TypeDesc.forClass(byte[].class);
final TypeDesc[] byteArrayParam = {byteArrayType};
- final TypeDesc codecType = TypeDesc.forClass(GenericStorableCodec.class);
- final TypeDesc decoderType = TypeDesc.forClass(Decoder.class);
- final TypeDesc weakRefType = TypeDesc.forClass(WeakReference.class);
-
- // If Layout provided, then keep a (weak) static reference to this
- // GenericStorableCodec in order to get decoders for different
- // generations. It is assigned a value after the class is loaded via a
- // public static method. It can only be assigned once.
- if (layout != null) {
- cf.addField(Modifiers.PRIVATE.toStatic(true), CODEC_FIELD_NAME, weakRefType);
- MethodInfo mi = cf.addMethod(Modifiers.PUBLIC.toStatic(true), ASSIGN_CODEC_METHOD_NAME,
- null, new TypeDesc[] {weakRefType});
- CodeBuilder b = new CodeBuilder(mi);
- b.loadStaticField(CODEC_FIELD_NAME, weakRefType);
- Label done = b.createLabel();
- b.ifNullBranch(done, false);
- b.loadLocal(b.getParameter(0));
- b.storeStaticField(CODEC_FIELD_NAME, weakRefType);
- done.setLocation();
- b.returnVoid();
- }
// Add constructors.
// 1: Accepts a RawSupport.
@@ -277,26 +257,16 @@ public class GenericStorableCodec<S extends Storable> implements StorableCodec<S
LocalVariable actualGeneration = b.createLocalVariable(null, TypeDesc.INT);
b.storeLocal(actualGeneration);
- b.loadStaticField(CODEC_FIELD_NAME, weakRefType);
- b.invokeVirtual(weakRefType, "get", TypeDesc.OBJECT, null);
- b.dup();
- Label haveCodec = b.createLabel();
- b.ifNullBranch(haveCodec, false);
-
- // Codec got reclaimed, which is unlikely to happen during normal
- // use since it must be referenced by the storage object.
- b.pop(); // Don't need the duped codec instance.
- CodeBuilderUtil.throwException(b, IllegalStateException.class, "Codec missing");
+ b.loadThis();
+ b.loadField(StorableGenerator.SUPPORT_FIELD_NAME, triggerSupportType);
+ b.checkCast(rawSupportType);
- haveCodec.setLocation();
- b.checkCast(codecType);
- b.loadLocal(actualGeneration);
Label tryStartDecode = b.createLabel().setLocation();
- b.invokeVirtual(codecType, "getDecoder", decoderType, new TypeDesc[] {TypeDesc.INT});
b.loadThis();
+ b.loadLocal(actualGeneration);
b.loadLocal(b.getParameter(0));
- b.invokeInterface(decoderType, "decode", null,
- new TypeDesc[] {storableType, byteArrayType});
+ b.invokeInterface(rawSupportType, "decode", null,
+ new TypeDesc[] {storableType, TypeDesc.INT, byteArrayType});
Label tryEndDecode = b.createLabel().setLocation();
b.returnVoid();
@@ -318,8 +288,14 @@ public class GenericStorableCodec<S extends Storable> implements StorableCodec<S
return ci.defineClass(cf);
}
- private final GenericStorableCodecFactory mFactory;
+ // Maps codec key and OrderedProperty[] keys to SearchKeyFactory instances.
+ private static final Map cCodecSearchKeyFactories = new SoftValuedHashMap();
+
+ // Maps codec key and layout generations to Decoders.
+ private static final Map cCodecDecoders = new SoftValuedHashMap();
+ private final Object mCodecKey;
+ private final GenericStorableCodecFactory mFactory;
private final Class<S> mType;
private final Class<? extends S> mStorableClass;
@@ -330,9 +306,6 @@ public class GenericStorableCodec<S extends Storable> implements StorableCodec<S
private final SearchKeyFactory<S> mPrimaryKeyFactory;
- // Maps OrderedProperty[] keys to SearchKeyFactory instances.
- private final Map mSearchKeyFactories = new SoftValuedHashMap();
-
private final Layout mLayout;
private final RawSupport<S> mSupport;
@@ -340,11 +313,16 @@ public class GenericStorableCodec<S extends Storable> implements StorableCodec<S
// Maps layout generations to Decoders.
private IntHashMap mDecoders;
- private GenericStorableCodec(GenericStorableCodecFactory factory,
+ /**
+ * @param codecKey cache key for this GenericStorableCodec instance
+ */
+ private GenericStorableCodec(Object codecKey,
+ GenericStorableCodecFactory factory,
Class<S> type, Class<? extends S> storableClass,
GenericEncodingStrategy<S> encodingStrategy,
Layout layout, RawSupport<S> support)
{
+ mCodecKey = codecKey;
mFactory = factory;
mType = type;
mStorableClass = storableClass;
@@ -354,16 +332,6 @@ public class GenericStorableCodec<S extends Storable> implements StorableCodec<S
mPrimaryKeyFactory = getSearchKeyFactory(encodingStrategy.gatherAllKeyProperties());
mLayout = layout;
mSupport = support;
-
- if (layout != null) {
- try {
- // Assign static reference back to this codec.
- Method m = storableClass.getMethod(ASSIGN_CODEC_METHOD_NAME, WeakReference.class);
- m.invoke(null, new WeakReference(this));
- } catch (Exception e) {
- ThrowUnchecked.fireFirstDeclaredCause(e);
- }
- }
}
/**
@@ -498,23 +466,36 @@ public class GenericStorableCodec<S extends Storable> implements StorableCodec<S
@SuppressWarnings("unchecked")
public SearchKeyFactory<S> getSearchKeyFactory(OrderedProperty<S>[] properties) {
// This KeyFactory makes arrays work as hashtable keys.
- Object key = org.cojen.util.KeyFactory.createKey(properties);
+ Object key = KeyFactory.createKey(new Object[] {mCodecKey, properties});
- synchronized (mSearchKeyFactories) {
- SearchKeyFactory<S> factory = (SearchKeyFactory<S>) mSearchKeyFactories.get(key);
+ synchronized (cCodecSearchKeyFactories) {
+ SearchKeyFactory<S> factory = (SearchKeyFactory<S>) cCodecSearchKeyFactories.get(key);
if (factory == null) {
factory = generateSearchKeyFactory(properties);
- mSearchKeyFactories.put(key, factory);
+ cCodecSearchKeyFactories.put(key, factory);
}
return factory;
}
}
+ @Override
+ public void decode(S dest, int generation, byte[] data) throws CorruptEncodingException {
+ try {
+ getDecoder(generation).decode(dest, data);
+ } catch (CorruptEncodingException e) {
+ throw e;
+ } catch (RepositoryException e) {
+ throw new CorruptEncodingException(e);
+ }
+ }
+
/**
* Returns a data decoder for the given generation.
*
* @throws FetchNoneException if generation is unknown
+ * @deprecated use direct decode method
*/
+ @Deprecated
public Decoder<S> getDecoder(int generation) throws FetchNoneException, FetchException {
try {
synchronized (mLayout) {
@@ -524,7 +505,22 @@ public class GenericStorableCodec<S extends Storable> implements StorableCodec<S
}
Decoder<S> decoder = (Decoder<S>) decoders.get(generation);
if (decoder == null) {
- decoder = generateDecoder(generation);
+ synchronized (cCodecDecoders) {
+ Object key = KeyFactory.createKey(new Object[] {mCodecKey, generation});
+ decoder = (Decoder<S>) cCodecDecoders.get(key);
+ if (decoder == null) {
+ decoder = generateDecoder(generation);
+ cCodecDecoders.put(key, decoder);
+ } else {
+ // Confirm that layout still exists.
+ try {
+ mLayout.getGeneration(generation);
+ } catch (FetchNoneException e) {
+ cCodecDecoders.remove(key);
+ throw e;
+ }
+ }
+ }
mDecoders.put(generation, decoder);
}
return decoder;
@@ -915,6 +911,6 @@ public class GenericStorableCodec<S extends Storable> implements StorableCodec<S
* @param data decoded into properties, some of which may be dropped if
* destination storable doesn't have it
*/
- void decode(S dest, byte[] data);
+ void decode(S dest, byte[] data) throws CorruptEncodingException;
}
}
diff --git a/src/main/java/com/amazon/carbonado/raw/RawSupport.java b/src/main/java/com/amazon/carbonado/raw/RawSupport.java
index b83e548..e2545b0 100644
--- a/src/main/java/com/amazon/carbonado/raw/RawSupport.java
+++ b/src/main/java/com/amazon/carbonado/raw/RawSupport.java
@@ -18,6 +18,7 @@
package com.amazon.carbonado.raw;
+import com.amazon.carbonado.CorruptEncodingException;
import com.amazon.carbonado.FetchException;
import com.amazon.carbonado.PersistException;
import com.amazon.carbonado.Storable;
@@ -102,4 +103,17 @@ public interface RawSupport<S extends Storable> extends MasterSupport<S> {
* @throws PersistException if blob is unrecognized
*/
long getLocator(Clob clob) throws PersistException;
+
+ /**
+ * Used for decoding different generations of Storable. If layout
+ * generations are not supported, simply throw a CorruptEncodingException.
+ *
+ * @param dest storable to receive decoded properties
+ * @param int storable layout generation number
+ * @param data decoded into properties, some of which may be dropped if
+ * destination storable doesn't have it
+ * @throws CorruptEncodingException if generation is unknown or if data cannot be decoded
+ * @since 1.2.1
+ */
+ void decode(S dest, int generation, byte[] data) throws CorruptEncodingException;
}
diff --git a/src/main/java/com/amazon/carbonado/raw/StorableCodec.java b/src/main/java/com/amazon/carbonado/raw/StorableCodec.java
index fefb0fe..6874305 100644
--- a/src/main/java/com/amazon/carbonado/raw/StorableCodec.java
+++ b/src/main/java/com/amazon/carbonado/raw/StorableCodec.java
@@ -18,6 +18,7 @@
package com.amazon.carbonado.raw;
+import com.amazon.carbonado.CorruptEncodingException;
import com.amazon.carbonado.FetchException;
import com.amazon.carbonado.Storable;
import com.amazon.carbonado.info.StorableIndex;
@@ -134,6 +135,19 @@ public interface StorableCodec<S extends Storable> {
byte[] encodePrimaryKeyPrefix();
/**
+ * Used for decoding different generations of Storable. If layout
+ * generations are not supported, simply throw a CorruptEncodingException.
+ *
+ * @param dest storable to receive decoded properties
+ * @param int storable layout generation number
+ * @param data decoded into properties, some of which may be dropped if
+ * destination storable doesn't have it
+ * @throws CorruptEncodingException if generation is unknown or if data cannot be decoded
+ * @since 1.2.1
+ */
+ void decode(S dest, int generation, byte[] data) throws CorruptEncodingException;
+
+ /**
* Returns the default {@link RawSupport} object that is supplied to
* Storable instances produced by this codec.
*
diff --git a/src/main/java/com/amazon/carbonado/repo/indexed/IndexEntryGenerator.java b/src/main/java/com/amazon/carbonado/repo/indexed/IndexEntryGenerator.java
index a126224..7fb80dc 100644
--- a/src/main/java/com/amazon/carbonado/repo/indexed/IndexEntryGenerator.java
+++ b/src/main/java/com/amazon/carbonado/repo/indexed/IndexEntryGenerator.java
@@ -28,6 +28,7 @@ import com.amazon.carbonado.Storable;
import com.amazon.carbonado.SupportException;
import com.amazon.carbonado.info.StorableIndex;
import com.amazon.carbonado.info.StorableProperty;
+import com.amazon.carbonado.synthetic.SyntheticStorableReferenceAccess;
import com.amazon.carbonado.synthetic.SyntheticStorableReferenceBuilder;
/**
@@ -100,7 +101,7 @@ class IndexEntryGenerator <S extends Storable> {
}
}
- private SyntheticStorableReferenceBuilder<S> mBuilder;
+ private SyntheticStorableReferenceAccess<S> mIndexAccess;
/**
* Convenience class for gluing new "builder" style synthetics to the traditional
@@ -112,13 +113,17 @@ class IndexEntryGenerator <S extends Storable> {
// but we have nothing better available to us
Class<S> type = index.getProperty(0).getEnclosingType();
- mBuilder = new SyntheticStorableReferenceBuilder<S>(type, index.isUnique());
+ SyntheticStorableReferenceBuilder<S> builder =
+ new SyntheticStorableReferenceBuilder<S>(type, index.isUnique());
for (int i=0; i<index.getPropertyCount(); i++) {
StorableProperty source = index.getProperty(i);
- mBuilder.addKeyProperty(source.getName(), index.getPropertyDirection(i));
+ builder.addKeyProperty(source.getName(), index.getPropertyDirection(i));
}
- mBuilder.build();
+
+ builder.build();
+
+ mIndexAccess = builder.getReferenceAccess();
}
/**
@@ -127,7 +132,7 @@ class IndexEntryGenerator <S extends Storable> {
* @return class of index entry, which is a custom Storable
*/
public Class<? extends Storable> getIndexEntryClass() {
- return mBuilder.getStorableClass();
+ return mIndexAccess.getReferenceClass();
}
/**
@@ -138,7 +143,7 @@ class IndexEntryGenerator <S extends Storable> {
* @param master master whose primary key properties will be set
*/
public void copyToMasterPrimaryKey(Storable indexEntry, S master) {
- mBuilder.copyToMasterPrimaryKey(indexEntry, master);
+ mIndexAccess.copyToMasterPrimaryKey(indexEntry, master);
}
/**
@@ -149,7 +154,7 @@ class IndexEntryGenerator <S extends Storable> {
* @param master source of property values
*/
public void copyFromMaster(Storable indexEntry, S master) {
- mBuilder.copyFromMaster(indexEntry, master);
+ mIndexAccess.copyFromMaster(indexEntry, master);
}
/**
@@ -161,13 +166,13 @@ class IndexEntryGenerator <S extends Storable> {
* @param master source of property values
*/
public boolean isConsistent(Storable indexEntry, S master) {
- return mBuilder.isConsistent(indexEntry, master);
+ return mIndexAccess.isConsistent(indexEntry, master);
}
/**
* Returns a comparator for ordering index entries.
*/
public Comparator<? extends Storable> getComparator() {
- return mBuilder.getComparator();
+ return mIndexAccess.getComparator();
}
}
diff --git a/src/main/java/com/amazon/carbonado/repo/sleepycat/BDBStorage.java b/src/main/java/com/amazon/carbonado/repo/sleepycat/BDBStorage.java
index f4a010b..1733167 100644
--- a/src/main/java/com/amazon/carbonado/repo/sleepycat/BDBStorage.java
+++ b/src/main/java/com/amazon/carbonado/repo/sleepycat/BDBStorage.java
@@ -24,6 +24,7 @@ import java.util.Map;
import org.cojen.classfile.TypeDesc;
+import com.amazon.carbonado.CorruptEncodingException;
import com.amazon.carbonado.Cursor;
import com.amazon.carbonado.FetchDeadlockException;
import com.amazon.carbonado.FetchException;
@@ -104,7 +105,7 @@ abstract class BDBStorage<Txn, S extends Storable> implements Storage<S>, Storag
private final Class<S> mType;
/** Does most of the work in generating storables, used for preparing and querying */
- private StorableCodec<S> mStorableCodec;
+ StorableCodec<S> mStorableCodec;
/**
* Reference to an instance of Proxy, defined in this class, which binds
@@ -135,7 +136,7 @@ abstract class BDBStorage<Txn, S extends Storable> implements Storage<S>, Storag
{
mRepository = repository;
mType = type;
- mRawSupport = new Support<Txn, S>(repository, this);
+ mRawSupport = new Support(repository, this);
mTriggerManager = new TriggerManager<S>();
try {
// Ask if any lobs via static method first, to prevent stack
@@ -1009,7 +1010,7 @@ abstract class BDBStorage<Txn, S extends Storable> implements Storage<S>, Storag
// Note: BDBStorage could just implement the RawSupport interface, but
// then these hidden methods would be public. A simple cast of Storage to
// RawSupport would expose them.
- private static class Support<Txn, S extends Storable> implements RawSupport<S> {
+ private class Support implements RawSupport<S> {
private final BDBRepository<Txn> mRepository;
private final BDBStorage<Txn, S> mStorage;
private Map<String, ? extends StorableProperty<S>> mProperties;
@@ -1128,6 +1129,10 @@ abstract class BDBStorage<Txn, S extends Storable> implements Storage<S>, Storag
return mStorage.getLocator(clob);
}
+ public void decode(S dest, int generation, byte[] data) throws CorruptEncodingException {
+ mStorableCodec.decode(dest, generation, data);
+ }
+
public SequenceValueProducer getSequenceValueProducer(String name)
throws PersistException
{
diff --git a/src/main/java/com/amazon/carbonado/synthetic/SyntheticStorableReferenceAccess.java b/src/main/java/com/amazon/carbonado/synthetic/SyntheticStorableReferenceAccess.java
new file mode 100644
index 0000000..778b4ac
--- /dev/null
+++ b/src/main/java/com/amazon/carbonado/synthetic/SyntheticStorableReferenceAccess.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2008 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.synthetic;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.UndeclaredThrowableException;
+
+import java.util.Comparator;
+import java.util.Iterator;
+
+import com.amazon.carbonado.Storable;
+
+import com.amazon.carbonado.cursor.SortedCursor;
+
+import com.amazon.carbonado.util.ThrowUnchecked;
+
+/**
+ * Provides access to the generated storable reference class and utility
+ * methods.
+ *
+ * @author Brian S O'Neill
+ * @see SyntheticStorableReferenceBuilder
+ * @since 1.2.1
+ */
+public class SyntheticStorableReferenceAccess<S extends Storable> {
+ private final Class<S> mMasterClass;
+ private final Class<? extends Storable> mReferenceClass;
+
+ private final Comparator<? extends Storable> mComparator;
+
+ private final Method mCopyFromMasterMethod;
+ private final Method mIsConsistentMethod;
+ private final Method mCopyToMasterPkMethod;
+
+ SyntheticStorableReferenceAccess(Class<S> masterClass,
+ Class<? extends Storable> referenceClass,
+ SyntheticStorableReferenceBuilder builder)
+ {
+ mMasterClass = masterClass;
+ mReferenceClass = referenceClass;
+
+ // We need a comparator which follows the same order as the generated
+ // storable.
+ SyntheticKey pk = builder.mPrimaryKey;
+ String[] orderBy = new String[pk.getPropertyCount()];
+ int i=0;
+ Iterator<String> it = pk.getProperties();
+ while (it.hasNext()) {
+ orderBy[i++] = it.next();
+ }
+ mComparator = SortedCursor.createComparator(referenceClass, orderBy);
+
+ try {
+ mCopyFromMasterMethod =
+ referenceClass.getMethod(builder.mCopyFromMasterMethodName, masterClass);
+
+ mIsConsistentMethod =
+ referenceClass.getMethod(builder.mIsConsistentMethodName, masterClass);
+
+ mCopyToMasterPkMethod =
+ referenceClass.getMethod(builder.mCopyToMasterPkMethodName, masterClass);
+ } catch (NoSuchMethodException e) {
+ throw new UndeclaredThrowableException(e);
+ }
+ }
+
+ /**
+ * Returns the storable class which is referenced.
+ */
+ public Class<S> getMasterClass() {
+ return mMasterClass;
+ }
+
+ /**
+ * Returns the generated storable reference class.
+ */
+ public Class<? extends Storable> getReferenceClass() {
+ return mReferenceClass;
+ }
+
+ /**
+ * Returns a comparator for ordering storable reference instances. This
+ * order matches the primary key of the master storable.
+ */
+ public Comparator<? extends Storable> getComparator() {
+ return mComparator;
+ }
+
+ /**
+ * Sets all the primary key properties of the given master, using the
+ * applicable properties of the given reference.
+ *
+ * @param reference source of property values
+ * @param master master whose primary key properties will be set
+ */
+ public void copyToMasterPrimaryKey(Storable reference, S master) {
+ try {
+ mCopyToMasterPkMethod.invoke(reference, master);
+ } catch (Exception e) {
+ ThrowUnchecked.fireFirstDeclaredCause(e);
+ }
+ }
+
+ /**
+ * Sets all the properties of the given reference, using the applicable
+ * properties of the given master.
+ *
+ * @param reference reference whose properties will be set
+ * @param master source of property values
+ */
+ public void copyFromMaster(Storable reference, S master) {
+ try {
+ mCopyFromMasterMethod.invoke(reference, master);
+ } catch (Exception e) {
+ ThrowUnchecked.fireFirstDeclaredCause(e);
+ }
+ }
+
+ /**
+ * Returns true if the properties of the given reference match those
+ * contained in the master, excluding any version property. This will
+ * always return true after a call to copyFromMaster.
+ *
+ * @param reference reference whose properties will be tested
+ * @param master source of property values
+ */
+ public boolean isConsistent(Storable reference, S master) {
+ try {
+ return (Boolean) mIsConsistentMethod.invoke(reference, master);
+ } catch (Exception e) {
+ ThrowUnchecked.fireFirstDeclaredCause(e);
+ // Not reached.
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/com/amazon/carbonado/synthetic/SyntheticStorableReferenceBuilder.java b/src/main/java/com/amazon/carbonado/synthetic/SyntheticStorableReferenceBuilder.java
index 4fddcd5..a06c557 100644
--- a/src/main/java/com/amazon/carbonado/synthetic/SyntheticStorableReferenceBuilder.java
+++ b/src/main/java/com/amazon/carbonado/synthetic/SyntheticStorableReferenceBuilder.java
@@ -18,7 +18,6 @@
package com.amazon.carbonado.synthetic;
import java.lang.reflect.Method;
-import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -29,13 +28,11 @@ import java.util.Set;
import com.amazon.carbonado.Storable;
import com.amazon.carbonado.SupportException;
-import com.amazon.carbonado.cursor.SortedCursor;
import com.amazon.carbonado.info.Direction;
import com.amazon.carbonado.info.StorableInfo;
import com.amazon.carbonado.info.StorableIntrospector;
import com.amazon.carbonado.info.StorableProperty;
import com.amazon.carbonado.gen.CodeBuilderUtil;
-import com.amazon.carbonado.util.ThrowUnchecked;
import org.cojen.classfile.ClassFile;
import org.cojen.classfile.CodeBuilder;
@@ -80,7 +77,7 @@ public class SyntheticStorableReferenceBuilder<S extends Storable>
// Information about the storable from which this one is derived
// private StorableInfo<S> mBaseStorableInfo;
- private Class mMasterStorableClass;
+ private Class<S> mMasterStorableClass;
// Stashed copy of the results of calling StorableIntrospector.examine(...)
// on the master storable class.
@@ -90,7 +87,7 @@ public class SyntheticStorableReferenceBuilder<S extends Storable>
private SyntheticStorableBuilder mBuilder;
// Primary key of generated storable.
- private SyntheticKey mPrimaryKey;
+ SyntheticKey mPrimaryKey;
// Elements added to primary key to ensure uniqueness
private Set<String> mExtraPkProps;
@@ -99,9 +96,6 @@ public class SyntheticStorableReferenceBuilder<S extends Storable>
// uniquely identify a unique instance of the referent.
private boolean mIsUnique = true;
- // The result of building
- private Class<? extends Storable> mSyntheticClass;
-
// The list of properties explicitly added to this reference builder
private List<SyntheticProperty> mUserProps;
@@ -110,16 +104,12 @@ public class SyntheticStorableReferenceBuilder<S extends Storable>
// are retrieved from the master.
private List<StorableProperty> mCommonProps;
- private String mCopyFromMasterMethodName;
- private Method mCopyFromMasterMethod;
-
- private String mIsConsistentMethodName;
- private Method mIsConsistentMethod;
-
- private String mCopyToMasterPkMethodName;
- private Method mCopyToMasterPkMethod;
+ String mCopyFromMasterMethodName;
+ String mIsConsistentMethodName;
+ String mCopyToMasterPkMethodName;
- private Comparator<? extends Storable> mComparator;
+ // The result of building.
+ private SyntheticStorableReferenceAccess mReferenceAccess;
/**
* @param storableClass
@@ -210,26 +200,27 @@ public class SyntheticStorableReferenceBuilder<S extends Storable>
return cfg;
}
+ /**
+ * Build and return access to the generated storable reference class.
+ *
+ * @since 1.2.1
+ */
+ public SyntheticStorableReferenceAccess getReferenceAccess() {
+ if (mReferenceAccess == null) {
+ Class<? extends Storable> referenceClass = mBuilder.getStorableClass();
+ mReferenceAccess = new SyntheticStorableReferenceAccess
+ (mMasterStorableClass, referenceClass, this);
+ }
+ return mReferenceAccess;
+ }
+
/*
* (non-Javadoc)
*
* @see com.amazon.carbonado.synthetic.SyntheticBuilder#getStorableClass()
*/
public Class<? extends Storable> getStorableClass() throws IllegalStateException {
- if (mSyntheticClass == null) {
- mSyntheticClass = mBuilder.getStorableClass();
-
- // We need a comparator which follows the same order as the generated
- // storable. We can't construct it until we get here.
- String[] orderBy = new String[mPrimaryKey.getPropertyCount()];
- int i=0;
- Iterator<String> it = mPrimaryKey.getProperties();
- while (it.hasNext()) {
- orderBy[i++] = it.next();
- }
- mComparator = SortedCursor.createComparator(mSyntheticClass, orderBy);
- }
- return mSyntheticClass;
+ return getReferenceAccess().getReferenceClass();
}
/*
@@ -356,22 +347,11 @@ public class SyntheticStorableReferenceBuilder<S extends Storable>
*
* @param indexEntry source of property values
* @param master master whose primary key properties will be set
+ * @deprecated call getReferenceAccess
*/
+ @Deprecated
public void copyToMasterPrimaryKey(Storable indexEntry, S master) {
- if (mCopyToMasterPkMethod == null) {
- try {
- mCopyToMasterPkMethod =
- mSyntheticClass.getMethod(mCopyToMasterPkMethodName, mMasterStorableClass);
- } catch (NoSuchMethodException e) {
- throw new UndeclaredThrowableException(e);
- }
- }
-
- try {
- mCopyToMasterPkMethod.invoke(indexEntry, master);
- } catch (Exception e) {
- ThrowUnchecked.fireFirstDeclaredCause(e);
- }
+ getReferenceAccess().copyToMasterPrimaryKey(indexEntry, master);
}
/**
@@ -380,22 +360,11 @@ public class SyntheticStorableReferenceBuilder<S extends Storable>
*
* @param indexEntry index entry whose properties will be set
* @param master source of property values
+ * @deprecated call getReferenceAccess
*/
+ @Deprecated
public void copyFromMaster(Storable indexEntry, S master) {
- if (mCopyFromMasterMethod == null) {
- try {
- mCopyFromMasterMethod =
- mSyntheticClass.getMethod(mCopyFromMasterMethodName, mMasterStorableClass);
- } catch (NoSuchMethodException e) {
- throw new UndeclaredThrowableException(e);
- }
- }
-
- try {
- mCopyFromMasterMethod.invoke(indexEntry, master);
- } catch (Exception e) {
- ThrowUnchecked.fireFirstDeclaredCause(e);
- }
+ getReferenceAccess().copyFromMaster(indexEntry, master);
}
/**
@@ -407,31 +376,20 @@ public class SyntheticStorableReferenceBuilder<S extends Storable>
* index entry whose properties will be tested
* @param master
* source of property values
+ * @deprecated call getReferenceAccess
*/
+ @Deprecated
public boolean isConsistent(Storable indexEntry, S master) {
- if (mIsConsistentMethod == null) {
- try {
- mIsConsistentMethod =
- mSyntheticClass.getMethod(mIsConsistentMethodName, mMasterStorableClass);
- } catch (NoSuchMethodException e) {
- throw new UndeclaredThrowableException(e);
- }
- }
-
- try {
- return (Boolean) mIsConsistentMethod.invoke(indexEntry, master);
- } catch (Exception e) {
- ThrowUnchecked.fireFirstDeclaredCause(e);
- // Not reached.
- return false;
- }
+ return getReferenceAccess().isConsistent(indexEntry, master);
}
/**
* Returns a comparator for ordering index entries.
+ * @deprecated call getReferenceAccess
*/
+ @Deprecated
public Comparator<? extends Storable> getComparator() {
- return mComparator;
+ return getReferenceAccess().getComparator();
}
/**