001package org.andromda.core.metafacade;
002
003import java.io.Serializable;
004import java.util.HashMap;
005import java.util.Map;
006
007/**
008 * A global cache for metafacades. Used by the {@link MetafacadeFactory}when constructing or retrieving metafacade
009 * instances. If the cache constains the metafacade it should not be constructed again.
010 *
011 * @author Chad Brandon
012 */
013public final class MetafacadeCache
014    implements Serializable
015{
016    private static final long serialVersionUID = 34L;
017
018    /**
019     * Constructs a new instance of this class.
020     *
021     * @return the new instance
022     */
023    public static MetafacadeCache newInstance()
024    {
025        return new MetafacadeCache();
026    }
027
028    private MetafacadeCache()
029    {
030        // don't allow instantiation
031    }
032
033    /**
034     * The namespace to which the cache currently applies
035     */
036    private String namespace;
037
038    /**
039     * Sets the namespace to which the cache currently applies.
040     *
041     * @param namespace the current namespace.
042     */
043    public final void setNamespace(final String namespace)
044    {
045        this.namespace = namespace;
046    }
047
048    /**
049     * The cache for already created metafacades.
050     */
051    private final Map<Object, Map<Class, Map<String, MetafacadeBase>>> metafacadeCache = new HashMap<Object, Map<Class, Map<String, MetafacadeBase>>>();
052
053    /**
054     * <p>
055     * Returns the metafacade from the metafacade cache. The Metafacades are cached first by according to its
056     * <code>mappingObject</code>, next the <code>metafacadeClass</code>, and finally by the current namespace. </p>
057     * <p>
058     * Metafacades must be cached in order to keep track of the state of its validation. If we keep creating a new one
059     * each time, we can never tell whether or not a metafacade has been previously validated. Not to mention tremendous
060     * performance gains. </p>
061     *
062     * @param mappingObject   the object to which the mapping applies
063     * @param metafacadeClass the class of the metafacade.
064     * @return MetafacadeBase stored in the cache.
065     */
066    public final MetafacadeBase get(
067        final Object mappingObject,
068        final Class metafacadeClass)
069    {
070        MetafacadeBase metafacade = null;
071        final Map<Class, Map<String, MetafacadeBase>> namespaceMetafacadeCache = this.metafacadeCache.get(mappingObject);
072        if (namespaceMetafacadeCache != null)
073        {
074            final Map<String, MetafacadeBase> metafacadeCache = namespaceMetafacadeCache.get(metafacadeClass);
075            if (metafacadeCache != null)
076            {
077                metafacade = metafacadeCache.get(this.namespace);
078            }
079        }
080        return metafacade;
081    }
082
083    /**
084     * Adds the <code>metafacade</code> to the cache according to first <code>mappingObject</code>, second the
085     * <code>metafacade</code>, and finally by the current <code>namespace</code>.
086     *
087     * @param mappingObject the mappingObject for which to cache the metafacade.
088     * @param metafacade the metafacade to cache.
089     */
090    public final void add(
091        final Object mappingObject,
092        final MetafacadeBase metafacade)
093    {
094        Map<Class, Map<String, MetafacadeBase>> namespaceMetafacadeCache = this.metafacadeCache.get(mappingObject);
095        if (namespaceMetafacadeCache == null)
096        {
097            namespaceMetafacadeCache = new HashMap<Class, Map<String, MetafacadeBase>>();
098            this.metafacadeCache.put(mappingObject, namespaceMetafacadeCache);
099        }
100        Map<String, MetafacadeBase> metafacadeCache = namespaceMetafacadeCache.get(metafacade.getClass());
101        if (metafacadeCache == null)
102        {
103            metafacadeCache = new HashMap<String, MetafacadeBase>();
104            namespaceMetafacadeCache.put(
105                metafacade.getClass(),
106                metafacadeCache);
107        }
108        metafacadeCache.put(this.namespace, metafacade);
109    }
110
111    /**
112     * Clears the cache of any metafacades
113     */
114    public final void clear()
115    {
116        this.metafacadeCache.clear();
117    }
118
119    /**
120     * @see Object#toString()
121     */
122    public String toString()
123    {
124        return this.metafacadeCache.toString();
125    }
126}