View Javadoc

1   /*
2    * Copyright 2005 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at 
7    * 
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software 
11   * distributed under the License is distributed on an "AS IS" BASIS, 
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License.
15   */
16  
17  package org.apache.jdo.impl.model.java;
18  
19  import java.util.Iterator;
20  import java.util.Map;
21  import java.util.HashMap;
22  
23  import org.apache.jdo.model.ModelException;
24  import org.apache.jdo.model.ModelFatalException;
25  import org.apache.jdo.model.java.JavaModel;
26  import org.apache.jdo.model.java.JavaModelFactory;
27  import org.apache.jdo.model.java.JavaType;
28  import org.apache.jdo.util.I18NHelper;
29  
30  /***
31   * Abstract super class for JavaModelFactory implementations. It provides a
32   * JavaModel cache and implements the JavaModel lookup method 
33   * {@link #getJavaModel(Object key)}.
34   * <p>
35   * A non-abstract subclass must implement method 
36   * {@link #createJavaModel(Object key)}. The lookup method calls this
37   * method if it cannot find a JavaModel instance in the cache. The method
38   * should also check whether the specified key is of an appropriate type
39   * for the JavaModelFactory implementation. A subclass should check whether
40   * it can implement method {@link #getJavaType(Object typeDesc)}. The
41   * implementation in AbstractJavaModelFactory always throws a
42   * ModelFatalException.
43   * 
44   * @author Michael Bouschen
45   * @since 1.0.1
46   * @version 2.0
47   */
48  abstract public class AbstractJavaModelFactory
49      implements JavaModelFactory
50  {    
51      /***
52       * Map of JavaModel instances, key is implementation specific.
53       * @see #getJavaModel(Object key)
54       */
55      private Map modelCache = new HashMap();
56      
57      /*** I18N support */
58      private static I18NHelper msg = 
59          I18NHelper.getInstance(AbstractJavaModelFactory.class);
60  
61      /***
62       * Creates a new empty JavaModel instance. A factory implementation may
63       * use the specified key when caching the new JavaModel instance. 
64       * <p>
65       * Each JavaModelFactory imposes its own restrictions for the keys to
66       * cache JavaModel instances. Some implementation will allow only keys
67       * of a certain type. Some implementations will prohibit
68       * <code>null</code> keys. Attempting to use an ineligible key will
69       * result in a {@link org.apache.jdo.model.ModelException}. This means
70       * the specified key is of an inappropriate type for this
71       * JavaModelFactory or if the key is <code>null</code> and this 
72       * JavaModelFactory does not support <code>null</code> keys.
73       * @param key the key that may be used to cache the returned JavaModel instance.
74       * @return a new JavaModel instance.
75       * @exception ModelException if impossible; the key is of an
76       * inappropriate type or the key is <code>null</code> and this
77       * JavaModelFactory does not support <code>null</code> keys.
78       */
79      abstract public JavaModel createJavaModel(Object key)
80          throws ModelException;
81  
82      /***
83       * Returns the JavaModel instance for the specified key.
84       * <p>
85       * The method throws a {@link org.apache.jdo.model.ModelFatalException},
86       * if the specified key is of an inappropriate type for this
87       * JavaModelFactory or if the key is <code>null</code> and this
88       * JavaModelFactory does not support <code>null</code> keys.
89       * @param key the key used to cache the returned JavaModel instance.
90       * @return a JavaModel instance for the specified key.
91       * @exception ModelFatalException the key is of an inappropriate type
92       * or the key is <code>null</code> and this JavaModelFactory does not
93       * support <code>null</code> keys.
94       */
95      public JavaModel getJavaModel(Object key)
96      {
97          synchronized (modelCache) {
98              JavaModel javaModel = (JavaModel)modelCache.get(key);
99              if (javaModel == null) {
100                 // create new model and store it using the specified key
101                 try {
102                     javaModel = createJavaModel(key);
103                     modelCache.put(key, javaModel);
104                 }
105                 catch (ModelException ex) {
106                     throw new ModelFatalException(
107                         msg.msg("EXC_CannotCreateJavaModel"), ex); //NOI18N
108                 }
109             } 
110             return javaModel;
111          }
112     }
113 
114     /***
115      * Removes the specified javaModel from the JavaModel cache. Note, if
116      * there are multiple entries in the cache with the specified javaModel
117      * as value, then all of them get removed. The method does not have an
118      * effect, if this factory does not have the specified javaModel.
119      * @param javaModel the JavaModel to be removed.
120      * @since 2.0
121      */
122     public void removeJavaModel(JavaModel javaModel) {
123         if (javaModel == null) {
124             // nothing to be removed => return
125             return;
126         }
127         
128         synchronized (modelCache) {
129             for (Iterator i = modelCache.entrySet().iterator(); i.hasNext();) {
130                 Map.Entry entry = (Map.Entry) i.next();
131                 Object value = entry.getValue();
132                 if ((javaModel == value) || javaModel.equals(value)) {
133                     // found javaModel => remove the entry
134                     i.remove();
135                 }
136             }
137         }
138     }
139 
140     /***
141      * Removes the JavaModel for the specified key from the JavaModel
142      * cache. The method does not have an effect, if this factory does not 
143      * have a JavaModel for the the specified key.
144      * @param key the key used to find the JavaModel instance to be removed.
145      * @since 2.0
146      */
147     public void removeJavaModel(Object key) {
148         synchronized (modelCache) {
149             modelCache.remove(key);
150         } 
151     }
152 
153     /***
154      * Returns a JavaType instance for the specified type description
155      * (optional operation). This method is a convenience method and a
156      * short cut for <code>getJavaModel(key).getJavaType(typeName)</code>. 
157      * If the factory supports this method, it needs to be able to get the
158      * key for the JavaModel lookup and the type name for the JavaType
159      * lookup from the specified typeDesc. An example for such a type
160      * description is the java.lang.Class instance in the runtime
161      * environment. 
162      * <p>
163      * The method throws a {@link org.apache.jdo.model.ModelFatalException}, 
164      * if this factory does not support this short cut or if it does not
165      * support the specified type description.
166      * <p>
167      * This implementation always throws a ModelFatalException.
168      * @param typeDesc the type description.
169      * @return a JavaType instance for the specified type.
170      * @exception ModelFatalException this factory does not support this
171      * short cut or does not support the specified type description.
172      */
173     public JavaType getJavaType(Object typeDesc)
174     {
175         throw new ModelFatalException(msg.msg(
176             "EXC_MethodNotSupported", this.getClass().getName(), //NOI18N
177             "getJavaType")); //NOI18N
178     }
179     
180 }
181