• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/db-4.8.30/java/src/com/sleepycat/bind/serial/
1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2000-2009 Oracle.  All rights reserved.
5 *
6 * $Id$
7 */
8
9package com.sleepycat.bind.serial;
10
11import java.io.IOException;
12
13import com.sleepycat.bind.EntryBinding;
14import com.sleepycat.db.DatabaseEntry;
15import com.sleepycat.util.FastInputStream;
16import com.sleepycat.util.FastOutputStream;
17import com.sleepycat.util.RuntimeExceptionWrapper;
18
19/**
20 * A concrete <code>EntryBinding</code> that treats a key or data entry as
21 * a serialized object.
22 *
23 * <p>This binding stores objects in serialized object format.  The
24 * deserialized objects are returned by the binding, and their
25 * <code>Class</code> must implement the <code>Serializable</code>
26 * interface.</p>
27 *
28 * <p>For key bindings, a tuple binding is usually a better choice than a
29 * serial binding.  A tuple binding gives a reasonable sort order, and works
30 * with comparators in all cases -- see below.</p>
31 *
32 * <p><em>WARNING:</em> SerialBinding should not be used with Berkeley DB Java
33 * Edition for key bindings, when a custom comparator is used.  In JE,
34 * comparators are instantiated and called internally at times when databases
35 * are not accessible.  Because serial bindings depend on the class catalog
36 * database, a serial binding cannot be used during these times.  An attempt
37 * to use a serial binding with a custom comparator will result in a
38 * NullPointerException during environment open or close.</p>
39 *
40 * <p><a name="evolution"><strong>Class Evolution</strong></a></p>
41 *
42 * <p>{@code SerialBinding} and other classes in this package use standard Java
43 * serialization and all rules of Java serialization apply.  This includes the
44 * rules for class evolution.  Once an instance of a class is stored, the class
45 * must maintain its {@code serialVersionUID} and follow the rules defined in
46 * the Java specification.  To use a new incompatible version of a class, a
47 * different {@link ClassCatalog} must be used or the class catalog database
48 * must be truncated.</p>
49 *
50 * <p>If more advanced class evolution features are required, consider using
51 * the {@link com.sleepycat.persist.evolve Direct Persistence Layer}.</p>
52 *
53 * @author Mark Hayes
54 */
55public class SerialBinding<E> extends SerialBase implements EntryBinding<E> {
56
57    private ClassCatalog classCatalog;
58    private Class<E> baseClass;
59
60    /**
61     * Creates a serial binding.
62     *
63     * @param classCatalog is the catalog to hold shared class information and
64     * for a database should be a {@link StoredClassCatalog}.
65     *
66     * @param baseClass is the base class for serialized objects stored using
67     * this binding -- all objects using this binding must be an instance of
68     * this class.
69     */
70    public SerialBinding(ClassCatalog classCatalog, Class<E> baseClass) {
71
72        if (classCatalog == null) {
73            throw new NullPointerException("classCatalog must be non-null");
74        }
75        this.classCatalog = classCatalog;
76        this.baseClass = baseClass;
77    }
78
79    /**
80     * Returns the base class for this binding.
81     *
82     * @return the base class for this binding.
83     */
84    public final Class<E> getBaseClass() {
85
86        return baseClass;
87    }
88
89    /**
90     * Returns the class loader to be used during deserialization, or null if
91     * a default class loader should be used.  The default implementation of
92     * this method returns
93     * <code>Thread.currentThread().getContextClassLoader()</code> to use the
94     * context class loader for the current thread.
95     *
96     * <p>This method may be overridden to return a dynamically determined class
97     * loader.  For example, <code>getBaseClass().getClassLoader()</code> could
98     * be called to use the class loader for the base class, assuming that a
99     * base class has been specified.</p>
100     *
101     * <p>If this method returns null, a default class loader will be used as
102     * determined by the <code>java.io.ObjectInputStream.resolveClass</code>
103     * method.</p>
104     */
105    public ClassLoader getClassLoader() {
106
107        return Thread.currentThread().getContextClassLoader();
108    }
109
110    /**
111     * Deserialize an object from an entry buffer.  May only be called for data
112     * that was serialized using {@link #objectToEntry}, since the fixed
113     * serialization header is assumed to not be included in the input data.
114     * {@link SerialInput} is used to deserialize the object.
115     *
116     * @param entry is the input serialized entry.
117     *
118     * @return the output deserialized object.
119     */
120    public E entryToObject(DatabaseEntry entry) {
121
122        int length = entry.getSize();
123        byte[] hdr = SerialOutput.getStreamHeader();
124        byte[] bufWithHeader = new byte[length + hdr.length];
125
126        System.arraycopy(hdr, 0, bufWithHeader, 0, hdr.length);
127        System.arraycopy(entry.getData(), entry.getOffset(),
128                         bufWithHeader, hdr.length, length);
129
130        try {
131            SerialInput jin = new SerialInput(
132                new FastInputStream(bufWithHeader, 0, bufWithHeader.length),
133                classCatalog,
134                getClassLoader());
135            return (E) jin.readObject();
136        } catch (IOException e) {
137            throw new RuntimeExceptionWrapper(e);
138        } catch (ClassNotFoundException e) {
139            throw new RuntimeExceptionWrapper(e);
140        }
141    }
142
143    /**
144     * Serialize an object into an entry buffer.  The fixed serialization
145     * header is not included in the output data to save space, and therefore
146     * to deserialize the data the complementary {@link #entryToObject} method
147     * must be used.  {@link SerialOutput} is used to serialize the object.
148     *
149     * <p>Note that this method sets the DatabaseEntry offset property to a
150     * non-zero value and the size property to a value less than the length of
151     * the byte array.</p>
152     *
153     * @param object is the input deserialized object.
154     *
155     * @param entry is the output serialized entry.
156     *
157     * @throws IllegalArgumentException if the object is not an instance of the
158     * base class for this binding.
159     */
160    public void objectToEntry(E object, DatabaseEntry entry) {
161
162        if (baseClass != null && !baseClass.isInstance(object)) {
163            throw new IllegalArgumentException(
164                        "Data object class (" + object.getClass() +
165                        ") not an instance of binding's base class (" +
166                        baseClass + ')');
167        }
168        FastOutputStream fo = getSerialOutput(object);
169        try {
170            SerialOutput jos = new SerialOutput(fo, classCatalog);
171            jos.writeObject(object);
172        } catch (IOException e) {
173            throw new RuntimeExceptionWrapper(e);
174        }
175
176        byte[] hdr = SerialOutput.getStreamHeader();
177        entry.setData(fo.getBufferBytes(), hdr.length,
178                     fo.getBufferLength() - hdr.length);
179    }
180}
181