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 2015/12/01 18:06:08 UTC

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

Author: schor
Date: Tue Dec  1 17:06:08 2015
New Revision: 1717469

URL: http://svn.apache.org/viewvc?rev=1717469&view=rev
Log:
[UIM-4663] fix FeaturePathImpl for many edge cases to operate like v2.

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

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeaturePathImpl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeaturePathImpl.java?rev=1717469&r1=1717468&r2=1717469&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeaturePathImpl.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeaturePathImpl.java Tue Dec  1 17:06:08 2015
@@ -52,15 +52,19 @@ class FeaturePathImpl implements Feature
   private static final String FUNCTION_NAME_COVERED_TEXT  = "coveredtext()";
   private static final String FUNCTION_NAME_ID            = "fsid()";
   private static final String FUNCTION_NAME_TYPE_NAME     = "typename()";
+  
+  private static final TOP FEATURE_PATH_FAILED = new TOP();
 
   /**
    * The path's builtInFunction, or 0
    */
   private byte                builtInFunction             = 0;
+  private String originalBuiltInName = null;
 
   // featurePath element names
   final private ArrayList<String> featurePathElementNames = new ArrayList<String>();
   
+  private boolean pathStartsWithSlash = true;
   /**
    * FeatureImpl array corresponding to feature path names.
    * This can change for each evaluation of this FeaturePath instance against a
@@ -72,6 +76,7 @@ class FeaturePathImpl implements Feature
   final private ArrayList<FeatureImpl>  boundFeatures = new ArrayList<FeatureImpl>();
   
   private FeatureImpl targetFeature;  // set to the last value of boundFeatures
+  private TypeImpl    targetType;     // set to type of range of last found feature, works when there are no features
 
   /**
    * The Type used as the starting type for path validation
@@ -137,6 +142,7 @@ class FeaturePathImpl implements Feature
   public void initialize(String featurePath) throws CASException {
 
     this.builtInFunction = NO_BUILT_IN_FUNCTION;
+    this.originalBuiltInName = null;
 
     // throw exception if featurePath is null
     if (featurePath == null) {
@@ -144,6 +150,8 @@ class FeaturePathImpl implements Feature
           new Object[] { featurePath, "null for a feature path" });
     }
 
+    pathStartsWithSlash = featurePath.startsWith("/"); // v2 compatibility 
+    
     // check featurePath for invalid character sequences
     if (featurePath.indexOf("//") > -1) { // two forward slashes in a
                                                      // row is invalid
@@ -167,10 +175,13 @@ class FeaturePathImpl implements Feature
         if ((index = token.indexOf(BUILT_IN_FUNCTION_SEPARATOR)) != -1) {
           if (index > 0) {
             // we have a built-in function that is separated with a ":"
-            this.featurePathElementNames.add(token.substring(0, index));
+            if (index > 0) {
+              this.featurePathElementNames.add(token.substring(0, index));
+            }
           }
           // get built-in function
-          String builtInFunctionName = token.substring(index + 1).toLowerCase();
+          originalBuiltInName = token.substring(index + 1);
+          String builtInFunctionName = originalBuiltInName.toLowerCase();
           if (builtInFunctionName.equals(FUNCTION_NAME_COVERED_TEXT)) {
             this.builtInFunction = FUNCTION_COVERED_TEXT;
           } else if (builtInFunctionName.equals(FUNCTION_NAME_ID)) {
@@ -255,7 +266,7 @@ class FeaturePathImpl implements Feature
   @Override
   public Boolean getBooleanValue(FeatureStructure fs) {
     TOP tgtFs = getTargetFs((TOP) fs); 
-    return (tgtFs == null || targetFeature == null) ? null : tgtFs.getBooleanValue(targetFeature);
+    return (tgtFs == FEATURE_PATH_FAILED) ? null : tgtFs.getBooleanValue(targetFeature);
   }
     
   /*
@@ -267,7 +278,7 @@ class FeaturePathImpl implements Feature
   @Override
   public Byte getByteValue(FeatureStructure fs) {
     TOP tgtFs = getTargetFs((TOP) fs); 
-    return (tgtFs == null || targetFeature == null) ? null : tgtFs.getByteValue(targetFeature);
+    return (tgtFs == FEATURE_PATH_FAILED) ? null : tgtFs.getByteValue(targetFeature);
   }    
 
   /*
@@ -279,7 +290,7 @@ class FeaturePathImpl implements Feature
   @Override
   public Double getDoubleValue(FeatureStructure fs) {
     TOP tgtFs = getTargetFs((TOP) fs); 
-    return (tgtFs == null || targetFeature == null) ? null : tgtFs.getDoubleValue(targetFeature);
+    return (tgtFs == FEATURE_PATH_FAILED) ? null : tgtFs.getDoubleValue(targetFeature);
   }    
 
   /*
@@ -291,7 +302,7 @@ class FeaturePathImpl implements Feature
   @Override
   public Float getFloatValue(FeatureStructure fs) {
     TOP tgtFs = getTargetFs((TOP) fs); 
-    return (tgtFs == null || targetFeature == null) ? null : tgtFs.getFloatValue(targetFeature);
+    return (tgtFs == FEATURE_PATH_FAILED) ? null : tgtFs.getFloatValue(targetFeature);
   }    
 
   /*
@@ -303,7 +314,7 @@ class FeaturePathImpl implements Feature
   @Override
   public FeatureStructure getFSValue(FeatureStructure fs) {
     TOP tgtFs = getTargetFs((TOP) fs); 
-    return (tgtFs == null) ? null : tgtFs;
+    return (tgtFs == FEATURE_PATH_FAILED) ? null : tgtFs;
   }    
   
   /*
@@ -315,7 +326,7 @@ class FeaturePathImpl implements Feature
   @Override
   public Integer getIntValue(FeatureStructure fs) {
     TOP tgtFs = getTargetFs((TOP) fs); 
-    return (tgtFs == null || targetFeature == null) ? null : tgtFs.getIntValue(targetFeature);
+    return (tgtFs == FEATURE_PATH_FAILED) ? null : tgtFs.getIntValue(targetFeature);
   }    
   
   /*
@@ -327,7 +338,7 @@ class FeaturePathImpl implements Feature
   @Override
   public Long getLongValue(FeatureStructure fs) {
     TOP tgtFs = getTargetFs((TOP) fs); 
-    return (tgtFs == null || targetFeature == null) ? null : tgtFs.getLongValue(targetFeature);
+    return (tgtFs == FEATURE_PATH_FAILED) ? null : tgtFs.getLongValue(targetFeature);
   }    
 
   /*
@@ -339,7 +350,7 @@ class FeaturePathImpl implements Feature
   @Override
   public Short getShortValue(FeatureStructure fs) {
     TOP tgtFs = getTargetFs((TOP) fs); 
-    return (tgtFs == null || targetFeature == null) ? null : tgtFs.getShortValue(targetFeature);
+    return (tgtFs == FEATURE_PATH_FAILED) ? null : tgtFs.getShortValue(targetFeature);
   }    
 
   /*
@@ -351,7 +362,7 @@ class FeaturePathImpl implements Feature
   @Override
   public String getStringValue(FeatureStructure fs) {
     TOP tgtFs = getTargetFs((TOP) fs); 
-    return (tgtFs == null || targetFeature == null) ? null : tgtFs.getStringValue(targetFeature);
+    return (tgtFs == FEATURE_PATH_FAILED) ? null : tgtFs.getStringValue(targetFeature);
   }    
 
   /*
@@ -364,7 +375,7 @@ class FeaturePathImpl implements Feature
   @Override
   public Object getJavaObjectValue(FeatureStructure fs) {
     TOP tgtFs = getTargetFs((TOP) fs); 
-    return (tgtFs == null || targetFeature == null) ? null : tgtFs.getJavaObjectValue(targetFeature);
+    return (tgtFs == FEATURE_PATH_FAILED) ? null : tgtFs.getJavaObjectValue(targetFeature);
   }    
 
   /*
@@ -376,7 +387,7 @@ class FeaturePathImpl implements Feature
   @Override
   public Type getType(FeatureStructure fs) {
     TOP tgtFs = getTargetFs((TOP) fs); 
-    return (targetFeature == null) ? null : targetFeature.getRange();
+    return (tgtFs == FEATURE_PATH_FAILED) ? null : targetType;
   }    
     
   /*
@@ -387,10 +398,8 @@ class FeaturePathImpl implements Feature
    */
   @Override
   public TypeClass getTypeClass(FeatureStructure fs) {
-    TOP tgtFs = getTargetFs((TOP) fs); 
-    return targetFeature == null 
-        ? null 
-        : TypeClass.values()[TypeSystemImpl.getTypeClass(targetFeature.getRangeImpl())];
+    TypeImpl type = (TypeImpl) getType(fs); 
+    return (type == null) ? null : TypeClass.values()[TypeSystemImpl.getTypeClass(type)];
   }    
 
   /*
@@ -414,50 +423,53 @@ class FeaturePathImpl implements Feature
   @Override
   public String getValueAsString(FeatureStructure fs) {
     TOP tgtFs = getTargetFs((TOP) fs);
-    if (tgtFs == null) {
+    if (tgtFs == FEATURE_PATH_FAILED) {
       return null;
     }
     
-    if (targetFeature != null) {
-      TypeImpl targetRange = targetFeature.getRangeImpl();
-      switch (TypeSystemImpl.getTypeClass(targetRange)) {
-      case LowLevelCAS.TYPE_CLASS_INVALID:
-        return null;
-        
-      case LowLevelCAS.TYPE_CLASS_STRING:
-      case LowLevelCAS.TYPE_CLASS_BOOLEAN:
-      case LowLevelCAS.TYPE_CLASS_BYTE:
-      case LowLevelCAS.TYPE_CLASS_SHORT:
-      case LowLevelCAS.TYPE_CLASS_INT:
-      case LowLevelCAS.TYPE_CLASS_LONG:
-      case LowLevelCAS.TYPE_CLASS_FLOAT:
-      case LowLevelCAS.TYPE_CLASS_DOUBLE:
-      case LowLevelCAS.TYPE_CLASS_JAVAOBJECT:
-        verifyNoBuiltInFunction();
-        return tgtFs.getFeatureValueAsString(targetFeature);
-          
-      case LowLevelCAS.TYPE_CLASS_BOOLEANARRAY:
-      case LowLevelCAS.TYPE_CLASS_BYTEARRAY:
-      case LowLevelCAS.TYPE_CLASS_SHORTARRAY:
-      case LowLevelCAS.TYPE_CLASS_INTARRAY:
-      case LowLevelCAS.TYPE_CLASS_LONGARRAY:
-      case LowLevelCAS.TYPE_CLASS_FLOATARRAY:
-      case LowLevelCAS.TYPE_CLASS_DOUBLEARRAY:
-      case LowLevelCAS.TYPE_CLASS_STRINGARRAY:
-      case LowLevelCAS.TYPE_CLASS_JAVAOBJECTARRAY:
-      case LowLevelCAS.TYPE_CLASS_FSARRAY:
-        if (this.builtInFunction > NO_BUILT_IN_FUNCTION) {
-          return evaluateBuiltInFunction(tgtFs);
-        }
-        return ((CommonArray)tgtFs).getValuesAsCommaSeparatedString();
-      
-      case LowLevelCAS.TYPE_CLASS_FS: 
-        if (this.builtInFunction > NO_BUILT_IN_FUNCTION) {
-          return evaluateBuiltInFunction(tgtFs);
-        }
-        return tgtFs.toString();
-      } // end of switch
+    if (targetType == null) {
+      return null;
     }
+    switch (TypeSystemImpl.getTypeClass(targetType)) {
+    case LowLevelCAS.TYPE_CLASS_INVALID:
+      return null;
+      
+    case LowLevelCAS.TYPE_CLASS_STRING:
+    case LowLevelCAS.TYPE_CLASS_BOOLEAN:
+    case LowLevelCAS.TYPE_CLASS_BYTE:
+    case LowLevelCAS.TYPE_CLASS_SHORT:
+    case LowLevelCAS.TYPE_CLASS_INT:
+    case LowLevelCAS.TYPE_CLASS_LONG:
+    case LowLevelCAS.TYPE_CLASS_FLOAT:
+    case LowLevelCAS.TYPE_CLASS_DOUBLE:
+    case LowLevelCAS.TYPE_CLASS_JAVAOBJECT:
+      verifyNoBuiltInFunction();
+      return tgtFs.getFeatureValueAsString(targetFeature);
+        
+    case LowLevelCAS.TYPE_CLASS_BOOLEANARRAY:
+    case LowLevelCAS.TYPE_CLASS_BYTEARRAY:
+    case LowLevelCAS.TYPE_CLASS_SHORTARRAY:
+    case LowLevelCAS.TYPE_CLASS_INTARRAY:
+    case LowLevelCAS.TYPE_CLASS_LONGARRAY:
+    case LowLevelCAS.TYPE_CLASS_FLOATARRAY:
+    case LowLevelCAS.TYPE_CLASS_DOUBLEARRAY:
+    case LowLevelCAS.TYPE_CLASS_STRINGARRAY:
+    case LowLevelCAS.TYPE_CLASS_JAVAOBJECTARRAY:
+    case LowLevelCAS.TYPE_CLASS_FSARRAY:
+      if (this.builtInFunction > NO_BUILT_IN_FUNCTION) {
+        return evaluateBuiltInFunction(tgtFs);
+      }
+      return ((CommonArray)tgtFs).getValuesAsCommaSeparatedString();
+    
+    case LowLevelCAS.TYPE_CLASS_FS: 
+      if (tgtFs == null) {
+        return null;
+      }
+      if (this.builtInFunction > NO_BUILT_IN_FUNCTION) {
+        return evaluateBuiltInFunction(tgtFs);
+      }
+      return tgtFs.toString();
+    } // end of switch
     return null;
   }
 
@@ -529,11 +541,13 @@ class FeaturePathImpl implements Feature
    *         
    */
   private TOP getTargetFs(TOP fs) {
-
-    if (fs == null) {
-      return null;
+ 
+    if (null == fs) {
+      return FEATURE_PATH_FAILED;
     }
-    if (this.featurePathElementNames.size() == 0) {
+    
+    if (this.featurePathElementNames.size() == 0) { 
+      targetType = fs._typeImpl;
       return fs;
     }
     
@@ -552,21 +566,29 @@ class FeaturePathImpl implements Feature
 
     // resolve feature path value
     for (int i = 0; i < this.featurePathElementNames.size(); i++) {
+      if (currentFs == null) {
+        return FEATURE_PATH_FAILED;
+      }
       
       if (i < this.boundFeatures.size()) {
-        targetFeature = this.boundFeatures.get(i);  
-      } else {
-        targetFeature = currentFs._typeImpl.getFeatureByBaseName(featurePathElementNames.get(i));
-        if (targetFeature == null) {
-          throw new CASRuntimeException(MESSAGE_DIGEST, "INVALID_FEATURE_PATH_FEATURE_NOT_DEFINED", 
-              new Object[] { getFeaturePathString(), currentFs._typeImpl.getName(), this.featurePathElementNames.get(i) });
+        targetFeature = this.boundFeatures.get(i);
+        /*
+         * It is possible that the previously bound feature isn't valid for this FS.  
+         * This can happen if a type hierarchy defines 2 different features for two different subtypes of type Tt
+         * with the same feature name. 
+         * 
+         * So we check if this bound feature is appropriate for the current FS
+         */
+        if ( ! ((TypeImpl)targetFeature.getDomain()).subsumes(currentFs._typeImpl)) {
+          setTargetFeature(currentFs, i);
         }
-        boundFeatures.add(targetFeature);  // cache for future use
+      } else {
+        setTargetFeature(currentFs, i);
       }
             
       // switch feature type class
 //        currentRangeTypeCode = llCas.ll_getTypeSystem().ll_getRangeType(targetFeatureCode);
-      rangeType = targetFeature.getRangeImpl();
+      targetType = rangeType = targetFeature.getRangeImpl();
       rangeTypeClass = TypeSystemImpl.getTypeClass(rangeType);
      
       switch (rangeTypeClass) {
@@ -597,6 +619,20 @@ class FeaturePathImpl implements Feature
       case LowLevelCAS.TYPE_CLASS_FS:
         currentFs = currentFs.getFeatureValue(targetFeature);
         if (currentFs == null) {
+          if (i == (this.featurePathElementNames.size() - 1)) {
+            // at the last element, keep targetType == to the range type
+          } else {
+            /*
+             * not at the last element, so terminating the feature path prematurely.
+             * There are 2 cases:
+             *   - the PathValid is POSSIBLE 
+             *   - the PathValid is ALWAYS 
+             */
+            PathValid pathValid = TypeSystemUtils.isPathValid(this.boundBaseType, this.featurePathElementNames);
+            if (pathValid == PathValid.POSSIBLE) {
+              targetType = null;   // following v2 design here
+            }
+          }
           return null;
         }  
         break;
@@ -607,6 +643,15 @@ class FeaturePathImpl implements Feature
     return currentFs;
   }
 
+  private void setTargetFeature(TOP currentFs, int i) {
+    targetFeature = currentFs._typeImpl.getFeatureByBaseName(featurePathElementNames.get(i));
+    if (targetFeature == null) {
+      throw new CASRuntimeException(MESSAGE_DIGEST, "INVALID_FEATURE_PATH_FEATURE_NOT_DEFINED", 
+          new Object[] { getFeaturePathString(), currentFs._typeImpl.getName(), this.featurePathElementNames.get(i) });
+    }
+    boundFeatures.add(targetFeature);  // cache for future use
+  }
+  
   private void verifyNoBuiltInFunction() {
     if (this.builtInFunction > NO_BUILT_IN_FUNCTION) {
       throwBuiltInFunctionException(targetFeature.getRangeImpl().getName());
@@ -615,18 +660,22 @@ class FeaturePathImpl implements Feature
   
   private String getFeaturePathString() {
     StringBuilder sb = new StringBuilder();
-    for (String s : featurePathElementNames) {
-      sb.append('/').append(s);
-    }
-    if (this.builtInFunction > 0) {
-      sb.append(':');
-      switch (this.builtInFunction) {
-      case FUNCTION_COVERED_TEXT: sb.append(FUNCTION_NAME_COVERED_TEXT); break;
-      case FUNCTION_ID          : sb.append(FUNCTION_NAME_ID          ); break;
-      case FUNCTION_TYPE_NAME   : sb.append(FUNCTION_NAME_TYPE_NAME   ); break;
-      default: assert(false);
+    if (featurePathElementNames.size() == 0) {
+      if (pathStartsWithSlash) {
+        sb.append('/');
+      }
+    } else {    
+      for (String s : featurePathElementNames) {
+        sb.append('/').append(s);
       }
     }
+    appendBuiltInFunction(sb);
     return sb.toString();
   }
+  
+  private void appendBuiltInFunction(StringBuilder sb) {
+    if (this.builtInFunction > 0) {
+      sb.append(':').append(originalBuiltInName);  // because capitalization could be different
+    }    
+  }
 }