/* * 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.raw; import java.lang.reflect.Method; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; import java.util.List; 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.BeanComparator; 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 static com.amazon.carbonado.gen.StorableGenerator.*; import com.amazon.carbonado.gen.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.StorableInfo; 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. * *

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 { /** * Defines extra encoding options. * * @since 1.2 */ public static enum Option { /** * Access properties by public methods instead of protected fields. * Option should be used if class being generated doesn't have access * to these fields. */ USE_METHODS, /** * Property values such as BigDecimal are normalized before being * encoded. */ NORMALIZE, } private static enum Mode { KEY, DATA, SERIAL } private final Class mType; private final StorableIndex 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 type, StorableIndex 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 type, StorableIndex 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> map = StorableIntrospector.examine(mType).getPrimaryKeyProperties(); StorableProperty[] properties = new StorableProperty[map.size()]; map.values().toArray(properties); Direction[] directions = new Direction[map.size()]; Arrays.fill(directions, Direction.UNSPECIFIED); pkIndex = new StorableIndex(properties, directions, true); } mPkIndex = pkIndex; } /** * Generates bytecode instructions to encode properties. The encoding is * suitable for "key" encoding, which means it is correctly comparable. * *

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 options optional encoding options * @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[] properties, LocalVariable instanceVar, Class adapterInstanceClass, EnumSet