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.io.IOException;
   22   import java.io.ObjectOutput;
   23   import java.io.Serializable;
   24   import java.sql.Timestamp;
   25   import java.util.Arrays;
   26   import java.util.Calendar;
   27   import java.util.Collection;
   28   import java.util.Date;
   29   import java.util.Iterator;
   30   import java.util.Map;
   31   
   32   import org.apache.openjpa.lib.util.Localizer;
   33   import org.apache.openjpa.meta.FieldMetaData;
   34   import org.apache.openjpa.meta.JavaTypes;
   35   import org.apache.openjpa.meta.ValueMetaData;
   36   import org.apache.openjpa.util.ChangeTracker;
   37   import org.apache.openjpa.util.Exceptions;
   38   import org.apache.openjpa.util.InvalidStateException;
   39   import org.apache.openjpa.util.MapChangeTracker;
   40   import org.apache.openjpa.util.ObjectId;
   41   import org.apache.openjpa.util.Proxies;
   42   import org.apache.openjpa.util.Proxy;
   43   import org.apache.openjpa.util.ProxyManager;
   44   import org.apache.openjpa.util.UserException;
   45   
   46   /**
   47    * FieldManager type used to hold onto a single field value and then
   48    * dispense it via the fetch methods. The manager can also perform actions
   49    * on the held field.
   50    *
   51    * @author Abe White
   52    */
   53   class SingleFieldManager
   54       extends TransferFieldManager
   55       implements Serializable {
   56   
   57       private static final Localizer _loc = Localizer.forPackage
   58           (SingleFieldManager.class);
   59   
   60       private final StateManagerImpl _sm;
   61       private final BrokerImpl _broker;
   62   
   63       public SingleFieldManager(StateManagerImpl sm, BrokerImpl broker) {
   64           _sm = sm;
   65           _broker = broker;
   66       }
   67   
   68       /**
   69        * Proxy the held field if needed. Return true if the field needs to
   70        * be replaced with the now-proxied instance.
   71        */
   72       public boolean proxy(boolean reset, boolean replaceNull) {
   73           FieldMetaData fmd = _sm.getMetaData().getField(field);
   74           Proxy proxy = null;
   75           boolean ret = false;
   76           switch (fmd.getDeclaredTypeCode()) {
   77               case JavaTypes.DATE:
   78                   if (objval == null)
   79                       return false;
   80                   proxy = checkProxy();
   81                   if (proxy == null) {
   82                       proxy = (Proxy) _sm.newFieldProxy(field);
   83                       ((Date) proxy).setTime(((Date) objval).getTime());
   84                       if (proxy instanceof Timestamp 
   85                           && objval instanceof Timestamp)
   86                           ((Timestamp) proxy).setNanos(((Timestamp) objval).
   87                               getNanos());
   88                       ret = true;
   89                   }
   90                   break;
   91               case JavaTypes.CALENDAR:
   92                   if (objval == null)
   93                       return false;
   94                   proxy = checkProxy();
   95                   if (proxy == null) {
   96                       proxy = (Proxy) _sm.newFieldProxy(field);
   97                       ((Calendar) proxy).setTime(((Calendar) objval).getTime());
   98                       ret = true;
   99                   }
  100                   break;
  101               case JavaTypes.COLLECTION:
  102                   if (objval == null && !replaceNull)
  103                       return false;
  104                   proxy = checkProxy();
  105                   if (proxy == null) {
  106                       proxy = (Proxy) _sm.newFieldProxy(field);
  107                       if (objval != null)
  108                           ((Collection) proxy).addAll((Collection) objval);
  109                       ret = true;
  110                   }
  111                   break;
  112               case JavaTypes.MAP:
  113                   if (objval == null && !replaceNull)
  114                       return false;
  115                   proxy = checkProxy();
  116                   if (proxy == null) {
  117                       proxy = (Proxy) _sm.newFieldProxy(field);
  118                       if (objval != null)
  119                           ((Map) proxy).putAll((Map) objval);
  120                       ret = true;
  121                   }
  122                   break;
  123               case JavaTypes.OBJECT:
  124                   if (objval == null)
  125                       return false;
  126                   proxy = checkProxy();
  127                   if (proxy == null) {
  128                       proxy = getProxyManager().newCustomProxy(objval);
  129                       ret = proxy != null;
  130                   }
  131                   break;
  132           }
  133   
  134           if (proxy != null) {
  135               proxy.setOwner(_sm, field);
  136               ChangeTracker tracker = proxy.getChangeTracker();
  137               if (reset && tracker != null) {
  138                   if (fmd.getDeclaredTypeCode() == JavaTypes.MAP) {
  139                       // track values if key is derived from value, else keys
  140                       boolean keys = fmd.getKey().getValueMappedBy() == null;
  141                       ((MapChangeTracker) tracker).setTrackKeys(keys);
  142                   }
  143                   tracker.startTracking();
  144               }
  145               objval = proxy;
  146           }
  147           return ret;
  148       }
  149   
  150       /**
  151        * If the current field is a usable proxy, return it; else return null.
  152        */
  153       private Proxy checkProxy() {
  154           if (!(objval instanceof Proxy))
  155               return null;
  156   
  157           Proxy proxy = (Proxy) objval;
  158           if (proxy.getOwner() == null || Proxies.isOwner(proxy, _sm, field))
  159               return proxy;
  160           return null;
  161       }
  162   
  163       /**
  164        * Unproxies the current field if needed.
  165        */
  166       public void unproxy() {
  167           if (objval == null)
  168               return;
  169   
  170           FieldMetaData fmd = _sm.getMetaData().getField(field);
  171           switch (fmd.getDeclaredTypeCode()) {
  172               case JavaTypes.COLLECTION:
  173               case JavaTypes.MAP:
  174               case JavaTypes.DATE:
  175               case JavaTypes.OBJECT:
  176                   if (objval instanceof Proxy) {
  177                       Proxy proxy = (Proxy) objval;
  178                       proxy.setOwner(null, -1);
  179                       if (proxy.getChangeTracker() != null)
  180                           proxy.getChangeTracker().stopTracking();
  181                   }
  182           }
  183       }
  184   
  185       /**
  186        * Release the currently embedded field (make it transient).
  187        */
  188       public void releaseEmbedded() {
  189           if (objval == null)
  190               return;
  191   
  192           FieldMetaData fmd = _sm.getMetaData().getField(field);
  193           switch (fmd.getDeclaredTypeCode()) {
  194               case JavaTypes.PC:
  195                   if (fmd.isEmbeddedPC())
  196                       releaseEmbedded(fmd, objval);
  197                   break;
  198               case JavaTypes.ARRAY:
  199                   if (fmd.getElement().isEmbeddedPC())
  200                       releaseEmbedded(fmd.getElement(), (Object[]) objval);
  201                   break;
  202               case JavaTypes.COLLECTION:
  203                   if (fmd.getElement().isEmbeddedPC())
  204                       releaseEmbedded(fmd.getElement(), (Collection) objval);
  205                   break;
  206               case JavaTypes.MAP:
  207                   if (fmd.getKey().isEmbeddedPC())
  208                       releaseEmbedded(fmd.getKey(), ((Map) objval).keySet());
  209                   if (fmd.getElement().isEmbeddedPC())
  210                       releaseEmbedded(fmd.getElement(), ((Map) objval).values());
  211                   break;
  212           }
  213       }
  214   
  215       /**
  216        * Release the given embedded objects.
  217        */
  218       private void releaseEmbedded(ValueMetaData vmd, Object[] objs) {
  219           for (int i = 0; i < objs.length; i++)
  220               releaseEmbedded(vmd, objs[i]);
  221       }
  222   
  223       /**
  224        * Release the given embedded objects.
  225        */
  226       private void releaseEmbedded(ValueMetaData vmd, Collection objs) {
  227           for (Iterator itr = objs.iterator(); itr.hasNext();)
  228               releaseEmbedded(vmd, itr.next());
  229       }
  230   
  231       /**
  232        * Release the given embedd object.
  233        */
  234       private void releaseEmbedded(ValueMetaData vmd, Object obj) {
  235           if (obj == null)
  236               return;
  237   
  238           StateManagerImpl sm = _broker.getStateManagerImpl(obj, false);
  239           if (sm != null && sm.getOwner() == _sm
  240               && sm.getOwnerIndex() == vmd.getFieldMetaData().getIndex())
  241               sm.release(true);
  242       }
  243   
  244       /**
  245        * Persist the stored field safely, preventing infinite recursion using
  246        * the given set of already-persisted objects. This method is only called
  247        * for fields that we know have cascade-immediate settings.
  248        */
  249       public void persist(OpCallbacks call) {
  250           if (objval == null)
  251               return;
  252   
  253           FieldMetaData fmd = _sm.getMetaData().getField(field);
  254           switch (fmd.getDeclaredTypeCode()) {
  255               case JavaTypes.PC:
  256               case JavaTypes.PC_UNTYPED:
  257                   if (!_broker.isDetachedNew() && _broker.isDetached(objval))
  258                       return; // allow but ignore
  259                   _broker.persist(objval, true, call);
  260                   break;
  261               case JavaTypes.ARRAY:
  262                   _broker.persistAll(Arrays.asList((Object[]) objval), true, 
  263                       call);
  264                   break;
  265               case JavaTypes.COLLECTION:
  266                   _broker.persistAll((Collection) objval, true, call);
  267                   break;
  268               case JavaTypes.MAP:
  269                   if (fmd.getKey().getCascadePersist()
  270                       == ValueMetaData.CASCADE_IMMEDIATE)
  271                       _broker.persistAll(((Map) objval).keySet(), true, call);
  272                   if (fmd.getElement().getCascadePersist()
  273                       == ValueMetaData.CASCADE_IMMEDIATE)
  274                       _broker.persistAll(((Map) objval).values(), true, call);
  275                   break;
  276           }
  277       }
  278   
  279       /**
  280        * Delete and/or dereference field values.
  281        */
  282       public void delete(OpCallbacks call) {
  283           delete(true, call);
  284       }
  285   
  286       /**
  287        * Dereference field values.
  288        */
  289       public void dereferenceDependent() {
  290           delete(false, null);
  291       }
  292   
  293       /**
  294        * Delete or dereference the stored field as necessary.
  295        */
  296       private void delete(boolean immediate, OpCallbacks call) {
  297           if (objval == null)
  298               return;
  299   
  300           FieldMetaData fmd = _sm.getMetaData().getField(field);
  301           if (fmd.getCascadeDelete() != ValueMetaData.CASCADE_NONE) {
  302               // immediate cascade works on field value; dependent deref
  303               // works on external value
  304               if ((immediate || fmd.isEmbeddedPC())
  305                   && fmd.getCascadeDelete() == ValueMetaData.CASCADE_IMMEDIATE)
  306                   delete(fmd, objval, call);
  307               else if (fmd.getCascadeDelete() == ValueMetaData.CASCADE_AUTO)
  308                   dereferenceDependent(fmd.getExternalValue(objval, _broker));
  309               return;
  310           }
  311   
  312           Object external = null;
  313           ValueMetaData vmd = fmd.getKey();
  314           if ((immediate || vmd.isEmbeddedPC())
  315               && vmd.getCascadeDelete() == ValueMetaData.CASCADE_IMMEDIATE)
  316               delete(vmd, ((Map) objval).keySet(), call);
  317           else if (vmd.getCascadeDelete() == ValueMetaData.CASCADE_AUTO) {
  318               external = fmd.getExternalValue(objval, _broker);
  319               if (external == null)
  320                   return;
  321               dereferenceDependent(((Map) external).keySet());
  322           }
  323   
  324           vmd = fmd.getElement();
  325           if ((immediate || vmd.isEmbeddedPC())
  326               && vmd.getCascadeDelete() == ValueMetaData.CASCADE_IMMEDIATE) {
  327               switch (fmd.getDeclaredTypeCode()) {
  328                   case JavaTypes.COLLECTION:
  329                       delete(vmd, (Collection) objval, call);
  330                       break;
  331                   case JavaTypes.ARRAY:
  332                       delete(vmd, (Object[]) objval, call);
  333                       break;
  334                   case JavaTypes.MAP:
  335                       delete(vmd, ((Map) objval).values(), call);
  336                       break;
  337               }
  338           } else if (vmd.getCascadeDelete() == ValueMetaData.CASCADE_AUTO) {
  339               if (external == null) {
  340                   external = fmd.getExternalValue(objval, _broker);
  341                   if (external == null)
  342                       return;
  343               }
  344   
  345               switch (fmd.getTypeCode()) {
  346                   case JavaTypes.COLLECTION:
  347                       dereferenceDependent((Collection) external);
  348                       break;
  349                   case JavaTypes.ARRAY:
  350                       dereferenceDependent((Object[]) external);
  351                       break;
  352                   case JavaTypes.MAP:
  353                       dereferenceDependent(((Map) external).values());
  354                       break;
  355               }
  356           }
  357       }
  358   
  359       /**
  360        * Delete the objects in the given value.
  361        */
  362       private void delete(ValueMetaData vmd, Object[] objs, OpCallbacks call) {
  363           for (int i = 0; i < objs.length; i++)
  364               delete(vmd, objs[i], call);
  365       }
  366   
  367       /**
  368        * Delete the objects embedded in the given value.
  369        */
  370       private void delete(ValueMetaData vmd, Collection objs, OpCallbacks call) {
  371           for (Iterator itr = objs.iterator(); itr.hasNext();)
  372               delete(vmd, itr.next(), call);
  373       }
  374   
  375       /**
  376        * Delete an object embedded in the given value.
  377        */
  378       void delete(ValueMetaData vmd, Object obj, OpCallbacks call) {
  379           if (obj == null)
  380               return;
  381   
  382           // delete if unknowned or this isn't an embedded field or if owned by us
  383           StateManagerImpl sm = _broker.getStateManagerImpl(obj, false);
  384           if (sm != null && (sm.getOwner() == null || !vmd.isEmbeddedPC()
  385               || (sm.getOwner() == _sm
  386               && sm.getOwnerIndex() == vmd.getFieldMetaData().getIndex())))
  387               _broker.delete(sm.getManagedInstance(), sm, call);
  388       }
  389   
  390       /**
  391        * Dereference all valid persistent objects in the given collection.
  392        */
  393       private void dereferenceDependent(Object[] objs) {
  394           for (int i = 0; i < objs.length; i++)
  395               dereferenceDependent(objs[i]);
  396       }
  397   
  398       /**
  399        * Dereference all valid persistent objects in the given collection.
  400        */
  401       private void dereferenceDependent(Collection objs) {
  402           for (Iterator itr = objs.iterator(); itr.hasNext();)
  403               dereferenceDependent(itr.next());
  404       }
  405   
  406       /**
  407        * Dereference the given object.
  408        */
  409       void dereferenceDependent(Object obj) {
  410           if (obj == null)
  411               return;
  412           StateManagerImpl sm = _broker.getStateManagerImpl(obj, false);
  413           if (sm != null)
  414               sm.setDereferencedDependent(true, true);
  415       }
  416   
  417       /**
  418        * Recursively invoke the broker to gather cascade-refresh objects in
  419        * the current field into the given set. This method is only called
  420        * for fields that we know have cascade-refresh settings.
  421        */
  422       public void gatherCascadeRefresh(OpCallbacks call) {
  423           if (objval == null)
  424               return;
  425   
  426           FieldMetaData fmd = _sm.getMetaData().getField(field);
  427           switch (fmd.getDeclaredTypeCode()) {
  428               case JavaTypes.PC:
  429               case JavaTypes.PC_UNTYPED:
  430                   _broker.gatherCascadeRefresh(objval, call);
  431                   break;
  432               case JavaTypes.ARRAY:
  433                   gatherCascadeRefresh((Object[]) objval, call);
  434                   break;
  435               case JavaTypes.COLLECTION:
  436                   gatherCascadeRefresh((Collection) objval, call);
  437                   break;
  438               case JavaTypes.MAP:
  439                   if (fmd.getKey().getCascadeRefresh()
  440                       == ValueMetaData.CASCADE_IMMEDIATE)
  441                       gatherCascadeRefresh(((Map) objval).keySet(), call);
  442                   if (fmd.getElement().getCascadeRefresh()
  443                       == ValueMetaData.CASCADE_IMMEDIATE)
  444                       gatherCascadeRefresh(((Map) objval).values(), call);
  445                   break;
  446           }
  447       }
  448   
  449       /**
  450        * Gather each element.
  451        */
  452       private void gatherCascadeRefresh(Object[] arr, OpCallbacks call) {
  453           for (int i = 0; i < arr.length; i++)
  454               _broker.gatherCascadeRefresh(arr[i], call);
  455       }
  456   
  457       /**
  458        * Gather each element.
  459        */
  460       private void gatherCascadeRefresh(Collection coll, OpCallbacks call) {
  461           for (Iterator itr = coll.iterator(); itr.hasNext();)
  462               _broker.gatherCascadeRefresh(itr.next(), call);
  463       }
  464   
  465       /**
  466        * Perform pre-flush tasks on the current field. This includes checking
  467        * for nulls, persisting pcs, embedding embedded fields, and ref'ing
  468        * pc fields. Return true if the field needs to be replaced with the
  469        * new value.
  470        */
  471       public boolean preFlush(boolean logical, OpCallbacks call) {
  472           // only care about object fields
  473           FieldMetaData fmd = _sm.getMetaData().getField(field);
  474           if (fmd.getDeclaredTypeCode() < JavaTypes.OBJECT)
  475               return false;
  476   
  477           // perform pers-by-reach and dependent refs
  478           boolean ret = preFlush(fmd, logical, call);
  479   
  480           // manage inverses
  481           InverseManager manager = _broker.getInverseManager();
  482           if (manager != null)
  483               manager.correctRelations(_sm, fmd, objval);
  484           return ret;
  485       }
  486   
  487       /**
  488        * Return true if the last-provided field has a default value.
  489        */
  490       public boolean isDefaultValue() {
  491           return dblval == 0 && longval == 0
  492               && (objval == null || "".equals(objval));
  493       }
  494   
  495       /**
  496        * Write the stored field or its default value to the given stream.
  497        */
  498       public void serialize(ObjectOutput out, boolean def)
  499           throws IOException {
  500           FieldMetaData fmd = _sm.getMetaData().getField(field);
  501           switch (fmd.getDeclaredTypeCode()) {
  502               case JavaTypes.BOOLEAN:
  503                   out.writeBoolean(!def && longval == 1);
  504                   break;
  505               case JavaTypes.BYTE:
  506                   out.writeByte((def) ? (byte) 0 : (byte) longval);
  507                   break;
  508               case JavaTypes.CHAR:
  509                   out.writeChar((def) ? (char) 0 : (char) longval);
  510                   break;
  511               case JavaTypes.DOUBLE:
  512                   out.writeDouble((def) ? 0D : dblval);
  513                   break;
  514               case JavaTypes.FLOAT:
  515                   out.writeFloat((def) ? 0F : (float) dblval);
  516                   break;
  517               case JavaTypes.INT:
  518                   out.writeInt((def) ? 0 : (int) longval);
  519                   break;
  520               case JavaTypes.LONG:
  521                   out.writeLong((def) ? 0L : longval);
  522                   break;
  523               case JavaTypes.SHORT:
  524                   out.writeShort((def) ? (short) 0 : (short) longval);
  525                   break;
  526               default:
  527                   out.writeObject((def) ? null : objval);
  528           }
  529       }
  530   
  531       /**
  532        * Helper method to perform pre flush actions on the current object.
  533        */
  534       private boolean preFlush(FieldMetaData fmd, boolean logical, 
  535           OpCallbacks call) {
  536           // check for illegal nulls
  537           if (objval == null) {
  538               if (fmd.getNullValue() == FieldMetaData.NULL_EXCEPTION
  539                   || fmd.getDeclaredTypeCode() == JavaTypes.OID)
  540                   throw new InvalidStateException(_loc.get("null-value",
  541                       fmd.getName(), _sm.getManagedInstance())).
  542                       setFatal(true);
  543               return false;
  544           }
  545   
  546           // nothing else to do for non-persistent
  547           if (fmd.getManagement() != FieldMetaData.MANAGE_PERSISTENT)
  548               return false;
  549   
  550           // don't allow managed objectid field value
  551           if (fmd.getDeclaredTypeCode() == JavaTypes.OID) {
  552               _sm.assertNotManagedObjectId(objval);
  553               if (_sm.getObjectId() != null
  554                   && !objval.equals(((ObjectId) _sm.getObjectId()).getId()))
  555                   throw new InvalidStateException(_loc.get("changed-oid",
  556                       _sm.getObjectId(), objval,
  557                       Exceptions.toString(_sm.getManagedInstance()))).
  558                       setFatal(true);
  559           }
  560   
  561           // check for pcs in field value
  562           if (preFlush(fmd, fmd.getDeclaredTypeCode(),
  563               fmd.getKey().getDeclaredTypeCode(),
  564               fmd.getElement().getDeclaredTypeCode(), false, logical, call))
  565               return true;
  566   
  567           // also check for pcs in externalized values
  568           if (fmd.isExternalized())
  569               preFlush(fmd, fmd.getTypeCode(), fmd.getKey().getTypeCode(),
  570                   fmd.getElement().getTypeCode(), true, logical, call);
  571           return false;
  572       }
  573   
  574       /**
  575        * Make new objects persistent and ref other objects so referenced
  576        * dependent objects won't be deleted.
  577        */
  578       private boolean preFlush(FieldMetaData fmd, int type, int keyType,
  579           int elemType, boolean external, boolean logical, OpCallbacks call) {
  580           Object val = objval;
  581           if (val == null)
  582               return false;
  583   
  584           boolean copy = false;
  585           switch (type) {
  586               case JavaTypes.PC:
  587                   if (fmd.isEmbeddedPC()) {
  588                       objval = embed(fmd, val);
  589                       copy = true;
  590                   } else {
  591                       if (external)
  592                           val = fmd.getExternalValue(val, _broker);
  593                       if (val != null)
  594                           preFlushPC(fmd, val, logical, call);
  595                   }
  596                   break;
  597               case JavaTypes.PC_UNTYPED:
  598                   if (external)
  599                       val = fmd.getExternalValue(val, _broker);
  600                   if (val != null)
  601                       preFlushPC(fmd, val, logical, call);
  602                   break;
  603               case JavaTypes.ARRAY:
  604                   if (fmd.getElement().isEmbeddedPC())
  605                       embed(fmd.getElement(), (Object[]) val);
  606                   else if (elemType == JavaTypes.PC
  607                       || elemType == JavaTypes.PC_UNTYPED) {
  608                       if (external)
  609                           val = fmd.getExternalValue(val, _broker);
  610                       if (val != null)
  611                           preFlushPCs(fmd.getElement(), (Object[]) val, logical, 
  612                               call);
  613                   }
  614                   break;
  615               case JavaTypes.COLLECTION:
  616                   if (fmd.getElement().isEmbeddedPC()) {
  617                       objval = embed(fmd.getElement(), (Collection) val);
  618                       copy = true;
  619                   } else if (elemType == JavaTypes.PC
  620                       || elemType == JavaTypes.PC_UNTYPED) {
  621                       boolean flushed = false;
  622                       if (external)
  623                           val = fmd.getExternalValue(val, _broker);
  624                       else if (val instanceof Proxy) {
  625                           // shortcut change trackers; also ensures we don't 
  626                           // iterate lrs fields
  627                           ChangeTracker ct = ((Proxy) val).getChangeTracker();
  628                           if (ct != null && ct.isTracking()) {
  629                               preFlushPCs(fmd.getElement(), ct.getAdded(), 
  630                                   logical, call);
  631                               preFlushPCs(fmd.getElement(), ct.getChanged(),
  632                                   logical, call);
  633                               flushed = true;
  634                           }
  635                       }
  636                       if (!flushed && val != null)
  637                           preFlushPCs(fmd.getElement(), (Collection) val, logical,
  638                               call);
  639                   }
  640                   break;
  641               case JavaTypes.MAP:
  642                   boolean keyEmbed = fmd.getKey().isEmbeddedPC();
  643                   boolean valEmbed = fmd.getElement().isEmbeddedPC();
  644                   if (keyEmbed || valEmbed) {
  645                       objval = embed(fmd, (Map) val, keyEmbed, valEmbed);
  646                       copy = keyEmbed;
  647                   }
  648   
  649                   if (!keyEmbed && (keyType == JavaTypes.PC
  650                       || keyType == JavaTypes.PC_UNTYPED)) {
  651                       boolean flushed = false;
  652                       if (external) {
  653                           val = fmd.getExternalValue(val, _broker);
  654                           external = false;
  655                       } else if (val instanceof Proxy) {
  656                           // shortcut change trackers; also ensures we don't 
  657                           // iterate lrs fields
  658                           MapChangeTracker ct = (MapChangeTracker) ((Proxy) val).
  659                               getChangeTracker();
  660                           if (ct != null && ct.isTracking() && ct.getTrackKeys())
  661                           {
  662                               preFlushPCs(fmd.getKey(), ct.getAdded(), logical,
  663                                   call);
  664                               preFlushPCs(fmd.getKey(), ct.getChanged(), logical,
  665                                   call);
  666                               flushed = true;
  667                           }
  668                       }
  669                       if (!flushed && val != null)
  670                           preFlushPCs(fmd.getKey(), ((Map) val).keySet(), logical,
  671                               call);
  672                   }
  673   
  674                   if (!valEmbed && (elemType == JavaTypes.PC
  675                       || elemType == JavaTypes.PC_UNTYPED)) {
  676                       boolean flushed = false;
  677                       if (external)
  678                           val = fmd.getExternalValue(val, _broker);
  679                       else if (val instanceof Proxy) {
  680                           // shortcut change trackers; also ensures we don't 
  681                           // iterate lrs fields
  682                           MapChangeTracker ct = (MapChangeTracker) ((Proxy) val).
  683                               getChangeTracker();
  684                           if (ct != null && ct.isTracking()) {
  685                               if (ct.getTrackKeys()) {
  686                                   preFlushPCs(fmd.getElement(), ct.getAdded(),
  687                                       (Map) val, logical, call);
  688                                   preFlushPCs(fmd.getElement(), ct.getChanged(),
  689                                       (Map) val, logical, call);
  690                               } else {
  691                                   preFlushPCs(fmd.getElement(), ct.getAdded(),
  692                                       logical, call);
  693                                   preFlushPCs(fmd.getElement(), ct.getChanged(),
  694                                       logical, call);
  695                               }
  696                               flushed = true;
  697                           }
  698                       }
  699                       if (!flushed && val != null)
  700                           preFlushPCs(fmd.getElement(), ((Map) val).values(),
  701                               logical, call);
  702                   }
  703                   break;
  704           }
  705           return copy;
  706       }
  707   
  708       /**
  709        * Make new objects persistent and ref all valid persistent objects for
  710        * the given keys.
  711        */
  712       private void preFlushPCs(ValueMetaData vmd, Collection keys, Map map,
  713           boolean logical, OpCallbacks call) {
  714           for (Iterator itr = keys.iterator(); itr.hasNext();)
  715               preFlushPC(vmd, map.get(itr.next()), logical, call);
  716       }
  717   
  718       /**
  719        * Make new objects persistent and ref all valid persistent objects in
  720        * the given array.
  721        */
  722       private void preFlushPCs(ValueMetaData vmd, Object[] objs,
  723           boolean logical, OpCallbacks call) {
  724           for (int i = 0; i < objs.length; i++)
  725               preFlushPC(vmd, objs[i], logical, call);
  726       }
  727   
  728       /**
  729        * Make new objects persistent and ref all valid persistent objects in
  730        * the given collection.
  731        */
  732       private void preFlushPCs(ValueMetaData vmd, Collection objs,
  733           boolean logical, OpCallbacks call) {
  734           for (Iterator itr = objs.iterator(); itr.hasNext();)
  735               preFlushPC(vmd, itr.next(), logical, call);
  736       }
  737   
  738       /**
  739        * Perform pre flush operations on the given object.
  740        */
  741       private void preFlushPC(ValueMetaData vmd, Object obj, boolean logical,
  742           OpCallbacks call) {
  743           if (obj == null)
  744               return;
  745   
  746           OpenJPAStateManager sm;
  747           if (vmd.getCascadePersist() == ValueMetaData.CASCADE_NONE) {
  748               if (!_broker.isDetachedNew() && _broker.isDetached(obj))
  749                   return; // allow but ignore
  750   
  751               sm = _broker.getStateManager(obj);
  752               if (sm == null || !sm.isPersistent())
  753                   throw new InvalidStateException(
  754                       _loc.get("cant-cascade-persist", vmd))
  755                       .setFailedObject(obj);
  756           } else {
  757               sm = _broker.getStateManager(obj);
  758               if (sm == null || !sm.isProvisional())
  759                   sm = _broker.persist(obj, null, true, call);
  760           }
  761   
  762           if (sm != null) {
  763               // if deleted and not managed inverse, die
  764               if (sm.isDeleted() && (_broker.getInverseManager() == null
  765                   || vmd.getFieldMetaData().getInverseMetaDatas().length == 0))
  766                   throw new UserException(_loc.get("ref-to-deleted",
  767                       Exceptions.toString(obj), vmd,
  768                       Exceptions.toString(_sm.getManagedInstance()))).
  769                       setFailedObject(obj);
  770   
  771               StateManagerImpl smimpl = (StateManagerImpl) sm;
  772               smimpl.nonprovisional(logical, call);
  773               smimpl.setDereferencedDependent(false, true);
  774           }
  775       }
  776   
  777       /**
  778        * Make all elements of the given array embedded.
  779        */
  780       private void embed(ValueMetaData vmd, Object[] arr) {
  781           for (int i = 0; i < arr.length; i++)
  782               arr[i] = embed(vmd, arr[i]);
  783       }
  784   
  785       /**
  786        * Create a copy of the given collection containing embedded elements.
  787        */
  788       private Collection embed(ValueMetaData vmd, Collection orig) {
  789           // we have to copy to get a collection of the right type and size,
  790           // though we immediately clear it
  791           Collection coll = getProxyManager().copyCollection(orig);
  792           if (coll == null)
  793               throw new UserException(_loc.get("not-copyable",
  794                   vmd.getFieldMetaData()));
  795   
  796           coll.clear();
  797           for (Iterator itr = orig.iterator(); itr.hasNext();)
  798               coll.add(embed(vmd, itr.next()));
  799           return coll;
  800       }
  801   
  802       /**
  803        * Embed the elements of the given map.
  804        */
  805       private Map embed(FieldMetaData fmd, Map orig, boolean keyEmbed,
  806           boolean valEmbed) {
  807           Map map;
  808           Map.Entry entry;
  809   
  810           // if we have to replace keys, we need to copy the map; otherwise
  811           // we can mutate the values directly
  812           if (keyEmbed) {
  813               // we have to copy to get a collection of the right type and size,
  814               // though we immediately clear it
  815               map = getProxyManager().copyMap(orig);
  816               if (map == null)
  817                   throw new UserException(_loc.get("not-copyable", fmd));
  818   
  819               map.clear();
  820               Object key, val;
  821               for (Iterator itr = orig.entrySet().iterator(); itr.hasNext();) {
  822                   entry = (Map.Entry) itr.next();
  823                   key = embed(fmd.getKey(), entry.getKey());
  824                   val = entry.getValue();
  825                   if (valEmbed)
  826                       val = embed(fmd.getElement(), val);
  827                   map.put(key, val);
  828               }
  829           } else {
  830               map = orig;
  831               for (Iterator itr = map.entrySet().iterator(); itr.hasNext();) {
  832                   entry = (Map.Entry) itr.next();
  833                   entry.setValue(embed(fmd.getElement(),
  834                       entry.getValue()));
  835               }
  836           }
  837           return map;
  838       }
  839   
  840       /**
  841        * Make the given object embedded.
  842        */
  843       private Object embed(ValueMetaData vmd, Object obj) {
  844           if (obj == null)
  845               return null;
  846           return _broker.embed(obj, null, _sm, vmd).getManagedInstance();
  847       }
  848   
  849       /**
  850        * Return the proxy manager.
  851        */
  852       private ProxyManager getProxyManager ()
  853   	{
  854   		return _broker.getConfiguration ().getProxyManagerInstance ();
  855   	}
  856   }

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