diff options
Diffstat (limited to 'src/main/java/com/amazon/carbonado/spi')
21 files changed, 1 insertions, 7574 deletions
diff --git a/src/main/java/com/amazon/carbonado/spi/StorableSerializer.java b/src/main/java/com/amazon/carbonado/spi/StorableSerializer.java index 1f6ab6e..83621e9 100644 --- a/src/main/java/com/amazon/carbonado/spi/StorableSerializer.java +++ b/src/main/java/com/amazon/carbonado/spi/StorableSerializer.java @@ -52,7 +52,7 @@ import com.amazon.carbonado.info.StorableProperty; import static com.amazon.carbonado.spi.CommonMethodNames.*;
-import com.amazon.carbonado.spi.raw.GenericEncodingStrategy;
+import com.amazon.carbonado.raw.GenericEncodingStrategy;
/**
* Support for general-purpose serialization of storables.
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/CustomStorableCodec.java b/src/main/java/com/amazon/carbonado/spi/raw/CustomStorableCodec.java deleted file mode 100644 index f908635..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/CustomStorableCodec.java +++ /dev/null @@ -1,332 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-import java.util.Map;
-
-import org.cojen.classfile.ClassFile;
-import org.cojen.classfile.CodeBuilder;
-import org.cojen.classfile.MethodInfo;
-import org.cojen.classfile.Modifiers;
-import org.cojen.classfile.TypeDesc;
-import org.cojen.util.ClassInjector;
-import org.cojen.util.WeakIdentityMap;
-
-import com.amazon.carbonado.CorruptEncodingException;
-import com.amazon.carbonado.FetchException;
-import com.amazon.carbonado.Storable;
-import com.amazon.carbonado.Storage;
-import com.amazon.carbonado.SupportException;
-
-import com.amazon.carbonado.info.Direction;
-import com.amazon.carbonado.info.StorableIndex;
-import com.amazon.carbonado.info.StorableIntrospector;
-import com.amazon.carbonado.info.StorableProperty;
-
-import com.amazon.carbonado.util.QuickConstructorGenerator;
-
-/**
- * Allows codecs to be defined for storables that have a custom encoding.
- *
- * @author Brian S O'Neill
- * @see CustomStorableCodecFactory
- */
-public abstract class CustomStorableCodec<S extends Storable> implements StorableCodec<S> {
- // Generated storable instances maintain a reference to user-defined
- // concrete subclass of this class.
- private static final String CUSTOM_STORABLE_CODEC_FIELD_NAME = "customStorableCodec$";
-
- @SuppressWarnings("unchecked")
- private static Map<Class, RawStorableGenerator.Flavors<? extends Storable>> cCache =
- new WeakIdentityMap();
-
- /**
- * Returns a storable implementation that calls into CustomStorableCodec
- * implementation for encoding and decoding.
- */
- @SuppressWarnings("unchecked")
- static <S extends Storable> Class<? extends S>
- getStorableClass(Class<S> type, boolean isMaster)
- throws SupportException
- {
- synchronized (cCache) {
- Class<? extends S> storableClass;
-
- RawStorableGenerator.Flavors<S> flavors =
- (RawStorableGenerator.Flavors<S>) cCache.get(type);
-
- if (flavors == null) {
- flavors = new RawStorableGenerator.Flavors<S>();
- cCache.put(type, flavors);
- } else if ((storableClass = flavors.getClass(isMaster)) != null) {
- return storableClass;
- }
-
- storableClass = generateStorableClass(type, isMaster);
- flavors.setClass(storableClass, isMaster);
-
- return storableClass;
- }
- }
-
- @SuppressWarnings("unchecked")
- private static <S extends Storable> Class<? extends S>
- generateStorableClass(Class<S> type, boolean isMaster)
- throws SupportException
- {
- final Class<? extends S> abstractClass =
- RawStorableGenerator.getAbstractClass(type, isMaster);
-
- ClassInjector ci = ClassInjector.create
- (type.getName(), abstractClass.getClassLoader());
-
- ClassFile cf = new ClassFile(ci.getClassName(), abstractClass);
- cf.markSynthetic();
- cf.setSourceFile(CustomStorableCodec.class.getName());
- cf.setTarget("1.5");
-
- // Declare some types.
- final TypeDesc rawSupportType = TypeDesc.forClass(RawSupport.class);
- final TypeDesc byteArrayType = TypeDesc.forClass(byte[].class);
- final TypeDesc[] byteArrayParam = {byteArrayType};
- final TypeDesc customStorableCodecType = TypeDesc.forClass(CustomStorableCodec.class);
-
- // Add field for saving reference to concrete CustomStorableCodec.
- cf.addField(Modifiers.PRIVATE.toFinal(true),
- CUSTOM_STORABLE_CODEC_FIELD_NAME, customStorableCodecType);
-
- // Add constructor that accepts a RawSupport and a CustomStorableCodec.
- {
- TypeDesc[] params = {rawSupportType, customStorableCodecType};
- MethodInfo mi = cf.addConstructor(Modifiers.PUBLIC, params);
- CodeBuilder b = new CodeBuilder(mi);
-
- // Call super class constructor.
- b.loadThis();
- b.loadLocal(b.getParameter(0));
- params = new TypeDesc[] {rawSupportType};
- b.invokeSuperConstructor(params);
-
- // Set private reference to customStorableCodec.
- b.loadThis();
- b.loadLocal(b.getParameter(1));
- b.storeField(CUSTOM_STORABLE_CODEC_FIELD_NAME, customStorableCodecType);
-
- b.returnVoid();
- }
-
- // Add constructor that accepts a RawSupport, an encoded key, an
- // encoded data, and a CustomStorableCodec.
- {
- TypeDesc[] params = {rawSupportType, byteArrayType, byteArrayType,
- customStorableCodecType};
- MethodInfo mi = cf.addConstructor(Modifiers.PUBLIC, params);
- CodeBuilder b = new CodeBuilder(mi);
-
- // Set private reference to customStorableCodec before calling
- // super constructor. This is necessary because super class
- // constructor will call our decode methods, which need the
- // customStorableCodec. This trick is not allowed in Java, but the
- // virtual machine verifier allows it.
- b.loadThis();
- b.loadLocal(b.getParameter(3));
- b.storeField(CUSTOM_STORABLE_CODEC_FIELD_NAME, customStorableCodecType);
-
- // Now call super class constructor.
- b.loadThis();
- b.loadLocal(b.getParameter(0));
- b.loadLocal(b.getParameter(1));
- b.loadLocal(b.getParameter(2));
- params = new TypeDesc[] {rawSupportType, byteArrayType, byteArrayType};
- b.invokeSuperConstructor(params);
-
- b.returnVoid();
- }
-
- // Implement protected abstract methods inherited from parent class.
-
- // byte[] encodeKey()
- {
- // Encode the primary key into a byte array that supports correct
- // ordering. No special key comparator is needed.
- MethodInfo mi = cf.addMethod(Modifiers.PROTECTED,
- RawStorableGenerator.ENCODE_KEY_METHOD_NAME,
- byteArrayType, null);
- CodeBuilder b = new CodeBuilder(mi);
-
- b.loadThis();
- b.loadField(CUSTOM_STORABLE_CODEC_FIELD_NAME, customStorableCodecType);
- TypeDesc[] params = {TypeDesc.forClass(Storable.class)};
- b.loadThis();
- b.invokeVirtual(customStorableCodecType, "encodePrimaryKey", byteArrayType, params);
- b.returnValue(byteArrayType);
- }
-
- // byte[] encodeData()
- {
- // Encoding non-primary key data properties.
- MethodInfo mi = cf.addMethod(Modifiers.PROTECTED,
- RawStorableGenerator.ENCODE_DATA_METHOD_NAME,
- byteArrayType, null);
- CodeBuilder b = new CodeBuilder(mi);
-
- b.loadThis();
- b.loadField(CUSTOM_STORABLE_CODEC_FIELD_NAME, customStorableCodecType);
- TypeDesc[] params = {TypeDesc.forClass(Storable.class)};
- b.loadThis();
- b.invokeVirtual(customStorableCodecType, "encodeData", byteArrayType, params);
- b.returnValue(byteArrayType);
- }
-
- // void decodeKey(byte[])
- {
- MethodInfo mi = cf.addMethod(Modifiers.PROTECTED,
- RawStorableGenerator.DECODE_KEY_METHOD_NAME,
- null, byteArrayParam);
- CodeBuilder b = new CodeBuilder(mi);
-
- b.loadThis();
- b.loadField(CUSTOM_STORABLE_CODEC_FIELD_NAME, customStorableCodecType);
- TypeDesc[] params = {TypeDesc.forClass(Storable.class), byteArrayType};
- b.loadThis();
- b.loadLocal(b.getParameter(0));
- b.invokeVirtual(customStorableCodecType, "decodePrimaryKey", null, params);
- b.returnVoid();
- }
-
- // void decodeData(byte[])
- {
- MethodInfo mi = cf.addMethod(Modifiers.PROTECTED,
- RawStorableGenerator.DECODE_DATA_METHOD_NAME,
- null, byteArrayParam);
- CodeBuilder b = new CodeBuilder(mi);
-
- b.loadThis();
- b.loadField(CUSTOM_STORABLE_CODEC_FIELD_NAME, customStorableCodecType);
- TypeDesc[] params = {TypeDesc.forClass(Storable.class), byteArrayType};
- b.loadThis();
- b.loadLocal(b.getParameter(0));
- b.invokeVirtual(customStorableCodecType, "decodeData", null, params);
- b.returnVoid();
- }
-
- return ci.defineClass(cf);
- }
-
- private final Class<S> mType;
- private final int mPkPropertyCount;
- private final InstanceFactory mInstanceFactory;
-
- public interface InstanceFactory {
- Storable instantiate(RawSupport support, CustomStorableCodec codec);
-
- Storable instantiate(RawSupport support, byte[] key, byte[] value,
- CustomStorableCodec codec)
- throws FetchException;
- }
-
- /**
- * @param isMaster when true, version properties and sequences are managed
- * @throws SupportException if Storable is not supported
- */
- public CustomStorableCodec(Class<S> type, boolean isMaster) throws SupportException {
- mType = type;
- mPkPropertyCount = getPrimaryKeyIndex().getPropertyCount();
- Class<? extends S> storableClass = getStorableClass(type, isMaster);
- mInstanceFactory = QuickConstructorGenerator
- .getInstance(storableClass, InstanceFactory.class);
- }
-
- public Class<S> getStorableType() {
- return mType;
- }
-
- @SuppressWarnings("unchecked")
- public S instantiate(RawSupport<S> support) {
- return (S) mInstanceFactory.instantiate(support, this);
- }
-
- @SuppressWarnings("unchecked")
- public S instantiate(RawSupport<S> support, byte[] key, byte[] value)
- throws FetchException
- {
- return (S) mInstanceFactory.instantiate(support, key, value, this);
- }
-
- public byte[] encodePrimaryKey(S storable) {
- return encodePrimaryKey(storable, 0, mPkPropertyCount);
- }
-
- public byte[] encodePrimaryKey(Object[] values) {
- return encodePrimaryKey(values, 0, mPkPropertyCount);
- }
-
- /**
- * Convenient access to all the storable properties.
- */
- public Map<String, ? extends StorableProperty<S>> getAllProperties() {
- return StorableIntrospector.examine(getStorableType()).getAllProperties();
- }
-
- /**
- * Convenient way to define the clustered primary key index
- * descriptor. Direction can be specified by prefixing the property name
- * with a '+' or '-'. If unspecified, direction is assumed to be ascending.
- */
- @SuppressWarnings("unchecked")
- public StorableIndex<S> buildPkIndex(String... propertyNames) {
- Map<String, ? extends StorableProperty<S>> map = getAllProperties();
- int length = propertyNames.length;
- StorableProperty<S>[] properties = new StorableProperty[length];
- Direction[] directions = new Direction[length];
- for (int i=0; i<length; i++) {
- String name = propertyNames[i];
- char c = name.charAt(0);
- Direction dir = Direction.fromCharacter(c);
- if (dir != Direction.UNSPECIFIED || c == Direction.UNSPECIFIED.toCharacter()) {
- name = name.substring(1);
- } else {
- // Default to ascending if not specified.
- dir = Direction.ASCENDING;
- }
- if ((properties[i] = map.get(name)) == null) {
- throw new IllegalArgumentException("Unknown property: " + name);
- }
- directions[i] = dir;
- }
- return new StorableIndex<S>(properties, directions, true, true);
- }
-
- /**
- * Decode the primary key into properties of the storable.
- */
- public abstract void decodePrimaryKey(S storable, byte[] bytes)
- throws CorruptEncodingException;
-
- /**
- * Encode all properties of the storable excluding the primary key.
- */
- public abstract byte[] encodeData(S storable);
-
- /**
- * Decode the data into properties of the storable.
- */
- public abstract void decodeData(S storable, byte[] bytes)
- throws CorruptEncodingException;
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/CustomStorableCodecFactory.java b/src/main/java/com/amazon/carbonado/spi/raw/CustomStorableCodecFactory.java deleted file mode 100644 index 64d19e8..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/CustomStorableCodecFactory.java +++ /dev/null @@ -1,70 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-import com.amazon.carbonado.Storable;
-import com.amazon.carbonado.SupportException;
-
-import com.amazon.carbonado.info.StorableIndex;
-import com.amazon.carbonado.layout.Layout;
-
-/**
- * Factory for custom storable codecs.
- *
- * @author Brian S O'Neill
- */
-public abstract class CustomStorableCodecFactory implements StorableCodecFactory {
- public CustomStorableCodecFactory() {
- }
-
- /**
- * Returns null to let repository decide what the name should be.
- */
- public String getStorageName(Class<? extends Storable> type) throws SupportException {
- return null;
- }
-
- /**
- * @param type type of storable to create codec for
- * @param pkIndex ignored
- * @param isMaster when true, version properties and sequences are managed
- * @param layout when non-null, attempt to encode a storable layout
- * generation value in each storable
- * @throws SupportException if type is not supported
- */
- public <S extends Storable> CustomStorableCodec<S> createCodec(Class<S> type,
- StorableIndex pkIndex,
- boolean isMaster,
- Layout layout)
- throws SupportException
- {
- return createCodec(type, isMaster, layout);
- }
-
- /**
- * @param type type of storable to create codec for
- * @param isMaster when true, version properties and sequences are managed
- * @param layout when non-null, attempt to encode a storable layout
- * generation value in each storable
- * @throws SupportException if type is not supported
- */
- protected abstract <S extends Storable> CustomStorableCodec<S>
- createCodec(Class<S> type, boolean isMaster, Layout layout)
- throws SupportException;
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/DataDecoder.java b/src/main/java/com/amazon/carbonado/spi/raw/DataDecoder.java deleted file mode 100644 index 66f2f2f..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/DataDecoder.java +++ /dev/null @@ -1,567 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-import com.amazon.carbonado.CorruptEncodingException;
-
-import static com.amazon.carbonado.spi.raw.DataEncoder.*;
-
-/**
- * A very low-level class that decodes key components encoded by methods of
- * {@link DataEncoder}.
- *
- * @author Brian S O'Neill
- */
-public class DataDecoder {
- static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
-
- /**
- * Decodes a signed integer from exactly 4 bytes.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return signed integer value
- */
- public static int decodeInt(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- int value = (src[srcOffset] << 24) | ((src[srcOffset + 1] & 0xff) << 16) |
- ((src[srcOffset + 2] & 0xff) << 8) | (src[srcOffset + 3] & 0xff);
- return value ^ 0x80000000;
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a signed Integer object from exactly 1 or 5 bytes. If null is
- * returned, then 1 byte was read.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return signed Integer object or null
- */
- public static Integer decodeIntegerObj(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- int b = src[srcOffset];
- if (b == NULL_BYTE_HIGH || b == NULL_BYTE_LOW) {
- return null;
- }
- return decodeInt(src, srcOffset + 1);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a signed long from exactly 8 bytes.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return signed long value
- */
- public static long decodeLong(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- return
- (((long)(((src[srcOffset ] ) << 24) |
- ((src[srcOffset + 1] & 0xff) << 16) |
- ((src[srcOffset + 2] & 0xff) << 8 ) |
- ((src[srcOffset + 3] & 0xff) )) ^ 0x80000000 ) << 32) |
- (((long)(((src[srcOffset + 4] ) << 24) |
- ((src[srcOffset + 5] & 0xff) << 16) |
- ((src[srcOffset + 6] & 0xff) << 8 ) |
- ((src[srcOffset + 7] & 0xff) )) & 0xffffffffL) );
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a signed Long object from exactly 1 or 9 bytes. If null is
- * returned, then 1 byte was read.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return signed Long object or null
- */
- public static Long decodeLongObj(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- int b = src[srcOffset];
- if (b == NULL_BYTE_HIGH || b == NULL_BYTE_LOW) {
- return null;
- }
- return decodeLong(src, srcOffset + 1);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a signed byte from exactly 1 byte.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return signed byte value
- */
- public static byte decodeByte(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- return (byte)(src[srcOffset] ^ 0x80);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a signed Byte object from exactly 1 or 2 bytes. If null is
- * returned, then 1 byte was read.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return signed Byte object or null
- */
- public static Byte decodeByteObj(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- int b = src[srcOffset];
- if (b == NULL_BYTE_HIGH || b == NULL_BYTE_LOW) {
- return null;
- }
- return decodeByte(src, srcOffset + 1);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a signed short from exactly 2 bytes.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return signed short value
- */
- public static short decodeShort(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- return (short)(((src[srcOffset] << 8) | (src[srcOffset + 1] & 0xff)) ^ 0x8000);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a signed Short object from exactly 1 or 3 bytes. If null is
- * returned, then 1 byte was read.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return signed Short object or null
- */
- public static Short decodeShortObj(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- int b = src[srcOffset];
- if (b == NULL_BYTE_HIGH || b == NULL_BYTE_LOW) {
- return null;
- }
- return decodeShort(src, srcOffset + 1);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a char from exactly 2 bytes.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return char value
- */
- public static char decodeChar(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- return (char)((src[srcOffset] << 8) | (src[srcOffset + 1] & 0xff));
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a Character object from exactly 1 or 3 bytes. If null is
- * returned, then 1 byte was read.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return Character object or null
- */
- public static Character decodeCharacterObj(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- int b = src[srcOffset];
- if (b == NULL_BYTE_HIGH || b == NULL_BYTE_LOW) {
- return null;
- }
- return decodeChar(src, srcOffset + 1);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a boolean from exactly 1 byte.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return boolean value
- */
- public static boolean decodeBoolean(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- return src[srcOffset] == (byte)128;
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a Boolean object from exactly 1 byte.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return Boolean object or null
- */
- public static Boolean decodeBooleanObj(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- switch (src[srcOffset]) {
- case NULL_BYTE_LOW: case NULL_BYTE_HIGH:
- return null;
- case (byte)128:
- return Boolean.TRUE;
- default:
- return Boolean.FALSE;
- }
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a float from exactly 4 bytes.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return float value
- */
- public static float decodeFloat(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- int bits = decodeFloatBits(src, srcOffset);
- bits ^= (bits < 0) ? 0x80000000 : 0xffffffff;
- return Float.intBitsToFloat(bits);
- }
-
- /**
- * Decodes a Float object from exactly 4 bytes.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return Float object or null
- */
- public static Float decodeFloatObj(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- int bits = decodeFloatBits(src, srcOffset);
- bits ^= (bits < 0) ? 0x80000000 : 0xffffffff;
- return bits == 0x7fffffff ? null : Float.intBitsToFloat(bits);
- }
-
- protected static int decodeFloatBits(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- return (src[srcOffset] << 24) | ((src[srcOffset + 1] & 0xff) << 16) |
- ((src[srcOffset + 2] & 0xff) << 8) | (src[srcOffset + 3] & 0xff);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a double from exactly 8 bytes.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return double value
- */
- public static double decodeDouble(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- long bits = decodeDoubleBits(src, srcOffset);
- bits ^= (bits < 0) ? 0x8000000000000000L : 0xffffffffffffffffL;
- return Double.longBitsToDouble(bits);
- }
-
- /**
- * Decodes a Double object from exactly 8 bytes.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return Double object or null
- */
- public static Double decodeDoubleObj(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- long bits = decodeDoubleBits(src, srcOffset);
- bits ^= (bits < 0) ? 0x8000000000000000L : 0xffffffffffffffffL;
- return bits == 0x7fffffffffffffffL ? null : Double.longBitsToDouble(bits);
- }
-
- protected static long decodeDoubleBits(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- return
- (((long)(((src[srcOffset ] ) << 24) |
- ((src[srcOffset + 1] & 0xff) << 16) |
- ((src[srcOffset + 2] & 0xff) << 8 ) |
- ((src[srcOffset + 3] & 0xff) )) ) << 32) |
- (((long)(((src[srcOffset + 4] ) << 24) |
- ((src[srcOffset + 5] & 0xff) << 16) |
- ((src[srcOffset + 6] & 0xff) << 8 ) |
- ((src[srcOffset + 7] & 0xff) )) & 0xffffffffL));
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes the given byte array.
- *
- * @param src source of encoded data
- * @param srcOffset offset into encoded data
- * @param valueRef decoded byte array is stored in element 0, which may be null
- * @return amount of bytes read from source
- * @throws CorruptEncodingException if source data is corrupt
- */
- public static int decode(byte[] src, int srcOffset, byte[][] valueRef)
- throws CorruptEncodingException
- {
- try {
- final int originalOffset = srcOffset;
-
- int b = src[srcOffset++] & 0xff;
- if (b >= 0xf8) {
- valueRef[0] = null;
- return 1;
- }
-
- int valueLength;
- if (b <= 0x7f) {
- valueLength = b;
- } else if (b <= 0xbf) {
- valueLength = ((b & 0x3f) << 8) | (src[srcOffset++] & 0xff);
- } else if (b <= 0xdf) {
- valueLength = ((b & 0x1f) << 16) | ((src[srcOffset++] & 0xff) << 8) |
- (src[srcOffset++] & 0xff);
- } else if (b <= 0xef) {
- valueLength = ((b & 0x0f) << 24) | ((src[srcOffset++] & 0xff) << 16) |
- ((src[srcOffset++] & 0xff) << 8) | (src[srcOffset++] & 0xff);
- } else {
- valueLength = ((b & 0x07) << 24) | ((src[srcOffset++] & 0xff) << 16) |
- ((src[srcOffset++] & 0xff) << 8) | (src[srcOffset++] & 0xff);
- }
-
- if (valueLength == 0) {
- valueRef[0] = EMPTY_BYTE_ARRAY;
- } else {
- byte[] value = new byte[valueLength];
- System.arraycopy(src, srcOffset, value, 0, valueLength);
- valueRef[0]= value;
- }
-
- return srcOffset - originalOffset + valueLength;
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes an encoded string from the given byte array.
- *
- * @param src source of encoded data
- * @param srcOffset offset into encoded data
- * @param valueRef decoded string is stored in element 0, which may be null
- * @return amount of bytes read from source
- * @throws CorruptEncodingException if source data is corrupt
- */
- public static int decodeString(byte[] src, int srcOffset, String[] valueRef)
- throws CorruptEncodingException
- {
- try {
- final int originalOffset = srcOffset;
-
- int b = src[srcOffset++] & 0xff;
- if (b >= 0xf8) {
- valueRef[0] = null;
- return 1;
- }
-
- int valueLength;
- if (b <= 0x7f) {
- valueLength = b;
- } else if (b <= 0xbf) {
- valueLength = ((b & 0x3f) << 8) | (src[srcOffset++] & 0xff);
- } else if (b <= 0xdf) {
- valueLength = ((b & 0x1f) << 16) | ((src[srcOffset++] & 0xff) << 8) |
- (src[srcOffset++] & 0xff);
- } else if (b <= 0xef) {
- valueLength = ((b & 0x0f) << 24) | ((src[srcOffset++] & 0xff) << 16) |
- ((src[srcOffset++] & 0xff) << 8) | (src[srcOffset++] & 0xff);
- } else {
- valueLength = ((src[srcOffset++] & 0xff) << 24) |
- ((src[srcOffset++] & 0xff) << 16) |
- ((src[srcOffset++] & 0xff) << 8) | (src[srcOffset++] & 0xff);
- }
-
- if (valueLength == 0) {
- valueRef[0] = "";
- return srcOffset - originalOffset;
- }
-
- char[] value = new char[valueLength];
- int valueOffset = 0;
-
- while (valueOffset < valueLength) {
- int c = src[srcOffset++] & 0xff;
- switch (c >> 5) {
- case 0: case 1: case 2: case 3:
- // 0xxxxxxx
- value[valueOffset++] = (char)c;
- break;
- case 4: case 5:
- // 10xxxxxx xxxxxxxx
- value[valueOffset++] = (char)(((c & 0x3f) << 8) | (src[srcOffset++] & 0xff));
- break;
- case 6:
- // 110xxxxx xxxxxxxx xxxxxxxx
- c = ((c & 0x1f) << 16) | ((src[srcOffset++] & 0xff) << 8)
- | (src[srcOffset++] & 0xff);
- if (c >= 0x10000) {
- // Split into surrogate pair.
- c -= 0x10000;
- value[valueOffset++] = (char)(0xd800 | ((c >> 10) & 0x3ff));
- value[valueOffset++] = (char)(0xdc00 | (c & 0x3ff));
- } else {
- value[valueOffset++] = (char)c;
- }
- break;
- default:
- // 111xxxxx
- // Illegal.
- throw new CorruptEncodingException
- ("Corrupt encoded string data (source offset = "
- + (srcOffset - 1) + ')');
- }
- }
-
- valueRef[0] = new String(value);
-
- return srcOffset - originalOffset;
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes the given byte array which was encoded by {@link
- * DataEncoder#encodeSingle}.
- *
- * @param prefixPadding amount of extra bytes to skip from start of encoded byte array
- * @param suffixPadding amount of extra bytes to skip at end of encoded byte array
- */
- public static byte[] decodeSingle(byte[] src, int prefixPadding, int suffixPadding)
- throws CorruptEncodingException
- {
- try {
- int length = src.length - suffixPadding - prefixPadding;
- if (length == 0) {
- return EMPTY_BYTE_ARRAY;
- }
- if (prefixPadding <= 0 && suffixPadding <= 0) {
- return src;
- }
- byte[] dst = new byte[length];
- System.arraycopy(src, prefixPadding, dst, 0, length);
- return dst;
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes the given byte array which was encoded by {@link
- * DataEncoder#encodeSingleNullable}.
- */
- public static byte[] decodeSingleNullable(byte[] src) throws CorruptEncodingException {
- return decodeSingleNullable(src, 0, 0);
- }
-
- /**
- * Decodes the given byte array which was encoded by {@link
- * DataEncoder#encodeSingleNullable}.
- *
- * @param prefixPadding amount of extra bytes to skip from start of encoded byte array
- * @param suffixPadding amount of extra bytes to skip at end of encoded byte array
- */
- public static byte[] decodeSingleNullable(byte[] src, int prefixPadding, int suffixPadding)
- throws CorruptEncodingException
- {
- try {
- byte b = src[prefixPadding];
- if (b == NULL_BYTE_HIGH || b == NULL_BYTE_LOW) {
- return null;
- }
- int length = src.length - suffixPadding - 1 - prefixPadding;
- if (length == 0) {
- return EMPTY_BYTE_ARRAY;
- }
- byte[] value = new byte[length];
- System.arraycopy(src, 1 + prefixPadding, value, 0, length);
- return value;
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/DataEncoder.java b/src/main/java/com/amazon/carbonado/spi/raw/DataEncoder.java deleted file mode 100644 index 15b8dca..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/DataEncoder.java +++ /dev/null @@ -1,595 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-/**
- * A very low-level class that supports encoding of primitive data. For
- * encoding data into keys, see {@link KeyEncoder}.
- *
- * @author Brian S O'Neill
- * @see DataDecoder
- */
-public class DataEncoder {
- // Note: Most of these methods are inherited by KeyEncoder, which is why
- // they are encoded for supporting proper ordering.
-
- /** Byte to use for null, low ordering */
- static final byte NULL_BYTE_LOW = 0;
-
- /** Byte to use for null, high ordering */
- static final byte NULL_BYTE_HIGH = (byte)~NULL_BYTE_LOW;
-
- /** Byte to use for not-null, low ordering */
- static final byte NOT_NULL_BYTE_HIGH = (byte)128;
-
- /** Byte to use for not-null, high ordering */
- static final byte NOT_NULL_BYTE_LOW = (byte)~NOT_NULL_BYTE_HIGH;
-
- static final byte[] NULL_BYTE_ARRAY_HIGH = {NULL_BYTE_HIGH};
- static final byte[] NULL_BYTE_ARRAY_LOW = {NULL_BYTE_LOW};
- static final byte[] NOT_NULL_BYTE_ARRAY_HIGH = {NOT_NULL_BYTE_HIGH};
- static final byte[] NOT_NULL_BYTE_ARRAY_LOW = {NOT_NULL_BYTE_LOW};
-
- /**
- * Encodes the given signed integer into exactly 4 bytes.
- *
- * @param value signed integer value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encode(int value, byte[] dst, int dstOffset) {
- value ^= 0x80000000;
- dst[dstOffset ] = (byte)(value >> 24);
- dst[dstOffset + 1] = (byte)(value >> 16);
- dst[dstOffset + 2] = (byte)(value >> 8);
- dst[dstOffset + 3] = (byte)value;
- }
-
- /**
- * Encodes the given signed Integer object into exactly 1 or 5 bytes. If
- * the Integer object is never expected to be null, consider encoding as an
- * int primitive.
- *
- * @param value optional signed Integer value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encode(Integer value, byte[] dst, int dstOffset) {
- if (value == null) {
- dst[dstOffset] = NULL_BYTE_HIGH;
- return 1;
- } else {
- dst[dstOffset] = NOT_NULL_BYTE_HIGH;
- encode(value.intValue(), dst, dstOffset + 1);
- return 5;
- }
- }
-
- /**
- * Encodes the given signed long into exactly 8 bytes.
- *
- * @param value signed long value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encode(long value, byte[] dst, int dstOffset) {
- int w = ((int)(value >> 32)) ^ 0x80000000;
- dst[dstOffset ] = (byte)(w >> 24);
- dst[dstOffset + 1] = (byte)(w >> 16);
- dst[dstOffset + 2] = (byte)(w >> 8);
- dst[dstOffset + 3] = (byte)w;
- w = (int)value;
- dst[dstOffset + 4] = (byte)(w >> 24);
- dst[dstOffset + 5] = (byte)(w >> 16);
- dst[dstOffset + 6] = (byte)(w >> 8);
- dst[dstOffset + 7] = (byte)w;
- }
-
- /**
- * Encodes the given signed Long object into exactly 1 or 9 bytes. If the
- * Long object is never expected to be null, consider encoding as a long
- * primitive.
- *
- * @param value optional signed Long value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encode(Long value, byte[] dst, int dstOffset) {
- if (value == null) {
- dst[dstOffset] = NULL_BYTE_HIGH;
- return 1;
- } else {
- dst[dstOffset] = NOT_NULL_BYTE_HIGH;
- encode(value.longValue(), dst, dstOffset + 1);
- return 9;
- }
- }
-
- /**
- * Encodes the given signed byte into exactly 1 byte.
- *
- * @param value signed byte value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encode(byte value, byte[] dst, int dstOffset) {
- dst[dstOffset] = (byte)(value ^ 0x80);
- }
-
- /**
- * Encodes the given signed Byte object into exactly 1 or 2 bytes. If the
- * Byte object is never expected to be null, consider encoding as a byte
- * primitive.
- *
- * @param value optional signed Byte value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encode(Byte value, byte[] dst, int dstOffset) {
- if (value == null) {
- dst[dstOffset] = NULL_BYTE_HIGH;
- return 1;
- } else {
- dst[dstOffset] = NOT_NULL_BYTE_HIGH;
- dst[dstOffset + 1] = (byte)(value ^ 0x80);
- return 2;
- }
- }
-
- /**
- * Encodes the given signed short into exactly 2 bytes.
- *
- * @param value signed short value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encode(short value, byte[] dst, int dstOffset) {
- value ^= 0x8000;
- dst[dstOffset ] = (byte)(value >> 8);
- dst[dstOffset + 1] = (byte)value;
- }
-
- /**
- * Encodes the given signed Short object into exactly 1 or 3 bytes. If the
- * Short object is never expected to be null, consider encoding as a short
- * primitive.
- *
- * @param value optional signed Short value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encode(Short value, byte[] dst, int dstOffset) {
- if (value == null) {
- dst[dstOffset] = NULL_BYTE_HIGH;
- return 1;
- } else {
- dst[dstOffset] = NOT_NULL_BYTE_HIGH;
- encode(value.shortValue(), dst, dstOffset + 1);
- return 3;
- }
- }
-
- /**
- * Encodes the given character into exactly 2 bytes.
- *
- * @param value character value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encode(char value, byte[] dst, int dstOffset) {
- dst[dstOffset ] = (byte)(value >> 8);
- dst[dstOffset + 1] = (byte)value;
- }
-
- /**
- * Encodes the given Character object into exactly 1 or 3 bytes. If the
- * Character object is never expected to be null, consider encoding as a
- * char primitive.
- *
- * @param value optional Character value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encode(Character value, byte[] dst, int dstOffset) {
- if (value == null) {
- dst[dstOffset] = NULL_BYTE_HIGH;
- return 1;
- } else {
- dst[dstOffset] = NOT_NULL_BYTE_HIGH;
- encode(value.charValue(), dst, dstOffset + 1);
- return 3;
- }
- }
-
- /**
- * Encodes the given boolean into exactly 1 byte.
- *
- * @param value boolean value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encode(boolean value, byte[] dst, int dstOffset) {
- dst[dstOffset] = value ? (byte)128 : (byte)127;
- }
-
- /**
- * Encodes the given Boolean object into exactly 1 byte.
- *
- * @param value optional Boolean value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encode(Boolean value, byte[] dst, int dstOffset) {
- if (value == null) {
- dst[dstOffset] = NULL_BYTE_HIGH;
- } else {
- dst[dstOffset] = value.booleanValue() ? (byte)128 : (byte)127;
- }
- }
-
- /**
- * Encodes the given float into exactly 4 bytes.
- *
- * @param value float value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encode(float value, byte[] dst, int dstOffset) {
- int bits = Float.floatToIntBits(value);
- bits ^= (bits < 0) ? 0xffffffff : 0x80000000;
- dst[dstOffset ] = (byte)(bits >> 24);
- dst[dstOffset + 1] = (byte)(bits >> 16);
- dst[dstOffset + 2] = (byte)(bits >> 8);
- dst[dstOffset + 3] = (byte)bits;
- }
-
- /**
- * Encodes the given Float object into exactly 4 bytes. A non-canonical NaN
- * value is used to represent null.
- *
- * @param value optional Float value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encode(Float value, byte[] dst, int dstOffset) {
- if (value == null) {
- encode(0x7fffffff, dst, dstOffset);
- } else {
- encode(value.floatValue(), dst, dstOffset);
- }
- }
-
- /**
- * Encodes the given double into exactly 8 bytes.
- *
- * @param value double value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encode(double value, byte[] dst, int dstOffset) {
- long bits = Double.doubleToLongBits(value);
- bits ^= (bits < 0) ? 0xffffffffffffffffL : 0x8000000000000000L;
- int w = (int)(bits >> 32);
- dst[dstOffset ] = (byte)(w >> 24);
- dst[dstOffset + 1] = (byte)(w >> 16);
- dst[dstOffset + 2] = (byte)(w >> 8);
- dst[dstOffset + 3] = (byte)w;
- w = (int)bits;
- dst[dstOffset + 4] = (byte)(w >> 24);
- dst[dstOffset + 5] = (byte)(w >> 16);
- dst[dstOffset + 6] = (byte)(w >> 8);
- dst[dstOffset + 7] = (byte)w;
- }
-
- /**
- * Encodes the given Double object into exactly 8 bytes. A non-canonical
- * NaN value is used to represent null.
- *
- * @param value optional Double value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encode(Double value, byte[] dst, int dstOffset) {
- if (value == null) {
- encode(0x7fffffffffffffffL, dst, dstOffset);
- } else {
- encode(value.doubleValue(), dst, dstOffset);
- }
- }
-
- /**
- * Encodes the given optional byte array into a variable amount of
- * bytes. If the byte array is null, exactly 1 byte is written. Otherwise,
- * the amount written can be determined by calling calculateEncodedLength.
- *
- * @param value byte array value to encode, may be null
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encode(byte[] value, byte[] dst, int dstOffset) {
- if (value == null) {
- dst[dstOffset] = NULL_BYTE_HIGH;
- return 1;
- }
- return encode(value, 0, value.length, dst, dstOffset);
- }
-
- /**
- * Encodes the given optional byte array into a variable amount of
- * bytes. If the byte array is null, exactly 1 byte is written. Otherwise,
- * the amount written can be determined by calling calculateEncodedLength.
- *
- * @param value byte array value to encode, may be null
- * @param valueOffset offset into byte array
- * @param valueLength length of data in byte array
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encode(byte[] value, int valueOffset, int valueLength,
- byte[] dst, int dstOffset) {
- if (value == null) {
- dst[dstOffset] = NULL_BYTE_HIGH;
- return 1;
- }
-
- // Write the value length first, in a variable amount of bytes.
- int amt = writeLength(valueLength, dst, dstOffset);
-
- // Now write the value.
- System.arraycopy(value, valueOffset, dst, dstOffset + amt, valueLength);
-
- return amt + valueLength;
- }
-
- /**
- * Returns the amount of bytes required to encode the given byte array.
- *
- * @param value byte array value to encode, may be null
- * @return amount of bytes needed to encode
- */
- public static int calculateEncodedLength(byte[] value) {
- return value == null ? 1 : calculateEncodedLength(value, 0, value.length);
- }
-
- /**
- * Returns the amount of bytes required to encode the given byte array.
- *
- * @param value byte array value to encode, may be null
- * @param valueOffset offset into byte array
- * @param valueLength length of data in byte array
- * @return amount of bytes needed to encode
- */
- public static int calculateEncodedLength(byte[] value, int valueOffset, int valueLength) {
- if (value == null) {
- return 1;
- } else if (valueLength < 128) {
- return 1 + valueLength;
- } else if (valueLength < 16384) {
- return 2 + valueLength;
- } else if (valueLength < 2097152) {
- return 3 + valueLength;
- } else if (valueLength < 268435456) {
- return 4 + valueLength;
- } else {
- return 5 + valueLength;
- }
- }
-
- /**
- * Encodes the given optional String into a variable amount of bytes. The
- * amount written can be determined by calling
- * calculateEncodedStringLength.
- * <p>
- * Strings are encoded in a fashion similar to UTF-8, in that ASCII
- * characters are written in one byte. This encoding is more efficient than
- * UTF-8, but it isn't compatible with UTF-8.
- *
- * @param value String value to encode, may be null
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encode(String value, byte[] dst, int dstOffset) {
- if (value == null) {
- dst[dstOffset] = NULL_BYTE_HIGH;
- return 1;
- }
- final int originalOffset = dstOffset;
-
- int valueLength = value.length();
-
- // Write the value length first, in a variable amount of bytes.
- dstOffset += writeLength(valueLength, dst, dstOffset);
-
- for (int i = 0; i < valueLength; i++) {
- int c = value.charAt(i);
- if (c <= 0x7f) {
- dst[dstOffset++] = (byte)c;
- } else if (c <= 0x3fff) {
- dst[dstOffset++] = (byte)(0x80 | (c >> 8));
- dst[dstOffset++] = (byte)(c & 0xff);
- } else {
- if (c >= 0xd800 && c <= 0xdbff) {
- // Found a high surrogate. Verify that surrogate pair is
- // well-formed. Low surrogate must follow high surrogate.
- if (i + 1 < valueLength) {
- int c2 = value.charAt(i + 1);
- if (c2 >= 0xdc00 && c2 <= 0xdfff) {
- c = 0x10000 + (((c & 0x3ff) << 10) | (c2 & 0x3ff));
- i++;
- }
- }
- }
- dst[dstOffset++] = (byte)(0xc0 | (c >> 16));
- dst[dstOffset++] = (byte)((c >> 8) & 0xff);
- dst[dstOffset++] = (byte)(c & 0xff);
- }
- }
-
- return dstOffset - originalOffset;
- }
-
- /**
- * Returns the amount of bytes required to encode the given String.
- *
- * @param value String to encode, may be null
- */
- public static int calculateEncodedStringLength(String value) {
- if (value == null) {
- return 1;
- }
-
- int valueLength = value.length();
- int encodedLen;
-
- if (valueLength < 128) {
- encodedLen = 1;
- } else if (valueLength < 16384) {
- encodedLen = 2;
- } else if (valueLength < 2097152) {
- encodedLen = 3;
- } else if (valueLength < 268435456) {
- encodedLen = 4;
- } else {
- encodedLen = 5;
- }
-
- for (int i = 0; i < valueLength; i++) {
- int c = value.charAt(i);
- if (c <= 0x7f) {
- encodedLen++;
- } else if (c <= 0x3fff) {
- encodedLen += 2;
- } else {
- if (c >= 0xd800 && c <= 0xdbff) {
- // Found a high surrogate. Verify that surrogate pair is
- // well-formed. Low surrogate must follow high surrogate.
- if (i + 1 < valueLength) {
- int c2 = value.charAt(i + 1);
- if (c2 >= 0xdc00 && c2 <= 0xdfff) {
- i++;
- }
- }
- }
- encodedLen += 3;
- }
- }
-
- return encodedLen;
- }
-
- private static int writeLength(int valueLength, byte[] dst, int dstOffset) {
- if (valueLength < 128) {
- dst[dstOffset] = (byte)valueLength;
- return 1;
- } else if (valueLength < 16384) {
- dst[dstOffset++] = (byte)((valueLength >> 8) | 0x80);
- dst[dstOffset] = (byte)valueLength;
- return 2;
- } else if (valueLength < 2097152) {
- dst[dstOffset++] = (byte)((valueLength >> 16) | 0xc0);
- dst[dstOffset++] = (byte)(valueLength >> 8);
- dst[dstOffset] = (byte)valueLength;
- return 3;
- } else if (valueLength < 268435456) {
- dst[dstOffset++] = (byte)((valueLength >> 24) | 0xe0);
- dst[dstOffset++] = (byte)(valueLength >> 16);
- dst[dstOffset++] = (byte)(valueLength >> 8);
- dst[dstOffset] = (byte)valueLength;
- return 4;
- } else {
- dst[dstOffset++] = (byte)0xf0;
- dst[dstOffset++] = (byte)(valueLength >> 24);
- dst[dstOffset++] = (byte)(valueLength >> 16);
- dst[dstOffset++] = (byte)(valueLength >> 8);
- dst[dstOffset] = (byte)valueLength;
- return 5;
- }
- }
-
- /**
- * Encodes the given byte array for use when there is only a single
- * property, whose type is a byte array. The original byte array is
- * returned if the padding lengths are zero.
- *
- * @param prefixPadding amount of extra bytes to allocate at start of encoded byte array
- * @param suffixPadding amount of extra bytes to allocate at end of encoded byte array
- */
- public static byte[] encodeSingle(byte[] value, int prefixPadding, int suffixPadding) {
- if (prefixPadding <= 0 && suffixPadding <= 0) {
- return value;
- }
- int length = value.length;
- byte[] dst = new byte[prefixPadding + length + suffixPadding];
- System.arraycopy(value, 0, dst, prefixPadding, length);
- return dst;
- }
-
- /**
- * Encodes the given byte array for use when there is only a single
- * nullable property, whose type is a byte array.
- */
- public static byte[] encodeSingleNullable(byte[] value) {
- return encodeSingleNullable(value, 0, 0);
- }
-
- /**
- * Encodes the given byte array for use when there is only a single
- * nullable property, whose type is a byte array.
- *
- * @param prefixPadding amount of extra bytes to allocate at start of encoded byte array
- * @param suffixPadding amount of extra bytes to allocate at end of encoded byte array
- */
- public static byte[] encodeSingleNullable(byte[] value, int prefixPadding, int suffixPadding) {
- if (prefixPadding <= 0 && suffixPadding <= 0) {
- if (value == null) {
- return NULL_BYTE_ARRAY_HIGH;
- }
-
- int length = value.length;
- if (length == 0) {
- return NOT_NULL_BYTE_ARRAY_HIGH;
- }
-
- byte[] dst = new byte[1 + length];
- dst[0] = NOT_NULL_BYTE_HIGH;
- System.arraycopy(value, 0, dst, 1, length);
- return dst;
- }
-
- if (value == null) {
- byte[] dst = new byte[prefixPadding + 1 + suffixPadding];
- dst[prefixPadding] = NULL_BYTE_HIGH;
- return dst;
- }
-
- int length = value.length;
- byte[] dst = new byte[prefixPadding + 1 + length + suffixPadding];
- dst[prefixPadding] = NOT_NULL_BYTE_HIGH;
- System.arraycopy(value, 0, dst, prefixPadding + 1, length);
- return dst;
- }
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/GenericEncodingStrategy.java b/src/main/java/com/amazon/carbonado/spi/raw/GenericEncodingStrategy.java deleted file mode 100644 index cd408e9..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/GenericEncodingStrategy.java +++ /dev/null @@ -1,1963 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.Map;
-
-import org.cojen.classfile.CodeAssembler;
-import org.cojen.classfile.Label;
-import org.cojen.classfile.LocalVariable;
-import org.cojen.classfile.Opcode;
-import org.cojen.classfile.TypeDesc;
-import org.cojen.util.BeanIntrospector;
-import org.cojen.util.BeanProperty;
-
-import com.amazon.carbonado.CorruptEncodingException;
-import com.amazon.carbonado.Storable;
-import com.amazon.carbonado.SupportException;
-
-import com.amazon.carbonado.lob.Blob;
-import com.amazon.carbonado.lob.Clob;
-import com.amazon.carbonado.lob.Lob;
-
-import com.amazon.carbonado.spi.StorableGenerator;
-import com.amazon.carbonado.spi.TriggerSupport;
-
-import com.amazon.carbonado.info.ChainedProperty;
-import com.amazon.carbonado.info.Direction;
-import com.amazon.carbonado.info.OrderedProperty;
-import com.amazon.carbonado.info.StorableIndex;
-import com.amazon.carbonado.info.StorableIntrospector;
-import com.amazon.carbonado.info.StorableProperty;
-import com.amazon.carbonado.info.StorablePropertyAdapter;
-
-/**
- * Generates bytecode instructions for encoding/decoding Storable properties
- * to/from raw bytes.
- *
- * <p>Note: subclasses must override and specialize the hashCode and equals
- * methods. Failure to do so interferes with {@link StorableCodecFactory}'s
- * generated code cache.
- *
- * @author Brian S O'Neill
- */
-public class GenericEncodingStrategy<S extends Storable> {
- private final Class<S> mType;
- private final StorableIndex<S> mPkIndex;
-
- private final int mKeyPrefixPadding;
- private final int mKeySuffixPadding;
- private final int mDataPrefixPadding;
- private final int mDataSuffixPadding;
-
- /**
- * @param type type of Storable to generate code for
- * @param pkIndex specifies sequence and ordering of key properties (optional)
- */
- public GenericEncodingStrategy(Class<S> type, StorableIndex<S> pkIndex) {
- this(type, pkIndex, 0, 0, 0, 0);
- }
-
- /**
- * @param type type of Storable to generate code for
- * @param pkIndex specifies sequence and ordering of key properties (optional)
- * @param keyPrefixPadding amount of padding bytes at start of keys
- * @param keySuffixPadding amount of padding bytes at end of keys
- * @param dataPrefixPadding amount of padding bytes at start of data values
- * @param dataSuffixPadding amount of padding bytes at end of data values
- */
- @SuppressWarnings("unchecked")
- public GenericEncodingStrategy(Class<S> type, StorableIndex<S> pkIndex,
- int keyPrefixPadding, int keySuffixPadding,
- int dataPrefixPadding, int dataSuffixPadding) {
- mType = type;
-
- if (keyPrefixPadding < 0 || keySuffixPadding < 0 ||
- dataPrefixPadding < 0 || dataSuffixPadding < 0) {
- throw new IllegalArgumentException();
- }
- mKeyPrefixPadding = keyPrefixPadding;
- mKeySuffixPadding = keySuffixPadding;
- mDataPrefixPadding = dataPrefixPadding;
- mDataSuffixPadding = dataSuffixPadding;
-
- if (pkIndex == null) {
- Map<String, ? extends StorableProperty<S>> map =
- StorableIntrospector.examine(mType).getPrimaryKeyProperties();
-
- StorableProperty<S>[] properties = new StorableProperty[map.size()];
- map.values().toArray(properties);
-
- Direction[] directions = new Direction[map.size()];
- Arrays.fill(directions, Direction.UNSPECIFIED);
-
- pkIndex = new StorableIndex<S>(properties, directions, true);
- }
-
- mPkIndex = pkIndex;
- }
-
- /**
- * Generates bytecode instructions to encode properties. The encoding is
- * suitable for "key" encoding, which means it is correctly comparable.
- *
- * <p>Note: if a partialStartVar is provided and this strategy has a key
- * prefix, the prefix is allocated only if the runtime value of
- * partialStartVar is zero. Likewise, if a partialEndVar is provided and
- * this strategy has a key suffix, the suffix is allocated only of the
- * runtime value of partialEndVar is one less than the property count.
- *
- * @param assembler code assembler to receive bytecode instructions
- * @param properties specific properties to encode, defaults to all key
- * properties if null
- * @param instanceVar local variable referencing Storable instance,
- * defaults to "this" if null. If variable type is an Object array, then
- * property values are read from the runtime value of this array instead
- * of a Storable instance.
- * @param adapterInstanceClass class containing static references to
- * adapter instances - defaults to instanceVar
- * @param useReadMethods when true, access properties by public read
- * methods instead of protected fields - should be used if class being
- * generated doesn't have access to these fields
- * @param partialStartVar optional variable for supporting partial key
- * generation. It must be an int, whose runtime value must be less than the
- * properties array length. It marks the range start of the partial
- * property range.
- * @param partialEndVar optional variable for supporting partial key
- * generation. It must be an int, whose runtime value must be less than or
- * equal to the properties array length. It marks the range end (exclusive)
- * of the partial property range.
- *
- * @return local variable referencing a byte array with encoded key
- *
- * @throws SupportException if any property type is not supported
- * @throws IllegalArgumentException if assembler is null, or if instanceVar
- * is not the correct instance type, or if partial variable types are not
- * ints
- */
- public LocalVariable buildKeyEncoding(CodeAssembler assembler,
- OrderedProperty<S>[] properties,
- LocalVariable instanceVar,
- Class<?> adapterInstanceClass,
- boolean useReadMethods,
- LocalVariable partialStartVar,
- LocalVariable partialEndVar)
- throws SupportException
- {
- properties = ensureKeyProperties(properties);
- return buildEncoding(true, assembler,
- extractProperties(properties), extractDirections(properties),
- instanceVar, adapterInstanceClass,
- useReadMethods,
- -1, // no generation support
- partialStartVar, partialEndVar);
- }
-
- /**
- * Generates bytecode instructions to decode properties. A
- * CorruptEncodingException may be thrown from generated code.
- *
- * @param assembler code assembler to receive bytecode instructions
- * @param properties specific properties to decode, defaults to all key
- * properties if null
- * @param instanceVar local variable referencing Storable instance,
- * defaults to "this" if null. If variable type is an Object array, then
- * property values are placed into the runtime value of this array instead
- * of a Storable instance.
- * @param adapterInstanceClass class containing static references to
- * adapter instances - defaults to instanceVar
- * @param useWriteMethods when true, set properties by public write
- * methods instead of protected fields - should be used if class being
- * generated doesn't have access to these fields
- * @param encodedVar required variable, which must be a byte array. At
- * runtime, it references an encoded key.
- *
- * @throws SupportException if any property type is not supported
- * @throws IllegalArgumentException if assembler is null, or if instanceVar
- * is not the correct instance type, or if encodedVar is not a byte array
- */
- public void buildKeyDecoding(CodeAssembler assembler,
- OrderedProperty<S>[] properties,
- LocalVariable instanceVar,
- Class<?> adapterInstanceClass,
- boolean useWriteMethods,
- LocalVariable encodedVar)
- throws SupportException
- {
- properties = ensureKeyProperties(properties);
- buildDecoding(true, assembler,
- extractProperties(properties), extractDirections(properties),
- instanceVar, adapterInstanceClass, useWriteMethods,
- -1, null, // no generation support
- encodedVar);
- }
-
- /**
- * Generates bytecode instructions to encode properties. The encoding is
- * suitable for "data" encoding, which means it is not correctly
- * comparable, but it is more efficient than key encoding. Partial encoding
- * is not supported.
- *
- * @param assembler code assembler to receive bytecode instructions
- * @param properties specific properties to encode, defaults to all non-key
- * properties if null
- * @param instanceVar local variable referencing Storable instance,
- * defaults to "this" if null. If variable type is an Object array, then
- * property values are read from the runtime value of this array instead
- * of a Storable instance.
- * @param adapterInstanceClass class containing static references to
- * adapter instances - defaults to instanceVar
- * @param useReadMethods when true, access properties by public read
- * methods instead of protected fields
- * @param generation when non-negative, write a storable layout generation
- * value in one or four bytes. Generation 0..127 is encoded in one byte, and
- * 128..max is encoded in four bytes, with the most significant bit set.
- *
- * @return local variable referencing a byte array with encoded data
- *
- * @throws SupportException if any property type is not supported
- * @throws IllegalArgumentException if assembler is null, or if instanceVar
- * is not the correct instance type
- */
- public LocalVariable buildDataEncoding(CodeAssembler assembler,
- StorableProperty<S>[] properties,
- LocalVariable instanceVar,
- Class<?> adapterInstanceClass,
- boolean useReadMethods,
- int generation)
- throws SupportException
- {
- properties = ensureDataProperties(properties);
- return buildEncoding(false, assembler,
- properties, null,
- instanceVar, adapterInstanceClass,
- useReadMethods, generation, null, null);
- }
-
- /**
- * Generates bytecode instructions to decode properties. A
- * CorruptEncodingException may be thrown from generated code.
- *
- * @param assembler code assembler to receive bytecode instructions
- * @param properties specific properties to decode, defaults to all non-key
- * properties if null
- * @param instanceVar local variable referencing Storable instance,
- * defaults to "this" if null. If variable type is an Object array, then
- * property values are placed into the runtime value of this array instead
- * of a Storable instance.
- * @param adapterInstanceClass class containing static references to
- * adapter instances - defaults to instanceVar
- * @param useWriteMethods when true, set properties by public write
- * methods instead of protected fields - should be used if class being
- * generated doesn't have access to these fields
- * @param generation when non-negative, decoder expects a storable layout
- * generation value to match this value. Otherwise, it throws a
- * CorruptEncodingException.
- * @param altGenerationHandler if non-null and a generation is provided,
- * this label defines an alternate generation handler. It is executed
- * instead of throwing a CorruptEncodingException if the generation doesn't
- * match. The actual generation is available on the top of the stack for
- * the handler to consume.
- * @param encodedVar required variable, which must be a byte array. At
- * runtime, it references encoded data.
- *
- * @throws SupportException if any property type is not supported
- * @throws IllegalArgumentException if assembler is null, or if instanceVar
- * is not the correct instance type, or if encodedVar is not a byte array
- */
- public void buildDataDecoding(CodeAssembler assembler,
- StorableProperty<S>[] properties,
- LocalVariable instanceVar,
- Class<?> adapterInstanceClass,
- boolean useWriteMethods,
- int generation,
- Label altGenerationHandler,
- LocalVariable encodedVar)
- throws SupportException
- {
- properties = ensureDataProperties(properties);
- buildDecoding(false, assembler, properties, null,
- instanceVar, adapterInstanceClass, useWriteMethods,
- generation, altGenerationHandler, encodedVar);
- }
-
- /**
- * Returns the type of Storable that code is generated for.
- */
- public final Class<S> getType() {
- return mType;
- }
-
- /**
- * Returns true if the type of the given property type is supported. The
- * types currently supported are primitives, primitive wrapper objects,
- * Strings, and byte arrays.
- */
- public boolean isSupported(Class<?> propertyType) {
- return isSupported(TypeDesc.forClass(propertyType));
- }
-
- /**
- * Returns true if the type of the given property type is supported. The
- * types currently supported are primitives, primitive wrapper objects,
- * Strings, byte arrays and Lobs.
- */
- public boolean isSupported(TypeDesc propertyType) {
- if (propertyType.toPrimitiveType() != null) {
- return true;
- }
- return propertyType == TypeDesc.STRING ||
- propertyType == TypeDesc.forClass(byte[].class) ||
- propertyType.toClass() != null && Lob.class.isAssignableFrom(propertyType.toClass());
- }
-
- public int getKeyPrefixPadding() {
- return mKeyPrefixPadding;
- }
-
- public int getKeySuffixPadding() {
- return mKeySuffixPadding;
- }
-
- public int getDataPrefixPadding() {
- return mDataPrefixPadding;
- }
-
- public int getDataSuffixPadding() {
- return mDataSuffixPadding;
- }
-
- /**
- * Returns amount of prefix key bytes that encoding strategy instance
- * produces which are always the same. Default implementation returns 0.
- */
- public int getConstantKeyPrefixLength() {
- return 0;
- }
-
- @Override
- public int hashCode() {
- return mType.hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj instanceof GenericEncodingStrategy) {
- GenericEncodingStrategy other = (GenericEncodingStrategy) obj;
- return mType == other.mType
- && mKeyPrefixPadding == other.mKeyPrefixPadding
- && mKeySuffixPadding == other.mKeySuffixPadding
- && mDataPrefixPadding == other.mDataPrefixPadding
- && mDataSuffixPadding == other.mDataSuffixPadding;
- }
- return false;
- }
-
- /**
- * Returns all key properties in the form of an index.
- */
- protected StorableIndex<S> getPrimaryKeyIndex() {
- return mPkIndex;
- }
-
- /**
- * Returns all key properties as ordered properties, possibly with
- * unspecified directions.
- */
- protected OrderedProperty<S>[] gatherAllKeyProperties() {
- return mPkIndex.getOrderedProperties();
- }
-
- /**
- * Returns all data properties for storable.
- */
- @SuppressWarnings("unchecked")
- protected StorableProperty<S>[] gatherAllDataProperties() {
- Map<String, ? extends StorableProperty<S>> map =
- StorableIntrospector.examine(mType).getDataProperties();
-
- StorableProperty<S>[] properties = new StorableProperty[map.size()];
-
- int ordinal = 0;
- for (StorableProperty<S> property : map.values()) {
- properties[ordinal++] = property;
- }
-
- return properties;
- }
-
- protected StorablePropertyInfo checkSupport(StorableProperty<S> property)
- throws SupportException
- {
- if (isSupported(property.getType())) {
- return new StorablePropertyInfo(property);
- }
-
- // Look for an adapter that will allow this property to be supported.
- if (property.getAdapter() != null) {
- StorablePropertyAdapter adapter = property.getAdapter();
- for (Class<?> storageType : adapter.getStorageTypePreferences()) {
- if (!isSupported(storageType)) {
- continue;
- }
-
- if (property.isNullable() && storageType.isPrimitive()) {
- continue;
- }
-
- Method fromStorage, toStorage;
- fromStorage = adapter.findAdaptMethod(storageType, property.getType());
- if (fromStorage == null) {
- continue;
- }
- toStorage = adapter.findAdaptMethod(property.getType(), storageType);
- if (toStorage != null) {
- return new StorablePropertyInfo(property, storageType, fromStorage, toStorage);
- }
- }
- }
-
- throw notSupported(property);
- }
-
- @SuppressWarnings("unchecked")
- protected StorablePropertyInfo[] checkSupport(StorableProperty<S>[] properties)
- throws SupportException
- {
- int length = properties.length;
- StorablePropertyInfo[] infos = new StorablePropertyInfo[length];
- for (int i=0; i<length; i++) {
- infos[i] = checkSupport(properties[i]);
- }
- return infos;
- }
-
- private SupportException notSupported(StorableProperty<S> property) {
- return notSupported(property.getName(), property.getType().getName());
- }
-
- private SupportException notSupported(String propertyName, String typeName) {
- return new SupportException
- ("Type \"" + typeName +
- "\" not supported for property \"" + propertyName + '"');
- }
-
- private OrderedProperty<S>[] ensureKeyProperties(OrderedProperty<S>[] properties) {
- if (properties == null) {
- properties = gatherAllKeyProperties();
- } else {
- for (Object prop : properties) {
- if (prop == null) {
- throw new IllegalArgumentException();
- }
- }
- }
- return properties;
- }
-
- @SuppressWarnings("unchecked")
- private StorableProperty<S>[] extractProperties(OrderedProperty<S>[] ordered) {
- StorableProperty<S>[] properties = new StorableProperty[ordered.length];
- for (int i=0; i<ordered.length; i++) {
- ChainedProperty chained = ordered[i].getChainedProperty();
- if (chained.getChainCount() > 0) {
- throw new IllegalArgumentException();
- }
- properties[i] = chained.getPrimeProperty();
- }
- return properties;
- }
-
- private Direction[] extractDirections(OrderedProperty<S>[] ordered) {
- Direction[] directions = new Direction[ordered.length];
- for (int i=0; i<ordered.length; i++) {
- directions[i] = ordered[i].getDirection();
- }
- return directions;
- }
-
- private StorableProperty<S>[] ensureDataProperties(StorableProperty<S>[] properties) {
- if (properties == null) {
- properties = gatherAllDataProperties();
- } else {
- for (Object prop : properties) {
- if (prop == null) {
- throw new IllegalArgumentException();
- }
- }
- }
- return properties;
- }
-
- /////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////
-
- private LocalVariable buildEncoding(boolean forKey,
- CodeAssembler a,
- StorableProperty<S>[] properties,
- Direction[] directions,
- LocalVariable instanceVar,
- Class<?> adapterInstanceClass,
- boolean useReadMethods,
- int generation,
- LocalVariable partialStartVar,
- LocalVariable partialEndVar)
- throws SupportException
- {
- if (a == null) {
- throw new IllegalArgumentException();
- }
- if (partialStartVar != null && partialStartVar.getType() != TypeDesc.INT) {
- throw new IllegalArgumentException();
- }
- if (partialEndVar != null && partialEndVar.getType() != TypeDesc.INT) {
- throw new IllegalArgumentException();
- }
-
- // Encoding order is:
- //
- // 1. Prefix
- // 2. Generation prefix
- // 3. Properties
- // 4. Suffix
-
- final int prefix = forKey ? mKeyPrefixPadding : mDataPrefixPadding;
-
- final int generationPrefix;
- if (generation < 0) {
- generationPrefix = 0;
- } else if (generation < 128) {
- generationPrefix = 1;
- } else {
- generationPrefix = 4;
- }
-
- final int suffix = forKey ? mKeySuffixPadding : mDataSuffixPadding;
-
- final TypeDesc byteArrayType = TypeDesc.forClass(byte[].class);
- final LocalVariable encodedVar = a.createLocalVariable(null, byteArrayType);
-
- StorablePropertyInfo[] infos = checkSupport(properties);
-
- if (properties.length == 1) {
- // Ignore partial key encoding variables, since there can't be a
- // partial of one property.
- partialStartVar = null;
- partialEndVar = null;
-
- StorableProperty<S> property = properties[0];
- StorablePropertyInfo info = infos[0];
-
- if (info.getStorageType().toClass() == byte[].class) {
- // Since there is only one property, and it is just a byte
- // array, optimize by not doing any fancy encoding. If the
- // property is optional, then a byte prefix is needed to
- // identify a null reference.
-
- loadPropertyValue(a, info, 0, useReadMethods,
- instanceVar, adapterInstanceClass, partialStartVar);
-
- boolean descending =
- forKey && directions != null && directions[0] == Direction.DESCENDING;
-
- TypeDesc[] params;
- if (prefix > 0 || generationPrefix > 0 || suffix > 0) {
- a.loadConstant(prefix + generationPrefix);
- a.loadConstant(suffix);
- params = new TypeDesc[] {byteArrayType, TypeDesc.INT, TypeDesc.INT};
- } else {
- params = new TypeDesc[] {byteArrayType};
- }
-
- if (property.isNullable()) {
- if (descending) {
- a.invokeStatic(KeyEncoder.class.getName(), "encodeSingleNullableDesc",
- byteArrayType, params);
- } else {
- a.invokeStatic(DataEncoder.class.getName(), "encodeSingleNullable",
- byteArrayType, params);
- }
- } else if (descending) {
- a.invokeStatic(KeyEncoder.class.getName(), "encodeSingleDesc",
- byteArrayType, params);
- } else if (prefix > 0 || generationPrefix > 0 || suffix > 0) {
- a.invokeStatic(DataEncoder.class.getName(), "encodeSingle",
- byteArrayType, params);
- } else {
- // Just return raw property value - no need to cache it either.
- }
-
- a.storeLocal(encodedVar);
-
- encodeGeneration(a, encodedVar, prefix, generation);
-
- return encodedVar;
- }
- }
-
- boolean doPartial = forKey && (partialStartVar != null || partialEndVar != null);
-
- // Calculate exactly how many bytes are needed to encode. The length
- // is composed of a static and a variable amount. The variable amount
- // is determined at runtime.
-
- int staticLength = 0;
- if (!forKey || partialStartVar == null) {
- // Only include prefix as static if no runtime check is needed
- // against runtime partial start value.
- staticLength += prefix + generationPrefix;
- }
- if (!forKey || partialEndVar == null) {
- // Only include suffix as static if no runtime check is needed
- // against runtime partial end value.
- staticLength += suffix;
- }
-
- boolean hasVariableLength;
- if (doPartial) {
- hasVariableLength = true;
- } else {
- hasVariableLength = false;
- for (GenericPropertyInfo info : infos) {
- int len = staticEncodingLength(info);
- if (len >= 0) {
- staticLength += len;
- } else {
- staticLength += ~len;
- hasVariableLength = true;
- }
- }
- }
-
- // Generate code that loops over all the properties that have a
- // variable length. Load each property and perform the necessary
- // tests to determine the exact encoding length.
-
- boolean hasStackVar = false;
- if (hasVariableLength) {
- Label[] entryPoints = null;
-
- if (partialStartVar != null) {
- // Will jump into an arbitrary location, so always have a stack
- // variable available.
- a.loadConstant(0);
- hasStackVar = true;
-
- entryPoints = jumpToPartialEntryPoints(a, partialStartVar, properties.length);
- }
-
- Label exitPoint = a.createLabel();
-
- for (int i=0; i<properties.length; i++) {
- StorableProperty<S> property = properties[i];
- StorablePropertyInfo info = infos[i];
-
- if (doPartial) {
- if (entryPoints != null) {
- entryPoints[i].setLocation();
- }
- if (partialEndVar != null) {
- // Add code to jump out of partial.
- a.loadConstant(i);
- a.loadLocal(partialEndVar);
- a.ifComparisonBranch(exitPoint, ">=");
- }
- } else if (staticEncodingLength(info) >= 0) {
- continue;
- }
-
- TypeDesc propType = info.getStorageType();
-
- if (propType.isPrimitive()) {
- // This should only ever get executed if implementing
- // partial support. Otherwise, the static encoding length
- // would have been already calculated.
- a.loadConstant(staticEncodingLength(info));
- if (hasStackVar) {
- a.math(Opcode.IADD);
- } else {
- hasStackVar = true;
- }
- } else if (propType.toPrimitiveType() != null) {
- int amt = 0;
- switch (propType.toPrimitiveType().getTypeCode()) {
- case TypeDesc.BYTE_CODE:
- case TypeDesc.BOOLEAN_CODE:
- amt = 1;
- break;
- case TypeDesc.SHORT_CODE:
- case TypeDesc.CHAR_CODE:
- amt = 2;
- break;
- case TypeDesc.INT_CODE:
- case TypeDesc.FLOAT_CODE:
- amt = 4;
- break;
- case TypeDesc.LONG_CODE:
- case TypeDesc.DOUBLE_CODE:
- amt = 8;
- break;
- }
-
- int extra = 0;
- if (doPartial) {
- // If value is null, then there may be a one byte size
- // adjust for the null value. Otherwise it is the extra
- // amount plus the size to encode the raw primitive
- // value. If doPartial is false, then this extra amount
- // was already accounted for in the static encoding
- // length.
-
- switch (propType.toPrimitiveType().getTypeCode()) {
- case TypeDesc.BYTE_CODE:
- case TypeDesc.SHORT_CODE:
- case TypeDesc.CHAR_CODE:
- case TypeDesc.INT_CODE:
- case TypeDesc.LONG_CODE:
- extra = 1;
- }
- }
-
- if (!property.isNullable() || (doPartial && extra == 0)) {
- a.loadConstant(amt);
- if (hasStackVar) {
- a.math(Opcode.IADD);
- }
- hasStackVar = true;
- } else {
- // Load property to test for null.
- loadPropertyValue(a, info, i, useReadMethods,
- instanceVar, adapterInstanceClass, partialStartVar);
-
- Label isNull = a.createLabel();
- a.ifNullBranch(isNull, true);
-
- a.loadConstant(amt);
-
- if (hasStackVar) {
- a.math(Opcode.IADD);
- isNull.setLocation();
- if (extra > 0) {
- a.loadConstant(extra);
- a.math(Opcode.IADD);
- }
- } else {
- hasStackVar = true;
- // Make sure that there is a zero (or extra) value on
- // the stack if the isNull branch is taken.
- Label notNull = a.createLabel();
- a.branch(notNull);
- isNull.setLocation();
- a.loadConstant(extra);
- notNull.setLocation();
- }
- }
- } else if (propType == TypeDesc.STRING) {
- // Load property to test for null.
- loadPropertyValue(a, info, i, useReadMethods,
- instanceVar, adapterInstanceClass, partialStartVar);
-
- String className =
- (forKey ? KeyEncoder.class : DataEncoder.class).getName();
- a.invokeStatic(className, "calculateEncodedStringLength",
- TypeDesc.INT, new TypeDesc[] {TypeDesc.STRING});
- if (hasStackVar) {
- a.math(Opcode.IADD);
- } else {
- hasStackVar = true;
- }
- } else if (propType.toClass() == byte[].class) {
- // Load property to test for null.
- loadPropertyValue(a, info, i, useReadMethods,
- instanceVar, adapterInstanceClass, partialStartVar);
-
- String className =
- (forKey ? KeyEncoder.class : DataEncoder.class).getName();
- a.invokeStatic(className, "calculateEncodedLength",
- TypeDesc.INT, new TypeDesc[] {byteArrayType});
- if (hasStackVar) {
- a.math(Opcode.IADD);
- } else {
- hasStackVar = true;
- }
- } else if (info.isLob()) {
- // Lob locator is a long, or 8 bytes.
- a.loadConstant(8);
- if (hasStackVar) {
- a.math(Opcode.IADD);
- } else {
- hasStackVar = true;
- }
- } else {
- throw notSupported(property);
- }
- }
-
- exitPoint.setLocation();
-
- if (forKey && partialStartVar != null && (prefix > 0 || generationPrefix > 0)) {
- // Prefix must be allocated only if runtime value of
- // partialStartVar is zero.
- a.loadLocal(partialStartVar);
- Label noPrefix = a.createLabel();
- a.ifZeroComparisonBranch(noPrefix, "!=");
- a.loadConstant(prefix + generationPrefix);
- if (hasStackVar) {
- a.math(Opcode.IADD);
- } else {
- hasStackVar = true;
- }
- noPrefix.setLocation();
- }
-
- if (forKey && partialEndVar != null && suffix > 0) {
- // Suffix must be allocated only if runtime value of
- // partialEndVar is equal to property count.
- a.loadLocal(partialEndVar);
- Label noSuffix = a.createLabel();
- a.loadConstant(properties.length);
- a.ifComparisonBranch(noSuffix, "!=");
- a.loadConstant(suffix);
- if (hasStackVar) {
- a.math(Opcode.IADD);
- } else {
- hasStackVar = true;
- }
- noSuffix.setLocation();
- }
- }
-
- // Allocate a byte array of the exact size.
- if (hasStackVar) {
- if (staticLength > 0) {
- a.loadConstant(staticLength);
- a.math(Opcode.IADD);
- }
- } else {
- a.loadConstant(staticLength);
- }
- a.newObject(byteArrayType);
- a.storeLocal(encodedVar);
-
- // Now encode into the byte array.
-
- int constantOffset = 0;
- LocalVariable offset = null;
-
- if (!forKey || partialStartVar == null) {
- // Only include prefix as constant offset if no runtime check is
- // needed against runtime partial start value.
- constantOffset += prefix + generationPrefix;
- encodeGeneration(a, encodedVar, prefix, generation);
- }
-
- Label[] entryPoints = null;
-
- if (forKey && partialStartVar != null) {
- // Will jump into an arbitrary location, so put an initial value
- // into offset variable.
-
- offset = a.createLocalVariable(null, TypeDesc.INT);
- a.loadConstant(0);
- if (prefix > 0) {
- // Prefix is allocated only if partial start is zero. Check if
- // offset should be adjusted to skip over it.
- a.loadLocal(partialStartVar);
- Label noPrefix = a.createLabel();
- a.ifZeroComparisonBranch(noPrefix, "!=");
- a.loadConstant(prefix + generationPrefix);
- a.math(Opcode.IADD);
- encodeGeneration(a, encodedVar, prefix, generation);
- noPrefix.setLocation();
- }
- a.storeLocal(offset);
-
- entryPoints = jumpToPartialEntryPoints(a, partialStartVar, properties.length);
- }
-
- Label exitPoint = a.createLabel();
-
- for (int i=0; i<properties.length; i++) {
- StorableProperty<S> property = properties[i];
- StorablePropertyInfo info = infos[i];
-
- if (doPartial) {
- if (entryPoints != null) {
- entryPoints[i].setLocation();
- }
- if (partialEndVar != null) {
- // Add code to jump out of partial.
- a.loadConstant(i);
- a.loadLocal(partialEndVar);
- a.ifComparisonBranch(exitPoint, ">=");
- }
- }
-
- if (info.isLob()) {
- // Need RawSupport instance for getting locator from Lob.
- pushRawSupport(a, instanceVar);
- }
-
- boolean fromInstance = loadPropertyValue
- (a, info, i, useReadMethods, instanceVar, adapterInstanceClass, partialStartVar);
-
- TypeDesc propType = info.getStorageType();
- if (!property.isNullable() && propType.toPrimitiveType() != null) {
- // Since property type is a required primitive wrapper, convert
- // to a primitive rather than encoding using the form that
- // distinguishes null.
-
- // Property value that was passed in may be null, which is not
- // allowed.
- if (!fromInstance && !propType.isPrimitive()) {
- a.dup();
- Label notNull = a.createLabel();
- a.ifNullBranch(notNull, false);
-
- TypeDesc errorType = TypeDesc.forClass(IllegalArgumentException.class);
- a.newObject(errorType);
- a.dup();
- a.loadConstant("Value for property \"" + property.getName() +
- "\" cannot be null");
- a.invokeConstructor(errorType, new TypeDesc[] {TypeDesc.STRING});
- a.throwObject();
-
- notNull.setLocation();
- }
-
- a.convert(propType, propType.toPrimitiveType());
- propType = propType.toPrimitiveType();
- }
-
- if (info.isLob()) {
- // Extract locator from RawSupport.
- getLobLocator(a, info);
-
- // Locator is a long, so switch the type to be encoded properly.
- propType = TypeDesc.LONG;
- }
-
- // Fill out remaining parameters before calling specific method
- // to encode property value.
- a.loadLocal(encodedVar);
- if (offset == null) {
- a.loadConstant(constantOffset);
- } else {
- a.loadLocal(offset);
- }
-
- boolean descending =
- forKey && directions != null && directions[i] == Direction.DESCENDING;
-
- int amt = encodeProperty(a, propType, forKey, descending);
-
- if (amt > 0) {
- if (i + 1 < properties.length) {
- // Only adjust offset if there are more properties.
-
- if (offset == null) {
- constantOffset += amt;
- } else {
- a.loadConstant(amt);
- a.loadLocal(offset);
- a.math(Opcode.IADD);
- a.storeLocal(offset);
- }
- }
- } else {
- if (i + 1 >= properties.length) {
- // Don't need to keep track of offset anymore.
- a.pop();
- } else {
- // Only adjust offset if there are more properties.
- if (offset == null) {
- if (constantOffset > 0) {
- a.loadConstant(constantOffset);
- a.math(Opcode.IADD);
- }
- offset = a.createLocalVariable(null, TypeDesc.INT);
- } else {
- a.loadLocal(offset);
- a.math(Opcode.IADD);
- }
- a.storeLocal(offset);
- }
- }
- }
-
- exitPoint.setLocation();
-
- return encodedVar;
- }
-
- /**
- * Generates code to load a property value onto the operand stack.
- *
- * @param info info for property to load
- * @param ordinal zero-based property ordinal, used only if instanceVar
- * refers to an object array.
- * @param useReadMethod when true, access property by public read method
- * instead of protected field
- * @param instanceVar local variable referencing Storable instance,
- * defaults to "this" if null. If variable type is an Object array, then
- * property values are read from the runtime value of this array instead
- * of a Storable instance.
- * @param adapterInstanceClass class containing static references to
- * adapter instances - defaults to instanceVar
- * @param partialStartVar optional variable for supporting partial key
- * generation. It must be an int, whose runtime value must be less than the
- * properties array length. It marks the range start of the partial
- * property range.
- * @return true if property was loaded from instance, false if loaded from
- * value array
- */
- protected boolean loadPropertyValue(CodeAssembler a,
- StorablePropertyInfo info, int ordinal,
- boolean useReadMethod,
- LocalVariable instanceVar,
- Class<?> adapterInstanceClass,
- LocalVariable partialStartVar)
- {
- TypeDesc type = info.getPropertyType();
- TypeDesc storageType = info.getStorageType();
-
- boolean isObjectArrayInstanceVar = instanceVar != null
- && instanceVar.getType() == TypeDesc.forClass(Object[].class);
-
- boolean useAdapterInstance = adapterInstanceClass != null
- && info.getToStorageAdapter() != null
- && (useReadMethod || isObjectArrayInstanceVar);
-
- if (useAdapterInstance) {
- // Push adapter instance to stack to be used later.
- String fieldName =
- info.getPropertyName() + StorableGenerator.ADAPTER_FIELD_ELEMENT + 0;
- TypeDesc adapterType = TypeDesc.forClass
- (info.getToStorageAdapter().getDeclaringClass());
- a.loadStaticField
- (TypeDesc.forClass(adapterInstanceClass), fieldName, adapterType);
- }
-
- if (instanceVar == null) {
- a.loadThis();
- if (useReadMethod) {
- info.addInvokeReadMethod(a);
- } else {
- // Access property value directly from protected field of "this".
- if (info.getToStorageAdapter() == null) {
- a.loadField(info.getPropertyName(), type);
- } else {
- // Invoke adapter method.
- a.invokeVirtual(info.getReadMethodName() + '$', storageType, null);
- }
- }
- } else if (!isObjectArrayInstanceVar) {
- a.loadLocal(instanceVar);
- if (useReadMethod) {
- info.addInvokeReadMethod(a, instanceVar.getType());
- } else {
- // Access property value directly from protected field of
- // referenced instance. Assumes code is being defined in the
- // same package or a subclass.
- if (info.getToStorageAdapter() == null) {
- a.loadField(instanceVar.getType(), info.getPropertyName(), type);
- } else {
- // Invoke adapter method.
- a.invokeVirtual(instanceVar.getType(),
- info.getReadMethodName() + '$', storageType, null);
- }
- }
- } else {
- // Access property value from object array.
-
- a.loadLocal(instanceVar);
- a.loadConstant(ordinal);
- if (ordinal > 0 && partialStartVar != null) {
- a.loadLocal(partialStartVar);
- a.math(Opcode.ISUB);
- }
-
- a.loadFromArray(TypeDesc.OBJECT);
- a.checkCast(type.toObjectType());
- if (type.isPrimitive()) {
- a.convert(type.toObjectType(), type);
- }
- }
-
- if (useAdapterInstance) {
- // Invoke adapter method on instance pushed earlier.
- a.invoke(info.getToStorageAdapter());
- }
-
- return !isObjectArrayInstanceVar;
- }
-
- /**
- * Returns a negative value if encoding is variable. The minimum static
- * amount is computed from the one's compliment. Of the types with variable
- * encoding lengths, only for primitives is the minimum static amount
- * returned more than zero.
- */
- private int staticEncodingLength(GenericPropertyInfo info) {
- TypeDesc type = info.getStorageType();
- TypeDesc primType = type.toPrimitiveType();
-
- if (primType == null) {
- if (info.isLob()) {
- // Lob locator is stored as a long.
- return 8;
- }
- } else {
- if (info.isNullable()) {
- // Type is a primitive wrapper.
- switch (primType.getTypeCode()) {
- case TypeDesc.BYTE_CODE:
- return ~1;
- case TypeDesc.BOOLEAN_CODE:
- return 1;
- case TypeDesc.SHORT_CODE:
- case TypeDesc.CHAR_CODE:
- return ~1;
- case TypeDesc.INT_CODE:
- return ~1;
- case TypeDesc.FLOAT_CODE:
- return 4;
- case TypeDesc.LONG_CODE:
- return ~1;
- case TypeDesc.DOUBLE_CODE:
- return 8;
- }
- } else {
- // Type is primitive or a required primitive wrapper.
- switch (type.getTypeCode()) {
- case TypeDesc.BYTE_CODE:
- case TypeDesc.BOOLEAN_CODE:
- return 1;
- case TypeDesc.SHORT_CODE:
- case TypeDesc.CHAR_CODE:
- return 2;
- case TypeDesc.INT_CODE:
- case TypeDesc.FLOAT_CODE:
- return 4;
- case TypeDesc.LONG_CODE:
- case TypeDesc.DOUBLE_CODE:
- return 8;
- }
- }
- }
-
- return ~0;
- }
-
- /**
- * @param partialStartVar must not be null
- */
- private Label[] jumpToPartialEntryPoints(CodeAssembler a, LocalVariable partialStartVar,
- int propertyCount) {
- // Create all the entry points for offset var, whose locations will be
- // set later.
- int[] cases = new int[propertyCount];
- Label[] entryPoints = new Label[propertyCount];
- for (int i=0; i<propertyCount; i++) {
- cases[i] = i;
- entryPoints[i] = a.createLabel();
- }
-
- // Now jump in!
- Label errorLoc = a.createLabel();
- a.loadLocal(partialStartVar);
- a.switchBranch(cases, entryPoints, errorLoc);
-
- errorLoc.setLocation();
- TypeDesc errorType = TypeDesc.forClass(IllegalArgumentException.class);
- a.newObject(errorType);
- a.dup();
- a.loadConstant("Illegal partial start offset");
- a.invokeConstructor(errorType, new TypeDesc[] {TypeDesc.STRING});
- a.throwObject();
-
- return entryPoints;
- }
-
- /**
- * Generates code that calls an encoding method in DataEncoder or
- * KeyEncoder. Parameters must already be on the stack.
- *
- * @return 0 if an int amount is pushed onto the stack, or a positive value
- * if offset adjust amount is constant
- */
- private int encodeProperty(CodeAssembler a, TypeDesc type,
- boolean forKey, boolean descending) {
- TypeDesc[] params = new TypeDesc[] {
- type, TypeDesc.forClass(byte[].class), TypeDesc.INT
- };
-
- if (type.isPrimitive()) {
- if (forKey && descending) {
- a.invokeStatic(KeyEncoder.class.getName(), "encodeDesc", null, params);
- } else {
- a.invokeStatic(DataEncoder.class.getName(), "encode", null, params);
- }
-
- switch (type.getTypeCode()) {
- case TypeDesc.BYTE_CODE:
- case TypeDesc.BOOLEAN_CODE:
- return 1;
- case TypeDesc.SHORT_CODE:
- case TypeDesc.CHAR_CODE:
- return 2;
- default:
- case TypeDesc.INT_CODE:
- case TypeDesc.FLOAT_CODE:
- return 4;
- case TypeDesc.LONG_CODE:
- case TypeDesc.DOUBLE_CODE:
- return 8;
- }
- } else if (type.toPrimitiveType() != null) {
- // Type is a primitive wrapper.
-
- int adjust;
- TypeDesc retType;
-
- switch (type.toPrimitiveType().getTypeCode()) {
- case TypeDesc.BOOLEAN_CODE:
- adjust = 1;
- retType = null;
- break;
- case TypeDesc.FLOAT_CODE:
- adjust = 4;
- retType = null;
- break;
- case TypeDesc.DOUBLE_CODE:
- adjust = 8;
- retType = null;
- break;
- default:
- adjust = 0;
- retType = TypeDesc.INT;
- }
-
- if (forKey && descending) {
- a.invokeStatic(KeyEncoder.class.getName(), "encodeDesc", retType, params);
- } else {
- a.invokeStatic(DataEncoder.class.getName(), "encode", retType, params);
- }
-
- return adjust;
- } else {
- // Type is a String or byte array.
- if (forKey) {
- if (descending) {
- a.invokeStatic
- (KeyEncoder.class.getName(), "encodeDesc", TypeDesc.INT, params);
- } else {
- a.invokeStatic(KeyEncoder.class.getName(), "encode", TypeDesc.INT, params);
- }
- } else {
- a.invokeStatic(DataEncoder.class.getName(), "encode", TypeDesc.INT, params);
- }
- return 0;
- }
- }
-
- /**
- * Generates code that stores a one or four byte generation value into a
- * byte array referenced by the local variable.
- *
- * @param generation if less than zero, no code is generated
- */
- private void encodeGeneration(CodeAssembler a, LocalVariable encodedVar,
- int offset, int generation)
- {
- if (offset < 0) {
- throw new IllegalArgumentException();
- }
- if (generation < 0) {
- return;
- }
- if (generation < 128) {
- a.loadLocal(encodedVar);
- a.loadConstant(offset);
- a.loadConstant((byte) generation);
- a.storeToArray(TypeDesc.BYTE);
- } else {
- generation |= 0x80000000;
- for (int i=0; i<4; i++) {
- a.loadLocal(encodedVar);
- a.loadConstant(offset + i);
- a.loadConstant((byte) (generation >> (8 * (3 - i))));
- a.storeToArray(TypeDesc.BYTE);
- }
- }
- }
-
- /**
- * Generates code to push RawSupport instance to the stack. RawSupport is
- * available only in Storable instances. If instanceVar is an Object[], a
- * SupportException is thrown.
- */
- private void pushRawSupport(CodeAssembler a, LocalVariable instanceVar)
- throws SupportException
- {
- boolean isObjectArrayInstanceVar = instanceVar != null
- && instanceVar.getType() == TypeDesc.forClass(Object[].class);
-
- if (isObjectArrayInstanceVar) {
- throw new SupportException("Lob properties not supported");
- }
-
- if (instanceVar == null) {
- a.loadThis();
- } else {
- a.loadLocal(instanceVar);
- }
-
- a.loadField(StorableGenerator.SUPPORT_FIELD_NAME,
- TypeDesc.forClass(TriggerSupport.class));
- a.checkCast(TypeDesc.forClass(RawSupport.class));
- }
-
- /**
- * Generates code to get a Lob locator value from RawSupport. RawSupport
- * instance and Lob instance must be on the stack. Result is a long locator
- * value on the stack.
- */
- private void getLobLocator(CodeAssembler a, StorablePropertyInfo info) {
- if (!info.isLob()) {
- throw new IllegalArgumentException();
- }
- a.invokeInterface(TypeDesc.forClass(RawSupport.class), "getLocator",
- TypeDesc.LONG, new TypeDesc[] {info.getStorageType()});
- }
-
- /**
- * Generates code to get a Lob from a locator from RawSupport. RawSupport
- * instance and long locator must be on the stack. Result is a Lob on the
- * stack, which may be null.
- */
- private void getLobFromLocator(CodeAssembler a, StorablePropertyInfo info) {
- if (!info.isLob()) {
- throw new IllegalArgumentException();
- }
-
- TypeDesc type = info.getStorageType();
- String name;
- if (Blob.class.isAssignableFrom(type.toClass())) {
- name = "getBlob";
- } else if (Clob.class.isAssignableFrom(type.toClass())) {
- name = "getClob";
- } else {
- throw new IllegalArgumentException();
- }
-
- a.invokeInterface(TypeDesc.forClass(RawSupport.class), name,
- type, new TypeDesc[] {TypeDesc.LONG});
- }
-
- /////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////
-
- private void buildDecoding(boolean forKey,
- CodeAssembler a,
- StorableProperty<S>[] properties,
- Direction[] directions,
- LocalVariable instanceVar,
- Class<?> adapterInstanceClass,
- boolean useWriteMethods,
- int generation,
- Label altGenerationHandler,
- LocalVariable encodedVar)
- throws SupportException
- {
- if (a == null) {
- throw new IllegalArgumentException();
- }
- if (encodedVar == null || encodedVar.getType() != TypeDesc.forClass(byte[].class)) {
- throw new IllegalArgumentException();
- }
-
- // Decoding order is:
- //
- // 1. Prefix
- // 2. Generation prefix
- // 3. Properties
- // 4. Suffix
-
- final int prefix = forKey ? mKeyPrefixPadding : mDataPrefixPadding;
-
- final int generationPrefix;
- if (generation < 0) {
- generationPrefix = 0;
- } else if (generation < 128) {
- generationPrefix = 1;
- } else {
- generationPrefix = 4;
- }
-
- final int suffix = forKey ? mKeySuffixPadding : mDataSuffixPadding;
-
- final TypeDesc byteArrayType = TypeDesc.forClass(byte[].class);
-
- StorablePropertyInfo[] infos = checkSupport(properties);
-
- decodeGeneration(a, encodedVar, prefix, generation, altGenerationHandler);
-
- if (properties.length == 1) {
- StorableProperty<S> property = properties[0];
- StorablePropertyInfo info = infos[0];
-
- if (info.getStorageType().toClass() == byte[].class) {
- // Since there is only one property, and it is just a byte
- // array, it doesn't have any fancy encoding.
-
- // Push to stack in preparation for storing a property.
- pushDecodingInstanceVar(a, 0, instanceVar);
-
- a.loadLocal(encodedVar);
-
- boolean descending =
- forKey && directions != null && directions[0] == Direction.DESCENDING;
-
- TypeDesc[] params;
- if (prefix > 0 || generationPrefix > 0 || suffix > 0) {
- a.loadConstant(prefix + generationPrefix);
- a.loadConstant(suffix);
- params = new TypeDesc[] {byteArrayType, TypeDesc.INT, TypeDesc.INT};
- } else {
- params = new TypeDesc[] {byteArrayType};
- }
-
- if (property.isNullable()) {
- if (descending) {
- a.invokeStatic(KeyDecoder.class.getName(), "decodeSingleNullableDesc",
- byteArrayType, params);
- } else {
- a.invokeStatic(DataDecoder.class.getName(), "decodeSingleNullable",
- byteArrayType, params);
- }
- } else if (descending) {
- a.invokeStatic(KeyDecoder.class.getName(), "decodeSingleDesc",
- byteArrayType, params);
- } else if (prefix > 0 || generationPrefix > 0 || suffix > 0) {
- a.invokeStatic(DataDecoder.class.getName(), "decodeSingle",
- byteArrayType, params);
- } else {
- // Just store raw property value.
- }
-
- storePropertyValue(a, info, useWriteMethods, instanceVar, adapterInstanceClass);
- return;
- }
- }
-
- // Now decode from the byte array.
-
- int constantOffset = prefix + generationPrefix;
- LocalVariable offset = null;
- // References to local variables which will hold references.
- LocalVariable[] stringRef = new LocalVariable[1];
- LocalVariable[] byteArrayRef = new LocalVariable[1];
- LocalVariable[] valueRefRef = new LocalVariable[1];
-
- for (int i=0; i<infos.length; i++) {
- StorablePropertyInfo info = infos[i];
-
- // Push to stack in preparation for storing a property.
- pushDecodingInstanceVar(a, i, instanceVar);
-
- TypeDesc storageType = info.getStorageType();
-
- if (info.isLob()) {
- // Need RawSupport instance for getting Lob from locator.
- pushRawSupport(a, instanceVar);
- // Locator is encoded as a long.
- storageType = TypeDesc.LONG;
- }
-
- a.loadLocal(encodedVar);
- if (offset == null) {
- a.loadConstant(constantOffset);
- } else {
- a.loadLocal(offset);
- }
-
- boolean descending =
- forKey && directions != null && directions[i] == Direction.DESCENDING;
-
- int amt = decodeProperty(a, info, storageType, forKey, descending,
- stringRef, byteArrayRef, valueRefRef);
-
- if (info.isLob()) {
- getLobFromLocator(a, info);
- }
-
- if (amt != 0) {
- if (i + 1 < properties.length) {
- // Only adjust offset if there are more properties.
-
- if (amt > 0) {
- if (offset == null) {
- constantOffset += amt;
- } else {
- a.loadConstant(amt);
- a.loadLocal(offset);
- a.math(Opcode.IADD);
- a.storeLocal(offset);
- }
- } else {
- // Offset adjust is one if returned object is null.
- a.dup();
- Label notNull = a.createLabel();
- a.ifNullBranch(notNull, false);
- a.loadConstant(1 + (offset == null ? constantOffset : 0));
- Label cont = a.createLabel();
- a.branch(cont);
- notNull.setLocation();
- a.loadConstant(~amt + (offset == null ? constantOffset : 0));
- cont.setLocation();
-
- if (offset == null) {
- offset = a.createLocalVariable(null, TypeDesc.INT);
- } else {
- a.loadLocal(offset);
- a.math(Opcode.IADD);
- }
- a.storeLocal(offset);
- }
- }
- } else {
- if (i + 1 >= properties.length) {
- // Don't need to keep track of offset anymore.
- a.pop();
- } else {
- // Only adjust offset if there are more properties.
- if (offset == null) {
- if (constantOffset > 0) {
- a.loadConstant(constantOffset);
- a.math(Opcode.IADD);
- }
- offset = a.createLocalVariable(null, TypeDesc.INT);
- } else {
- a.loadLocal(offset);
- a.math(Opcode.IADD);
- }
- a.storeLocal(offset);
- }
-
- // Get the value out of the ref array so that it can be stored.
- a.loadLocal(valueRefRef[0]);
- a.loadConstant(0);
- a.loadFromArray(valueRefRef[0].getType());
- }
-
- storePropertyValue(a, info, useWriteMethods, instanceVar, adapterInstanceClass);
- }
- }
-
- /**
- * Generates code that calls a decoding method in DataDecoder or
- * KeyDecoder. Parameters must already be on the stack.
- *
- * @return 0 if an int amount is pushed onto the stack, or a positive value
- * if offset adjust amount is constant, or a negative value if offset
- * adjust is constant or one more
- */
- private int decodeProperty(CodeAssembler a,
- GenericPropertyInfo info, TypeDesc storageType,
- boolean forKey, boolean descending,
- LocalVariable[] stringRefRef, LocalVariable[] byteArrayRefRef,
- LocalVariable[] valueRefRef)
- throws SupportException
- {
- TypeDesc primType = storageType.toPrimitiveType();
-
- if (primType != null) {
- String methodName;
- TypeDesc returnType;
- int adjust;
-
- if (primType != storageType && info.isNullable()) {
- // Property type is a nullable boxed primitive.
- returnType = storageType;
-
- switch (primType.getTypeCode()) {
- case TypeDesc.BYTE_CODE:
- methodName = "decodeByteObj";
- adjust = ~2;
- break;
- case TypeDesc.BOOLEAN_CODE:
- methodName = "decodeBooleanObj";
- adjust = 1;
- break;
- case TypeDesc.SHORT_CODE:
- methodName = "decodeShortObj";
- adjust = ~3;
- break;
- case TypeDesc.CHAR_CODE:
- methodName = "decodeCharacterObj";
- adjust = ~3;
- break;
- default:
- case TypeDesc.INT_CODE:
- methodName = "decodeIntegerObj";
- adjust = ~5;
- break;
- case TypeDesc.FLOAT_CODE:
- methodName = "decodeFloatObj";
- adjust = 4;
- break;
- case TypeDesc.LONG_CODE:
- methodName = "decodeLongObj";
- adjust = ~9;
- break;
- case TypeDesc.DOUBLE_CODE:
- methodName = "decodeDoubleObj";
- adjust = 8;
- break;
- }
- } else {
- // Property type is a primitive or a boxed primitive.
- returnType = primType;
-
- switch (primType.getTypeCode()) {
- case TypeDesc.BYTE_CODE:
- methodName = "decodeByte";
- adjust = 1;
- break;
- case TypeDesc.BOOLEAN_CODE:
- methodName = "decodeBoolean";
- adjust = 1;
- break;
- case TypeDesc.SHORT_CODE:
- methodName = "decodeShort";
- adjust = 2;
- break;
- case TypeDesc.CHAR_CODE:
- methodName = "decodeChar";
- adjust = 2;
- break;
- default:
- case TypeDesc.INT_CODE:
- methodName = "decodeInt";
- adjust = 4;
- break;
- case TypeDesc.FLOAT_CODE:
- methodName = "decodeFloat";
- adjust = 4;
- break;
- case TypeDesc.LONG_CODE:
- methodName = "decodeLong";
- adjust = 8;
- break;
- case TypeDesc.DOUBLE_CODE:
- methodName = "decodeDouble";
- adjust = 8;
- break;
- }
- }
-
- TypeDesc[] params = {TypeDesc.forClass(byte[].class), TypeDesc.INT};
- if (forKey && descending) {
- a.invokeStatic
- (KeyDecoder.class.getName(), methodName + "Desc", returnType, params);
- } else {
- a.invokeStatic
- (DataDecoder.class.getName(), methodName, returnType, params);
- }
-
- if (returnType.isPrimitive()) {
- if (!storageType.isPrimitive()) {
- // Wrap it.
- a.convert(returnType, storageType);
- }
- }
-
- return adjust;
- } else {
- String className = (forKey ? KeyDecoder.class : DataDecoder.class).getName();
- String methodName;
- TypeDesc refType;
-
- if (storageType == TypeDesc.STRING) {
- methodName = (forKey && descending) ? "decodeStringDesc" : "decodeString";
- refType = TypeDesc.forClass(String[].class);
- if (stringRefRef[0] == null) {
- stringRefRef[0] = a.createLocalVariable(null, refType);
- a.loadConstant(1);
- a.newObject(refType);
- a.storeLocal(stringRefRef[0]);
- }
- a.loadLocal(stringRefRef[0]);
- valueRefRef[0] = stringRefRef[0];
- } else if (storageType.toClass() == byte[].class) {
- methodName = (forKey && descending) ? "decodeDesc" : "decode";
- refType = TypeDesc.forClass(byte[][].class);
- if (byteArrayRefRef[0] == null) {
- byteArrayRefRef[0] = a.createLocalVariable(null, refType);
- a.loadConstant(1);
- a.newObject(refType);
- a.storeLocal(byteArrayRefRef[0]);
- }
- a.loadLocal(byteArrayRefRef[0]);
- valueRefRef[0] = byteArrayRefRef[0];
- } else {
- throw notSupported(info.getPropertyName(), storageType.getFullName());
- }
-
- TypeDesc[] params = {TypeDesc.forClass(byte[].class), TypeDesc.INT, refType};
- a.invokeStatic(className, methodName, TypeDesc.INT, params);
-
- return 0;
- }
- }
-
- /**
- * Push decoding instanceVar to stack in preparation to calling
- * storePropertyValue.
- *
- * @param ordinal zero-based property ordinal, used only if instanceVar
- * refers to an object array.
- * @param instanceVar local variable referencing Storable instance,
- * defaults to "this" if null. If variable type is an Object array, then
- * property values are written to the runtime value of this array instead
- * of a Storable instance.
- * @see #storePropertyValue storePropertyValue
- */
- protected void pushDecodingInstanceVar(CodeAssembler a, int ordinal,
- LocalVariable instanceVar) {
- if (instanceVar == null) {
- // Push this to stack in preparation for storing a property.
- a.loadThis();
- } else if (instanceVar.getType() != TypeDesc.forClass(Object[].class)) {
- // Push reference to stack in preparation for storing a property.
- a.loadLocal(instanceVar);
- } else {
- // Push array and index to stack in preparation for storing a property.
- a.loadLocal(instanceVar);
- a.loadConstant(ordinal);
- }
- }
-
- /**
- * Generates code to store a property value into an instance which is
- * already on the operand stack. If instance is an Object array, index into
- * array must also be on the operand stack.
- *
- * @param info info for property to store to
- * @param useWriteMethod when true, set property by public write method
- * instead of protected field
- * @param instanceVar local variable referencing Storable instance,
- * defaults to "this" if null. If variable type is an Object array, then
- * property values are written to the runtime value of this array instead
- * of a Storable instance.
- * @param adapterInstanceClass class containing static references to
- * adapter instances - defaults to instanceVar
- * @see #pushDecodingInstanceVar pushDecodingInstanceVar
- */
- protected void storePropertyValue(CodeAssembler a, StorablePropertyInfo info,
- boolean useWriteMethod,
- LocalVariable instanceVar,
- Class<?> adapterInstanceClass) {
- TypeDesc type = info.getPropertyType();
- TypeDesc storageType = info.getStorageType();
-
- boolean isObjectArrayInstanceVar = instanceVar != null
- && instanceVar.getType() == TypeDesc.forClass(Object[].class);
-
- boolean useAdapterInstance = adapterInstanceClass != null
- && info.getToStorageAdapter() != null
- && (useWriteMethod || isObjectArrayInstanceVar);
-
- if (useAdapterInstance) {
- // Push adapter instance to adapt property value. It must be on the
- // stack before the property value, so swap.
-
- // Store unadapted property to temp var in order to be swapped.
- LocalVariable temp = a.createLocalVariable(null, storageType);
- a.storeLocal(temp);
-
- String fieldName =
- info.getPropertyName() + StorableGenerator.ADAPTER_FIELD_ELEMENT + 0;
- TypeDesc adapterType = TypeDesc.forClass
- (info.getToStorageAdapter().getDeclaringClass());
- a.loadStaticField
- (TypeDesc.forClass(adapterInstanceClass), fieldName, adapterType);
-
- a.loadLocal(temp);
- a.invoke(info.getFromStorageAdapter());
-
- // Stack now contains property adapted to its publicly declared type.
- }
-
- if (instanceVar == null) {
- if (useWriteMethod) {
- info.addInvokeWriteMethod(a);
- } else {
- // Set property value directly to protected field of instance.
- if (info.getToStorageAdapter() == null) {
- a.storeField(info.getPropertyName(), type);
- } else {
- // Invoke adapter method.
- a.invokeVirtual(info.getWriteMethodName() + '$',
- null, new TypeDesc[] {storageType});
- }
- }
- } else if (!isObjectArrayInstanceVar) {
- TypeDesc instanceVarType = instanceVar.getType();
-
- // Drop properties that are missing or whose types are incompatible.
- doDrop: {
- Class instanceVarClass = instanceVarType.toClass();
- if (instanceVarClass != null) {
- Map<String, BeanProperty> props =
- BeanIntrospector.getAllProperties(instanceVarClass);
- BeanProperty prop = props.get(info.getPropertyName());
- if (prop != null) {
- if (prop.getType() == type.toClass()) {
- break doDrop;
- }
- // Types differ, but if primitive types, perform conversion.
- TypeDesc primType = type.toPrimitiveType();
- if (primType != null) {
- TypeDesc propType = TypeDesc.forClass(prop.getType());
- TypeDesc primPropType = propType.toPrimitiveType();
- if (primPropType != null) {
- // Apply conversion and store property.
- a.convert(type, propType);
- type = propType;
- break doDrop;
- }
- }
- }
- }
-
- // Drop missing or incompatible property.
- if (storageType.isDoubleWord()) {
- a.pop2();
- } else {
- a.pop();
- }
- return;
- }
-
- if (useWriteMethod) {
- info.addInvokeWriteMethod(a, instanceVarType);
- } else {
- // Set property value directly to protected field of referenced
- // instance. Assumes code is being defined in the same package
- // or a subclass.
- if (info.getToStorageAdapter() == null) {
- a.storeField(instanceVarType, info.getPropertyName(), type);
- } else {
- // Invoke adapter method.
- a.invokeVirtual(instanceVarType, info.getWriteMethodName() + '$',
- null, new TypeDesc[] {storageType});
- }
- }
- } else {
- // Set property value to object array. No need to check if we
- // should call a write method because arrays don't have write
- // methods.
- if (type.isPrimitive()) {
- a.convert(type, type.toObjectType());
- }
- a.storeToArray(TypeDesc.OBJECT);
- }
- }
-
- /**
- * Generates code that ensures a matching generation value exists in the
- * byte array referenced by the local variable, throwing a
- * CorruptEncodingException otherwise.
- *
- * @param generation if less than zero, no code is generated
- */
- private void decodeGeneration(CodeAssembler a, LocalVariable encodedVar,
- int offset, int generation, Label altGenerationHandler)
- {
- if (offset < 0) {
- throw new IllegalArgumentException();
- }
- if (generation < 0) {
- return;
- }
-
- LocalVariable actualGeneration = a.createLocalVariable(null, TypeDesc.INT);
- a.loadLocal(encodedVar);
- a.loadConstant(offset);
- a.loadFromArray(TypeDesc.BYTE);
- a.storeLocal(actualGeneration);
- a.loadLocal(actualGeneration);
- Label compareGeneration = a.createLabel();
- a.ifZeroComparisonBranch(compareGeneration, ">=");
-
- // Decode four byte generation format.
- a.loadLocal(actualGeneration);
- a.loadConstant(24);
- a.math(Opcode.ISHL);
- a.loadConstant(0x7fffffff);
- a.math(Opcode.IAND);
- for (int i=1; i<4; i++) {
- a.loadLocal(encodedVar);
- a.loadConstant(offset + i);
- a.loadFromArray(TypeDesc.BYTE);
- a.loadConstant(0xff);
- a.math(Opcode.IAND);
- int shift = 8 * (3 - i);
- if (shift > 0) {
- a.loadConstant(shift);
- a.math(Opcode.ISHL);
- }
- a.math(Opcode.IOR);
- }
- a.storeLocal(actualGeneration);
-
- compareGeneration.setLocation();
-
- a.loadConstant(generation);
- a.loadLocal(actualGeneration);
- Label generationMatches = a.createLabel();
- a.ifComparisonBranch(generationMatches, "==");
-
- if (altGenerationHandler != null) {
- a.loadLocal(actualGeneration);
- a.branch(altGenerationHandler);
- } else {
- // Throw CorruptEncodingException.
-
- TypeDesc corruptEncodingEx = TypeDesc.forClass(CorruptEncodingException.class);
- a.newObject(corruptEncodingEx);
- a.dup();
- a.loadConstant(generation); // expected generation
- a.loadLocal(actualGeneration); // actual generation
- a.invokeConstructor(corruptEncodingEx, new TypeDesc[] {TypeDesc.INT, TypeDesc.INT});
- a.throwObject();
- }
-
- generationMatches.setLocation();
- }
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/GenericInstanceFactory.java b/src/main/java/com/amazon/carbonado/spi/raw/GenericInstanceFactory.java deleted file mode 100644 index 5a6a4cb..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/GenericInstanceFactory.java +++ /dev/null @@ -1,36 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-import com.amazon.carbonado.FetchException;
-import com.amazon.carbonado.Storable;
-import com.amazon.carbonado.Storage;
-
-/**
- * Can be used with {@link com.amazon.carbonado.util.QuickConstructorGenerator}
- * for instantiating generic storable instances.
- *
- * @author Brian S O'Neill
- */
-public interface GenericInstanceFactory {
- Storable instantiate(RawSupport support);
-
- Storable instantiate(RawSupport support, byte[] key, byte[] value)
- throws FetchException;
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/GenericPropertyInfo.java b/src/main/java/com/amazon/carbonado/spi/raw/GenericPropertyInfo.java deleted file mode 100644 index c734f03..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/GenericPropertyInfo.java +++ /dev/null @@ -1,60 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-import java.lang.reflect.Method;
-
-import org.cojen.classfile.TypeDesc;
-
-/**
- * Minimal information required by {@link GenericEncodingStrategy} to encode
- * and decode a storable property or layout property.
- *
- * @author Brian S O'Neill
- */
-public interface GenericPropertyInfo {
- String getPropertyName();
-
- /**
- * Returns the user specified property type.
- */
- TypeDesc getPropertyType();
-
- /**
- * Returns the storage supported type. If it differs from the property
- * type, then adapter methods must also exist.
- */
- TypeDesc getStorageType();
-
- boolean isNullable();
-
- boolean isLob();
-
- /**
- * Returns the optional method used to adapt the property from the
- * storage supported type to the user visible type.
- */
- Method getFromStorageAdapter();
-
- /**
- * Returns the optional method used to adapt the property from the user
- * visible type to the storage supported type.
- */
- Method getToStorageAdapter();
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/GenericStorableCodec.java b/src/main/java/com/amazon/carbonado/spi/raw/GenericStorableCodec.java deleted file mode 100644 index 7a98540..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/GenericStorableCodec.java +++ /dev/null @@ -1,813 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-import java.lang.ref.WeakReference;
-import java.lang.reflect.Method;
-import java.lang.reflect.UndeclaredThrowableException;
-import java.util.Map;
-
-import org.cojen.classfile.ClassFile;
-import org.cojen.classfile.CodeBuilder;
-import org.cojen.classfile.Label;
-import org.cojen.classfile.LocalVariable;
-import org.cojen.classfile.MethodInfo;
-import org.cojen.classfile.Modifiers;
-import org.cojen.classfile.TypeDesc;
-import org.cojen.util.ClassInjector;
-import org.cojen.util.IntHashMap;
-import org.cojen.util.KeyFactory;
-import org.cojen.util.SoftValuedHashMap;
-
-import com.amazon.carbonado.CorruptEncodingException;
-import com.amazon.carbonado.FetchException;
-import com.amazon.carbonado.FetchNoneException;
-import com.amazon.carbonado.RepositoryException;
-import com.amazon.carbonado.Storable;
-import com.amazon.carbonado.Storage;
-import com.amazon.carbonado.SupportException;
-import com.amazon.carbonado.info.Direction;
-import com.amazon.carbonado.info.OrderedProperty;
-import com.amazon.carbonado.info.StorableIndex;
-import com.amazon.carbonado.layout.Layout;
-import com.amazon.carbonado.spi.CodeBuilderUtil;
-import com.amazon.carbonado.util.ThrowUnchecked;
-import com.amazon.carbonado.util.QuickConstructorGenerator;
-
-/**
- * Generic codec that supports any kind of storable by auto-generating and
- * caching storable implementations.
- *
- * @author Brian S O'Neill
- * @see GenericStorableCodecFactory
- */
-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.
- private static final Map cCache = new SoftValuedHashMap();
-
- /**
- * Returns an instance of the codec. The Storable type itself may be an
- * interface or a class. If it is a class, then it must not be final, and
- * it must have a public, no-arg constructor.
- *
- * @param isMaster when true, version properties and sequences are managed
- * @param layout when non-null, encode a storable layout generation
- * value in one or four bytes. Generation 0..127 is encoded in one byte, and
- * 128..max is encoded in four bytes, with the most significant bit set.
- * @throws SupportException if Storable is not supported
- * @throws amazon.carbonado.MalformedTypeException if Storable type is not well-formed
- * @throws IllegalArgumentException if type is null
- */
- @SuppressWarnings("unchecked")
- static synchronized <S extends Storable> GenericStorableCodec<S> getInstance
- (GenericStorableCodecFactory factory,
- GenericEncodingStrategy<S> encodingStrategy, boolean isMaster, Layout layout)
- throws SupportException
- {
- Object key;
- if (layout == null) {
- key = KeyFactory.createKey(new Object[] {encodingStrategy, isMaster});
- } else {
- key = KeyFactory.createKey
- (new Object[] {encodingStrategy, isMaster, factory, layout.getGeneration()});
- }
-
- GenericStorableCodec<S> codec = (GenericStorableCodec<S>) cCache.get(key);
- if (codec == null) {
- codec = new GenericStorableCodec<S>
- (factory,
- encodingStrategy.getType(),
- generateStorable(encodingStrategy, isMaster, layout),
- encodingStrategy,
- layout);
- cCache.put(key, codec);
- }
-
- return codec;
- }
-
- @SuppressWarnings("unchecked")
- private static <S extends Storable> Class<? extends S> generateStorable
- (GenericEncodingStrategy<S> encodingStrategy, boolean isMaster, Layout layout)
- throws SupportException
- {
- final Class<S> storableClass = encodingStrategy.getType();
- final Class<? extends S> abstractClass =
- RawStorableGenerator.getAbstractClass(storableClass, isMaster);
- final int generation = layout == null ? -1 : layout.getGeneration();
-
- ClassInjector ci = ClassInjector.create
- (storableClass.getName(), abstractClass.getClassLoader());
-
- ClassFile cf = new ClassFile(ci.getClassName(), abstractClass);
- cf.markSynthetic();
- cf.setSourceFile(GenericStorableCodec.class.getName());
- cf.setTarget("1.5");
-
- // Declare some types.
- final TypeDesc storageType = TypeDesc.forClass(Storage.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 constructor that accepts a RawSupport.
- {
- TypeDesc[] params = {rawSupportType};
- MethodInfo mi = cf.addConstructor(Modifiers.PUBLIC, params);
- CodeBuilder b = new CodeBuilder(mi);
- b.loadThis();
- b.loadLocal(b.getParameter(0));
- b.invokeSuperConstructor(params);
- b.returnVoid();
- }
-
- // Add constructor that accepts a RawSupport, an encoded key, and an
- // encoded data.
- {
- TypeDesc[] params = {rawSupportType, byteArrayType, byteArrayType};
- MethodInfo mi = cf.addConstructor(Modifiers.PUBLIC, params);
- CodeBuilder b = new CodeBuilder(mi);
- b.loadThis();
- b.loadLocal(b.getParameter(0));
- b.loadLocal(b.getParameter(1));
- b.loadLocal(b.getParameter(2));
- b.invokeSuperConstructor(params);
- b.returnVoid();
- }
-
- // Implement protected abstract methods inherited from parent class.
-
- // byte[] encodeKey()
- {
- // Encode the primary key into a byte array that supports correct
- // ordering. No special key comparator is needed.
- MethodInfo mi = cf.addMethod(Modifiers.PROTECTED,
- RawStorableGenerator.ENCODE_KEY_METHOD_NAME,
- byteArrayType, null);
- CodeBuilder b = new CodeBuilder(mi);
-
- // TODO: Consider caching generated key. Rebuild if null or if pk is dirty.
-
- // assembler = b
- // properties = null (defaults to all key properties)
- // instanceVar = null (null means "this")
- // adapterInstanceClass = null (null means use instanceVar, in this case is "this")
- // useReadMethods = false (will read fields directly)
- // partialStartVar = null (only support encoding all properties)
- // partialEndVar = null (only support encoding all properties)
- LocalVariable encodedVar =
- encodingStrategy.buildKeyEncoding(b, null, null, null, false, null, null);
-
- b.loadLocal(encodedVar);
- b.returnValue(byteArrayType);
- }
-
- // byte[] encodeData()
- {
- // Encoding non-primary key data properties.
- MethodInfo mi = cf.addMethod(Modifiers.PROTECTED,
- RawStorableGenerator.ENCODE_DATA_METHOD_NAME,
- byteArrayType, null);
- CodeBuilder b = new CodeBuilder(mi);
-
- // assembler = b
- // properties = null (defaults to all non-key properties)
- // instanceVar = null (null means "this")
- // adapterInstanceClass = null (null means use instanceVar, in this case is "this")
- // useReadMethods = false (will read fields directly)
- // generation = generation
- LocalVariable encodedVar =
- encodingStrategy.buildDataEncoding(b, null, null, null, false, generation);
-
- b.loadLocal(encodedVar);
- b.returnValue(byteArrayType);
- }
-
- // void decodeKey(byte[])
- {
- MethodInfo mi = cf.addMethod(Modifiers.PROTECTED,
- RawStorableGenerator.DECODE_KEY_METHOD_NAME,
- null, byteArrayParam);
- CodeBuilder b = new CodeBuilder(mi);
-
- // assembler = b
- // properties = null (defaults to all key properties)
- // instanceVar = null (null means "this")
- // adapterInstanceClass = null (null means use instanceVar, in this case is "this")
- // useWriteMethods = false (will set fields directly)
- // encodedVar = references byte array with encoded key
- encodingStrategy.buildKeyDecoding(b, null, null, null, false, b.getParameter(0));
-
- b.returnVoid();
- }
-
- // void decodeData(byte[])
- {
- MethodInfo mi = cf.addMethod(Modifiers.PROTECTED,
- RawStorableGenerator.DECODE_DATA_METHOD_NAME,
- null, byteArrayParam);
- CodeBuilder b = new CodeBuilder(mi);
- Label altGenerationHandler = b.createLabel();
-
- // assembler = b
- // properties = null (defaults to all non-key properties)
- // instanceVar = null (null means "this")
- // adapterInstanceClass = null (null means use instanceVar, in this case is "this")
- // useWriteMethods = false (will set fields directly)
- // generation = generation
- // altGenerationHandler = altGenerationHandler
- // encodedVar = references byte array with encoded data
- encodingStrategy.buildDataDecoding
- (b, null, null, null, false, generation, altGenerationHandler, b.getParameter(0));
-
- b.returnVoid();
-
- // Support decoding alternate generation.
-
- altGenerationHandler.setLocation();
- 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");
-
- haveCodec.setLocation();
- b.checkCast(codecType);
- b.loadLocal(actualGeneration);
- b.invokeVirtual(codecType, "getDecoder", decoderType, new TypeDesc[] {TypeDesc.INT});
- b.loadThis();
- b.loadLocal(b.getParameter(0));
- b.invokeInterface(decoderType, "decode", null,
- new TypeDesc[] {TypeDesc.forClass(Storable.class), byteArrayType});
-
- b.returnVoid();
- }
-
- return ci.defineClass(cf);
- }
-
- private final GenericStorableCodecFactory mFactory;
-
- private final Class<S> mType;
-
- private final Class<? extends S> mStorableClass;
-
- // Weakly reference the encoding strategy because of the way
- // GenericStorableCodec instances are cached in a SoftValuedHashMap.
- // GenericStorableCodec can still be reclaimed by the garbage collector.
- private final WeakReference<GenericEncodingStrategy<S>> mEncodingStrategy;
-
- private final GenericInstanceFactory mInstanceFactory;
-
- private final SearchKeyFactory<S> mPrimaryKeyFactory;
-
- // Maps OrderedProperty[] keys to SearchKeyFactory instances.
- private final Map mSearchKeyFactories = new SoftValuedHashMap();
-
- private final Layout mLayout;
-
- // Maps layout generations to Decoders.
- private IntHashMap mDecoders;
-
- private GenericStorableCodec(GenericStorableCodecFactory factory,
- Class<S> type, Class<? extends S> storableClass,
- GenericEncodingStrategy<S> encodingStrategy,
- Layout layout) {
- mFactory = factory;
- mType = type;
- mStorableClass = storableClass;
- mEncodingStrategy = new WeakReference<GenericEncodingStrategy<S>>(encodingStrategy);
- mInstanceFactory = QuickConstructorGenerator
- .getInstance(storableClass, GenericInstanceFactory.class);
- mPrimaryKeyFactory = getSearchKeyFactory(encodingStrategy.gatherAllKeyProperties());
- mLayout = layout;
-
- 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);
- }
- }
- }
-
- /**
- * Returns the type of Storable that code is generated for.
- */
- public final Class<S> getStorableType() {
- return mType;
- }
-
- /**
- * Instantiate a Storable with no key or value defined yet.
- *
- * @param support binds generated storable with a storage layer
- */
- @SuppressWarnings("unchecked")
- public S instantiate(RawSupport<S> support) {
- return (S) mInstanceFactory.instantiate(support);
- }
-
- /**
- * Instantiate a Storable with a specific key and value.
- *
- * @param support binds generated storable with a storage layer
- */
- @SuppressWarnings("unchecked")
- public S instantiate(RawSupport<S> support, byte[] key, byte[] value)
- throws FetchException
- {
- return (S) mInstanceFactory.instantiate(support, key, value);
- }
-
- public StorableIndex<S> getPrimaryKeyIndex() {
- return getEncodingStrategy().getPrimaryKeyIndex();
- }
-
- public int getPrimaryKeyPrefixLength() {
- return getEncodingStrategy().getConstantKeyPrefixLength();
- }
-
- public byte[] encodePrimaryKey(S storable) {
- return mPrimaryKeyFactory.encodeSearchKey(storable);
- }
-
- public byte[] encodePrimaryKey(S storable, int rangeStart, int rangeEnd) {
- return mPrimaryKeyFactory.encodeSearchKey(storable, rangeStart, rangeEnd);
- }
-
- public byte[] encodePrimaryKey(Object[] values) {
- return mPrimaryKeyFactory.encodeSearchKey(values);
- }
-
- public byte[] encodePrimaryKey(Object[] values, int rangeStart, int rangeEnd) {
- return mPrimaryKeyFactory.encodeSearchKey(values, rangeStart, rangeEnd);
- }
-
- public byte[] encodePrimaryKeyPrefix() {
- return mPrimaryKeyFactory.encodeSearchKeyPrefix();
- }
-
- /**
- * Returns a concrete Storable implementation, which is fully
- * thread-safe. It has two constructors defined:
- *
- * <pre>
- * public <init>(Storage, RawSupport);
- *
- * public <init>(Storage, RawSupport, byte[] key, byte[] value);
- * </pre>
- *
- * Convenience methods are provided in this class to instantiate the
- * generated Storable.
- */
- public Class<? extends S> getStorableClass() {
- return mStorableClass;
- }
-
- /**
- * Returns a search key factory, which is useful for implementing indexes
- * and queries.
- *
- * @param properties properties to build the search key from
- */
- @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);
-
- synchronized (mSearchKeyFactories) {
- SearchKeyFactory<S> factory = (SearchKeyFactory<S>) mSearchKeyFactories.get(key);
- if (factory == null) {
- factory = generateSearchKeyFactory(properties);
- mSearchKeyFactories.put(key, factory);
- }
- return factory;
- }
- }
-
- /**
- * Returns a data decoder for the given generation.
- *
- * @throws FetchNoneException if generation is unknown
- */
- public Decoder<S> getDecoder(int generation) throws FetchNoneException, FetchException {
- try {
- synchronized (mLayout) {
- IntHashMap decoders = mDecoders;
- if (decoders == null) {
- mDecoders = decoders = new IntHashMap();
- }
- Decoder<S> decoder = (Decoder<S>) decoders.get(generation);
- if (decoder == null) {
- decoder = generateDecoder(generation);
- mDecoders.put(generation, decoder);
- }
- return decoder;
- }
- } catch (NullPointerException e) {
- if (mLayout == null) {
- throw new FetchNoneException("Layout evolution not supported");
- }
- throw e;
- }
- }
-
- private GenericEncodingStrategy<S> getEncodingStrategy() {
- // Should never be null, even though it is weakly referenced. As long
- // as this class can be reached by the cache, the encoding strategy
- // object exists since it is the cache key.
- return mEncodingStrategy.get();
- }
-
- @SuppressWarnings("unchecked")
- private SearchKeyFactory<S> generateSearchKeyFactory(OrderedProperty<S>[] properties) {
- GenericEncodingStrategy encodingStrategy = getEncodingStrategy();
-
- ClassInjector ci;
- {
- StringBuilder b = new StringBuilder();
- b.append(mType.getName());
- b.append('$');
- for (OrderedProperty property : properties) {
- if (property.getDirection() == Direction.UNSPECIFIED) {
- property = property.direction(Direction.ASCENDING);
- }
- try {
- property.appendTo(b);
- } catch (java.io.IOException e) {
- // Not gonna happen
- }
- }
- String prefix = b.toString();
- ci = ClassInjector.create(prefix, mStorableClass.getClassLoader());
- }
-
- ClassFile cf = new ClassFile(ci.getClassName());
- cf.addInterface(SearchKeyFactory.class);
- cf.markSynthetic();
- cf.setSourceFile(GenericStorableCodec.class.getName());
- cf.setTarget("1.5");
-
- // Add public no-arg constructor.
- cf.addDefaultConstructor();
-
- // Declare some types.
- final TypeDesc storableType = TypeDesc.forClass(Storable.class);
- final TypeDesc byteArrayType = TypeDesc.forClass(byte[].class);
- final TypeDesc objectArrayType = TypeDesc.forClass(Object[].class);
- final TypeDesc instanceType = TypeDesc.forClass(mStorableClass);
-
- // Define encodeSearchKey(Storable).
- try {
- MethodInfo mi = cf.addMethod
- (Modifiers.PUBLIC, "encodeSearchKey", byteArrayType,
- new TypeDesc[] {storableType});
- CodeBuilder b = new CodeBuilder(mi);
- b.loadLocal(b.getParameter(0));
- b.checkCast(instanceType);
- LocalVariable instanceVar = b.createLocalVariable(null, instanceType);
- b.storeLocal(instanceVar);
-
- // assembler = b
- // properties = properties to encode
- // instanceVar = instanceVar which references storable instance
- // adapterInstanceClass = null (null means use instanceVar)
- // useReadMethods = false (will read fields directly)
- // partialStartVar = null (only support encoding all properties)
- // partialEndVar = null (only support encoding all properties)
- LocalVariable encodedVar = encodingStrategy.buildKeyEncoding
- (b, properties, instanceVar, null, false, null, null);
-
- b.loadLocal(encodedVar);
- b.returnValue(byteArrayType);
- } catch (SupportException e) {
- // Shouldn't happen since all properties were checked in order
- // to create this StorableCodec.
- throw new UndeclaredThrowableException(e);
- }
-
- // Define encodeSearchKey(Storable, int, int).
- try {
- MethodInfo mi = cf.addMethod
- (Modifiers.PUBLIC, "encodeSearchKey", byteArrayType,
- new TypeDesc[] {storableType, TypeDesc.INT, TypeDesc.INT});
- CodeBuilder b = new CodeBuilder(mi);
- b.loadLocal(b.getParameter(0));
- b.checkCast(instanceType);
- LocalVariable instanceVar = b.createLocalVariable(null, instanceType);
- b.storeLocal(instanceVar);
-
- // assembler = b
- // properties = properties to encode
- // instanceVar = instanceVar which references storable instance
- // adapterInstanceClass = null (null means use instanceVar)
- // useReadMethods = false (will read fields directly)
- // partialStartVar = int parameter 1, references start property index
- // partialEndVar = int parameter 2, references end property index
- LocalVariable encodedVar = encodingStrategy.buildKeyEncoding
- (b, properties, instanceVar, null, false, b.getParameter(1), b.getParameter(2));
-
- b.loadLocal(encodedVar);
- b.returnValue(byteArrayType);
- } catch (SupportException e) {
- // Shouldn't happen since all properties were checked in order
- // to create this StorableCodec.
- throw new UndeclaredThrowableException(e);
- }
-
- // The Storable class that we generated earlier is a subclass of the
- // abstract class defined by StorableGenerator. StorableGenerator
- // creates static final adapter instances, with protected
- // access. Calling getSuperclass results in the exact class that
- // StorableGenerator made, which is where the fields are.
- final Class<?> adapterInstanceClass = getStorableClass().getSuperclass();
-
- // Define encodeSearchKey(Object[] values).
- try {
- MethodInfo mi = cf.addMethod
- (Modifiers.PUBLIC, "encodeSearchKey", byteArrayType,
- new TypeDesc[] {objectArrayType});
- CodeBuilder b = new CodeBuilder(mi);
-
- // assembler = b
- // properties = properties to encode
- // instanceVar = parameter 0, an object array
- // adapterInstanceClass = adapterInstanceClass - see comment above
- // useReadMethods = false (will read fields directly)
- // partialStartVar = null (only support encoding all properties)
- // partialEndVar = null (only support encoding all properties)
- LocalVariable encodedVar = encodingStrategy.buildKeyEncoding
- (b, properties, b.getParameter(0), adapterInstanceClass, false, null, null);
-
- b.loadLocal(encodedVar);
- b.returnValue(byteArrayType);
- } catch (SupportException e) {
- // Shouldn't happen since all properties were checked in order
- // to create this StorableCodec.
- throw new UndeclaredThrowableException(e);
- }
-
- // Define encodeSearchKey(Object[] values, int, int).
- try {
- MethodInfo mi = cf.addMethod
- (Modifiers.PUBLIC, "encodeSearchKey", byteArrayType,
- new TypeDesc[] {objectArrayType, TypeDesc.INT, TypeDesc.INT});
- CodeBuilder b = new CodeBuilder(mi);
-
- // assembler = b
- // properties = properties to encode
- // instanceVar = parameter 0, an object array
- // adapterInstanceClass = adapterInstanceClass - see comment above
- // useReadMethods = false (will read fields directly)
- // partialStartVar = int parameter 1, references start property index
- // partialEndVar = int parameter 2, references end property index
- LocalVariable encodedVar = encodingStrategy.buildKeyEncoding
- (b, properties, b.getParameter(0), adapterInstanceClass,
- false, b.getParameter(1), b.getParameter(2));
-
- b.loadLocal(encodedVar);
- b.returnValue(byteArrayType);
- } catch (SupportException e) {
- // Shouldn't happen since all properties were checked in order
- // to create this StorableCodec.
- throw new UndeclaredThrowableException(e);
- }
-
- // Define encodeSearchKeyPrefix().
- try {
- MethodInfo mi = cf.addMethod
- (Modifiers.PUBLIC, "encodeSearchKeyPrefix", byteArrayType, null);
- CodeBuilder b = new CodeBuilder(mi);
-
- if (encodingStrategy.getKeyPrefixPadding() == 0 &&
- encodingStrategy.getKeySuffixPadding() == 0) {
- // Return null instead of a zero-length array.
- b.loadNull();
- b.returnValue(byteArrayType);
- } else {
- // Build array once and re-use. Trust that no one modifies it.
- cf.addField(Modifiers.PRIVATE.toStatic(true).toFinal(true),
- BLANK_KEY_FIELD_NAME, byteArrayType);
- b.loadStaticField(BLANK_KEY_FIELD_NAME, byteArrayType);
- b.returnValue(byteArrayType);
-
- // Create static initializer to set field.
- mi = cf.addInitializer();
- b = new CodeBuilder(mi);
-
- // assembler = b
- // properties = no parameters - we just want the key prefix
- // instanceVar = null (no parameters means we don't need this)
- // adapterInstanceClass = null (no parameters means we don't need this)
- // useReadMethods = false (no parameters means we don't need this)
- // partialStartVar = null (no parameters means we don't need this)
- // partialEndVar = null (no parameters means we don't need this)
- LocalVariable encodedVar = encodingStrategy.buildKeyEncoding
- (b, new OrderedProperty[0], null, null, false, null, null);
-
- b.loadLocal(encodedVar);
- b.storeStaticField(BLANK_KEY_FIELD_NAME, byteArrayType);
- b.returnVoid();
- }
- } catch (SupportException e) {
- // Shouldn't happen since all properties were checked in order
- // to create this StorableCodec.
- throw new UndeclaredThrowableException(e);
- }
-
- Class<? extends SearchKeyFactory> clazz = ci.defineClass(cf);
- try {
- return clazz.newInstance();
- } catch (InstantiationException e) {
- throw new UndeclaredThrowableException(e);
- } catch (IllegalAccessException e) {
- throw new UndeclaredThrowableException(e);
- }
- }
-
- private Decoder<S> generateDecoder(int generation) throws FetchException {
- // Create an encoding strategy against the reconstructed storable.
- GenericEncodingStrategy<? extends Storable> altStrategy;
- try {
- Class<? extends Storable> altStorable = mLayout.getGeneration(generation)
- .reconstruct(mStorableClass.getClassLoader());
- altStrategy = mFactory.createStrategy(altStorable, null);
- } catch (RepositoryException e) {
- throw new CorruptEncodingException(e);
- }
-
- ClassInjector ci = ClassInjector.create(mType.getName(), mStorableClass.getClassLoader());
- ClassFile cf = new ClassFile(ci.getClassName());
- cf.addInterface(Decoder.class);
- cf.markSynthetic();
- cf.setSourceFile(GenericStorableCodec.class.getName());
- cf.setTarget("1.5");
-
- // Add public no-arg constructor.
- cf.addDefaultConstructor();
-
- // Declare some types.
- final TypeDesc storableType = TypeDesc.forClass(Storable.class);
- final TypeDesc byteArrayType = TypeDesc.forClass(byte[].class);
-
- // Define the required decode method.
- MethodInfo mi = cf.addMethod
- (Modifiers.PUBLIC, "decode", null, new TypeDesc[] {storableType, byteArrayType});
- CodeBuilder b = new CodeBuilder(mi);
-
- LocalVariable uncastDestVar = b.getParameter(0);
- b.loadLocal(uncastDestVar);
- LocalVariable destVar = b.createLocalVariable(null, TypeDesc.forClass(mStorableClass));
- b.checkCast(destVar.getType());
- b.storeLocal(destVar);
- LocalVariable dataVar = b.getParameter(1);
-
- // assembler = b
- // properties = null (defaults to all non-key properties)
- // instanceVar = "dest" storable
- // adapterInstanceClass = null (null means use instanceVar, in this case is "dest")
- // useWriteMethods = false (will set fields directly)
- // generation = generation
- // altGenerationHandler = null (generation should match)
- // encodedVar = "data" byte array
- try {
- altStrategy.buildDataDecoding
- (b, null, destVar, null, false, generation, null, dataVar);
- } catch (SupportException e) {
- throw new CorruptEncodingException(e);
- }
-
- b.returnVoid();
-
- Class<? extends Decoder> clazz = ci.defineClass(cf);
- try {
- return clazz.newInstance();
- } catch (InstantiationException e) {
- throw new UndeclaredThrowableException(e);
- } catch (IllegalAccessException e) {
- throw new UndeclaredThrowableException(e);
- }
- }
-
- /**
- * Creates custom raw search keys for {@link Storable} types. It is
- * intended for supporting queries and indexes.
- */
- public interface SearchKeyFactory<S extends Storable> {
- /**
- * Build a search key by extracting all the desired properties from the
- * given storable.
- *
- * @param storable extract a subset of properties from this instance
- * @return raw search key
- */
- byte[] encodeSearchKey(S storable);
-
- /**
- * Build a search key by extracting all the desired properties from the
- * given storable.
- *
- * @param storable extract a subset of properties from this instance
- * @param rangeStart index of first property to use. Its value must be less
- * than the count of properties used by this factory.
- * @param rangeEnd index of last property to use, exlusive. Its value must
- * be less than or equal to the count of properties used by this factory.
- * @return raw search key
- */
- byte[] encodeSearchKey(S storable, int rangeStart, int rangeEnd);
-
- /**
- * Build a search key by supplying property values without a storable.
- *
- * @param values values to build into a key. It must be long enough to
- * accommodate all of properties used by this factory.
- * @return raw search key
- */
- byte[] encodeSearchKey(Object[] values);
-
- /**
- * Build a search key by supplying property values without a storable.
- *
- * @param values values to build into a key. The length may be less than
- * the amount of properties used by this factory. It must not be less than the
- * difference between rangeStart and rangeEnd.
- * @param rangeStart index of first property to use. Its value must be less
- * than the count of properties used by this factory.
- * @param rangeEnd index of last property to use, exlusive. Its value must
- * be less than or equal to the count of properties used by this factory.
- * @return raw search key
- */
- byte[] encodeSearchKey(Object[] values, int rangeStart, int rangeEnd);
-
- /**
- * Returns the search key for when there are no values. Returned value
- * may be null.
- */
- byte[] encodeSearchKeyPrefix();
- }
-
- /**
- * Used for decoding different generations of Storable.
- */
- public interface Decoder<S extends Storable> {
- /**
- * @param dest storable to receive decoded properties
- * @param data decoded into properties, some of which may be dropped if
- * destination storable doesn't have it
- */
- void decode(S dest, byte[] data);
- }
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/GenericStorableCodecFactory.java b/src/main/java/com/amazon/carbonado/spi/raw/GenericStorableCodecFactory.java deleted file mode 100644 index fefa880..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/GenericStorableCodecFactory.java +++ /dev/null @@ -1,76 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-import com.amazon.carbonado.Storable;
-import com.amazon.carbonado.SupportException;
-
-import com.amazon.carbonado.info.StorableIndex;
-import com.amazon.carbonado.layout.Layout;
-
-/**
- * Factory for generic codec that supports any kind of storable by
- * auto-generating and caching storable implementations.
- *
- * @author Brian S O'Neill
- */
-public class GenericStorableCodecFactory implements StorableCodecFactory {
- public GenericStorableCodecFactory() {
- }
-
- /**
- * Returns null to let repository decide what the name should be.
- */
- public String getStorageName(Class<? extends Storable> type) throws SupportException {
- return null;
- }
-
- /**
- * @param type type of storable to create codec for
- * @param pkIndex suggested index for primary key (optional)
- * @param isMaster when true, version properties and sequences are managed
- * @param layout when non-null, encode a storable layout generation
- * value in one or four bytes. Generation 0..127 is encoded in one byte, and
- * 128..max is encoded in four bytes, with the most significant bit set.
- * @throws SupportException if type is not supported
- */
- @SuppressWarnings("unchecked")
- public <S extends Storable> GenericStorableCodec<S> createCodec(Class<S> type,
- StorableIndex pkIndex,
- boolean isMaster,
- Layout layout)
- throws SupportException
- {
- return GenericStorableCodec.getInstance
- (this, createStrategy(type, pkIndex), isMaster, layout);
- }
-
- /**
- * Override to return a different EncodingStrategy.
- *
- * @param type type of Storable to generate code for
- * @param pkIndex specifies sequence and ordering of key properties (optional)
- */
- protected <S extends Storable> GenericEncodingStrategy<S> createStrategy
- (Class<S> type, StorableIndex<S> pkIndex)
- throws SupportException
- {
- return new GenericEncodingStrategy<S>(type, pkIndex);
- }
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/KeyDecoder.java b/src/main/java/com/amazon/carbonado/spi/raw/KeyDecoder.java deleted file mode 100644 index 127216f..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/KeyDecoder.java +++ /dev/null @@ -1,646 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-import com.amazon.carbonado.CorruptEncodingException;
-
-import static com.amazon.carbonado.spi.raw.KeyEncoder.*;
-
-/**
- * A very low-level class that decodes key components encoded by methods of
- * {@link KeyEncoder}.
- *
- * @author Brian S O'Neill
- */
-public class KeyDecoder extends DataDecoder {
-
- /**
- * Decodes a signed integer from exactly 4 bytes, as encoded for descending
- * order.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return signed integer value
- */
- public static int decodeIntDesc(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- return ~decodeInt(src, srcOffset);
- }
-
- /**
- * Decodes a signed Integer object from exactly 1 or 5 bytes, as encoded
- * for descending order. If null is returned, then 1 byte was read.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return signed Integer object or null
- */
- public static Integer decodeIntegerObjDesc(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- int b = src[srcOffset];
- if (b == NULL_BYTE_HIGH || b == NULL_BYTE_LOW) {
- return null;
- }
- return decodeIntDesc(src, srcOffset + 1);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a signed long from exactly 8 bytes, as encoded for descending
- * order.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return signed long value
- */
- public static long decodeLongDesc(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- return ~decodeLong(src, srcOffset);
- }
-
- /**
- * Decodes a signed Long object from exactly 1 or 9 bytes, as encoded for
- * descending order. If null is returned, then 1 byte was read.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return signed Long object or null
- */
- public static Long decodeLongObjDesc(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- int b = src[srcOffset];
- if (b == NULL_BYTE_HIGH || b == NULL_BYTE_LOW) {
- return null;
- }
- return decodeLongDesc(src, srcOffset + 1);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a signed byte from exactly 1 byte, as encoded for descending
- * order.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return signed byte value
- */
- public static byte decodeByteDesc(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- return (byte)(src[srcOffset] ^ 0x7f);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a signed Byte object from exactly 1 or 2 bytes, as encoded for
- * descending order. If null is returned, then 1 byte was read.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return signed Byte object or null
- */
- public static Byte decodeByteObjDesc(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- int b = src[srcOffset];
- if (b == NULL_BYTE_HIGH || b == NULL_BYTE_LOW) {
- return null;
- }
- return decodeByteDesc(src, srcOffset + 1);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a signed short from exactly 2 bytes, as encoded for descending
- * order.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return signed short value
- */
- public static short decodeShortDesc(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- return (short)(((src[srcOffset] << 8) | (src[srcOffset + 1] & 0xff)) ^ 0x7fff);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a signed Short object from exactly 1 or 3 bytes, as encoded for
- * descending order. If null is returned, then 1 byte was read.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return signed Short object or null
- */
- public static Short decodeShortObjDesc(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- int b = src[srcOffset];
- if (b == NULL_BYTE_HIGH || b == NULL_BYTE_LOW) {
- return null;
- }
- return decodeShortDesc(src, srcOffset + 1);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a char from exactly 2 bytes, as encoded for descending order.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return char value
- */
- public static char decodeCharDesc(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- return (char)~((src[srcOffset] << 8) | (src[srcOffset + 1] & 0xff));
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a Character object from exactly 1 or 3 bytes, as encoded for
- * descending order. If null is returned, then 1 byte was read.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return Character object or null
- */
- public static Character decodeCharacterObjDesc(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- int b = src[srcOffset];
- if (b == NULL_BYTE_HIGH || b == NULL_BYTE_LOW) {
- return null;
- }
- return decodeCharDesc(src, srcOffset + 1);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a boolean from exactly 1 byte, as encoded for descending order.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return boolean value
- */
- public static boolean decodeBooleanDesc(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- return src[srcOffset] == 127;
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a Boolean object from exactly 1 byte, as encoded for descending
- * order.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return Boolean object or null
- */
- public static Boolean decodeBooleanObjDesc(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- try {
- switch (src[srcOffset]) {
- case NULL_BYTE_LOW: case NULL_BYTE_HIGH:
- return null;
- case (byte)127:
- return Boolean.TRUE;
- default:
- return Boolean.FALSE;
- }
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes a float from exactly 4 bytes, as encoded for descending order.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return float value
- */
- public static float decodeFloatDesc(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- int bits = decodeFloatBits(src, srcOffset);
- if (bits >= 0) {
- bits ^= 0x7fffffff;
- }
- return Float.intBitsToFloat(bits);
- }
-
- /**
- * Decodes a Float object from exactly 4 bytes.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return Float object or null
- */
- public static Float decodeFloatObjDesc(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- int bits = decodeFloatBits(src, srcOffset);
- if (bits >= 0) {
- bits ^= 0x7fffffff;
- }
- return bits == 0x7fffffff ? null : Float.intBitsToFloat(bits);
- }
-
- /**
- * Decodes a double from exactly 8 bytes, as encoded for descending order.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return double value
- */
- public static double decodeDoubleDesc(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- long bits = decodeDoubleBits(src, srcOffset);
- if (bits >= 0) {
- bits ^= 0x7fffffffffffffffL;
- }
- return Double.longBitsToDouble(bits);
- }
-
- /**
- * Decodes a Double object from exactly 8 bytes.
- *
- * @param src source of encoded bytes
- * @param srcOffset offset into source array
- * @return Double object or null
- */
- public static Double decodeDoubleObjDesc(byte[] src, int srcOffset)
- throws CorruptEncodingException
- {
- long bits = decodeDoubleBits(src, srcOffset);
- if (bits >= 0) {
- bits ^= 0x7fffffffffffffffL;
- }
- return bits == 0x7fffffffffffffffL ? null : Double.longBitsToDouble(bits);
- }
-
- /**
- * Decodes the given byte array as originally encoded for ascending order.
- * The decoding stops when any kind of terminator or illegal byte has been
- * read. The decoded bytes are stored in valueRef.
- *
- * @param src source of encoded data
- * @param srcOffset offset into encoded data
- * @param valueRef decoded byte array is stored in element 0, which may be null
- * @return amount of bytes read from source
- * @throws CorruptEncodingException if source data is corrupt
- */
- public static int decode(byte[] src, int srcOffset, byte[][] valueRef)
- throws CorruptEncodingException
- {
- try {
- return decode(src, srcOffset, valueRef, 0);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes the given byte array as originally encoded for descending order.
- * The decoding stops when any kind of terminator or illegal byte has been
- * read. The decoded bytes are stored in valueRef.
- *
- * @param src source of encoded data
- * @param srcOffset offset into encoded data
- * @param valueRef decoded byte array is stored in element 0, which may be null
- * @return amount of bytes read from source
- * @throws CorruptEncodingException if source data is corrupt
- */
- public static int decodeDesc(byte[] src, int srcOffset, byte[][] valueRef)
- throws CorruptEncodingException
- {
- try {
- return decode(src, srcOffset, valueRef, -1);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * @param xorMask 0 for normal decoding, -1 for descending decoding
- */
- private static int decode(byte[] src, int srcOffset, byte[][] valueRef, int xorMask) {
- // Scan ahead, looking for terminator.
- int srcEnd = srcOffset;
- while (true) {
- byte b = src[srcEnd++];
- if (-32 <= b && b < 32) {
- if (b == NULL_BYTE_HIGH || b == NULL_BYTE_LOW) {
- if ((srcEnd - 1) <= srcOffset) {
- valueRef[0] = null;
- return 1;
- }
- }
- break;
- }
- }
-
- if (srcEnd - srcOffset == 1) {
- valueRef[0] = EMPTY_BYTE_ARRAY;
- return 1;
- }
-
- // Value is decoded from base-32768.
-
- int valueLength = ((srcEnd - srcOffset - 1) * 120) >> 7;
- byte[] value = new byte[valueLength];
- int valueOffset = 0;
-
- final int originalOffset = srcOffset;
-
- int accumBits = 0;
- int accum = 0;
-
- while (true) {
- int d = (src[srcOffset++] ^ xorMask) & 0xff;
- int b;
- if (srcOffset == srcEnd ||
- (b = (src[srcOffset++] ^ xorMask) & 0xff) < 32 || b > 223) {
- // Handle special case where one byte was emitted for digit.
- d -= 32;
- // To produce digit, multiply d by 192 and add 191 to adjust
- // for missing remainder. The lower bits are discarded anyhow.
- d = (d << 7) + (d << 6) + 191;
-
- // Shift decoded digit into accumulator.
- accumBits += 15;
- accum = (accum << 15) | d;
-
- break;
- }
-
- d -= 32;
- // To produce digit, multiply d by 192 and add in remainder.
- d = ((d << 7) + (d << 6)) + b - 32;
-
- // Shift decoded digit into accumulator.
- accumBits += 15;
- accum = (accum << 15) | d;
-
- if (accumBits == 15) {
- value[valueOffset++] = (byte)(accum >> 7);
- } else {
- value[valueOffset++] = (byte)(accum >> (accumBits - 8));
- accumBits -= 8;
- value[valueOffset++] = (byte)(accum >> (accumBits - 8));
- }
- accumBits -= 8;
- }
-
- if (accumBits >= 8 && valueOffset < valueLength) {
- value[valueOffset] = (byte)(accum >> (accumBits - 8));
- }
-
- valueRef[0] = value;
-
- return srcOffset - originalOffset;
- }
-
- /**
- * Decodes an encoded string from the given byte array.
- *
- * @param src source of encoded data
- * @param srcOffset offset into encoded data
- * @param valueRef decoded string is stored in element 0, which may be null
- * @return amount of bytes read from source
- * @throws CorruptEncodingException if source data is corrupt
- */
- public static int decodeString(byte[] src, int srcOffset, String[] valueRef)
- throws CorruptEncodingException
- {
- try {
- return decodeString(src, srcOffset, valueRef, 0);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes an encoded string from the given byte array as originally
- * encoded for descending order.
- *
- * @param src source of encoded data
- * @param srcOffset offset into encoded data
- * @param valueRef decoded string is stored in element 0, which may be null
- * @return amount of bytes read from source
- * @throws CorruptEncodingException if source data is corrupt
- */
- public static int decodeStringDesc(byte[] src, int srcOffset, String[] valueRef)
- throws CorruptEncodingException
- {
- try {
- return decodeString(src, srcOffset, valueRef, -1);
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * @param xorMask 0 for normal decoding, -1 for descending decoding
- */
- private static int decodeString(byte[] src, int srcOffset, String[] valueRef, int xorMask)
- throws CorruptEncodingException
- {
- // Scan ahead, looking for terminator.
- int srcEnd = srcOffset;
- while (true) {
- byte b = src[srcEnd++];
- if (-2 <= b && b < 2) {
- if (b == NULL_BYTE_HIGH || b == NULL_BYTE_LOW) {
- if ((srcEnd - 1) <= srcOffset) {
- valueRef[0] = null;
- return 1;
- }
- }
- break;
- }
- }
-
- if (srcEnd - srcOffset == 1) {
- valueRef[0] = "";
- return 1;
- }
-
- // Allocate a character array which may be longer than needed once
- // bytes are decoded into characters.
- char[] value = new char[srcEnd - srcOffset];
- int valueOffset = 0;
-
- final int originalOffset = srcOffset;
-
- while (srcOffset < srcEnd) {
- int c = (src[srcOffset++] ^ xorMask) & 0xff;
- switch (c >> 5) {
- case 0: case 1: case 2: case 3:
- // 0xxxxxxx
- value[valueOffset++] = (char)(c - 2);
- break;
- case 4: case 5:
- // 10xxxxxx xxxxxxxx
-
- c = c & 0x3f;
- // Multiply by 192, add in remainder, remove offset of 2, and de-normalize.
- value[valueOffset++] =
- (char)((c << 7) + (c << 6) + ((src[srcOffset++] ^ xorMask) & 0xff) + 94);
-
- break;
- case 6:
- // 110xxxxx xxxxxxxx xxxxxxxx
-
- c = c & 0x1f;
- // Multiply by 192, add in remainder...
- c = (c << 7) + (c << 6) + ((src[srcOffset++] ^ xorMask) & 0xff) - 32;
- // ...multiply by 192, add in remainder, remove offset of 2, and de-normalize.
- c = (c << 7) + (c << 6) + ((src[srcOffset++] ^ xorMask) & 0xff) + 12382;
-
- if (c >= 0x10000) {
- // Split into surrogate pair.
- c -= 0x10000;
- value[valueOffset++] = (char)(0xd800 | ((c >> 10) & 0x3ff));
- value[valueOffset++] = (char)(0xdc00 | (c & 0x3ff));
- } else {
- value[valueOffset++] = (char)c;
- }
-
- break;
- default:
- // 111xxxxx
- // Illegal.
- throw new CorruptEncodingException
- ("Corrupt encoded string data (source offset = "
- + (srcOffset - 1) + ')');
- }
- }
-
- valueRef[0] = new String(value, 0, valueOffset - 1);
-
- return srcEnd - originalOffset;
- }
-
- /**
- * Decodes the given byte array which was encoded by {@link
- * KeyEncoder#encodeSingleDesc}.
- */
- public static byte[] decodeSingleDesc(byte[] src) throws CorruptEncodingException {
- return decodeSingleDesc(src, 0, 0);
- }
-
- /**
- * Decodes the given byte array which was encoded by {@link
- * KeyEncoder#encodeSingleDesc}.
- *
- * @param prefixPadding amount of extra bytes to skip from start of encoded byte array
- * @param suffixPadding amount of extra bytes to skip at end of encoded byte array
- */
- public static byte[] decodeSingleDesc(byte[] src, int prefixPadding, int suffixPadding)
- throws CorruptEncodingException
- {
- try {
- int length = src.length - suffixPadding - prefixPadding;
- if (length == 0) {
- return EMPTY_BYTE_ARRAY;
- }
- byte[] dst = new byte[length];
- while (--length >= 0) {
- dst[length] = (byte) (~src[prefixPadding + length]);
- }
- return dst;
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-
- /**
- * Decodes the given byte array which was encoded by {@link
- * KeyEncoder#encodeSingleNullableDesc}.
- */
- public static byte[] decodeSingleNullableDesc(byte[] src) throws CorruptEncodingException {
- return decodeSingleNullableDesc(src, 0, 0);
- }
-
- /**
- * Decodes the given byte array which was encoded by {@link
- * KeyEncoder#encodeSingleNullableDesc}.
- *
- * @param prefixPadding amount of extra bytes to skip from start of encoded byte array
- * @param suffixPadding amount of extra bytes to skip at end of encoded byte array
- */
- public static byte[] decodeSingleNullableDesc(byte[] src, int prefixPadding, int suffixPadding)
- throws CorruptEncodingException
- {
- try {
- byte b = src[prefixPadding];
- if (b == NULL_BYTE_HIGH || b == NULL_BYTE_LOW) {
- return null;
- }
- int length = src.length - suffixPadding - 1 - prefixPadding;
- if (length == 0) {
- return EMPTY_BYTE_ARRAY;
- }
- byte[] dst = new byte[length];
- while (--length >= 0) {
- dst[length] = (byte) (~src[1 + prefixPadding + length]);
- }
- return dst;
- } catch (IndexOutOfBoundsException e) {
- throw new CorruptEncodingException(null, e);
- }
- }
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/KeyEncoder.java b/src/main/java/com/amazon/carbonado/spi/raw/KeyEncoder.java deleted file mode 100644 index dd0faf9..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/KeyEncoder.java +++ /dev/null @@ -1,741 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-/**
- * A very low-level class that supports encoding of primitive data into unique,
- * sortable byte array keys. If the data to encode is of a variable size, then
- * it is written in base-32768, using only byte values 32..223. This allows
- * special values such as nulls and terminators to be unambiguously
- * encoded. Terminators for variable data can be encoded using 1 for ascending
- * order and 254 for descending order. Nulls can be encoded as 255 for high
- * ordering and 0 for low ordering.
- *
- * @author Brian S O'Neill
- * @see KeyDecoder
- */
-public class KeyEncoder extends DataEncoder {
-
- /** Byte to terminate variable data encoded for ascending order */
- static final byte TERMINATOR = (byte)1;
-
- /**
- * Encodes the given signed integer into exactly 4 bytes for descending
- * order.
- *
- * @param value signed integer value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encodeDesc(int value, byte[] dst, int dstOffset) {
- encode(~value, dst, dstOffset);
- }
-
- /**
- * Encodes the given signed Integer object into exactly 1 or 5 bytes for
- * descending order. If the Integer object is never expected to be null,
- * consider encoding as an int primitive.
- *
- * @param value optional signed Integer value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encodeDesc(Integer value, byte[] dst, int dstOffset) {
- if (value == null) {
- dst[dstOffset] = NULL_BYTE_LOW;
- return 1;
- } else {
- dst[dstOffset] = NOT_NULL_BYTE_LOW;
- encode(~value.intValue(), dst, dstOffset + 1);
- return 5;
- }
- }
-
- /**
- * Encodes the given signed long into exactly 8 bytes for descending order.
- *
- * @param value signed long value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encodeDesc(long value, byte[] dst, int dstOffset) {
- encode(~value, dst, dstOffset);
- }
-
- /**
- * Encodes the given signed Long object into exactly 1 or 9 bytes for
- * descending order. If the Long object is never expected to be null,
- * consider encoding as a long primitive.
- *
- * @param value optional signed Long value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encodeDesc(Long value, byte[] dst, int dstOffset) {
- if (value == null) {
- dst[dstOffset] = NULL_BYTE_LOW;
- return 1;
- } else {
- dst[dstOffset] = NOT_NULL_BYTE_LOW;
- encode(~value.longValue(), dst, dstOffset + 1);
- return 9;
- }
- }
-
- /**
- * Encodes the given signed byte into exactly 1 byte for descending order.
- *
- * @param value signed byte value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encodeDesc(byte value, byte[] dst, int dstOffset) {
- dst[dstOffset] = (byte)(value ^ 0x7f);
- }
-
- /**
- * Encodes the given signed Byte object into exactly 1 or 2 bytes for
- * descending order. If the Byte object is never expected to be null,
- * consider encoding as a byte primitive.
- *
- * @param value optional signed Byte value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encodeDesc(Byte value, byte[] dst, int dstOffset) {
- if (value == null) {
- dst[dstOffset] = NULL_BYTE_LOW;
- return 1;
- } else {
- dst[dstOffset] = NOT_NULL_BYTE_LOW;
- dst[dstOffset + 1] = (byte)(value ^ 0x7f);
- return 2;
- }
- }
-
- /**
- * Encodes the given signed short into exactly 2 bytes for descending
- * order.
- *
- * @param value signed short value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encodeDesc(short value, byte[] dst, int dstOffset) {
- encode((short) ~value, dst, dstOffset);
- }
-
- /**
- * Encodes the given signed Short object into exactly 1 or 3 bytes for
- * descending order. If the Short object is never expected to be null,
- * consider encoding as a short primitive.
- *
- * @param value optional signed Short value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encodeDesc(Short value, byte[] dst, int dstOffset) {
- if (value == null) {
- dst[dstOffset] = NULL_BYTE_LOW;
- return 1;
- } else {
- dst[dstOffset] = NOT_NULL_BYTE_LOW;
- encode((short) ~value.shortValue(), dst, dstOffset + 1);
- return 3;
- }
- }
-
- /**
- * Encodes the given character into exactly 2 bytes for descending order.
- *
- * @param value character value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encodeDesc(char value, byte[] dst, int dstOffset) {
- encode((char) ~value, dst, dstOffset);
- }
-
- /**
- * Encodes the given Character object into exactly 1 or 3 bytes for
- * descending order. If the Character object is never expected to be null,
- * consider encoding as a char primitive.
- *
- * @param value optional Character value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encodeDesc(Character value, byte[] dst, int dstOffset) {
- if (value == null) {
- dst[dstOffset] = NULL_BYTE_LOW;
- return 1;
- } else {
- dst[dstOffset] = NOT_NULL_BYTE_LOW;
- encode((char) ~value.charValue(), dst, dstOffset + 1);
- return 3;
- }
- }
-
- /**
- * Encodes the given boolean into exactly 1 byte for descending order.
- *
- * @param value boolean value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encodeDesc(boolean value, byte[] dst, int dstOffset) {
- dst[dstOffset] = value ? (byte)127 : (byte)128;
- }
-
- /**
- * Encodes the given Boolean object into exactly 1 byte for descending
- * order.
- *
- * @param value optional Boolean value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encodeDesc(Boolean value, byte[] dst, int dstOffset) {
- if (value == null) {
- dst[dstOffset] = NULL_BYTE_LOW;
- } else {
- dst[dstOffset] = value.booleanValue() ? (byte)127 : (byte)128;
- }
- }
-
- /**
- * Encodes the given float into exactly 4 bytes for descending order.
- *
- * @param value float value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encodeDesc(float value, byte[] dst, int dstOffset) {
- int bits = Float.floatToIntBits(value);
- if (bits >= 0) {
- bits ^= 0x7fffffff;
- }
- dst[dstOffset ] = (byte)(bits >> 24);
- dst[dstOffset + 1] = (byte)(bits >> 16);
- dst[dstOffset + 2] = (byte)(bits >> 8);
- dst[dstOffset + 3] = (byte)bits;
- }
-
- /**
- * Encodes the given Float object into exactly 4 bytes for descending
- * order. A non-canonical NaN value is used to represent null.
- *
- * @param value optional Float value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encodeDesc(Float value, byte[] dst, int dstOffset) {
- if (value == null) {
- encode(~0x7fffffff, dst, dstOffset);
- } else {
- encodeDesc(value.floatValue(), dst, dstOffset);
- }
- }
-
- /**
- * Encodes the given double into exactly 8 bytes for descending order.
- *
- * @param value double value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encodeDesc(double value, byte[] dst, int dstOffset) {
- long bits = Double.doubleToLongBits(value);
- if (bits >= 0) {
- bits ^= 0x7fffffffffffffffL;
- }
- int w = (int)(bits >> 32);
- dst[dstOffset ] = (byte)(w >> 24);
- dst[dstOffset + 1] = (byte)(w >> 16);
- dst[dstOffset + 2] = (byte)(w >> 8);
- dst[dstOffset + 3] = (byte)w;
- w = (int)bits;
- dst[dstOffset + 4] = (byte)(w >> 24);
- dst[dstOffset + 5] = (byte)(w >> 16);
- dst[dstOffset + 6] = (byte)(w >> 8);
- dst[dstOffset + 7] = (byte)w;
- }
-
- /**
- * Encodes the given Double object into exactly 8 bytes for descending
- * order. A non-canonical NaN value is used to represent null.
- *
- * @param value optional Double value to encode
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- */
- public static void encodeDesc(Double value, byte[] dst, int dstOffset) {
- if (value == null) {
- encode(~0x7fffffffffffffffL, dst, dstOffset);
- } else {
- encodeDesc(value.doubleValue(), dst, dstOffset);
- }
- }
-
- /**
- * Encodes the given optional unsigned byte array into a variable amount of
- * bytes. If the byte array is null, exactly 1 byte is written. Otherwise,
- * the amount written can be determined by calling calculateEncodedLength.
- *
- * @param value byte array value to encode, may be null
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encode(byte[] value, byte[] dst, int dstOffset) {
- if (value == null) {
- dst[dstOffset] = NULL_BYTE_HIGH;
- return 1;
- }
- return encode(value, 0, value.length, dst, dstOffset, 0);
- }
-
- /**
- * Encodes the given optional unsigned byte array into a variable amount of
- * bytes. If the byte array is null, exactly 1 byte is written. Otherwise,
- * the amount written can be determined by calling calculateEncodedLength.
- *
- * @param value byte array value to encode, may be null
- * @param valueOffset offset into byte array
- * @param valueLength length of data in byte array
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encode(byte[] value, int valueOffset, int valueLength,
- byte[] dst, int dstOffset) {
- return encode(value, valueOffset, valueLength, dst, dstOffset, 0);
- }
-
- /**
- * Encodes the given optional unsigned byte array into a variable amount of
- * bytes for descending order. If the byte array is null, exactly 1 byte is
- * written. Otherwise, the amount written is determined by calling
- * calculateEncodedLength.
- *
- * @param value byte array value to encode, may be null
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encodeDesc(byte[] value, byte[] dst, int dstOffset) {
- if (value == null) {
- dst[dstOffset] = NULL_BYTE_LOW;
- return 1;
- }
- return encode(value, 0, value.length, dst, dstOffset, -1);
- }
-
- /**
- * Encodes the given optional unsigned byte array into a variable amount of
- * bytes for descending order. If the byte array is null, exactly 1 byte is
- * written. Otherwise, the amount written is determined by calling
- * calculateEncodedLength.
- *
- * @param value byte array value to encode, may be null
- * @param valueOffset offset into byte array
- * @param valueLength length of data in byte array
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encodeDesc(byte[] value, int valueOffset, int valueLength,
- byte[] dst, int dstOffset) {
- return encode(value, valueOffset, valueLength, dst, dstOffset, -1);
- }
-
- /**
- * @param xorMask 0 for normal encoding, -1 for descending encoding
- */
- private static int encode(byte[] value, int valueOffset, int valueLength,
- byte[] dst, int dstOffset, int xorMask) {
- if (value == null) {
- dst[dstOffset] = (byte)(NULL_BYTE_HIGH ^ xorMask);
- return 1;
- }
-
- final int originalOffset = dstOffset;
-
- // Value is encoded in base-32768.
-
- int accumBits = 0;
- int accum = 0;
-
- final int end = valueOffset + valueLength;
- for (int i=valueOffset; i<end; i++) {
- if (accumBits <= 7) {
- accumBits += 8;
- accum = (accum << 8) | (value[i] & 0xff);
- if (accumBits == 15) {
- emitDigit(accum, dst, dstOffset, xorMask);
- dstOffset += 2;
- accum = 0;
- accumBits = 0;
- }
- } else {
- int supply = 15 - accumBits;
- accum = (accum << supply) | ((value[i] & 0xff) >> (8 - supply));
- emitDigit(accum, dst, dstOffset, xorMask);
- dstOffset += 2;
- accumBits = 8 - supply;
- accum = value[i] & ((1 << accumBits) - 1);
- }
- }
-
- if (accumBits > 0) {
- // Pad with zeros.
- accum <<= (15 - accumBits);
- if (accumBits <= 7) {
- // Since amount of significant bits is small, emit only the
- // upper half of the digit. The following code is modified from
- // emitDigit.
-
- int a = (accum * 21845) >> 22;
- if (accum - ((a << 7) + (a << 6)) == 192) {
- a++;
- }
- dst[dstOffset++] = (byte)((a + 32) ^ xorMask);
- } else {
- emitDigit(accum, dst, dstOffset, xorMask);
- dstOffset += 2;
- }
- }
-
- // Append terminator.
- dst[dstOffset++] = (byte)(TERMINATOR ^ xorMask);
-
- return dstOffset - originalOffset;
- }
-
- /**
- * Emits a base-32768 digit using exactly two bytes. The first byte is in the range
- * 32..202 and the second byte is in the range 32..223.
- *
- * @param value digit value in the range 0..32767
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @param xorMask 0 for normal encoding, -1 for descending encoding
- */
- private static void emitDigit(int value, byte[] dst, int dstOffset, int xorMask) {
- // The first byte is computed as ((value / 192) + 32) and the second
- // byte is computed as ((value % 192) + 32). To speed things up a bit,
- // the integer division and remainder operations are replaced with a
- // scaled multiplication.
-
- // approximate value / 192
- int a = (value * 21845) >> 22;
-
- // approximate value % 192
- // Note: the value 192 was chosen as a divisor because a multiply by
- // 192 can be replaced with two summed shifts.
- int b = value - ((a << 7) + (a << 6));
- if (b == 192) {
- // Fix error.
- a++;
- b = 0;
- }
-
- dst[dstOffset++] = (byte)((a + 32) ^ xorMask);
- dst[dstOffset] = (byte)((b + 32) ^ xorMask);
- }
-
- /**
- * Returns the amount of bytes required to encode a byte array of the given
- * length.
- *
- * @param value byte array value to encode, may be null
- * @return amount of bytes needed to encode
- */
- public static int calculateEncodedLength(byte[] value) {
- return value == null ? 1 : calculateEncodedLength(value, 0, value.length);
- }
-
- /**
- * Returns the amount of bytes required to encode the given byte array.
- *
- * @param value byte array value to encode, may be null
- * @param valueOffset offset into byte array
- * @param valueLength length of data in byte array
- * @return amount of bytes needed to encode
- */
- public static int calculateEncodedLength(byte[] value, int valueOffset, int valueLength) {
- // The add of 119 is used to force ceiling rounding.
- return value == null ? 1 : (((valueLength << 7) + 119) / 120 + 1);
- }
-
- /**
- * Encodes the given optional String into a variable amount of bytes. The
- * amount written can be determined by calling
- * calculateEncodedStringLength.
- * <p>
- * Strings are encoded in a fashion similar to UTF-8, in that ASCII
- * characters are usually written in one byte. This encoding is more
- * efficient than UTF-8, but it isn't compatible with UTF-8.
- *
- * @param value String value to encode, may be null
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encode(String value, byte[] dst, int dstOffset) {
- return encode(value, dst, dstOffset, 0);
- }
-
- /**
- * Encodes the given optional String into a variable amount of bytes for
- * descending order. The amount written can be determined by calling
- * calculateEncodedStringLength.
- * <p>
- * Strings are encoded in a fashion similar to UTF-8, in that ASCII
- * characters are usually written in one byte. This encoding is more
- * efficient than UTF-8, but it isn't compatible with UTF-8.
- *
- * @param value String value to encode, may be null
- * @param dst destination for encoded bytes
- * @param dstOffset offset into destination array
- * @return amount of bytes written
- */
- public static int encodeDesc(String value, byte[] dst, int dstOffset) {
- return encode(value, dst, dstOffset, -1);
- }
-
- /**
- * @param xorMask 0 for normal encoding, -1 for descending encoding
- */
- private static int encode(String value, byte[] dst, int dstOffset, int xorMask) {
- if (value == null) {
- dst[dstOffset] = (byte)(NULL_BYTE_HIGH ^ xorMask);
- return 1;
- }
-
- final int originalOffset = dstOffset;
-
- // All characters have an offset of 2 added, in order to reserve bytes
- // 0 and 1 for encoding nulls and terminators. This means the ASCII
- // string "HelloWorld" is actually encoded as "JgnnqYqtnf". This also
- // means that the ASCII '~' and del characters are encoded in two bytes.
-
- int length = value.length();
- for (int i = 0; i < length; i++) {
- int c = value.charAt(i) + 2;
- if (c <= 0x7f) {
- // 0xxxxxxx
- dst[dstOffset++] = (byte)(c ^ xorMask);
- } else if (c <= 12415) {
- // 10xxxxxx xxxxxxxx
-
- // Second byte cannot have the values 0, 1, 254, or 255 because
- // they clash with null and terminator bytes. Divide by 192 and
- // store in first 6 bits. The remainder, with 32 added, goes
- // into the second byte. Note that (192 * 63 + 191) + 128 == 12415.
- // 63 is the maximum value that can be represented in 6 bits.
-
- c -= 128; // c will always be at least 128, so normalize.
-
- // approximate value / 192
- int a = (c * 21845) >> 22;
-
- // approximate value % 192
- // Note: the value 192 was chosen as a divisor because a multiply by
- // 192 can be replaced with two summed shifts.
- c = c - ((a << 7) + (a << 6));
- if (c == 192) {
- // Fix error.
- a++;
- c = 0;
- }
-
- dst[dstOffset++] = (byte)((0x80 | a) ^ xorMask);
- dst[dstOffset++] = (byte)((c + 32) ^ xorMask);
- } else {
- // 110xxxxx xxxxxxxx xxxxxxxx
-
- if ((c - 2) >= 0xd800 && (c - 2) <= 0xdbff) {
- // Found a high surrogate. Verify that surrogate pair is
- // well-formed. Low surrogate must follow high surrogate.
- if (i + 1 < length) {
- int c2 = value.charAt(i + 1);
- if (c2 >= 0xdc00 && c2 <= 0xdfff) {
- c = ((((c - 2) & 0x3ff) << 10) | (c2 & 0x3ff)) + 0x10002;
- i++;
- }
- }
- }
-
- // Second and third bytes cannot have the values 0, 1, 254, or
- // 255 because they clash with null and terminator
- // bytes. Divide by 192 twice, storing the first and second
- // remainders in the third and second bytes, respectively.
- // Note that largest unicode value supported is 2^20 + 65535 ==
- // 1114111. When divided by 192 twice, the value is 30, which
- // just barely fits in the 5 available bits of the first byte.
-
- c -= 12416; // c will always be at least 12416, so normalize.
-
- int a = (int)((c * 21845L) >> 22);
- c = c - ((a << 7) + (a << 6));
- if (c == 192) {
- a++;
- c = 0;
- }
-
- dst[dstOffset + 2] = (byte)((c + 32) ^ xorMask);
-
- c = (a * 21845) >> 22;
- a = a - ((c << 7) + (c << 6));
- if (a == 192) {
- c++;
- a = 0;
- }
-
- dst[dstOffset++] = (byte)((0xc0 | c) ^ xorMask);
- dst[dstOffset++] = (byte)((a + 32) ^ xorMask);
- dstOffset++;
- }
- }
-
- // Append terminator.
- dst[dstOffset++] = (byte)(TERMINATOR ^ xorMask);
-
- return dstOffset - originalOffset;
- }
-
- /**
- * Returns the amount of bytes required to encode the given String.
- *
- * @param value String to encode, may be null
- */
- public static int calculateEncodedStringLength(String value) {
- int encodedLen = 1;
- if (value != null) {
- int valueLength = value.length();
- for (int i = 0; i < valueLength; i++) {
- int c = value.charAt(i);
- if (c <= (0x7f - 2)) {
- encodedLen++;
- } else if (c <= (12415 - 2)) {
- encodedLen += 2;
- } else {
- if (c >= 0xd800 && c <= 0xdbff) {
- // Found a high surrogate. Verify that surrogate pair is
- // well-formed. Low surrogate must follow high surrogate.
- if (i + 1 < valueLength) {
- int c2 = value.charAt(i + 1);
- if (c2 >= 0xdc00 && c2 <= 0xdfff) {
- i++;
- }
- }
- }
- encodedLen += 3;
- }
- }
- }
- return encodedLen;
- }
-
- /**
- * Encodes the given byte array for use when there is only a single
- * required property, descending order, whose type is a byte array. The
- * original byte array is returned if the length is zero.
- */
- public static byte[] encodeSingleDesc(byte[] value) {
- return encodeSingleDesc(value, 0, 0);
- }
-
- /**
- * Encodes the given byte array for use when there is only a single
- * required property, descending order, whose type is a byte array. The
- * original byte array is returned if the length and padding lengths are
- * zero.
- *
- * @param prefixPadding amount of extra bytes to allocate at start of encoded byte array
- * @param suffixPadding amount of extra bytes to allocate at end of encoded byte array
- */
- public static byte[] encodeSingleDesc(byte[] value, int prefixPadding, int suffixPadding) {
- int length = value.length;
- if (prefixPadding <= 0 && suffixPadding <= 0 && length == 0) {
- return value;
- }
- byte[] dst = new byte[prefixPadding + length + suffixPadding];
- while (--length >= 0) {
- dst[prefixPadding + length] = (byte) (~value[length]);
- }
- return dst;
- }
-
- /**
- * Encodes the given byte array for use when there is only a single
- * nullable property, descending order, whose type is a byte array.
- */
- public static byte[] encodeSingleNullableDesc(byte[] value) {
- return encodeSingleNullableDesc(value, 0, 0);
- }
-
- /**
- * Encodes the given byte array for use when there is only a single
- * nullable property, descending order, whose type is a byte array.
- *
- * @param prefixPadding amount of extra bytes to allocate at start of encoded byte array
- * @param suffixPadding amount of extra bytes to allocate at end of encoded byte array
- */
- public static byte[] encodeSingleNullableDesc(byte[] value,
- int prefixPadding, int suffixPadding) {
- if (prefixPadding <= 0 && suffixPadding <= 0) {
- if (value == null) {
- return NULL_BYTE_ARRAY_LOW;
- }
-
- int length = value.length;
- if (length == 0) {
- return NOT_NULL_BYTE_ARRAY_LOW;
- }
-
- byte[] dst = new byte[1 + length];
- dst[0] = NOT_NULL_BYTE_LOW;
- while (--length >= 0) {
- dst[1 + length] = (byte) (~value[length]);
- }
- return dst;
- }
-
- if (value == null) {
- byte[] dst = new byte[prefixPadding + 1 + suffixPadding];
- dst[prefixPadding] = NULL_BYTE_LOW;
- return dst;
- }
-
- int length = value.length;
- byte[] dst = new byte[prefixPadding + 1 + length + suffixPadding];
- dst[prefixPadding] = NOT_NULL_BYTE_LOW;
- while (--length >= 0) {
- dst[prefixPadding + 1 + length] = (byte) (~value[length]);
- }
- return dst;
- }
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/LayoutPropertyInfo.java b/src/main/java/com/amazon/carbonado/spi/raw/LayoutPropertyInfo.java deleted file mode 100644 index 362c17c..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/LayoutPropertyInfo.java +++ /dev/null @@ -1,86 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-import java.lang.reflect.Method;
-
-import org.cojen.classfile.TypeDesc;
-
-import com.amazon.carbonado.layout.LayoutProperty;
-import com.amazon.carbonado.lob.Lob;
-
-/**
- *
- *
- * @author Brian S O'Neill
- */
-public class LayoutPropertyInfo implements GenericPropertyInfo {
- private final LayoutProperty mProp;
- private final TypeDesc mPropertyType;
- private final TypeDesc mStorageType;
- private final Method mFromStorage;
- private final Method mToStorage;
-
- LayoutPropertyInfo(LayoutProperty property) {
- this(property, null, null, null);
- }
-
- LayoutPropertyInfo(LayoutProperty property,
- Class<?> storageType, Method fromStorage, Method toStorage)
- {
- mProp = property;
- mPropertyType = TypeDesc.forDescriptor(property.getPropertyTypeDescriptor());
- if (storageType == null) {
- mStorageType = mPropertyType;
- } else {
- mStorageType = TypeDesc.forClass(storageType);
- }
- mFromStorage = fromStorage;
- mToStorage = toStorage;
- }
-
- public String getPropertyName() {
- return mProp.getPropertyName();
- }
-
- public TypeDesc getPropertyType() {
- return mPropertyType;
- }
-
- public TypeDesc getStorageType() {
- return mStorageType;
- }
-
- public boolean isNullable() {
- return mProp.isNullable();
- }
-
- public boolean isLob() {
- Class clazz = mPropertyType.toClass();
- return clazz != null && Lob.class.isAssignableFrom(clazz);
- }
-
- public Method getFromStorageAdapter() {
- return mFromStorage;
- }
-
- public Method getToStorageAdapter() {
- return mToStorage;
- }
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/RawCursor.java b/src/main/java/com/amazon/carbonado/spi/raw/RawCursor.java deleted file mode 100644 index b665191..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/RawCursor.java +++ /dev/null @@ -1,743 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-import java.util.NoSuchElementException;
-
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-import com.amazon.carbonado.FetchException;
-import com.amazon.carbonado.cursor.AbstractCursor;
-
-/**
- * Abstract Cursor implementation for a repository that manipulates raw bytes.
- *
- * @author Brian S O'Neill
- */
-public abstract class RawCursor<S> extends AbstractCursor<S> {
- // States for mState.
- private static final byte
- UNINITIALIZED = 0,
- CLOSED = 1,
- TRY_NEXT = 2,
- HAS_NEXT = 3;
-
- /** Lock object, as passed into the constructor */
- protected final Lock mLock;
-
- private final byte[] mStartBound;
- private final boolean mInclusiveStart;
- private final byte[] mEndBound;
- private final boolean mInclusiveEnd;
- private final int mPrefixLength;
- private final boolean mReverse;
-
- private byte mState;
-
- /**
- * @param lock operations lock on this object
- * @param startBound specify the starting key for the cursor, or null if first
- * @param inclusiveStart true if start bound is inclusive
- * @param endBound specify the ending key for the cursor, or null if last
- * @param inclusiveEnd true if end bound is inclusive
- * @param maxPrefix maximum expected common initial bytes in start and end bound
- * @param reverse when true, iteration is reversed
- * @throws IllegalArgumentException if any bound is null but is not inclusive
- */
- protected RawCursor(Lock lock,
- byte[] startBound, boolean inclusiveStart,
- byte[] endBound, boolean inclusiveEnd,
- int maxPrefix,
- boolean reverse) {
- mLock = lock == null ? new ReentrantLock() : lock;
-
- if ((startBound == null && !inclusiveStart) || (endBound == null && !inclusiveEnd)) {
- throw new IllegalArgumentException();
- }
-
- mStartBound = startBound;
- mInclusiveStart = inclusiveStart;
- mEndBound = endBound;
- mInclusiveEnd = inclusiveEnd;
- mReverse = reverse;
-
- // Determine common prefix for start and end bound.
- if (maxPrefix <= 0 || startBound == null && endBound == null) {
- mPrefixLength = 0;
- } else {
- int len = Math.min(maxPrefix, Math.min(startBound.length, endBound.length));
- int i;
- for (i=0; i<len; i++) {
- if (startBound[i] != endBound[i]) {
- break;
- }
- }
- mPrefixLength = i;
- }
- }
-
- public void close() throws FetchException {
- mLock.lock();
- try {
- if (mState != CLOSED) {
- release();
- // Switch state to closed before committing transaction, to
- // prevent infinite recursion that results when transaction
- // exits. Exiting a transaction causes all cursors to close.
- mState = CLOSED;
- }
- } finally {
- mLock.unlock();
- }
- }
-
- public boolean hasNext() throws FetchException {
- mLock.lock();
- try {
- try {
- switch (mState) {
- case UNINITIALIZED:
- if (mReverse ? toBoundedLast() : toBoundedFirst()) {
- mState = HAS_NEXT;
- return true;
- } else {
- mState = TRY_NEXT;
- }
- break;
-
- case CLOSED: default:
- return false;
-
- case TRY_NEXT:
- if (mReverse ? toBoundedPrevious() : toBoundedNext()) {
- mState = HAS_NEXT;
- return true;
- }
- break;
-
- case HAS_NEXT:
- return true;
- }
- } catch (FetchException e) {
- // Auto-close in response to FetchException.
- try {
- close();
- } catch (FetchException e2) {
- // Ignore.
- }
- throw e;
- }
-
- // Reached the end naturally, so close.
- close();
- } finally {
- mLock.unlock();
- }
-
- return false;
- }
-
- public S next() throws FetchException, NoSuchElementException {
- mLock.lock();
- try {
- if (!hasNext()) {
- handleNoSuchElement();
- throw new NoSuchElementException();
- }
- try {
- S obj = instantiateCurrent();
- mState = TRY_NEXT;
- return obj;
- } catch (FetchException e) {
- // Auto-close in response to FetchException.
- try {
- close();
- } catch (FetchException e2) {
- // Ignore.
- }
- throw e;
- }
- } finally {
- mLock.unlock();
- }
- }
-
- public int skipNext(int amount) throws FetchException {
- if (amount <= 0) {
- if (amount < 0) {
- throw new IllegalArgumentException("Cannot skip negative amount: " + amount);
- }
- return 0;
- }
-
- mLock.lock();
- try {
- int actual = 0;
-
- if (hasNext()) {
- try {
- actual += mReverse ? toBoundedPrevious(amount) : toBoundedNext(amount);
- } catch (FetchException e) {
- // Auto-close in response to FetchException.
- try {
- close();
- } catch (FetchException e2) {
- // Ignore.
- }
- throw e;
- }
-
- if (actual >= amount) {
- return actual;
- }
- mState = TRY_NEXT;
- // Since state was HAS_NEXT and is forced into TRY_NEXT, actual
- // amount skipped is effectively one more.
- actual++;
- }
-
- // Reached the end naturally, so close.
- close();
-
- return actual;
- } finally {
- mLock.unlock();
- }
- }
-
- /**
- * Release any internal resources, called when closed.
- */
- protected abstract void release() throws FetchException;
-
- /**
- * Returns the contents of the current key being referenced, or null
- * otherwise. Caller is responsible for making a copy of the key. The array
- * must not be modified concurrently.
- *
- * <p>If cursor is not opened, null must be returned.
- *
- * @return currently referenced key bytes or null if no current
- * @throws IllegalStateException if key is disabled
- */
- protected abstract byte[] getCurrentKey() throws FetchException;
-
- /**
- * Returns the contents of the current value being referenced, or null
- * otherwise. Caller is responsible for making a copy of the value. The
- * array must not be modified concurrently.
- *
- * <p>If cursor is not opened, null must be returned.
- *
- * @return currently referenced value bytes or null if no current
- * @throws IllegalStateException if value is disabled
- */
- protected abstract byte[] getCurrentValue() throws FetchException;
-
- /**
- * An optimization hint which disables key and value acquisition. The
- * default implementation of this method does nothing.
- */
- protected void disableKeyAndValue() {
- }
-
- /**
- * An optimization hint which disables just value acquisition. The default
- * implementation of this method does nothing.
- */
- protected void disableValue() {
- }
-
- /**
- * Enable key and value acquisition again, after they have been
- * disabled. Calling this method forces the key and value to be
- * re-acquired, if they had been disabled. Key and value acquisition must
- * be enabled by default. The default implementation of this method does
- * nothing.
- */
- protected void enableKeyAndValue() throws FetchException {
- }
-
- /**
- * Returns a new Storable instance for the currently referenced entry.
- *
- * @return new Storable instance, never null
- * @throws IllegalStateException if no current entry to instantiate
- */
- protected abstract S instantiateCurrent() throws FetchException;
-
- /**
- * Move the cursor to the first available entry. If false is returned, the
- * cursor must be positioned before the first available entry.
- *
- * @return true if first entry exists and is now current
- * @throws IllegalStateException if cursor is not opened
- */
- protected abstract boolean toFirst() throws FetchException;
-
- /**
- * Move the cursor to the first available entry at or after the given
- * key. If false is returned, the cursor must be positioned before the
- * first available entry. Caller is responsible for preserving contents of
- * array.
- *
- * @param key key to search for
- * @return true if first entry exists and is now current
- * @throws IllegalStateException if cursor is not opened
- */
- protected abstract boolean toFirst(byte[] key) throws FetchException;
-
- /**
- * Move the cursor to the last available entry. If false is returned, the
- * cursor must be positioned after the last available entry.
- *
- * @return true if last entry exists and is now current
- * @throws IllegalStateException if cursor is not opened
- */
- protected abstract boolean toLast() throws FetchException;
-
- /**
- * Move the cursor to the last available entry at or before the given
- * key. If false is returned, the cursor must be positioned after the last
- * available entry. Caller is responsible for preserving contents of array.
- *
- * @param key key to search for
- * @return true if last entry exists and is now current
- * @throws IllegalStateException if cursor is not opened
- */
- protected abstract boolean toLast(byte[] key) throws FetchException;
-
- /**
- * Move the cursor to the next available entry, returning false if none. If
- * false is returned, the cursor must be positioned after the last
- * available entry.
- *
- * @return true if moved to next entry
- * @throws IllegalStateException if cursor is not opened
- */
- protected abstract boolean toNext() throws FetchException;
-
- /**
- * Move the cursor to the next available entry, incrementing by the amount
- * given. The actual amount incremented is returned. If the amount is less
- * then requested, the cursor must be positioned after the last available
- * entry. Subclasses may wish to override this method with a faster
- * implementation.
- *
- * <p>Calling to toNext(1) is equivalent to calling toNext().
- *
- * @param amount positive amount to advance
- * @return actual amount advanced
- * @throws IllegalStateException if cursor is not opened
- */
- protected int toNext(int amount) throws FetchException {
- if (amount <= 1) {
- return (amount <= 0) ? 0 : (toNext() ? 1 : 0);
- }
-
- int count = 0;
-
- disableKeyAndValue();
- try {
- while (amount > 0) {
- if (toNext()) {
- count++;
- amount--;
- } else {
- break;
- }
- }
- } finally {
- enableKeyAndValue();
- }
-
- return count;
- }
-
- /**
- * Move the cursor to the next unique key, returning false if none. If
- * false is returned, the cursor must be positioned after the last
- * available entry. Subclasses may wish to override this method with a
- * faster implementation.
- *
- * @return true if moved to next unique key
- * @throws IllegalStateException if cursor is not opened
- */
- protected boolean toNextKey() throws FetchException {
- byte[] initialKey = getCurrentKey();
- if (initialKey == null) {
- return false;
- }
-
- disableValue();
- try {
- while (true) {
- if (toNext()) {
- byte[] currentKey = getCurrentKey();
- if (currentKey == null) {
- return false;
- }
- if (compareKeysPartially(currentKey, initialKey) > 0) {
- break;
- }
- } else {
- return false;
- }
- }
- } finally {
- enableKeyAndValue();
- }
-
- return true;
- }
-
- /**
- * Move the cursor to the previous available entry, returning false if
- * none. If false is returned, the cursor must be positioned before the
- * first available entry.
- *
- * @return true if moved to previous entry
- * @throws IllegalStateException if cursor is not opened
- */
- protected abstract boolean toPrevious() throws FetchException;
-
- /**
- * Move the cursor to the previous available entry, decrementing by the
- * amount given. The actual amount decremented is returned. If the amount
- * is less then requested, the cursor must be positioned before the first
- * available entry. Subclasses may wish to override this method with a
- * faster implementation.
- *
- * <p>Calling to toPrevious(1) is equivalent to calling toPrevious().
- *
- * @param amount positive amount to retreat
- * @return actual amount retreated
- * @throws IllegalStateException if cursor is not opened
- */
- protected int toPrevious(int amount) throws FetchException {
- if (amount <= 1) {
- return (amount <= 0) ? 0 : (toPrevious() ? 1 : 0);
- }
-
- int count = 0;
-
- disableKeyAndValue();
- try {
- while (amount > 0) {
- if (toPrevious()) {
- count++;
- amount--;
- } else {
- break;
- }
- }
- } finally {
- enableKeyAndValue();
- }
-
- return count;
- }
-
- /**
- * Move the cursor to the previous unique key, returning false if none. If
- * false is returned, the cursor must be positioned before the first
- * available entry. Subclasses may wish to override this method with a
- * faster implementation.
- *
- * @return true if moved to previous unique key
- * @throws IllegalStateException if cursor is not opened
- */
- protected boolean toPreviousKey() throws FetchException {
- byte[] initialKey = getCurrentKey();
- if (initialKey == null) {
- return false;
- }
-
- disableValue();
- try {
- while (true) {
- if (toPrevious()) {
- byte[] currentKey = getCurrentKey();
- if (currentKey == null) {
- return false;
- }
- if (compareKeysPartially(getCurrentKey(), initialKey) < 0) {
- break;
- }
- } else {
- return false;
- }
- }
- } finally {
- enableKeyAndValue();
- }
-
- return true;
- }
-
- /**
- * Returns <0 if key1 is less, 0 if equal (at least partially), >0
- * if key1 is greater.
- */
- protected int compareKeysPartially(byte[] key1, byte[] key2) {
- int length = Math.min(key1.length, key2.length);
- for (int i=0; i<length; i++) {
- int a1 = key1[i];
- int a2 = key2[i];
- if (a1 != a2) {
- return (a1 & 0xff) - (a2 & 0xff);
- }
- }
- return 0;
- }
-
- /**
- * Called right before throwing NoSuchElementException. Subclasses may
- * override to do special checks or throw a different exception.
- */
- protected void handleNoSuchElement() throws FetchException {
- }
-
- private boolean prefixMatches() throws FetchException {
- int prefixLen = mPrefixLength;
- if (prefixLen > 0) {
- byte[] prefix = mStartBound;
- byte[] key = getCurrentKey();
- if (key == null) {
- return false;
- }
- for (int i=0; i<prefixLen; i++) {
- if (prefix[i] != key[i]) {
- return false;
- }
- }
- }
- return true;
- }
-
- // Calls toFirst, but considers start and end bounds.
- private boolean toBoundedFirst() throws FetchException {
- if (mStartBound == null) {
- if (!toFirst()) {
- return false;
- }
- } else {
- if (!toFirst(mStartBound.clone())) {
- return false;
- }
- if (!mInclusiveStart) {
- byte[] currentKey = getCurrentKey();
- if (currentKey == null) {
- return false;
- }
- if (compareKeysPartially(mStartBound, currentKey) == 0) {
- if (!toNextKey()) {
- return false;
- }
- }
- }
- }
-
- if (mEndBound != null) {
- byte[] currentKey = getCurrentKey();
- if (currentKey == null) {
- return false;
- }
- int result = compareKeysPartially(currentKey, mEndBound);
- if (result >= 0) {
- if (result > 0 || !mInclusiveEnd) {
- return false;
- }
- }
- }
-
- return prefixMatches();
- }
-
- // Calls toLast, but considers start and end bounds. Caller is responsible
- // for preserving key.
- private boolean toBoundedLast() throws FetchException {
- if (mEndBound == null) {
- if (!toLast()) {
- return false;
- }
- } else {
- if (!toLast(mEndBound.clone())) {
- return false;
- }
- if (!mInclusiveEnd) {
- byte[] currentKey = getCurrentKey();
- if (currentKey == null) {
- return false;
- }
- if (compareKeysPartially(mEndBound, currentKey) == 0) {
- if (!toPreviousKey()) {
- return false;
- }
- }
- }
- }
-
- if (mStartBound != null) {
- byte[] currentKey = getCurrentKey();
- if (currentKey == null) {
- return false;
- }
- int result = compareKeysPartially(currentKey, mStartBound);
- if (result <= 0) {
- if (result < 0 || !mInclusiveStart) {
- return false;
- }
- }
- }
-
- return prefixMatches();
- }
-
- // Calls toNext, but considers end bound.
- private boolean toBoundedNext() throws FetchException {
- if (!toNext()) {
- return false;
- }
-
- if (mEndBound != null) {
- byte[] currentKey = getCurrentKey();
- if (currentKey == null) {
- return false;
- }
- int result = compareKeysPartially(currentKey, mEndBound);
- if (result >= 0) {
- if (result > 0 || !mInclusiveEnd) {
- return false;
- }
- }
- }
-
- return prefixMatches();
- }
-
- // Calls toNext, but considers end bound.
- private int toBoundedNext(int amount) throws FetchException {
- if (mEndBound == null) {
- return toNext(amount);
- }
-
- int count = 0;
-
- disableValue();
- try {
- while (amount > 0) {
- if (!toNext()) {
- break;
- }
-
- byte[] currentKey = getCurrentKey();
- if (currentKey == null) {
- break;
- }
-
- int result = compareKeysPartially(currentKey, mEndBound);
- if (result >= 0) {
- if (result > 0 || !mInclusiveEnd) {
- break;
- }
- }
-
- if (!prefixMatches()) {
- break;
- }
-
- count++;
- amount--;
- }
- } finally {
- enableKeyAndValue();
- }
-
- return count;
- }
-
- // Calls toPrevious, but considers start bound.
- private boolean toBoundedPrevious() throws FetchException {
- if (!toPrevious()) {
- return false;
- }
-
- if (mStartBound != null) {
- byte[] currentKey = getCurrentKey();
- if (currentKey == null) {
- return false;
- }
- int result = compareKeysPartially(currentKey, mStartBound);
- if (result <= 0) {
- if (result < 0 || !mInclusiveStart) {
- // Too far now, reset to first.
- toBoundedFirst();
- return false;
- }
- }
- }
-
- return prefixMatches();
- }
-
- // Calls toPrevious, but considers start bound.
- private int toBoundedPrevious(int amount) throws FetchException {
- if (mStartBound == null) {
- return toPrevious(amount);
- }
-
- int count = 0;
-
- disableValue();
- try {
- while (amount > 0) {
- if (!toPrevious()) {
- break;
- }
-
- byte[] currentKey = getCurrentKey();
- if (currentKey == null) {
- break;
- }
-
- int result = compareKeysPartially(currentKey, mStartBound);
- if (result <= 0) {
- if (result < 0 || !mInclusiveStart) {
- // Too far now, reset to first.
- toBoundedFirst();
- break;
- }
- }
-
- if (!prefixMatches()) {
- break;
- }
-
- count++;
- amount--;
- }
- } finally {
- enableKeyAndValue();
- }
-
- return count;
- }
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/RawStorableGenerator.java b/src/main/java/com/amazon/carbonado/spi/raw/RawStorableGenerator.java deleted file mode 100644 index 6d6fbe5..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/RawStorableGenerator.java +++ /dev/null @@ -1,355 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-import java.lang.ref.Reference;
-import java.lang.ref.SoftReference;
-import java.util.EnumSet;
-import java.util.Map;
-
-import org.cojen.classfile.ClassFile;
-import org.cojen.classfile.CodeBuilder;
-import org.cojen.classfile.Label;
-import org.cojen.classfile.LocalVariable;
-import org.cojen.classfile.MethodInfo;
-import org.cojen.classfile.Modifiers;
-import org.cojen.classfile.TypeDesc;
-import org.cojen.util.ClassInjector;
-import org.cojen.util.WeakIdentityMap;
-
-import com.amazon.carbonado.FetchException;
-import com.amazon.carbonado.PersistException;
-import com.amazon.carbonado.Storable;
-import com.amazon.carbonado.Storage;
-import com.amazon.carbonado.SupportException;
-
-import com.amazon.carbonado.spi.MasterFeature;
-import com.amazon.carbonado.spi.MasterStorableGenerator;
-import com.amazon.carbonado.spi.MasterSupport;
-import com.amazon.carbonado.spi.StorableGenerator;
-import com.amazon.carbonado.spi.TriggerSupport;
-
-import static com.amazon.carbonado.spi.CommonMethodNames.*;
-
-/**
- * Generates and caches abstract implementations of {@link Storable} types
- * which are encoded and decoded in a raw format. The generated abstract
- * classes extend those created by {@link MasterStorableGenerator}.
- *
- * @author Brian S O'Neill
- * @see GenericStorableCodec
- * @see RawSupport
- */
-public class RawStorableGenerator {
- // Note: All generated fields/methods have a "$" character in them to
- // prevent name collisions with any inherited fields/methods. User storable
- // properties are defined as fields which exactly match the property
- // name. We don't want collisions with those either. Legal bean properties
- // cannot have "$" in them, so there's nothing to worry about.
-
- /** Name of protected abstract method in generated storable */
- public static final String
- ENCODE_KEY_METHOD_NAME = "encodeKey$",
- DECODE_KEY_METHOD_NAME = "decodeKey$",
- ENCODE_DATA_METHOD_NAME = "encodeData$",
- DECODE_DATA_METHOD_NAME = "decodeData$";
-
- @SuppressWarnings("unchecked")
- private static Map<Class, Flavors<? extends Storable>> cCache = new WeakIdentityMap();
-
- /**
- * Collection of different abstract class flavors.
- */
- static class Flavors<S extends Storable> {
- private Reference<Class<? extends S>> mMasterFlavor;
-
- private Reference<Class<? extends S>> mNonMasterFlavor;
-
- /**
- * May return null.
- */
- Class<? extends S> getClass(boolean isMaster) {
- Reference<Class<? extends S>> ref;
- if (isMaster) {
- ref = mMasterFlavor;
- } else {
- ref = mNonMasterFlavor;
- }
- return (ref != null) ? ref.get() : null;
- }
-
- @SuppressWarnings("unchecked")
- void setClass(Class<? extends S> clazz, boolean isMaster) {
- Reference<Class<? extends S>> ref = new SoftReference(clazz);
- if (isMaster) {
- mMasterFlavor = ref;
- } else {
- mNonMasterFlavor = ref;
- }
- }
- }
-
- // Can't be instantiated or extended
- private RawStorableGenerator() {
- }
-
- /**
- * Returns an abstract implementation of the given Storable type, which is
- * fully thread-safe. The Storable type itself may be an interface or a
- * class. If it is a class, then it must not be final, and it must have a
- * public, no-arg constructor. Two constructors are defined for the
- * abstract implementation:
- *
- * <pre>
- * public <init>(RawSupport);
-
- * public <init>(RawSupport, byte[] key, byte[] value);
- * </pre>
- *
- * <p>Subclasses must implement the following abstract protected methods,
- * whose exact names are defined by constants in this class:
- *
- * <pre>
- * // Encode the primary key of this storable.
- * protected abstract byte[] encodeKey();
- *
- * // Encode all properties of this storable excluding the primary key.
- * protected abstract byte[] encodeData();
- *
- * // Decode the primary key into properties of this storable.
- * // Note: this method is also invoked by the four argument constructor.
- * protected abstract void decodeKey(byte[]);
- *
- * // Decode the data into properties of this storable.
- * // Note: this method is also invoked by the four argument constructor.
- * protected abstract void decodeData(byte[]);
- * </pre>
- *
- * @param isMaster when true, version properties, sequences, and triggers are managed
- * @throws IllegalArgumentException if type is null
- */
- @SuppressWarnings("unchecked")
- public static <S extends Storable> Class<? extends S>
- getAbstractClass(Class<S> type, boolean isMaster)
- throws SupportException, IllegalArgumentException
- {
- synchronized (cCache) {
- Class<? extends S> abstractClass;
-
- Flavors<S> flavors = (Flavors<S>) cCache.get(type);
-
- if (flavors == null) {
- flavors = new Flavors<S>();
- cCache.put(type, flavors);
- } else if ((abstractClass = flavors.getClass(isMaster)) != null) {
- return abstractClass;
- }
-
- abstractClass = generateAbstractClass(type, isMaster);
- flavors.setClass(abstractClass, isMaster);
-
- return abstractClass;
- }
- }
-
- @SuppressWarnings("unchecked")
- private static <S extends Storable> Class<? extends S>
- generateAbstractClass(Class<S> storableClass, boolean isMaster)
- throws SupportException
- {
- EnumSet<MasterFeature> features;
- if (isMaster) {
- features = EnumSet.of(MasterFeature.VERSIONING,
- MasterFeature.UPDATE_FULL,
- MasterFeature.INSERT_SEQUENCES,
- MasterFeature.INSERT_CHECK_REQUIRED);
- } else {
- features = EnumSet.of(MasterFeature.UPDATE_FULL);
- }
-
- final Class<? extends S> abstractClass =
- MasterStorableGenerator.getAbstractClass(storableClass, features);
-
- ClassInjector ci = ClassInjector.create
- (storableClass.getName(), abstractClass.getClassLoader());
-
- ClassFile cf = new ClassFile(ci.getClassName(), abstractClass);
- cf.setModifiers(cf.getModifiers().toAbstract(true));
- cf.markSynthetic();
- cf.setSourceFile(RawStorableGenerator.class.getName());
- cf.setTarget("1.5");
-
- // Declare some types.
- final TypeDesc storableType = TypeDesc.forClass(Storable.class);
- final TypeDesc storageType = TypeDesc.forClass(Storage.class);
- final TypeDesc triggerSupportType = TypeDesc.forClass(TriggerSupport.class);
- final TypeDesc masterSupportType = TypeDesc.forClass(MasterSupport.class);
- final TypeDesc rawSupportType = TypeDesc.forClass(RawSupport.class);
- final TypeDesc byteArrayType = TypeDesc.forClass(byte[].class);
-
- // Add constructor that accepts a RawSupport.
- {
- TypeDesc[] params = {rawSupportType};
- MethodInfo mi = cf.addConstructor(Modifiers.PUBLIC, params);
- CodeBuilder b = new CodeBuilder(mi);
- b.loadThis();
- b.loadLocal(b.getParameter(0));
- b.invokeSuperConstructor(new TypeDesc[] {masterSupportType});
- b.returnVoid();
- }
-
- // Add constructor that accepts a RawSupport, an encoded key, and an
- // encoded data.
- {
- TypeDesc[] params = {rawSupportType, byteArrayType, byteArrayType};
- MethodInfo mi = cf.addConstructor(Modifiers.PUBLIC, params);
- CodeBuilder b = new CodeBuilder(mi);
- b.loadThis();
- b.loadLocal(b.getParameter(0));
- b.invokeSuperConstructor(new TypeDesc[] {masterSupportType});
-
- params = new TypeDesc[] {byteArrayType};
-
- b.loadThis();
- b.loadLocal(b.getParameter(1));
- b.invokeVirtual(DECODE_KEY_METHOD_NAME, null, params);
-
- b.loadThis();
- b.loadLocal(b.getParameter(2));
- b.invokeVirtual(DECODE_DATA_METHOD_NAME, null, params);
-
- // Indicate that object is clean by calling markAllPropertiesClean.
- b.loadThis();
- b.invokeVirtual(MARK_ALL_PROPERTIES_CLEAN, null, null);
-
- b.returnVoid();
- }
-
- // Declare protected abstract methods.
- {
- cf.addMethod(Modifiers.PROTECTED.toAbstract(true),
- ENCODE_KEY_METHOD_NAME, byteArrayType, null);
- cf.addMethod(Modifiers.PROTECTED.toAbstract(true),
- DECODE_KEY_METHOD_NAME, null, new TypeDesc[]{byteArrayType});
- cf.addMethod(Modifiers.PROTECTED.toAbstract(true),
- ENCODE_DATA_METHOD_NAME, byteArrayType, null);
- cf.addMethod(Modifiers.PROTECTED.toAbstract(true),
- DECODE_DATA_METHOD_NAME, null, new TypeDesc[]{byteArrayType});
- }
-
- // Add required protected doTryLoad_master method, which delegates to RawSupport.
- {
- MethodInfo mi = cf.addMethod
- (Modifiers.PROTECTED.toFinal(true),
- MasterStorableGenerator.DO_TRY_LOAD_MASTER_METHOD_NAME, TypeDesc.BOOLEAN, null);
- mi.addException(TypeDesc.forClass(FetchException.class));
- CodeBuilder b = new CodeBuilder(mi);
-
- b.loadThis();
- b.loadField(StorableGenerator.SUPPORT_FIELD_NAME, triggerSupportType);
- b.checkCast(rawSupportType);
- b.loadThis();
- b.invokeVirtual(ENCODE_KEY_METHOD_NAME, byteArrayType, null);
- TypeDesc[] params = {byteArrayType};
- b.invokeInterface(rawSupportType, "tryLoad", byteArrayType, params);
- LocalVariable encodedDataVar = b.createLocalVariable(null, byteArrayType);
- b.storeLocal(encodedDataVar);
- b.loadLocal(encodedDataVar);
- Label notNull = b.createLabel();
- b.ifNullBranch(notNull, false);
- b.loadConstant(false);
- b.returnValue(TypeDesc.BOOLEAN);
- notNull.setLocation();
- b.loadThis();
- b.loadLocal(encodedDataVar);
- params = new TypeDesc[] {byteArrayType};
- b.invokeVirtual(DECODE_DATA_METHOD_NAME, null, params);
- b.loadConstant(true);
- b.returnValue(TypeDesc.BOOLEAN);
- }
-
- // Add required protected doTryInsert_master method, which delegates to RawSupport.
- {
- MethodInfo mi = cf.addMethod
- (Modifiers.PROTECTED.toFinal(true),
- MasterStorableGenerator.DO_TRY_INSERT_MASTER_METHOD_NAME, TypeDesc.BOOLEAN, null);
- mi.addException(TypeDesc.forClass(PersistException.class));
- CodeBuilder b = new CodeBuilder(mi);
-
- // return rawSupport.tryInsert(this, this.encodeKey$(), this.encodeData$());
- b.loadThis();
- b.loadField(StorableGenerator.SUPPORT_FIELD_NAME, triggerSupportType);
- b.checkCast(rawSupportType);
- b.loadThis(); // pass this to tryInsert method
- b.loadThis();
- b.invokeVirtual(ENCODE_KEY_METHOD_NAME, byteArrayType, null);
- b.loadThis();
- b.invokeVirtual(ENCODE_DATA_METHOD_NAME, byteArrayType, null);
- TypeDesc[] params = {storableType, byteArrayType, byteArrayType};
- b.invokeInterface(rawSupportType, "tryInsert", TypeDesc.BOOLEAN, params);
- b.returnValue(TypeDesc.BOOLEAN);
- }
-
- // Add required protected doTryUpdate_master method, which delegates to RawSupport.
- {
- MethodInfo mi = cf.addMethod
- (Modifiers.PROTECTED.toFinal(true),
- MasterStorableGenerator.DO_TRY_UPDATE_MASTER_METHOD_NAME, TypeDesc.BOOLEAN, null);
- mi.addException(TypeDesc.forClass(PersistException.class));
- CodeBuilder b = new CodeBuilder(mi);
-
- // rawSupport.store(this, this.encodeKey$(), this.encodeData$());
- // return true;
- b.loadThis();
- b.loadField(StorableGenerator.SUPPORT_FIELD_NAME, triggerSupportType);
- b.checkCast(rawSupportType);
- b.loadThis(); // pass this to store method
- b.loadThis();
- b.invokeVirtual(ENCODE_KEY_METHOD_NAME, byteArrayType, null);
- b.loadThis();
- b.invokeVirtual(ENCODE_DATA_METHOD_NAME, byteArrayType, null);
- TypeDesc[] params = {storableType, byteArrayType, byteArrayType};
- b.invokeInterface(rawSupportType, "store", null, params);
- b.loadConstant(true);
- b.returnValue(TypeDesc.BOOLEAN);
- }
-
- // Add required protected doTryDelete_master method, which delegates to RawSupport.
- {
- MethodInfo mi = cf.addMethod
- (Modifiers.PROTECTED.toFinal(true),
- MasterStorableGenerator.DO_TRY_DELETE_MASTER_METHOD_NAME, TypeDesc.BOOLEAN, null);
- mi.addException(TypeDesc.forClass(PersistException.class));
- CodeBuilder b = new CodeBuilder(mi);
-
- // return rawSupport.tryDelete(this.encodeKey$());
- b.loadThis();
- b.loadField(StorableGenerator.SUPPORT_FIELD_NAME, triggerSupportType);
- b.checkCast(rawSupportType);
- b.loadThis();
- b.invokeVirtual(ENCODE_KEY_METHOD_NAME, byteArrayType, null);
-
- TypeDesc[] params = {byteArrayType};
- b.invokeInterface(rawSupportType, "tryDelete", TypeDesc.BOOLEAN, params);
- b.returnValue(TypeDesc.BOOLEAN);
- }
-
- return ci.defineClass(cf);
- }
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/RawSupport.java b/src/main/java/com/amazon/carbonado/spi/raw/RawSupport.java deleted file mode 100644 index 895089d..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/RawSupport.java +++ /dev/null @@ -1,97 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-import com.amazon.carbonado.FetchException;
-import com.amazon.carbonado.PersistException;
-import com.amazon.carbonado.Storable;
-
-import com.amazon.carbonado.lob.Blob;
-import com.amazon.carbonado.lob.Clob;
-
-import com.amazon.carbonado.spi.MasterSupport;
-
-/**
- * Provides runtime support for Storable classes generated by {@link RawStorableGenerator}.
- *
- * @author Brian S O'Neill
- */
-public interface RawSupport<S extends Storable> extends MasterSupport<S> {
- /**
- * Try to load the entry referenced by the given key, but return null
- * if not found.
- *
- * @param key non-null key to search for
- * @return non-null value that was found, or null if not found
- */
- byte[] tryLoad(byte[] key) throws FetchException;
-
- /**
- * Try to insert the entry referenced by the given key with the given
- * value.
- *
- * @param storable storable object that key and value were derived from
- * @param key non-null key to insert
- * @param value non-null value to insert
- * @return false if unique constraint prevents insert
- */
- boolean tryInsert(S storable, byte[] key, byte[] value) throws PersistException;
-
- /**
- * Try to store the entry referenced by the given key with the given
- * value. If the entry does not exist, insert it. Otherwise, update it.
- *
- * @param storable storable object that key and value were derived from
- * @param key non-null key to store
- * @param value non-null value to store
- */
- void store(S storable, byte[] key, byte[] value) throws PersistException;
-
- /**
- * Try to delete the entry referenced by the given key.
- *
- * @param key non-null key to delete
- * @return true if entry existed and is now deleted
- */
- boolean tryDelete(byte[] key) throws PersistException;
-
- /**
- * Returns the Blob for the given locator, returning null if not found.
- */
- Blob getBlob(long locator) throws FetchException;
-
- /**
- * Returns the locator for the given Blob, returning zero if null.
- *
- * @throws PersistException if blob is unrecognized
- */
- long getLocator(Blob blob) throws PersistException;
-
- /**
- * Returns the Clob for the given locator, returning null if not found.
- */
- Clob getClob(long locator) throws FetchException;
-
- /**
- * Returns the locator for the given Clob, returning zero if null.
- *
- * @throws PersistException if blob is unrecognized
- */
- long getLocator(Clob clob) throws PersistException;
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/RawUtil.java b/src/main/java/com/amazon/carbonado/spi/raw/RawUtil.java deleted file mode 100644 index 5224b6c..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/RawUtil.java +++ /dev/null @@ -1,66 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-/**
- * Utilities for manipulating binary data.
- *
- * @author Brian S O'Neill
- */
-public class RawUtil {
- /**
- * Adds one to an unsigned integer, represented as a byte array. If
- * overflowed, value in byte array is 0x00, 0x00, 0x00...
- *
- * @param value unsigned integer to increment
- * @return false if overflowed
- */
- public static boolean increment(byte[] value) {
- for (int i=value.length; --i>=0; ) {
- byte newValue = (byte) ((value[i] & 0xff) + 1);
- value[i] = newValue;
- if (newValue != 0) {
- // No carry bit, so done adding.
- return true;
- }
- }
- // This point is reached upon overflow.
- return false;
- }
-
- /**
- * Subtracts one from an unsigned integer, represented as a byte array. If
- * overflowed, value in byte array is 0xff, 0xff, 0xff...
- *
- * @param value unsigned integer to decrement
- * @return false if overflowed
- */
- public static boolean decrement(byte[] value) {
- for (int i=value.length; --i>=0; ) {
- byte newValue = (byte) ((value[i] & 0xff) + -1);
- value[i] = newValue;
- if (newValue != -1) {
- // No borrow bit, so done subtracting.
- return true;
- }
- }
- // This point is reached upon overflow.
- return false;
- }
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/StorableCodec.java b/src/main/java/com/amazon/carbonado/spi/raw/StorableCodec.java deleted file mode 100644 index 307fe7e..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/StorableCodec.java +++ /dev/null @@ -1,118 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-import com.amazon.carbonado.FetchException;
-import com.amazon.carbonado.Storable;
-import com.amazon.carbonado.Storage;
-
-import com.amazon.carbonado.info.StorableIndex;
-
-/**
- * Supports encoding and decoding of storables.
- *
- * @author Brian S O'Neill
- * @see StorableCodecFactory
- */
-public interface StorableCodec<S extends Storable> {
- /**
- * Returns the type of Storable produced by this codec.
- */
- Class<S> getStorableType();
-
- /**
- * Instantiate a Storable with no key or value defined yet.
- *
- * @param support binds generated storable with a storage layer
- */
- S instantiate(RawSupport<S> support);
-
- /**
- * Instantiate a Storable with a specific key and value.
- *
- * @param support binds generated storable with a storage layer
- */
- S instantiate(RawSupport<S> support, byte[] key, byte[] value)
- throws FetchException;
-
- /**
- * Returns the sequence and directions of properties that make up the
- * primary key.
- */
- StorableIndex<S> getPrimaryKeyIndex();
-
- /**
- * Returns the number of prefix bytes in the primary key, which may be
- * zero.
- */
- int getPrimaryKeyPrefixLength();
-
- /**
- * Encode a key by extracting all the primary key properties from the given
- * storable.
- *
- * @param storable extract primary key properties from this instance
- * @return raw search key
- */
- byte[] encodePrimaryKey(S storable);
-
- /**
- * Encode a key by extracting all the primary key properties from the given
- * storable.
- *
- * @param storable extract primary key properties from this instance
- * @param rangeStart index of first property to use. Its value must be less
- * than the count of primary key properties.
- * @param rangeEnd index of last property to use, exlusive. Its value must
- * be less than or equal to the count of primary key properties.
- * @return raw search key
- */
- byte[] encodePrimaryKey(S storable, int rangeStart, int rangeEnd);
-
- /**
- * Encode a key by extracting all the primary key properties from the given
- * storable.
- *
- * @param values values to build into a key. It must be long enough to
- * accommodate all primary key properties.
- * @return raw search key
- */
- byte[] encodePrimaryKey(Object[] values);
-
- /**
- * Encode a key by extracting all the primary key properties from the given
- * storable.
- *
- * @param values values to build into a key. The length may be less than
- * the amount of primary key properties used by this factory. It must not
- * be less than the difference between rangeStart and rangeEnd.
- * @param rangeStart index of first property to use. Its value must be less
- * than the count of primary key properties.
- * @param rangeEnd index of last property to use, exlusive. Its value must
- * be less than or equal to the count of primary key properties.
- * @return raw search key
- */
- byte[] encodePrimaryKey(Object[] values, int rangeStart, int rangeEnd);
-
- /**
- * Encode the primary key for when there are no values, but there may be a
- * prefix. Returned value may be null if no prefix is defined.
- */
- byte[] encodePrimaryKeyPrefix();
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/StorableCodecFactory.java b/src/main/java/com/amazon/carbonado/spi/raw/StorableCodecFactory.java deleted file mode 100644 index 26e3858..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/StorableCodecFactory.java +++ /dev/null @@ -1,54 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-import com.amazon.carbonado.Storable;
-import com.amazon.carbonado.SupportException;
-
-import com.amazon.carbonado.info.StorableIndex;
-import com.amazon.carbonado.layout.Layout;
-
-/**
- * Factory for creating instances of {@link StorableCodec}.
- *
- * @author Brian S O'Neill
- */
-public interface StorableCodecFactory {
- /**
- * Returns the preferred storage/database name for the given type. Return
- * null to let repository decide.
- *
- * @throws SupportException if type is not supported
- */
- String getStorageName(Class<? extends Storable> type) throws SupportException;
-
- /**
- * @param type type of storable to create codec for
- * @param pkIndex suggested index for primary key (optional)
- * @param isMaster when true, version properties and sequences are managed
- * @param layout when non-null, attempt to encode a storable layout
- * generation value in each storable
- * @throws SupportException if type is not supported
- */
- <S extends Storable> StorableCodec<S> createCodec(Class<S> type,
- StorableIndex pkIndex,
- boolean isMaster,
- Layout layout)
- throws SupportException;
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/StorablePropertyInfo.java b/src/main/java/com/amazon/carbonado/spi/raw/StorablePropertyInfo.java deleted file mode 100644 index f13a56c..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/StorablePropertyInfo.java +++ /dev/null @@ -1,132 +0,0 @@ -/*
- * Copyright 2006 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.spi.raw;
-
-import java.lang.reflect.Method;
-
-import org.cojen.classfile.CodeAssembler;
-import org.cojen.classfile.TypeDesc;
-
-import com.amazon.carbonado.info.StorableProperty;
-import com.amazon.carbonado.lob.Lob;
-
-/**
- *
- *
- * @author Brian S O'Neill
- */
-public class StorablePropertyInfo implements GenericPropertyInfo {
- private final StorableProperty<?> mProp;
- private final TypeDesc mPropertyType;
- private final TypeDesc mStorageType;
- private final Method mFromStorage;
- private final Method mToStorage;
-
- StorablePropertyInfo(StorableProperty<?> property) {
- this(property, null, null, null);
- }
-
- StorablePropertyInfo(StorableProperty<?> property,
- Class<?> storageType, Method fromStorage, Method toStorage) {
- mProp = property;
- mPropertyType = TypeDesc.forClass(property.getType());
- if (storageType == null) {
- mStorageType = mPropertyType;
- } else {
- mStorageType = TypeDesc.forClass(storageType);
- }
- mFromStorage = fromStorage;
- mToStorage = toStorage;
- }
-
- public String getPropertyName() {
- return mProp.getName();
- }
-
- public TypeDesc getPropertyType() {
- return mPropertyType;
- }
-
- public TypeDesc getStorageType() {
- return mStorageType;
- }
-
- public boolean isNullable() {
- return mProp.isNullable();
- }
-
- public boolean isLob() {
- Class clazz = mPropertyType.toClass();
- return clazz != null && Lob.class.isAssignableFrom(clazz);
- }
-
- public Method getFromStorageAdapter() {
- return mFromStorage;
- }
-
- public Method getToStorageAdapter() {
- return mToStorage;
- }
-
- public String getReadMethodName() {
- return mProp.getReadMethodName();
- }
-
- public void addInvokeReadMethod(CodeAssembler a) {
- a.invoke(mProp.getReadMethod());
- }
-
- public void addInvokeReadMethod(CodeAssembler a, TypeDesc instanceType) {
- Class clazz = instanceType.toClass();
- if (clazz == null) {
- // Can't know if instance should be invoked as an interface or as a
- // virtual method.
- throw new IllegalArgumentException("Instance type has no known class");
- }
- if (clazz.isInterface()) {
- a.invokeInterface(instanceType, getReadMethodName(), getPropertyType(), null);
- } else {
- a.invokeVirtual(instanceType, getReadMethodName(), getPropertyType(), null);
- }
- }
-
- public String getWriteMethodName() {
- return mProp.getWriteMethodName();
- }
-
- public void addInvokeWriteMethod(CodeAssembler a) {
- a.invoke(mProp.getWriteMethod());
- }
-
- public void addInvokeWriteMethod(CodeAssembler a, TypeDesc instanceType) {
- Class clazz = instanceType.toClass();
- if (clazz == null) {
- // Can't know if instance should be invoked as an interface or as a
- // virtual method.
- throw new IllegalArgumentException("Instance type has no known class");
- }
- if (clazz.isInterface()) {
- a.invokeInterface(instanceType,
- getWriteMethodName(), null, new TypeDesc[] {getPropertyType()});
- } else {
- a.invokeVirtual(instanceType,
- getWriteMethodName(), null, new TypeDesc[] {getPropertyType()});
- }
- }
-}
diff --git a/src/main/java/com/amazon/carbonado/spi/raw/package-info.java b/src/main/java/com/amazon/carbonado/spi/raw/package-info.java deleted file mode 100644 index 8d47419..0000000 --- a/src/main/java/com/amazon/carbonado/spi/raw/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/*
- * Copyright 2006 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.
- */
-
-/**
- * Provides support for repositories that encode/decode storables in a raw
- * binary format.
- */
-package com.amazon.carbonado.spi.raw;
|