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.Serializable;
   22   import java.util.ArrayList;
   23   import java.util.Collection;
   24   import java.util.Collections;
   25   import java.util.HashMap;
   26   import java.util.HashSet;
   27   import java.util.Iterator;
   28   import java.util.List;
   29   import java.util.Map;
   30   
   31   import org.apache.openjpa.lib.util.Localizer;
   32   import org.apache.openjpa.lib.util.ReferenceHashSet;
   33   import org.apache.openjpa.util.Exceptions;
   34   import org.apache.openjpa.util.InternalException;
   35   import org.apache.openjpa.util.UserException;
   36   
   37   /**
   38    * Cache of managed objects. Must be static for serialization reasons.
   39    */
   40   class ManagedCache implements Serializable {
   41   
   42       private static final Localizer _loc =
   43           Localizer.forPackage(ManagedCache.class);
   44   
   45       private Map _main; // oid -> sm
   46       private Map _conflicts = null; // conflict oid -> new sm
   47       private Map _news = null; // tmp id -> new sm
   48       private Collection _embeds = null; // embedded/non-persistent sms
   49       private Collection _untracked = null; // hard refs to untracked sms
   50       private BrokerImpl broker;
   51   
   52       /**
   53        * Constructor; supply primary cache map.
   54        */
   55       ManagedCache(BrokerImpl broker) {
   56           this.broker = broker;
   57           _main = broker.newManagedObjectCache();
   58       }
   59   
   60       /**
   61        * Return the instance for the given oid, optionally allowing
   62        * new instances.
   63        */
   64       public StateManagerImpl getById(Object oid, boolean allowNew) {
   65           if (oid == null)
   66               return null;
   67   
   68           // check main cache for oid
   69           StateManagerImpl sm = (StateManagerImpl) _main.get(oid);
   70           StateManagerImpl sm2;
   71           if (sm != null) {
   72               // if it's a new instance, we know it's the only match, because
   73               // other pers instances override new instances in _cache
   74               if (sm.isNew() && !sm.isDeleted())
   75                   return (allowNew) ? sm : null;
   76               if (!allowNew || !sm.isDeleted())
   77                   return sm;
   78   
   79               // sm is deleted; check conflict cache
   80               if (_conflicts != null) {
   81                   sm2 = (StateManagerImpl) _conflicts.get(oid);
   82                   if (sm2 != null)
   83                       return sm2;
   84               }
   85           }
   86   
   87           // at this point sm is null or deleted; check the new cache for
   88           // any matches. this allows us to match app id objects to new
   89           // instances without permanant oids
   90           if (allowNew && _news != null && !_news.isEmpty()) {
   91               sm2 = (StateManagerImpl) _news.get(oid);
   92               if (sm2 != null)
   93                   return sm2;
   94           }
   95           return sm;
   96       }
   97   
   98       /**
   99        * Call this method when a new state manager initializes itself.
  100        */
  101       public void add(StateManagerImpl sm) {
  102           if (!sm.isIntercepting()) {
  103               if (_untracked == null)
  104                   _untracked = new HashSet();
  105               _untracked.add(sm);
  106           }
  107   
  108           if (!sm.isPersistent() || sm.isEmbedded()) {
  109               if (_embeds == null)
  110                   _embeds = new ReferenceHashSet(ReferenceHashSet.WEAK);
  111               _embeds.add(sm);
  112               return;
  113           }
  114   
  115           // initializing new instance; put in new cache because won't have
  116           // permanent oid yet
  117           if (sm.isNew()) {
  118               if (_news == null)
  119                   _news = new HashMap();
  120               _news.put(sm.getId(), sm);
  121               return;
  122           }
  123   
  124           // initializing persistent instance; put in main cache
  125           StateManagerImpl orig = (StateManagerImpl) _main.put
  126               (sm.getObjectId(), sm);
  127           if (orig != null) {
  128               _main.put(sm.getObjectId(), orig);
  129               throw new UserException(_loc.get("dup-load", sm.getObjectId(),
  130                   Exceptions.toString(orig.getManagedInstance())))
  131                   .setFailedObject(sm.getManagedInstance());
  132           }
  133       }
  134   
  135       /**
  136        * Remove the given state manager from the cache when it transitions
  137        * to transient.
  138        */
  139       public void remove(Object id, StateManagerImpl sm) {
  140           // if it has a permanent oid, remove from main / conflict cache,
  141           // else remove from embedded/nontrans cache, and if not there
  142           // remove from new cache
  143           Object orig;
  144           if (sm.getObjectId() != null) {
  145               orig = _main.remove(id);
  146               if (orig != sm) {
  147                   if (orig != null)
  148                       _main.put(id, orig); // put back
  149                   if (_conflicts != null) {
  150                       orig = _conflicts.remove(id);
  151                       if (orig != null && orig != sm)
  152                           _conflicts.put(id, orig); // put back
  153                   }
  154               }
  155           } else if ((_embeds == null || !_embeds.remove(sm))
  156               && _news != null) {
  157               orig = _news.remove(id);
  158               if (orig != null && orig != sm)
  159                   _news.put(id, orig); // put back
  160           }
  161   
  162           if (_untracked != null)
  163               _untracked.remove(sm);
  164       }
  165   
  166       /**
  167        * An embedded or nonpersistent managed instance has been persisted.
  168        */
  169       public void persist(StateManagerImpl sm) {
  170           if (_embeds != null)
  171               _embeds.remove(sm);
  172       }
  173   
  174       /**
  175        * A new instance has just been assigned a permanent oid.
  176        */
  177       public void assignObjectId(Object id, StateManagerImpl sm) {
  178           // if assigning oid, remove from new cache and put in primary; may
  179           // not be in new cache if another new instance had same id
  180           StateManagerImpl orig = null;
  181           if (_news != null) {
  182               orig = (StateManagerImpl) _news.remove(id);
  183               if (orig != null && orig != sm)
  184                   _news.put(id, orig); // put back
  185           }
  186   
  187           // put in main cache, but make sure we don't replace another
  188           // instance with the same oid
  189           orig = (StateManagerImpl) _main.put(sm.getObjectId(), sm);
  190           if (orig != null) {
  191               _main.put(sm.getObjectId(), orig);
  192               if (!orig.isDeleted())
  193                   throw new UserException(_loc.get("dup-oid-assign",
  194                       sm.getObjectId(),
  195                       Exceptions.toString(sm.getManagedInstance())))
  196                       .setFailedObject(sm.getManagedInstance());
  197   
  198               // same oid as deleted instance; put in conflict cache
  199               if (_conflicts == null)
  200                   _conflicts = new HashMap();
  201               _conflicts.put(sm.getObjectId(), sm);
  202           }
  203       }
  204   
  205       /**
  206        * A new instance has committed; recache under permanent oid.
  207        */
  208       public void commitNew(Object id, StateManagerImpl sm) {
  209           // if the id didn't change, the instance was already assigned an
  210           // id, but it could have been in conflict cache
  211           StateManagerImpl orig;
  212           if (sm.getObjectId() == id) {
  213               orig = (_conflicts == null) ? null
  214                   : (StateManagerImpl) _conflicts.remove(id);
  215               if (orig == sm) {
  216                   orig = (StateManagerImpl) _main.put(id, sm);
  217                   if (orig != null && !orig.isDeleted()) {
  218                       _main.put(sm.getObjectId(), orig);
  219                       throw new UserException(_loc.get("dup-oid-assign",
  220                           sm.getObjectId(), Exceptions.toString(
  221                               sm.getManagedInstance())))
  222                           .setFailedObject(sm.getManagedInstance())
  223                           .setFatal(true);
  224                   }
  225               }
  226               return;
  227           }
  228   
  229           // oid changed, so it must previously have been a new instance
  230           // without an assigned oid.  remove it from the new cache; ok if
  231           // we end up removing another instance with same id
  232           if (_news != null)
  233               _news.remove(id);
  234   
  235           // and put into main cache now that id is asssigned
  236           orig = (StateManagerImpl) _main.put(sm.getObjectId(), sm);
  237           if (orig != null && orig != sm && !orig.isDeleted()) {
  238               // put back orig and throw error
  239               _main.put(sm.getObjectId(), orig);
  240               throw new UserException(_loc.get("dup-oid-assign",
  241                   sm.getObjectId(), Exceptions.toString(sm.getManagedInstance())))
  242                       .setFailedObject(sm.getManagedInstance()).setFatal(true);
  243           }
  244       }
  245   
  246       /**
  247        * Return a copy of all cached persistent objects.
  248        */
  249       public Collection copy() {
  250           // proxies not included here because the state manager is always
  251           // present in other caches too
  252   
  253           int size = _main.size();
  254           if (_conflicts != null)
  255               size += _conflicts.size();
  256           if (_news != null)
  257               size += _news.size();
  258           if (_embeds != null)
  259               size += _embeds.size();
  260           if (size == 0)
  261               return Collections.EMPTY_LIST;
  262   
  263           List copy = new ArrayList(size);
  264           for (Iterator itr = _main.values().iterator(); itr.hasNext();)
  265               copy.add(itr.next());
  266           if (_conflicts != null && !_conflicts.isEmpty())
  267               for (Iterator itr = _conflicts.values().iterator();
  268                   itr.hasNext();)
  269                   copy.add(itr.next());
  270           if (_news != null && !_news.isEmpty())
  271               for (Iterator itr = _news.values().iterator(); itr.hasNext();)
  272                   copy.add(itr.next());
  273           if (_embeds != null && !_embeds.isEmpty())
  274               for (Iterator itr = _embeds.iterator(); itr.hasNext();)
  275                   copy.add(itr.next());
  276           return copy;
  277       }
  278   
  279       /**
  280        * Clear the cache.
  281        */
  282       public void clear() {
  283           _main = broker.newManagedObjectCache();
  284           if (_conflicts != null)
  285               _conflicts = null;
  286           if (_news != null)
  287               _news = null;
  288           if (_embeds != null)
  289               _embeds = null;
  290           if (_untracked != null)
  291               _untracked = null;
  292       }
  293   
  294       /**
  295        * Clear new instances without permanent oids.
  296        */
  297       public void clearNew() {
  298           if (_news != null)
  299               _news = null;
  300       }
  301   
  302       void dirtyCheck() {
  303           if (_untracked == null)
  304               return;
  305   
  306           for (Iterator iter = _untracked.iterator(); iter.hasNext(); )
  307               ((StateManagerImpl) iter.next()).dirtyCheck();
  308       }
  309   }

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