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.reflection;
18  
19  import java.security.AccessController;
20  import java.security.PrivilegedAction;
21  import java.io.InputStream;
22  
23  import org.apache.jdo.impl.model.java.AbstractJavaModel;
24  import org.apache.jdo.impl.model.jdo.caching.JDOModelFactoryImplCaching;
25  import org.apache.jdo.model.java.JavaType;
26  import org.apache.jdo.model.jdo.JDOModel;
27  import org.apache.jdo.model.jdo.JDOModelFactory;
28  
29  /***
30   * A reflection based JavaModel implementation used at runtime.  
31   * The implementation takes <code>java.lang.Class</code> and
32   * <code>java.lang.reflect.Field</code> instances to get Java related
33   * metadata about types and fields. 
34   * <p>
35   * The ReflectionJavaModel implementation will use this ClassLoader to lookup
36   * any type by name. This makes sure that the type name is unique.
37   *
38   * @since 1.1
39   * @version 2.0
40   */
41  public class ReflectionJavaModel
42      extends AbstractJavaModel
43  {
44      /*** The ClassLoader instance used as key to cache this JavaModel. */
45      private final ClassLoader classLoader;
46  
47      /*** The declaring JavaModelFactory. */
48      protected final ReflectionJavaModelFactory declaringJavaModelFactory;
49  
50      /*** Constructor. */
51      protected ReflectionJavaModel(ClassLoader classLoader,
52          ReflectionJavaModelFactory declaringJavaModelFactory)
53      {
54          super();
55          this.classLoader = classLoader;
56          this.declaringJavaModelFactory = declaringJavaModelFactory;
57      }
58  
59      /*** 
60       * The method returns the JavaType instance for the specified type
61       * name. A type name is unique within one JavaModel instance. The
62       * method returns <code>null</code> if this model instance does not
63       * know a type with the specified name.
64       * <p>
65       * Note, this method calls Class.forName with the wrapped ClassLoader,
66       * if it cannot find a JavaType with the specified name in the cache.
67       * @param name the name of the type
68       * @return a JavaType instance for the specified name or
69       * <code>null</code> if not present in this model instance.
70       */
71      public JavaType getJavaType(String name) 
72      {
73          synchronized (types) {
74              JavaType javaType = (JavaType)types.get(name);
75              if (javaType == null) {
76                  try {
77                      final boolean initialize = false; 
78                      Class clazz = ReflectionJavaModelFactory.forNamePrivileged(
79                          name, initialize, classLoader);
80                      javaType = getJavaTypeInternal(clazz);
81                  }
82                  catch (ClassNotFoundException ex) {
83                      // cannot find class => return null
84                  }
85              }
86              return javaType;
87          }
88      }
89  
90      /*** 
91       * The method returns the JavaType instance for the type name of the
92       * specified class object. This is a convenience method for 
93       * <code>getJavaType(clazz.getName())</code>. The major difference
94       * between this method and getJavaType taking a type name is that this 
95       * method is supposed to return a non-<code>null<code> value. The
96       * specified class object describes an existing type.
97       * @param clazz the Class instance representing the type
98       * @return a JavaType instance for the name of the specified class
99       * object.
100      */
101     public JavaType getJavaType(Class clazz)
102     {
103         if (clazz == null)
104             return null;
105         
106         return getJavaTypeInternal(clazz);
107     }
108 
109     /***
110      * Finds a resource with a given name. A resource is some data that can
111      * be accessed by class code in a way that is independent of the
112      * location of the code. The name of a resource is a "/"-separated path
113      * name that identifies the resource. The method method opens the
114      * resource for reading and returns an InputStream. It returns 
115      * <code>null</code> if no resource with this name is found or if the
116      * caller doesn't have adequate privileges to get the resource.  
117      * <p>
118      * This implementation delegates the request to the wrapped
119      * ClassLoader. 
120      * @param resourceName the resource name
121      * @return an input stream for reading the resource, or <code>null</code> 
122      * if the resource could not be found or if the caller doesn't have
123      * adequate privileges to get the resource. 
124      */
125     public InputStream getInputStreamForResource(final String resourceName)
126     {
127         return (InputStream) AccessController.doPrivileged(
128             new PrivilegedAction () {
129                 public Object run () {
130                     ClassLoader loader = (classLoader == null) ?
131                         ClassLoader.getSystemClassLoader() : classLoader;
132                     return loader.getResourceAsStream(resourceName);
133                 }
134             }
135             );
136     }
137 
138     /***
139      * Returns the corresponding JDOModel instance.
140      * @return the corresponding JDOModel.
141      */
142     public JDOModel getJDOModel()
143     {
144         if (jdoModel == null) {
145             JDOModelFactory factory = JDOModelFactoryImplCaching.getInstance();
146             jdoModel = factory.getJDOModel(this);
147         }
148         return jdoModel;
149     }
150 
151     // ===== Methods not defined in JavaModel =====
152 
153     /*** 
154      * Returns the ClassLoader wrapped by this ReflectionJavaModel instance.
155      * @return the ClassLoader
156      */
157     public ClassLoader getClassLoader()
158     {
159         return classLoader;
160     }
161 
162     /***
163      * The method returns the JavaType instance for the type name of the
164      * specified class object. It first checks the cache and if there is no
165      * entry for the type name in the cache then it creates a new JavaType
166      * instance for the specified Class object.
167      * @param clazz the Class instance representing the type
168      * @return a JavaType instance for the name of the specified class
169      * object or <code>null</code> if not present in this model instance.
170      */
171     public JavaType getJavaTypeInternal(Class clazz)
172     {
173         String name = clazz.getName();
174         synchronized (types) {
175             JavaType javaType = (JavaType)types.get(name);
176             if (javaType == null) {
177                 javaType = newJavaTypeInstance(clazz);
178                 types.put(name, javaType);
179             }
180             return javaType;
181         }
182     }
183 
184     /***
185      * Returns the declaring ReflectionJavaModelFactory of this
186      * ReflectionJavaModel.
187      * @return the declaring ReflectionJavaModelFactory
188      */
189     public ReflectionJavaModelFactory getDeclaringJavaModelFactory()
190     {
191         return declaringJavaModelFactory;
192     }
193 
194     /*** 
195      * Creates a new instance of the JavaType implementation class.
196      * <p>
197      * This implementation returns a ReflectionJavaType instance.
198      * @param clazz the Class instance representing the type
199      * @return a new JavaType instance
200      */
201     protected JavaType newJavaTypeInstance(Class clazz)
202     {
203         return new ReflectionJavaType(clazz, this);
204     }
205     
206 }