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 19:00:54 UTC

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

Author: schor
Date: Tue Dec  1 18:00:54 2015
New Revision: 1717475

URL: http://svn.apache.org/viewvc?rev=1717475&view=rev
Log:
[UIM-4663] FeaturePathImpl updates for this class.

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

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemUtils.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemUtils.java?rev=1717475&r1=1717474&r2=1717475&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemUtils.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemUtils.java Tue Dec  1 18:00:54 2015
@@ -19,7 +19,9 @@
 
 package org.apache.uima.cas.impl;
 
+import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Deque;
 import java.util.List;
 import java.util.Stack;
 import java.util.StringTokenizer;
@@ -29,9 +31,8 @@ import org.apache.uima.cas.Type;
 import org.apache.uima.cas.TypeSystem;
 
 /**
- * Class comment for TypeSystemUtils.java goes here.
- * 
- * 
+ * Type Utilities - all static, so class is abstract to prevent creation
+ * Used by Feature Path
  */
 public abstract class TypeSystemUtils {
 
@@ -321,8 +322,9 @@ public abstract class TypeSystemUtils {
   }
 
   /**
-   * Checks if a feature path is valid for a given type.
-   * 
+   * <p>Given a starting Type and a list of features representing a feature path, 
+   * checks if a feature path is valid for a given type.</p>
+
    * <p>
    * We distinguish three cases:
    * <ol>
@@ -330,10 +332,10 @@ public abstract class TypeSystemUtils {
    * <code>path</code> can ever be defined.</li>
    * <li><code>PathValid.ALWAYS</code>: if all intermediate objects are non-null, this
    * <code>path</code> will always be defined on any object of <code>type</code>. </li>
-   * <li><code>PathValid.POSSIBLE</code>: some objects of <code>type</code> will have<code>path</code> 
+   * <li><code>PathValid.POSSIBLE</code>: some objects of <code>type</code> will have <code>path</code> 
    * defined, while others may not.</li>
    * </ol>
-   * <b>Note:</b> we always assume that all references are not null.  A return value of ALWAYS
+   * <b>Note:</b> In computing validity, we always assume that all references are not null.  A return value of ALWAYS
    * can of course not guarantee that all intermediate objects will always exist; only that if they
    * exist, the path will be defined.
    * 
@@ -343,57 +345,76 @@ public abstract class TypeSystemUtils {
    * {@link PathValid#NEVER NEVER}.
    */
   public static final PathValid isPathValid(Type type, List<String> path) {
-    Stack<String> fStack = new Stack<String>();
-    // Note: addAll() adds elements to the stack in the wrong order.
-    for (int i = (path.size() - 1); i >= 0; i--) {
-      fStack.push(path.get(i));
-    }
-    return isPathValid(type, fStack, PathValid.ALWAYS);
+    return isPathValid((TypeImpl)type, new ArrayDeque<>(path), PathValid.ALWAYS);
   }
-
-  private static final PathValid isPathValid(Type type, Stack<String> path, 
-      PathValid status) {
+   
+  /**
+   * Recursively called on each successive path element.
+   * Pops a feature name off the path, and checks if it exists for the type.
+   *   -- if exists, gets its range type and iterates via recursion.
+   * Stops when the queue of feature names is empty.
+   * 
+   * @param type
+   * @param path
+   * @param status the returned value if the feature is found.
+   * @return
+   */
+  private static final PathValid isPathValid(TypeImpl type, Deque<String> path, PathValid status) {
     // If the path is empty, return the input status.
     if (path.isEmpty()) {
       return status;
     }
     // Pop the next feature name from the stack and check if it's defined for the current type.
-    String fName = path.pop();
-    Feature feat = type.getFeatureByBaseName(fName);
-    if (feat != null) {
+    String featName = path.pop();
+    FeatureImpl fi = type.getFeatureByBaseName(featName);
+    if (fi != null) {
       // If feature is defined, we can continue directly.
-      return isPathValid(feat.getRange(), path, status);
+      return isPathValid(fi.getRangeImpl(), path, status);
     }
     // If feature is not defined for type, check to see if there are any subtypes for which the
     // path is defined (possible).
-    List<Type> subtypes = new ArrayList<Type>();
-    getFeatureDefiningSubtypes(type, fName, subtypes);
-    for (int i = 0; i < subtypes.size(); i++) {
-      // Retrieve the feature value type
-      Type nextType = subtypes.get(i).getFeatureByBaseName(fName).getRange();
-      // Call isPathValid() on next type in chain.
-      PathValid newStatus = isPathValid(nextType, path, PathValid.POSSIBLE);
-      if (newStatus == PathValid.POSSIBLE) {
-        // If we found one, we can stop here and return.
-        return PathValid.POSSIBLE;
-      }
-    }
-    // No subtype was found for which the path was defined.
-    return PathValid.NEVER;
+
+    return isPathValidInSubtypes(type, featName, path);
+    
   }
-  
-  // Find subtypes that define the feature.  Add subtypes to list.
-  private static final void getFeatureDefiningSubtypes(Type type, String fName, List<Type> types) {
-    TypeSystem ts = ((TypeImpl) type).getTypeSystem();
-    List<Type> subtypes = ts.getDirectSubtypes(type);
-    for (int i = 0; i < subtypes.size(); i++) {
-      Type subtype = (Type) subtypes.get(i);
-      if (subtype.getFeatureByBaseName(fName) != null) {
-        types.add((Type) subtypes.get(i));
-      } else {
-        getFeatureDefiningSubtypes(subtype, fName, types);
+   
+  /**
+   * Called when the Feature Name is not a valid feature of the current <code>type</code>.
+   * 
+   * It examines all the subtypes to see if it can find one for which the feature is valid.
+   * 
+   * If the feature name is found in any subtype (recursively) of the type
+   *   - given one subtype is found having the feature, 
+   *     continue the checking of subsequent features in the path - to see if there's some path where all the features are found.
+   *     -- if so, return PathValid.POSSIBLE.
+   *     -- if not, loop to try other subtypes.
+   *   - if no subtypes have all the features, return PathValid.NEVER. 
+   *     
+   *   The subtypes are descended when the feature name isn't a feature of a subtype, to see if a sub-sub-type
+   *     might define the feature.  
+   *   The subtypes for one type are iterated while they have no match at any depth for the feature name
+   *      
+   * @param type the type whose subtypes should be checked
+   * @param fName
+   * @param nextPath
+   * @return
+   */
+  private static final PathValid isPathValidInSubtypes(TypeImpl type, String fName, Deque<String> nextPath) {
+    for (TypeImpl subtype : type.getDirectSubtypes()) {
+      FeatureImpl fi = subtype.getFeatureByBaseName(fName); 
+      if (fi != null) {
+        if (PathValid.POSSIBLE == isPathValid(fi.getRangeImpl(), nextPath, PathValid.POSSIBLE)) { // check subsequent types.
+          return PathValid.POSSIBLE;
+        } else {
+          continue; // try another subtype
+        }
+      } else { // look in sub-sub-types for feature
+        if (PathValid.POSSIBLE == isPathValidInSubtypes(subtype, fName, nextPath)) {
+          return PathValid.POSSIBLE;
+        }
       }
-    }
+    }  // loop for all subtypes, looking for a POSSIBLE path
+    return PathValid.NEVER;
   }
 
 }