Author: schor
Date: Tue Jan 23 21:02:30 2018
New Revision: 1822059

URL: http://svn.apache.org/viewvc?rev=1822059&view=rev
Log:
[UIMA-5698] support JCas imputed features, fix test case

Modified:
    
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java
    
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl.java
    
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java
    
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties
    
uima/uv3/uimaj-v3/trunk/uimaj-core/src/test/java/org/apache/uima/cas/impl/JCasReinitTest.java

Modified: 
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java?rev=1822059&r1=1822058&r2=1822059&view=diff
==============================================================================
--- 
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java
 (original)
+++ 
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java
 Tue Jan 23 21:02:30 2018
@@ -34,13 +34,11 @@ import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Parameter;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 
 import org.apache.uima.UIMAFramework;
 import org.apache.uima.UIMARuntimeException;
@@ -111,7 +109,9 @@ import org.apache.uima.util.Logger;
  */
 
 public abstract class FSClassRegistry { // abstract to prevent instantiating; 
this class only has static methods
-  
+
+//  private static final boolean IS_TRACE_AUGMENT_TS = false;
+//  private static final boolean IS_TIME_AUGMENT_FEATURES = false;
   /* ========================================================= */
   /*    This class has only static methods and fields          */
   /*    To allow multi-threaded use, some fields are           */
@@ -242,6 +242,10 @@ public abstract class FSClassRegistry {
     boolean isPearOverride(ClassLoader cl) {
       return jcasClass.getClassLoader().equals(cl);
     }
+    
+    TypeImpl getUimaType(TypeSystemImpl tsi) {
+      return tsi.getType(Misc.javaClassName2UimaTypeName(jcasClass.getName()));
+    }
   }
   
   /**
@@ -249,7 +253,7 @@ public abstract class FSClassRegistry {
    * Used to expand the type system when the JCas defines more features
    * than the type system declares.
    */
-  private static class JCasClassFeatureInfo {
+  static class JCasClassFeatureInfo {
     final String shortName;
     // rangename is byte.class, etc
     // or x.y.z.JCasClassName
@@ -259,6 +263,17 @@ public abstract class FSClassRegistry {
       this.shortName = shortName;
       this.uimaRangeName = uimaRangeName;
     }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+      return String.format("JCasClassFeatureInfo feature: %s, range: %s", 
(shortName == null) ? "<null>" : shortName, 
+                                                            (uimaRangeName == 
null) ? "<null>" : uimaRangeName);
+    }
+    
+    
   }
     
 
@@ -519,7 +534,7 @@ public abstract class FSClassRegistry {
       maybeLoadJCasAndSubtypes(tsi, subtype, jcci_or_copyDown, cl, type2jcci, 
callSites_toSync, lookup);
     }
   }
