You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-commits@db.apache.org by mb...@apache.org on 2005/10/27 23:27:51 UTC

svn commit: r328951 - in /incubator/jdo/trunk: core20/src/java/org/apache/jdo/impl/model/java/ core20/src/java/org/apache/jdo/impl/model/java/reflection/ enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/model/ fostore20/test/conf/ ri11/src/java/or...

Author: mbo
Date: Thu Oct 27 14:27:16 2005
New Revision: 328951

URL: http://svn.apache.org/viewcvs?rev=328951&view=rev
Log:
Fixed ClassLoader issue in JavaModel implementation.
- Call Class.forName in a doPrivileged block to avoid SecurityException.
- The RuntimeJavaModel delegates a getJavaType lookup to the JavaModel
  corresponding to the ClassLoader hat loads the class.
- A getJavaType lookup per Class instance asserts that the specified Class 
  instance is loaded by the ClassLoader bound to the RuntimeJavaModel instance.

Modified:
    incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/BaseReflectionJavaField.java
    incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/Bundle.properties
    incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModel.java
    incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModelFactory.java
    incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/model/EnhancerJavaModel.java
    incubator/jdo/trunk/fostore20/test/conf/JDO20Policy
    incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/meta/model/EnhancerJavaModel.java
    incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/AbstractJavaModelFactory.java
    incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/BaseReflectionJavaField.java
    incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/Bundle.properties
    incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModel.java
    incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModelFactory.java
    incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/runtime/Bundle.properties
    incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModel.java
    incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModelFactory.java
    incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/xml/XMLExists.java
    incubator/jdo/trunk/runtime20/src/java/org/apache/jdo/impl/model/java/runtime/Bundle.properties
    incubator/jdo/trunk/runtime20/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModel.java
    incubator/jdo/trunk/runtime20/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModelFactory.java

Modified: incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/BaseReflectionJavaField.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/BaseReflectionJavaField.java?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/BaseReflectionJavaField.java (original)
+++ incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/BaseReflectionJavaField.java Thu Oct 27 14:27:16 2005
@@ -165,11 +165,6 @@
                     catch (NoSuchFieldException ex) {
                         return null; // do nothing, just return null
                     }
-                    catch (LinkageError ex) {
-                        throw new ModelFatalException(msg.msg(
-                           "EXC_ClassLoadingError", clazz.getName(), //NOI18N
-                           ex.toString()));
-                    }
                 }
             }
             );
@@ -197,11 +192,6 @@
                         throw new ModelFatalException(
                             msg.msg("EXC_CannotGetDeclaredFields", //NOI18N
                                     clazz.getName()), ex); 
-                    }
-                    catch (LinkageError ex) {
-                        throw new ModelFatalException(msg.msg(
-                           "EXC_ClassLoadingError", clazz.getName(), //NOI18N
-                           ex.toString()));
                     }
                 }
             }

Modified: incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/Bundle.properties
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/Bundle.properties?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/Bundle.properties (original)
+++ incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/Bundle.properties Thu Oct 27 14:27:16 2005
@@ -21,11 +21,6 @@
 #NOI18N
 ERR_InvalidNullFieldInstance={0}: specified Field instance is null.
 
-
-# {0} - class name
-# {1} - detailed message of the cause
-EXC_ClassLoadingError=Error during loading of class ''{0}'': {1}.
-
 #
 # BaseReflectionJavaType
 #
@@ -75,6 +70,13 @@
 must grant ReflectPermission("getClassLoader") to the codeBase containing the \
 JavaModel and JDOModel implementation.
 
+# {0} - class name
+# {1} - class loader
+EXC_CannotGetClassInstance=A SecurityException was thrown when trying to call \
+Class.forName for class ''{0}'' and class loader ''{1}''. In order to get \
+runtime metadata, you must grant ReflectPermission("getClassLoader") to the \
+codeBase containing the JavaModel and JDOModel implementation.
+
 # {0} - key instance
 EXC_InvalidJavaModelKey=Invalid key for runtime JavaModel lookup: \
 expected ''java.lang.ClassLoader'' instance, found ''{0}'' instance.
@@ -87,6 +89,18 @@
 EXC_InvalidJavaType=Invalid JavaType instance for getJavaClass method: \
 expected ''org.apache.jdo.impl.model.java.ReflectionJavaType'' instance, \
 found ''{0}'' instance.
+
+#
+# ReflectionJavaModel
+#
+
+# {0} - class name
+# {1} - class loader of class instance
+# {2} - class loader of JavaModel
+#NOI18N
+ERR_UnexpectedClassLoader=Unexpected class loader. The specified class \
+instance of class ''{0}'' was loaded by class loader ''{1}'', but the \
+JavaModel instance is bound to a different class loader ''{2}''.
 
 #
 # ReflectionJavaTypeIntrospector

Modified: incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModel.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModel.java?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModel.java (original)
+++ incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModel.java Thu Oct 27 14:27:16 2005
@@ -22,11 +22,9 @@
 
 import org.apache.jdo.impl.model.java.AbstractJavaModel;
 import org.apache.jdo.impl.model.jdo.caching.JDOModelFactoryImplCaching;
-import org.apache.jdo.model.ModelFatalException;
 import org.apache.jdo.model.java.JavaType;
 import org.apache.jdo.model.jdo.JDOModel;
 import org.apache.jdo.model.jdo.JDOModelFactory;
-import org.apache.jdo.util.I18NHelper;
 
 /**
  * A reflection based JavaModel implementation used at runtime.  
@@ -37,9 +35,8 @@
  * The ReflectionJavaModel implementation will use this ClassLoader to lookup
  * any type by name. This makes sure that the type name is unique.
  *
- * @author Michael Bouschen
- * @since JDO 1.1
- * @version JDO 2.0
+ * @since 1.1
+ * @version 2.0
  */
 public class ReflectionJavaModel
     extends AbstractJavaModel
@@ -47,30 +44,15 @@
     /** The ClassLoader instance used as key to cache this JavaModel. */
     private final ClassLoader classLoader;
 
-    /** Flag passed to the Class.forName call. */
-    private final boolean initialize;
-
     /** The declaring JavaModelFactory. */
     protected final ReflectionJavaModelFactory declaringJavaModelFactory;
 
