001    package com.sptci.prevayler;
002    
003    import com.sptci.prevayler.annotations.ForeignKey.DeleteAction;
004    
005    import java.io.Serializable;
006    import java.util.Collection;
007    import java.util.Collections;
008    import java.util.LinkedHashMap;
009    import java.util.Map;
010    
011    /**
012     * A store for maintaining the relations between a prevalent object and
013     * the other prevalent objects in the prevalent system.  This store is
014     * consulted for determining the actions to be performed when deleting
015     * prevalent objects.  This store is mainly responsible for enforcing
016     * managed relations between prevalent objects.
017     *
018     * <p>&copy; Copyright 2008 <a href='http://sptci.com/' target='_top'>Sans Pareil Technologies, Inc.</a></p>
019     * @author Rakesh Vidyadharan 2008-05-23
020     * @version $Id: RelationStorage.java 4345 2008-06-30 21:22:03Z rakesh $
021     */
022    public class RelationStorage implements Serializable
023    {
024      private static final long serialVersionUID = 1L;
025    
026      /**
027       * A map used to store the meta data associated with a prevalent object.
028       * The <code>key</code> to the map is the type of prevalent object, while
029       * the <code>value</code> is a {@link
030       * com.sptci.prevayler.annotations.ForeignKey.DeleteAction} object that
031       * defines the action to be applied.
032       */
033      private final Map<String,DeleteRule> map
034          = new LinkedHashMap<String,DeleteRule>();
035    
036      /** The name of the prevalent object whose relations are being mapped. */
037      private final String className;
038    
039      /**
040       * Create a new instance of the storage for the specified class name.
041       *
042       * @param name The {@link #className} value to use.
043       */
044      public RelationStorage( final String name )
045      {
046        this.className = name;
047      }
048    
049      /**
050       * A a new relationship to the store for the specified prevalent object.
051       *
052       * @param object The prevalent object that is related to the prevalent
053       *   object identified by {@link #className}.
054       * @param field The name of the field in <code>object</code> that is an
055       *   instance of type {@link #className}.
056       * @param action The delete action to use on the <code>fiele</code> when
057       *   the instance of type {@link #className} is deleted.
058       */
059      public void add( final PrevalentObject object, final String field,
060          final DeleteAction action )
061      {
062        final String name = object.getClass().getName();
063    
064        if ( ! map.containsKey( name) )
065        {
066          map.put( name, new DeleteRule() );
067        }
068    
069        map.get( name ).add( field, action );
070      }
071    
072      /**
073       * Return the names of the classes that hold a reference to the prevalent
074       * class that is being managed.
075       *
076       * @return The collection of class names that hold references to
077       *   instances of the managed class.
078       */
079      public Collection<String> getRelations()
080      {
081        return Collections.unmodifiableCollection( map.keySet() );
082      }
083    
084      /**
085       * Return a map of field name of delete actions for the specified
086       * prevalent class with which the class being managed has relations.
087       *
088       * @see com.sptci.prevayler.RelationStorage.DeleteRule#getRules
089       * @param name The name of prevalent class with which relations are
090       *   maintained.
091       * @return A map of field-delete rule mappings.  Returns an empty
092       *   map if no rules exist for the specified class.
093       */
094      public Map<String,DeleteAction> getDeleteRules( final String name )
095      {
096        final Map<String,DeleteAction> results = new LinkedHashMap<String,DeleteAction>();
097        final DeleteRule rule = map.get( name );
098        results.putAll( rule.getRules() );
099        return results;
100      }
101    
102      /**
103       * Return the fully qualified class name of the prevalent object for which
104       * the reference relations are being stored.
105       *
106       * @return The {@link #className} value.
107       */
108      public String getClassName()
109      {
110        return className;
111      }
112    
113      /**
114       * A class used to capture the names of the fields in a prevalent object
115       * that are related to the prevalent object being managed by this
116       * store.
117       */
118      private class DeleteRule implements Serializable
119      {
120        private static final long serialVersionUID = 1L;
121    
122        /**
123         * The map used to maintain the field-name to delete rule mapping.
124         */
125        private Map<String,DeleteAction> actionMap =
126            new LinkedHashMap<String,DeleteAction>();
127    
128        /**
129         * Add a mapping for the specified field name with the associated
130         * deleted rule.
131         *
132         * @param field The name of the field for the mapping.
133         * @param action The delete rule to apply for the field.
134         */
135        private void add( final String field, final DeleteAction action )
136        {
137          if ( ! actionMap.containsKey( field ) )
138          {
139            actionMap.put( field, action );
140          }
141        }
142    
143        /**
144         * Return the {@link #actionMap} as an unmodifiable view.
145         *
146         * @return The mappings in {@link #actionMap}.
147         */
148        private Map<String,DeleteAction> getRules()
149        {
150          return Collections.unmodifiableMap( actionMap );
151        }
152      }
153    }