-
+  
   /** 
    * For a particular type name, get the JCasClassInfo
    *   - by fetching the cached value
@@ -540,21 +555,8 @@ public abstract class FSClassRegistry {
     JCasClassInfo jcci = type2jcci.get(ti.getJCasClassName());
 
     if (jcci == null) {
-      // first time encountering this typename.  Attempt to load a jcas class 
for this
-      //   - if none, the next call returns null.      
-      jcci = createJCasClassInfo(ti, cl, lookup); // does update of callsites 
if was able find JCas class
-          
-      if (null != jcci) {    
-        // not done here, needs to be done additionally with different type 
systems
-        // done as part of conformance check
-//        if (!ti.isBuiltIn) {  
-//          validateSuperClass(jcci, ti);
-//        }
-        type2jcci.put(ti.getJCasClassName(), jcci);
-        // non-creatable JCas types (e.g. FSList) do not have a valid jcasType
-      
-      }
-    } 
+      jcci = maybeCreateJCasClassInfo(ti, cl, type2jcci, lookup);
+    }
     
     // do this setup for new type systems using previously loaded jcci, as 
well as
     // for new jccis
@@ -564,6 +566,15 @@ public abstract class FSClassRegistry {
     return jcci;
   }
   
+  static JCasClassInfo maybeCreateJCasClassInfo(TypeImpl ti, ClassLoader cl, 
Map<String, JCasClassInfo> type2jcci, Lookup lookup) {
+    JCasClassInfo jcci = createJCasClassInfo(ti, cl, lookup); // does update 
of callsites if was able find JCas class
+    
+    if (null != jcci) {    
+      type2jcci.put(ti.getJCasClassName(), jcci);
+      // non-creatable JCas types (e.g. FSList) do not have a valid jcasType   
 
+    }
+    return jcci;    
+  }
   
   public static JCasClassInfo createJCasClassInfo(
       TypeImpl ti, 
@@ -587,67 +598,133 @@ public abstract class FSClassRegistry {
         return null;
       }
     }         
-//    if (ti.getTypeSystem().isCommitted()) {
-//      try { 
-//        updateOrValidateAllCallSitesForJCasClass(clazz, ti, 
callSites_toSync);
-//      } finally {
-//        TypeSystemImpl.typeBeingLoadedThreadLocal.set(null);
-//      }
-//    }
     return createJCasClassInfo(clazz, ti, jcasType, lookup);
   }
   
-  static void augmentFeaturesFromJCas(
-      TypeImpl type, 
-      ClassLoader cl, 
-      TypeSystemImpl tsi, 
-      Map<String, JCasClassInfo> type2jcci,
-      Lookup lookup) {
-    
-    if (type.isBuiltIn) {
-      return;
-    }
-    
-    
/**************************************************************************************
-     *    N O T E :                                                            
           *
-     *    fixup the ordering of staticMergedFeatures:                          
           *
-     *      - supers, then features introduced by this type.                   
           *
-     *      - order may be "bad" if later feature merge introduced an 
additional feature  *
-     
**************************************************************************************/
-    type.getFeatureImpls(); // done to reorder the features if needed, see 
above comment block
-    
-    if ( ! type.isTopType()) {
-      // skip for top level; no features there, but no super type either
-      type.getFeatureImpls(); // done for side effect of 
computingcomputeStaticMergedFeaturesList();
-      
-      TypeSystemImpl.typeBeingLoadedThreadLocal.set(type); // only for 
supporting previous version of v3 jcas
-      
-      JCasClassInfo jcci = getOrCreateJCasClassInfo(type, cl, type2jcci, 
lookup);  // no call site sync
-      if (jcci != null) {
-        for (JCasClassFeatureInfo f : jcci.features) {
-          FeatureImpl fi = type.getFeatureByBaseName(f.shortName);
-          if (fi == null) {
-            // feature is missing in the type, add it
-            // Range is either one of the uima primitives, or
-            // a fs reference.  FS References could be to "unknown" types in 
this type system.
-            // If so, use TOP
-            TypeImpl rangeType = tsi.getType(f.uimaRangeName);
-            if (rangeType == null) {
-              rangeType = tsi.topType;
-            }            
-            tsi.addFeature(f.shortName, type, rangeType);
-          }
-        }
-      }
-    }
-     
-    
-    for (TypeImpl subti : type.getDirectSubtypes()) {
-      augmentFeaturesFromJCas(subti, cl, tsi, type2jcci, lookup);
-    }
-  }
+//  static AtomicLong time = IS_TIME_AUGMENT_FEATURES ? new AtomicLong(0) : 
null;
+//  
+//  static {
+//    if (IS_TIME_AUGMENT_FEATURES) {
+//      Runtime.getRuntime().addShutdownHook(new Thread(null, () -> {
+//        System.out.format("Augment features from JCas time: %,d ms%n",
+//            time.get() / 1000000L);
+//      }, "show augment feat from jcas time"));
+//    }
+//  }
+//  
+//  static void augmentFeaturesFromJCas(
+//      TypeImpl type, 
+//      ClassLoader cl, 
+//      TypeSystemImpl tsi, 
+//      Map<String, JCasClassInfo> type2jcci,
+//      Lookup lookup) {
+//       
+//    long startTime = 0;
+//    if (type.isTopType()) {
+//      if (IS_TIME_AUGMENT_FEATURES) {
+//        startTime = System.nanoTime();
+//      }
+//    } else {
+//      
/**************************************************************************************
+//       *    N O T E :                                                        
               *
+//       *    fixup the ordering of staticMergedFeatures:                      
               *
+//       *      - supers, then features introduced by this type.               
               *
+//       *      - order may be "bad" if later feature merge introduced an 
additional feature  *
+//       
**************************************************************************************/
+//      // skip for top level; no features there, but no super type either
+//      type.getFeatureImpls(); // done for side effect of 
computingcomputeStaticMergedFeaturesList();
+//    }
+//    
+//    if (  //false &&  // debugging  
+//        ! type.isBuiltIn) {
+//
+//      if (IS_TRACE_AUGMENT_TS) System.out.println("trace Augment TS from 
JCas, for type " + type.getName());
+//
+//      
+//      TypeSystemImpl.typeBeingLoadedThreadLocal.set(type); // only for 
supporting previous version of v3 jcas
+//      
+//      JCasClassInfo jcci = getOrCreateJCasClassInfo(type, cl, type2jcci, 
lookup);  // no call site sync
+//      if (jcci != null) {
+//
+//        if (IS_TRACE_AUGMENT_TS) System.out.println("  trace Augment TS from 
JCas, adding features: " + Misc.ppList(Arrays.asList(jcci.features)));
+//        
+//        type.jcci = jcci;
+//        // also recurse for supertypes to load jcci's (in case some don't 
have uima type)
+//        //   recursion stops when have jcci already
+//        jcci = type2jcci.get(jcci.jcasClass.getSuperclass());
+//        if (null == jcci) {
+//          
+//        }
+//        
+////        for (JCasClassFeatureInfo f : jcci.features) {
+////          FeatureImpl fi = type.getFeatureByBaseName(f.shortName);
+////          if (fi == null) {
+////            
+////            /* 
*********************************************************************************
+////             * feature is missing in the type, a pseudo feature for it     
                                     *            