-    /** I18N support */
-    private final static I18NHelper msg =  
-        I18NHelper.getInstance("org.apache.jdo.impl.model.java.Bundle"); //NOI18N
-
-    /** Constructor. */
-    public ReflectionJavaModel(ClassLoader classLoader,
-        ReflectionJavaModelFactory declaringJavaModelFactory)
-    {
-        this(classLoader, true, declaringJavaModelFactory);
-    }
-    
     /** Constructor. */
-    protected ReflectionJavaModel(ClassLoader classLoader, boolean initialize, 
+    protected ReflectionJavaModel(ClassLoader classLoader,
         ReflectionJavaModelFactory declaringJavaModelFactory)
     {
         super();
         this.classLoader = classLoader;
-        this.initialize = initialize;
         this.declaringJavaModelFactory = declaringJavaModelFactory;
     }
 
@@ -92,20 +74,14 @@
             JavaType javaType = (JavaType)types.get(name);
             if (javaType == null) {
                 try {
-                    // Note, if name denotes a pc class that has not been
-                    // loaded, Class.forName will load the class which
-                    // calls RegisterClassListener.registerClass.
-                    // This will create a new JavaType entry in the cache.
-                    javaType = getJavaTypeInternal(
-                        Class.forName(name, initialize, classLoader));
+                    final boolean initialize = false; 
+                    Class clazz = ReflectionJavaModelFactory.forNamePrivileged(
+                        name, initialize, classLoader);
+                    javaType = getJavaTypeInternal(clazz);
                 }
                 catch (ClassNotFoundException ex) {
                     // cannot find class => return null
                 }
-                catch (LinkageError ex) {
-                    throw new ModelFatalException(msg.msg(
-                        "EXC_ClassLoadingError", name, ex.toString())); //NOI18N
-                }
             }
             return javaType;
         }
@@ -118,32 +94,15 @@
      * between this method and getJavaType taking a type name is that this 
      * method is supposed to return a non-<code>null<code> value. The
      * specified class object describes an existing type.
-     * <p>
-     * Note, this implementation does not call the overloaded getJavaType
-     * method taking a String, because this would retrieve the Class
-     * instance for the specified type again. Instead, it checks the cache 
-     * directly. If not available it creates a new ReflectionJavaType using
-     * the specified class instance.
      * @param clazz the Class instance representing the type
      * @return a JavaType instance for the name of the specified class
-     * object or <code>null</code> if not present in this model instance.
+     * object.
      */
     public JavaType getJavaType(Class clazz)
     {
         if (clazz == null)
             return null;
         
-        if (initialize) {
-            try {
-                // make sure the class is initialized
-                Class.forName(clazz.getName(), initialize, 
-                    ReflectionJavaModelFactory.getClassLoaderPrivileged(clazz));
-            }
-            catch (ClassNotFoundException ex) {
-                // ignore, since class has already been loaded 
-            }
-        }
-
         return getJavaTypeInternal(clazz);
     }
 
@@ -168,7 +127,9 @@
         return (InputStream) AccessController.doPrivileged(
             new PrivilegedAction () {
                 public Object run () {
-                    return classLoader.getResourceAsStream(resourceName);
+                    ClassLoader loader = (classLoader == null) ?
+                        ClassLoader.getSystemClassLoader() : classLoader;
+                    return loader.getResourceAsStream(resourceName);
                 }
             }
             );
@@ -207,7 +168,7 @@
      * @return a JavaType instance for the name of the specified class
      * object or <code>null</code> if not present in this model instance.
      */
-    protected JavaType getJavaTypeInternal(Class clazz)
+    public JavaType getJavaTypeInternal(Class clazz)
     {
         String name = clazz.getName();
         synchronized (types) {
@@ -219,8 +180,12 @@
             return javaType;
         }
     }
-    
-    /** */
+
+    /**
+     * Returns the declaring ReflectionJavaModelFactory of this
+     * ReflectionJavaModel.
+     * @return the declaring ReflectionJavaModelFactory
+     */
     public ReflectionJavaModelFactory getDeclaringJavaModelFactory()
     {
         return declaringJavaModelFactory;

Modified: incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModelFactory.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModelFactory.java?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModelFactory.java (original)
+++ incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModelFactory.java Thu Oct 27 14:27:16 2005
@@ -18,6 +18,8 @@
 
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 
 import org.apache.jdo.model.ModelException;
 import org.apache.jdo.model.ModelFatalException;
@@ -34,8 +36,7 @@
  * metadata about types and fields. This implementation caches JavaModel
  * instances per ClassLoader.
  * 
- * @author Michael Bouschen
- * @since JDO 1.1
+ * @since 1.1
  */
 public abstract class ReflectionJavaModelFactory
     extends AbstractJavaModelFactory
@@ -49,8 +50,7 @@
      * use the specified key when caching the new JavaModel instance. 
      * <p>
      * This implementation only accepts <code>java.lang.ClassLoader</code>
-     * instances as key and does not support <code>null</code> keys. A
-     * ModelException indicates an invalid key.
+     * instances as key. A ModelException indicates an invalid key.
      * <p>
      * The method automatically sets the parent/child relationship for the
      * created JavaModel according to the parent/child relationship of the 
@@ -59,22 +59,21 @@
      * instance. 
      * @return a new JavaModel instance.
      * @exception ModelException if impossible; the key is of an
-     * inappropriate type or the key is <code>null</code> and this
-     * JavaModelFactory does not support <code>null</code> keys.
+     * inappropriate type.
      */
     public JavaModel createJavaModel(Object key)
         throws ModelException
     {
-        if ((key == null) || (!(key instanceof ClassLoader)))
+        if ((key != null) && (!(key instanceof ClassLoader)))
             throw new ModelException(msg.msg("EXC_InvalidJavaModelKey", //NOI18N
-                (key==null?"null":key.getClass().getName()))); //NOI18N
+                                             key.getClass().getName()));
         
         ClassLoader classLoader = (ClassLoader)key;
         JavaModel javaModel = newJavaModelInstance(classLoader);
 
         // check parent <-> child relationship
