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.reflection;
19
20 import java.security.AccessController;
21 import java.security.PrivilegedAction;
22 import java.security.PrivilegedActionException;
23 import java.security.PrivilegedExceptionAction;
24
25 import org.apache.jdo.model.ModelException;
26 import org.apache.jdo.model.ModelFatalException;
27 import org.apache.jdo.model.java.JavaModel;
28 import org.apache.jdo.model.java.JavaType;
29 import org.apache.jdo.impl.model.java.AbstractJavaModelFactory;
30 import org.apache.jdo.impl.model.java.BaseReflectionJavaType;
31 import org.apache.jdo.util.I18NHelper;
32
33 /***
34 * A reflection based JavaModelFactory implementation.
35 * The implementation takes <code>java.lang.Class</code> and
36 * <code>java.lang.reflect.Field</code> instances to get Java related
37 * metadata about types and fields. This implementation caches JavaModel
38 * instances per ClassLoader.
39 *
40 * @since 1.1
41 */
42 public abstract class ReflectionJavaModelFactory
43 extends AbstractJavaModelFactory
44 {
45 /*** I18N support */
46 private final static I18NHelper msg =
47 I18NHelper.getInstance("org.apache.jdo.impl.model.java.Bundle");
48
49 /***
50 * Creates a new empty JavaModel instance. A factory implementation may
51 * use the specified key when caching the new JavaModel instance.
52 * <p>
53 * This implementation only accepts <code>java.lang.ClassLoader</code>
54 * instances as key. A ModelException indicates an invalid key.
55 * <p>
56 * The method automatically sets the parent/child relationship for the
57 * created JavaModel according to the parent/child relationship of the
58 * ClassLoader passed as key.
59 * @param key the key that may be used to cache the returned JavaModel
60 * instance.
61 * @return a new JavaModel instance.
62 * @exception ModelException if impossible; the key is of an
63 * inappropriate type.
64 */
65 public JavaModel createJavaModel(Object key)
66 throws ModelException
67 {
68 if ((key != null) && (!(key instanceof ClassLoader)))
69 throw new ModelException(msg.msg("EXC_InvalidJavaModelKey",
70 key.getClass().getName()));
71
72 ClassLoader classLoader = (ClassLoader)key;
73 JavaModel javaModel = newJavaModelInstance(classLoader);
74
75
76 if (classLoader != null) {
77
78
79 try {
80 ClassLoader parentClassLoader = classLoader.getParent();
81 if (parentClassLoader != null) {
82 javaModel.setParent(getJavaModel(parentClassLoader));
83 }
84 }
85 catch (SecurityException ex) {
86
87 }
88 }
89
90 return javaModel;
91 }
92
93 /***
94 * Returns a JavaType instance for the specified type description
95 * (optional operation). This method is a convenience method and a
96 * short cut for <code>getJavaModel(key).getJavaType(typeName)</code>.
97 * <p>
98 * The ReflectionJavaModelFactory supports this short cut and accepts
99 * <code>java.lang.Class</code> instances as valid arguments for this
100 * method. The method throws a
101 * {@link org.apache.jdo.model.ModelFatalException}, if the specified
102 * type descriptor is not a <code>java.lang.Class</code> instance.
103 * @param typeDesc the type description
104 * @return a JavaType instance for the specified type.
105 * @exception ModelFatalException the specified type description is not
106 * a <code>java.lang.Class</code> instance.
107 */
108 public JavaType getJavaType(Object typeDesc)
109 {
110 if (typeDesc == null)
111 return null;
112
113 try {
114 Class clazz = (Class)typeDesc;
115 ClassLoader classLoader = getClassLoaderPrivileged(clazz);
116 return getJavaModel(classLoader).getJavaType(clazz);
117 }
118 catch (ClassCastException ex) {
119 throw new ModelFatalException(msg.msg("EXC_InvalidTypeDesc",
120 typeDesc.getClass().getName()));
121 }
122 }
123
124
125
126 /***
127 * Calls getClassLoader on the specified Class instance in a
128 * doPrivileged block. Any SecurityException is wrapped into a
129 * ModelFatalException.
130 * @param clazz the class to get the ClassLoader from.
131 * @return the class loader that loaded the specified Class instance.
132 * @exception ModelFatalException wraps the SecurityException thrown by
133 * getClassLoader.
134 */
135 public static ClassLoader getClassLoaderPrivileged(final Class clazz)
136 {
137 if (clazz == null)
138 return null;
139
140 try {
141 return (ClassLoader) AccessController.doPrivileged(
142 new PrivilegedAction () {
143 public Object run () {
144 return clazz.getClassLoader();
145 }
146 }
147 );
148 }
149 catch (SecurityException ex) {
150 throw new ModelFatalException(
151 msg.msg("EXC_CannotGetClassLoader", clazz), ex);
152 }
153 }
154
155 /***
156 * Calls Class.forName in a doPrivileged block. Any SecurityException is
157 * wrapped into a ModelFatalException.
158 * @param name fully qualified name of the desired class
159 * @param initialize whether the class must be initialized
160 * @param loader class loader from which the class must be loaded
161 * @return class object representing the desired class.
162 * @exception ModelFatalException wraps the SecurityException thrown by
163 * getClassLoader.
164 * @exception ClassNotFoundException if the class cannot be located by the
165 * specified class loader.
166 */
167 public static Class forNamePrivileged(final String name,
168 final boolean initialize,
169 final ClassLoader loader)
170 throws ClassNotFoundException
171 {
172 try {
173 return (Class) AccessController.doPrivileged(
174 new PrivilegedExceptionAction () {
175 public Object run () throws ClassNotFoundException {
176 return Class.forName(name, initialize, loader);
177 }
178 }
179 );
180 }
181 catch (PrivilegedActionException pae) {
182 throw (ClassNotFoundException) pae.getException();
183 }
184 catch (SecurityException ex) {
185 throw new ModelFatalException(
186 msg.msg("EXC_CannotGetClassInstance", name, loader), ex);
187 }
188 }
189
190 /***
191 * Returns the <code>java.lang.Class</code> wrapped in the specified
192 * JavaType.
193 * @return the <code>java.lang.Class</code> for the specified
194 * JavaType.
195 * @exception ModelFatalException the specified JavaType does
196 * not wrap a <code>java.lang.Class</code> instance.
197 */
198 public Class getJavaClass(JavaType javaType)
199 {
200 if (javaType == null)
201 return null;
202
203 try {
204 return ((BaseReflectionJavaType)javaType).getJavaClass();
205 }
206 catch (ClassCastException ex) {
207 throw new ModelFatalException(msg.msg(
208 "EXC_InvalidJavaType", javaType.getClass()));
209 }
210 }
211
212
213
214 /***
215 * Creates a new instance of the JavaModel implementation class.
216 * <p>
217 * This implementation returns a <code>ReflectionJavaModel</code>
218 * instance.
219 * @return a new JavaModel instance.
220 */
221 protected JavaModel newJavaModelInstance(ClassLoader classLoader) {
222 return new ReflectionJavaModel(classLoader, this);
223 }
224
225 }