+////             * 
*********************************************************************************/
+////            
+////            /* Range is either one of the uima primitives, or              
                    *
+////             * a fs reference.  FS References could be to "unknown" types 
in this type system. *
+////             *   If so, use TOP                                            
                    */
+////            TypeImpl rangeType = tsi.getType(f.uimaRangeName);
+////            if (rangeType == null) {
+////              rangeType = tsi.topType;
+////            }
+////            
+////            /** Can't add feature to type "{0}" since it is feature final. 
*/
+////            if (type.isFeatureFinal()) {
+////              throw new 
CASAdminException(CASAdminException.TYPE_IS_FEATURE_FINAL, type.getName());
+////            }
+//// 
+////            if (IS_TRACE_AUGMENT_TS) System.out.println("    trace Augment 
TS from JCas, for feature: " + f.shortName );
+////           
+////            if (tsi.isInInt(rangeType)) {
+////              type.jcas_added_int_slots.add(new 
FeatureImpl_jcas_only(f.shortName, rangeType));
+////            } else {
+////              type.jcas_added_ref_slots.add(new 
FeatureImpl_jcas_only(f.shortName, rangeType));
+////            }
+////          }
+////        }
+//      }
+//    }
+//     
+//    if (IS_TRACE_AUGMENT_TS) System.out.println("trace Augment TS from JCas, 
for subtypes of type " + type.getName() + ", " + 
Misc.ppList(type.getDirectSubtypes()));
+//    for (TypeImpl subti : type.getDirectSubtypes()) {
+//      augmentFeaturesFromJCas(subti, cl, tsi, type2jcci, lookup);
+//    }
+//    
+//    if (IS_TIME_AUGMENT_FEATURES && type.isTopType()) {
+//      time.addAndGet(System.nanoTime() - startTime);
+//    }
+//  }
 
-  
+//  private void setTypeJcci(TypeImpl type, ClassLoader cl, Lookup lookup, 
Map<String, JCasClassInfo> type2jcci) {
+//    if (IS_TRACE_AUGMENT_TS) System.out.println("trace Augment TS from JCas, 
for type " + type.getName());
+//    
+//    TypeSystemImpl.typeBeingLoadedThreadLocal.set(type); // only for 
supporting previous version of v3 jcas
+//    
+//    JCasClassInfo jcci = getOrCreateJCasClassInfo(type, cl, type2jcci, 
lookup);  // no call site sync
+//    if (jcci != null) {
+//
+//      if (IS_TRACE_AUGMENT_TS) System.out.println("  trace Augment TS from 
JCas, adding features: " + Misc.ppList(Arrays.asList(jcci.features)));
+//      
+//      type.jcci = jcci;
+//      // also recurse for supertypes to load jcci's (in case some don't have 
uima type)
+//      //   recursion stops when have jcci already
+//      Class<?> superClass = jcci.jcasClass.getSuperclass();
+//      String superClassName = superClass.getName();
+//      jcci = type2jcci.get(superClassName);
+//      
+//      if (null == jcci) {
+//        TypeSystemImpl tsi = type.getTypeSystem();
+//        TypeImpl ti = 
tsi.getType(Misc.javaClassName2UimaTypeName(superClassName));
+//        
+//      
+//        setTypeJcci()
+//      }
+//    
+//  }
   
 //  private static String superTypeJCasName(TypeImpl ti) {
 //    return Misc.typeName2ClassName(ti.getSuperType().getName());
@@ -758,13 +835,15 @@ public abstract class FSClassRegistry {
     String className = ti.getJCasClassName();
     
     try { 
+      TypeSystemImpl.typeBeingLoadedThreadLocal.set(ti);  // only for 
backwards compat with alpha02 release
       clazz = (Class<? extends TOP>) Class.forName(className, true, cl);
     } catch (ClassNotFoundException e) {
       // Class not found is normal, if there is no JCas for this class
       return clazz;
-    } catch (Throwable e) {
-      e.printStackTrace(System.err);
+    } finally {
+      TypeSystemImpl.typeBeingLoadedThreadLocal.set(null);
     }
+    
     return clazz;
   }
       
