001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: ReflectionAccessor.java,v 1.18.2.5 2008/01/07 15:14:20 cwl Exp $
007: */
008:
009: package com.sleepycat.persist.impl;
010:
011: import java.lang.reflect.AccessibleObject;
012: import java.lang.reflect.Array;
013: import java.lang.reflect.Constructor;
014: import java.lang.reflect.Field;
015: import java.lang.reflect.InvocationTargetException;
016: import java.lang.reflect.Modifier;
017: import java.util.List;
018:
019: /**
020: * Implements Accessor using reflection.
021: *
022: * @author Mark Hayes
023: */
024: class ReflectionAccessor implements Accessor {
025:
026: private static final FieldAccess[] EMPTY_KEYS = {};
027:
028: private Class type;
029: private Accessor super Accessor;
030: private Constructor constructor;
031: private FieldAccess priKey;
032: private FieldAccess[] secKeys;
033: private FieldAccess[] nonKeys;
034:
035: private ReflectionAccessor(Class type, Accessor super Accessor) {
036: this .type = type;
037: this .super Accessor = super Accessor;
038: try {
039: constructor = type.getDeclaredConstructor();
040: } catch (NoSuchMethodException e) {
041: throw new IllegalStateException(type.getName());
042: }
043: if (!Modifier.isPublic(constructor.getModifiers())) {
044: setAccessible(constructor, type.getName() + "()");
045: }
046: }
047:
048: ReflectionAccessor(Catalog catalog, Class type,
049: Accessor super Accessor, FieldInfo priKeyField,
050: List<FieldInfo> secKeyFields, List<FieldInfo> nonKeyFields) {
051: this (type, super Accessor);
052: if (priKeyField != null) {
053: priKey = getField(catalog, priKeyField, true, false);
054: } else {
055: priKey = null;
056: }
057: if (secKeyFields.size() > 0) {
058: secKeys = getFields(catalog, secKeyFields, false, false);
059: } else {
060: secKeys = EMPTY_KEYS;
061: }
062: if (nonKeyFields.size() > 0) {
063: nonKeys = getFields(catalog, nonKeyFields, false, false);
064: } else {
065: nonKeys = EMPTY_KEYS;
066: }
067: }
068:
069: ReflectionAccessor(Catalog catalog, Class type,
070: List<FieldInfo> fieldInfos) {
071: this (type, null);
072: priKey = null;
073: secKeys = EMPTY_KEYS;
074: nonKeys = getFields(catalog, fieldInfos, true, true);
075: }
076:
077: private FieldAccess[] getFields(Catalog catalog,
078: List<FieldInfo> fieldInfos, boolean isRequiredKeyField,
079: boolean isCompositeKey) {
080: int index = 0;
081: FieldAccess[] fields = new FieldAccess[fieldInfos.size()];
082: for (FieldInfo info : fieldInfos) {
083: fields[index] = getField(catalog, info, isRequiredKeyField,
084: isCompositeKey);
085: index += 1;
086: }
087: return fields;
088: }
089:
090: private FieldAccess getField(Catalog catalog, FieldInfo fieldInfo,
091: boolean isRequiredKeyField, boolean isCompositeKey) {
092: Field field;
093: try {
094: field = type.getDeclaredField(fieldInfo.getName());
095: } catch (NoSuchFieldException e) {
096: throw new IllegalStateException(e);
097: }
098: if (!Modifier.isPublic(field.getModifiers())) {
099: setAccessible(field, field.getName());
100: }
101: Class fieldCls = field.getType();
102: if (fieldCls.isPrimitive()) {
103: assert SimpleCatalog.isSimpleType(fieldCls);
104: return new PrimitiveAccess(field, SimpleCatalog
105: .getSimpleFormat(fieldCls));
106: } else if (isRequiredKeyField) {
107: Format format = catalog.getFormat(fieldCls);
108: if (isCompositeKey && !SimpleCatalog.isSimpleType(fieldCls)) {
109: throw new IllegalArgumentException(
110: "Composite key class has non-simple type field: "
111: + type.getName() + '.'
112: + field.getName());
113: }
114: return new KeyObjectAccess(field, format);
115: } else {
116: return new ObjectAccess(field);
117: }
118: }
119:
120: private void setAccessible(AccessibleObject object,
121: String memberName) {
122: try {
123: object.setAccessible(true);
124: } catch (SecurityException e) {
125: throw new IllegalStateException(
126: "Unable to access non-public member: "
127: + type.getName()
128: + '.'
129: + memberName
130: + ". Please configure the Java Security Manager setting: "
131: + " ReflectPermission suppressAccessChecks",
132: e);
133: }
134: }
135:
136: public Object newInstance() {
137: try {
138: return constructor.newInstance();
139: } catch (IllegalAccessException e) {
140: throw new IllegalStateException(e);
141: } catch (InstantiationException e) {
142: throw new IllegalStateException(e);
143: } catch (InvocationTargetException e) {
144: throw new IllegalStateException(e);
145: }
146: }
147:
148: public Object newArray(int len) {
149: return Array.newInstance(type, len);
150: }
151:
152: public boolean isPriKeyFieldNullOrZero(Object o) {
153: try {
154: if (priKey != null) {
155: return priKey.isNullOrZero(o);
156: } else if (super Accessor != null) {
157: return super Accessor.isPriKeyFieldNullOrZero(o);
158: } else {
159: throw new IllegalStateException("No primary key field");
160: }
161: } catch (IllegalAccessException e) {
162: throw new IllegalStateException(e);
163: }
164: }
165:
166: public void writePriKeyField(Object o, EntityOutput output) {
167: try {
168: if (priKey != null) {
169: priKey.write(o, output);
170: } else if (super Accessor != null) {
171: super Accessor.writePriKeyField(o, output);
172: } else {
173: throw new IllegalStateException("No primary key field");
174: }
175: } catch (IllegalAccessException e) {
176: throw new IllegalStateException(e);
177: }
178: }
179:
180: public void readPriKeyField(Object o, EntityInput input) {
181: try {
182: if (priKey != null) {
183: priKey.read(o, input);
184: } else if (super Accessor != null) {
185: super Accessor.readPriKeyField(o, input);
186: } else {
187: throw new IllegalStateException("No primary key field");
188: }
189: } catch (IllegalAccessException e) {
190: throw new IllegalStateException(e);
191: }
192: }
193:
194: public void writeSecKeyFields(Object o, EntityOutput output) {
195: try {
196: if (priKey != null && !priKey.isPrimitive) {
197: output.registerPriKeyObject(priKey.field.get(o));
198: }
199: if (super Accessor != null) {
200: super Accessor.writeSecKeyFields(o, output);
201: }
202: for (int i = 0; i < secKeys.length; i += 1) {
203: secKeys[i].write(o, output);
204: }
205: } catch (IllegalAccessException e) {
206: throw new IllegalStateException(e);
207: }
208: }
209:
210: public void readSecKeyFields(Object o, EntityInput input,
211: int startField, int endField, int super Level) {
212: try {
213: if (priKey != null && !priKey.isPrimitive) {
214: input.registerPriKeyObject(priKey.field.get(o));
215: }
216: if (super Level != 0 && super Accessor != null) {
217: super Accessor.readSecKeyFields(o, input, startField,
218: endField, super Level - 1);
219: } else {
220: if (super Level > 0) {
221: throw new IllegalStateException(
222: "Superclass does not exist");
223: }
224: }
225: if (super Level <= 0) {
226: for (int i = startField; i <= endField
227: && i < secKeys.length; i += 1) {
228: secKeys[i].read(o, input);
229: }
230: }
231: } catch (IllegalAccessException e) {
232: throw new IllegalStateException(e);
233: }
234: }
235:
236: public void writeNonKeyFields(Object o, EntityOutput output) {
237: try {
238: if (super Accessor != null) {
239: super Accessor.writeNonKeyFields(o, output);
240: }
241: for (int i = 0; i < nonKeys.length; i += 1) {
242: nonKeys[i].write(o, output);
243: }
244: } catch (IllegalAccessException e) {
245: throw new IllegalStateException(e);
246: }
247: }
248:
249: public void readNonKeyFields(Object o, EntityInput input,
250: int startField, int endField, int super Level) {
251: try {
252: if (super Level != 0 && super Accessor != null) {
253: super Accessor.readNonKeyFields(o, input, startField,
254: endField, super Level - 1);
255: } else {
256: if (super Level > 0) {
257: throw new IllegalStateException(
258: "Superclass does not exist");
259: }
260: }
261: if (super Level <= 0) {
262: for (int i = startField; i <= endField
263: && i < nonKeys.length; i += 1) {
264: nonKeys[i].read(o, input);
265: }
266: }
267: } catch (IllegalAccessException e) {
268: throw new IllegalStateException(e);
269: }
270: }
271:
272: public Object getField(Object o, int field, int super Level,
273: boolean isSecField) {
274: if (super Level > 0) {
275: return super Accessor.getField(o, field, super Level - 1,
276: isSecField);
277: }
278: try {
279: Field fld = isSecField ? secKeys[field].field
280: : nonKeys[field].field;
281: return fld.get(o);
282: } catch (IllegalAccessException e) {
283: throw new IllegalStateException(e);
284: }
285: }
286:
287: public void setField(Object o, int field, int super Level,
288: boolean isSecField, Object value) {
289: if (super Level > 0) {
290: super Accessor.setField(o, field, super Level - 1,
291: isSecField, value);
292: return;
293: }
294: try {
295: Field fld = isSecField ? secKeys[field].field
296: : nonKeys[field].field;
297: fld.set(o, value);
298: } catch (IllegalAccessException e) {
299: throw new IllegalStateException(e);
300: }
301: }
302:
303: /**
304: * Abstract base class for field access classes.
305: */
306: private static abstract class FieldAccess {
307:
308: Field field;
309: boolean isPrimitive;
310:
311: FieldAccess(Field field) {
312: this .field = field;
313: isPrimitive = field.getType().isPrimitive();
314: }
315:
316: /**
317: * Writes a field.
318: */
319: abstract void write(Object o, EntityOutput out)
320: throws IllegalAccessException;
321:
322: /**
323: * Reads a field.
324: */
325: abstract void read(Object o, EntityInput in)
326: throws IllegalAccessException;
327:
328: /**
329: * Returns whether a field is null (for reference types) or zero (for
330: * primitive integer types). This implementation handles the reference
331: * types.
332: */
333: boolean isNullOrZero(Object o) throws IllegalAccessException {
334:
335: return field.get(o) == null;
336: }
337: }
338:
339: /**
340: * Access for fields with object types.
341: */
342: private static class ObjectAccess extends FieldAccess {
343:
344: ObjectAccess(Field field) {
345: super (field);
346: }
347:
348: @Override
349: void write(Object o, EntityOutput out)
350: throws IllegalAccessException {
351:
352: out.writeObject(field.get(o), null);
353: }
354:
355: @Override
356: void read(Object o, EntityInput in)
357: throws IllegalAccessException {
358:
359: field.set(o, in.readObject());
360: }
361: }
362:
363: /**
364: * Access for primary key fields and composite key fields with object
365: * types.
366: */
367: private static class KeyObjectAccess extends FieldAccess {
368:
369: private Format format;
370:
371: KeyObjectAccess(Field field, Format format) {
372: super (field);
373: this .format = format;
374: }
375:
376: @Override
377: void write(Object o, EntityOutput out)
378: throws IllegalAccessException {
379:
380: out.writeKeyObject(field.get(o), format);
381: }
382:
383: @Override
384: void read(Object o, EntityInput in)
385: throws IllegalAccessException {
386:
387: field.set(o, in.readKeyObject(format));
388: }
389: }
390:
391: /**
392: * Access for fields with primitive types.
393: */
394: private static class PrimitiveAccess extends FieldAccess {
395:
396: private SimpleFormat format;
397:
398: PrimitiveAccess(Field field, SimpleFormat format) {
399: super (field);
400: this .format = format;
401: }
402:
403: @Override
404: void write(Object o, EntityOutput out)
405: throws IllegalAccessException {
406:
407: format.writePrimitiveField(o, out, field);
408: }
409:
410: @Override
411: void read(Object o, EntityInput in)
412: throws IllegalAccessException {
413:
414: format.readPrimitiveField(o, in, field);
415: }
416:
417: @Override
418: boolean isNullOrZero(Object o) throws IllegalAccessException {
419:
420: return field.getLong(o) == 0;
421: }
422: }
423: }
|