-        if (classLoader != ClassLoader.getSystemClassLoader()) {
-            // if the specified classLoader is not the system class loader
+        if (classLoader != null) {
+            // if the specified classLoader is not null,
             // try to get the parent class loader and update the parent property
             try {
                 ClassLoader parentClassLoader = classLoader.getParent();
@@ -91,20 +90,6 @@
     }
 
     /**
-     * Returns the JavaModel instance for the specified key.
-     * @param key the key used to cache the returned JavaModel instance
-     */
-    public JavaModel getJavaModel(Object key)
-    {
-        if (key == null) {
-            // null classLoader might happen for classes loaded by the
-            // bootstrap class loder
-            key = ClassLoader.getSystemClassLoader();
-        }
-        return super.getJavaModel(key);
-    }
-    
-    /**
      * Returns a JavaType instance for the specified type description
      * (optional operation). This method is a convenience method and a
      * short cut for <code>getJavaModel(key).getJavaType(typeName)</code>.
@@ -138,10 +123,11 @@
     // ===== Methods not defined in JavaModelFactory =====
 
     /**
-     * Calls getClassLoader on the specified class instance in a
+     * Calls getClassLoader on the specified Class instance in a
      * doPrivileged block. Any SecurityException is wrapped into a
      * ModelFatalException. 
-     * @return the class loader that loaded the specified class instance.
+     * @param clazz the class to get the ClassLoader from.
+     * @return the class loader that loaded the specified Class instance.
      * @exception ModelFatalException wraps the SecurityException thrown by
      * getClassLoader.
      */
@@ -162,6 +148,41 @@
         catch (SecurityException ex) {
             throw new ModelFatalException(
                 msg.msg("EXC_CannotGetClassLoader", clazz), ex); //NOI18N
+        }
+    }
+
+    /**
+     * Calls Class.forName in a doPrivileged block. Any SecurityException is
+     * wrapped into a ModelFatalException.
+     * @param name fully qualified name of the desired class
+     * @param initialize whether the class must be initialized
+     * @param loader class loader from which the class must be loaded
+     * @return class object representing the desired class.
+     * @exception ModelFatalException wraps the SecurityException thrown by
+     * getClassLoader.
+     * @exception ClassNotFoundException if the class cannot be located by the
+     * specified class loader.
+     */
+    public static Class forNamePrivileged(final String name, 
+                                          final boolean initialize, 
+                                          final ClassLoader loader)
+        throws ClassNotFoundException
+    {
+        try { 
+            return (Class) AccessController.doPrivileged(
+                new PrivilegedExceptionAction () {
+                    public Object run () throws ClassNotFoundException {
+                        return Class.forName(name, initialize, loader);
+                    }
+                }
+                );
+        }
+        catch (PrivilegedActionException pae) {
+            throw (ClassNotFoundException) pae.getException();
+        }
+        catch (SecurityException ex) {
+            throw new ModelFatalException(
+                msg.msg("EXC_CannotGetClassInstance", name, loader), ex);
         }
     }
 

Modified: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/model/EnhancerJavaModel.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/model/EnhancerJavaModel.java?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/model/EnhancerJavaModel.java (original)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/model/EnhancerJavaModel.java Thu Oct 27 14:27:16 2005
@@ -43,7 +43,7 @@
     public EnhancerJavaModel(ClassLoader classLoader,
                              ResourceLocator locator)
     {
-        super(classLoader, false, null);
+        super(classLoader, null);
         this.locator = locator;
     }
     

Modified: incubator/jdo/trunk/fostore20/test/conf/JDO20Policy
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/test/conf/JDO20Policy?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/fostore20/test/conf/JDO20Policy (original)
+++ incubator/jdo/trunk/fostore20/test/conf/JDO20Policy Thu Oct 27 14:27:16 2005
@@ -33,6 +33,9 @@
 	// Allow jdori classes to get metadata for persistence-capable classes.
 	permission javax.jdo.spi.JDOPermission "getMetadata";
 
+	// Allow jdo model classes to get a class loader
+	permission java.lang.RuntimePermission "getClassLoader";
+
 	// Allow jdori classes to access declared members of a class 
 	// (e.g. a query accessing transient instances or non-managed fields).
 	// The query component needs access to persistent fields.

Modified: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/meta/model/EnhancerJavaModel.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/meta/model/EnhancerJavaModel.java?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/meta/model/EnhancerJavaModel.java (original)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/meta/model/EnhancerJavaModel.java Thu Oct 27 14:27:16 2005
@@ -43,7 +43,7 @@
     public EnhancerJavaModel(ClassLoader classLoader,
                              ResourceLocator locator)
     {
-        super(classLoader, false);
+        super(classLoader, null);
         this.locator = locator;
     }
     

Modified: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/AbstractJavaModelFactory.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/AbstractJavaModelFactory.java?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/AbstractJavaModelFactory.java (original)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/AbstractJavaModelFactory.java Thu Oct 27 14:27:16 2005
@@ -32,9 +32,7 @@
 /**
  * Abstract super class for JavaModelFactory implementations. It provides a
  * JavaModel cache and implements the JavaModel lookup method 
- * {@link #getJavaModel(Object key)}. Any JavaModel instance returned by
- * this method is automatically connected to its corresponding JDOModel
- * instance.
+ * {@link #getJavaModel(Object key)}.
  * <p>
  * A non-abstract subclass must implement method 
  * {@link #createJavaModel(Object key)}. The lookup method calls this
@@ -46,7 +44,8 @@
  * ModelFatalException.
  * 
  * @author Michael Bouschen
- * @since JDO 1.0.1
+ * @since 1.0.1
+ * @version 1.1
  */
 abstract public class AbstractJavaModelFactory
     implements JavaModelFactory
@@ -97,7 +96,7 @@
      */
     public JavaModel getJavaModel(Object key)
     {
-        synchronized (this.modelCache) {
+        synchronized (modelCache) {
             JavaModel javaModel = (JavaModel)modelCache.get(key);
             if (javaModel == null) {
                 // create new model and store it using the specified key
@@ -107,7 +106,7 @@
                 }
                 catch (ModelException ex) {
                     throw new ModelFatalException(
-                        "EXC_CannotCreateJavaModel", ex); //NOI18N
+                        msg.msg("EXC_CannotCreateJavaModel"), ex); //NOI18N
                 }
             } 
             return javaModel;

Modified: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/BaseReflectionJavaField.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/BaseReflectionJavaField.java?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/BaseReflectionJavaField.java (original)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/BaseReflectionJavaField.java Thu Oct 27 14:27:16 2005
@@ -145,11 +145,6 @@
                     catch (NoSuchFieldException ex) {
                         return null; // do nothing, just return null
                     }
-                    catch (LinkageError ex) {
-                        throw new ModelFatalException(msg.msg(
-                           "EXC_ClassLoadingError", clazz.getName(), //NOI18N
-                           ex.toString()));
-                    }
                 }
             }
             );

