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