001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.openjpa.util;
020:
021: import java.lang.reflect.Field;
022: import java.lang.reflect.Modifier;
023: import java.math.BigDecimal;
024: import java.math.BigInteger;
025: import java.security.AccessController;
026: import java.security.PrivilegedActionException;
027: import java.util.Date;
028:
029: import org.apache.openjpa.enhance.FieldManager;
030: import org.apache.openjpa.enhance.PCRegistry;
031: import org.apache.openjpa.enhance.PersistenceCapable;
032: import org.apache.openjpa.enhance.Reflection;
033: import org.apache.openjpa.kernel.ObjectIdStateManager;
034: import org.apache.openjpa.kernel.OpenJPAStateManager;
035: import org.apache.openjpa.kernel.StateManagerImpl;
036: import org.apache.openjpa.kernel.StoreManager;
037: import org.apache.openjpa.lib.util.J2DoPrivHelper;
038: import org.apache.openjpa.lib.util.Localizer;
039: import org.apache.openjpa.meta.ClassMetaData;
040: import org.apache.openjpa.meta.FieldMetaData;
041: import org.apache.openjpa.meta.JavaTypes;
042: import org.apache.openjpa.meta.ValueStrategies;
043: import serp.util.Numbers;
044:
045: /**
046: * Utility class for manipulating application object ids.
047: *
048: * @author Abe White
049: * @nojavadoc
050: */
051: public class ApplicationIds {
052:
053: private static final Localizer _loc = Localizer
054: .forPackage(ApplicationIds.class);
055: private static final Localizer _loc2 = Localizer
056: .forPackage(StateManagerImpl.class);
057:
058: /**
059: * Return the primary key values for the given object id. The values
060: * will be returned in the same order as the metadata primary key fields.
061: * Values for PC primary key fields will be the primarky key value or
062: * oid value of the related instance (depending on
063: * {@link FieldMetaData#isObjectIdFieldIdOfPC}).
064: */
065: public static Object[] toPKValues(Object oid, ClassMetaData meta) {
066: if (meta == null)
067: return null;
068:
069: Object[] pks;
070: if (meta.isOpenJPAIdentity()) {
071: pks = new Object[1];
072: if (oid != null)
073: pks[0] = ((OpenJPAId) oid).getIdObject();
074: return pks;
075: }
076:
077: // reset owning 'meta' to the owner of the primary key fields, because
078: // the one passed in might be a proxy, like for embedded mappings;
079: // since getPrimaryKeyFields is guaranteed to return the primary
080: // keys in the order of inheritance, we are guaranteed that
081: // the last element will be the most-derived class.
082: FieldMetaData[] fmds = meta.getPrimaryKeyFields();
083: meta = fmds[fmds.length - 1].getDeclaringMetaData();
084: pks = new Object[fmds.length];
085: if (oid == null)
086: return pks;
087:
088: if (!Modifier
089: .isAbstract(meta.getDescribedType().getModifiers())) {
090: // copy fields from the oid
091: PrimaryKeyFieldManager consumer = new PrimaryKeyFieldManager();
092: consumer.setStore(pks);
093: PCRegistry.copyKeyFieldsFromObjectId(meta
094: .getDescribedType(), consumer, oid);
095: return consumer.getStore();
096: }
097:
098: // default to reflection
099: if (meta.isObjectIdTypeShared())
100: oid = ((ObjectId) oid).getId();
101: Class oidType = oid.getClass();
102: for (int i = 0; i < fmds.length; i++) {
103: if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD)
104: pks[i] = Reflection.get(oid, Reflection.findField(
105: oidType, fmds[i].getName(), true));
106: else
107: pks[i] = Reflection.get(oid, Reflection.findGetter(
108: oidType, fmds[i].getName(), true));
109: }
110: return pks;
111: }
112:
113: /**
114: * Return a new object id constructed from the given primary key values.
115: * Values for PC primary key fields should be the primarky key value or
116: * oid value of the related instance (depending on
117: * {@link FieldMetaData#isObjectIdFieldIdOfPC}).
118: */
119: public static Object fromPKValues(Object[] pks, ClassMetaData meta) {
120: if (meta == null || pks == null)
121: return null;
122:
123: boolean convert = !meta.getRepository().getConfiguration()
124: .getCompatibilityInstance().getStrictIdentityValues();
125: if (meta.isOpenJPAIdentity()) {
126: int type = meta.getPrimaryKeyFields()[0]
127: .getObjectIdFieldTypeCode();
128: Object val = (convert) ? JavaTypes.convert(pks[0], type)
129: : pks[0];
130: switch (type) {
131: case JavaTypes.BYTE:
132: case JavaTypes.BYTE_OBJ:
133: if (!convert && !(val instanceof Byte))
134: throw new ClassCastException("!(x instanceof Byte)");
135: return new ByteId(meta.getDescribedType(),
136: val == null ? 0 : ((Number) val).byteValue());
137: case JavaTypes.CHAR:
138: case JavaTypes.CHAR_OBJ:
139: return new CharId(meta.getDescribedType(),
140: val == null ? 0 : ((Character) val).charValue());
141: case JavaTypes.DOUBLE:
142: case JavaTypes.DOUBLE_OBJ:
143: if (!convert && !(val instanceof Double))
144: throw new ClassCastException(
145: "!(x instanceof Double)");
146: return new DoubleId(meta.getDescribedType(),
147: val == null ? 0 : ((Number) val).doubleValue());
148: case JavaTypes.FLOAT:
149: case JavaTypes.FLOAT_OBJ:
150: if (!convert && !(val instanceof Float))
151: throw new ClassCastException(
152: "!(x instanceof Float)");
153: return new FloatId(meta.getDescribedType(),
154: val == null ? 0 : ((Number) val).floatValue());
155: case JavaTypes.INT:
156: case JavaTypes.INT_OBJ:
157: if (!convert && !(val instanceof Integer))
158: throw new ClassCastException(
159: "!(x instanceof Integer)");
160: return new IntId(meta.getDescribedType(),
161: val == null ? 0 : ((Number) val).intValue());
162: case JavaTypes.LONG:
163: case JavaTypes.LONG_OBJ:
164: if (!convert && !(val instanceof Long))
165: throw new ClassCastException("!(x instanceof Long)");
166: return new LongId(meta.getDescribedType(),
167: val == null ? 0 : ((Number) val).longValue());
168: case JavaTypes.SHORT:
169: case JavaTypes.SHORT_OBJ:
170: if (!convert && !(val instanceof Short))
171: throw new ClassCastException(
172: "!(x instanceof Short)");
173: return new ShortId(meta.getDescribedType(),
174: val == null ? 0 : ((Number) val).shortValue());
175: case JavaTypes.STRING:
176: return new StringId(meta.getDescribedType(),
177: (String) val);
178: case JavaTypes.DATE:
179: return new DateId(meta.getDescribedType(), (Date) val);
180: case JavaTypes.OID:
181: case JavaTypes.OBJECT:
182: return new ObjectId(meta.getDescribedType(), val);
183: case JavaTypes.BIGDECIMAL:
184: if (!convert && !(val instanceof BigDecimal))
185: throw new ClassCastException(
186: "!(x instanceof BigDecimal)");
187: return new BigDecimalId(meta.getDescribedType(),
188: (BigDecimal) val);
189: case JavaTypes.BIGINTEGER:
190: if (!convert && !(val instanceof BigInteger))
191: throw new ClassCastException(
192: "!(x instanceof BigInteger)");
193: return new BigIntegerId(meta.getDescribedType(),
194: (BigInteger) val);
195: default:
196: throw new InternalException();
197: }
198: }
199:
200: // copy pks to oid
201: if (!Modifier
202: .isAbstract(meta.getDescribedType().getModifiers())) {
203: Object oid = PCRegistry
204: .newObjectId(meta.getDescribedType());
205: PrimaryKeyFieldManager producer = new PrimaryKeyFieldManager();
206: producer.setStore(pks);
207: if (convert)
208: producer.setMetaData(meta);
209: PCRegistry.copyKeyFieldsToObjectId(meta.getDescribedType(),
210: producer, oid);
211: return oid;
212: }
213:
214: // default to reflection
215: Class oidType = meta.getObjectIdType();
216: if (Modifier.isAbstract(oidType.getModifiers()))
217: throw new UserException(_loc.get("objectid-abstract", meta));
218: Object copy = null;
219: try {
220: copy = AccessController.doPrivileged(J2DoPrivHelper
221: .newInstanceAction(oidType));
222: } catch (Throwable t) {
223: if (t instanceof PrivilegedActionException)
224: t = ((PrivilegedActionException) t).getException();
225: throw new GeneralException(t);
226: }
227:
228: FieldMetaData[] fmds = meta.getPrimaryKeyFields();
229: Object val;
230: for (int i = 0; i < fmds.length; i++) {
231: val = (convert) ? JavaTypes.convert(pks[i], fmds[i]
232: .getObjectIdFieldTypeCode()) : pks[i];
233: if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD)
234: Reflection.set(copy, Reflection.findField(oidType,
235: fmds[i].getName(), true), val);
236: else
237: Reflection.set(copy, Reflection.findSetter(oidType,
238: fmds[i].getName(), fmds[i].getDeclaredType(),
239: true), val);
240: }
241:
242: if (meta.isObjectIdTypeShared())
243: copy = new ObjectId(meta.getDescribedType(), copy);
244: return copy;
245: }
246:
247: /**
248: * Copy the given oid value.
249: */
250: public static Object copy(Object oid, ClassMetaData meta) {
251: if (meta == null || oid == null)
252: return null;
253:
254: if (meta.isOpenJPAIdentity()) {
255: // use meta type instead of oid type in case it's a subclass
256: Class cls = meta.getDescribedType();
257: OpenJPAId koid = (OpenJPAId) oid;
258: FieldMetaData pk = meta.getPrimaryKeyFields()[0];
259: switch (pk.getObjectIdFieldTypeCode()) {
260: case JavaTypes.BYTE:
261: case JavaTypes.BYTE_OBJ:
262: return new ByteId(cls, ((ByteId) oid).getId(), koid
263: .hasSubclasses());
264: case JavaTypes.CHAR:
265: case JavaTypes.CHAR_OBJ:
266: return new CharId(cls, ((CharId) oid).getId(), koid
267: .hasSubclasses());
268: case JavaTypes.DOUBLE:
269: case JavaTypes.DOUBLE_OBJ:
270: return new DoubleId(cls, ((DoubleId) oid).getId(), koid
271: .hasSubclasses());
272: case JavaTypes.FLOAT:
273: case JavaTypes.FLOAT_OBJ:
274: return new FloatId(cls, ((FloatId) oid).getId(), koid
275: .hasSubclasses());
276: case JavaTypes.INT:
277: case JavaTypes.INT_OBJ:
278: return new IntId(cls, ((IntId) oid).getId(), koid
279: .hasSubclasses());
280: case JavaTypes.LONG:
281: case JavaTypes.LONG_OBJ:
282: return new LongId(cls, ((LongId) oid).getId(), koid
283: .hasSubclasses());
284: case JavaTypes.SHORT:
285: case JavaTypes.SHORT_OBJ:
286: return new ShortId(cls, ((ShortId) oid).getId(), koid
287: .hasSubclasses());
288: case JavaTypes.STRING:
289: return new StringId(cls, oid.toString(), koid
290: .hasSubclasses());
291: case JavaTypes.OID:
292: ClassMetaData embed = pk.getEmbeddedMetaData();
293: Object inner = koid.getIdObject();
294: if (embed != null)
295: inner = copy(inner, embed, embed.getFields());
296: return new ObjectId(cls, inner, koid.hasSubclasses());
297: case JavaTypes.OBJECT:
298: return new ObjectId(cls, koid.getIdObject(), koid
299: .hasSubclasses());
300: case JavaTypes.DATE:
301: return new DateId(cls, ((DateId) oid).getId(), koid
302: .hasSubclasses());
303: case JavaTypes.BIGDECIMAL:
304: return new BigDecimalId(cls, ((BigDecimalId) oid)
305: .getId(), koid.hasSubclasses());
306: case JavaTypes.BIGINTEGER:
307: return new BigIntegerId(cls, ((BigIntegerId) oid)
308: .getId(), koid.hasSubclasses());
309: default:
310: throw new InternalException();
311: }
312: }
313:
314: // create a new pc instance of the right type, set its key fields
315: // to the original oid values, then copy its key fields to a new
316: // oid instance
317: if (!Modifier
318: .isAbstract(meta.getDescribedType().getModifiers())
319: && !hasPCPrimaryKeyFields(meta)) {
320: Class type = meta.getDescribedType();
321: PersistenceCapable pc = PCRegistry.newInstance(type, null,
322: oid, false);
323: Object copy = pc.pcNewObjectIdInstance();
324: pc.pcCopyKeyFieldsToObjectId(copy);
325: return copy;
326: }
327:
328: Object copy = (!meta.isObjectIdTypeShared()) ? oid
329: : ((ObjectId) oid).getId();
330: copy = copy(copy, meta, meta.getPrimaryKeyFields());
331: if (meta.isObjectIdTypeShared())
332: copy = new ObjectId(meta.getDescribedType(), copy,
333: ((OpenJPAId) oid).hasSubclasses());
334: return copy;
335: }
336:
337: /**
338: * Return true if any of the given type's primary key fields are
339: * persistent objects.
340: */
341: private static boolean hasPCPrimaryKeyFields(ClassMetaData meta) {
342: FieldMetaData[] fmds = meta.getPrimaryKeyFields();
343: for (int i = 0; i < fmds.length; i++)
344: if (fmds[i].getDeclaredTypeCode() == JavaTypes.PC)
345: return true;
346: return false;
347: }
348:
349: /**
350: * Copy the given identity object using reflection.
351: */
352: private static Object copy(Object oid, ClassMetaData meta,
353: FieldMetaData[] fmds) {
354: if (oid == null)
355: return null;
356:
357: Class oidType = oid.getClass();
358: Object copy = null;
359: try {
360: copy = AccessController.doPrivileged(J2DoPrivHelper
361: .newInstanceAction(oidType));
362: } catch (Throwable t) {
363: if (t instanceof PrivilegedActionException)
364: t = ((PrivilegedActionException) t).getException();
365: throw new GeneralException(t);
366: }
367:
368: Field field;
369: Object val;
370: for (int i = 0; i < fmds.length; i++) {
371: if (fmds[i].getManagement() != FieldMetaData.MANAGE_PERSISTENT)
372: continue;
373:
374: if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD) {
375: field = Reflection.findField(oidType,
376: fmds[i].getName(), true);
377: Reflection.set(copy, field, Reflection.get(oid, field));
378: } else { // property
379: val = Reflection.get(oid, Reflection.findGetter(
380: oidType, fmds[i].getName(), true));
381: Reflection.set(copy, Reflection.findSetter(oidType,
382: fmds[i].getName(), fmds[i]
383: .getObjectIdFieldType(), true), val);
384: }
385: }
386: return copy;
387: }
388:
389: /**
390: * Return the given primary key field value from the given oid.
391: */
392: public static Object get(Object oid, FieldMetaData fmd) {
393: if (oid == null)
394: return null;
395: if (oid instanceof OpenJPAId)
396: return ((OpenJPAId) oid).getIdObject();
397:
398: ClassMetaData meta = fmd.getDefiningMetaData();
399: Class oidType = oid.getClass();
400: if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD)
401: return Reflection.get(oid, Reflection.findField(oidType,
402: fmd.getName(), true));
403: return Reflection.get(oid, Reflection.findGetter(oidType, fmd
404: .getName(), true));
405: }
406:
407: /**
408: * Generate an application id based on the current primary key field state
409: * of the given instance.
410: */
411: public static Object create(PersistenceCapable pc,
412: ClassMetaData meta) {
413: if (pc == null)
414: return null;
415:
416: Object oid = pc.pcNewObjectIdInstance();
417: if (oid == null)
418: return null;
419:
420: if (!meta.isOpenJPAIdentity()) {
421: pc.pcCopyKeyFieldsToObjectId(oid);
422: return oid;
423: }
424:
425: FieldMetaData pk = meta.getPrimaryKeyFields()[0];
426: if (pk.getDeclaredTypeCode() != JavaTypes.OID)
427: return oid;
428:
429: // always copy oid object in case field value mutates or becomes
430: // managed
431: ObjectId objid = (ObjectId) oid;
432: ClassMetaData embed = pk.getEmbeddedMetaData();
433: objid.setId(copy(objid.getId(), embed, embed.getFields()));
434: return objid;
435: }
436:
437: /**
438: * Assign an application identity object to the given state, or return
439: * false if determining the application identity requires a flush.
440: */
441: public static boolean assign(OpenJPAStateManager sm,
442: StoreManager store, boolean preFlush) {
443: ClassMetaData meta = sm.getMetaData();
444: if (meta.getIdentityType() != ClassMetaData.ID_APPLICATION)
445: throw new InternalException();
446:
447: boolean ret;
448: FieldMetaData[] pks = meta.getPrimaryKeyFields();
449: if (meta.isOpenJPAIdentity()
450: && pks[0].getDeclaredTypeCode() == JavaTypes.OID) {
451: OpenJPAStateManager oidsm = new ObjectIdStateManager(sm
452: .fetchObjectField(pks[0].getIndex()), sm, pks[0]);
453: ret = assign(oidsm, store, pks[0].getEmbeddedMetaData()
454: .getFields(), preFlush);
455: sm.storeObjectField(pks[0].getIndex(), oidsm
456: .getManagedInstance());
457: } else
458: ret = assign(sm, store, meta.getPrimaryKeyFields(),
459: preFlush);
460: if (!ret)
461: return false;
462:
463: // base oid on field values
464: sm.setObjectId(create(sm.getPersistenceCapable(), meta));
465: return true;
466: }
467:
468: /**
469: * Assign generated values to given primary key fields.
470: */
471: private static boolean assign(OpenJPAStateManager sm,
472: StoreManager store, FieldMetaData[] pks, boolean preFlush) {
473: for (int i = 0; i < pks.length; i++)
474: // If we are generating values...
475: if (pks[i].getValueStrategy() != ValueStrategies.NONE) {
476: // If a value already exists on this field, throw exception.
477: // This is considered an application coding error.
478: if (!sm.isDefaultValue(pks[i].getIndex()))
479: throw new InvalidStateException(_loc2.get(
480: "existing-value-override-excep", pks[i]
481: .getFullName(false)));
482: // Assign the generated value
483: if (store.assignField(sm, pks[i].getIndex(), preFlush))
484: pks[i].setValueGenerated(true);
485: else
486: return false;
487: }
488: return true;
489: }
490:
491: /**
492: * Helper class used to transfer pk values to/from application oids.
493: */
494: private static class PrimaryKeyFieldManager implements FieldManager {
495:
496: private Object[] _store = null;
497: private int _index = 0;
498: private ClassMetaData _meta = null;
499:
500: public void setMetaData(ClassMetaData meta) {
501: _meta = meta;
502: }
503:
504: public Object[] getStore() {
505: return _store;
506: }
507:
508: public void setStore(Object[] store) {
509: _store = store;
510: }
511:
512: public void storeBooleanField(int field, boolean val) {
513: store((val) ? Boolean.TRUE : Boolean.FALSE);
514: }
515:
516: public void storeByteField(int field, byte val) {
517: store(new Byte(val));
518: }
519:
520: public void storeCharField(int field, char val) {
521: store(new Character(val));
522: }
523:
524: public void storeShortField(int field, short val) {
525: store(new Short(val));
526: }
527:
528: public void storeIntField(int field, int val) {
529: store(Numbers.valueOf(val));
530: }
531:
532: public void storeLongField(int field, long val) {
533: store(Numbers.valueOf(val));
534: }
535:
536: public void storeFloatField(int field, float val) {
537: store(new Float(val));
538: }
539:
540: public void storeDoubleField(int field, double val) {
541: store(new Double(val));
542: }
543:
544: public void storeStringField(int field, String val) {
545: store(val);
546: }
547:
548: public void storeObjectField(int field, Object val) {
549: store(val);
550: }
551:
552: public boolean fetchBooleanField(int field) {
553: return (retrieve(field) == Boolean.TRUE) ? true : false;
554: }
555:
556: public char fetchCharField(int field) {
557: return ((Character) retrieve(field)).charValue();
558: }
559:
560: public byte fetchByteField(int field) {
561: return ((Number) retrieve(field)).byteValue();
562: }
563:
564: public short fetchShortField(int field) {
565: return ((Number) retrieve(field)).shortValue();
566: }
567:
568: public int fetchIntField(int field) {
569: return ((Number) retrieve(field)).intValue();
570: }
571:
572: public long fetchLongField(int field) {
573: return ((Number) retrieve(field)).longValue();
574: }
575:
576: public float fetchFloatField(int field) {
577: return ((Number) retrieve(field)).floatValue();
578: }
579:
580: public double fetchDoubleField(int field) {
581: return ((Number) retrieve(field)).doubleValue();
582: }
583:
584: public String fetchStringField(int field) {
585: return (String) retrieve(field);
586: }
587:
588: public Object fetchObjectField(int field) {
589: return retrieve(field);
590: }
591:
592: private void store(Object val) {
593: _store[_index++] = val;
594: }
595:
596: private Object retrieve(int field) {
597: Object val = _store[_index++];
598: if (_meta != null) {
599: FieldMetaData fmd = _meta.getField(field);
600: if (fmd.getDeclaredTypeCode() != JavaTypes.PC)
601: val = JavaTypes.convert(val, fmd
602: .getDeclaredTypeCode());
603: else
604: val = JavaTypes.convert(val, JavaTypes
605: .getTypeCode(fmd.getObjectIdFieldType()));
606: }
607: return val;
608: }
609: }
610: }
|