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