@@ -1150,8 +1229,12 @@ public abstract class FSClassRegistry {
         FeatureImpl fi = ti.getFeatureByBaseName(featName);
         if (fi == null) {
           add2errors(errorSet, 
+                     /** JCAS class "{0}" defines a UIMA field "{1}" but the 
UIMA type doesn''t define that field. */
                      new 
CASRuntimeException(CASRuntimeException.JCAS_FIELD_MISSING_IN_TYPE_SYSTEM, 
clazz.getName(), featName), 
-                     false);  // don't throw on this error, field is set to -1 
and will throw if trying to use it   
+                     false);  // don't throw on this error, field is still set 
up    
+//         //debug
+//         System.out.format("debug JCAS field not in ts: type: %s, field: %s 
%n%s%n",
+//                   clazz.getName(), featName, Misc.getCallers(1, 30));
         } else {
           Field mhf = clazz.getDeclaredField("_FH_" + featName);
           mhf.setAccessible(true);
@@ -1333,6 +1416,13 @@ public abstract class FSClassRegistry {
 //          System.out.println("debug " + fieldName);
           String featureName = fieldName.substring("_FC_".length());
           final int index = TypeSystemImpl.getAdjustedFeatureOffset(type, 
featureName);
+//          //debug
+//          if (type.getShortName().equals("Split") && 
featureName.equals("splits")
+//              ) {
+//            System.out.println("debug attempting to set offset for splits in 
Splits to " + index);
+//            System.out.println(type.toString(2));
+//            System.out.println(Misc.getCallers(1, 32));
+//          }
           if (index == -1) {
             continue;  // a feature defined in the JCas class doesn't exist in 
the currently loaded type
           }             // skip setting it.  If code uses this, a runtime 
error will happen.

Modified: 
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl.java?rev=1822059&r1=1822058&r2=1822059&view=diff
==============================================================================
--- 
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl.java
 (original)
+++ 
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl.java
 Tue Jan 23 21:02:30 2018
@@ -164,7 +164,7 @@ public class TypeImpl implements Type, C
    
   // for journalling allocation: This is a 0-based offset for all features in 
feature order
   int highestOffset = -1;
-  
+    
 //  FeatureImpl featUimaUID = null;  // null or the feature named uimaUID with 
range type long
 
   private TypeImpl() {
@@ -423,7 +423,7 @@ public class TypeImpl implements Type, C
   public FeatureImpl getFeatureByBaseName(String featureShortName) {
     return staticMergedFeatures.get(featureShortName);
   }
-
+  
   /**
    * @see org.apache.uima.cas.Type#getShortName()
    */
@@ -914,31 +914,7 @@ public class TypeImpl implements Type, C
                           ? ((CommonArrayFS)fs).size()  
                           : 0);
   }  
-
-  
-  void setOffset2Feat(List<FeatureImpl> tempIntFis, 
-                      List<FeatureImpl> tempRefFis,
-                      List<FeatureImpl> tempNsr,
-                      FeatureImpl fi, 
-                      int next) {
-    if (fi.isInInt) {     
-      assert tempIntFis.size() == next;
-      tempIntFis.add(fi);
-      if (fi.getRangeImpl().isLongOrDouble) {
-        tempIntFis.add(null);  
-      }
-    } else {
-      assert tempRefFis.size() == next;
-      tempRefFis.add(fi);
-      TypeImpl range = fi.getRangeImpl();
-        
-      if (range.isRefType && 
-          range.typeCode != TypeSystemConstants.sofaTypeCode) {
-        tempNsr.add(fi);
-      }
-    }
-  }
-  
+    
   void initAdjOffset2FeatureMaps(List<FeatureImpl> tmpIntFis, 
List<FeatureImpl> tmpRefFis, List<FeatureImpl> tmpNsr) {
     tmpIntFis.addAll(Arrays.asList(superType.staticMergedIntFeaturesList));
     tmpRefFis.addAll(Arrays.asList(superType.staticMergedRefFeaturesList));

Modified: 
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java?rev=1822059&r1=1822058&r2=1822059&view=diff
==============================================================================
--- 
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java
 (original)
+++ 
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java
 Tue Jan 23 21:02:30 2018
@@ -123,6 +123,8 @@ import org.apache.uima.util.impl.Constan
  */
 public class TypeSystemImpl implements TypeSystem, TypeSystemMgr, 
LowLevelTypeSystem {  
   
+  private static final boolean IS_TRACE_JCAS_EXPAND = false;  // set to show 
jcas expands of types
+  
   /**
    * Define this JVM property to disable equal type system consolidation.  
    * When a type system is committed, it normally is compared with other 
committed type systems
@@ -441,6 +443,12 @@ public class TypeSystemImpl implements T
    *   
    */
   private final Map<ClassLoader, FsGenerator3[]> generators4pearsByClassLoader 
= new IdentityHashMap<>();
+  
+  private int nextI;  // temp value used in computing adjusted offsets 
+  private int nextR;  // temp value used in computing adjusted offsets
+  private Map<String, JCasClassInfo> type2jcci;  // temp value used in 
computing adjusted offsets
+  private Lookup lookup;
+  private ClassLoader cl_for_commit;
 
   public TypeSystemImpl() {
 
@@ -909,7 +917,9 @@ public class TypeSystemImpl implements T
 
 
   public boolean isInInt(Type rangeType) {
-    return rangeType.isPrimitive() && !subsumes(stringType, rangeType);
+    return (rangeType == null) 
+             ? false
+             : (rangeType.isPrimitive() && !subsumes(stringType, rangeType));
   }
   
   @Override
@@ -1368,12 +1378,6 @@ public class TypeSystemImpl implements T
       // because it will call the type system iterator
   //    this.casMetadata.setupFeaturesAndCreatableTypes();
 
-      // Augment (if called for) the features for the types, based on features 
defined in the JCas classes (if they exist)
-      //   - also does feature reordering if necessary so subtype added 
features follow super type added ones.
-      Map<String, JCasClassInfo> type2jcci = 
FSClassRegistry.get_className_to_jcci(cl, false);  // is not pear
-      Lookup lookup = FSClassRegistry.getLookup(cl);
-      FSClassRegistry.augmentFeaturesFromJCas(this.topType, cl, this, 
type2jcci, lookup);      
-
       if (!IS_DISABLE_TYPESYSTEM_CONSOLIDATION) {
         WeakReference<TypeSystemImpl> prevWr = committedTypeSystems.get(this);
         if (null != prevWr) {
@@ -1398,8 +1402,12 @@ public class TypeSystemImpl implements T
 //          }
 //        }
 //      }
-      
-      computeAdjustedFeatureOffsets(topType, 0, 0);  // must preceed the 
FSClassRegistry JCas stuff below
+
+      type2jcci = FSClassRegistry.get_className_to_jcci(cl, false);  // is not 
pear
+      lookup = FSClassRegistry.getLookup(cl);
+      cl_for_commit = cl;
+
+      computeAdjustedFeatureOffsets(topType);  // must preceed the 
FSClassRegistry JCas stuff below
       
       // Load all the available JCas classes (if not already loaded).
       // Has to follow above, because information computed above is used when
@@ -1428,27 +1436,68 @@ public class TypeSystemImpl implements T
   
   /**
    * This is the actual offset for the feature, in either the int or ref array
+   * 
+   * Offsets for super types come before types, because
+   *   multiple subtypes can share the same super type
+   *   
+   * Offsets due to JCas defined features are set before those from type 
systems, because
+   *   the same JCas class might be used with different type system,
+   *   and this increases the chance that the assignment is still valid.
    *   
+   * Special handling for JCas defined features which are missing in the type 
system.
+   *   - these are allocated artificial "feature impls", which participate in 
the offset
+   *     setting, but not in anything else (like serialization)
+   * 
+   * Special handling for JCas super types which have no corresponding uima 
types
+   *   - features inferred from these are incorporated for purposes of 
computing offsets (only), because
+   *     some later type system might have these.
+   * 
+   * Sets offset into 2 places:
+   *   - the FeatureImpl
+   *   - a set of arrays in the type:
+   *       one mapping offset to featureImpl for refs
+   *       one mapping offset to featureImpl for ints
+   *       one mapping offset to non-fs-refs (for efficiency in enquing these 
before refs) 
+   * 
+   * also sets the number-of-used slots (int / ref) for allocating, in the type
+   * 
    * @param ti - the type
-   * @param nextI - the next available slot to use - for int style items
-   * @param nextR - the next available slot to use - for ref style items
    */
-  private void computeAdjustedFeatureOffsets(TypeImpl ti, int nextI, int 
nextR) {
+  private void computeAdjustedFeatureOffsets(TypeImpl ti) {
+
     List<FeatureImpl> tempIntFis = new ArrayList<>();
     List<FeatureImpl> tempRefFis = new ArrayList<>();
-    List<FeatureImpl> tempNsr    = new ArrayList<>();
+    List<FeatureImpl> tempNsr    = new ArrayList<>();    
+
     if (ti != topType) {
+      // initialize these offset -> fi maps from supertype
       ti.initAdjOffset2FeatureMaps(tempIntFis, tempRefFis, tempNsr);
+      nextI = ti.getSuperType().nbrOfUsedIntDataSlots;
+      nextR = ti.getSuperType().nbrOfUsedRefDataSlots;
+    } else {
+      nextI = 0;
+      nextR = 0;
     }
+ 
+    // all the JCas slots come first, because their offsets can't easily change
+    // this includes any superClass of a jcas class which is not in this type 
system
     
+    JCasClassInfo jcci = getJcci(ti);
+    
+    if (jcci != null) {
+      addJCasOffsetsWithSupers(jcci.jcasClass, tempIntFis, tempRefFis, 
tempNsr);
+//      addJCasOffsets(ti.jcci, tempIntFis, tempRefFis, tempNsr); // already 
done by above
+    }
+        
     for (final FeatureImpl fi : 
ti.getMergedStaticFeaturesIntroducedByThisType()) {
-      fi.setAdjustedOffset(fi.isInInt ? nextI : nextR);
-      ti.setOffset2Feat(tempIntFis, tempRefFis, tempNsr, fi, fi.isInInt ? 
(nextI++) : (nextR++));
-      if (((TypeImpl)fi.getRange()).isLongOrDouble) {
-        nextI ++;
-      }        
+      if (fi.getAdjustedOffset() == -1) {
+        // wasn't set due to jcas class, above
+        setFeatureAdjustedOffset(fi, tempIntFis, tempRefFis, tempNsr);
+      } else {
+        
+      }
     }
-    
+        
     ti.nbrOfUsedIntDataSlots = nextI;
     ti.nbrOfUsedRefDataSlots = nextR;
     
@@ -1467,15 +1516,166 @@ public class TypeSystemImpl implements T
 //    ti.hasNoSlots = ti.nbrOfUsedIntDataSlots == 0 && 
ti.nbrOfUsedRefDataSlots == 0;
     
     for (TypeImpl sub : ti.getDirectSubtypes()) {
-      computeAdjustedFeatureOffsets(sub, nextI, nextR);
+      computeAdjustedFeatureOffsets(sub);
     }  
   }
       
+  
+  /**
+   * Insures that any super class jcas-defined features, 
+   *   not already defined (due to having a corresponding type in this
+   *   type system)
+   *   get their features done first
+   *   
+   * Walking up the super chain:
+   *   - could encounter a class which has no jcci (it's not a jcas class)
+   *     but has a super class which is one) - so don't stop the up walk.
+   *     
+   * Stop the up walk when
+   *   - reach the TOP or Object
+   *   - reach a class which has a corresponding uima type (the assumption is 
that
+   *     this type is a super type
+   *     
+   * @param ti the type associated with clazz, or null, if none   
+   * @param clazz the class whose supertypes are being scanned.  May not be a 
JCas class
+   * @param tempIntFis the array of int offsets (refs to feature impls (maybe 
jcas-only)
+   * @param tempRefFis the array of ref offsets (refs to feature impls (maybe 
jcas-only)
+   * @param tempNsrFis a list of non fs-ref ref values
+   */
+  private void addJCasOffsetsWithSupers(Class<?> clazz,  
+                                        List<FeatureImpl> tempIntFis, 
+                                        List<FeatureImpl> tempRefFis,
+                                        List<FeatureImpl> tempNsrFis) {
+    
+    Class<?> superClass = clazz.getSuperclass();
+    /* **********************
+     *   STOP if get to top *
+     * **********************/
+    if (superClass == Object.class) {
+      return;
+    }
+
+    String superClassName = superClass.getName();
+    String uimaSuperTypeName = 
Misc.javaClassName2UimaTypeName(superClassName);    
+    if (this.getType(uimaSuperTypeName) != null) {
+      
+      /* ****************************
+       *   STOP if get to UIMA type *
+       * ****************************/
+
+      // But process this jcas class level
+      // then return to recursively process other jcas class levels.
+      String className = clazz.getName();
+      String uimaTypeName = Misc.javaClassName2UimaTypeName(className);
+      TypeImpl ti = this.getType(uimaTypeName);
+      if (ti != null) {
+        maybeAddJCasOffsets(ti, tempIntFis, tempRefFis, tempNsrFis);
+      }
+      return;
+    }
+    
+    // recurse up the superclass chain for all jcci's not having UIMA types
+    //   If they exist, they will have been loaded/created by 
FSClassRegistry.augmentFeaturesFromJCas
+    //   some intermediate superclasses may not have jccis, just skip over 
them.   
+    
+    addJCasOffsetsWithSupers(superClass, tempIntFis, tempRefFis, tempNsrFis);
+//    maybeAddJCasOffsets(clazz, tempIntFis, tempRefFis, tempNsrFis); // 
already done by above statement
+  }
+  
+  
+  /**
+   * 
+   * @param ti the type having offsets set up for
+   * @param jcci a corresponding jcci, either for this type or for a super 
type 
+   *               when the super type is not in this uima type system
+   * @param tempIntFis list to augment with additional slots
+   * @param tempRefFis list to augment with additional slots
+   */
+  private void maybeAddJCasOffsets(TypeImpl ti, 
+                                   List<FeatureImpl> tempIntFis, 
+                                   List<FeatureImpl> tempRefFis,
+                                   List<FeatureImpl> tempNsrFis) {
+    
+    JCasClassInfo jcci = getJcci(ti);
+    if (null != jcci) {  // could be null if class is not a JCas class   
+      addJCasOffsets(jcci, tempIntFis, tempRefFis, tempNsrFis);
+    }
+  }
+  
+  private void addJCasOffsets(JCasClassInfo jcci, 
+      List<FeatureImpl> tempIntFis, 
+      List<FeatureImpl> tempRefFis,
+      List<FeatureImpl> tempNsrFis) {
+
+    List<FeatureImpl> added = IS_TRACE_JCAS_EXPAND ? (new ArrayList<>(0)) : 
null;
+    for (FSClassRegistry.JCasClassFeatureInfo jcci_feat : jcci.features) {
+      TypeImpl rangeType = getType(jcci_feat.uimaRangeName); // could be null
+      TypeImpl ti = jcci.getUimaType(this); // could be null
+      FeatureImpl fi = null;
+      if (ti != null) {
+        fi = ti.getFeatureByBaseName(jcci_feat.shortName); // could be null
+      }
+      if (fi == null) { //
+        // no feature for this type in this type system, but in the JCas.
+        // create a FeatureImpl_jcas_only, to hold the offset info to use for
+        // later in the
+        // update of the CallSites to install the offsets
+        fi = new FeatureImpl_jcas_only(jcci_feat.shortName, rangeType);
+        if (IS_TRACE_JCAS_EXPAND) {
+          added.add(fi);
+        }
+      }
+      assert fi.getAdjustedOffset() == -1;
+      setFeatureAdjustedOffset(fi, tempIntFis, tempRefFis, tempNsrFis);
+    }
+    
+    if (IS_TRACE_JCAS_EXPAND && added.size() > 0) {
+      System.out.format("debug trace jcas added: %d slots, %s%n", 
added.size(), 
+          Misc.ppList(added));
+    }
+  }
+  
+  void setFeatureAdjustedOffset(FeatureImpl fi, List<FeatureImpl> tmpIntFis, 
List<FeatureImpl> tmpRefFis, List<FeatureImpl> tmpNsr) {
+    boolean isInt = fi.isInInt;
+    fi.setAdjustedOffset(isInt ? nextI : nextR);
+    setOffset2Feat(tmpIntFis, tmpRefFis, tmpNsr, fi, isInt ? (nextI++) : 
(nextR++));
+    if (fi.isLongOrDouble) {
+      nextI ++;
+    }        
+  }
+  
+  void setOffset2Feat(
+      List<FeatureImpl> tempIntFis, 
+      List<FeatureImpl> tempRefFis,
+      List<FeatureImpl> tempNsr,
+      FeatureImpl fi, 
+      int next) {
+    boolean is_jcas_only = fi instanceof FeatureImpl_jcas_only;
+    if (fi.isInInt) {
+      // assert tempIntFis.size() == next; // could have added slots from JCas
+      tempIntFis.add(is_jcas_only ? null : fi);
+      if (fi.getRangeImpl().isLongOrDouble) {
+        tempIntFis.add(null);
+      }
+    } else {
+      // assert tempRefFis.size() == next; // could have added slots from JCas
+      tempRefFis.add(is_jcas_only ? null : fi);
+      TypeImpl range = fi.getRangeImpl();
+
+      if (!is_jcas_only && range.isRefType && range != sofaType) {
+        tempNsr.add(fi);
+      }
+    }
+  }
+  
+  private JCasClassInfo getJcci(TypeImpl ti) {
+    return FSClassRegistry.getOrCreateJCasClassInfo(ti, cl_for_commit, 
type2jcci, lookup);
+  }
+  
   /**
    * Feature "ids" - offsets without adjusting for whether or not they're in 
the class itself
    * @param ti a type to compute these for
-   * @param nextI - the next available int offset
-   * @param nextR - the next available ref offset
+   * @param next - the next offset
    */
   private void computeFeatureOffsets(TypeImpl ti, int next) {
     
@@ -2619,6 +2819,7 @@ public class TypeSystemImpl implements T
 //    return jcasClassesInfo[typecode].jcasClass; 
 //  }
     /**
+     * ******** OBSOLETE  - only left in for supporting some jcas style in 
alpha level *************
    * This code is run when a JCas class is loaded and resolved, for the first 
time, as part of type system commit, or
    * as part of statically loading the FSClassRegister class (where this is 
done for all the built-ins, once).
    * It looks up the offset value in the type system (via a thread-local)
@@ -2627,6 +2828,7 @@ public class TypeSystemImpl implements T
    * @param featName -
    * @return the offset in the int or ref data arrays for the named feature
    */
+  // ******** OBSOLETE  - only left in for supporting some jcas style in alpha 
level *************
   public static synchronized int getAdjustedFeatureOffset(String featName) {
     TypeImpl type = typeBeingLoadedThreadLocal.get();
     if (null == type) {
@@ -2648,7 +2850,12 @@ public class TypeSystemImpl implements T
   
   static int getAdjustedFeatureOffset(TypeImpl type, String featName) {
     FeatureImpl fi = type.getFeatureByBaseName(featName);
-    return (fi == null) ? -1 : fi.getAdjustedOffset();    
+    return (fi == null) ? -1 : fi.getAdjustedOffset();
+//    if (fi == null) {
+//      FeatureImpl_jcas_only fi_j = type.getJcasAddedFeature(featName);
+//      return (fi_j == null) ? -1 : fi_j.getAdjustedOffset();
+//    }
+//    return fi.getAdjustedOffset();    
   }
     
   /**

Modified: 
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties
URL: 
http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties?rev=1822059&r1=1822058&r2=1822059&view=diff
==============================================================================
--- 
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties
 (original)
+++ 
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties
 Tue Jan 23 21:02:30 2018
@@ -558,7 +558,7 @@ JCAS_UNKNOWN_TYPE_NOT_IN_CAS = Unknown J
 JCAS_FIELD_MISSING_IN_TYPE_SYSTEM = JCAS class "{0}" defines a UIMA field 
"{1}" but the UIMA type doesn''t define that field.
 JCAS_FIELD_ADJ_OFFSET_CHANGED = In JCAS class "{0}", UIMA field "{1}" was set 
up when this class was previously loaded and initialized, to have an adjusted 
offset of "{2}" but now the feature has a different adjusted offset of "{3}"; 
this may be due to something else other than type system commit actions loading 
and initializing the JCas class, or to having a different non-compatible type 
system for this class, trying to use a common JCas cover class, which is not 
supported. 
 JCAS_CAS_MISMATCH_SUPERTYPE = JCas Class's supertypes for "{0}", "{1}" and the 
corresponding UIMA Supertypes for "{2}", "{3}" don't have an intersection.
-JCAS_MISMATCH_SUPERTYPE = The JCas class: "{0}" has supertype: "{1}" which 
doesn''t match the UIMA type "{2}"''s supertype "{3}".
+JCAS_MISMATCH_SUPERTYPE = The JCas class: "{0}" has supertypes: "{1}" which do 
not match the UIMA type "{2}"''s supertypes "{3}".
 JCAS_TYPE_RANGE_MISMATCH = CAS type system type "{0}" defines field "{1}" with 
range "{2}", but JCas getter method is returning "{3}" which is not a subtype 
of the declared range.
 JCAS_GET_NTH_ON_EMPTY_LIST = JCas getNthElement method called via invalid 
object - an empty list: {0}.
 JCAS_GET_NTH_NEGATIVE_INDEX = JCas getNthElement method called with index 
"{0}" which is negative.

Modified: 
uima/uv3/uimaj-v3/trunk/uimaj-core/src/test/java/org/apache/uima/cas/impl/JCasReinitTest.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/trunk/uimaj-core/src/test/java/org/apache/uima/cas/impl/JCasReinitTest.java?rev=1822059&r1=1822058&r2=1822059&view=diff
==============================================================================
--- 
uima/uv3/uimaj-v3/trunk/uimaj-core/src/test/java/org/apache/uima/cas/impl/JCasReinitTest.java
 (original)
+++ 
uima/uv3/uimaj-v3/trunk/uimaj-core/src/test/java/org/apache/uima/cas/impl/JCasReinitTest.java
 Tue Jan 23 21:02:30 2018
@@ -62,12 +62,23 @@ public class JCasReinitTest extends Test
   public void testReinit() throws Throwable {
     File typeSystemFile1;
     
-    typeSystemFile1 = 
JUnitExtension.getFile("ExampleCas/testTypeSystem_token_no_features.xml");
+//    // x.y.z.Token with no features
+//    typeSystemFile1 = 
JUnitExtension.getFile("ExampleCas/testTypeSystem_token_no_features.xml");
+//    typeSystemDescription  = 
UIMAFramework.getXMLParser().parseTypeSystemDescription(
+//        new XMLInputSource(typeSystemFile1));
+//   
+//    cas = (CASImpl) CasCreationUtils.createCas(typeSystemDescription, new 
TypePriorities_impl(), null);
+//    T.dumpOffset();
+//    
+
+    typeSystemFile1 = 
JUnitExtension.getFile("ExampleCas/testTypeSystem_t_nofeatures.xml");
     typeSystemDescription  = 
UIMAFramework.getXMLParser().parseTypeSystemDescription(
         new XMLInputSource(typeSystemFile1));
-   
-    cas = (CASImpl) CasCreationUtils.createCas(typeSystemDescription, new 
TypePriorities_impl(), null);
     
+    cas_no_features = (CASImpl) 
CasCreationUtils.createCas(typeSystemDescription, new TypePriorities_impl(), 
null);
+    
+    T.dumpOffset();
+
     typeSystemFile1 = 
JUnitExtension.getFile("ExampleCas/testTypeSystem_t_1_feature.xml");
     typeSystemDescription  = 
UIMAFramework.getXMLParser().parseTypeSystemDescription(
         new XMLInputSource(typeSystemFile1));
@@ -77,13 +88,6 @@ public class JCasReinitTest extends Test
     T.dumpOffset();
 
 
-    typeSystemFile1 = 
JUnitExtension.getFile("ExampleCas/testTypeSystem_t_nofeatures.xml");
-    typeSystemDescription  = 
UIMAFramework.getXMLParser().parseTypeSystemDescription(
-        new XMLInputSource(typeSystemFile1));
-    
-    cas_no_features = (CASImpl) 
CasCreationUtils.createCas(typeSystemDescription, new TypePriorities_impl(), 
null);
-    
-    T.dumpOffset();
 
    
   }


Reply via email to