Modified: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/Bundle.properties
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/Bundle.properties?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/Bundle.properties (original)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/Bundle.properties Thu Oct 27 14:27:16 2005
@@ -22,10 +22,6 @@
 ERR_InvalidNullFieldInstance={0}: specified Field instance is null.
 
 
-# {0} - class name
-# {1} - detailed message of the cause
-EXC_ClassLoadingError=Error during loading of class ''{0}'': {1}.
-
 #
 # BaseReflectionJavaType
 #
@@ -64,6 +60,8 @@
 # {1} - method name
 EXC_MethodNotSupported=Class {0} does not support method {1}.
 
+EXC_CannotCreateJavaModel=Problems during JavaModel creation.
+
 #
 # ReflectionJavaModelFactory
 #
@@ -73,4 +71,12 @@
 class loader of class instance ''{0}''. In order to get runtime metadata, you \
 must grant ReflectPermission("getClassLoader") to the codeBase containing the \
 JDO Reference Implementation (jdori.jar).
+
+# {0} - class name
+# {1} - class loader
+EXC_CannotGetClassInstance=A SecurityException was thrown when trying to call \
+Class.forName for class ''{0}'' and class loader ''{1}''. In order to get \
+runtime metadata, you must grant ReflectPermission("getClassLoader") to the \
+codeBase containing the JDO Reference Implementation (jdori.jar).
+
 

Modified: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModel.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModel.java?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModel.java (original)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModel.java Thu Oct 27 14:27:16 2005
@@ -21,10 +21,8 @@
 import java.io.InputStream;
 
 import org.apache.jdo.impl.model.java.AbstractJavaModel;
-import org.apache.jdo.model.ModelFatalException;
 import org.apache.jdo.model.java.JavaType;
 import org.apache.jdo.model.jdo.JDOModel;
-import org.apache.jdo.util.I18NHelper;
 
 /**
  * A reflection based JavaModel implementation used at runtime.  
@@ -35,8 +33,7 @@
  * The ReflectionJavaModel implementation will use this ClassLoader to lookup
  * any type by name. This makes sure that the type name is unique.
  *
- * @author Michael Bouschen
- * @since JDO 1.1
+ * @since 1.1
  */
 public abstract class ReflectionJavaModel
     extends AbstractJavaModel
@@ -44,25 +41,16 @@
     /** The ClassLoader instance used as key to cache this JavaModel. */
     private final ClassLoader classLoader;
 
-    /** Flag passed to the Class.forName call. */
-    private final boolean initialize;
+    /** The declaring JavaModelFactory. */
+    protected final ReflectionJavaModelFactory declaringJavaModelFactory;
 
-    /** I18N support */
-    private final static I18NHelper msg =  
-        I18NHelper.getInstance("org.apache.jdo.impl.model.java.Bundle"); //NOI18N
-
-    /** Constructor taking the ClassLoader. */
-    public ReflectionJavaModel(ClassLoader classLoader) 
-    {
-        this(classLoader, true);
-    }
-    
-    /** */
-    protected ReflectionJavaModel(ClassLoader classLoader, boolean initialize)
+    /** Constructor. */
+    public ReflectionJavaModel(ClassLoader classLoader,
+        ReflectionJavaModelFactory declaringJavaModelFactory)
     {
         super();
         this.classLoader = classLoader;
-        this.initialize = initialize;
+        this.declaringJavaModelFactory = declaringJavaModelFactory;
     }
 
     /** 
@@ -83,20 +71,14 @@
             JavaType javaType = (JavaType)types.get(name);
             if (javaType == null) {
                 try {
-                    // Note, if name denotes a pc class that has not been
-                    // loaded, Class.forName will load the class which
-                    // calls RegisterClassListener.registerClass.
-                    // This will create a new JavaType entry in the cache.
-                    javaType = getJavaTypeInternal(
-                        Class.forName(name, initialize, classLoader));
+                    final boolean initialize = false;
+                    Class clazz = ReflectionJavaModelFactory.forNamePrivileged(
+                        name, initialize, classLoader);
+                    javaType = getJavaTypeInternal(clazz);
                 }
                 catch (ClassNotFoundException ex) {
                     // cannot find class => return null
                 }
-                catch (LinkageError ex) {
-                    throw new ModelFatalException(msg.msg(
-                        "EXC_ClassLoadingError", name, ex.toString())); //NOI18N
-                }
             }
             return javaType;
         }
@@ -109,32 +91,15 @@
      * between this method and getJavaType taking a type name is that this 
      * method is supposed to return a non-<code>null<code> value. The
      * specified class object describes an existing type.
-     * <p>
-     * Note, this implementation does not call the overloaded getJavaType
-     * method taking a String, because this would retrieve the Class
-     * instance for the specified type again. Instead, it checks the cache 
-     * directly. If not available it creates a new ReflectionJavaType using
-     * the specified class instance.
      * @param clazz the Class instance representing the type
      * @return a JavaType instance for the name of the specified class
-     * object or <code>null</code> if not present in this model instance.
+     * object.
      */
     public JavaType getJavaType(Class clazz)
     {
         if (clazz == null)
             return null;
         
-        if (initialize) {
-            try {
-                // make sure the class is initialized
-                Class.forName(clazz.getName(), initialize, 
-                    ReflectionJavaModelFactory.getClassLoaderPrivileged(clazz));
-            }
-            catch (ClassNotFoundException ex) {
-                // ignore, since class has already been loaded 
-            }
-        }
-
         return getJavaTypeInternal(clazz);
     }
 
