2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 2002, 2012 Oracle and/or its affiliates. All rights reserved.
8 package com.sleepycat.persist.impl;
10 import java.lang.reflect.Array;
14 import com.sleepycat.compat.DbCompat;
15 import com.sleepycat.db.DatabaseEntry;
16 import com.sleepycat.persist.model.EntityModel;
17 import com.sleepycat.persist.raw.RawObject;
18 import java.util.IdentityHashMap;
21 * An array of objects having a specified number of dimensions. All
22 * multidimensional arrays are handled by this class, since even a primitive
23 * array of more than one dimension is an array of objects, where the component
24 * objects may be primitive arrays. The {@link PrimitiveArrayFormat} class
25 * handles primitive arrays of one dimension only.
27 * In this class, and {@link PrimitiveArrayFormat}, we resort to using
28 * reflection to allocate multidimensional arrays. If there is a need for it,
29 * reflection could be avoided in the future by generating code as new array
30 * formats are encountered.
34 public class ObjectArrayFormat extends Format {
36 private static final long serialVersionUID = 4317004346690441892L;
38 private Format componentFormat;
39 private int nDimensions;
40 private transient Format useComponentFormat;
42 ObjectArrayFormat(Catalog catalog, Class type) {
44 String name = getClassName();
46 name.charAt(nDimensions) == '[';
52 public boolean isArray() {
57 public int getDimensions() {
62 public Format getComponentType() {
63 return (useComponentFormat != null) ?
64 useComponentFormat : componentFormat;
68 void collectRelatedFormats(Catalog catalog,
69 Map<String, Format> newFormats) {
70 Class cls = getType().getComponentType();
71 catalog.createFormat(cls, newFormats);
75 void initialize(Catalog catalog, EntityModel model, int initVersion) {
76 /* Set the component format for a new (never initialized) format. */
77 if (componentFormat == null) {
78 Class cls = getType().getComponentType();
79 componentFormat = catalog.getFormat(cls.getName());
81 useComponentFormat = componentFormat.getLatestVersion();
85 boolean isAssignableTo(Format format) {
86 if (super.isAssignableTo(format)) {
89 if (format instanceof ObjectArrayFormat) {
90 ObjectArrayFormat other = (ObjectArrayFormat) format;
91 if (useComponentFormat.isAssignableTo(other.useComponentFormat)) {
99 Object newArray(int len) {
100 return Array.newInstance(getType(), len);
104 public Object newInstance(EntityInput input, boolean rawAccess) {
105 int len = input.readArrayLength();
107 return new RawObject(this, new Object[len]);
109 return useComponentFormat.newArray(len);
114 public Object readObject(Object o, EntityInput input, boolean rawAccess)
115 throws RefreshException {
119 a = ((RawObject) o).getElements();
123 if (useComponentFormat.getId() == Format.ID_STRING) {
124 for (int i = 0; i < a.length; i += 1) {
125 a[i] = input.readStringObject();
128 for (int i = 0; i < a.length; i += 1) {
129 a[i] = input.readObject();
136 void writeObject(Object o, EntityOutput output, boolean rawAccess)
137 throws RefreshException {
141 a = ((RawObject) o).getElements();
145 output.writeArrayLength(a.length);
146 if (useComponentFormat.getId() == Format.ID_STRING) {
147 for (int i = 0; i < a.length; i += 1) {
148 output.writeString((String)a[i]);
151 for (int i = 0; i < a.length; i += 1) {
152 output.writeObject(a[i], useComponentFormat);
158 Object convertRawObject(Catalog catalog,
161 IdentityHashMap converted)
162 throws RefreshException {
164 RawArrayInput input = new RawArrayInput
165 (catalog, rawAccess, converted, rawObject, useComponentFormat);
166 Object a = newInstance(input, rawAccess);
167 converted.put(rawObject, a);
168 return readObject(a, input, rawAccess);
172 void skipContents(RecordInput input)
173 throws RefreshException {
175 int len = input.readPackedInt();
176 for (int i = 0; i < len; i += 1) {
177 input.skipField(useComponentFormat);
182 void copySecMultiKey(RecordInput input, Format keyFormat, Set results)
183 throws RefreshException {
185 int len = input.readPackedInt();
186 for (int i = 0; i < len; i += 1) {
187 KeyLocation loc = input.getKeyLocation(useComponentFormat);
189 throw new IllegalArgumentException
190 ("Secondary key values in array may not be null");
192 if (loc.format != useComponentFormat) {
193 throw DbCompat.unexpectedState
194 (useComponentFormat.getClassName());
196 int off1 = loc.input.getBufferOffset();
197 useComponentFormat.skipContents(loc.input);
198 int off2 = loc.input.getBufferOffset();
199 DatabaseEntry entry = new DatabaseEntry
200 (loc.input.getBufferBytes(), off1, off2 - off1);
206 boolean evolve(Format newFormat, Evolver evolver) {
209 * When the class name of the component changes, we need a new format
210 * that references it. Otherwise, don't propogate changes from
211 * components upward to their arrays.
213 Format latest = componentFormat.getLatestVersion();
214 if (latest != componentFormat &&
215 !latest.getClassName().equals(componentFormat.getClassName())) {
216 evolver.useEvolvedFormat(this, newFormat, newFormat);
218 evolver.useOldFormat(this, newFormat);