You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by sc...@apache.org on 2016/03/29 23:48:07 UTC

svn commit: r1737066 - /uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java

Author: schor
Date: Tue Mar 29 21:48:07 2016
New Revision: 1737066

URL: http://svn.apache.org/viewvc?rev=1737066&view=rev
Log:
[UIMA-4666] rework JCasClassInfo to eliminate unused constructor arg, add a new field.  Add synchronization to avoid issues with parallel loading. Fix bug in conformance testing.  Report, but don't throw if someone overrides a JCas getter with an identically named method that returns a type different from the UIMA type - for backward compatibility.

Modified:
    uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java?rev=1737066&r1=1737065&r2=1737066&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java Tue Mar 29 21:48:07 2016
@@ -169,17 +169,17 @@ public class FSClassRegistry {
      */
     final Class<?> jcasClass;
     
+    final int jcasType;
+    
 //    /**
 //     * map from the feature short name to the getter/setter Lambda
 //     */
 //    final Map<String, GetterSetter> gettersAndSetters = new HashMap<>(1);
     
-    JCasClassInfo(String typeName, Class<?> jcasClass, Object generator) {
+    JCasClassInfo(Class<?> jcasClass, Object generator, int jcasType) {
       this.generator = generator;
       this.jcasClass = jcasClass;
-      
-      // add to map
-      type2JCas.put(typeName, this);
+      this.jcasType = jcasType;
     }
   }
 
@@ -195,6 +195,7 @@ public class FSClassRegistry {
    * These instances are shared for all type systems
    */
   private static final JCasClassInfo[] jcasClassesInfoForBuiltins;
+
   static {
     TypeSystemImpl tsi = TypeSystemImpl.staticTsi;
     jcasClassesInfoForBuiltins = new JCasClassInfo[tsi.getTypeArraySize()]; 
@@ -213,7 +214,8 @@ public class FSClassRegistry {
       Class<?> builtinClass = maybeLoadJCas(typeName);
       assert (builtinClass != null);  // builtin types must be present
       // copy down to subtypes, if needed, done later
-      JCasClassInfo jcasClassInfo = createJCasClassInfo(builtinClass, ti); 
+      int jcasType = Misc.getStaticIntFieldNoInherit(builtinClass, "typeIndexID");
+      JCasClassInfo jcasClassInfo = createJCasClassInfo(builtinClass, ti, jcasType); 
       jcasClassesInfoForBuiltins[ti.getCode()] = jcasClassInfo; 
 //      setupGetterSetter(ti, jcasClassInfo);
     }
@@ -234,6 +236,11 @@ public class FSClassRegistry {
    * Also, for all loaded JCas classes, set the javaClass field (including
    *   in subtypes with no JCas class defined).
    *   
+   * Called under TypeSystemImpl - instance - lock 
+   * 
+   * Could be running multiple threads
+   *   - one per TypeSystemImpl - instance
+   *   
    * @param ts - the type system
    * @param isDoUserJCasLoading a flag to skip loading the JCas classes
    */
@@ -320,27 +327,57 @@ public class FSClassRegistry {
    * @param copyDownDefault_jcasClassInfo
    */
   private void maybeLoadJCasAndSubtypes(TypeSystemImpl ts, TypeImpl ti, JCasClassInfo copyDownDefault_jcasClassInfo) {
-    JCasClassInfo jcasClassInfo = type2JCas.get(ti.getName());
-    if (jcasClassInfo == null) {
-      // not yet loaded.  if Built-in, always skip this body
-      jcasClassInfo = copyDownDefault_jcasClassInfo;  // initialize in case no JCas for this type
     
-    
-      Class<?> clazz;
-  
-      TypeSystemImpl.typeBeingLoadedThreadLocal.set(ti);    
-      clazz = maybeLoadJCas(ti.getName());  
+    JCasClassInfo jcasClassInfo;
+//    boolean debug = "com.ibm.hutt.Predicate".equals(ti.getName());
+//    if (debug) {
+//      System.out.println("Loading com.ibm.hutt.Predicate");
+//    }
+    synchronized(type2JCas) {
+      jcasClassInfo = type2JCas.get(ti.getName());
+//      if (debug) {
+//        System.out.println("Loading com.ibm.hutt.Predicate: jcasClassInfo fetch was " + ((jcasClassInfo == null) ? "null" : "not null"));
+//      }
+      if (jcasClassInfo == null) {
+        // not yet loaded.  if Built-in, always skip this body
+        jcasClassInfo = copyDownDefault_jcasClassInfo;  // initialize in case no JCas for this type
+      
       
-      if (null != clazz && TOP.class.isAssignableFrom(clazz)) {
-        jcasClassInfo = createJCasClassInfo(clazz, ti); 
-        if (!Modifier.isAbstract(clazz.getModifiers())) { // skip next for abstract classes
-          int i = Misc.getStaticIntFieldNoInherit(clazz, "typeIndexID");
-          // if i is negative, this means there's no value for this field
-          assert(i >= 0);
-          ts.setJCasRegisteredType(i, ti);
+        Class<?> clazz;
+    
+        TypeSystemImpl.typeBeingLoadedThreadLocal.set(ti);    
+        clazz = maybeLoadJCas(ti.getName());  
+//        if (debug) {
+//          System.out.println("Loading com.ibm.hutt.Predicate: returned class from loading was " + ((clazz == null) ? "null" : "not null"));
+//          if (null != clazz) {
+//            System.out.println("Loading com.ibm.hutt.Predicate: TOP was " + ((TOP.class.isAssignableFrom(clazz)) ? "assignable" : "not assignable") + " from Predicate");
+//          }
+//        }
+        if (null != clazz && TOP.class.isAssignableFrom(clazz)) {
+          
+          int jcasType = -1;
+          if (!Modifier.isAbstract(clazz.getModifiers())) { // skip next for abstract classes
+            jcasType = Misc.getStaticIntFieldNoInherit(clazz, "typeIndexID");
+            // if jcasType is negative, this means there's no value for this field
+            assert(jcasType >= 0);
+            ts.setJCasRegisteredType(jcasType, ti);
+          } else {
+//            if (debug) {
+//              System.out.println("Loading com.ibm.hutt.Predicate: SKIPPED setting register because class was Abstract!");
+//            }
+          }
+          
+          jcasClassInfo = createJCasClassInfo(clazz, ti, jcasType); 
+          type2JCas.put(ti.getName(), jcasClassInfo);
+
+        } 
+      } else {  // jcasClassInfo already set
+        // already have info for this class, but need to set the jcas registry for this type system
+        if (jcasClassInfo.jcasType >= 0) {
+          ts.setJCasRegisteredType(jcasClassInfo.jcasType, ti);
         }
-      } 
-    }
+      }
+    } // end of synch on type2JCas
     
     // this check is done even after the class is first loaded, in case the type system changed.
     //   -- if the new type system is equal to a previous one, then no new FSClassRegistry is created.
@@ -356,7 +393,7 @@ public class FSClassRegistry {
       maybeLoadJCasAndSubtypes(ts, subtype, jcasClassInfo);
     }
   }
-  
+    
 //  private static void setupGettersSetters(TypeSystemImpl ts, TypeImpl ti, JCasClassInfo[] jci) {
 //    boolean isBuiltin = BuiltinTypeKinds.creatableBuiltinJCas.contains(ti.getName());
 //
@@ -396,6 +433,8 @@ public class FSClassRegistry {
    * Called at TypeSystemCommit for non-built-in types
    *   Runs the static initializers in the loaded JCas classes - doing resolve
    *   
+   * Synchronization: each unique name
+   *   
    * @param typeName -
    * @param cl the class loader to use
    * @return the loaded / resolved class
@@ -403,8 +442,12 @@ public class FSClassRegistry {
   private static Class<?> maybeLoadJCas(String typeName) {
     Class<?> clazz = null;
     String className = Misc.typeName2ClassName(typeName);
+    
     try {
-      clazz = Class.forName(className, true, FSClassRegistry.class.getClassLoader());
+//      synchronized (className) { // to insure clazz receives a fully-resolved class, must use interned name
+        // parallel class loaders already sync on the name
+        clazz = Class.forName(className, true, FSClassRegistry.class.getClassLoader());
+//      }
     } catch (ClassNotFoundException e) {
       // This is normal, if there is no JCas for this class
     }
@@ -560,11 +603,11 @@ public class FSClassRegistry {
    * @param ti the type
    * @return the info for this JCas that is shared across all type systems under this class loader
    */
-  private static JCasClassInfo createJCasClassInfo(Class<?> jcasClass, TypeImpl ti) {
+  private static JCasClassInfo createJCasClassInfo(Class<?> jcasClass, TypeImpl ti, int jcasType) {
     boolean noGenerator = ti.getCode() == TypeSystemImpl.sofaTypeCode ||
                           Modifier.isAbstract(jcasClass.getModifiers()); 
     Object generator = noGenerator ? null : createGenerator(jcasClass, ti.isArray());
-    JCasClassInfo jcasClassInfo = new JCasClassInfo(ti.getName(), jcasClass, generator);
+    JCasClassInfo jcasClassInfo = new JCasClassInfo(jcasClass, generator, jcasType);
     return jcasClassInfo;
   }
   
@@ -647,6 +690,7 @@ public class FSClassRegistry {
       FeatureImpl fi = ti.getFeatureByBaseName(fname);
       if (fi == null) {
         fname = mname.charAt(3) + suffix;
+        fi = ti.getFeatureByBaseName(fname);
         if (fi == null) continue;
       }
       
@@ -660,12 +704,12 @@ public class FSClassRegistry {
           rangeClass = range.getComponentType().getJavaClass();
         }
       }
-      if (!returnClass.isAssignableFrom(rangeClass)) {
+      if (!rangeClass.isAssignableFrom(returnClass)) {  // can return subclass of TOP, OK if range is TOP
         /** CAS type system type "{0}" defines field "{1}" with range "{2}", but JCas class has range "{3}". */
         add2errors(errorSet, 
                    new CASRuntimeException(CASRuntimeException.JCAS_TYPE_RANGE_MISMATCH, 
                        ti.getName(), fi.getShortName(), rangeClass, returnClass),
-                   true);  // throw  
+                   false);  // should throw, but some code breaks!  
       }
     }