@@ -159,7 +124,9 @@
         return (InputStream) AccessController.doPrivileged(
             new PrivilegedAction () {
                 public Object run () {
-                    return classLoader.getResourceAsStream(resourceName);
+                    ClassLoader loader = (classLoader == null) ?
+                        ClassLoader.getSystemClassLoader() : classLoader;
+                    return loader.getResourceAsStream(resourceName);
                 }
             }
             );
@@ -185,7 +152,7 @@
      * @return a JavaType instance for the name of the specified class
      * object or <code>null</code> if not present in this model instance.
      */
-    protected JavaType getJavaTypeInternal(Class clazz)
+    public JavaType getJavaTypeInternal(Class clazz)
     {
         String name = clazz.getName();
         synchronized (types) {
@@ -196,6 +163,16 @@
             }
             return javaType;
         }
+    }
+
+    /**
+     * Returns the declaring ReflectionJavaModelFactory of this
+     * ReflectionJavaModel.
+     * @return the declaring ReflectionJavaModelFactory
+     */
+    public ReflectionJavaModelFactory getDeclaringJavaModelFactory()
+    {
+        return declaringJavaModelFactory;
     }
 
     /** 

Modified: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModelFactory.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModelFactory.java?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModelFactory.java (original)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/reflection/ReflectionJavaModelFactory.java Thu Oct 27 14:27:16 2005
@@ -18,19 +18,17 @@
 
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 
-import org.apache.jdo.model.ModelException;
 import org.apache.jdo.model.ModelFatalException;
-import org.apache.jdo.model.java.JavaModel;
-import org.apache.jdo.model.java.JavaType;
 import org.apache.jdo.impl.model.java.AbstractJavaModelFactory;
-import org.apache.jdo.impl.model.java.BaseReflectionJavaType;
 import org.apache.jdo.util.I18NHelper;
 
 /**
  * A reflection based JavaModelFactory implementation. 
  * 
- * @since JDO 1.1
+ * @since 1.1
  */
 public abstract class ReflectionJavaModelFactory
     extends AbstractJavaModelFactory
@@ -42,10 +40,11 @@
     // ===== Methods not defined in JavaModelFactory =====
 
     /**
-     * Calls getClassLoader on the specified class instance in a
+     * Calls getClassLoader on the specified Class instance in a
      * doPrivileged block. Any SecurityException is wrapped into a
      * ModelFatalException. 
-     * @return the class loader that loaded the specified class instance.
+     * @param clazz the class to get the ClassLoader from.
+     * @return the class loader that loaded the specified Class instance.
      * @exception ModelFatalException wraps the SecurityException thrown by
      * getClassLoader.
      */
@@ -66,6 +65,41 @@
         catch (SecurityException ex) {
             throw new ModelFatalException(
                 msg.msg("EXC_CannotGetClassLoader", clazz), ex); //NOI18N
+        }
+    }
+
+    /**
+     * Calls Class.forName in a doPrivileged block. Any SecurityException is
+     * wrapped into a ModelFatalException.
+     * @param name fully qualified name of the desired class
+     * @param initialize whether the class must be initialized
+     * @param loader class loader from which the class must be loaded
+     * @return class object representing the desired class.
+     * @exception ModelFatalException wraps the SecurityException thrown by
+     * getClassLoader.
+     * @exception ClassNotFoundException if the class cannot be located by the
+     * specified class loader.
+     */
+    public static Class forNamePrivileged(final String name, 
+                                          final boolean initialize, 
+                                          final ClassLoader loader)
+        throws ClassNotFoundException
+    {
+        try { 
+            return (Class) AccessController.doPrivileged(
+                new PrivilegedExceptionAction () {
+                    public Object run () throws ClassNotFoundException {
+                        return Class.forName(name, initialize, loader);
+                    }
+                }
+                );
+        }
+        catch (PrivilegedActionException pae) {
+            throw (ClassNotFoundException) pae.getException();
+        }
+        catch (SecurityException ex) {
+            throw new ModelFatalException(
+                msg.msg("CannotGetClassInstance", name, loader), ex);
         }
     }
 

Modified: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/runtime/Bundle.properties
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/runtime/Bundle.properties?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/runtime/Bundle.properties (original)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/runtime/Bundle.properties Thu Oct 27 14:27:16 2005
@@ -43,3 +43,18 @@
 #NOI18N
 ERR_CannotSetJDOModel=Cannot set JDOModel for JavaModel instance.
 
+#
+# RuntimeJavaModel
+#
+
+# {0} - class name
+# {1} - detailed message of the cause
+EXC_ClassLoadingError=Error during loading of class ''{0}'': {1}.
+
+# {0} - class name
+# {1} - class loader of class instance
+# {2} - class loader of JavaModel
+#NOI18N
+ERR_UnexpectedClassLoader=Unexpected class loader. The specified class \
+instance of class ''{0}'' was loaded by class loader ''{1}'', but the \
+JavaModel instance is bound to a different class loader ''{2}''.

Modified: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModel.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModel.java?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModel.java (original)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModel.java Thu Oct 27 14:27:16 2005
@@ -16,11 +16,9 @@
 
 package org.apache.jdo.impl.model.java.runtime;
 
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.io.InputStream;
-
+import org.apache.jdo.impl.model.java.PredefinedType; // for javadoc
 import org.apache.jdo.impl.model.java.reflection.ReflectionJavaModel;
+import org.apache.jdo.impl.model.java.reflection.ReflectionJavaModelFactory;
 import org.apache.jdo.model.ModelFatalException;
 import org.apache.jdo.model.java.JavaType;
 import org.apache.jdo.model.jdo.JDOModel;
@@ -35,23 +33,130 @@
  * The RuntimeJavaModelFactory caches JavaModel instances per ClassLoader.
  * The RuntimeJavaModel implementation will use this ClassLoader to lookup
  * any type by name. This makes sure that the type name is unique.
