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.ObjectInputStream;
   23   import java.io.ObjectOutputStream;
   24   import java.io.Serializable;
   25   import java.util.BitSet;
   26   import java.util.Collection;
   27   import java.util.Date;
   28   import java.util.Map;
   29   
   30   import org.apache.openjpa.enhance.PersistenceCapable;
   31   import org.apache.openjpa.meta.FieldMetaData;
   32   import org.apache.openjpa.meta.JavaTypes;
   33   import org.apache.openjpa.util.ProxyManager;
   34   
   35   /**
   36    * FieldManager type used to store information for rollback.
   37    *
   38    * @author Abe White
   39    */
   40   public class SaveFieldManager
   41       extends ClearFieldManager
   42       implements Serializable {
   43   
   44       private final StateManagerImpl _sm;
   45       private final BitSet _unloaded;
   46       private BitSet _saved = null;
   47       private int[] _copyField = null;
   48       private transient PersistenceCapable _state = null;
   49   
   50       // used to track field value during store/fetch cycle
   51       private Object _field = null;
   52   
   53       /**
   54        * Constructor. Provide {@link StateManagerImpl} of instance to save.
   55        */
   56       SaveFieldManager(StateManagerImpl sm, PersistenceCapable pc, BitSet dirty) {
   57           _sm = sm;
   58           _state = pc;
   59   
   60           // if instance is new or transient all fields will be marked dirty even
   61           // though they have their original values, so we can restore them;
   62           // otherwise, we need to record already-dirty persistent fields as
   63           // ones we won't be able to restore
   64           FieldMetaData[] fields = _sm.getMetaData().getFields();
   65           if (_sm.isNew() || !_sm.isPersistent() || dirty == null)
   66               _unloaded = new BitSet(fields.length);
   67           else {
   68               _unloaded = (BitSet) dirty.clone();
   69               for (int i = 0; i < fields.length; i++)
   70                   if (fields[i].getManagement() != fields[i].MANAGE_PERSISTENT)
   71                       _unloaded.clear(i);
   72           }
   73       }
   74   
   75       /**
   76        * Return the persistence capable copy holding the rollback field values.
   77        */
   78       public PersistenceCapable getState() {
   79           return _state;
   80       }
   81   
   82       /**
   83        * Return the currently-loaded fields that will be unloaded after rollback.
   84        */
   85       public BitSet getUnloaded() {
   86           return _unloaded;
   87       }
   88   
   89       /**
   90        * Save the given field. If this method returns true, then you need
   91        * to use this field manager to replace the given field in the instance
   92        * returned by {@link #getState}.
   93        */
   94       public boolean saveField(int field) {
   95           // if not loaded we can't save orig value; mark as unloaded on rollback
   96           if (_sm.getLoaded() != null && !_sm.getLoaded().get(field)) {
   97               _unloaded.set(field);
   98               return false;
   99           }
  100   
  101           // already saved?
  102           if (_saved != null && _saved.get(field))
  103               return false;
  104   
  105           FieldMetaData fmd = _sm.getMetaData().getField(field);
  106           boolean mutable = false;
  107           switch (fmd.getDeclaredTypeCode()) {
  108               case JavaTypes.DATE:
  109               case JavaTypes.ARRAY:
  110               case JavaTypes.COLLECTION:
  111               case JavaTypes.MAP:
  112               case JavaTypes.OBJECT:
  113                   mutable = true;
  114           }
  115   
  116           // if this is not an inverse field and the proper restore flag is
  117           // not set, skip it
  118   
  119           if (_sm.getBroker().getInverseManager() == null
  120               || fmd.getInverseMetaDatas().length == 0) {
  121               // use sm's restore directive, not broker's
  122               int restore = _sm.getBroker().getRestoreState();
  123               if (restore == RestoreState.RESTORE_NONE
  124                   || (mutable && restore == RestoreState.RESTORE_IMMUTABLE)) {
  125                   _unloaded.set(field);
  126                   return false;
  127               }
  128           }
  129   
  130           // prepare to save the field
  131           if (_state == null)
  132               _state = _sm.getPersistenceCapable().pcNewInstance(_sm, true);
  133           if (_saved == null)
  134               _saved = new BitSet(_sm.getMetaData().getFields().length);
  135   
  136           _saved.set(field);
  137   
  138           // if mutable, return true to indicate that the field needs to be
  139           // copied by providing and replacing it using this field manager
  140           if (mutable)
  141               return true;
  142   
  143           // immutable fields can just be copied over
  144           if (_copyField == null)
  145               _copyField = new int[1];
  146           _copyField[0] = field;
  147           getState().pcCopyFields(_sm.getPersistenceCapable(), _copyField);
  148           return false;
  149       }
  150   
  151       /**
  152        * Restore the given field. If this method returns true, then you need
  153        * to use this field manager to replace the given field in the state
  154        * manager's instance.
  155        */
  156       public boolean restoreField(int field) {
  157           // if the given field needs to be unloaded, return true so that it gets
  158           // replaced with a default value
  159           if (_unloaded.get(field))
  160               return true;
  161   
  162           // if the field was not saved, it must not have gotten dirty; just
  163           // return false so that the current value is kept
  164           if (_saved == null || !_saved.get(field))
  165               return false;
  166   
  167           // copy the saved field over
  168           if (_copyField == null)
  169               _copyField = new int[1];
  170           _copyField[0] = field;
  171           _sm.getPersistenceCapable().pcCopyFields(getState(), _copyField);
  172           return false;
  173       }
  174   
  175       /**
  176        * Compare the given field.
  177        * @return <code>true</code> if the field is the same in the current
  178        * state and in the saved state; otherwise, <code>false</code>.
  179        */
  180       public boolean isFieldEqual(int field, Object current) {
  181           // if the field is not available, assume that it has changed.
  182           if (_saved == null || !_saved.get(field))
  183               return false;
  184           if (!(getState().pcGetStateManager() instanceof StateManagerImpl))
  185               return false;
  186   
  187           StateManagerImpl sm = (StateManagerImpl) getState().pcGetStateManager();
  188           SingleFieldManager single = new SingleFieldManager(sm, sm.getBroker());
  189           sm.provideField(getState(), single, field);
  190           Object old = single.fetchObjectField(field);
  191           return current == old || current != null && current.equals(old);
  192       }
  193   
  194       public Object fetchObjectField(int field) {
  195           // return the copied field during save, or a null value during restore
  196           Object val = _field;
  197           _field = null;
  198           return val;
  199       }
  200   
  201       public void storeObjectField(int field, Object curVal) {
  202           // copy mutable fields
  203           ProxyManager proxy = _sm.getBroker().getConfiguration().
  204               getProxyManagerInstance();
  205           FieldMetaData fmd = _sm.getMetaData().getField(field);
  206           switch (fmd.getDeclaredTypeCode()) {
  207               case JavaTypes.ARRAY:
  208                   _field = proxy.copyArray(curVal);
  209                   break;
  210               case JavaTypes.COLLECTION:
  211                   _field = proxy.copyCollection((Collection) curVal);
  212                   break;
  213               case JavaTypes.MAP:
  214                   _field = proxy.copyMap((Map) curVal);
  215                   break;
  216               case JavaTypes.DATE:
  217                   _field = proxy.copyDate((Date) curVal);
  218                   break;
  219               case JavaTypes.OBJECT:
  220                   _field = proxy.copyCustom(curVal);
  221                   if (_field == null)
  222                       _field = curVal;
  223                   break;
  224               default:
  225                   _field = curVal;
  226           }
  227   
  228           // if we couldn't get a copy of the sco, act like it wasn't saved
  229           if (curVal != null && _field == null) {
  230               _unloaded.set(field);
  231               _saved.clear(field);
  232   		}
  233   	}
  234   
  235       private void writeObject(ObjectOutputStream oos) throws IOException {
  236           oos.defaultWriteObject();
  237           _sm.writePC(oos, _state);
  238       }
  239   
  240       private void readObject(ObjectInputStream ois)
  241           throws IOException, ClassNotFoundException {
  242           ois.defaultReadObject();
  243           _state = _sm.readPC(ois);
  244       }
  245   }

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