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

Save This Page
Home » apache-openjpa-1.1.0-source » org.apache.openjpa » util » [javadoc | source]