+ * <p>
+ * Any JavaType instance bound to a RuntimeJavaModel instance wraps a class
+ * instance that is loaded by the ClassLoader that corresponds to this
+ * RuntimeJavaModel. The only exception are PredefinedType instances 
+ * (see {@link PredefinedType.getPredefinedTypes()} which are present in every
+ * RuntimeJavaModel instance.
  *
- * @author Michael Bouschen
- * @since JDO 1.0.1
+ * @since 1.0.1
+ * @version 1.1
  */
 public class RuntimeJavaModel
     extends ReflectionJavaModel
 {
-    /** Constructor taking the ClassLoader. */
-    public RuntimeJavaModel(ClassLoader classLoader) 
+    /** I18N support */
+    private final static I18NHelper msg =  
+        I18NHelper.getInstance("org.apache.jdo.impl.model.java.runtime.Bundle"); //NOI18N
+
+    /** Constructor. */
+    public RuntimeJavaModel(ClassLoader classLoader, 
+                            ReflectionJavaModelFactory declaringJavaModelFactory) 
     {
-        super(classLoader, true);
+        super(classLoader, declaringJavaModelFactory);
     }
     
-    /** */
-    protected RuntimeJavaModel(ClassLoader classLoader, boolean initialize)
+    /** 
+     * The method returns the JavaType instance for the specified type
+     * name. A type name is unique within one JavaModel instance. The
+     * method returns <code>null</code> if this model instance does not
+     * know a type with the specified name.
+     * <p>
+     * Note, this method calls Class.forName with the wrapped ClassLoader,
+     * if it cannot find a JavaType with the specified name in the cache.
+     * @param name the name of the type
+     * @return a JavaType instance for the specified name or
+     * <code>null</code> if not present in this model instance.
+     */
+    public JavaType getJavaType(String name) 
+    {
+        synchronized (types) {
+            JavaType javaType = (JavaType)types.get(name);
+            if (javaType == null) {
+                try {
+                    // Note, if name denotes a pc class that has not been
+                    // loaded, Class.forName will load the class which will
+                    // register the runtime metadata at the JDOImplHelper.
+                    // This will create a new JavaType entry in the cache.
+                    final boolean initialize = true;
+                    Class clazz = RuntimeJavaModelFactory.forNamePrivileged(
+                        name, initialize, getClassLoader());
+                    // Get the class loader of the Class instance
+                    ClassLoader loader = RuntimeJavaModelFactory.
+                        getClassLoaderPrivileged(clazz);
+                    // and get the JavaModel instance for the class loader. 
+                    RuntimeJavaModel javaModel = (RuntimeJavaModel)
+                        declaringJavaModelFactory.getJavaModel(loader);
+                    // Delegate the JavaType lookup to the JavaModel instance.
+                    javaType = javaModel.getJavaTypeInternal(clazz);
+                }
+                catch (ClassNotFoundException ex) {
+                    // cannot find class => return null
+                }
+                catch (LinkageError ex) {
+                    throw new ModelFatalException(msg.msg(
+                        "EXC_ClassLoadingError", name, ex.toString())); //NOI18N
+                }
+            }
+            return javaType;
+        }
+    }
+
+    /** 
+     * The method returns the JavaType instance for the type name of the
+     * specified class object. This is a convenience method for 
+     * <code>getJavaType(clazz.getName())</code>. The major difference
+     * between this method and getJavaType taking a type name is that this 
+     * method is supposed to return a non-<code>null<code> value. The
+     * specified class object describes an existing type.
+     * <p>
+     * Note, this implementation does not call the overloaded getJavaType
+     * method taking a String, because this would retrieve the Class
+     * instance for the specified type again. Instead, it checks the cache 
+     * directly. If not available it creates a new ReflectionJavaType using
+     * the specified Class instance.
+     * @param clazz the Class instance representing the type
+     * @return a JavaType instance for the name of the specified class
+     * object or <code>null</code> if not present in this model instance.
+     */
+    public JavaType getJavaType(Class clazz)
     {
-        super(classLoader, initialize);
+        if (clazz == null)
+            return null;
+        
+        String name = clazz.getName();
+        synchronized (types) {
+            JavaType javaType = (JavaType)types.get(name);
+            if (javaType == null) {
+                // Check whether the specified class object is loaded by the
+                // class loader bound to this JavaModel. Note, we never
+                // execute this check for any PredefinedType instance, because
+                // the cache lookup will always find a JavaType (the cache is
+                // initialized with all PredefinedTypes). The check would
+                // potentially fail for a PredefinedType, because it might be
+                // loaded by a different class loader.
+                ClassLoader loader = 
+                    RuntimeJavaModelFactory.getClassLoaderPrivileged(clazz);
+                if (loader != getClassLoader()) {
+                    throw new ModelFatalException(msg.msg(
+                        "ERR_UnexpectedClassLoader", //NOI18N
+                        clazz.getName(), loader, getClassLoader()));
+                }
+                try {
+                    // Make sure the class is initialized, because this will
+                    // register the runtime metadata at the JDOImplHelper. 
+                    final boolean initialize = true;
+                    RuntimeJavaModelFactory.forNamePrivileged(
+                        clazz.getName(), initialize, loader);
+                }
+                catch (ClassNotFoundException ex) {
+                    // ignore, since class has already been loaded 
+                }
+                javaType = getJavaTypeInternal(clazz);
+            }
+            return javaType;
+        }
     }
 
     /** 

Modified: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModelFactory.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModelFactory.java?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModelFactory.java (original)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModelFactory.java Thu Oct 27 14:27:16 2005
@@ -18,7 +18,6 @@
 
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.lang.reflect.Field;
 
 import javax.jdo.spi.JDOImplHelper;
 import javax.jdo.spi.JDOPermission;
@@ -48,8 +47,8 @@
  * JDOImplHelper to handle the runtime metadata as generated by the
  * enhancer. 
  * 
- * @author Michael Bouschen
- * @since JDO 1.0.1
+ * @since 1.0.1
+ * @version 1.1
  */
 public class RuntimeJavaModelFactory
     extends ReflectionJavaModelFactory
@@ -60,7 +59,7 @@
 
     /** I18N support */
     private final static I18NHelper msg =  
-        I18NHelper.getInstance("org.apache.jdo.impl.model.java.runtime.Bundle"); //NOI18N
+        I18NHelper.getInstance(RuntimeJavaModelFactory.class);
 
     /** */
     static
@@ -127,8 +126,7 @@
      * use the specified key when caching the new JavaModel instance. 
      * <p>
      * This implementation only accepts <code>java.lang.ClassLoader</code>
-     * instances as key and does not support <code>null</code> keys. A
-     * ModelException indicates an invalid key.
+     * instances as key. A ModelException indicates an invalid key.
      * <p>
      * The method automatically sets the parent/child relationship for the
      * created JavaModel according to the parent/child relationship of the 
@@ -137,28 +135,23 @@
      * instance. 
      * @return a new JavaModel instance.
      * @exception ModelException if impossible; the key is of an
-     * inappropriate type or the key is <code>null</code> and this
-     * JavaModelFactory does not support <code>null</code> keys.
+     * inappropriate type.
      */
     public JavaModel createJavaModel(Object key)
         throws ModelException
     {
-        if ((key == null) || (!(key instanceof ClassLoader)))
+        if ((key != null) && (!(key instanceof ClassLoader)))
             throw new ModelException(msg.msg("EXC_InvalidJavaModelKey", //NOI18N
-                (key==null?"null":key.getClass().getName())));
+                key.getClass().getName()));
         
         ClassLoader classLoader = (ClassLoader)key;
-        JavaModel javaModel = new RuntimeJavaModel(classLoader);
+        JavaModel javaModel = new RuntimeJavaModel(classLoader, this);
 
         // check parent <-> child relationship
-        if (classLoader != ClassLoader.getSystemClassLoader()) {
-            // if the specified classLoader is not the system class loader
-            // try to get the parent class loader and update the parent property
+        if (classLoader != null) {
             try {
                 ClassLoader parentClassLoader = classLoader.getParent();
-                if (parentClassLoader != null) {
-                    javaModel.setParent(getJavaModel(parentClassLoader));
-                }
+                javaModel.setParent(getJavaModel(parentClassLoader));
             }
             catch (SecurityException ex) {
                 // ignore => parentClassLoader and parent JavaModel are null
@@ -171,20 +164,6 @@
         return javaModel;
     }
 
-    /**
-     * Returns the JavaModel instance for the specified key.
-     * @param key the key used to cache the returned JavaModel instance
-     */
-    public JavaModel getJavaModel(Object key)
-    {
-        if (key == null) {
-            // null classLoader might happen for classes loaded by the
-            // bootstrap class loder
-            key = ClassLoader.getSystemClassLoader();
-        }
-        return super.getJavaModel(key);
-    }
-    
     /**
      * Returns a JavaType instance for the specified type description
      * (optional operation). This method is a convenience method and a

Modified: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/xml/XMLExists.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/xml/XMLExists.java?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/xml/XMLExists.java (original)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/xml/XMLExists.java Thu Oct 27 14:27:16 2005
@@ -18,7 +18,7 @@
 
 import java.util.*;
 
-import org.apache.jdo.impl.model.java.AbstractJavaModelFactory;
+import org.apache.jdo.impl.model.java.reflection.ReflectionJavaModelFactory;
 import org.apache.jdo.impl.model.java.runtime.RuntimeJavaModel;
 import org.apache.jdo.impl.model.jdo.caching.JDOModelFactoryImplCaching;
 import org.apache.jdo.impl.model.jdo.util.PrintSupport;
@@ -268,18 +268,18 @@
      * generated metadata.
      */
     private static class XMLExistsJDOModelFactory 
-        extends AbstractJavaModelFactory {
+        extends ReflectionJavaModelFactory {
 
         /** */
         protected XMLExistsJDOModelFactory() {}
 
         /** */
         public JavaModel createJavaModel(Object key) throws ModelException {
-            if ((key == null) || (!(key instanceof ClassLoader)))
+            if ((key != null) && (!(key instanceof ClassLoader)))
                 throw new ModelException("Invalid key " + key + 
                                          " expected ClassLoader");
             ClassLoader classLoader = (ClassLoader)key;
-            JavaModel javaModel = new RuntimeJavaModel(classLoader); 
+            JavaModel javaModel = new RuntimeJavaModel(classLoader, this);
 
             // set the JDOModel property in JavaModel
             setJDOModelInternal(javaModel);

Modified: incubator/jdo/trunk/runtime20/src/java/org/apache/jdo/impl/model/java/runtime/Bundle.properties
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/runtime20/src/java/org/apache/jdo/impl/model/java/runtime/Bundle.properties?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/runtime20/src/java/org/apache/jdo/impl/model/java/runtime/Bundle.properties (original)
+++ incubator/jdo/trunk/runtime20/src/java/org/apache/jdo/impl/model/java/runtime/Bundle.properties Thu Oct 27 14:27:16 2005
@@ -28,6 +28,22 @@
 codeBases containing the JDO API and the JavaModel and JDOModel implementation.
 
 #
+# RuntimeJavaModel
+#
+
+# {0} - class name
+# {1} - detailed message of the cause
+EXC_ClassLoadingError=Error during loading of class ''{0}'': {1}.
+
+# {0} - class name
+# {1} - class loader of class instance
+# {2} - class loader of JavaModel
+#NOI18N
+ERR_UnexpectedClassLoader=Unexpected class loader. The specified class \
+instance of class ''{0}'' was loaded by class loader ''{1}'', but the \
+JavaModel instance is bound to a different class loader ''{2}''.
+
+#
 # RuntimeJavaType
 #
 
@@ -36,3 +52,8 @@
 # {2} - field name
 #NOI18N
 ERR_MultipleJavaField={0}: multiple JavaField ''{1}'' for class ''{2}''.
+
+# {0} - class name
+# {1} - detailed message of the cause
+EXC_ClassLoadingError=Error during loading of class ''{0}'': {1}.
+

Modified: incubator/jdo/trunk/runtime20/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModel.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/runtime20/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModel.java?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/runtime20/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModel.java (original)
+++ incubator/jdo/trunk/runtime20/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModel.java Thu Oct 27 14:27:16 2005
@@ -16,8 +16,11 @@
 
 package org.apache.jdo.impl.model.java.runtime;
 
+import org.apache.jdo.impl.model.java.PredefinedType; // for javadoc
 import org.apache.jdo.impl.model.java.reflection.ReflectionJavaModel;
+import org.apache.jdo.model.ModelFatalException;
 import org.apache.jdo.model.java.JavaType;
+import org.apache.jdo.util.I18NHelper;
 
 /**
  * A reflection based JavaModel implementation used at runtime.  
@@ -28,21 +31,132 @@
  * The RuntimeJavaModelFactory caches JavaModel instances per ClassLoader.
  * The RuntimeJavaModel implementation will use this ClassLoader to lookup
  * any type by name. This makes sure that the type name is unique.
+ * <p>
+ * Any JavaType instance bound to a RuntimeJavaModel instance wraps a class
+ * instance that is loaded by the ClassLoader that corresponds to this
+ * RuntimeJavaModel. The only exception are PredefinedType instances 
+ * (see {@link PredefinedType.getPredefinedTypes()} which are present in every
+ * RuntimeJavaModel instance.
  *
- * @author Michael Bouschen
- * @since JDO 1.0.1
- * @version JDO 2.0
+ * @since 1.0.1
+ * @version 2.0
  */
 public class RuntimeJavaModel
     extends ReflectionJavaModel
 {
+    /** I18N support */
+    private final static I18NHelper msg =  
+        I18NHelper.getInstance("org.apache.jdo.impl.model.java.runtime.Bundle"); //NOI18N
+
     /** Constructor. */
     public RuntimeJavaModel(ClassLoader classLoader, 
                             RuntimeJavaModelFactory declaringJavaModelFactory) 
     {
         super(classLoader, declaringJavaModelFactory);
     }
-    
+
+    /** 
+     * The method returns the JavaType instance for the specified type
+     * name. A type name is unique within one JavaModel instance. The
+     * method returns <code>null</code> if this model instance does not
+     * know a type with the specified name.
+     * <p>
+     * Note, this method calls Class.forName with the wrapped ClassLoader,
+     * if it cannot find a JavaType with the specified name in the cache.
+     * @param name the name of the type
+     * @return a JavaType instance for the specified name or
+     * <code>null</code> if not present in this model instance.
+     */
+    public JavaType getJavaType(String name) 
+    {
+        synchronized (types) {
+            JavaType javaType = (JavaType)types.get(name);
+            if (javaType == null) {
+                try {
+                    // Note, if name denotes a pc class that has not been
+                    // loaded, Class.forName will load the class which will
+                    // register the runtime metadata at the JDOImplHelper.
+                    // This will create a new JavaType entry in the cache.
+                    final boolean initialize = true; 
+                    Class clazz = RuntimeJavaModelFactory.forNamePrivileged(
+                        name, initialize, getClassLoader());
+                    // Get the class loader of the Class instance
+                    ClassLoader loader = RuntimeJavaModelFactory.
+                        getClassLoaderPrivileged(clazz);
+                    // and get the JavaModel instance for the class loader. 
+                    RuntimeJavaModel javaModel = (RuntimeJavaModel)
+                        declaringJavaModelFactory.getJavaModel(loader);
+                    // Delegate the JavaType lookup to the JavaModel instance.
+                    javaType = javaModel.getJavaTypeInternal(clazz);
+                }
+                catch (ClassNotFoundException ex) {
+                    // cannot find class => return null
+                }
+                catch (LinkageError ex) {
+                    throw new ModelFatalException(msg.msg(
+                        "EXC_ClassLoadingError", name, ex.toString())); //NOI18N
+                }
+            }
+            return javaType;
+        }
+    }
+
+    /** 
+     * The method returns the JavaType instance for the type name of the
+     * specified class object. This is a convenience method for 
+     * <code>getJavaType(clazz.getName())</code>. The major difference
+     * between this method and getJavaType taking a type name is that this 
+     * method is supposed to return a non-<code>null<code> value. The
+     * specified class object describes an existing type.
+     * <p>
+     * Note, this implementation does not call the overloaded getJavaType
+     * method taking a String, because this would retrieve the Class
+     * instance for the specified type again. Instead, it checks the cache 
+     * directly. If not available it creates a new ReflectionJavaType using
+     * the specified Class instance.
+     * @param clazz the Class instance representing the type
+     * @return a JavaType instance for the name of the specified class
+     * object or <code>null</code> if not present in this model instance.
+     */
+    public JavaType getJavaType(Class clazz)
+    {
+        if (clazz == null)
+            return null;
+        
+        String name = clazz.getName();
+        synchronized (types) {
+            JavaType javaType = (JavaType)types.get(name);
+            if (javaType == null) {
+                // Check whether the specified class object is loaded by the
+                // class loader bound to this JavaModel. Note, we never
+                // execute this check for any PredefinedType instance, because
+                // the cache lookup will always find a JavaType (the cache is
+                // initialized with all PredefinedTypes). The check would
+                // potentially fail for a PredefinedType, because it might be
+                // loaded by a different class loader.
+                ClassLoader loader = 
+                    RuntimeJavaModelFactory.getClassLoaderPrivileged(clazz);
+                if (loader != getClassLoader()) {
+                    throw new ModelFatalException(msg.msg(
+                        "ERR_UnexpectedClassLoader", //NOI18N
+                        clazz.getName(), loader, getClassLoader()));
+                }
+                try {
+                    // Make sure the class is initialized, because this will
+                    // register the runtime metadata at the JDOImplHelper. 
+                    final boolean initialize = true; 
+                    RuntimeJavaModelFactory.forNamePrivileged(
+                        clazz.getName(), initialize, loader);
+                }
+                catch (ClassNotFoundException ex) {
+                    // ignore, since class has already been loaded 
+                }
+                javaType = getJavaTypeInternal(clazz);
+            }
+            return javaType;
+        }
+    }
+
     /** 
      * Creates a new instance of the JavaType implementation class.
      * <p>

Modified: incubator/jdo/trunk/runtime20/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModelFactory.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/runtime20/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModelFactory.java?rev=328951&r1=328950&r2=328951&view=diff
==============================================================================
--- incubator/jdo/trunk/runtime20/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModelFactory.java (original)
+++ incubator/jdo/trunk/runtime20/src/java/org/apache/jdo/impl/model/java/runtime/RuntimeJavaModelFactory.java Thu Oct 27 14:27:16 2005
@@ -41,9 +41,8 @@
  * JDOImplHelper to handle the runtime metadata as generated by the
  * enhancer. 
  * 
- * @author Michael Bouschen
- * @since JDO 1.0.1
- * @version JDO 2.0
+ * @since 1.0.1
+ * @version 2.0
  */
 public class RuntimeJavaModelFactory
     extends ReflectionJavaModelFactory