summaryrefslogtreecommitdiffstats
path: root/sonar-batch
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2014-05-07 12:17:04 +0200
committerJulien HENRY <julien.henry@sonarsource.com>2014-05-07 12:18:25 +0200
commita593b587293f7e7948db5fdfc714ac25d0c0e23f (patch)
tree0764e27271a3a0cba88e91ef10261f9d8577fc96 /sonar-batch
parentcc1be45db85751a50b98c1d36002582a7b886b5b (diff)
downloadsonarqube-a593b587293f7e7948db5fdfc714ac25d0c0e23f.tar.gz
sonarqube-a593b587293f7e7948db5fdfc714ac25d0c0e23f.zip
SONAR-5189 Use custom version of persisitit
Diffstat (limited to 'sonar-batch')
-rw-r--r--sonar-batch/pom.xml4
-rw-r--r--sonar-batch/src/main/java/com/persistit/Value.java5467
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/Cache.java30
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/Caches.java7
4 files changed, 11 insertions, 5497 deletions
diff --git a/sonar-batch/pom.xml b/sonar-batch/pom.xml
index 8e527478c01..db45a80e535 100644
--- a/sonar-batch/pom.xml
+++ b/sonar-batch/pom.xml
@@ -21,8 +21,8 @@
<scope>provided</scope>
</dependency>
<dependency>
- <groupId>com.akiban</groupId>
- <artifactId>akiban-persistit</artifactId>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-persistit</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.sonar</groupId>
diff --git a/sonar-batch/src/main/java/com/persistit/Value.java b/sonar-batch/src/main/java/com/persistit/Value.java
deleted file mode 100644
index e71ec43d4b6..00000000000
--- a/sonar-batch/src/main/java/com/persistit/Value.java
+++ /dev/null
@@ -1,5467 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package com.persistit;
-
-import com.persistit.encoding.CoderContext;
-import com.persistit.encoding.CoderManager;
-import com.persistit.encoding.HandleCache;
-import com.persistit.encoding.SerialValueCoder;
-import com.persistit.encoding.ValueCoder;
-import com.persistit.encoding.ValueDisplayer;
-import com.persistit.encoding.ValueRenderer;
-import com.persistit.exception.ConversionException;
-import com.persistit.exception.InvalidKeyException;
-import com.persistit.exception.MalformedValueException;
-import com.persistit.exception.PersistitException;
-import com.persistit.util.Debug;
-import com.persistit.util.Util;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.NotActiveException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.ObjectStreamClass;
-import java.io.OutputStream;
-import java.io.Serializable;
-import java.lang.ref.SoftReference;
-import java.lang.ref.WeakReference;
-import java.lang.reflect.Array;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * <p>
- * Encapsulates the serialized form of an <code>Object</code> or a primitive
- * value. To store data, the application modifies the <code>Exchange</code>'s
- * <code>Value</code> object and then invokes the {@link Exchange#store()}
- * operation to write the encoded value into the database. To fetch data, the
- * application modifies the <code>Exchange</code>'s <code>Key</code> object,
- * invokes the {@link Exchange#fetch()} operation and then reads the resulting
- * state from the <code>Value</code>.
- * </p>
- * <p>
- * A <code>Value</code>'s state is represented internally by an array of bytes.
- * Methods of this class encode primitive or object values into the byte array,
- * and decode bytes in the array into values equivalent to their original
- * values. For primitive-valued values, the decoded value is identical to the
- * original value. That is, after: <blockquote>
- *
- * <pre>
- * int a = 123;
- * value.put(a);
- * int b = value.get();
- * </pre>
- *
- * </blockquote> <code>a == b</code> is true. For object-valued items, the
- * result will be an object that, subject to the accuracy of serialization code,
- * is equal to the original object, but generally with different identity. That
- * is, after: <blockquote>
- *
- * <pre>
- * Object a = new Fricostat();
- * value.put(a);
- * int b = value.get();
- * </pre>
- *
- * </blockquote> usually <code>a == b</code> is false, but
- * <code>a.equals(b)</code> is true.
- * </p>
- * <p>
- * <code>Value</code> uses three strategies for these conversions:
- * <ul>
- * <li>For primitive types, their wrapper classes and certain other classes,
- * <code>Value</code> uses built-in logic to perform these conversions. Objects
- * of class <code>java.lang.String</code>, <code>java.util.Date</code>,
- * <code>java.math.BigInteger</code>, <code>java.math.BigDecimal</code> and all
- * arrays are encoded and decoded by built-in methods.</li>
- * <li>For an object of any other class, the encoding and decoding methods of
- * <code>Value</code> attempt to find an associated
- * {@link com.persistit.encoding.ValueCoder} to perform custom encoding and
- * decoding of the object.</li>
- * <li>If there is no <code>ValueCoder</code> then if the class implements
- * <code>java.io.Serializable</code> or <code>java.io.Externalizable</code>,
- * encoding and decoding is performed through serialization logic using extended
- * <code>java.io.ObjectOutputStream</code> and
- * <code>java.io.ObjectInputStream</code> classes implemented by
- * <code>Value</code>.</li>
- * </ul>
- * Note that <code>Value</code> can only encode an object if it has a
- * <code>ValueCoder</code> or implements either
- * <code>java.io.Serializable</code> or <code>java.io.Externalizable</code>.
- * </p>
- * <p>
- * Persistit JSA 1.1 introduces a faster, more compact internal storage format
- * for serialization. Objects encoded in 1.1 without the assistance of a
- * registered <code>ValueCoder</code> are normally stored in this new format and
- * cannot be decoded by earlier versions of Persistit. However, the converse is
- * not true: objects serialized by earlier versions of Persistit can be
- * deserialized properly by 1.1. Thus you may upgrade an installed application
- * from version 1.0 to 1.1 without running any type of database conversion
- * process.
- * </p>
- * <p>
- * In certain cases it may be preferable to store values using the default Java
- * serialization format defined by the <a href=
- * "http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/serialTOC.html"
- * > Java Object Serialization Specification</a>. You may set the
- * <code>serialOverride</code> configuration property to specify classes that
- * are to be serialized in standard form.
- * </p>
- * <p>
- * See <a href="../../../Object_Serialization_Notes.html"> Persistit JSA 1.1
- * Object Serialization</a> for more detailed information on these these
- * subjects.
- * </p>
- * <h3>Value as the key of a HashMap or WeakHashMap</h3>
- * <p>
- * It may be useful to build a WeakHashMap associating the serialized content of
- * a <code>Value</code> with an associated deserialized object to avoid object
- * deserialization overhead or to implement correct identity semantics. Since
- * <code>Value</code> is mutable it is a poor choice for use as a map key.
- * Instead, an immutable {@link ValueState} should be used to hold an immutable
- * copy of this state. <code>Value</code> and <code>ValueState</code> implement
- * <code>hashCode</code> and <code>equals</code> in a compatible fashion so that
- * code similar to the following works as expected: <blockquote>
- *
- * <pre>
- * ...
- * Value value = &lt;some value&gt;;
- * if (!map.contains(value)) // uses the transient current state
- * {
- * ValueState vs = new ValueState(value);
- * map.put(vs, object); // uses an immutable copy as the key
- * }
- * </pre>
- *
- * </blockquote>
- * </p>
- * <a name="_displayableFormat" /> <h3>Displayable Format</h3>
- * <p>
- * The {@link #toString()} method of this class attempts to construct a
- * human-readable representation of the serialized value. The Tree display panel
- * of the AdminUI utility uses this capability to summarize the contents of
- * values stored in a tree. The string representation is constructed as follows:
- * <ol>
- * <li>If the state represented by this <code>Value</code> is undefined, then
- * return "undefined".</li>
- * <li>If the state is <code>null</code> or a <code>boolean</code>, return
- * "null" "false", or "true".</li>
- * <li>If the value represents a primitive type, return the string
- * representation of the value, prefixed by "(byte)", "(short)", "(char)",
- * "(long)", or "(float)" for the corresponding types. Values of type
- * <code>int</code> and <code>double</code> are presented without prefix to
- * reduce clutter.</li>
- * <li>If the value represents a String, return a modified form of the string
- * enclosed in double quotes. For each character of the string, if it is a
- * double quote replace it by "\"", otherwise if it is outside of the printable
- * ASCII character set replace the character in the modified string by "\b",
- * "\t", "\n", "\r" or "\u0000" such that the modified string would be a valid
- * Java string constant.</li>
- * <li>If the value represents a <code>java.util.Date</code>, return a formatted
- * representation of the date using the format specified by {@link Key#SDF}.
- * This is a readable format the displays the date with full precision,
- * including milliseconds.</li>
- * <li>If the value represents an array, return a list of comma-separated
- * element values surrounded by square brackets.</li>
- * <li>If the value represents one of the standard <code>Collection</code>
- * implementations in the <code>java.util</code> package, then return a
- * comma-separated list of values surrounded by square brackets.</li>
- * <li>If the value represents one of the standard <code>Map</code>
- * implementations in the <code>java.util</code> package, then return a
- * comma-separated list of key/value pairs surrounded by square brackets. Each
- * key/value pair is represented by a string in the form
- * <i>key</i>-&gt;<i>value</i>.</li>
- * <li>If the value represents an object of a class for which there is a
- * registered {@link com.persistit.encoding.ValueDisplayer}, invoke the
- * displayer's {@link com.persistit.encoding.ValueDisplayer#display display}
- * method to format a displayable representation of the object.</li>
- * <li>If the value represents an object that has been stored using the version
- * 1.1 storage mechanism described object, return the class name of the object
- * followed by a comma-separated tuple, enclosed within curly brace characters,
- * representing the value of each field of the object.</li>
- * <li>If the value represents an object encoded through standard Java
- * serialization, return the string "(Serialized-object)" followed by a sequence
- * of hex digits representing the serialized bytes. Note that this process does
- * not attempt to deserialize the object, which might have unintended
- * consequences.</li>
- * <li>If the value represents an object that has already been represented
- * within the formatted result - for example, if a <code>Collection</code>
- * contain two references to the same object - then instead of creating an
- * additional string representing the second or subsequent instance, emit a back
- * reference pointer in the form @NNN where NNN is the character offset within
- * the displayable string where the first instance was found. (Note: does not
- * apply to strings and the primitive wrapper classes.)</li>
- * </ol>
- * <p>
- * For example, consider a Person class with fields for date of birth, first
- * name, last name, salary and friends, an array of other Person objects. The
- * result returned by {@link #toString} on a <code>Value</code> representing two
- * Person instances, each with just the other as a friend, might appear as
- * follows: (Note, space added for legibility.)
- *
- * <pre>
- * <code>
- * (Person){(Date)19490826000000.000-0400,"Mary","Jones",(long)75000,[
- * (Person){(Date)19550522000000.000-0400,"John","Smith",(long)68000,[@0]}]}
- * </code>
- * </pre>
- *
- * In this example, John Smith's <code>friends</code> array contains a back
- * reference to Mary Jones in the form "@0" because Mary's displayable reference
- * starts at the beginning of the string.
- * </p>
- * <a name="_streamMode" /> <h3>Stream mode</h3>
- * <p>
- * A <code>Value</code> normally contains just one object or primitive value. In
- * its normal mode of operation, the <code>put</code> operation overwrites any
- * previously held state, and the <code>get</code> operation retrieves the one
- * object or primitive value represented by the current state of the
- * <code>Value</code>. A subsequent invocation of <code>get</code> returns the
- * same value.
- * </p>
- * <p>
- * However, at certain times it is useful to store multiple items (fields)
- * together in one <code>Value</code> object. To allow this, <code>Value</code>
- * implements an alternative mode of operation called <i>stream</i> mode in
- * which each <code>put</code> invocation appends a new field to the state
- * rather than replacing the previous state. Similarly, <code>get</code>
- * operations retrieve sequentially written fields rather than rereading the
- * same field. Stream allows {@link com.persistit.encoding.ValueCoder
- * ValueCoder} implementations to aggregate the multiple fields encapsulated
- * within an encoded value.
- * </p>
- * <a name="_lowLevelAPI" /> <h3>Low-Level API</h3>
- * <p>
- * The low-level API allows an application to bypass the encoding and decoding
- * operations described above and instead to operate directly on the byte array
- * stored in the database. This might be appropriate for an existing application
- * that has already implemented its own serialization mechanisms. Applications
- * should use these methods only if there is a compelling design requirement to
- * do so.
- * </p>
- * <p>
- * The low-level API methods are: <br>
- * <blockquote>
- *
- * <pre>
- * byte[] {@link #getEncodedBytes}
- * int {@link #getEncodedSize}
- * void {@link #setEncodedSize(int)}
- * void {@link #putEncodedBytes(byte[], int, int)}
- * void {@link #copyFromEncodedBytes(byte[], int, int, int)}
- * boolean {@link #ensureFit(int)}
- * </blockquote>
- * </pre>
- *
- * </p>
- *
- *
- * @version 1.1
- */
-public final class Value {
-
- /**
- * A Value that is always EMPTY - i.e., for which <code>isDefined()</code>
- * is always false.
- */
- public final static Value EMPTY_VALUE = new Value(null, 0, 0);
- /**
- * Default initial size of the byte array that backs this <code>Value</code>
- * .
- */
- public final static int INITIAL_SIZE = 256;
- /**
- * Default maximum size to which the backing buffer can grow. The default
- * value is 4Mb.
- */
- public final static int DEFAULT_MAXIMUM_SIZE = 1024 * 1024 * 4;
-
- /**
- * Absolute maximum size limit.
- */
- public final static int MAXIMUM_SIZE = 64 * 1024 * 1024;
-
- private final static int SIZE_GRANULARITY = 256;
-
- private final static char TRUE_CHAR = 'T';
- private final static char FALSE_CHAR = 'F';
- private final static String UNDEFINED = "undefined";
-
- //
- // Primitive values first. Codes allocated for .net types as well as
- // Java and mutually available types.
- //
- private final static int TYPE_NULL = 1;
- private final static int TYPE_BOOLEAN = 2;
- private final static int TYPE_BYTE = 3;
- // private final static int TYPE_UBYTE = 4;
- private final static int TYPE_SHORT = 5;
- // private final static int TYPE_USHORT = 6;
- private final static int TYPE_CHAR = 7;
- private final static int TYPE_INT = 8;
- // private final static int TYPE_UINT = 9;
- private final static int TYPE_LONG = 10;
- // private final static int TYPE_ULONG = 11;
- // private final static int TYPE_DECIMAL = 12;
- private final static int TYPE_FLOAT = 13;
- private final static int TYPE_DOUBLE = 14;
- //
- // Wrapper classes for primitive types.
- // Note: we need to encode these differently than primitive
- // types, even though we automatically convert ("autobox") because
- // we need to know the component type of an array. Byte[] is
- // different than byte[], and so we need to differentiate.
- //
- private final static int CLASS_BOOLEAN = 18;
- private final static int CLASS_BYTE = 19;
- // private final static int CLASS_UBYTE = 20;
- private final static int CLASS_SHORT = 21;
- // private final static int CLASS_USHORT = 22;
- private final static int CLASS_CHAR = 23;
- private final static int CLASS_INT = 24;
- // private final static int CLASS_UINT = 25;
- private final static int CLASS_LONG = 26;
- // private final static int CLASS_ULONG = 27;
- // private final static int CLASS_DECIMAL = 28;
- private final static int CLASS_FLOAT = 29;
- private final static int CLASS_DOUBLE = 30;
- //
- // Used when recording the component type of an array
- //
- private final static int CLASS_OBJECT = 31;
- //
- // Standard classes encoded with built-in encoding scheme.
- //
- private final static int CLASS_STRING = 32;
- private final static int CLASS_DATE = 33;
- private final static int CLASS_BIG_INTEGER = 34;
- private final static int CLASS_BIG_DECIMAL = 35;
-
- //
- // Indicates a key range to be removed. Used only in representing
- // pending remove operations in the Transaction tree.O
- //
- final static int CLASS_ANTIVALUE = 49;
- //
- // Indicates a reference to an object that was encoded earlier in this
- // Value. Followed by the identityHashCode and a unique handle for the
- // object.
- //
- private final static int CLASS_REREF = 50;
- //
- // Indicates a record in a directory tree.
- //
- final static int CLASS_ACCUMULATOR = 58;
- final static int CLASS_TREE_STATISTICS = 59;
- final static int CLASS_TREE = 60;
- //
- // Serialized type introducer. Followed by the Persistit handle for the
- // type (even though serialization also represents that type - we need to
- // be able to decode the class without deserializing the object).
- //
- private final static int CLASS_SERIALIZED = 61;
- //
- // Array class introducer. Followed by component type and
- // length.
- //
- private final static int CLASS_ARRAY = 62;
- //
- // Array of arrays. Is followed by the number of dimensions and then the
- // component type.
- //
- private final static int CLASS_MULTI_ARRAY = 63;
- //
- // The following introduce integer-valued class IDs, sizes and counts.
- // For each of these, the bottom four bits hold the most significant 4
- // bits of the integer value being represented.
- //
- // A CLASS handle is by the current ClassIndex. There is a
- // one-to-one mapping between handle values and ClassInfo objects.
- // Each ClassInfo identifies a Class.
- //
- // A SIZE is a count of bytes. A size is encoded as a prefix for a
- // variable-length inner item. The outermost item is never prefixed
- // the size is given by the raw byte count.
- //
- // A COUNT is a count of items within a list.
- //
- // CLASS1 / SIZE2 / COUNT2
- // is followed by no additional bytes, and therefore
- // can encode values between 0 and 15
- //
- // CLASS2 / SIZE2 / COUNT2
- // is followed by one byte, and therefore can encode
- // values between 0 and 2**12 - 1.
- //
- // CLASS3 / SIZE4 /COUNT3
- // is followed by two bytes, and therefore can encode
- // values between 0 and 2**20 - 1.
- //
- // CLASS5 / SIZE5 / COUNT5
- // is followed by a 4-byte integer. The low bytes of
- // the introducer byte are ignored. This representation
- // can encode values up to Integer.MAX_VALUE. (With
- // 5 bits left available if needed for longer values.
- //
- // There are 15 open values following the CLASS encoding scheme. Collisions
- // are avoided because CLASS5 always has zeros in its low 4 bits, meaning
- // that the highest byte in a standard class encoding will be 0xF0 (240).
- //
- // An MVV is introduced by 0xFE (254) as the first byte. This is mostly
- // opaque to the Value class but exposed here for consistency,
- // documentation,
- // and for use by debug and toString() methods.
- //
- private final static int TYPE_MVV = MVV.TYPE_MVV;
- //
- // Note that a LONGREC is introduced by 0xFF (255) as the first byte.
- //
-
- private final static int BASE1 = 0x00;
- private final static int BASE2 = 0x10;
- private final static int BASE3 = 0x20;
- private final static int BASE5 = 0x30;
-
- private final static int CLASS1 = 0x40;
- // private final static int CLASS2 = 0x50;
- // private final static int CLASS3 = 0x60;
- private final static int CLASS5 = 0x70;
- //
- private final static int COUNT1 = 0x80;
- // private final static int COUNT2 = 0x90;
- // private final static int COUNT3 = 0xA0;
- private final static int COUNT5 = 0xB0;
- //
- private final static int SIZE1 = 0xC0;
- // private final static int SIZE2 = 0xD0;
- // private final static int SIZE3 = 0xE0;
- private final static int SIZE5 = 0xF0;
-
- private final static int[] ENCODED_SIZE_BITS = {-1, 0x00, 0x10, 0x20, -1, 0x30};
-
- private final static Class<?>[] CLASSES = {
- null, // 0
- Void.TYPE, Boolean.TYPE, Byte.TYPE,
- null, // reserved for .net unsigned byte
- Short.TYPE,
- null, // reserved for .net unsigned short
- Character.TYPE, Integer.TYPE,
- null, // reserved for .net unsigned int
- Long.TYPE,
- null, // reserved for .net unsigned long
- null, // reserved for .net decimal
- Float.TYPE, Double.TYPE, null,
-
- null, // 16
- Void.class, Boolean.class, Byte.class,
- null, // reserved for .net unsigned byte
- Short.class,
- null, // reserved for .net unsigned short
- Character.class, Integer.class,
- null, // reserved for .net unsigned int
- Long.class,
- null, // reserved for .net unsigned long
- null, // reserved for .net decimal
- Float.class, Double.class, Object.class,
-
- String.class, // 32
- Date.class, BigInteger.class, BigDecimal.class, null, null, null, null, null, null, null, null, null, null,
- null, null,
-
- null, // 48
- AntiValue.class, Object.class, // 50 Reference to previously encoded
- // Object,
- null, null, null, null, null, null, null, null, null, Serializable.class, // 60
- Serializable.class, // 61
-
- };
-
- //
- // A non-negative element of this array denotes the fixed number of bytes
- // required to represent the corresponding array element.
- // Element value -1 means that the corresponding item is variable-length.
- //
- private final static int[] FIXED_ENCODING_SIZES = {0, // 0
- 0, // null
- 1, // boolean
- 1, // byte
- 1, // unsigned byte
- 2, // short
- 2, // unsigned short
- 2, // char
- 4, // int
- 4, // unsigned int
- 8, // long
- 8, // unsigned long
- 16, // decimal
- 4, // float
- 8, // double
- -1,
-
- 0, // 16
- 0, // null
- 1, // boolean
- 1, // byte
- 1, // unsigned byte
- 2, // short
- 2, // unsigned short
- 2, // char
- 4, // int
- 4, // unsigned int
- 8, // long
- 8, // unsigned long
- 16, // decimal
- 4, // float
- 8, // double
- -1,
-
- -1, // 32 String
- 8, // Date
- -1, // BigInteger
- -1 // BigDecimal
-
- };
-
- private final static int TOO_MANY_LEVELS_THRESHOLD = 100;
- private final static int SAB_INCREMENT = 1024;
- private final Map<Class<?>, Class<?>[]> _arrayTypeCache = new HashMap<Class<?>, Class<?>[]>();
- private int _maximumSize = DEFAULT_MAXIMUM_SIZE;
-
- private int _size = 0;
- private int _end = 0;
- private int _next = 0;
- private int _depth = 0;
- private int[] _endArray;
- private int _level;
-
- private byte[] _bytes;
- private byte[] _longBytes;
- private int _longSize;
- private boolean _longMode;
-
- private long _pointer = -1;
- private int _pointerPageType = -1;
-
- private ValueObjectInputStream _vis;
- private ValueObjectOutputStream _vos;
-
- private int _serializedItemCount;
- private WeakReference<ValueCache> _valueCacheWeakRef;
- private ValueCache _valueCache;
-
- private boolean _shared = true;
- private DefaultValueCoder _currentCoder;
- private Object _currentObject;
-
- private final Persistit _persistit;
-
- private SoftReference<StringBuilder> _stringAssemblyBufferSoftRef;
-
- /**
- * Construct a <code>Value</code> object with default initial and maximum
- * encoded sizes.
- */
- public Value(final Persistit persistit) {
- this(persistit, INITIAL_SIZE, DEFAULT_MAXIMUM_SIZE);
- }
-
- /**
- * Construct a <code>Value</code> object with specified initial encoded size
- * and default maximum size.
- *
- * @param initialSize
- * Initial size of the encoded value buffer.
- */
- public Value(final Persistit persistit, final int initialSize) {
- this(persistit, initialSize, DEFAULT_MAXIMUM_SIZE);
- }
-
- /**
- * Construct a <code>Value</code> object with specific initial encoded size
- * and specified maximum size.
- *
- * @param initialSize
- * Initial size of the encoded value buffer.
- * @param maximumSize
- * Maximum size of the encoded value buffer.
- */
- public Value(final Persistit persistit, final int initialSize, final int maximumSize) {
- _persistit = persistit;
- _bytes = new byte[initialSize];
- _maximumSize = maximumSize;
- }
-
- /**
- * Construct a new <code>Value</code> that represents the same data as the
- * source.
- *
- * @param source
- * A <code>Value</code> whose state should be copied as the
- * initial state of this <code>Value</code>.
- */
- public Value(final Value source) {
- this(source._persistit, source._bytes.length, source._maximumSize);
- source.copyTo(this);
- }
-
- /**
- * Remove all content from this <code>Value</code>. This method also
- * disables stream mode.
- *
- * @return this Value to permit call-chaining
- *
- */
- public Value clear() {
- _size = 0;
- reset();
- return this;
- }
-
- void clear(final boolean secure) {
- if (secure) {
- Util.clearBytes(_bytes, 0, _bytes.length);
- if (_longBytes != null) {
- Util.clearBytes(_longBytes, 0, _longBytes.length);
- }
- _longSize = 0;
- if (_stringAssemblyBufferSoftRef != null) {
- final StringBuilder sb = _stringAssemblyBufferSoftRef.get();
- if (sb != null) {
- final int length = sb.length();
- for (int index = 0; index < length; index++) {
- sb.setCharAt(index, (char) 0);
- }
- }
- }
- }
- clear();
- }
-
- private StringBuilder getStringAssemblyBuffer(final int size) {
- StringBuilder sb = null;
- if (_stringAssemblyBufferSoftRef != null) {
- sb = _stringAssemblyBufferSoftRef.get();
- }
- if (sb == null) {
- sb = new StringBuilder(size + SAB_INCREMENT);
- _stringAssemblyBufferSoftRef = new SoftReference<StringBuilder>(sb);
- } else {
- sb.setLength(0);
- }
- return sb;
- }
-
- /**
- * Copy the state of this <code>Value</code> to another <code>Value</code>.
- *
- * @param target
- * The <code>Value</code> to which state should be copied.
- */
- public void copyTo(final Value target) {
- if (target == this) {
- return;
- }
- Debug.$assert0.t(!isLongRecordMode());
- Debug.$assert0.t(!target.isLongRecordMode());
-
- target._maximumSize = _maximumSize;
- target.ensureFit(_size);
- System.arraycopy(_bytes, 0, target._bytes, 0, _size);
- target._size = _size;
- target._pointer = _pointer;
- target._longMode = _longMode;
- target.reset();
- }
-
- /**
- * Hash code for the current state of this <code>Value</code>. Note that if
- * the underlying state changes, <code>hashCode</code> will produce a
- * different result. Construct a {@link ValueState} instance to hold an
- * immutable copy of the current state of a <code>Value</code>.
- */
- @Override
- public int hashCode() {
- int hashCode = 0;
- for (int index = 0; index < _size; index++) {
- hashCode = (hashCode * 17) ^ (_bytes[index] & 0xFF);
- }
- return hashCode & 0x7FFFFFFF;
- }
-
- /**
- * Implements the <code>equals</code> method such that <code>Value</code>
- * and {@link ValueState} objects may be used interchangeably as map keys.
- */
- @Override
- public boolean equals(final Object obj) {
- if (obj instanceof Value) {
- final Value value = (Value) obj;
- if (value._size != _size)
- return false;
- for (int i = 0; i < _size; i++) {
- if (value._bytes[i] != _bytes[i])
- return false;
- }
- return true;
- } else if (obj instanceof ValueState) {
- return ((ValueState) obj).equals(this);
- } else return false;
- }
-
- /**
- * Reduce the backing byte buffer to the minimal length needed to represent
- * the current state.
- *
- * @return <code>true</code> if the size was actually reduced.
- */
- public boolean trim() {
- return trim(0);
- }
-
- /**
- * Reduce the backing byte buffer to the greater of the minimal length
- * needed to represent the current state and the specified lower bound.
- *
- * @param newSize
- * the minimum size of the backing buffer.
- * @return <code>true</code> if the size was actually reduced.
- */
- public boolean trim(final int newSize) {
- if (_bytes.length > _size && _bytes.length > newSize) {
- final byte[] bytes = new byte[Math.max(_size, newSize)];
- System.arraycopy(_bytes, 0, bytes, 0, _size);
- _bytes = bytes;
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * <p>
- * Ensures that the specified number of bytes can be appended to the backing
- * byte array. If the available space is too small, this method replaces the
- * array with a new one having at least <code>length</code> available bytes.
- * Applications using the low-level API must call {@link #getEncodedBytes}
- * to get a reference to the new array after this replacement has occurred.
- * </p>
- * <p>
- * This method is part of the <a href="#_lowLevelAPI">Low-Level API</a>.
- * </p>
- *
- * @param length
- * @return <code>true</code> if the backing byte array was replaced by a
- * larger array.
- */
- public boolean ensureFit(final int length) {
- if (_size + length <= _bytes.length) {
- return false;
- }
- if (_size + length > _maximumSize) {
- throw new ConversionException("Requested size=" + (_size + length) + " exceeds maximum size="
- + _maximumSize);
- }
- int newArraySize = (((_size + length) * 2 + SIZE_GRANULARITY - 1) / SIZE_GRANULARITY) * SIZE_GRANULARITY;
- if (newArraySize > _maximumSize) {
- newArraySize = _maximumSize;
- }
- final byte[] bytes = new byte[newArraySize];
- System.arraycopy(_bytes, 0, bytes, 0, _size);
- _bytes = bytes;
-
- return true;
- }
-
- /**
- * Copy a subarray from the encoded byte array to a target. This method is
- * part of the <a href="#_lowLevelAPI">Low-Level API</a>.
- *
- * @param dest
- * The target byte array
- * @param from
- * Offset from which to start the copy
- * @param to
- * Offset into the target at which the subarray should be copied
- * @param length
- * Number of bytes to copy
- * @throws ArrayIndexOutOfBoundsException
- */
- public void copyFromEncodedBytes(final byte[] dest, final int from, final int to, final int length) {
- System.arraycopy(_bytes, from, dest, to, length);
- }
-
- /**
- * Returns the number of bytes used to encode the current value. This method
- * is part of the <a href="#_lowLevelAPI">Low-Level API</a>.
- *
- * @return The size
- */
- public int getEncodedSize() {
- return _size;
- }
-
- /**
- * Replace the encoded value with bytes from a supplied array. This method
- * is part of the <a href="#_lowLevelAPI">Low-Level API</a>.
- *
- * @param from
- * Byte array from which to copy the encoded value
- * @param offset
- * Offset to first byte in the supplied array from which to copy
- * @param length
- * Number of bytes to copy
- * @throws ArrayIndexOutOfBoundsException
- * if the supplied offset or size exceed the bounds of the
- * supplied array
- * @throws ConversionException
- * if the resulting value size exceeds the maximum size
- */
- public void putEncodedBytes(final byte[] from, final int offset, final int length) {
- ensureFit(length);
- if (length > 0) {
- System.arraycopy(from, offset, _bytes, 0, length);
- }
- setEncodedSize(length);
- }
-
- /**
- * Returns the backing byte array used to hold the state of this
- * <code>Value</code>. This method is part of the <a
- * href="#_lowLevelAPI">Low-Level API</a>.
- *
- * @return The byte array
- */
- public byte[] getEncodedBytes() {
- return _bytes;
- }
-
- /**
- * Sets the length of the encoded data in the backing byte array. This
- * length governs the number of bytes from the backing byte array that will
- * be stored in the database during the next <code>store</code> operation.
- * This method is part of the <a href="#_lowLevelAPI">Low-Level API</a>.
- */
- public void setEncodedSize(final int size) {
- if (size < 0 || size > _bytes.length) {
- throw new IllegalArgumentException("Size " + size + " exceeds capacity");
- }
- _size = size;
- _depth = 0;
- }
-
- /**
- * Returns the maximum size to which the backing buffer can grow.
- *
- * @return The maximum size
- */
- public int getMaximumSize() {
- return _maximumSize;
- }
-
- /**
- * Modifies the maximum size to which the backing buffer can grow and trims
- * the current backing buffer to be no larger than the new maximum.
- *
- * @param size
- * The maximum size
- *
- * @throws IllegalArgumentException
- * If the backing buffer is already larger than
- * <code>size</code>, this method
- *
- */
- public void setMaximumSize(final int size) {
- if (size < _size) {
- throw new IllegalArgumentException("Value is larger than new maximum size");
- }
- if (size > MAXIMUM_SIZE) {
- throw new IllegalArgumentException("Value is larger than absolute limit " + MAXIMUM_SIZE);
- }
- trim(size);
- _maximumSize = size;
- }
-
- public int getCursor() {
- return _next;
- }
-
- public void setCursor(final int cursor) {
- if (cursor < 0 || cursor > _size) {
- throw new IllegalArgumentException("Cursor out of bound (0," + _size + ")");
- }
- _next = cursor;
- }
-
- /**
- * Enables or disables stream mode. See <a href="#_streamMode">Stream
- * Mode</a> for further information.
- *
- * @param b
- * <code>true</code> to enable stream mode, <code>false</code> to
- * disable it.
- */
- public void setStreamMode(final boolean b) {
- reset();
- _depth = b ? 1 : 0;
- }
-
- /**
- * Indicates whether stream mode is enabled. See <a
- * href="#_streamMode">Stream Mode</a> for further information.
- *
- * @return <code>true</code> if stream mode is enabled.
- */
- public boolean isStreamMode() {
- return _depth > 0;
- }
-
- /**
- * Indicates whether there is data associated with this <code>Value</code>.
- * The result of fetching a <code>Key</code> that has no associated record
- * in the database leaves the corresponding <code>Value</code> in an
- * undefined state. Note that a Value containing <code>null</code> is
- * defined. Persistit distinguishes between null and undefined states.
- *
- * @return <code>true</code> if there is data represented by this
- * <code>Value</code> .
- */
- public boolean isDefined() {
- return _size != 0;
- }
-
- /**
- * Tests whether the data held by this <code>Value</code> is null.
- *
- * @return <code>true</code> if the current state of this <code>Value</code>
- * represents <i>null</i>.
- */
- public boolean isNull() {
- return getTypeHandle() == TYPE_NULL;
- }
-
- /**
- * Determine whether the data held by this <code>Value</code> is null. As a
- * side effect, if <code>skipNull</code> is true and <a
- * href="#_streamMode">Stream Mode</a> is enabled this method also advances
- * the cursor to the next field if the current field is null.
- *
- * @param skipNull
- * if <code>true</code>, the <code>Value</code> is in stream mode
- * and the current field is null, then advance the cursor to next
- * field
- * @return <code>true</code> if the current state of this <code>Value</code>
- * represents <i>null</i>.
- */
- public boolean isNull(final boolean skipNull) {
- if (isNull()) {
- if (skipNull && _depth > 0) {
- _next++;
- _serializedItemCount++;
- }
- return true;
- } else {
- return false;
- }
- }
-
- boolean isAntiValue() {
- if (_size == 0) {
- return false;
- }
- return (_bytes[0] & 0xFF) == CLASS_ANTIVALUE;
- }
-
- /**
- * Provides a String representation of the state of this <code>Value</code>.
- *
- * @see #decodeDisplayable(boolean, StringBuilder)
- *
- * @return A String value. If this Value is undefined, returns the word
- * "undefined". Note that this value is indistinguishable from the
- * result of <code>toString</code> on a <code>Value</code> whose
- * state represents the string "undefined". Invoke the
- * {@link #isDefined()} method to determine reliably whether the
- * <code>Value</code> is defined.
- */
- @Override
- public String toString() {
- if (_size == 0) {
- return UNDEFINED;
- }
-
- if (_longMode && (_bytes[0] & 0xFF) == Buffer.LONGREC_TYPE && (_size >= Buffer.LONGREC_SIZE)) {
- return toStringLongMode();
- }
-
- final int saveDepth = _depth;
- final int saveLevel = _level;
- final int saveNext = _next;
- final int saveEnd = _end;
- final StringBuilder sb = new StringBuilder();
- setStreamMode(true);
- try {
- boolean first = true;
- while (_next < _size) {
- if (!first) {
- sb.append(",");
- }
- first = false;
- decodeDisplayable(true, sb, null);
- }
- } catch (final ConversionException e) {
- final int truncatedSize = Math.min(_size - _next, 256);
- sb.append("ConversionException " + e.getCause() + " index=" + _next + " size=" + (_size - _next) + ": "
- + Util.hexDump(_bytes, 0, truncatedSize));
- } catch (final Exception e) {
- sb.append("Exception " + e + " while decoding value at index=" + _next + ": " + e);
- } finally {
- _end = saveEnd;
- _next = saveNext;
- _level = saveLevel;
- _depth = saveDepth;
- }
- return sb.toString();
- }
-
- private String toStringLongMode() {
- final StringBuilder sb = new StringBuilder();
- sb.append("LongRec size=");
- sb.append(Buffer.decodeLongRecordDescriptorSize(_bytes, 0));
- sb.append(" page=");
- sb.append(Buffer.decodeLongRecordDescriptorPointer(_bytes, 0));
- return sb.toString();
- }
-
- /**
- * Appends a displayable, printable String version of a value into the
- * supplied StringBuilder. If <code>quoted</code> is <code>true</code>, then
- * the all String values in the result will be enclosed and converted to a
- * printable format.
- *
- * @see #decodeDisplayable(boolean, StringBuilder, CoderContext)
- *
- * @param quoted
- * <code>true</code> to quote and convert all strings to
- * printable form.
- * @param sb
- * A <code>StringBuilder</code> to which the displayable value
- * will be appended.
- */
- public void decodeDisplayable(final boolean quoted, final StringBuilder sb) {
- decodeDisplayable(quoted, sb, null);
- }
-
- /**
- * Appends a displayable String version of a value into the supplied
- * StringBuilder. If <code>quoted</code> is <code>true</code>, then the all
- * String values in the result will be enclosed and converted to a printable
- * format.
- *
- * @param quoted
- * <code>true</code> to quote and convert all strings to
- * printable form.
- * @param sb
- * A <code>StringBuilder</code> to which the displayable value
- * will be appended.
- * @param context
- * A <code>CoderContext</code> to be passed to any underlying
- * {@link ValueDisplayer}.
- */
- public void decodeDisplayable(final boolean quoted, final StringBuilder sb, final CoderContext context) {
- checkSize(1);
-
- final int start = _next;
- final int level = _level;
-
- final int classHandle = nextType();
- final int currentItemCount = _serializedItemCount;
- final boolean isVariableLength = (_next - start) > 1;
- switch (classHandle) {
- case TYPE_NULL: {
- _next = start;
- sb.append(getNull());
- break;
- }
-
- case TYPE_BYTE: {
- _next = start;
- appendParenthesizedFriendlyClassName(sb, byte.class);
- sb.append(getByte());
- break;
- }
-
- case TYPE_CHAR: {
- _next = start;
- appendParenthesizedFriendlyClassName(sb, char.class);
- if (quoted)
- Util.appendQuotedChar(sb, getChar());
- else sb.append((int) getChar());
- break;
- }
-
- case TYPE_INT: {
- _next = start;
- sb.append(getInt());
- break;
- }
-
- case TYPE_LONG: {
- _next = start;
- appendParenthesizedFriendlyClassName(sb, long.class);
- sb.append(getLong());
- break;
- }
-
- case TYPE_FLOAT: {
- _next = start;
- appendParenthesizedFriendlyClassName(sb, float.class);
- sb.append(getFloat());
- break;
- }
-
- case TYPE_DOUBLE: {
- _next = start;
- sb.append(getDouble());
- break;
- }
-
- case TYPE_BOOLEAN: {
- _next = start;
- sb.append(getBoolean());
- break;
- }
-
- case CLASS_STRING:
- case CLASS_BOOLEAN:
- case CLASS_BYTE:
- case CLASS_SHORT:
- case CLASS_CHAR:
- case CLASS_INT:
- case CLASS_LONG:
- case CLASS_FLOAT:
- case CLASS_DOUBLE: {
- // For these built-in types we don't display the back
- // reference.
- _next = start;
- if (_level != level)
- _end = popEnd();
- final Object value = get(null, context);
- appendDisplayable(sb, value, quoted, false);
- break;
- }
-
- case CLASS_REREF: {
- _next = start;
- final Object value = get(null, context);
- appendDisplayable(sb, value, quoted, true);
- break;
- }
-
- case CLASS_ARRAY: {
- try {
- _depth++;
- _serializedItemCount++;
- registerEncodedObject(sb.length());
- final int componentClassHandle = nextType();
- switch (componentClassHandle) {
- case TYPE_BOOLEAN: {
- sb.append("boolean[]{");
- final int length = _end - _next;
- for (int index = 0; index < length; index++) {
- if (index > 0)
- sb.append(',');
- sb.append(toBoolean(_next) ? "true" : "false");
- _next++;
- }
- break;
- }
-
- case TYPE_BYTE: {
- sb.append("byte[]{");
- final int length = _end - _next;
- for (int index = 0; index < length; index++) {
- if (index > 0)
- sb.append(',');
- sb.append(Util.getByte(_bytes, _next));
- _next++;
- }
- break;
- }
-
- case TYPE_SHORT: {
- sb.append("short[]{");
- final int length = arraySize(_end, _next, 2);
- for (int index = 0; index < length; index++) {
- if (index > 0)
- sb.append(',');
- sb.append(Util.getShort(_bytes, _next));
- _next += 2;
- }
- break;
- }
-
- case TYPE_CHAR: {
- sb.append("char[]{");
- final int length = arraySize(_end, _next, 2);
- for (int index = 0; index < length; index++) {
- if (index > 0)
- sb.append(',');
- final int c = Util.getChar(_bytes, _next);
- if (quoted)
- Util.appendQuotedChar(sb, c);
- else sb.append(c);
- _next += 2;
- }
- break;
- }
-
- case TYPE_INT: {
- sb.append("int[]{");
- final int length = arraySize(_end, _next, 4);
- for (int index = 0; index < length; index++) {
- if (index > 0)
- sb.append(',');
- sb.append(Util.getInt(_bytes, _next));
- _next += 4;
- }
- break;
- }
-
- case TYPE_LONG: {
- sb.append("long[]{");
- final int length = arraySize(_end, _next, 8);
- for (int index = 0; index < length; index++) {
- if (index > 0)
- sb.append(',');
- sb.append(Util.getLong(_bytes, _next));
- _next += 8;
- }
- break;
- }
-
- case TYPE_FLOAT: {
- sb.append("float[]{");
- final int length = arraySize(_end, _next, 4);
- for (int index = 0; index < length; index++) {
- if (index > 0)
- sb.append(',');
- final float f = Float.intBitsToFloat(Util.getInt(_bytes, _next));
- sb.append(f);
- _next += 4;
- }
- break;
- }
-
- case TYPE_DOUBLE: {
- sb.append("double[]{");
- final int length = arraySize(_end, _next, 8);
- for (int index = 0; index < length; index++) {
- if (index > 0)
- sb.append(',');
- final double d = Double.longBitsToDouble(Util.getLong(_bytes, _next));
- sb.append(d);
- _next += 8;
- }
- break;
- }
-
- default: {
- final Class<?> cl = classForHandle(componentClassHandle);
- if (cl != null)
- appendFriendlyClassName(sb, cl);
- sb.append("[]{");
- final int length = decodeElementCount();
- for (int index = 0; index < length; index++) {
- if (index > 0)
- sb.append(',');
- decodeDisplayable(quoted, sb, context);
- }
- break;
- }
- }
- sb.append('}');
- } finally {
- _depth--;
- }
- if (isVariableLength)
- closeVariableLengthItem();
- break;
- }
- case CLASS_MULTI_ARRAY: {
- _next = start;
- decodeDisplayableMultiArray(quoted, sb, context, null);
- break;
- }
- case CLASS_SERIALIZED: {
- _next = start;
- final int length = sb.length();
- _depth++;
- try {
- final Object object = get(null, context);
- getValueCache().store(currentItemCount, new DisplayMarker(sb.length()));
- appendDisplayable(sb, object, quoted, false);
- } catch (final Exception e) {
- sb.setLength(length);
- sb.append("(Serialized-Object)");
- Util.bytesToHex(sb, _bytes, start, _end - start);
- } finally {
- _depth--;
- if (isVariableLength)
- closeVariableLengthItem();
- }
- break;
- }
-
- case TYPE_MVV: {
- final int savedSize = _size;
- sb.append('[');
-
- try {
- MVV.visitAllVersions(new MVV.VersionVisitor() {
- boolean first = true;
-
- @Override
- public void init() {
- }
-
- @Override
- public void sawVersion(final long version, final int offset, final int valueLength) {
- if (!first) {
- sb.append(',');
- }
- sb.append(TransactionStatus.versionString(version));
- try {
- final long tc = _persistit.getTransactionIndex().commitStatus(version, Long.MAX_VALUE, 0);
- sb.append("<" + TransactionStatus.tcString(tc) + ">");
- } catch (final Exception e) {
- sb.append("<" + e + ">");
- }
-
- sb.append(':');
- if (valueLength == 0) {
- sb.append(UNDEFINED);
- } else {
- _next = offset;
- _end = _size = _next + valueLength;
- decodeDisplayable(quoted, sb, context);
- }
- first = false;
- }
-
- }, getEncodedBytes(), 0, getEncodedSize());
- } catch (final Throwable t) {
- sb.append("<<").append(t).append(">>");
- } finally {
- _next = _end = _size = savedSize;
- }
-
- sb.append(']');
- }
- break;
-
- default: {
- if (classHandle >= CLASS1) {
- try {
- final Class<?> clazz = classForHandle(classHandle);
- ValueCoder coder = null;
- _depth++;
- getValueCache().store(currentItemCount, new DisplayMarker(sb.length()));
-
- _serializedItemCount++;
-
- if (clazz != null) {
- coder = getValueCoder(clazz);
- }
- if (coder instanceof ValueDisplayer) {
- appendParenthesizedFriendlyClassName(sb, clazz);
- ((ValueDisplayer) coder).display(this, sb, clazz, context);
- } else if (coder instanceof SerialValueCoder) {
- final int length = sb.length();
- try {
- _next = start;
- final Object object = get(null, context);
- getValueCache().store(currentItemCount, new DisplayMarker(sb.length()));
- appendDisplayable(sb, object, quoted, false);
- } catch (final Exception e) {
- sb.setLength(length);
- sb.append("(Serialized-Object)");
- Util.bytesToHex(sb, _bytes, start, _end - start);
- }
- } else {
- appendParenthesizedFriendlyClassName(sb, clazz);
- sb.append('{');
- boolean first = true;
- while (hasMoreItems()) {
- if (!first)
- sb.append(',');
- first = false;
- decodeDisplayable(true, sb, null);
- }
- sb.append('}');
- }
- break;
- } catch (final Throwable t) {
- sb.append("<<" + t + ">>");
- } finally {
- _depth--;
- if (isVariableLength)
- closeVariableLengthItem();
- }
- } else {
- try {
- _next = start;
- final Object value = get(null, context);
- getValueCache().store(currentItemCount, new DisplayMarker(sb.length()));
- appendDisplayable(sb, value, quoted, false);
- } catch (final Throwable t) {
- sb.append("<<" + t + ">>");
- } finally {
- if (isVariableLength)
- closeVariableLengthItem();
- }
- break;
- }
- }
- }
- }
-
- private void decodeDisplayableMultiArray(final boolean quoted, final StringBuilder sb, final CoderContext context,
- Class<?> prototype) {
- final int start = _next;
- final int type = nextType(CLASS_MULTI_ARRAY, CLASS_REREF);
- if (type == CLASS_REREF) {
- _next = start;
- final Object array = get(null, null);
- if (array == null || array instanceof DisplayMarker || array.getClass().isArray()) {
- appendDisplayable(sb, array, quoted, true);
- } else {
- throw new ConversionException("Referenced object is not an array");
- }
- } else {
- try {
- _depth++;
- final int componentClassHandle = nextType();
- checkSize(1);
- final int dimensions = _bytes[_next++] & 0xFF;
- if (prototype == null) {
- prototype = Array.newInstance(classForHandle(componentClassHandle), new int[dimensions]).getClass();
- }
- final int length = decodeElementCount();
-
- _serializedItemCount++;
- registerEncodedObject(sb.length());
- sb.append('[');
- final Class<?> componentType = prototype.getComponentType();
- if (componentType.getComponentType().isArray()) {
- for (int index = 0; index < length; index++) {
- if (index > 0)
- sb.append(',');
- decodeDisplayableMultiArray(quoted, sb, context, componentType);
- }
- } else {
- for (int index = 0; index < length; index++) {
- if (index > 0)
- sb.append(',');
- decodeDisplayable(quoted, sb, context);
- }
- }
- sb.append(']');
- } finally {
- _depth--;
- }
- closeVariableLengthItem();
- }
- }
-
- private void appendParenthesizedFriendlyClassName(final StringBuilder sb, final Class<?> cl) {
- sb.append('(');
- appendFriendlyClassName(sb, cl);
- sb.append(')');
- }
-
- private void appendFriendlyClassName(final StringBuilder sb, final Class<?> cl) {
- if (cl == null) {
- sb.append(cl);
- return;
- }
- if (cl.isPrimitive()) {
- sb.append(cl.getName());
- } else if (cl.isArray()) {
- appendFriendlyClassName(sb, cl.getComponentType());
- sb.append("[]");
- } else if (cl == String.class) {
- sb.append("String");
- } else if (cl == Date.class) {
- sb.append("Date");
- } else if (Number.class.isAssignableFrom(cl) && cl.getName().startsWith("java.lang.")
- || cl.getName().startsWith("java.math.")) {
- sb.append(cl.getName().substring(10));
- } else {
- sb.append(cl.getName());
- }
- }
-
- private void appendDisplayable(final StringBuilder sb, final Object value, final boolean quoted,
- final boolean reference) {
- if (value == null) {
- sb.append(value);
- } else {
- final Class<?> cl = value.getClass();
- final String className = cl.getName();
-
- if (cl == String.class) {
- final String s = (String) value;
- int length = s.length();
- if (length > 24 && reference)
- length = 21;
- if (quoted) {
- sb.append("\"");
- for (int index = 0; index < s.length(); index++) {
- Util.appendQuotedChar(sb, s.charAt(index));
- }
- sb.append("\"");
- } else {
- sb.append(s.substring(0, length));
- }
- if (length < s.length())
- sb.append("...");
- } else if (cl == Date.class) {
- appendParenthesizedFriendlyClassName(sb, cl);
- sb.append(Key.SDF.format((Date) value));
- } else if (value instanceof Number) {
- sb.append('(');
- sb.append(className.startsWith("java.lang.") ? className.substring(10) : className);
- sb.append(')');
- sb.append(value);
- } else if (value instanceof DisplayMarker) {
- sb.append(value);
- } else if (value instanceof AntiValue) {
- sb.append(cl.getSimpleName());
- sb.append(value);
- } else {
- appendParenthesizedFriendlyClassName(sb, cl);
- try {
- final String s = value.toString();
- appendDisplayable(sb, s, false, reference);
- } catch (final Throwable t) {
- sb.append("<<" + t + ">>");
- }
- }
- }
- }
-
- int getTypeHandle() {
- final int saveDepth = _depth;
- final int saveLevel = _level;
- final int saveNext = _next;
- final int saveEnd = _end;
- final int result = nextType();
- _end = saveEnd;
- _next = saveNext;
- _level = saveLevel;
- _depth = saveDepth;
- return result;
- }
-
- /**
- * Returns the type of the object represented by the current state of this
- * <code>Value</code>.
- *
- * @return The type
- */
- public Class<?> getType() {
- final int saveDepth = _depth;
- final int saveLevel = _level;
- final int saveNext = _next;
- final int saveEnd = _end;
- try {
- final int classHandle = nextType();
- if (classHandle == CLASS_REREF) {
- final int base = _bytes[_next++] & 0xFF;
- final int handle = decodeVariableLengthInt(base);
- final Object object = getValueCache().get(handle);
- if (object == null) {
- throw new IllegalStateException("Reference to handle " + handle + " has no value");
- }
- return object.getClass();
- } else if (classHandle > 0 && classHandle < CLASSES.length && CLASSES[classHandle] != null) {
- return CLASSES[classHandle];
- } else if (classHandle == CLASS_ARRAY) {
- _depth++;
- final int componentClassHandle = nextType();
- return arrayClass(classForHandle(componentClassHandle), 1);
- } else if (classHandle == CLASS_MULTI_ARRAY) {
- _depth++;
- final int componentClassHandle = nextType();
- checkSize(1);
- final int dimensions = _bytes[_next++] & 0xFF;
- return arrayClass(classForHandle(componentClassHandle), dimensions);
- }
-
- else return classForHandle(classHandle);
- } finally {
- _end = saveEnd;
- _next = saveNext;
- _level = saveLevel;
- _depth = saveDepth;
- }
- }
-
- public boolean isType(final Class<?> clazz) {
- final int classHandle = getTypeHandle();
- if (classHandle == TYPE_MVV || classHandle == CLASS_ANTIVALUE) {
- return false;
- }
- if (classHandle > 0 && classHandle < CLASSES.length) {
- return CLASSES[classHandle] == clazz;
- }
- try {
- return getType() == clazz;
- } catch (final Exception e) {
- return false;
- }
- }
-
- private Class<?> arrayClass(final Class<?> componentClass, final int dimensions) {
- Class<?>[] arraysByDimension = _arrayTypeCache.get(componentClass);
- Class<?> result = null;
- if (arraysByDimension != null && arraysByDimension.length > dimensions)
- result = arraysByDimension[dimensions];
- if (result != null)
- return result;
-
- if (dimensions == 1)
- result = Array.newInstance(componentClass, 0).getClass();
-
- else result = Array.newInstance(componentClass, new int[dimensions]).getClass();
- if (arraysByDimension != null) {
- if (arraysByDimension.length <= dimensions) {
- final Class<?>[] temp = new Class<?>[dimensions + 2];
- System.arraycopy(arraysByDimension, 0, temp, 0, arraysByDimension.length);
- arraysByDimension = temp;
- _arrayTypeCache.put(componentClass, arraysByDimension);
- }
- } else arraysByDimension = new Class<?>[dimensions + 2];
-
- arraysByDimension[dimensions] = result;
- return result;
- }
-
- /**
- * Decodes the object value represented by the current state of this
- * <code>Value</code> and verifies that it is <code>null</code>.
- *
- * @return <code>null</code>
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent
- * <code>null</code>.
- */
- public Object getNull() {
- final int start = _next;
- final int type = nextType();
- if (type == TYPE_NULL) {
- _serializedItemCount++;
- return null;
- }
- _next = start;
- final Object object = get(null, null);
- if (object == null)
- return null;
- throw new ConversionException("Expected null");
- }
-
- /**
- * Decodes the boolean value represented by the current state of this
- * <code>Value</code>.
- *
- * @return The value as a boolean.
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent data
- * of this type.
- */
- public boolean getBoolean() {
- final int start = _next;
- if (nextType() == TYPE_BOOLEAN) {
- _serializedItemCount++;
- return getBooleanInternal();
- }
- _next = start;
- return ((Boolean) getExpectedType(Boolean.class)).booleanValue();
- }
-
- private boolean getBooleanInternal() {
- checkSize(1);
- final boolean result = toBoolean(_next);
- _next++;
- return result;
- }
-
- /**
- * Decodes the byte value represented by the current state of this
- * <code>Value</code>.
- *
- * @return The value as a byte.
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent data
- * of this type.
- */
- public byte getByte() {
- final int start = _next;
- if (nextType() == TYPE_BYTE) {
- _serializedItemCount++;
- return getByteInternal();
- }
- _next = start;
- return ((Byte) getExpectedType(Byte.class)).byteValue();
- }
-
- private byte getByteInternal() {
- checkSize(1);
- final byte result = _bytes[_next++];
- return result;
- }
-
- /**
- * Decodes the short value represented by the current state of this
- * <code>Value</code>.
- *
- * @return The value as a short.
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent data
- * of this type.
- */
- public short getShort() {
- final int start = _next;
- if (nextType() == TYPE_SHORT) {
- _serializedItemCount++;
- return getShortInternal();
- }
- _next = start;
- return ((Short) getExpectedType(Short.class)).shortValue();
- }
-
- private short getShortInternal() {
- checkSize(2);
- final short result = (short) Util.getShort(_bytes, _next);
- _next += 2;
- return result;
- }
-
- /**
- * Decodes the char value represented by the current state of this
- * <code>Value</code>.
- *
- * @return The value as a char.
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent data
- * of this type.
- */
- public char getChar() {
- final int start = _next;
- if (nextType() == TYPE_CHAR) {
- _serializedItemCount++;
- return getCharInternal();
- }
- _next = start;
- return ((Character) getExpectedType(Character.class)).charValue();
- }
-
- private char getCharInternal() {
- checkSize(2);
- final char result = (char) Util.getChar(_bytes, _next);
- _next += 2;
- return result;
- }
-
- /**
- * Decodes the int value represented by the current state of this
- * <code>Value</code>.
- *
- * @return The value as a int.
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent data
- * of this type.
- */
- public int getInt() {
- final int start = _next;
- if (nextType() == TYPE_INT) {
- _serializedItemCount++;
- return getIntInternal();
- }
- _next = start;
- return ((Integer) getExpectedType(Integer.class)).intValue();
- }
-
- private int getIntInternal() {
- checkSize(4);
- final int result = Util.getInt(_bytes, _next);
- _next += 4;
- return result;
- }
-
- /**
- * Decodes the long value represented by the current state of this
- * <code>Value</code>.
- *
- * @return The value as a long.
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent data
- * of this type.
- */
- public long getLong() {
- final int start = _next;
- if (nextType() == TYPE_LONG) {
- _serializedItemCount++;
- return getLongInternal();
- }
- _next = start;
- return ((Long) getExpectedType(Long.class)).longValue();
- }
-
- private long getLongInternal() {
- checkSize(8);
- final long result = Util.getLong(_bytes, _next);
- _next += 8;
- return result;
- }
-
- /**
- * Decodes the float value represented by the current state of this
- * <code>Value</code>.
- *
- * @return The value as a float.
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent data
- * of this type.
- */
- public float getFloat() {
- final int start = _next;
- if (nextType() == TYPE_FLOAT) {
- _serializedItemCount++;
- return getFloatInternal();
- }
- _next = start;
- return ((Float) getExpectedType(Float.class)).floatValue();
- }
-
- private float getFloatInternal() {
- checkSize(4);
- final float result = Float.intBitsToFloat(Util.getInt(_bytes, _next));
- _next += 4;
- return result;
- }
-
- /**
- * Decodes the double value represented by the current state of this
- * <code>Value</code>.
- *
- * @return The value as a double.
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent data
- * of this type.
- */
- public double getDouble() {
- final int start = _next;
- if (nextType() == TYPE_DOUBLE) {
- _serializedItemCount++;
- return getDoubleInternal();
- }
- _next = start;
- return ((Double) getExpectedType(Double.class)).doubleValue();
- }
-
- private double getDoubleInternal() {
- checkSize(8);
- final double result = Double.longBitsToDouble(Util.getLong(_bytes, _next));
- _next += 8;
- return result;
- }
-
- /**
- * Decodes the object value represented by the current state of this
- * <code>Value</code>. This method is identical to {@link #get()} except
- * that in <a href="#_streamMode">Stream Mode</a> the pointer to the next
- * retrieved value is not advanced.
- *
- * @return The value as a Object.
- *
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent data
- * of a recognizable class.
- *
- * @throws MalformedValueException
- * if this <code>Value</code> is structurally corrupt.
- */
- public Object peek() {
- return peek(null, null);
- }
-
- /**
- * <p>
- * Decodes the object value represented by the current state of this
- * <code>Value</code>. This method is identical to {@link #get(Object)}
- * except that in <a href="#_streamMode">Stream Mode</a> the pointer to the
- * next retrieved value is not advanced.
- * </p>
- * <p>
- * This variant of <code>get</code> <i>may</i> modify and return the target
- * object supplied as a parameter, rather than creating a new object. This
- * behavior will occur only if the encoded value has a registered
- * {@link ValueRenderer}. See the documentation for
- * <code>ValueRenderer</code> for more information.
- * </p>
- *
- * @param target
- * A mutable object into which a {@link ValueRenderer} <i>may</i>
- * decode this <code>Value</code>.
- *
- * @return The value as a Object.
- *
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent data
- * of a recognizable class.
- *
- * @throws MalformedValueException
- * if this <code>Value</code> is structurally corrupt.
- */
- public Object peek(final Object target) {
- return peek(target, null);
- }
-
- /**
- * <p>
- * Decodes the object value represented by the current state of this
- * <code>Value</code>. This method is identical to
- * {@link #get(Object, CoderContext)} except that in <a
- * href="#_streamMode">Stream Mode</a> the pointer to the next retrieved
- * value is not advanced.
- * </p>
- *
- * @param target
- * A mutable object into which a {@link ValueRenderer} <i>may</i>
- * decode this <code>Value</code>.
- *
- * @return The value as a Object.
- *
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent data
- * of a recognizable class.
- *
- * @throws MalformedValueException
- * if this <code>Value</code> is structurally corrupt.
- */
- public Object peek(final Object target, final CoderContext context) {
- final Object object;
- final int saveDepth = _depth;
- final int saveLevel = _level;
- final int saveNext = _next;
- final int saveEnd = _end;
- try {
- object = get(target, context);
- } finally {
- _end = saveEnd;
- _next = saveNext;
- _level = saveLevel;
- _depth = saveDepth;
- }
- return object;
- }
-
- /**
- * Decodes the object value represented by the current state of this
- * <code>Value</code>. If the represented value is primitive, this method
- * returns the wrapped object of the corresponding class. For example, if
- * the value represents an <code>int</code>, this method returns a
- * <code>java.lang.Integer</code>.
- *
- * @return The value as a Object.
- *
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent data
- * of a recognizable class.
- *
- * @throws MalformedValueException
- * if this <code>Value</code> is structurally corrupt.
- */
- public Object get() {
- return get(null, null);
- }
-
- /**
- * <p>
- * Decodes the object value represented by the current state of this
- * <code>Value</code>. If the represented value is primitive, this method
- * returns the wrapped object of the corresponding class. For example, if
- * the value represents an <code>int</code>, this method returns a
- * <code>java.lang.Integer</code>.
- * </p>
- * <p>
- * This variant of <code>get</code> <i>may</i> modify and return the target
- * object supplied as a parameter, rather than creating a new object. This
- * behavior will occur only if the encoded value has a registered
- * {@link ValueRenderer}. See the documentation for
- * <code>ValueRenderer</code> for more information.
- * </p>
- *
- * @param target
- * A mutable object into which a {@link ValueRenderer} <i>may</i>
- * decode this <code>Value</code>.
- *
- * @return The value as a Object.
- *
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent data
- * of a recognizable class.
- *
- * @throws MalformedValueException
- * if this <code>Value</code> is structurally corrupt.
- */
- public Object get(final Object target) {
- return get(target, null);
- }
-
- /**
- * <p>
- * Decodes the object value represented by the current state of this
- * <code>Value</code>. If the represented value is primitive, this method
- * returns the wrapped object of the corresponding class. For example, if
- * the value represents an <code>int</code>, this method returns a
- * <code>java.lang.Integer</code>.
- * </p>
- * <p>
- * This variant of <code>get</code> <i>may</i> modify and return the target
- * object supplied as a parameter, rather than creating a new object. This
- * behavior will occur only if the encoded value has an associated
- * {@link ValueRenderer} registered by {@link CoderManager}. See the
- * documentation for those classes for a detailed explanation of value
- * rendering.
- * </p>
- *
- * @param target
- * A mutable object into which a {@link ValueRenderer} <i>may</i>
- * decode this <code>Value</code>.
- *
- * @param context
- * An application-specified value that may assist a
- * {@link ValueCoder}. The context is passed to the
- * {@link ValueCoder#get} method.
- *
- * @return The value as a Object.
- *
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent data
- * of a recognizable class.
- *
- * @throws MalformedValueException
- * if this <code>Value</code> is structurally corrupt.
- */
- public Object get(final Object target, final CoderContext context) {
- Object object = null;
- final int start = _next;
- final int classHandle = nextType();
- final int currentItemCount = _serializedItemCount++;
-
- switch (classHandle) {
- case TYPE_NULL:
- break;
-
- case TYPE_BOOLEAN:
- case CLASS_BOOLEAN:
- object = getBooleanInternal() ? Boolean.TRUE : Boolean.FALSE;
- break;
-
- case TYPE_BYTE:
- case CLASS_BYTE:
- object = Byte.valueOf(getByteInternal());
- break;
-
- case TYPE_SHORT:
- case CLASS_SHORT:
- object = Short.valueOf(getShortInternal());
- break;
-
- case TYPE_CHAR:
- case CLASS_CHAR:
- object = Character.valueOf(getCharInternal());
- break;
-
- case TYPE_INT:
- case CLASS_INT:
- object = Integer.valueOf(getIntInternal());
- break;
-
- case TYPE_FLOAT:
- case CLASS_FLOAT:
- object = Float.valueOf(getFloatInternal());
- break;
-
- case TYPE_LONG:
- case CLASS_LONG:
- object = Long.valueOf(getLongInternal());
- break;
-
- case TYPE_DOUBLE:
- case CLASS_DOUBLE:
- object = Double.valueOf(getDoubleInternal());
- break;
-
- case CLASS_STRING: {
- if (target != null && target instanceof Appendable) {
- utfToAppendable((Appendable) target, _next, _end);
- object = target;
- } else {
- final StringBuilder sb = getStringAssemblyBuffer(_end - _next);
- utfToAppendable(sb, _next, _end);
- object = sb.toString();
- }
- closeVariableLengthItem();
- break;
- }
-
- case CLASS_DATE:
- final long time = Util.getLong(_bytes, _next);
- _next += 8;
- object = new Date(time);
- break;
-
- case CLASS_BIG_INTEGER: {
- final int length = _end - _next;
- final byte[] bytes = new byte[length];
- System.arraycopy(_bytes, _next, bytes, 0, length);
- _next += length;
- object = new BigInteger(bytes);
- closeVariableLengthItem();
- break;
- }
-
- case CLASS_ACCUMULATOR: {
- AccumulatorState accumulator;
- if (target != null && target instanceof AccumulatorState) {
- accumulator = (AccumulatorState) target;
- } else {
- accumulator = new AccumulatorState();
- }
- _depth++;
- try {
- accumulator.load(this);
- } finally {
- _depth--;
- }
- object = accumulator;
- break;
- }
-
- case CLASS_TREE_STATISTICS: {
- TreeStatistics treeStatistics;
- if (target != null && target instanceof TreeStatistics) {
- treeStatistics = (TreeStatistics) target;
- } else {
- treeStatistics = new TreeStatistics();
- }
- _next += treeStatistics.load(_bytes, _next, _end - _next);
- object = treeStatistics;
- break;
- }
-
- case CLASS_TREE: {
- if (target != null && target instanceof Tree) {
- final Tree tree = (Tree) target;
- _next += tree.load(_bytes, _next, _end - _next);
- object = tree;
- } else {
- final TreeState treeState = new TreeState();
- _next += treeState.load(_bytes, _next, _end - _next);
- object = treeState;
- }
- break;
- }
-
- case CLASS_BIG_DECIMAL: {
- final int length = _end - _next;
- final int scale = Util.getInt(_bytes, _next);
- final byte[] bytes = new byte[length - 4];
- System.arraycopy(_bytes, _next + 4, bytes, 0, length - 4);
- _next += length;
- object = new BigDecimal(new BigInteger(bytes), scale);
- closeVariableLengthItem();
- break;
- }
-
- case CLASS_ANTIVALUE: {
- final int length = _end - _next;
- int elisionCount = 0;
- byte[] bytes = null;
- if (length > 0) {
- elisionCount = Util.getShort(_bytes, _next);
- bytes = new byte[length - 2];
- System.arraycopy(_bytes, _next + 2, bytes, 0, length - 2);
- }
- _next += length;
- object = new AntiValue(elisionCount, bytes);
- closeVariableLengthItem();
- break;
- }
-
- case CLASS_ARRAY: {
- try {
- _depth++;
- final int componentClassHandle = nextType();
- switch (componentClassHandle) {
- case TYPE_BOOLEAN: {
- final boolean[] result = new boolean[_end - _next];
- for (int index = 0; index < result.length; index++) {
- result[index] = toBoolean(_next + index);
- }
- object = result;
- break;
- }
-
- case TYPE_BYTE: {
- final byte[] result = new byte[_end - _next];
- System.arraycopy(_bytes, _next, result, 0, _end - _next);
- object = result;
- break;
- }
-
- case TYPE_SHORT: {
- final short[] result = new short[arraySize(_end, _next, 2)];
- for (int index = 0; index < result.length; index++) {
- result[index] = (short) Util.getShort(_bytes, _next + (index * 2));
- }
- object = result;
- break;
- }
-
- case TYPE_CHAR: {
- final char[] result = new char[arraySize(_end, _next, 2)];
- for (int index = 0; index < result.length; index++) {
- result[index] = (char) Util.getChar(_bytes, _next + (index * 2));
- }
- object = result;
- break;
- }
-
- case TYPE_INT: {
- final int[] result = new int[arraySize(_end, _next, 4)];
- for (int index = 0; index < result.length; index++) {
- result[index] = Util.getInt(_bytes, _next + (index * 4));
- }
- object = result;
- break;
- }
-
- case TYPE_LONG: {
- final long[] result = new long[arraySize(_end, _next, 8)];
- for (int index = 0; index < result.length; index++) {
- result[index] = Util.getLong(_bytes, _next + (index * 8));
- }
- object = result;
- break;
- }
-
- case TYPE_FLOAT: {
- final float[] result = new float[arraySize(_end, _next, 4)];
- for (int index = 0; index < result.length; index++) {
- result[index] = Float.intBitsToFloat(Util.getInt(_bytes, _next + (index * 4)));
- }
- object = result;
- break;
- }
-
- case TYPE_DOUBLE: {
- final double[] result = new double[arraySize(_end, _next, 8)];
- for (int index = 0; index < result.length; index++) {
- result[index] = Double.longBitsToDouble(Util.getLong(_bytes, _next + (index * 8)));
- }
- object = result;
- break;
- }
-
- case CLASS_STRING: {
- final int length = decodeElementCount();
- final String[] result = new String[length];
- for (int index = 0; index < length; index++) {
- result[index] = getString();
- }
- object = result;
- break;
- }
-
- default: {
- final Class<?> componentClass = classForHandle(componentClassHandle);
- final int length = decodeElementCount();
- final Object[] result = (Object[]) Array.newInstance(componentClass, length);
- getValueCache().store(currentItemCount, result);
- for (int index = 0; index < length; index++) {
- Array.set(result, index, get(null, null));
- }
- object = result;
- break;
- }
- }
- } finally {
- _depth--;
- }
- closeVariableLengthItem();
- break;
-
- }
-
- case CLASS_MULTI_ARRAY:
- _next--;
- _serializedItemCount--;
- object = getMultiArray(null);
- break;
-
- case CLASS_SERIALIZED:
- _depth++;
- try {
- final ObjectInputStream ois = new OldValueInputStream(this);
- object = ois.readObject();
- if (_next != _end) {
- throw new ConversionException("Invalid serialized Object at index=" + _next);
- }
- closeVariableLengthItem();
- } catch (final IOException ioe) {
- throw new ConversionException("@" + start, ioe);
- } catch (final ClassNotFoundException cnfe) {
- throw new ConversionException("@" + start, cnfe);
- } finally {
- _depth--;
- }
-
- break;
-
- case CLASS_REREF: {
- final int base = _bytes[_next++] & 0xFF;
- final int handle = decodeVariableLengthInt(base);
- object = getValueCache().get(handle);
- break;
- }
-
- case TYPE_MVV: {
- final int savedSize = _size;
- final ArrayList<Object> outList = new ArrayList<Object>();
-
- try {
- _depth++;
-
- MVV.visitAllVersions(new MVV.VersionVisitor() {
- @Override
- public void init() {
- }
-
- @Override
- public void sawVersion(final long version, final int offset, final int valueLength) {
- Object obj = null;
- if (valueLength > 0) {
- _next = offset;
- _end = _size = _next + valueLength;
- obj = get(target, context);
- }
- outList.add(obj);
- }
-
- }, getEncodedBytes(), 0, getEncodedSize());
- } catch (final PersistitException pe) {
- throw new ConversionException("@" + start, pe);
- } finally {
- _depth--;
- _next = _end = _size = savedSize;
- }
-
- return outList.toArray();
- }
-
- default: {
- final int saveDepth = _depth;
- try {
- _depth++;
- final Class<?> cl = classForHandle(classHandle);
- final ValueCoder coder = getValueCoder(cl);
-
- if (coder != null) {
- if (target == null) {
- object = coder.get(this, cl, context);
- }
-
- else if (coder instanceof ValueRenderer) {
- ((ValueRenderer) coder).render(this, target, cl, context);
- object = target;
- } else {
- throw new ConversionException("No ValueRenderer for class " + cl.getName());
- }
- } else {
- throw new ConversionException("No ValueCoder for class " + cl.getName());
- }
- } finally {
- _depth = saveDepth;
- }
- closeVariableLengthItem();
- break;
- }
- }
- if (_depth > 0) {
- getValueCache().store(currentItemCount, object);
- } else {
- releaseValueCache();
- }
- return object;
- }
-
- private int arraySize(final int end, final int next, final int blockSize) {
- final int size = end - next;
- if ((size % blockSize) != 0) {
- throw new ConversionException("Invalid array size");
- }
- return size / blockSize;
- }
-
- private int utfToAppendable(final Appendable sb, final int offset, final int end) {
- final int counter = 0;
-
- for (int i = offset; i < end; i++) {
- final int b = _bytes[i] & 0xFF;
- int b2;
- int b3;
- switch (b >> 4) {
-
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- /* 0xxxxxxx */
- Util.append(sb, (char) b);
- break;
-
- case 12:
- case 13:
- /* 110x xxxx 10xx xxxx */
- i++;
- if (i >= _end) {
- throw new ConversionException();
- }
- b2 = _bytes[i];
- if ((b2 & 0xC0) != 0x80) {
- throw new ConversionException();
- }
- Util.append(sb, (char) (((b & 0x1F) << 6) | (b2 & 0x3F)));
- break;
-
- case 14:
- /* 1110 xxxx 10xx xxxx 10xx xxxx */
- i += 2;
- if (i >= _end) {
- throw new ConversionException();
- }
- b2 = _bytes[i - 1];
- b3 = _bytes[i];
- if (((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80)) {
- throw new ConversionException();
- }
- Util.append(sb, (char) (((b & 0x0F) << 12) | ((b2 & 0x3F) << 6) | ((b3 & 0x3F) << 0)));
- break;
-
- default:
- /* 10xx xxxx, 1111 xxxx */
- throw new ConversionException();
- }
- }
- return counter;
- }
-
- /**
- * Registers an object with an internal handle used to represent back
- * references. For example, suppose objects x and y have fields that refer
- * to each other. Then serializing x will serialize y, and the the reference
- * in y to x will be represented in the serialization stream by a back
- * reference handle. This method should be called from the
- * {@link ValueCoder#get(Value, Class, CoderContext)} method of custom
- * <code>ValueCoder</code>s. See <a
- * href="../../../Object_Serialization_Notes.html>Persistit 1.1 Object
- * Serialization</a> for further details.
- *
- * @param object
- * A newly created objected whose fields are about to be
- * deserialized
- */
- public void registerEncodedObject(final Object object) {
- if (_depth > 0) {
- getValueCache().store(_serializedItemCount - 1, object);
- }
- }
-
- /**
- * Registers a display marker with the current object handle.
- *
- * @param index
- * Current position in the output string
- */
- private void registerEncodedObject(final int index) {
- if (_depth > 0) {
- getValueCache().store(_serializedItemCount - 1, new DisplayMarker(index));
- }
- }
-
- /**
- * Decodes the <code>java.lang.String</code> value represented by the
- * current state of this <code>Value</code>.
- *
- * @return The value as a String.
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent a
- * String.
- */
- public String getString() {
- return (String) getExpectedType(String.class);
- }
-
- /**
- * Decodes the <code>java.lang.String</code> value represented by the
- * current state of this <code>Value</code> into a supplied
- * <code>java.lang.Appendable</code>.
- *
- * @return The supplied Appendable, modified to contain the decoded String
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent a
- * String.
- */
- public <T extends Appendable> Appendable getString(final T sb) {
- _serializedItemCount++;
- if (nextType(CLASS_STRING) == TYPE_NULL) {
- return null;
- }
- utfToAppendable(sb, _next, _end);
- closeVariableLengthItem();
- return sb;
- }
-
- /**
- * Decodes the <code>java.util.Date</code> value represented by the current
- * state of this <code>Value</code>.
- *
- * @return The value as a Date.
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent a
- * Date.
- */
- public Date getDate() {
- return (Date) getExpectedType(Date.class);
- }
-
- /**
- * Decodes the <code>java.math.BigInteger</code> value represented by the
- * current state of this <code>Value</code>.
- *
- * @return The value as a BigInteger.
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent a
- * BigInteger.
- */
- public BigInteger getBigInteger() {
- return (BigInteger) getExpectedType(BigInteger.class);
- }
-
- /**
- * Decodes the <code>java.math.BigDecimal</code> value represented by the
- * current state of this <code>Value</code>.
- *
- * @return The value as a BigDecimal.
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent a
- * BigDecimal.
- */
- public BigDecimal getBigDecimal() {
- return (BigDecimal) getExpectedType(BigDecimal.class);
- }
-
- /**
- * Returns the element count for the array represented by the current state
- * of this <code>Value</code>.
- *
- * @return The element count, or -1 if the Value represents
- * <code>null</code> rather than an array.
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent an
- * array.
- */
- public int getArrayLength() {
- final int start = _next;
- final int type = nextType(CLASS_ARRAY, CLASS_MULTI_ARRAY);
- if (type == TYPE_NULL)
- return -1;
- int componentClassHandle = -1;
- int result = -1;
- try {
- _depth++;
- componentClassHandle = nextType();
- if (type == CLASS_MULTI_ARRAY)
- _next++; // skip the dimension count.
- final int length = _end - _next;
- if (type == CLASS_ARRAY && componentClassHandle > 0 && componentClassHandle <= TYPE_DOUBLE
- && FIXED_ENCODING_SIZES[componentClassHandle] > 0) {
- result = length / FIXED_ENCODING_SIZES[componentClassHandle];
- } else {
- result = decodeElementCount();
- }
- } finally {
- closeVariableLengthItem();
- _depth--;
- _next = start;
- }
- return result;
- }
-
- /**
- * Decodes the array value represented by the current state of this
- * <code>Value</code>.
- *
- * @return The value as an Object that can be cast to an array.
- * @throws ConversionException
- * if this <code>Value</code> does not currently represent an
- * array.
- */
- public Object getArray() {
- final Object object = get(null, null);
- if (object == null || object.getClass().isArray()) {
- return object;
- }
- throw new ConversionException("Expected an array but value is a " + object.getClass().getName());
- }
-
- /**
- * Returns a <code>boolean</code> array representing the state of this
- * <code>Value</code>. Equivalent to </code>(boolean)[])get()</code>.
- *
- * @return The array.
- */
- public boolean[] getBooleanArray() {
- return (boolean[]) getExpectedType(boolean[].class);
- }
-
- /**
- * Copies a subarray of the <code>boolean</code> array represented by the
- * state of this <code>Value</code> into the supplied target array. The
- * subarray is bounded by <code>fromOffset</code> and <code>length</code>,
- * and truncated to fit within the target array.
- *
- * @param array
- * The target array
- * @param fromOffset
- * Offset of the first element within the source array to copy
- * from
- * @param toOffset
- * Offset of the first element within the target array to copy to
- * @param length
- * The maximum number of elements to copy.
- *
- * @return The number of elements actually copied, or -1 if the
- * <code>Value</code> object represents <code>null</code>.
- */
- public int getBooleanArray(final boolean[] array, final int fromOffset, final int toOffset, int length) {
- _serializedItemCount++;
- if (nextType(CLASS_ARRAY) == TYPE_NULL)
- return -1;
- try {
- _depth++;
- nextType(TYPE_BOOLEAN);
- final int sourceLength = _end - _next;
- if (length > sourceLength - fromOffset)
- length = sourceLength - fromOffset;
- if (length > array.length - toOffset)
- length = array.length - toOffset;
- for (int index = 0; index < length; index++) {
- array[toOffset + index] = toBoolean(index + fromOffset);
- }
- closeVariableLengthItem();
- return length;
- } finally {
- _depth--;
- }
- }
-
- /**
- * Returns a <code>byte</code> array representing the state of this
- * <code>Value</code>. Equivalent to </code>(byte[])get()</code>.
- *
- * @return The array.
- */
- public byte[] getByteArray() {
- return (byte[]) getExpectedType(byte[].class);
- }
-
- /**
- * Copies a subarray of the <code>byte</code> array represented by the state
- * of this <code>Value</code> into the supplied target array. The subarray
- * is bounded by <code>fromOffset</code> and <code>length</code>, and
- * truncated to fit within the target array.
- *
- * @param array
- * The target array
- * @param fromOffset
- * Offset of the first element within the source array to copy
- * from
- * @param toOffset
- * Offset of the first element within the target array to copy to
- * @param length
- * The maximum number of elements to copy.
- *
- * @return The number of elements actually copied, or -1 if the
- * <code>Value</code> object represents <code>null</code>.
- */
- public int getByteArray(final byte[] array, final int fromOffset, final int toOffset, int length) {
- _serializedItemCount++;
- if (array == _bytes) {
- throw new IllegalArgumentException("Can't overwrite encoded bytes");
- }
- if (nextType(CLASS_ARRAY) == TYPE_NULL)
- return -1;
- try {
- _depth++;
- nextType(TYPE_BYTE);
- final int sourceLength = _end - _next;
- if (length > sourceLength - fromOffset)
- length = sourceLength - fromOffset;
- if (length > array.length - toOffset)
- length = array.length - toOffset;
- if (length > 0)
- System.arraycopy(_bytes, _next + fromOffset, array, toOffset, length);
- closeVariableLengthItem();
- return length;
- } finally {
- _depth--;
- }
- }
-
- /**
- * Returns a <code>short</code> array representing the state of this
- * <code>Value</code>. Equivalent to </code>(short[])get()</code>.
- *
- * @return The array.
- */
- public short[] getShortArray() {
- return (short[]) getExpectedType(short[].class);
- }
-
- /**
- * Copies a subarray of the <code>short</code> array represented by the
- * state of this <code>Value</code> into the supplied target array. The
- * subarray is bounded by <code>fromOffset</code> and <code>length</code>,
- * and truncated to fit within the target array.
- *
- * @param array
- * The target array
- * @param fromOffset
- * Offset of the first element within the source array to copy
- * from
- * @param toOffset
- * Offset of the first element within the target array to copy to
- * @param length
- * The maximum number of elements to copy.
- *
- * @return The number of elements actually copied, or -1 if the
- * <code>Value</code> object represents <code>null</code>.
- */
- public int getShortArray(final short[] array, final int fromOffset, final int toOffset, int length) {
- _serializedItemCount++;
- if (nextType(CLASS_ARRAY) == TYPE_NULL)
- return -1;
- try {
- _depth++;
- nextType(TYPE_SHORT);
- final int sourceLength = (_end - _next) / 2;
- if (length > sourceLength - fromOffset)
- length = sourceLength - fromOffset;
- if (length > array.length - toOffset)
- length = array.length - toOffset;
- for (int index = 0; index < length; index++) {
- array[toOffset + index] = (short) Util.getShort(_bytes, _next + (index + fromOffset) * 2);
- }
- closeVariableLengthItem();
- return length;
- } finally {
- _depth--;
- }
- }
-
- /**
- * Returns a <code>char</code> array representing the state of this
- * <code>Value</code>. Equivalent to </code>(char[])get()</code>.
- *
- * @return The array.
- */
- public char[] getCharArray() {
- return (char[]) getExpectedType(char[].class);
- }
-
- /**
- * Copies a subarray of the <code>char</code> array represented by the state
- * of this <code>Value</code> into the supplied target array. The subarray
- * is bounded by <code>fromOffset</code> and <code>length</code>, and
- * truncated to fit within the target array.
- *
- * @param array
- * The target array
- * @param fromOffset
- * Offset of the first element within the source array to copy
- * from
- * @param toOffset
- * Offset of the first element within the target array to copy to
- * @param length
- * The maximum number of elements to copy.
- *
- * @return The number of elements actually copied, or -1 if the
- * <code>Value</code> object represents <code>null</code>.
- */
- public int getCharArray(final char[] array, final int fromOffset, final int toOffset, int length) {
- _serializedItemCount++;
- if (nextType(CLASS_ARRAY) == TYPE_NULL)
- return -1;
- try {
- _depth++;
- nextType(TYPE_CHAR);
- final int sourceLength = (_end - _next) / 2;
- if (length > sourceLength - fromOffset)
- length = sourceLength - fromOffset;
- if (length > array.length - toOffset)
- length = array.length - toOffset;
- for (int index = 0; index < length; index++) {
- array[toOffset + index] = (char) Util.getChar(_bytes, _next + (index + fromOffset) * 2);
- }
- closeVariableLengthItem();
- return length;
- } finally {
- _depth--;
- }
- }
-
- /**
- * Returns a <code>int</code> array representing the state of this
- * <code>Value</code>. Equivalent to </code>(int[])get()</code>.
- *
- * @return The array.
- */
- public int[] getIntArray() {
- return (int[]) getExpectedType(int[].class);
- }
-
- /**
- * Copies a subarray of the <code>int</code> array represented by the state
- * of this <code>Value</code> into the supplied target array. The subarray
- * is bounded by <code>fromOffset</code> and <code>length</code>, and
- * truncated to fit within the target array.
- *
- * @param array
- * The target array
- * @param fromOffset
- * Offset of the first element within the source array to copy
- * from
- * @param toOffset
- * Offset of the first element within the target array to copy to
- * @param length
- * The maximum number of elements to copy.
- *
- * @return The number of elements actually copied, or -1 if the
- * <code>Value</code> object represents <code>null</code>.
- */
- public int getIntArray(final int[] array, final int fromOffset, final int toOffset, int length) {
- _serializedItemCount++;
- if (nextType(CLASS_ARRAY) == TYPE_NULL)
- return -1;
- try {
- _depth++;
- nextType(TYPE_INT);
- final int sourceLength = (_end - _next) / 4;
- if (length > sourceLength - fromOffset)
- length = sourceLength - fromOffset;
- if (length > array.length - toOffset)
- length = array.length - toOffset;
- for (int index = 0; index < length; index++) {
- array[toOffset + index] = Util.getInt(_bytes, _next + (index + fromOffset) * 4);
- }
- closeVariableLengthItem();
- return length;
- } finally {
- _depth--;
- }
- }
-
- /**
- * Returns a <code>long</code> array representing the state of this
- * <code>Value</code>. Equivalent to </code>(long[])get()</code>.
- *
- * @return The array.
- */
- public long[] getLongArray() {
- return (long[]) getExpectedType(long[].class);
- }
-
- /**
- * Copies a subarray of the <code>long</code> array represented by the state
- * of this <code>Value</code> into the supplied target array. The subarray
- * is bounded by <code>fromOffset</code> and <code>length</code>, and
- * truncated to fit within the target array.
- *
- * @param array
- * The target array
- * @param fromOffset
- * Offset of the first element within the source array to copy
- * from
- * @param toOffset
- * Offset of the first element within the target array to copy to
- * @param length
- * The maximum number of elements to copy.
- *
- * @return The number of elements actually copied, or -1 if the
- * <code>Value</code> object represents <code>null</code>.
- */
- public int getLongArray(final long[] array, final int fromOffset, final int toOffset, int length) {
- _serializedItemCount++;
- if (nextType(CLASS_ARRAY) == TYPE_NULL)
- return -1;
- ;
- try {
- _depth++;
- nextType(TYPE_LONG);
- final int sourceLength = (_end - _next) / 8;
- if (length > sourceLength - fromOffset)
- length = sourceLength - fromOffset;
- if (length > array.length - toOffset)
- length = array.length - toOffset;
- for (int index = 0; index < length; index++) {
- array[toOffset + index] = Util.getLong(_bytes, _next + (index + fromOffset) * 8);
- }
- closeVariableLengthItem();
- return length;
- } finally {
- _depth--;
- }
- }
-
- /**
- * Returns a <code>float</code> array representing the state of this
- * <code>Value</code>. Equivalent to </code>(float[])get()</code>.
- *
- * @return The array.
- */
- public float[] getFloatArray() {
- return (float[]) getExpectedType(float[].class);
- }
-
- /**
- * Copies a subarray of the <code>float</code> array represented by the
- * state of this <code>Value</code> into the supplied target array. The
- * subarray is bounded by <code>fromOffset</code> and <code>length</code>,
- * and truncated to fit within the target array.
- *
- * @param array
- * The target array
- * @param fromOffset
- * Offset of the first element within the source array to copy
- * from
- * @param toOffset
- * Offset of the first element within the target array to copy to
- * @param length
- * The maximum number of elements to copy.
- *
- * @return The number of elements actually copied, or -1 if the
- * <code>Value</code> object represents <code>null</code>.
- */
- public int getFloatArray(final float[] array, final int fromOffset, final int toOffset, int length) {
- _serializedItemCount++;
- if (nextType(CLASS_ARRAY) == TYPE_NULL)
- return -1;
- try {
- _depth++;
- nextType(TYPE_FLOAT);
- final int sourceLength = (_end - _next) / 4;
- if (length > sourceLength - fromOffset)
- length = sourceLength - fromOffset;
- if (length > array.length - toOffset)
- length = array.length - toOffset;
- for (int index = 0; index < length; index++) {
- array[toOffset + index] = Float.intBitsToFloat(Util.getInt(_bytes, _next + (index + fromOffset) * 4));
- }
- closeVariableLengthItem();
- return length;
- } finally {
- _depth--;
- }
- }
-
- /**
- * Returns a <code>double</code> array representing the state of this
- * <code>Value</code>. Equivalent to </code>(double[])get()</code>.
- *
- * @return The array.
- */
- public double[] getDoubleArray() {
- return (double[]) getExpectedType(double[].class);
- }
-
- /**
- * Copies a subarray of the <code>double</code> array represented by the
- * state of this <code>Value</code> into the supplied target array. The
- * subarray is bounded by <code>fromOffset</code> and <code>length</code>,
- * and truncated to fit within the target array.
- *
- * @param array
- * The target array
- * @param fromOffset
- * Offset of the first element within the source array to copy
- * from
- * @param toOffset
- * Offset of the first element within the target array to copy to
- * @param length
- * The maximum number of elements to copy.
- *
- * @return The number of elements actually copied, or -1 if the
- * <code>Value</code> object represents <code>null</code>.
- */
- public int getDoubleArray(final double[] array, final int fromOffset, final int toOffset, int length) {
- _serializedItemCount++;
- if (nextType(CLASS_ARRAY) == TYPE_NULL)
- return -1;
- try {
- _depth++;
- nextType(TYPE_DOUBLE);
- final int sourceLength = (_end - _next) / 8;
- if (length > sourceLength - fromOffset)
- length = sourceLength - fromOffset;
- if (length > array.length - toOffset)
- length = array.length - toOffset;
- for (int index = 0; index < length; index++) {
- array[toOffset + index] = Double.longBitsToDouble(Util
- .getLong(_bytes, _next + (index + fromOffset) * 8));
- }
- closeVariableLengthItem();
- return length;
- } finally {
- _depth--;
- }
- }
-
- /**
- * Returns a <code>Object</code> array representing the state of this
- * <code>Value</code>. This is equivalent to
- * </code>(Object[])getArray()</code>.
- *
- * @return The array.
- */
- public Object[] getObjectArray() {
- return (Object[]) getExpectedType(Object[].class);
- }
-
- /**
- * Returns a <code>Object</code> array representing the state of this
- * <code>Value</code>. This is equivalent to
- * </code>(Object[])getArray()</code>.
- *
- * @return The array.
- */
- public String[] getStringArray() {
- return (String[]) getExpectedType(String[].class);
- }
-
- /**
- * Indicates whether there is at least one more item in this
- * <code>Value</code>. This method is valid only if the Value is in <a
- * href="#_streamMode">Stream Mode</a>. (See {@link #isStreamMode}.)
- *
- * @return <code>true</code> if another item can be decoded from this
- * <code>Value</code>.
- */
- public boolean hasMoreItems() {
- return _next < _end;
- }
-
- /**
- * Replaces the current state with the supplied <code>boolean</code> value
- * (or in <a href="#_streamMode">stream mode</a>, appends a new field
- * containing this value to the state).
- *
- * @param booleanValue
- * The new value
- */
- public void put(final boolean booleanValue) {
- preparePut();
- ensureFit(2);
- _bytes[_size++] = (byte) TYPE_BOOLEAN;
- _bytes[_size++] = (byte) (booleanValue ? TRUE_CHAR : FALSE_CHAR);
- _serializedItemCount++;
- }
-
- /**
- * Replaces the current state with the supplied <code>byte</code> value (or
- * in <a href="#_streamMode">stream mode</a>, appends a new field containing
- * this value to the state).
- *
- * @param byteValue
- * The new value
- */
- public void put(final byte byteValue) {
- preparePut();
- ensureFit(2);
- _bytes[_size++] = (byte) TYPE_BYTE;
- _bytes[_size++] = byteValue;
- _serializedItemCount++;
- }
-
- /**
- * Replaces the current state with the supplied <code>short</code> value (or
- * in <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this value to the state).
- *
- * @param shortValue
- * The new value
- */
- public void put(final short shortValue) {
- preparePut();
- ensureFit(3);
- _bytes[_size++] = (byte) TYPE_SHORT;
- Util.putShort(_bytes, _size, shortValue);
- _size += 2;
- _serializedItemCount++;
- }
-
- /**
- * Replaces the current state with the supplied <code>char</code> value (or
- * in <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this value to the state).
- *
- * @param charValue
- * The new value
- */
- public void put(final char charValue) {
- preparePut();
- ensureFit(3);
- _bytes[_size++] = (byte) TYPE_CHAR;
- Util.putChar(_bytes, _size, charValue);
- _size += 2;
- _serializedItemCount++;
- }
-
- /**
- * Replaces the current state with the supplied <code>int</code> value (or
- * in <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this value to the state).
- *
- * @param intValue
- * The new value
- */
- public void put(final int intValue) {
- preparePut();
- ensureFit(5);
- _bytes[_size++] = (byte) TYPE_INT;
- Util.putInt(_bytes, _size, intValue);
- _size += 4;
- _serializedItemCount++;
- }
-
- /**
- * Replaces the current state with the supplied <code>long</code> value (or
- * in <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this value to the state).
- *
- * @param longValue
- * The new value
- */
- public void put(final long longValue) {
- preparePut();
- ensureFit(9);
- _bytes[_size++] = (byte) TYPE_LONG;
- Util.putLong(_bytes, _size, longValue);
- _size += 8;
- _serializedItemCount++;
- }
-
- /**
- * Replaces the current state with the supplied <code>float</code> value (or
- * in <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this value to the state).
- *
- * @param floatValue
- * The new value
- */
- public void put(final float floatValue) {
- preparePut();
- ensureFit(5);
- _bytes[_size++] = (byte) TYPE_FLOAT;
- Util.putInt(_bytes, _size, Float.floatToIntBits(floatValue));
- _size += 4;
- _serializedItemCount++;
- }
-
- /**
- * Replaces the current state with the supplied <code>double</code> value
- * (or in <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this value to the state).
- *
- * @param doubleValue
- * The new value
- */
- public void put(final double doubleValue) {
- preparePut();
- ensureFit(9);
- _bytes[_size++] = (byte) TYPE_DOUBLE;
- Util.putLong(_bytes, _size, Double.doubleToLongBits(doubleValue));
- _size += 8;
- _serializedItemCount++;
- }
-
- /**
- * Replaces the current state with the supplied <code>Object</code> (or in
- * <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this value to the state).
- *
- * @param object
- * The new value. The supplied Object must be <i>null</i>, or it
- * must implement <code>java.io.Serializable</code> or
- * <code>java.io.Externalizable</code>, or it must be handled by
- * a registered {@link com.persistit.encoding.ValueCoder}.
- *
- * @throws ConversionException
- * if the Object cannot be encoded as a sequence of bytes.
- */
- public void put(final Object object) {
- put(object, null);
- }
-
- /**
- * Replaces the current state with the supplied <code>Object</code> (or in
- * <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this value to the state).
- *
- * @param object
- * The new value. The supplied Object must be <i>null</i>, or it
- * must implement <code>java.io.Serializable</code> or
- * <code>java.io.Externalizable</code>, or it must be handled by
- * a registered {@link com.persistit.encoding.ValueCoder}.
- *
- * @param context
- * An application-specified value that may assist a
- * {@link ValueCoder}. The context is passed to the
- * {@link ValueCoder#put} method.
- *
- * @throws ConversionException
- * if the Object cannot be encoded as a sequence of bytes.
- */
- public void put(Object object, final CoderContext context) {
- preparePut();
- final int currentItemCount = _serializedItemCount++;
-
- if (object == null) {
- ensureFit(1);
- _bytes[_size++] = TYPE_NULL;
- return;
- }
- if (_depth > 0 && _shared) {
- final int serializationHandle = getValueCache().put(currentItemCount, object);
- if (serializationHandle != -1) {
- ensureFit(5);
- _bytes[_size++] = (byte) CLASS_REREF;
- _size += encodeVariableLengthInt(0, _size, serializationHandle);
- return;
- }
- }
- Class<?> cl = object.getClass();
- if (cl == String.class) {
- final String string = (String) object;
- putUTF(string);
- } else if (cl == Date.class) {
- ensureFit(9);
- _bytes[_size++] = CLASS_DATE;
- Util.putLong(_bytes, _size, ((Date) object).getTime());
- _size += 8;
- } else if (cl == BigInteger.class) {
- final byte[] bytes = ((BigInteger) object).toByteArray();
- final int length = bytes.length;
- ensureFit(length + 2);
- int index = _size;
- _bytes[index++] = CLASS_BIG_INTEGER;
- System.arraycopy(bytes, 0, _bytes, index, length);
- _size = index + length;
- endVariableSizeItem(length + 1);
-
- } else if (cl == BigDecimal.class) {
- final BigDecimal bigDecimalValue = (BigDecimal) object;
- final BigInteger unscaled = bigDecimalValue.unscaledValue();
- final byte[] bytes = unscaled.toByteArray();
- final int length = bytes.length;
- ensureFit(length + 8);
- int index = _size;
- _bytes[index++] = CLASS_BIG_DECIMAL;
- Util.putInt(_bytes, index, bigDecimalValue.scale());
- index += 4;
- System.arraycopy(bytes, 0, _bytes, index, length);
- _size = index + length;
- endVariableSizeItem(length + 5);
- }
- //
- // All Primitive wrapper classes go here.
- //
- else if (cl == Boolean.class) {
- ensureFit(2);
- _bytes[_size++] = (byte) CLASS_BOOLEAN;
- _bytes[_size++] = (byte) (((Boolean) object).booleanValue() ? TRUE_CHAR : FALSE_CHAR);
- } else if (cl == Byte.class) {
- ensureFit(2);
- _bytes[_size++] = (byte) CLASS_BYTE;
- _bytes[_size++] = ((Byte) object).byteValue();
- } else if (cl == Short.class) {
- ensureFit(3);
- _bytes[_size++] = (byte) CLASS_SHORT;
- Util.putShort(_bytes, _size, ((Short) object).shortValue());
- _size += 2;
- } else if (cl == Character.class) {
- ensureFit(3);
- _bytes[_size++] = (byte) CLASS_CHAR;
- Util.putChar(_bytes, _size, ((Character) object).charValue());
- _size += 2;
- } else if (cl == Integer.class) {
- ensureFit(5);
- _bytes[_size++] = (byte) CLASS_INT;
- Util.putInt(_bytes, _size, ((Integer) object).intValue());
- _size += 4;
- } else if (cl == Long.class) {
- ensureFit(9);
- _bytes[_size++] = (byte) CLASS_LONG;
- Util.putLong(_bytes, _size, ((Long) object).longValue());
- _size += 8;
- } else if (cl == Float.class) {
- ensureFit(5);
- _bytes[_size++] = (byte) CLASS_FLOAT;
- Util.putInt(_bytes, _size, Float.floatToRawIntBits(((Float) object).floatValue()));
- _size += 4;
- } else if (cl == Double.class) {
- ensureFit(9);
- _bytes[_size++] = (byte) CLASS_DOUBLE;
- Util.putLong(_bytes, _size, Double.doubleToRawLongBits(((Double) object).doubleValue()));
- _size += 8;
- } else if (object instanceof Accumulator) {
- ensureFit(Accumulator.MAX_SERIALIZED_SIZE);
- _bytes[_size++] = (byte) CLASS_ACCUMULATOR;
- _depth++;
- try {
- ((Accumulator) object).store(this);
- } finally {
- _depth--;
- }
- } else if (cl == TreeStatistics.class) {
- ensureFit(TreeStatistics.MAX_SERIALIZED_SIZE);
- _bytes[_size++] = (byte) CLASS_TREE_STATISTICS;
- _size += ((TreeStatistics) object).store(_bytes, _size);
- } else if (cl == Tree.class) {
- ensureFit(Tree.MAX_SERIALIZED_SIZE);
- _bytes[_size++] = (byte) CLASS_TREE;
- _size += ((Tree) object).store(_bytes, _size);
- } else if (cl.isArray()) {
- final Class<?> componentClass = cl.getComponentType();
- final int length = Array.getLength(object);
- if (componentClass.isPrimitive()) {
- if (componentClass == Boolean.TYPE) {
- putBooleanArray1((boolean[]) object, 0, length);
- } else if (componentClass == Byte.TYPE) {
- putByteArray1((byte[]) object, 0, length);
- } else if (componentClass == Short.TYPE) {
- putShortArray1((short[]) object, 0, length);
- } else if (componentClass == Character.TYPE) {
- putCharArray1((char[]) object, 0, length);
- } else if (componentClass == Integer.TYPE) {
- putIntArray1((int[]) object, 0, length);
- } else if (componentClass == Long.TYPE) {
- putLongArray1((long[]) object, 0, length);
- } else if (componentClass == Float.TYPE) {
- putFloatArray1((float[]) object, 0, length);
- } else if (componentClass == Double.TYPE) {
- putDoubleArray1((double[]) object, 0, length);
- }
- } else {
- putObjectArray1((Object[]) object, 0, length);
- }
- }
-
- else {
- ensureFit(6);
- final int start = _size;
- int end = start;
- boolean replaced = false;
-
- try {
- if (_shared && _depth == 0) {
- getValueCache().put(currentItemCount, object);
- }
- _depth++;
- ValueCoder coder = getValueCoder(cl);
-
- while (coder instanceof DefaultObjectCoder) {
- final Object replacement = ((DefaultObjectCoder) coder).writeReplace(this, object);
-
- if (replacement == object)
- break;
-
- replaced = true;
-
- if (replacement != null) {
- object = replacement;
- cl = replacement.getClass();
- coder = getValueCoder(cl);
- } else {
- break;
- }
- }
-
- if (replaced) {
- put(object, context);
- end = _size;
- } else {
- int handle;
- if (cl == Object.class) {
- handle = CLASS_OBJECT;
- } else handle = handleForClass(cl);
-
- if (coder != null) {
- _size += encodeVariableLengthInt(CLASS1, _size, handle - CLASS1);
- coder.put(this, object, context);
- end = _size;
- } else {
- _bytes[_size++] = CLASS_SERIALIZED;
- final ObjectOutputStream oos = new OldValueOutputStream(this);
- oos.writeObject(object);
- oos.close();
- end = _size;
- }
- }
- } catch (final IOException ioe) {
- throw new ConversionException(ioe);
- } finally {
- _depth--;
- //
- // Restores _size to original value in the event of an
- // exception.
- // No-op on successful completion, because end will be equal to
- // the updated value of _size. This is kludgey, but it gets
- // the semantics right.
- //
- _size = end;
- }
- if (!replaced)
- endVariableSizeItem(_size - start);
- }
- if (_depth == 0) {
- releaseValueCache();
- }
- }
-
- /**
- * Replaces the current state with <i>null</i> (or in <i><a
- * href="#_streamMode">stream mode</a></i>, appends a null to the state).
- */
- public void putNull() {
- put(null, null);
- }
-
- /**
- * Replaces the current state with the supplied
- * <code>java.lang.String</code> (or in <i><a href="#_streamMode">stream
- * mode</a></i>, appends a new field containing this value to the state).
- *
- * @param string
- * The new value
- */
- public void putString(final String string) {
- put(string, null);
- }
-
- /**
- * Replaces the current state with the supplied
- * <code>java.lang.String</code> (or in <i><a href="#_streamMode">stream
- * mode</a></i>, appends a new field containing this value to the state).
- * Unlike <code>putString</code>, this method always writes a new copy of
- * the String rather than a reference to a previously written value. Thus on
- * deserialization, two copies of the same string written by this method
- * will result in two unique String objects.
- *
- * @param string
- * The new value
- */
- public void putUTF(final String string) {
- preparePut();
- putCharSequenceInternal(string);
- }
-
- /**
- * Replaces the current state with the String represented by the supplied
- * CharSequence (or in <i><a href="#_streamMode">stream mode</a></i>,
- * appends a new field containing this value to the state).
- *
- * @param sb
- * The String value as a CharSequence
- */
- public void putString(final CharSequence sb) {
- if (sb == null) {
- putNull();
- } else {
- _serializedItemCount++;
- preparePut();
- putCharSequenceInternal(sb);
- }
- }
-
- /**
- * Replaces the current state with the supplied <code>java.util.Date</code>
- * (or in <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this value to the state).
- *
- * @param dateValue
- * The new value
- */
- public void putDate(final Date dateValue) {
- put(dateValue, null);
- }
-
- /**
- * Replaces the current state with the supplied
- * <code>java.math.BigInteger</code> (or in <i><a href="#_streamMode">stream
- * mode</a></i>, appends a new field containing this value to the state).
- *
- * @param bigIntValue
- * The new value
- */
- public void putBigInteger(final BigInteger bigIntValue) {
- put(bigIntValue, null);
- }
-
- /**
- * Replaces the current state with the supplied
- * <code>java.math.BigDecimal</code> (or in <i><a href="#_streamMode">stream
- * mode</a></i>, appends a new field containing this value to the state).
- *
- * @param bigDecimalValue
- * The new value
- */
- public void putBigDecimal(final BigDecimal bigDecimalValue) {
- put(bigDecimalValue, null);
- }
-
- /**
- * Replaces the current state with the supplied <code>boolean</code> (or in
- * <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this array to the state).
- *
- * @param array
- * The new array value
- */
- public void putBooleanArray(final boolean[] array) {
- put(array, null);
- }
-
- /**
- * Replaces the current state with a subarray of the supplied array of
- * <code>boolean</code>-valued elements (or in <i><a
- * href="#_streamMode">stream mode</a></i>, appends a new field containing
- * this subarray to the state).
- *
- * @param array
- * The array
- * @param offset
- * Offset of the subarray in <code>array</code>
- * @param length
- * Length of the subarray
- */
- public void putBooleanArray(final boolean[] array, final int offset, final int length) {
- checkArrayLength(length, offset, array.length);
- preparePut();
- putBooleanArray1(array, offset, length);
- }
-
- private void putBooleanArray1(final boolean[] array, final int offset, final int length) {
- ensureFit(length + 2);
- _bytes[_size++] = CLASS_ARRAY;
- _bytes[_size++] = TYPE_BOOLEAN;
- for (int index = 0; index < length; index++) {
- Util.putByte(_bytes, _size, array[index + offset] ? TRUE_CHAR : FALSE_CHAR);
- _size++;
- }
- endVariableSizeItem(length + 2);
- }
-
- /**
- * Replaces the current state with the supplied <code>byte</code> array, (or
- * in <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this array to the state).
- *
- * @param array
- * The new array value
- */
- public void putByteArray(final byte[] array) {
- put(array, null);
- }
-
- /**
- * Replaces the current state with a subarray of the supplied array of
- * <code>byte</code>-valued elements (or in <i><a href="#_streamMode">stream
- * mode</a></i>, appends a new field containing this subarray to the state).
- *
- * @param array
- * The array
- * @param offset
- * Offset of the subarray in <code>array</code>
- * @param length
- * Length of the subarray
- */
- public void putByteArray(final byte[] array, final int offset, final int length) {
- checkArrayLength(length, offset, array.length);
- preparePut();
- putByteArray1(array, offset, length);
- }
-
- private void putByteArray1(final byte[] array, final int offset, final int length) {
- ensureFit(length + 2);
- int index = _size;
- _bytes[index++] = CLASS_ARRAY;
- _bytes[index++] = TYPE_BYTE;
- System.arraycopy(array, offset, _bytes, index, length);
- _size = index + length;
- endVariableSizeItem(length + 2);
- }
-
- /**
- * Replaces the current state with the supplied <code>short</code> array (or
- * in <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this array to the state).
- *
- * @param array
- * The new array value
- */
- public void putShortArray(final short[] array) {
- put(array, null);
- }
-
- /**
- * Replaces the current state with a subarray of the supplied array of
- * <code>short</code>-valued elements (or in <i><a
- * href="#_streamMode">stream mode</a></i>, appends a new field containing
- * this subarray to the state).
- *
- * @param array
- * The array
- * @param offset
- * Offset of the subarray in <code>array</code>
- * @param length
- * Length of the subarray
- */
- public void putShortArray(final short[] array, final int offset, final int length) {
- checkArrayLength(length, offset, array.length);
- preparePut();
- putShortArray1(array, offset, length);
- }
-
- void putShortArray1(final short[] array, final int offset, final int length) {
- ensureFit(length * 2 + 2);
- _bytes[_size++] = CLASS_ARRAY;
- _bytes[_size++] = TYPE_SHORT;
- for (int index = 0; index < length; index++) {
- Util.putShort(_bytes, _size, array[index + offset]);
- _size += 2;
- }
- endVariableSizeItem((length * 2) + 2);
- }
-
- /**
- * Replaces the current state with the supplied <code>char</code> array (or
- * in <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this array to the state).
- *
- * @param array
- * The new array value
- */
- public void putCharArray(final char[] array) {
- put(array, null);
- }
-
- /**
- * Replaces the current state with a subarray of the supplied array of
- * <code>char</code>-valued elements (or in <i><a href="#_streamMode">stream
- * mode</a></i>, appends a new field containing this subarray to the state).
- *
- * @param array
- * The array
- * @param offset
- * Offset of the subarray in <code>array</code>
- * @param length
- * Length of the subarray
- */
- public void putCharArray(final char[] array, final int offset, final int length) {
- checkArrayLength(length, offset, array.length);
- preparePut();
- putCharArray1(array, offset, length);
- }
-
- private void putCharArray1(final char[] array, final int offset, final int length) {
- ensureFit(length * 2 + 2);
- _bytes[_size++] = CLASS_ARRAY;
- _bytes[_size++] = TYPE_CHAR;
- for (int index = 0; index < length; index++) {
- Util.putChar(_bytes, _size, array[index + offset]);
- _size += 2;
- }
- endVariableSizeItem((length * 2) + 2);
- }
-
- /**
- * Replaces the current state with the supplied <code>int</code> array (or
- * in <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this array to the state).
- *
- * @param array
- * The new array value
- */
- public void putIntArray(final int[] array) {
- put(array, null);
- }
-
- /**
- * Replaces the current state with a subarray of the supplied array of
- * <code>int</code>-valued elements (or in <i><a href="#_streamMode">stream
- * mode</a></i>, appends a new field containing this subarray to the state).
- *
- * @param array
- * The array
- * @param offset
- * Offset of the subarray in <code>array</code>
- * @param length
- * Length of the subarray
- */
- public void putIntArray(final int[] array, final int offset, final int length) {
- checkArrayLength(length, offset, array.length);
- preparePut();
- putIntArray1(array, offset, length);
- }
-
- private void putIntArray1(final int[] array, final int offset, final int length) {
- ensureFit(length * 4 + 2);
- _bytes[_size++] = CLASS_ARRAY;
- _bytes[_size++] = TYPE_INT;
- for (int index = 0; index < length; index++) {
- Util.putInt(_bytes, _size, array[index + offset]);
- _size += 4;
- }
- endVariableSizeItem((length * 4) + 2);
- }
-
- /**
- * Replaces the current state with the supplied <code>long</code> array (or
- * in <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this array to the state).
- *
- * @param array
- * The new array value
- */
- public void putLongArray(final long[] array) {
- put(array, null);
- }
-
- /**
- * Replaces the current state with a subarray of the supplied array of
- * <code>long</code>-valued elements (or in <i><a href="#_streamMode">stream
- * mode</a></i>, appends a new field containing this subarray to the state).
- *
- * @param array
- * The array
- * @param offset
- * Offset of the subarray in <code>array</code>
- * @param length
- * Length of the subarray
- */
- public void putLongArray(final long[] array, final int offset, final int length) {
- checkArrayLength(length, offset, array.length);
- preparePut();
- putLongArray1(array, offset, length);
- }
-
- private void putLongArray1(final long[] array, final int offset, final int length) {
- ensureFit(length * 8 + 2);
- _bytes[_size++] = CLASS_ARRAY;
- _bytes[_size++] = TYPE_LONG;
- for (int index = 0; index < length; index++) {
- Util.putLong(_bytes, _size, array[index + offset]);
- _size += 8;
- }
- endVariableSizeItem((length * 8) + 2);
- }
-
- /**
- * Replaces the current state with the supplied <code>float</code> array (or
- * in <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this array to the state).
- *
- * @param array
- * The new array value
- */
- public void putFloatArray(final float[] array) {
- put(array, null);
- }
-
- /**
- * Replaces the current state with a subarray of the supplied array of
- * <code>float</code>-valued elements (or in <i><a
- * href="#_streamMode">stream mode</a></i>, appends a new field containing
- * this subarray to the state).
- *
- * @param array
- * The array
- * @param offset
- * Offset of the subarray in <code>array</code>
- * @param length
- * Length of the subarray
- */
- public void putFloatArray(final float[] array, final int offset, final int length) {
- checkArrayLength(length, offset, array.length);
- preparePut();
- putFloatArray1(array, offset, length);
- }
-
- private void putFloatArray1(final float[] array, final int offset, final int length) {
- ensureFit(length * 4 + 2);
- _bytes[_size++] = CLASS_ARRAY;
- _bytes[_size++] = TYPE_FLOAT;
- for (int index = 0; index < length; index++) {
- Util.putInt(_bytes, _size, Float.floatToRawIntBits(array[index + offset]));
- _size += 4;
- }
- endVariableSizeItem((length * 4) + 2);
- }
-
- /**
- * Replaces the current state with the supplied <code>double</code> array
- * (or in <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this array to the state).
- *
- * @param array
- * The new array value
- */
- public void putDoubleArray(final double[] array) {
- put(array, null);
- }
-
- /**
- * Replaces the current state with a subarray of the supplied array of
- * <code>double</code>-valued elements (or in <i><a
- * href="#_streamMode">stream mode</a></i>, appends a new field containing
- * this subarray to the state).
- *
- * @param array
- * The array
- * @param offset
- * Offset of the subarray in <code>array</code>
- * @param length
- * Length of the subarray
- */
- public void putDoubleArray(final double[] array, final int offset, final int length) {
- checkArrayLength(length, offset, array.length);
- preparePut();
- putDoubleArray1(array, offset, length);
- }
-
- private void putDoubleArray1(final double[] array, final int offset, final int length) {
- ensureFit(length * 8 + 2);
- _bytes[_size++] = CLASS_ARRAY;
- _bytes[_size++] = TYPE_DOUBLE;
- for (int index = 0; index < length; index++) {
- Util.putLong(_bytes, _size, Double.doubleToRawLongBits(array[index + offset]));
- _size += 8;
- }
- endVariableSizeItem((length * 8) + 2);
- }
-
- /**
- * Replaces the current state with the supplied <code>String</code> array
- * (or in <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this array to the state).
- *
- * @param array
- * The new array value
- */
- public void putStringArray(final String[] array) {
- put(array, null);
- }
-
- /**
- * Replaces the current state with a subarray of the supplied array of
- * <code>String</code>-valued elements (or in <i><a
- * href="#_streamMode">stream mode</a></i>, appends a new field containing
- * this subarray to the state).
- *
- * @param array
- * The array
- * @param offset
- * Offset of the subarray in <code>array</code>
- * @param length
- * Length of the subarray
- */
- public void putStringArray(final String[] array, final int offset, final int length) {
- checkArrayLength(length, offset, array.length);
- preparePut();
- ensureFit(7 + length);
- final int start = _size;
- _bytes[_size++] = CLASS_ARRAY;
- _bytes[_size++] = CLASS_STRING;
- _size += encodeVariableLengthInt(COUNT1, _size, length);
- for (int index = 0; index < length; index++) {
- try {
- _depth++;
- putString(array[index + offset]);
- } finally {
- _depth--;
- }
- }
- endVariableSizeItem(_size - start);
- }
-
- /**
- * Replaces the current state with the supplied <code>Object</code> array
- * (or in <i><a href="#_streamMode">stream mode</a></i>, appends a new field
- * containing this array to the state).
- *
- * @param array
- * The new array value
- */
- public void putObjectArray(final Object[] array) {
- put(array, null);
- }
-
- /**
- * Replaces the current state with a subarray of the supplied array of
- * <code>Object</code>-valued elements (or in <i><a
- * href="#_streamMode">stream mode</a></i>, appends a new field containing
- * this subarray to the state).
- *
- * @param array
- * The array
- * @param offset
- * Offset of the subarray in <code>array</code>
- * @param length
- * Length of the subarray
- */
- public void putObjectArray(final Object[] array, final int offset, final int length) {
- preparePut();
- putObjectArray1(array, offset, length);
- }
-
- /**
- * Does nothing except when this <code>Value</code> is in <i>stream
- * mode</i>. In stream mode, this method skips a field. It is generally
- * faster to <code>skip</code> a field rather than to <code>get</code> and
- * discard it because the value and its interior state do not actually need
- * to be decoded and constructed.
- */
- public void skip() {
- if (_depth == 0) {
- return;
- }
- final int currentHandle = _serializedItemCount++;
- final int saveNext = _next;
- final int saveEnd = _end;
- final int classHandle = nextType();
- if (classHandle == 0)
- return;
- int size = -1;
- if (classHandle < FIXED_ENCODING_SIZES.length) {
- size = FIXED_ENCODING_SIZES[classHandle];
- } else if (classHandle == CLASS_REREF) {
- final int base = _bytes[_next++] & 0xFF;
- decodeVariableLengthInt(base);
- size = 0;
- }
-
- if (size >= 0) {
- _next += size;
- } else {
- getValueCache().put(currentHandle, new SkippedFieldMarker(this, saveNext, saveEnd));
- closeVariableLengthItem();
- }
- }
-
- private void putObjectArray1(final Object[] array, final int offset, final int length) {
- int dimensions = 1;
- Class<?> componentType = array.getClass().getComponentType();
-
- while (componentType.isArray()) {
- componentType = componentType.getComponentType();
- dimensions++;
- }
- checkArrayLength(length, offset, array.length);
- final int start = _size;
- ensureFit(12);
- _bytes[_size++] = (byte) (dimensions == 1 ? CLASS_ARRAY : CLASS_MULTI_ARRAY);
- encodeClass(componentType);
- if (dimensions != 1) {
- _bytes[_size++] = (byte) dimensions;
- }
- _size += encodeVariableLengthInt(COUNT1, _size, length);
- for (int index = 0; index < length; index++) {
- try {
- _depth++;
- put(array[index + offset]);
- } finally {
- _depth--;
- }
- }
- endVariableSizeItem(_size - start);
- }
-
- void putAntiValue(final short elisionCount, final byte[] bytes) {
- preparePut();
- final int start = _size;
- ensureFit(8 + bytes.length);
- _bytes[_size++] = (byte) CLASS_ANTIVALUE;
- Util.putShort(_bytes, _size, elisionCount);
- _size += Util.putBytes(_bytes, _size + 2, bytes) + 2;
- endVariableSizeItem(_size - start);
- }
-
- void putAntiValueMVV() {
- preparePut();
- ensureFit(1);
- _bytes[_size++] = (byte) CLASS_ANTIVALUE;
- _serializedItemCount++;
- }
-
- /**
- * Optimized put method to be used in specialized circumstances where an
- * applications can supply a {@link ValueCoder} directly. This method
- * receives the <code>ValueCoder</code> to be used from the application and
- * therefore avoids the cost of looking it up from the class of the supplied
- * <code>Object</code>. For example, suppose the application has registered
- * a <code>ValueCoder</code> named <code>myCoder</code> to handle
- * serialization and deserialization for a class called <code>MyClass</code>
- * . The following
- *
- * <pre>
- * <code>
- * value.directPut(myCoder, myClassValue, context);
- * </code>
- * </pre>
- *
- * is equivalent to but somewhat faster than
- *
- * <pre>
- * <code>
- * value.put(myClassValue, context);
- * </code>
- * </pre>
- *
- * @param coder
- * The <code>ValueCoder</code> registered for the class of
- * <code>object</code>
- * @param object
- * The object value to store
- * @param context
- * The <code>CoderContext</code> or <code>null</code>
- */
- public void directPut(final ValueCoder coder, final Object object, final CoderContext context) {
- if (object == null) {
- putNull();
- return;
- }
- preparePut();
- _depth++;
- int end = _size;
- try {
- ensureFit(6);
- final int handle = directHandle(coder, object.getClass());
- assert handle >= CLASS1 && handle < CLASS5;
- _size += encodeVariableLengthInt(CLASS1, _size, handle - CLASS1);
- coder.put(this, object, context);
- end = _size;
- } finally {
- _depth--;
- _size = end;
- }
- }
-
- /**
- * Optimized get method to be used in specialized circumstances where an
- * applications can supply a {@link ValueCoder} directly. This method
- * receives the <code>ValueCoder</code> to be used from the application and
- * therefore avoids the cost of looking it up from the class of the supplied
- * <code>Object</code>. For example, suppose the application has registered
- * a <code>ValueCoder</code> named <code>myCoder</code> to handle
- * serialization and deserialization for a class called <code>MyClass</code>
- * . The following
- *
- * <pre>
- * <code>
- * MyClass myClassValue = (MyClass)value.directGet(myCoder, context);
- * </code>
- * </pre>
- *
- * is equivalent to but somewhat faster than
- *
- * <pre>
- * <code>
- * MyClass myClassValue = (MyClass)value.get(null, context);
- * </code>
- * </pre>
- *
- * @param coder
- * The <code>ValueCoder</code> registered for the class of
- * <code>object</code>
- * @param clazz
- * The class of the object value to get
- * @param context
- * The <code>CoderContext</code> or <code>null</code>
- * @return an object of class <code>clazz</code>, or <code>null</code>
- */
- public Object directGet(final ValueRenderer coder, final Class<?> clazz, final CoderContext context) {
- final int type = nextType();
- if (type == TYPE_NULL) {
- return null;
- }
- final int expectedType = directHandle(coder, clazz);
- assert expectedType >= CLASS1 && expectedType < CLASS5;
- expectType(expectedType, type);
- _depth++;
- _serializedItemCount++;
- try {
- return coder.get(this, clazz, context);
- } finally {
- _depth--;
- }
- }
-
- /**
- * Optimized get method to be used in specialized circumstances where an
- * applications can supply a {@link ValueCoder} directly. This method
- * receives the <code>ValueCoder</code> to be used from the application and
- * therefore avoids the cost of looking it up from the class of the supplied
- * <code>Object</code>. For example, suppose the application has registered
- * a <code>ValueCoder</code> named <code>myCoder</code> to handle
- * serialization and deserialization for a class called <code>MyClass</code>
- * . The following
- *
- * <pre>
- * <code>
- * MyClass myClassValue = new MyClass();
- * value.directGet(myCoder, myClassValue, context);
- * </code>
- * </pre>
- *
- * is equivalent to but somewhat faster than
- *
- * <pre>
- * <code>
- * MyClass myClassValue = new MyClass();
- * (MyClass)value.get(myClassValue, context);
- * </code>
- * </pre>
- *
- * @param coder
- * The <code>ValueCoder</code> registered for the class of
- * <code>object</code>
- * @param target
- * A mutable object of type <code>clazz</code> into which a
- * {@link ValueRenderer} <i>may</i> decode this
- * <code>Value</code>.
- * @param clazz
- * The class of the object value to get
- * @param context
- * The <code>CoderContext</code> or <code>null</code>
- */
- public Object directGet(final ValueRenderer coder, final Object target, final Class<?> clazz,
- final CoderContext context) {
- final int type = nextType();
- if (type == TYPE_NULL) {
- return null;
- }
- final int expectedType = directHandle(coder, clazz);
- assert expectedType >= CLASS1 && expectedType < CLASS5;
- expectType(expectedType, type);
- _depth++;
- _serializedItemCount++;
- try {
- coder.render(this, target, clazz, context);
- return target;
- } finally {
- _depth--;
- }
- }
-
- long getPointerValue() {
- return _pointer;
- }
-
- void setPointerValue(final long pointer) {
- _pointer = pointer;
- }
-
- int getPointerPageType() {
- return _pointerPageType;
- }
-
- void setPointerPageType(final int pageType) {
- _pointerPageType = pageType;
- }
-
- byte[] getLongBytes() {
- return _longBytes;
- }
-
- int getLongSize() {
- return _longSize;
- }
-
- void setLongSize(final int size) {
- _longSize = size;
- }
-
- boolean isLongRecordMode() {
- return _longMode;
- }
-
- void setLongRecordMode(final boolean mode) {
- _longMode = mode;
- }
-
- private ValueCoder getValueCoder(final Class<?> clazz) {
- final CoderManager cm = _persistit.getCoderManager();
- if (cm != null) {
- return cm.getValueCoder(clazz);
- }
- return null;
- }
-
- void changeLongRecordMode(final boolean mode) {
- if (mode != _longMode) {
-
- if (_longBytes == null || _longBytes.length < Buffer.LONGREC_SIZE) {
- _longBytes = new byte[Buffer.LONGREC_SIZE];
- _longSize = Buffer.LONGREC_SIZE;
- }
-
- //
- // Swap the regular and long raw byte arrays
- //
- final byte[] tempBytes = _bytes;
- final int tempSize = _size;
- _bytes = _longBytes;
- _size = _longSize;
- _longBytes = tempBytes;
- _longSize = tempSize;
- _longMode = mode;
-
- assertLongRecordModeIsCorrect();
- }
- }
-
- private void assertLongRecordModeIsCorrect() {
- if (_longMode) {
- Debug.$assert1.t(_bytes.length == Buffer.LONGREC_SIZE);
- } else {
- Debug.$assert1.t(_longBytes == null || _longBytes.length == Buffer.LONGREC_SIZE);
- }
- }
-
- private void reset() {
- _next = 0;
- _end = _size;
- _depth = 0;
- _level = 0;
- _serializedItemCount = 0;
- if (_endArray != null && _endArray.length > TOO_MANY_LEVELS_THRESHOLD) {
- _endArray = null;
- }
- releaseValueCache();
- }
-
- private void preparePut() {
- if (_depth == 0) {
- _size = 0;
- releaseValueCache();
- }
- }
-
- private void checkSize(final int size) {
- if (_next + size != _size) {
- if (_next + size >= _size) {
- throw new MalformedValueException("Not enough bytes in Value at index=" + (_next - 1));
- }
- if (_depth == 0) {
- throw new MalformedValueException("Too many bytes in Value at index=" + (_next - 1));
- }
- }
- }
-
- private void checkArrayLength(final int length, final int offset, final int arrayLength) {
- if (length < 0 || length + offset > arrayLength) {
- throw new IllegalArgumentException("Invalid length " + length);
- }
- }
-
- private void pushEnd(final int end) {
- if (_endArray == null)
- _endArray = new int[10];
- else if (_level >= _endArray.length) {
- final int[] temp = new int[_level * 2 + 1];
- System.arraycopy(_endArray, 0, temp, 0, _level);
- _endArray = temp;
- }
- _endArray[_level++] = end;
- }
-
- private void closeVariableLengthItem() {
- _next = _end;
- if (_level > 0)
- _end = popEnd();
- else _end = _size;
- }
-
- private int popEnd() {
- return _endArray[--_level];
- }
-
- private int type() {
- if (_next >= _end) {
- throw new ConversionException("No more data at index=" + _next + " end=" + _end);
- }
- return _bytes[_next] & 0xFF;
- }
-
- private int nextType() {
- int type;
- if (_depth > 0) {
- while (_next >= _end && _level > 0) {
- _end = popEnd();
- }
- type = type();
- _next++;
- if (type >= SIZE1 && type <= SIZE5) {
- final int size = decodeVariableLengthInt(type);
- pushEnd(_end);
- _end = _next + size;
- type = _bytes[_next++] & 0xFF;
- }
- if (type >= CLASS1 && type <= CLASS5) {
- type = decodeVariableLengthInt(type) + CLASS1;
- } else if (type == Buffer.LONGREC_TYPE)
- return -1;
- } else {
- _next = 0;
- _end = _size;
- _serializedItemCount = 0;
- releaseValueCache();
- if (_level != 0) {
- _level = 0;
- if (_endArray != null && _endArray.length > TOO_MANY_LEVELS_THRESHOLD) {
- _endArray = null;
- }
- }
- if (_size == 0) {
- throw new ConversionException("Value is undefined");
- }
- type = _bytes[_next++] & 0xFF;
- if (type >= CLASS1 && type <= CLASS5) {
- type = decodeVariableLengthInt(type) + CLASS1;
- } else if (type == Buffer.LONGREC_TYPE) {
- return -1;
- }
- }
- return type;
- }
-
- private int nextType(final int expectedType) {
- final int type = nextType();
- if (type != TYPE_NULL) {
- expectType(expectedType, type);
- }
- return type;
- }
-
- private int nextType(final int expectedType1, final int expectedType2) {
- final int type = nextType();
- if (type != TYPE_NULL && type != expectedType2) {
- expectType(expectedType1, type);
- }
- return type;
- }
-
- private void expectType(final int expected, final int actual) {
- if (expected != actual) {
- throw new ConversionException("Expected a " + classForHandle(expected) + " but value is a "
- + classForHandle(actual));
- }
- }
-
- private Object getExpectedType(final Class<?> type) {
- final Object object = get(null, null);
- if (object == null || type.isAssignableFrom(object.getClass())) {
- return object;
- } else {
- throw new ConversionException("Expected a " + type.getName() + " but value is a "
- + object.getClass().getName());
- }
- }
-
- private void endVariableSizeItem(final int itemSize) {
- if (_depth > 0) {
- _size += encodeVariableLengthInt(SIZE1, _size - itemSize, itemSize);
- }
- }
-
- private int encodeVariableLengthInt(int base, final int index, int value) {
- Debug.$assert0.t((base & 0x3F) == 0);
-
- final int encodingSize = value < 0x00000010 ? 1 : value < 0x00001000 ? 2 : value < 0x00100000 ? 3 : 5;
-
- if (_size > index) {
- ensureFit(encodingSize);
- System.arraycopy(_bytes, index, _bytes, index + encodingSize, _size - index);
- }
- base |= ENCODED_SIZE_BITS[encodingSize];
- switch (encodingSize) {
- case 5:
- _bytes[index + 4] = (byte) (value & 0xFF);
- value >>>= 8;
- _bytes[index + 3] = (byte) (value & 0xFF);
- value >>>= 8;
- // intentionally falls through
-
- case 3:
- _bytes[index + 2] = (byte) (value & 0xFF);
- value >>>= 8;
- // intentionally falls through
-
- case 2:
- _bytes[index + 1] = (byte) (value & 0xFF);
- value >>>= 8;
- // intentionally falls through
-
- case 1:
- _bytes[index] = (byte) (base | (value & 0x0F));
- // intentionally falls through
- }
- return encodingSize;
- }
-
- private int decodeElementCount() {
- final int base = _bytes[_next] & 0xFF;
- if (base < COUNT1 || base > COUNT5) {
- throw new MalformedValueException("Invalid element count introducer " + base + " at " + _next);
- }
- _next++;
- return decodeVariableLengthInt(base);
- }
-
- private int decodeVariableLengthInt(int base) {
- int result = base & 0x0F;
- base &= 0x30;
- switch (base) {
- case BASE5:
- result = result << 8 | (_bytes[_next++] & 0xFF);
- result = result << 8 | (_bytes[_next++] & 0xFF);
- // intentionally falls through
-
- case BASE3:
- result = result << 8 | (_bytes[_next++] & 0xFF);
- // intentionally falls through
-
- case BASE2:
- result = result << 8 | (_bytes[_next++] & 0xFF);
- // intentionally falls through
-
- case BASE1:
- break;
- }
- return result;
- }
-
- private void encodeClass(final Class<?> cl) {
- final int classHandle = handleForClass(cl);
- if (classHandle < CLASS1) {
- ensureFit(1);
- _bytes[_size++] = (byte) classHandle;
- } else {
- ensureFit(5);
- _size += encodeVariableLengthInt(CLASS1, _size, classHandle - CLASS1);
- }
- }
-
- private int handleForClass(final Class<?> cl) {
- if (cl.isArray()) {
- return CLASS_ARRAY;
- }
- int from, to;
- if (cl.isPrimitive()) {
- from = TYPE_NULL;
- to = TYPE_DOUBLE;
- } else {
- from = CLASS_BOOLEAN;
- to = CLASSES.length;
- }
- for (int index = from; index < to; index++) {
- if (CLASSES[index] == cl)
- return index;
- }
- return handleForIndexedClass(cl);
- }
-
- private int handleForIndexedClass(final Class<?> cl) {
- final ClassInfo ci = _persistit.getClassIndex().lookupByClass(cl);
- if (ci != null) {
- return ci.getHandle();
- }
- throw new ConversionException("Class not mapped to handle " + cl.getName());
- }
-
- private Class<?> classForHandle(final int classHandle) {
- if (classHandle > 0 && classHandle < CLASSES.length && CLASSES[classHandle] != null) {
- return CLASSES[classHandle];
- } else if (classHandle == CLASS_ARRAY) {
- return Object[].class;
- } else if (classHandle == CLASS_MULTI_ARRAY) {
- return Object[][].class;
- }
- final ClassInfo ci = classInfoForHandle(classHandle);
- return ci.getDescribedClass();
- }
-
- private ClassInfo classInfoForHandle(final int classHandle) {
- final ClassInfo classInfo = _persistit.getClassIndex().lookupByHandle(classHandle);
- if (classInfo != null) {
- return classInfo;
- }
- throw new ConversionException("Unknown class handle " + classHandle);
- }
-
- private boolean toBoolean(final int index) {
- final char ch = (char) (_bytes[index] & 0xFF);
- if (ch == TRUE_CHAR)
- return true;
- if (ch == FALSE_CHAR)
- return false;
- throw new ConversionException("Expected a Boolean " + " but value " + ch + " is neither 'T' nor 'F' at index="
- + index);
- }
-
- private Object getMultiArray(Class<?> prototype) {
- final int start = _next;
- final int type = nextType(CLASS_MULTI_ARRAY, CLASS_REREF);
- if (type == CLASS_REREF) {
- _next = start;
- final Object array = get(null, null);
- if (array == null || array.getClass().isArray()) {
- return array;
- } else {
- throw new ConversionException("Referenced object is not an array");
- }
- }
- Object result;
- try {
- _depth++;
- final int componentClassHandle = nextType();
- checkSize(1);
- final int dimensions = _bytes[_next++] & 0xFF;
- if (prototype == null) {
- prototype = Array.newInstance(classForHandle(componentClassHandle), new int[dimensions]).getClass();
- }
- final int length = decodeElementCount();
- result = Array.newInstance(prototype.getComponentType(), length);
-
- _serializedItemCount++;
- registerEncodedObject(result);
-
- final Class<?> componentType = prototype.getComponentType();
- if (componentType.getComponentType().isArray()) {
- for (int index = 0; index < length; index++) {
- Array.set(result, index, getMultiArray(componentType));
- }
- } else {
- for (int index = 0; index < length; index++) {
- Array.set(result, index, get(null, null));
- }
- }
- } finally {
- _depth--;
- }
- closeVariableLengthItem();
- return result;
- }
-
- void decodeAntiValue(final Exchange exchange) throws InvalidKeyException {
- nextType(CLASS_ANTIVALUE);
- final int length = _end - _next;
- if (length > 0) {
- final int elisionCount = Util.getShort(_bytes, _next);
- AntiValue.fixUpKeys(exchange, elisionCount, _bytes, _next + 2, length - 2);
- }
- _next += length;
- closeVariableLengthItem();
- }
-
- /**
- * Return a <code>java.io.ObjectOutputStream</code> that writes bytes
- * directly into this Value. The implementation returned by this method
- * overrides the standard implementation to work correctly within the
- * Persistit context. See <a
- * href="../../../Object_Serialization_Notes.html"> Notes on Object
- * Serialization</a> for details.
- *
- * @return The <code>ObjectOutputStream</code>
- */
- public ObjectOutputStream getObjectOutputStream() throws ConversionException {
- if (_vos == null) {
- _vos = (ValueObjectOutputStream) getPrivilegedStream(true);
- }
- return _vos;
- }
-
- /**
- * Return a <code>java.io.ObjectInputStream</code> that reads bytes from
- * this Value. The implementation returned by this method overrides the
- * standard implementation to work correctly within the Persistit context.
- * See <a href="../../../Object_Serialization_Notes.html"> Notes on Object
- * Serialization</a> for details.
- *
- * @return The <code>ObjectInputStream</code>
- */
- public ObjectInputStream getObjectInputStream() throws ConversionException {
- if (_vis == null) {
- _vis = (ValueObjectInputStream) getPrivilegedStream(false);
- }
- return _vis;
- }
-
- private Object getPrivilegedStream(final boolean output) {
- try {
- final Value value = this;
- return AccessController.doPrivileged(new PrivilegedExceptionAction() {
- @Override
- public Object run() throws IOException {
- if (output)
- return new ValueObjectOutputStream(value);
- else
- return new ValueObjectInputStream(value);
- }
- });
- } catch (final PrivilegedActionException pae) {
- throw new ConversionException("While creating "
- + (output ? "ValueObjectOutputStream" : "ValueObjectInputStream"), pae.getException());
- }
- }
-
- /**
- * An OutputStream that writes bytes into this Value. The resulting stream
- * can be wrapped in an ObjectOutputStream for serialization of Objects.
- */
- private static class ValueObjectOutputStream extends ObjectOutputStream {
- private final Value _value;
-
- private ValueObjectOutputStream(final Value value) throws IOException {
- super();
- _value = value;
- }
-
- @Override
- public void writeObjectOverride(final Object object) {
- writeObject0(object, true);
- }
-
- @Override
- public void write(final int b) {
- _value.ensureFit(1);
- _value._bytes[_value._size++] = (byte) b;
- }
-
- @Override
- public void write(final byte[] bytes) {
- write(bytes, 0, bytes.length);
- }
-
- @Override
- public void write(final byte[] bytes, final int offset, final int size) {
- _value.ensureFit(size);
- System.arraycopy(bytes, offset, _value._bytes, _value._size, size);
- _value._size += size;
- }
-
- @Override
- public void writeBoolean(final boolean v) {
- _value.put(v);
- }
-
- @Override
- public void writeByte(final int v) {
- _value.put((byte) v);
- }
-
- @Override
- public void writeShort(final int v) {
- _value.put((short) v);
- }
-
- @Override
- public void writeChar(final int v) {
- _value.put((char) v);
- }
-
- @Override
- public void writeInt(final int v) {
- _value.put(v);
- }
-
- @Override
- public void writeLong(final long v) {
- _value.put(v);
- }
-
- @Override
- public void writeFloat(final float v) {
- _value.put(v);
- }
-
- @Override
- public void writeDouble(final double v) {
- _value.put(v);
- }
-
- @Override
- public void writeUnshared(final Object object) {
- writeObject0(object, false);
- }
-
- @Override
- public void writeUTF(final String v) {
- _value.putUTF(v);
- }
-
- @Override
- public void writeBytes(final String s) {
- throw new UnsupportedOperationException("No writeBytes method");
- }
-
- @Override
- public void writeChars(final String s) {
- throw new UnsupportedOperationException("No writeChars method");
- }
-
- private void writeObject0(final Object object, final boolean shared) {
- final boolean saveShared = _value._shared;
- _value._shared = shared;
- try {
- _value.put(object);
- } finally {
- _value._shared = saveShared;
- }
- }
-
- @Override
- public void close() {
- // no effect - we can reuse this stream all we want.
- }
-
- @Override
- public void defaultWriteObject() throws IOException {
- if (_value._currentCoder == null || _value._currentObject == null) {
- throw new NotActiveException("not in call to writeObject");
- }
- _value._currentCoder.putDefaultFields(_value, _value._currentObject);
- }
- }
-
- /**
- * An InputStream that reads bytes from this Value. The resulting stream can
- * be wrapped in an ObjectOutputStream for serialization of Objects.
- */
- private static class ValueObjectInputStream extends ObjectInputStream {
- Value _value;
-
- private ValueObjectInputStream(final Value value) throws IOException {
- super();
- _value = value;
- }
-
- @Override
- public Object readObjectOverride() {
- return _value.get();
- }
-
- @Override
- public boolean markSupported() {
- return false;
- }
-
- @Override
- public boolean readBoolean() {
- return _value.getBoolean();
- }
-
- @Override
- public byte readByte() {
- return _value.getByte();
- }
-
- @Override
- public int readUnsignedByte() {
- return _value.getByte() & 0xFF;
- }
-
- @Override
- public short readShort() {
- return _value.getShort();
- }
-
- @Override
- public int readUnsignedShort() {
- return _value.getShort() & 0xFFFF;
- }
-
- @Override
- public char readChar() {
- return _value.getChar();
- }
-
- @Override
- public int readInt() {
- return _value.getInt();
- }
-
- @Override
- public long readLong() {
- return _value.getLong();
- }
-
- @Override
- public float readFloat() {
- return _value.getFloat();
- }
-
- @Override
- public double readDouble() {
- return _value.getDouble();
- }
-
- @Override
- public String readUTF() {
- return _value.getString();
- }
-
- @Override
- public void readFully(final byte[] b) throws IOException {
- read(b, 0, b.length);
- }
-
- @Override
- public void readFully(final byte[] b, final int offset, final int length) throws IOException {
- read(b, offset, length);
- }
-
- @Override
- public int read(final byte[] b) throws IOException {
- return read(b, 0, b.length);
- }
-
- @Override
- public int read(final byte[] b, final int offset, final int length) throws IOException {
- if (offset < 0 || offset + length > b.length) {
- throw new IndexOutOfBoundsException();
- }
- final int sourceLength = _value._end - _value._next;
- if (length > sourceLength) {
- throw new IOException("Not enough bytes remaining in value");
- }
- System.arraycopy(_value._bytes, _value._next, b, offset, length);
- _value._next += length;
- return length;
- }
-
- @Override
- public int skipBytes(final int length) throws IOException {
- final int sourceLength = _value._end - _value._next;
- if (length > sourceLength) {
- throw new IOException("Not enough bytes remaining in value");
- }
- _value._next += length;
- return length;
- }
-
- @Override
- public String readLine() {
- throw new UnsupportedOperationException("No readLine method");
- }
-
- @Override
- public void defaultReadObject() {
- if (_value._currentCoder == null || _value._currentObject == null) {
- throw new ConversionException("not in call to readObject");
- }
- _value._currentCoder.renderDefaultFields(_value, _value._currentObject);
- }
-
- }
-
- public OldValueInputStream oldValueInputStream(final ObjectStreamClass classDescriptor) throws IOException {
- return new OldValueInputStream(this, classDescriptor);
- }
-
- public OldValueOutputStream oldValueOutputStream(final ObjectStreamClass classDescriptor) throws IOException {
- return new OldValueOutputStream(this, classDescriptor);
- }
-
- /**
- * An ObjectOutputStream that reads bytes from this Value using standard
- * Java serialization. If constructed with a non-null ObjectStreamClass,
- * then readStreamHeader and readClassDescriptor are overridden to read
- * nothing because the SerialValueCoder will already have access to the
- * necessary information.
- */
- public static class OldValueInputStream extends ObjectInputStream {
- Value _value;
- boolean _innerClassDescriptor;
- int _mark = -1;
- ObjectStreamClass _classDescriptor;
-
- private OldValueInputStream(final Value value, final ObjectStreamClass classDescriptor) throws IOException {
- this(value);
- if (classDescriptor == null) {
- throw new ConversionException("Null class descriptor");
- }
- _value = value;
- _classDescriptor = classDescriptor;
- }
-
- private OldValueInputStream(final Value value) throws IOException {
- super(new InputStream() {
- @Override
- public int read() {
- if (value._next < value._end) {
- return value._bytes[value._next++] & 0xFF;
- } else {
- return -1;
- }
- }
-
- @Override
- public int read(final byte[] bytes) {
- return read(bytes, 0, bytes.length);
- }
-
- @Override
- public int read(final byte[] bytes, final int offset, int size) {
- if (value._next + size > value._end) {
- size = value._end - value._next;
- }
- if (size <= 0) {
- size = -1;
- } else {
- System.arraycopy(value._bytes, value._next, bytes, offset, size);
-
- value._next += size;
- }
- return size;
- }
-
- @Override
- public long skip(final long lsize) {
- int size = lsize > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) lsize;
- if (size < 0)
- return 0;
- if (value._next + size > value._end) {
- size = value._end - value._next;
- }
- if (size < 0)
- return 0;
- value._next += size;
- return size;
- }
-
- @Override
- public int available() {
- final int available = value._end - value._next;
- return available > 0 ? available : 0;
- }
-
- });
- _value = value;
- }
-
- @Override
- protected final ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
- if (_classDescriptor == null) {
- return super.readClassDescriptor();
- } else if (_innerClassDescriptor) {
- final int handle = readInt();
- final ClassInfo classInfo = _value.classInfoForHandle(handle);
- ObjectStreamClass classDescriptor = null;
- if (classInfo != null) {
- classDescriptor = classInfo.getClassDescriptor();
- }
- if (classDescriptor == null) {
- throw new ConversionException("Unknown class handle " + handle);
- }
- return classDescriptor;
- } else {
- _innerClassDescriptor = true;
- return _classDescriptor;
- }
- }
-
- @Override
- protected final void readStreamHeader() throws IOException {
- if (_classDescriptor == null)
- super.readStreamHeader();
- }
-
- @Override
- public void mark(final int readLimit) {
- _mark = _value._next;
- }
-
- @Override
- public void reset() throws IOException {
- if (_mark < 0) {
- throw new IOException("No mark");
- } else {
- _value._next = _mark;
- }
- }
-
- @Override
- public boolean markSupported() {
- return true;
- }
-
- /**
- * Override the default implementation because we want to use the
- * application's ClassLoader, not necessarily the bootstrap loader.
- */
- @Override
- protected Class<?> resolveClass(final ObjectStreamClass desc) throws ClassNotFoundException {
- final String name = desc.getName();
- return Class.forName(name, false, Thread.currentThread().getContextClassLoader());
- }
- }
-
- /**
- * An ObjectOutputStream that writes bytes into this Value using standard
- * Java serialization. If constructed with a non-null ObjectStreamClass,
- * then writeStreamHeader and writeClassDescriptor are overridden to write
- * nothing because the SerialValueCoder will already have access to the
- * necessary information.
- */
- static class OldValueOutputStream extends ObjectOutputStream {
- Value _value;
- ObjectStreamClass _classDescriptor;
- boolean _innerClassDescriptor;
-
- OldValueOutputStream(final Value value, final ObjectStreamClass classDescriptor) throws IOException {
- this(value);
- if (classDescriptor == null) {
- throw new ConversionException("Null class descriptor");
- }
- _classDescriptor = classDescriptor;
- }
-
- private OldValueOutputStream(final Value value) throws IOException {
- super(new OutputStream() {
- @Override
- public void write(final int b) {
- value.ensureFit(1);
- value._bytes[value._size++] = (byte) b;
- }
-
- @Override
- public void write(final byte[] bytes) {
- write(bytes, 0, bytes.length);
- }
-
- @Override
- public void write(final byte[] bytes, final int offset, final int size) {
- value.ensureFit(size);
- System.arraycopy(bytes, offset, value._bytes, value._size, size);
- value._size += size;
- }
- });
- _value = value;
- }
-
- @Override
- protected final void writeClassDescriptor(final ObjectStreamClass classDescriptor) throws IOException {
- if (_classDescriptor == null) {
- super.writeClassDescriptor(classDescriptor);
- } else if (_innerClassDescriptor) {
- final Class<?> clazz = classDescriptor.forClass();
- final int handle = _value.handleForIndexedClass(clazz);
- writeInt(handle);
- } else {
- _innerClassDescriptor = true;
- }
- }
-
- @Override
- protected final void writeStreamHeader() throws IOException {
- if (_classDescriptor == null)
- super.writeStreamHeader();
- }
- }
-
- DefaultValueCoder getCurrentCoder() {
- return _currentCoder;
- }
-
- Object getCurrentObject() {
- return _currentObject;
- }
-
- void setCurrentCoder(final DefaultValueCoder coder) {
- _currentCoder = coder;
- }
-
- void setCurrentObject(final Object object) {
- _currentObject = object;
- }
-
- private ValueCache getValueCache() {
- if (_valueCache == null && _valueCacheWeakRef != null) {
- _valueCache = _valueCacheWeakRef.get();
- }
- if (_valueCache == null) {
- _valueCache = new ValueCache();
- _valueCacheWeakRef = new WeakReference<ValueCache>(_valueCache);
- }
- return _valueCache;
- }
-
- private void releaseValueCache() {
- _serializedItemCount = 0;
- if (_valueCache != null) {
- _valueCache.clear();
- // Clear the hard reference.
- _valueCache = null;
- }
- }
-
- /**
- * Holds a collection of Object values associated with their position within
- * the serialized Value. Used only during get and put operations so that
- * reference graphs with cycles can be encoded and decoded properly. A
- * Persistit instance has a collection of ValueCache objects that get() and
- * put() operations allocate and relinquish when done.
- */
- static class ValueCache {
- private final static int INITIAL_SIZE = 256;
-
- /**
- * handle -> Object
- */
- Object[] _array = new Object[INITIAL_SIZE];
-
- int _handleCount = 0;
-
- ValueCache() {
- clear();
- }
-
- /**
- * Look up the handle for an Object that has already been stored in this
- * Value.
- *
- * @param object
- * @return The handle, or -1 if the object has not been stored yet.
- */
- int lookup(final Object object) {
- for (int index = _handleCount; --index >= 0;) {
- if (_array[index] == object) {
- return index;
- }
- }
- return -1;
- }
-
- /**
- * Get the object stored with the supplied handle value.
- *
- * @param handle
- * @return The object
- */
- Object get(final int handle) {
- Object object = _array[handle];
- if (object instanceof SkippedFieldMarker) {
- object = ((SkippedFieldMarker) object).get();
- _array[handle] = object;
- }
- return object;
- }
-
- /**
- * Record the association between the supplied handle and object values.
- * Subsequent lookup and get operations will then be able to find this
- * object or fetch it by handle.
- *
- * @param handle
- * @param object
- * @return previous handle, or -1 if none
- */
- void store(final int handle, final Object object) {
- if (handle >= _array.length)
- grow(1 + handle * 2);
- if (handle >= _handleCount) {
- _handleCount = handle + +1;
- }
- _array[handle] = object;
- }
-
- int put(final int handle, final Object object) {
- final int previous = lookup(object);
- if (previous != -1) {
- return previous;
- }
- store(handle, object);
- return -1;
- }
-
- /**
- * Enlarges the backing arrays to support more objects
- */
- void grow(final int newSize) {
- final Object[] temp = _array;
- _array = new Object[newSize];
- System.arraycopy(temp, 0, _array, 0, temp.length);
- }
-
- /**
- * Clears all object/handle associations.
- */
- void clear() {
- for (int index = _handleCount; --index >= 0;) {
- _array[index] = null;
- }
- _handleCount = 0;
- }
- }
-
- private static class DisplayMarker {
- int _start;
-
- DisplayMarker(final int start) {
- _start = start;
- }
-
- @Override
- public String toString() {
- return "@" + Integer.toString(_start);
- }
- }
-
- private static class SkippedFieldMarker {
- final Value _value;
- final int _next;
- final int _end;
-
- private SkippedFieldMarker(final Value value, final int next, final int end) {
- _value = value;
- _next = next;
- _end = end;
- }
-
- private Object get() {
- final int saveDepth = _value._depth;
- final int saveLevel = _value._level;
- final int saveNext = _value._next;
- final int saveEnd = _value._end;
- try {
- _value._next = _next;
- _value._end = _end;
- return _value.get();
- } finally {
- _value._end = saveEnd;
- _value._next = saveNext;
- _value._level = saveLevel;
- _value._depth = saveDepth;
- }
- }
- }
-
- static class Version {
- private final long _versionHandle;
- private final long _commitTimestamp;
- private final Value _value;
-
- private Version(final long versionHandle, final long commitTimestamp, final Value value) {
- _versionHandle = versionHandle;
- _commitTimestamp = commitTimestamp;
- _value = value;
- }
-
- /**
- * @return the versionHandle
- */
- public long getVersionHandle() {
- return _versionHandle;
- }
-
- /**
- * @return the commitTimestamp
- */
- public long getCommitTimestamp() {
- return _commitTimestamp;
- }
-
- /**
- * @return the value
- */
- public Value getValue() {
- return _value;
- }
-
- public long getStartTimestamp() {
- return TransactionIndex.vh2ts(_versionHandle);
- }
-
- public int getStep() {
- return TransactionIndex.vh2step(_versionHandle);
- }
-
- @Override
- public String toString() {
- try {
- final StringBuilder sb = new StringBuilder();
- sb.append(String.format("%,d", getStartTimestamp()));
- if (getStep() > 0) {
- sb.append(String.format("#%02d", getStep()));
- }
- sb.append("<" + TransactionStatus.tcString(_commitTimestamp) + ">");
- sb.append(":");
- sb.append(_value);
- return sb.toString();
- } catch (final Exception e) {
- e.printStackTrace();
- return e.toString();
- }
- }
- }
-
- /**
- * Construct a list of <code>Version</code> objects, each denoting one of
- * the multi-value versions currently held in this Value object.
- *
- * @return the list of <code>Version<code>s
- * @throws PersistitException
- */
- List<Version> unpackMvvVersions() throws PersistitException {
- final List<Version> versions = new ArrayList<Version>();
- final MVV.VersionVisitor visitor = new MVV.VersionVisitor() {
-
- @Override
- public void sawVersion(final long version, final int valueOffset, final int valueLength) {
- long tc = -1;
-
- try {
- tc = _persistit.getTransactionIndex().commitStatus(version, TransactionStatus.UNCOMMITTED, 0);
- } catch (final Exception e) {
- tc = -1;
- }
- final Value value = new Value(_persistit);
- value.ensureFit(valueLength);
- System.arraycopy(_bytes, valueOffset, value.getEncodedBytes(), 0, valueLength);
- value.setEncodedSize(valueLength);
- value.trim();
- versions.add(new Version(version, tc, value));
- }
-
- @Override
- public void init() throws PersistitException {
-
- }
- };
- MVV.visitAllVersions(visitor, getEncodedBytes(), 0, getEncodedSize());
- return versions;
- }
-
- private void putCharSequenceInternal(final CharSequence string) {
- int length = string.length();
- ensureFit(length + 1);
- final int saveSize = _size;
- int index = _size;
- _bytes[index++] = (byte) CLASS_STRING;
-
- int maxLength = _bytes.length;
-
- for (int i = 0; i < length; i++) {
- final char c = string.charAt(i);
-
- if (c <= 0x007F) {
- if (index + 1 > maxLength) {
- _size = index;
- ensureFit(index + 1 + (length - i) * 2);
- maxLength = _bytes.length;
- }
- _bytes[index++] = (byte) c;
- } else if (c > 0x07FF) {
- if (index + 3 > maxLength) {
- _size = index;
- ensureFit(index + 3 + (length - i) * 2);
- maxLength = _bytes.length;
- }
- _bytes[index++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
- _bytes[index++] = (byte) (0x80 | ((c >> 6) & 0x3F));
- _bytes[index++] = (byte) (0x80 | ((c >> 0) & 0x3F));
- } else {
- if (index + 2 > maxLength) {
- _size = index;
- ensureFit(index + 2 + (length - i) * 2);
- maxLength = _bytes.length;
- }
- _bytes[index++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
- _bytes[index++] = (byte) (0x80 | ((c >> 0) & 0x3F));
- }
- }
- length = index - saveSize;
- _size = index;
- endVariableSizeItem(length);
- }
-
- private int directHandle(final ValueCoder coder, final Class<?> clazz) {
- if (coder instanceof HandleCache) {
- final HandleCache cache = (HandleCache) coder;
- int handle = cache.getHandle();
- if (handle == 0) {
- handle = handleForClass(clazz);
- cache.setHandle(handle);
- }
- return handle;
- } else {
- return handleForClass(clazz);
- }
- }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/Cache.java b/sonar-batch/src/main/java/org/sonar/batch/index/Cache.java
index 71cdd8dc344..1cbe6af68ca 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/Cache.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/Cache.java
@@ -23,14 +23,12 @@ import com.google.common.collect.Sets;
import com.persistit.Exchange;
import com.persistit.Key;
import com.persistit.KeyFilter;
-import com.persistit.Value;
import com.persistit.exception.PersistitException;
import org.apache.commons.lang.builder.ToStringBuilder;
import javax.annotation.CheckForNull;
import java.io.Serializable;
-import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
@@ -249,7 +247,7 @@ public class Cache<V extends Serializable> {
try {
Set<Object> keys = Sets.newLinkedHashSet();
exchange.clear();
- Exchange iteratorExchange = newExchange(exchange);
+ Exchange iteratorExchange = new Exchange(exchange);
iteratorExchange.append(key);
iteratorExchange.append(Key.BEFORE);
while (iteratorExchange.next(false)) {
@@ -266,7 +264,7 @@ public class Cache<V extends Serializable> {
try {
Set<Object> keys = Sets.newLinkedHashSet();
exchange.clear();
- Exchange iteratorExchange = newExchange(exchange);
+ Exchange iteratorExchange = new Exchange(exchange);
iteratorExchange.append(firstKey);
iteratorExchange.append(secondKey);
iteratorExchange.append(Key.BEFORE);
@@ -288,7 +286,7 @@ public class Cache<V extends Serializable> {
try {
Set<Object> keys = Sets.newLinkedHashSet();
exchange.clear();
- Exchange iteratorExchange = newExchange(exchange);
+ Exchange iteratorExchange = new Exchange(exchange);
iteratorExchange.append(Key.BEFORE);
while (iteratorExchange.next(false)) {
keys.add(iteratorExchange.getKey().indexTo(-1).decode());
@@ -306,7 +304,7 @@ public class Cache<V extends Serializable> {
try {
exchange.clear();
exchange.append(firstKey).append(secondKey).append(Key.BEFORE);
- Exchange iteratorExchange = newExchange(exchange);
+ Exchange iteratorExchange = new Exchange(exchange);
KeyFilter filter = new KeyFilter().append(KeyFilter.simpleTerm(firstKey)).append(KeyFilter.simpleTerm(secondKey));
return new ValueIterable<V>(iteratorExchange, filter);
} catch (Exception e) {
@@ -321,7 +319,7 @@ public class Cache<V extends Serializable> {
try {
exchange.clear();
exchange.append(firstKey).append(Key.BEFORE);
- Exchange iteratorExchange = newExchange(exchange);
+ Exchange iteratorExchange = new Exchange(exchange);
KeyFilter filter = new KeyFilter().append(KeyFilter.simpleTerm(firstKey));
return new ValueIterable<V>(iteratorExchange, filter);
} catch (Exception e) {
@@ -335,7 +333,7 @@ public class Cache<V extends Serializable> {
public Iterable<V> values() {
try {
exchange.clear().append(Key.BEFORE);
- Exchange iteratorExchange = newExchange(exchange);
+ Exchange iteratorExchange = new Exchange(exchange);
KeyFilter filter = new KeyFilter().append(KeyFilter.ALL);
return new ValueIterable<V>(iteratorExchange, filter);
} catch (Exception e) {
@@ -346,13 +344,13 @@ public class Cache<V extends Serializable> {
public Iterable<Entry<V>> entries() {
exchange.clear().to(Key.BEFORE);
KeyFilter filter = new KeyFilter().append(KeyFilter.ALL);
- return new EntryIterable<V>(newExchange(exchange), filter);
+ return new EntryIterable<V>(new Exchange(exchange), filter);
}
public Iterable<Entry<V>> entries(Object firstKey) {
exchange.clear().append(firstKey).append(Key.BEFORE);
KeyFilter filter = new KeyFilter().append(KeyFilter.simpleTerm(firstKey));
- return new EntryIterable<V>(newExchange(exchange), filter);
+ return new EntryIterable<V>(new Exchange(exchange), filter);
}
private void resetKey(Object key) {
@@ -513,16 +511,4 @@ public class Cache<V extends Serializable> {
}
}
- private Exchange newExchange(Exchange sourceExchange) {
- Exchange exchange = new Exchange(sourceExchange);
- try {
- Method getSpareValue = Exchange.class.getDeclaredMethod("getAuxiliaryValue");
- getSpareValue.setAccessible(true);
- Value spareValue = (Value) getSpareValue.invoke(exchange);
- spareValue.setMaximumSize(Value.MAXIMUM_SIZE);
- } catch (Exception e) {
- throw new IllegalStateException("Unable to set size of persisitit value");
- }
- return exchange;
- }
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/Caches.java b/sonar-batch/src/main/java/org/sonar/batch/index/Caches.java
index 087b323fbd7..ab32231dbea 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/Caches.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/Caches.java
@@ -35,7 +35,6 @@ import org.sonar.api.utils.TempFolder;
import java.io.File;
import java.io.Serializable;
-import java.lang.reflect.Method;
import java.util.Properties;
import java.util.Set;
@@ -84,11 +83,7 @@ public class Caches implements BatchComponent, Startable {
Preconditions.checkState(!cacheNames.contains(cacheName), "Cache is already created: " + cacheName);
try {
Exchange exchange = persistit.getExchange(volume, cacheName, true);
- exchange.getValue().setMaximumSize(Value.MAXIMUM_SIZE);
- Method getSpareValue = Exchange.class.getDeclaredMethod("getAuxiliaryValue");
- getSpareValue.setAccessible(true);
- Value spareValue = (Value) getSpareValue.invoke(exchange);
- spareValue.setMaximumSize(Value.MAXIMUM_SIZE);
+ exchange.setMaximumValueSize(Value.MAXIMUM_SIZE);
Cache<V> cache = new Cache<V>(cacheName, exchange);
cacheNames.add(cacheName);
return cache;