Home » apache-openjpa-1.1.0-source » org.apache.openjpa » kernel » [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.kernel;
   20   
   21   import java.util.Collection;
   22   import java.util.Iterator;
   23   import java.util.Map;
   24   
   25   import org.apache.openjpa.enhance.PersistenceCapable;
   26   import org.apache.openjpa.enhance.StateManager;
   27   import org.apache.openjpa.lib.util.Localizer;
   28   import org.apache.openjpa.meta.ClassMetaData;
   29   import org.apache.openjpa.meta.FieldMetaData;
   30   import org.apache.openjpa.meta.JavaTypes;
   31   import org.apache.openjpa.meta.ValueMetaData;
   32   import org.apache.openjpa.meta.ValueStrategies;
   33   import org.apache.openjpa.util.ApplicationIds;
   34   import org.apache.openjpa.util.ObjectNotFoundException;
   35   import org.apache.openjpa.util.OptimisticException;
   36   import org.apache.openjpa.util.ImplHelper;
   37   import org.apache.openjpa.event.LifecycleEvent;
   38   
   39   /**
   40    * Handles attaching instances using version and primary key fields.
   41    *
   42    * @nojavadoc
   43    * @author Steve Kim
   44    */
   45   class VersionAttachStrategy
   46       extends AttachStrategy
   47       implements DetachState {
   48   
   49       private static final Localizer _loc = Localizer.forPackage
   50           (VersionAttachStrategy.class);
   51   
   52       protected Object getDetachedObjectId(AttachManager manager,
   53           Object toAttach) {
   54           Broker broker = manager.getBroker();
   55           ClassMetaData meta = broker.getConfiguration().
   56               getMetaDataRepositoryInstance().getMetaData(
   57                   ImplHelper.getManagedInstance(toAttach).getClass(),
   58                   broker.getClassLoader(), true);
   59           return ApplicationIds.create(ImplHelper.toPersistenceCapable(toAttach,
   60               broker.getConfiguration()),
   61               meta);
   62       }
   63   
   64       protected void provideField(Object toAttach, StateManagerImpl sm,
   65           int field) {
   66           sm.provideField(ImplHelper.toPersistenceCapable(toAttach,
   67               sm.getContext().getConfiguration()), this, field);
   68       }
   69   
   70       public Object attach(AttachManager manager, Object toAttach,
   71           ClassMetaData meta, PersistenceCapable into, OpenJPAStateManager owner,
   72           ValueMetaData ownerMeta, boolean explicit) {
   73           BrokerImpl broker = manager.getBroker();
   74           PersistenceCapable pc = ImplHelper.toPersistenceCapable(toAttach,
   75               meta.getRepository().getConfiguration());
   76   
   77           boolean embedded = ownerMeta != null && ownerMeta.isEmbeddedPC();
   78           boolean isNew = !broker.isDetached(pc);
   79           Object version = null;
   80           StateManagerImpl sm;
   81   
   82           // if the state manager for the embedded instance is null, then
   83           // it should be treated as a new instance (since the
   84           // newly persisted owner may create a new embedded instance
   85           // in the constructor); fixed bug #1075.
   86           // also, if the user has attached a detached obj from somewhere
   87           // else in the graph to an embedded field that was previously null,
   88           // copy into a new embedded instance
   89           if (embedded && (isNew || into == null
   90               || broker.getStateManager(into) == null)) {
   91               if (into == null)
   92                   into = pc.pcNewInstance(null, false);
   93               sm = (StateManagerImpl) broker.embed(into, null, owner, ownerMeta);
   94               into = sm.getPersistenceCapable();
   95           } else if (isNew) {
   96               Object oid = null;
   97               if (!isPrimaryKeysGenerated(meta))
   98                   oid = ApplicationIds.create(pc, meta);
   99   
  100               sm = persist(manager, pc, meta, oid, explicit);
  101               into = sm.getPersistenceCapable();
  102           } else if (!embedded && into == null) {
  103               Object id = getDetachedObjectId(manager, toAttach);
  104               if (id != null)
  105                   into =
  106                       ImplHelper.toPersistenceCapable(broker.find(id, true, null),
  107                           broker.getConfiguration());
  108               if (into == null)
  109                   throw new OptimisticException(_loc.get("attach-version-del",
  110                       ImplHelper.getManagedInstance(pc).getClass(), id, version))
  111                       .setFailedObject(toAttach);
  112   
  113               sm = manager.assertManaged(into);
  114               if (meta.getDescribedType()
  115                   != sm.getMetaData().getDescribedType()) {
  116                   throw new ObjectNotFoundException(_loc.get
  117                       ("attach-wrongclass", id, toAttach.getClass(),
  118                           sm.getMetaData().getDescribedType())).
  119                       setFailedObject(toAttach);
  120               }
  121           } else
  122               sm = manager.assertManaged(into);
  123   
  124           // mark that we attached the instance *before* we
  125           // fill in values to avoid endless recursion
  126           manager.setAttachedCopy(toAttach, into);
  127   
  128           // if persisting in place, just attach field values
  129           if (pc == into) {
  130               attachFieldsInPlace(manager, sm);
  131               return into;
  132           }
  133   
  134           if (isNew) {
  135               broker.fireLifecycleEvent(toAttach, null, meta,
  136                   LifecycleEvent.BEFORE_PERSIST);
  137           } else {
  138               // invoke any preAttach on the detached instance
  139               manager.fireBeforeAttach(toAttach, meta);
  140           }
  141   
  142           // assign the detached pc the same state manager as the object we're
  143           // copying into during the attach process
  144           StateManager smBefore = pc.pcGetStateManager();
  145           pc.pcReplaceStateManager(sm);
  146           int detach = (isNew) ? DETACH_ALL : broker.getDetachState();
  147           FetchConfiguration fetch = broker.getFetchConfiguration();
  148           try {
  149               FieldMetaData[] fmds = meta.getFields();
  150               for (int i = 0; i < fmds.length; i++) {
  151                   switch (detach) {
  152                       case DETACH_ALL:
  153                           attachField(manager, toAttach, sm, fmds[i], true);
  154                           break;
  155                       case DETACH_FETCH_GROUPS:
  156                           if (fetch.requiresFetch(fmds[i]) 
  157                               != FetchConfiguration.FETCH_NONE)
  158                               attachField(manager, toAttach, sm, fmds[i], true);
  159                           break;
  160                       case DETACH_LOADED:
  161                           attachField(manager, toAttach, sm, fmds[i], false);
  162                           break;
  163                   }
  164               }
  165           } finally {
  166               pc.pcReplaceStateManager(smBefore);
  167           }
  168           if (!embedded && !isNew)
  169               compareVersion(sm, pc);
  170           return ImplHelper.getManagedInstance(into);
  171       }
  172   
  173       /**
  174        * Make sure the version information is correct in the detached object.
  175        */
  176       private void compareVersion(StateManagerImpl sm, PersistenceCapable pc) {
  177           Object version = pc.pcGetVersion();
  178           if (version == null)
  179               return;
  180   
  181           // don't need to load unloaded fields since its implicitly
  182           // a single field value
  183           StoreManager store = sm.getBroker().getStoreManager();
  184           switch (store.compareVersion(sm, version, sm.getVersion())) {
  185               case StoreManager.VERSION_LATER:
  186                   // we have a later version: set it into the object.
  187                   // lock validation will occur at commit time
  188                   sm.setVersion(version);
  189                   break;
  190               case StoreManager.VERSION_EARLIER:
  191               case StoreManager.VERSION_DIFFERENT:
  192                   sm.setVersion(version);
  193                   throw new OptimisticException(sm.getManagedInstance());
  194               case StoreManager.VERSION_SAME:
  195                   // no action required
  196                   break;
  197           }
  198       }
  199   
  200       /**
  201        * Attach the fields of an in-place persisted instance.
  202        */
  203       private void attachFieldsInPlace(AttachManager manager,
  204           StateManagerImpl sm) {
  205           FieldMetaData[] fmds = sm.getMetaData().getFields();
  206           for (int i = 0; i < fmds.length; i++) {
  207               if (fmds[i].getManagement() != FieldMetaData.MANAGE_PERSISTENT)
  208                   continue;
  209   
  210               Object cur, attached;
  211               switch (fmds[i].getDeclaredTypeCode()) {
  212                   case JavaTypes.PC:
  213                   case JavaTypes.PC_UNTYPED:
  214                       cur = sm.fetchObjectField(i);
  215                       attached = attachInPlace(manager, sm, fmds[i], cur);
  216                       break;
  217                   case JavaTypes.ARRAY:
  218                       if (!fmds[i].getElement().isDeclaredTypePC())
  219                           continue;
  220                       cur = sm.fetchObjectField(i);
  221                       attached =
  222                           attachInPlace(manager, sm, fmds[i], (Object[]) cur);
  223                       break;
  224                   case JavaTypes.COLLECTION:
  225                       if (!fmds[i].getElement().isDeclaredTypePC())
  226                           continue;
  227                       cur = sm.fetchObjectField(i);
  228                       attached = attachInPlace(manager, sm, fmds[i],
  229                           (Collection) cur);
  230                       break;
  231                   case JavaTypes.MAP:
  232                       if (!fmds[i].getElement().isDeclaredTypePC()
  233                           && !fmds[i].getKey().isDeclaredTypePC())
  234                           continue;
  235                       cur = sm.fetchObjectField(i);
  236                       attached = attachInPlace(manager, sm, fmds[i], (Map) cur);
  237                       break;
  238                   default:
  239                       continue;
  240               }
  241   
  242               if (cur != attached)
  243                   sm.settingObjectField(sm.getPersistenceCapable(), i,
  244                       cur, attached, StateManager.SET_REMOTE);
  245           }
  246       }
  247   
  248       /**
  249        * Attach the given pc.
  250        */
  251       private Object attachInPlace(AttachManager manager, StateManagerImpl sm,
  252           ValueMetaData vmd, Object pc) {
  253           if (pc == null)
  254               return null;
  255           Object attached = manager.getAttachedCopy(pc);
  256           if (attached != null)
  257               return attached;
  258   
  259           OpenJPAStateManager into = manager.getBroker().getStateManager(pc);
  260           PersistenceCapable intoPC = (into == null) ? null
  261               : into.getPersistenceCapable();
  262           if (vmd.isEmbedded())
  263               return manager.attach(pc, intoPC, sm, vmd, false);
  264           return manager.attach(pc, intoPC, null, null, false);
  265       }
  266   
  267       /**
  268        * Attach the given array.
  269        */
  270       private Object[] attachInPlace(AttachManager manager, StateManagerImpl sm,
  271           FieldMetaData fmd, Object[] arr) {
  272           if (arr == null)
  273               return null;
  274   
  275           for (int i = 0; i < arr.length; i++)
  276               arr[i] = attachInPlace(manager, sm, fmd.getElement(), arr[i]);
  277           return arr;
  278       }
  279   
  280       /**
  281        * Attach the given collection.
  282        */
  283       private Collection attachInPlace(AttachManager manager,
  284           StateManagerImpl sm, FieldMetaData fmd, Collection coll) {
  285           if (coll == null || coll.isEmpty())
  286               return coll;
  287   
  288           // copy if elements embedded or contains detached, which will mean
  289           // we'll have to copy the existing elements
  290           Collection copy = null;
  291           if (fmd.getElement().isEmbedded())
  292               copy = (Collection) sm.newFieldProxy(fmd.getIndex());
  293           else {
  294               for (Iterator itr = coll.iterator(); itr.hasNext();) {
  295                   if (manager.getBroker().isDetached(itr.next())) {
  296                       copy = (Collection) sm.newFieldProxy(fmd.getIndex());
  297                       break;
  298                   }
  299               }
  300           }
  301   
  302           Object attached;
  303           for (Iterator itr = coll.iterator(); itr.hasNext();) {
  304               attached = attachInPlace(manager, sm, fmd.getElement(),
  305                   itr.next());
  306               if (copy != null)
  307                   copy.add(attached);
  308           }
  309           return (copy == null) ? coll : copy;
  310       }
  311   
  312       /**
  313        * Attach the given map.
  314        */
  315       private Map attachInPlace(AttachManager manager, StateManagerImpl sm,
  316           FieldMetaData fmd, Map map) {
  317           if (map == null || map.isEmpty())
  318               return map;
  319   
  320           Map copy = null;
  321           Map.Entry entry;
  322           boolean keyPC = fmd.getKey().isDeclaredTypePC();
  323           boolean valPC = fmd.getElement().isDeclaredTypePC();
  324   
  325           // copy if embedded pcs or detached pcs, which will require us to
  326           // copy elements
  327           if (fmd.getKey().isEmbeddedPC() || fmd.getElement().isEmbeddedPC())
  328               copy = (Map) sm.newFieldProxy(fmd.getIndex());
  329           else {
  330               for (Iterator itr = map.entrySet().iterator(); itr.hasNext();) {
  331                   entry = (Map.Entry) itr.next();
  332                   if ((keyPC && manager.getBroker().isDetached(entry.getKey()))
  333                       || (valPC && manager.getBroker().isDetached
  334                       (entry.getValue()))) {
  335                       copy = (Map) sm.newFieldProxy(fmd.getIndex());
  336                       break;
  337                   }
  338               }
  339           }
  340   
  341           Object key, val;
  342           for (Iterator itr = map.entrySet().iterator(); itr.hasNext();) {
  343               entry = (Map.Entry) itr.next();
  344               key = entry.getKey();
  345               if (keyPC)
  346                   key = attachInPlace(manager, sm, fmd.getKey(), key);
  347               val = entry.getValue();
  348               if (valPC)
  349                   val = attachInPlace(manager, sm, fmd.getElement(), val);
  350               if (copy != null)
  351                   copy.put(key, val);
  352           }
  353           return (copy == null) ? map : copy;
  354   	}
  355   
  356       /**
  357        * Find a PersistenceCapable instance of an Object if it exists in the
  358        * database. If the object is null or can't be found in the database.
  359        *
  360        * @param pc An object which will be attached into the current context. The
  361        * object may or may not correspond to a row in the database.
  362        *
  363        * @return If the object is null or can't be found in the database this
  364        * method returns null. Otherwise a PersistenceCapable representation of the
  365        * object is returned.
  366        */
  367       protected PersistenceCapable findFromDatabase(AttachManager manager,
  368           Object pc) {
  369           Object oid = manager.getBroker().newObjectId(pc.getClass(),
  370               manager.getDetachedObjectId(pc));
  371   
  372           if (oid != null) {
  373               return ImplHelper.toPersistenceCapable(
  374                   manager.getBroker().find(oid, true, null),
  375                   manager.getBroker().getConfiguration());
  376           } else {
  377               return null;
  378           }
  379       }
  380   
  381       private boolean isPrimaryKeysGenerated(ClassMetaData meta) {
  382           FieldMetaData[] pks = meta.getPrimaryKeyFields();
  383           for (int i = 0; i < pks.length; i++) {
  384               if (pks[i].getValueStrategy() != ValueStrategies.NONE)
  385                   return true;
  386           }
  387           return false;
  388       }
  389   }

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