View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software 
12   * distributed under the License is distributed on an "AS IS" BASIS, 
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
14   * See the License for the specific language governing permissions and 
15   * limitations under the License.
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                 // create new model and store it using the specified key
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); //NOI18N
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             // nothing to be removed => return
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                     // found javaModel => remove the entry
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(), //NOI18N
178             "getJavaType")); //NOI18N
179     }
180     
181 }
182