001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: ObjectArrayFormat.java,v 1.23.2.3 2008/01/07 15:14:19 cwl Exp $
007: */
008:
009: package com.sleepycat.persist.impl;
010:
011: import java.lang.reflect.Array;
012: import java.util.IdentityHashMap;
013: import java.util.Map;
014: import java.util.Set;
015:
016: import com.sleepycat.je.DatabaseEntry;
017: import com.sleepycat.persist.raw.RawObject;
018:
019: /**
020: * An array of objects having a specified number of dimensions. All
021: * multidimensional arrays are handled by this class, since even a primitive
022: * array of more than one dimension is an array of objects, where the component
023: * objects may be primitive arrays. The {@link PrimitiveArrayFormat} class
024: * handles primitive arrays of one dimension only.
025: *
026: * In this class, and {@link PrimitiveArrayFormat}, we resort to using
027: * reflection to allocate multidimensional arrays. If there is a need for it,
028: * reflection could be avoided in the future by generating code as new array
029: * formats are encountered.
030: *
031: * @author Mark Hayes
032: */
033: public class ObjectArrayFormat extends Format {
034:
035: private static final long serialVersionUID = 4317004346690441892L;
036:
037: private Format componentFormat;
038: private int nDimensions;
039: private transient Format useComponentFormat;
040:
041: ObjectArrayFormat(Class type) {
042: super (type);
043: String name = getClassName();
044: for (nDimensions = 0; name.charAt(nDimensions) == '['; nDimensions += 1) {
045: }
046: }
047:
048: @Override
049: public boolean isArray() {
050: return true;
051: }
052:
053: @Override
054: public int getDimensions() {
055: return nDimensions;
056: }
057:
058: @Override
059: public Format getComponentType() {
060: return (useComponentFormat != null) ? useComponentFormat
061: : componentFormat;
062: }
063:
064: @Override
065: void collectRelatedFormats(Catalog catalog,
066: Map<String, Format> newFormats) {
067: Class cls = getType().getComponentType();
068: catalog.createFormat(cls, newFormats);
069: }
070:
071: @Override
072: void initialize(Catalog catalog, int initVersion) {
073: /* Set the component format for a new (never initialized) format. */
074: if (componentFormat == null) {
075: Class cls = getType().getComponentType();
076: componentFormat = catalog.getFormat(cls.getName());
077: }
078: useComponentFormat = componentFormat.getLatestVersion();
079: }
080:
081: @Override
082: boolean isAssignableTo(Format format) {
083: if (super .isAssignableTo(format)) {
084: return true;
085: }
086: if (format instanceof ObjectArrayFormat) {
087: ObjectArrayFormat other = (ObjectArrayFormat) format;
088: if (useComponentFormat
089: .isAssignableTo(other.useComponentFormat)) {
090: return true;
091: }
092: }
093: return false;
094: }
095:
096: @Override
097: Object newArray(int len) {
098: return Array.newInstance(getType(), len);
099: }
100:
101: @Override
102: public Object newInstance(EntityInput input, boolean rawAccess) {
103: int len = input.readArrayLength();
104: if (rawAccess) {
105: return new RawObject(this , new Object[len]);
106: } else {
107: return useComponentFormat.newArray(len);
108: }
109: }
110:
111: @Override
112: public Object readObject(Object o, EntityInput input,
113: boolean rawAccess) {
114: Object[] a;
115: if (rawAccess) {
116: a = ((RawObject) o).getElements();
117: } else {
118: a = (Object[]) o;
119: }
120: for (int i = 0; i < a.length; i += 1) {
121: a[i] = input.readObject();
122: }
123: return o;
124: }
125:
126: @Override
127: void writeObject(Object o, EntityOutput output, boolean rawAccess) {
128: Object[] a;
129: if (rawAccess) {
130: a = ((RawObject) o).getElements();
131: } else {
132: a = (Object[]) o;
133: }
134: output.writeArrayLength(a.length);
135: for (int i = 0; i < a.length; i += 1) {
136: output.writeObject(a[i], useComponentFormat);
137: }
138: }
139:
140: @Override
141: Object convertRawObject(Catalog catalog, boolean rawAccess,
142: RawObject rawObject, IdentityHashMap converted) {
143: RawArrayInput input = new RawArrayInput(catalog, rawAccess,
144: converted, rawObject, useComponentFormat);
145: Object a = newInstance(input, rawAccess);
146: converted.put(rawObject, a);
147: return readObject(a, input, rawAccess);
148: }
149:
150: @Override
151: void skipContents(RecordInput input) {
152: int len = input.readPackedInt();
153: for (int i = 0; i < len; i += 1) {
154: input.skipField(useComponentFormat);
155: }
156: }
157:
158: @Override
159: void copySecMultiKey(RecordInput input, Format keyFormat,
160: Set results) {
161: int len = input.readPackedInt();
162: for (int i = 0; i < len; i += 1) {
163: KeyLocation loc = input.getKeyLocation(useComponentFormat);
164: if (loc == null) {
165: throw new IllegalArgumentException(
166: "Secondary key values in array may not be null");
167: }
168: if (loc.format != useComponentFormat) {
169: throw new IllegalStateException(useComponentFormat
170: .getClassName());
171: }
172: int off1 = loc.input.getBufferOffset();
173: useComponentFormat.skipContents(loc.input);
174: int off2 = loc.input.getBufferOffset();
175: DatabaseEntry entry = new DatabaseEntry(loc.input
176: .getBufferBytes(), off1, off2 - off1);
177: results.add(entry);
178: }
179: }
180:
181: @Override
182: boolean evolve(Format newFormat, Evolver evolver) {
183:
184: /*
185: * When the class name of the component changes, we need a new format
186: * that references it. Otherwise, don't propogate changes from
187: * components upward to their arrays.
188: */
189: Format latest = componentFormat.getLatestVersion();
190: if (latest != componentFormat
191: && !latest.getClassName().equals(
192: componentFormat.getClassName())) {
193: evolver.useEvolvedFormat(this , newFormat, newFormat);
194: } else {
195: evolver.useOldFormat(this , newFormat);
196: }
197: return true;
198: }
199: }
|