001    package com.sptci.prevayler;
002    
003    import java.util.Collection;
004    import java.util.LinkedHashMap;
005    import java.util.LinkedHashSet;
006    import java.util.Map;
007    import java.util.logging.Logger;
008    
009    /**
010     * The base class for the prevalent system that provides the storage engine
011     * for storing the various prevalent object maintained by the system.
012     *
013     * <p>&copy; Copyright 2008 <a href='http://sptci.com/' target='_top'>Sans Pareil Technologies, Inc.</a></p>
014     * @author Rakesh 2008-05-22
015     * @version $Id: StorageSystem.java 22 2008-11-24 19:04:25Z sptrakesh $
016     */
017    abstract class StorageSystem implements DatabaseSystem
018    {
019      private static final long serialVersionUID = 1L;
020    
021      /** The logger to use to log messages/errors. */
022      protected static transient final Logger logger =
023          Logger.getLogger( "SPTODBLogger" );
024    
025      /**
026       * A map used to manage the various prevalent objects that may be managed
027       * by this prevalent system.  This map provides the primary storage for
028       * the prevalent objects maintained in the system.  The <code>key</code>
029       * for the map are the various classes that are stored in the prevalent
030       * system while the values are the {@link PrimaryStorage} instances that
031       * store the prevalent objects of each type.
032       */
033      private final Map<String,PrimaryStorage> classMap =
034          new LinkedHashMap<String,PrimaryStorage>();
035    
036      /**
037       * A map used to maintain indices for the various prevalent object types
038       * that are managed by this prevalent system.  The <code>key</code> for
039       * the map are the various classes that are stored in the prevalent
040       * system while the values are the {@link IndexStorage} instances that
041       * store the indices for the indexed fields in the prevalent objects of
042       * each type.
043       */
044      private final Map<String,IndexStorage> indexMap =
045          new LinkedHashMap<String,IndexStorage>();
046    
047      /**
048       * A map used to maintain the references in a prevalent object to other
049       * prevalent objects.  This is used to ensure that references are
050       * properly reconstituted when de-serialised.   The <code>key</code> for
051       * the map are the various classes that are stored in the prevalent
052       * system while the values are the {@link ReferenceStorage} instances that
053       * store the references for the prevalent objects referenced by the
054       * prevalent object being managed.
055       */
056      private final Map<String,ReferenceStorage> referenceMap =
057          new LinkedHashMap<String,ReferenceStorage>();
058    
059      /**
060       * A map used to maintain the reverse relationships from prevalent objects
061       * to their parents.  This is used to implement configured actions when
062       * deleting a prevalent object.
063       */
064      private final Map<String,RelationStorage> relationMap =
065          new LinkedHashMap<String,RelationStorage>();
066    
067      /**
068       * A task queue used when persisting object graphs to avoid infinite loops
069       * due to the recursive nature of following object graphs.
070       */
071      private static transient TaskQueue taskQueue = new TaskQueue();
072    
073      /** The sequence used to generate object ids. */
074      private long sequence = 0;
075    
076      /**
077       * Generate the oid to assign to the specified prevalent object. Default
078       * implementation returns an incremented {@link #sequence} value if the
079       * prevalent object does not already have an object id.
080       *
081       * @param object The prevalent object for which an oid is to be generated.
082       * @return The oid to assign to the prevalent object.
083       */
084      @SuppressWarnings( value = "unchecked" )
085      protected Object generateOid( final PrevalentObject object )
086      {
087        Object oid = object.getObjectId();
088        if ( oid == null )
089        {
090          oid = ++sequence;
091        }
092    
093        return oid;
094      }
095    
096      /**
097       * Return the map used to maintain instances of the specified type of
098       * prevalent objects by its object id.
099       *
100       * @see #getPrimaryStorage( String )
101       * @param cls The class whose primary storage is to be retrieved.
102       * @return The primary storage used for the specified prevalent type.
103       */
104      protected PrimaryStorage getPrimaryStorage( final Class cls )
105      {
106        return getPrimaryStorage( cls.getName() );
107      }
108    
109      /**
110       * Return the map used to maintain instances of the specified type of
111       * prevalent objects by its object id.
112       *
113       * @param name The fully qualified name of the class whose primary storage
114       *   is to be retrieved.
115       * @return The primary storage used for the specified prevalent type.
116       */
117      protected PrimaryStorage getPrimaryStorage( final String name )
118      {
119        if ( ! classMap.containsKey( name ) )
120        {
121          classMap.put( name, new PrimaryStorage() );
122        }
123    
124        return classMap.get( name );
125      }
126    
127      /**
128       * Return the map in which the indices for the prevalent class are
129       * stored with the indexed field name.
130       *
131       * @see #getIndexStorage( String )
132       * @param cls The class whose index storage is to be retrieved.
133       * @return The index storage for the specified prevalent type.
134       */
135      protected IndexStorage getIndexStorage( final Class cls )
136      {
137        return getIndexStorage( cls.getName() );
138      }
139    
140      /**
141       * Return the map in which the indices for the prevalent class are
142       * stored with the indexed field name.
143       *
144       * @param name The fully qualified name of the class whose index storage
145       *   is to be retrieved.
146       * @return The index storage for the specified prevalent type.
147       */
148      protected IndexStorage getIndexStorage( final String name )
149      {
150        if ( ! indexMap.containsKey( name ) )
151        {
152          indexMap.put( name, new IndexStorage() );
153        }
154    
155        return indexMap.get( name );
156      }
157    
158      /**
159       * Return the map used to manage the references to other prevalent objects
160       * for the specified prevalent class.
161       *
162       * @see #getReferenceStorage( String )
163       * @param cls The class whose reference storage is to be retrieved.
164       * @return The reference storage for the prevalent class.
165       */
166      protected ReferenceStorage getReferenceStorage( final Class cls )
167      {
168        return getReferenceStorage( cls.getName() );
169      }
170    
171      /**
172       * Return the map used to manage the references to other prevalent objects
173       * for the specified prevalent class.
174       *
175       * @param name The fully qualified name of the class whose reference storage
176       *   is to be retrieved.
177       * @return The reference storage for the prevalent class.
178       */
179      protected ReferenceStorage getReferenceStorage( final String name )
180      {
181        if ( ! referenceMap.containsKey( name ) )
182        {
183          referenceMap.put( name, new ReferenceStorage() );
184        }
185    
186        return referenceMap.get( name );
187      }
188    
189      /**
190       * Return the map used to manage the relations to other prevalent objects
191       * for the specified prevalent class.
192       *
193       * @see #getRelationStorage( String )
194       * @param cls The class whose relations storage is to be retrieved.
195       * @return The relations storage for the prevalent class.
196       */
197      protected RelationStorage getRelationStorage( final Class cls )
198      {
199        return getRelationStorage( cls.getName() );
200      }
201    
202      /**
203       * Return the map used to manage the relations to other prevalent objects
204       * for the specified prevalent class.
205       *
206       * @param name The fully qualified name of the class whose relation storage
207       *   is to be retrieved.
208       * @return The relations storage for the prevalent class.
209       */
210      protected RelationStorage getRelationStorage( final String name )
211      {
212        if ( ! relationMap.containsKey( name ) )
213        {
214          relationMap.put( name, new RelationStorage( name ) );
215        }
216    
217        return relationMap.get( name );
218      }
219    
220      /**
221       * Return the task queue used when persisting objects by reachability.
222       *
223       * @return The queue of prevalent objects in the object graph.
224       */
225      protected Collection<PrevalentObject> getTaskQueue()
226      {
227        return taskQueue.get();
228      }
229    
230      /**
231       * The task queue used to ensure that recursive loops when persisting
232       * inter-related object graphs do not result in infinite loops.
233       */
234      protected static class TaskQueue extends ThreadLocal<Collection<PrevalentObject>>
235      {
236        protected synchronized Collection<PrevalentObject> initialValue()
237        {
238          return new LinkedHashSet<PrevalentObject>();
239        }
240      }
241    }