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