[maven-release-plugin]  copy for tag uimaj-2.6.0

git-svn-id: https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-2.6.0@1592862 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl.java
index 9979cfc..411c392 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl.java
@@ -202,6 +202,9 @@
     return getFeatureByBaseName(featureName);
   }
 
+  /**
+   * guaranteed to be non-null, but might be empty list
+   */
   public List<Feature> getFeatures() {
     int[] feats = this.ts.ll_getAppropriateFeatures(this.code);
     List<Feature> list = new ArrayList<Feature>(feats.length);
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/impl/JCasHashMap.java b/uimaj-core/src/main/java/org/apache/uima/jcas/impl/JCasHashMap.java
index e3934ed..ca828da 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/impl/JCasHashMap.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/impl/JCasHashMap.java
@@ -110,30 +110,40 @@
   // you have to also put a call to jcas.showJfsFromCaddrHistogram() at the end of the run
   private static final boolean TUNE = false;
 
-  /** 
-   * must be a power of 2, > 0 
-   * public for testing
-   */
-  public static final int DEFAULT_CONCURRENCY_LEVEL;
-      
-  private static final int PROBE_ADDR_INDEX = 0;
-  private static final int PROBE_DELTA_INDEX = 1;
-  
-  private static int nextHigherPowerOf2(int i) {
+  static int nextHigherPowerOf2(int i) {
     return (i < 1) ? 1 : Integer.highestOneBit(i) << ( (Integer.bitCount(i) == 1 ? 0 : 1));
   }
 
+  /** 
+   * must be a power of 2, > 0 
+   * package private for testing
+   * 
+   * not final to allow test case to reset it
+   */
+  static int DEFAULT_CONCURRENCY_LEVEL;
+  
   static {
     int cores = Runtime.getRuntime().availableProcessors();
     // cores:lvl   0:1  1:1  2:2  3-15:4  16-31:8  32-63:16  else 32  
     DEFAULT_CONCURRENCY_LEVEL = 
         (cores <= 1)  ? 1 :
-        (cores == 2)  ? 2 :
-        (cores <= 15) ? 4 :
-        (cores <= 31) ? 8 :
-        (cores <= 63) ? 16 :
-                        32;    
+        (cores <= 4)  ? 2 :  // assumption: cores used for other work, too
+        (cores <= 32) ? 4 :
+        (cores <= 128) ? 8 :
+                        16;   // emprical guesswork, not scientifically set    
   }
+
+  static int getDEFAULT_CONCURRENCY_LEVEL() {
+    return DEFAULT_CONCURRENCY_LEVEL;
+  }
+  
+  static void setDEFAULT_CONCURRENCY_LEVEL(int dEFAULT_CONCURRENCY_LEVEL) {
+    DEFAULT_CONCURRENCY_LEVEL = nextHigherPowerOf2(dEFAULT_CONCURRENCY_LEVEL);
+//    System.out.println("JCasHashMap setting concurrency level to " + DEFAULT_CONCURRENCY_LEVEL);
+  }
+
+  private static final int PROBE_ADDR_INDEX = 0;
+  private static final int PROBE_DELTA_INDEX = 1;
     
   private static class ReserveTopType extends TOP_Type {
     public ReserveTopType() {
@@ -141,8 +151,9 @@
     }
   }
   
-  // public for test case use
-  public static final TOP_Type RESERVE_TOP_TYPE_INSTANCE = new ReserveTopType(); 
+  // package private for test case use
+  static final TOP_Type RESERVE_TOP_TYPE_INSTANCE = new ReserveTopType(); 
+  
   private static boolean isReserve(FeatureStructureImpl m) {
     return m != null && ((TOP)m).jcasType == RESERVE_TOP_TYPE_INSTANCE;
   }
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparer.java b/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparer.java
index 08b3a8b..90a07e2 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparer.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparer.java
@@ -19,24 +19,30 @@
 
 package org.apache.uima.cas_data.impl;
 
-import java.util.HashMap;
+import static junit.framework.Assert.assertTrue;
+
+import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
+import java.util.Set;
 
 import junit.framework.Assert;
 
 import org.apache.uima.cas.ArrayFS;
+import org.apache.uima.cas.BooleanArrayFS;
+import org.apache.uima.cas.ByteArrayFS;
 import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.CommonArrayFS;
+import org.apache.uima.cas.DoubleArrayFS;
 import org.apache.uima.cas.FSIterator;
 import org.apache.uima.cas.Feature;
 import org.apache.uima.cas.FeatureStructure;
 import org.apache.uima.cas.FloatArrayFS;
 import org.apache.uima.cas.IntArrayFS;
+import org.apache.uima.cas.LongArrayFS;
+import org.apache.uima.cas.ShortArrayFS;
 import org.apache.uima.cas.SofaFS;
 import org.apache.uima.cas.StringArrayFS;
 import org.apache.uima.cas.Type;
-import org.apache.uima.cas.impl.CASImpl;
-import org.apache.uima.cas.text.AnnotationFS;
 
 /**
  * A non-perfect CAS equality checker for JUnit.
@@ -69,7 +75,7 @@
   }
 
   public static void assertEqualViews(CAS c1, CAS c2) {
-    Map<FeatureStructure, FeatureStructure> visited = new HashMap<FeatureStructure, FeatureStructure>();
+    Set<FeatureStructure> visited = new HashSet<FeatureStructure>();
     
     FSIterator<FeatureStructure> it1 = c1.getIndexRepository().getAllIndexedFS(c1.getTypeSystem().getTopType());
     FSIterator<FeatureStructure> it2 = c2.getIndexRepository().getAllIndexedFS(c2.getTypeSystem().getTopType());
@@ -86,24 +92,27 @@
   }
 
   public static void assertEquals(FeatureStructure fs1, FeatureStructure fs2) {
-    assertEquals(fs1, fs2, new HashMap<FeatureStructure, FeatureStructure>());
+    assertEquals(fs1, fs2, new HashSet<FeatureStructure>());
   }
 
-  public static void assertEquals(FeatureStructure fs1, FeatureStructure fs2, Map<FeatureStructure, FeatureStructure> visited) {
+  public static void assertEquals(FeatureStructure fs1, FeatureStructure fs2, Set<FeatureStructure> visited) {
     if (fs1 == null) {
       Assert.assertNull(fs2);
       return;
     } else {
       Assert.assertNotNull(fs2);
     }
-
-    if (visited.containsKey(fs1)) {
+    
+    if (!visited.add(fs1)) {  // true if item already in the set
       return;
     }
-    visited.put(fs1, fs1);
 
     // System.out.println("Comparing " + fs1.getType().getName());
     Assert.assertEquals(fs1.getType().getName(), fs2.getType().getName());
+    
+    if (fs1 instanceof SofaFS) {
+      return;
+    }
 
     List<Feature> features1 = fs1.getType().getFeatures();
     List<Feature> features2 = fs2.getType().getFeatures();
@@ -119,70 +128,106 @@
 
       if (fs1.getCAS().getTypeSystem().subsumes(
               fs1.getCAS().getTypeSystem().getType(CAS.TYPE_NAME_STRING), rangeType1)) {
-        Assert.assertEquals(fs1.getStringValue(feat1), fs2.getStringValue(feat2));
+        assertEqualsNullIsEmpty(fs1.getStringValue(feat1), fs2.getStringValue(feat2));
+      } else if (compareArrayFSs(rangeTypeName, fs1, feat1, fs2, feat2, visited)) {
+        continue;
       } else if (CAS.TYPE_NAME_INTEGER.equals(rangeTypeName)) {
         Assert.assertEquals(fs1.getIntValue(feat1), fs2.getIntValue(feat2));
       } else if (CAS.TYPE_NAME_FLOAT.equals(rangeTypeName)) {
-        Assert.assertEquals(fs1.getFloatValue(feat1), fs2.getFloatValue(feat2), 0);
-      } else if (CAS.TYPE_NAME_STRING_ARRAY.equals(rangeTypeName)) {
-        StringArrayFS arrayFS1 = (StringArrayFS) fs1.getFeatureValue(feat1);
-        StringArrayFS arrayFS2 = (StringArrayFS) fs2.getFeatureValue(feat2);
-        if ((arrayFS1 == null) && (arrayFS2 == null)) {
-          // ok
-        } else {
-          Assert.assertEquals(arrayFS1.size(), arrayFS2.size());
-          for (int j = 0; j < arrayFS1.size(); j++) {
-            // Temporary workaround for UIMA-2490 - null and "" string values
-            String s1 = arrayFS1.get(j);
-            String s2 = arrayFS2.get(j);
-            if ((s1 == null) && (s2 != null) && (s2.length() == 0)) {
-              continue;
-            }
-            if ((s2 == null) && (s1 != null) && (s1.length() == 0)) {
-              continue;
-            }
-            Assert.assertEquals(arrayFS1.get(j), arrayFS2.get(j));
-          }
-        }
-      } else if (CAS.TYPE_NAME_INTEGER_ARRAY.equals(rangeTypeName)) {
-        IntArrayFS arrayFS1 = (IntArrayFS) fs1.getFeatureValue(feat1);
-        IntArrayFS arrayFS2 = (IntArrayFS) fs2.getFeatureValue(feat2);
-        if ((arrayFS1 == null) && (arrayFS2 == null)) {
-          // ok
-        } else {
-          Assert.assertEquals(arrayFS1.size(), arrayFS2.size());
-          for (int j = 0; j < arrayFS1.size(); j++) {
-            Assert.assertEquals(arrayFS1.get(j), arrayFS2.get(j));
-          }
-        }
-      } else if (CAS.TYPE_NAME_FLOAT_ARRAY.equals(rangeTypeName)) {
-        FloatArrayFS arrayFS1 = (FloatArrayFS) fs1.getFeatureValue(feat1);
-        FloatArrayFS arrayFS2 = (FloatArrayFS) fs2.getFeatureValue(feat2);
-        if ((arrayFS1 == null) && (arrayFS2 == null)) {
-          // ok
-        } else {
-          Assert.assertEquals(arrayFS1.size(), arrayFS2.size());
-          for (int j = 0; j < arrayFS1.size(); j++) {
-            Assert.assertEquals(arrayFS1.get(j), arrayFS2.get(j), 0);
-          }
-        }
-      } else if (CAS.TYPE_NAME_FS_ARRAY.equals(rangeTypeName)) {
-        ArrayFS arrayFS1 = (ArrayFS) fs1.getFeatureValue(feat1);
-        ArrayFS arrayFS2 = (ArrayFS) fs2.getFeatureValue(feat2);
-        if ((arrayFS1 == null) && (arrayFS2 == null)) {
-          // ok
-        } else {
-          Assert.assertEquals(arrayFS1.size(), arrayFS2.size());
-          for (int j = 0; j < arrayFS1.size(); j++) {
-            assertEquals(arrayFS1.get(j), arrayFS2.get(j), visited);
-          }
-        }
-      } else // single feature value
-      {
+        Assert.assertEquals(fs1.getFloatValue(feat1), fs2.getFloatValue(feat2), 0);        
+      } else if (CAS.TYPE_NAME_BYTE.equals(rangeTypeName)) {
+        Assert.assertEquals(fs1.getByteValue(feat1), fs2.getByteValue(feat2));
+      } else if (CAS.TYPE_NAME_SHORT.equals(rangeTypeName)) {
+        Assert.assertEquals(fs1.getShortValue(feat1), fs2.getShortValue(feat2));
+      } else if (CAS.TYPE_NAME_LONG.equals(rangeTypeName)) {
+        Assert.assertEquals(fs1.getLongValue(feat1), fs2.getLongValue(feat2));
+      } else if (CAS.TYPE_NAME_DOUBLE.equals(rangeTypeName)) {
+        Assert.assertEquals(fs1.getDoubleValue(feat1), fs2.getDoubleValue(feat2));
+      } else { // single feature value
         FeatureStructure fsVal1 = fs1.getFeatureValue(feat1);
         FeatureStructure fsVal2 = fs2.getFeatureValue(feat2);
         assertEquals(fsVal1, fsVal2, visited);
       }
     }
   }
+  
+  // returns true if the items were arrays
+  public static boolean compareArrayFSs(String rangeTypeName, FeatureStructure arrayFS1fs, Feature feat1, FeatureStructure arrayFS2fs, Feature feat2, Set<FeatureStructure> visited) {
+    
+    if (CAS.TYPE_NAME_STRING_ARRAY.equals(rangeTypeName) ||
+        CAS.TYPE_NAME_SHORT_ARRAY.equals(rangeTypeName) ||
+        CAS.TYPE_NAME_LONG_ARRAY.equals(rangeTypeName) ||
+        CAS.TYPE_NAME_INTEGER_ARRAY.equals(rangeTypeName) ||
+        CAS.TYPE_NAME_FLOAT_ARRAY.equals(rangeTypeName) ||
+        CAS.TYPE_NAME_DOUBLE_ARRAY.equals(rangeTypeName) ||
+        CAS.TYPE_NAME_BYTE_ARRAY.equals(rangeTypeName) ||
+        CAS.TYPE_NAME_BOOLEAN_ARRAY.equals(rangeTypeName) ||
+        CAS.TYPE_NAME_FS_ARRAY.equals(rangeTypeName)) {
+
+      CommonArrayFS arrayFS1 = (CommonArrayFS)arrayFS1fs.getFeatureValue(feat1);
+      CommonArrayFS arrayFS2 = (CommonArrayFS)arrayFS2fs.getFeatureValue(feat2);
+      
+      if ((arrayFS1 == null) && (arrayFS2 == null)) {
+        return true; // is ok
+      } else if (arrayFS1 != null && arrayFS2 != null) {        
+        
+        Assert.assertEquals(arrayFS1.size(), arrayFS2.size());
+        
+        for (int j = 0; j < arrayFS1.size(); j++) {
+          if (arrayFS1      instanceof ArrayFS) {
+              Assert.assertTrue(arrayFS2 instanceof ArrayFS);
+              assertEquals(((ArrayFS)arrayFS1).get(j), ((ArrayFS)arrayFS2).get(j), visited);
+          } else if (arrayFS1 instanceof BooleanArrayFS) {
+              assertTrue(arrayFS2 instanceof BooleanArrayFS);
+              Assert.assertEquals(((BooleanArrayFS)arrayFS1).get(j), ((BooleanArrayFS)arrayFS2).get(j));
+          } else if (arrayFS1 instanceof ByteArrayFS) {
+            assertTrue(arrayFS2 instanceof ByteArrayFS);
+            Assert.assertEquals(((ByteArrayFS)arrayFS1).get(j), ((ByteArrayFS)arrayFS2).get(j));
+          } else if (arrayFS1 instanceof DoubleArrayFS) {
+            assertTrue(arrayFS2 instanceof DoubleArrayFS);
+            Assert.assertEquals(((DoubleArrayFS)arrayFS1).get(j), ((DoubleArrayFS)arrayFS2).get(j));
+          } else if (arrayFS1 instanceof FloatArrayFS) {
+            assertTrue(arrayFS2 instanceof FloatArrayFS);
+            Assert.assertEquals(((FloatArrayFS)arrayFS1).get(j), ((FloatArrayFS)arrayFS2).get(j));
+          } else if (arrayFS1 instanceof IntArrayFS) {
+            assertTrue(arrayFS2 instanceof IntArrayFS);
+            Assert.assertEquals(((IntArrayFS)arrayFS1).get(j), ((IntArrayFS)arrayFS2).get(j));
+          } else if (arrayFS1 instanceof LongArrayFS) {
+            assertTrue(arrayFS2 instanceof LongArrayFS);
+            Assert.assertEquals(((LongArrayFS)arrayFS1).get(j), ((LongArrayFS)arrayFS2).get(j));
+          } else if (arrayFS1 instanceof ShortArrayFS) {
+            assertTrue(arrayFS2 instanceof ShortArrayFS);
+            Assert.assertEquals(((ShortArrayFS)arrayFS1).get(j), ((ShortArrayFS)arrayFS2).get(j));
+          } else if (arrayFS1 instanceof StringArrayFS) {
+            assertTrue(arrayFS2 instanceof StringArrayFS);
+            // Temporary workaround for UIMA-2490 - null and "" string values
+            assertEqualsNullIsEmpty(((StringArrayFS)arrayFS1).get(j), ((StringArrayFS)arrayFS2).get(j));
+          }
+        }
+      } else {
+        assertTrue(String.format("One array was null, the other not-null%n  array1=%s%n  array2=%s%n",
+                                 arrayFS1fs, arrayFS2fs),
+                   false);
+      }
+      return true;
+    }
+    return false;
+  }
+    
+  public static void assertEqualsNullIsEmpty(String s1, String s2) {
+    // override the Assert.assertEquals for strings to make null and "" be equal
+    if (((s1 == null) && (s2 != null) && (s2.length() == 0)) || 
+        ((s2 == null) && (s1 != null) && (s1.length() == 0))) {
+      return;
+    }
+    if ((s1 != null) && (s2 != null)) {
+      Assert.assertEquals(s1, s2);
+      return;
+    }
+    if ((s1 == null) && (s2 == null)) {
+      return;
+    }
+    assertTrue(String.format("one string value was null,  the other not%n  s1=%s%n  s2=%s%n", s1, s2), false);
+  }
+
 }
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparerViewChange.java b/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparerViewChange.java
index b92f548..f870ec8 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparerViewChange.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparerViewChange.java
@@ -19,27 +19,14 @@
 
 package org.apache.uima.cas_data.impl;
 
-import java.util.HashMap;
+import static junit.framework.Assert.assertTrue;
+
 import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
-import junit.framework.Assert;
-import static junit.framework.Assert.*;
-
-import org.apache.uima.cas.ArrayFS;
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.FSIterator;
-import org.apache.uima.cas.Feature;
 import org.apache.uima.cas.FeatureStructure;
-import org.apache.uima.cas.FloatArrayFS;
-import org.apache.uima.cas.IntArrayFS;
-import org.apache.uima.cas.SofaFS;
-import org.apache.uima.cas.StringArrayFS;
-import org.apache.uima.cas.Type;
-import org.apache.uima.cas.impl.CASImpl;
-import org.apache.uima.cas.text.AnnotationFS;
 
 /**
  * A non-perfect CAS equality checker for JUnit with different views
@@ -50,20 +37,14 @@
   
   private final CAS view1;
   private final CAS view2;
-  private final String view1Name;
-  private final String view2Name;
-  
-  private final Set<FeatureStructure> visited = new HashSet<FeatureStructure>();
-  
+    
   public CasComparerViewChange(CAS view1, CAS view2) {
     this.view1 = view1;
     this.view2 = view2;
-    view1Name = view1.getViewName();
-    view2Name = view2.getViewName();
   }
   
   public void assertEqualViews() {
-    visited.clear();
+    Set<FeatureStructure> visited = new HashSet<FeatureStructure>();
     FSIterator<FeatureStructure> it1 = view1.getIndexRepository().getAllIndexedFS(view1.getTypeSystem().getTopType());
     FSIterator<FeatureStructure> it2 = view2.getIndexRepository().getAllIndexedFS(view2.getTypeSystem().getTopType());
     while (it1.isValid()) {
@@ -71,113 +52,12 @@
 
       FeatureStructure fs1 = it1.get();
       FeatureStructure fs2 = it2.get();
-      assertFsEqual(fs1, fs2);
+
+      CasComparer.assertEquals(fs1, fs2, visited);
       
       it1.moveToNext();
       it2.moveToNext();
     }
   }
-  
- private void assertFsEqual(FeatureStructure fs1, FeatureStructure fs2) {
-    if (fs1 == null) {
-      assertNull(fs2);
-    } else {
-      assertNotNull(fs2);
-    }
-
-    if (visited.contains(fs1) || null == fs1) {
-      return;
-    }
-    visited.add(fs1);
-
-    // System.out.println("Comparing " + fs1.getType().getName());
-    assertEquals(fs1.getType().getName(), fs2.getType().getName());
-
-    if (fs1 instanceof SofaFS &&
-        ((SofaFS)fs1).getSofaID().equals(view1Name) &&
-        ((SofaFS)fs2).getSofaID().equals(view2Name)) {
-      return;
-    }
-    
-    List<Feature> features1 = fs1.getType().getFeatures();
-    List<Feature> features2 = fs2.getType().getFeatures();
-    for (int i = 0; i < features1.size(); i++) {
-      Feature feat1 = features1.get(i);
-      Feature feat2 = features2.get(i);
-      // System.out.println("Comparing " + feat1.getName());
-      Type rangeType1 = feat1.getRange();
-      Type rangeType2 = feat2.getRange();
-      Assert.assertEquals(rangeType1.getName(), rangeType2.getName());
-      // System.out.println("Range type " + rangeType1);
-      String rangeTypeName = rangeType1.getName();
-
-      if (fs1.getCAS().getTypeSystem().subsumes(
-              fs1.getCAS().getTypeSystem().getType(CAS.TYPE_NAME_STRING), rangeType1)) {
-        assertEquals(fs1.getStringValue(feat1), fs2.getStringValue(feat2));
-      } else if (CAS.TYPE_NAME_INTEGER.equals(rangeTypeName)) {
-        assertEquals(fs1.getIntValue(feat1), fs2.getIntValue(feat2));
-      } else if (CAS.TYPE_NAME_FLOAT.equals(rangeTypeName)) {
-        assertEquals(fs1.getFloatValue(feat1), fs2.getFloatValue(feat2), 0);
-      } else if (CAS.TYPE_NAME_STRING_ARRAY.equals(rangeTypeName)) {
-        StringArrayFS arrayFS1 = (StringArrayFS) fs1.getFeatureValue(feat1);
-        StringArrayFS arrayFS2 = (StringArrayFS) fs2.getFeatureValue(feat2);
-        if ((arrayFS1 == null) && (arrayFS2 == null)) {
-          // ok
-        } else {
-          Assert.assertEquals(arrayFS1.size(), arrayFS2.size());
-          for (int j = 0; j < arrayFS1.size(); j++) {
-            // Temporary workaround for UIMA-2490 - null and "" string values
-            String s1 = arrayFS1.get(j);
-            String s2 = arrayFS2.get(j);
-            if ((s1 == null) && (s2 != null) && (s2.length() == 0)) {
-              continue;
-            }
-            if ((s2 == null) && (s1 != null) && (s1.length() == 0)) {
-              continue;
-            }
-            assertEquals(arrayFS1.get(j), arrayFS2.get(j));
-          }
-        }
-      } else if (CAS.TYPE_NAME_INTEGER_ARRAY.equals(rangeTypeName)) {
-        IntArrayFS arrayFS1 = (IntArrayFS) fs1.getFeatureValue(feat1);
-        IntArrayFS arrayFS2 = (IntArrayFS) fs2.getFeatureValue(feat2);
-        if ((arrayFS1 == null) && (arrayFS2 == null)) {
-          // ok
-        } else {
-          assertEquals(arrayFS1.size(), arrayFS2.size());
-          for (int j = 0; j < arrayFS1.size(); j++) {
-            assertEquals(arrayFS1.get(j), arrayFS2.get(j));
-          }
-        }
-      } else if (CAS.TYPE_NAME_FLOAT_ARRAY.equals(rangeTypeName)) {
-        FloatArrayFS arrayFS1 = (FloatArrayFS) fs1.getFeatureValue(feat1);
-        FloatArrayFS arrayFS2 = (FloatArrayFS) fs2.getFeatureValue(feat2);
-        if ((arrayFS1 == null) && (arrayFS2 == null)) {
-          // ok
-        } else {
-          assertEquals(arrayFS1.size(), arrayFS2.size());
-          for (int j = 0; j < arrayFS1.size(); j++) {
-            assertEquals(arrayFS1.get(j), arrayFS2.get(j), 0);
-          }
-        }
-      } else if (CAS.TYPE_NAME_FS_ARRAY.equals(rangeTypeName)) {
-        ArrayFS arrayFS1 = (ArrayFS) fs1.getFeatureValue(feat1);
-        ArrayFS arrayFS2 = (ArrayFS) fs2.getFeatureValue(feat2);
-        if ((arrayFS1 == null) && (arrayFS2 == null)) {
-          // ok
-        } else {
-          assertEquals(arrayFS1.size(), arrayFS2.size());
-          for (int j = 0; j < arrayFS1.size(); j++) {
-            assertFsEqual(arrayFS1.get(j), arrayFS2.get(j));
-          }
-        }
-      } else // single feature value
-      {
-        FeatureStructure fsVal1 = fs1.getFeatureValue(feat1);
-        FeatureStructure fsVal2 = fs2.getFeatureValue(feat2);
-        assertFsEqual(fsVal1, fsVal2);
-      }
-    }
-  }
- 
+   
 }
diff --git a/uimaj-core/src/test/java/org/apache/uima/jcas/impl/JCasHashMapCompareTest.java b/uimaj-core/src/test/java/org/apache/uima/jcas/impl/JCasHashMapCompareTest.java
index fbeabb2..7b37590 100644
--- a/uimaj-core/src/test/java/org/apache/uima/jcas/impl/JCasHashMapCompareTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/jcas/impl/JCasHashMapCompareTest.java
@@ -56,15 +56,16 @@
 

   

   public void testComp() throws Exception {

-    Thread.sleep(0000);

-    int numberOfThreads =  MultiThreadUtils.PROCESSORS;    

+    Thread.sleep(0000);  // set non-zero to delay so you can get yourkit tooling hooked up, if using yourkit

+    int numberOfThreads =  MultiThreadUtils.PROCESSORS; 

+    numberOfThreads = Math.min(8, JCasHashMap.nextHigherPowerOf2(numberOfThreads));  // avoid too big slowdown on giant machines.

     System.out.format("test JCasHashMapComp with %d threads%n", numberOfThreads);

     runCustom(numberOfThreads);

     runConCur(numberOfThreads);

-    runCustom(numberOfThreads);

-    runConCur(numberOfThreads);

-    runCustom(numberOfThreads);

-    runConCur(numberOfThreads);

+    runCustom(numberOfThreads*2);

+    runConCur(numberOfThreads*2);

+    runCustom(numberOfThreads*4);

+    runConCur(numberOfThreads*4);

 //    stats("custom", runCustom(numberOfThreads));  // not accurate, use yourkit retained size instead

 //    stats("concur", runConCur(numberOfThreads));

     Set<Integer> ints = new HashSet<Integer>();

@@ -84,8 +85,10 @@
     final ConcurrentMap<Integer, FeatureStructureImpl> m = 

         new ConcurrentHashMap<Integer, FeatureStructureImpl>(200, 0.75F, numberOfThreads);

     concurrentMap = m;

-    final Object[] waiters = new Object[16];

-    for (int i = 0; i < 16; i++) {

+    

+    final int numberOfWaiters = numberOfThreads*2;

+    final Object[] waiters = new Object[numberOfWaiters];

+    for (int i = 0; i < numberOfWaiters; i++) {

       waiters[i] = new Object();

     }

     MultiThreadUtils.Run2isb run2isb= new MultiThreadUtils.Run2isb() {

@@ -94,7 +97,7 @@
 //        int founds = 0, puts = 0;

         for (int i = 0; i < sizeOfTest*threadNumber; i++) {

           final int key = hash(i, threadNumber) / 2;

-          final Object waiter = waiters[key & 15];

+          final Object waiter = waiters[key & (numberOfWaiters - 1)];

           FeatureStructureImpl fs = m.putIfAbsent(key, new TOP(key, JCasHashMap.RESERVE_TOP_TYPE_INSTANCE));

           while (fs != null && ((TOP)fs).jcasType == JCasHashMap.RESERVE_TOP_TYPE_INSTANCE) {

             // someone else reserved this

@@ -134,7 +137,7 @@
           public void run() {

             m.clear();

         }});

-    System.out.format("JCasCompTest - concur, time = %,f seconds%n", (System.currentTimeMillis() - start) / 1000.f);

+    System.out.format("JCasCompTest - concur, threads = %d, time = %,f seconds%n", numberOfThreads, (System.currentTimeMillis() - start) / 1000.f);

     return m.size();

   }

   

@@ -168,7 +171,7 @@
           public void run() {

             m.clear();

         }});

-    System.out.format("JCasCompTest - custom, time = %,f seconds%n", (System.currentTimeMillis() - start) / 1000.f);

+    System.out.format("JCasCompTest - custom, threads = %d, time = %,f seconds%n", numberOfThreads, (System.currentTimeMillis() - start) / 1000.f);

     m.showHistogram();

     return m.getApproximateSize();

   }

diff --git a/uimaj-core/src/test/java/org/apache/uima/jcas/impl/JCasHashMapTest.java b/uimaj-core/src/test/java/org/apache/uima/jcas/impl/JCasHashMapTest.java
index f419803..0df8788 100644
--- a/uimaj-core/src/test/java/org/apache/uima/jcas/impl/JCasHashMapTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/jcas/impl/JCasHashMapTest.java
@@ -60,25 +60,23 @@
    

   public void testBasic() {

     JCasHashMap m;

-    int defaultLevel = JCasHashMap.DEFAULT_CONCURRENCY_LEVEL;

-    if (defaultLevel < 2) {

-      System.out.println("JCasHashMap  skipping basic, nbr of processors is " + Runtime.getRuntime().availableProcessors());

-      return;

+

+    for (int i = 1; i <= 128; i *= 2) {

+      JCasHashMap.setDEFAULT_CONCURRENCY_LEVEL(i);

+      // test default concurrency level adjusted down 

+      m = new JCasHashMap(32 * i, true);

+      assertEquals( i, m.getConcurrencyLevel());

+      m = new JCasHashMap(16 * i, true);

+      assertEquals(Math.max(1, i / 2), m.getConcurrencyLevel());

+      

+      //test capacity adjusted up

+      m = new JCasHashMap(32 * i, true, i);

+      assertEquals( 32 * i, m.getCapacity());

+      m = new JCasHashMap(31 * i, true, i);

+      assertEquals( 32 * i, m.getCapacity());

+      m = new JCasHashMap(16 * i, true, i);

+      assertEquals( 32 * i, m.getCapacity());

     }

-    

-    // test default concurrency level adjusted down 

-    m = new JCasHashMap(32 * defaultLevel, true);

-    assertEquals( defaultLevel, m.getConcurrencyLevel());

-    m = new JCasHashMap(16 * defaultLevel, true);

-    assertEquals(Math.max(1, defaultLevel / 2), m.getConcurrencyLevel());

-    

-    //test capacity adjusted up

-    m = new JCasHashMap(32 * defaultLevel, true, defaultLevel);

-    assertEquals( 32 * defaultLevel, m.getCapacity());

-    m = new JCasHashMap(31 * defaultLevel, true, defaultLevel);

-    assertEquals( 32 * defaultLevel, m.getCapacity());

-    m = new JCasHashMap(16 * defaultLevel, true, defaultLevel);

-    assertEquals( 32 * defaultLevel, m.getCapacity());    

   }

   

   public void testWithPerf()  {

@@ -98,86 +96,93 @@
   public void testMultiThread() throws Exception {

     final Random random = new Random();

     int numberOfThreads = MultiThreadUtils.PROCESSORS;    

-    System.out.format("test JCasHashMap with %d threads%n", numberOfThreads);

-    

-    final JCasHashMap m = new JCasHashMap(200, true); // true = do use cache 

+    System.out.format("test JCasHashMap with up to %d threads%n", numberOfThreads);

 

-    MultiThreadUtils.Run2isb run2isb = new MultiThreadUtils.Run2isb() {

-      

-      public void call(int threadNumber, int repeatNumber, StringBuilder sb) {

-        for (int k = 0; k < 4; k++) {

-          for (int i = 0; i < SIZE / 4; i++) {

-            final int key = addrs[random.nextInt(SIZE / 16)];

-            FeatureStructureImpl fs = m.getReserve(key);

-            if (null == fs) {

-              m.put(new TOP(key, FAKE_TOP_TYPE_INSTANCE));

+    

+    for (int th = 2; th <= numberOfThreads; th *=2) {

+      JCasHashMap.setDEFAULT_CONCURRENCY_LEVEL(th);

+      final JCasHashMap m = new JCasHashMap(200, true); // true = do use cache   

+      MultiThreadUtils.Run2isb run2isb = new MultiThreadUtils.Run2isb() {

+        

+        public void call(int threadNumber, int repeatNumber, StringBuilder sb) {

+          for (int k = 0; k < 4; k++) {

+            for (int i = 0; i < SIZE / 4; i++) {

+              final int key = addrs[random.nextInt(SIZE / 16)];

+              FeatureStructureImpl fs = m.getReserve(key);

+              if (null == fs) {

+                m.put(new TOP(key, FAKE_TOP_TYPE_INSTANCE));

+              }

+            }

+            try {

+              Thread.sleep(0, random.nextInt(1000));

+            } catch (InterruptedException e) {

+              // TODO Auto-generated catch block

+              e.printStackTrace();

             }

           }

-          try {

-            Thread.sleep(0, random.nextInt(1000));

-          } catch (InterruptedException e) {

-            // TODO Auto-generated catch block

-            e.printStackTrace();

-          }

+  //        System.out.println(sb.toString());

         }

-//        System.out.println(sb.toString());

-      }

-    };  

-    MultiThreadUtils.tstMultiThread("JCasHashMapTest",  numberOfThreads,  10, run2isb,

-        new Runnable() {

-          public void run() {

-            m.clear();

-          }});

+      };  

+      MultiThreadUtils.tstMultiThread("JCasHashMapTest",  numberOfThreads,  10, run2isb,

+          new Runnable() {

+            public void run() {

+              m.clear();

+            }});

+    }

   }

 

   public void testMultiThreadCompare() throws Exception {

     final Random random = new Random();

     int numberOfThreads = MultiThreadUtils.PROCESSORS;    

-    System.out.format("test JCasHashMap with compare with %d threads%n", numberOfThreads);

+    System.out.format("test JCasHashMap with compare with up to %d threads%n", numberOfThreads);

 

     final ConcurrentMap<Integer, FeatureStructureImpl> check = 

         new ConcurrentHashMap<Integer, FeatureStructureImpl>(SIZE, .5F, numberOfThreads * 2);

-    final JCasHashMap m = new JCasHashMap(200, true); // true = do use cache 

-

-    MultiThreadUtils.Run2isb run2isb = new MultiThreadUtils.Run2isb() {

-      

-      public void call(int threadNumber, int repeatNumber, StringBuilder sb) {

-        for (int k = 0; k < 4; k++) {

-          for (int i = 0; i < SIZE / 4; i++) {

-            final int key = addrs[random.nextInt(SIZE / 16)];

-            FeatureStructureImpl fs = m.getReserve(key);

-            if (null == fs) {

-              fs = new TOP(key, FAKE_TOP_TYPE_INSTANCE);

-              check.put(key, fs);  

-              m.put(fs);

-            } else {

-              FeatureStructureImpl fscheck = check.get(key);

-              if (fscheck == null || fscheck != fs) {

-                String msg = String.format("JCasHashMapTest miscompare, repeat=%,d, count=%,d key=%,d"

-                    + ", checkKey=%s JCasHashMapKey=%,d",

-                    k, i, key, (null == fscheck) ? "null" : Integer.toString(fscheck.getAddress()), fs.getAddress());

-                System.err.println(msg);

-                throw new RuntimeException(msg);

+    

+    for (int th = 2; th <= numberOfThreads; th *= 2) {

+      JCasHashMap.setDEFAULT_CONCURRENCY_LEVEL(th);

+      final JCasHashMap m = new JCasHashMap(200, true); // true = do use cache 

+  

+      MultiThreadUtils.Run2isb run2isb = new MultiThreadUtils.Run2isb() {

+        

+        public void call(int threadNumber, int repeatNumber, StringBuilder sb) {

+          for (int k = 0; k < 4; k++) {

+            for (int i = 0; i < SIZE / 4; i++) {

+              final int key = addrs[random.nextInt(SIZE / 16)];

+              FeatureStructureImpl fs = m.getReserve(key);

+              if (null == fs) {

+                fs = new TOP(key, FAKE_TOP_TYPE_INSTANCE);

+                check.put(key, fs);  

+                m.put(fs);

+              } else {

+                FeatureStructureImpl fscheck = check.get(key);

+                if (fscheck == null || fscheck != fs) {

+                  String msg = String.format("JCasHashMapTest miscompare, repeat=%,d, count=%,d key=%,d"

+                      + ", checkKey=%s JCasHashMapKey=%,d",

+                      k, i, key, (null == fscheck) ? "null" : Integer.toString(fscheck.getAddress()), fs.getAddress());

+                  System.err.println(msg);

+                  throw new RuntimeException(msg);

+                }

               }

             }

+            try {

+              Thread.sleep(0, random.nextInt(1000));

+            } catch (InterruptedException e) {

+              // TODO Auto-generated catch block

+              e.printStackTrace();

+            }

           }

-          try {

-            Thread.sleep(0, random.nextInt(1000));

-          } catch (InterruptedException e) {

-            // TODO Auto-generated catch block

-            e.printStackTrace();

-          }

+  //        System.out.println(sb.toString());

         }

-//        System.out.println(sb.toString());

-      }

-    };  

-    MultiThreadUtils.tstMultiThread("JCasHashMapTest",  numberOfThreads,  10, run2isb, 

-        new Runnable() {

-          public void run() {

-            check.clear();

-            m.clear();

-          }

-    });

+      };  

+      MultiThreadUtils.tstMultiThread("JCasHashMapTest",  numberOfThreads,  10, run2isb, 

+          new Runnable() {

+            public void run() {

+              check.clear();

+              m.clear();

+            }

+      });

+    }

   }

   /**

    * Create situation

@@ -194,58 +199,62 @@
     if (numberOfThreads < 2) {

       return;

     }

-    System.out.format("test JCasHashMap collide with %d threads", numberOfThreads);

+    System.out.format("test JCasHashMap collide with up to %d threads", numberOfThreads);

     final Random r = new Random();

-    final JCasHashMap m = new JCasHashMap(200, true); // true = do use cache 

     final int hashKey = 15;

     final TOP fs = new TOP(hashKey, FAKE_TOP_TYPE_INSTANCE);

-    

-    final Thread[] threads = new Thread[numberOfThreads];

-    final FeatureStructureImpl[] found = new FeatureStructureImpl[numberOfThreads];

-    

-    for (int i = 0; i < numberOfThreads; i++) {

-      final int finalI = i;

-      threads[i] = new Thread(new Runnable() {

-        public void run() {

-          try {

-            Thread.sleep(r.nextInt(5));

-          } catch (InterruptedException e) {

+

+    for (int th = 2; th <= numberOfThreads; th *= 2) {

+      JCasHashMap.setDEFAULT_CONCURRENCY_LEVEL(th);

+      final JCasHashMap m = new JCasHashMap(200, true); // true = do use cache 

+  

+      final Thread[] threads = new Thread[numberOfThreads];

+      final FeatureStructureImpl[] found = new FeatureStructureImpl[numberOfThreads];

+      

+      for (int i = 0; i < numberOfThreads; i++) {

+        final int finalI = i;

+        threads[i] = new Thread(new Runnable() {

+          public void run() {

+            try {

+              Thread.sleep(r.nextInt(5));

+            } catch (InterruptedException e) {

+            }

+             found[finalI] = m.getReserve(hashKey);

           }

-           found[finalI] = m.getReserve(hashKey);

+        });

+        threads[i].start();

+      }

+      Thread.sleep(100); 

+      // verify that one thread finished, others are waiting

+      int numberWaiting = 0;

+      int threadFinished = -1;

+      for (int i = 0; i < numberOfThreads; i++) {

+        if (threads[i].isAlive()) {

+          numberWaiting ++;

+        } else {

+          threadFinished = i;

         }

-      });

-      threads[i].start();

-    }

-    Thread.sleep(100); 

-    // verify that one thread finished, others are waiting

-    int numberWaiting = 0;

-    int threadFinished = -1;

-    for (int i = 0; i < numberOfThreads; i++) {

-      if (threads[i].isAlive()) {

-        numberWaiting ++;

-      } else {

-        threadFinished = i;

       }

-    }

-    

-    assertEquals(numberOfThreads - 1, numberWaiting);

-    m.put(fs);

-    found[threadFinished] = fs;

-    Thread.sleep(10);  

-    

-    numberWaiting = 0;

-    for (int i = 0; i < numberOfThreads; i++) {

-      if (threads[i].isAlive()) {

-        numberWaiting ++;

+      

+      assertEquals(numberOfThreads - 1, numberWaiting);

+      m.put(fs);

+      found[threadFinished] = fs;

+      Thread.sleep(10);  

+      

+      numberWaiting = 0;

+      for (int i = 0; i < numberOfThreads; i++) {

+        if (threads[i].isAlive()) {

+          numberWaiting ++;

+        }

       }

-    }

-    assertEquals(0, numberWaiting);

-    System.out.format("JCasHashMapTest collide,  found = %s%n", intList(found));

-    for (FeatureStructureImpl f : found) {

-      if (f != fs) {

-        System.err.format("JCasHashMapTest miscompare fs = %s,  f = %s%n", fs, (f == null) ? "null" : f);

+      assertEquals(0, numberWaiting);

+//      System.out.format("JCasHashMapTest collide,  found = %s%n", intList(found));

+      for (FeatureStructureImpl f : found) {

+        if (f != fs) {

+          System.err.format("JCasHashMapTest miscompare fs = %s,  f = %s%n", fs, (f == null) ? "null" : f);

+        }

+        assertTrue(f == fs);

       }

-      assertTrue(f == fs);

     }

   }

   

@@ -322,54 +331,69 @@
   

   public void testGrowth() {

     System.out.println("JCasHashMapTest growth");

-    int cores = Runtime.getRuntime().availableProcessors();

-    double loadfactor = .6;

-    int sub_capacity = 64;

-    int subs = (cores < 17) ? cores / 2 :

-               (cores < 33) ? 8 + (cores - 16) / 4 : 

-                             12 + (cores - 24) / 8;

-    int agg_capacity = subs * sub_capacity;

-    JCasHashMap m = new JCasHashMap(agg_capacity, true); // true = do use cache 

-    assertTrue(m.getApproximateSize() == 0);

-     

-    int switchpoint = (int)Math.floor(agg_capacity * loadfactor);

-    fill(switchpoint, m);

-    assertTrue(checkSubsCapacity(m, 64, 128));

-    System.out.println("JCasHashMapTest growth - adding 1 past switchpoint");

-    m.put(new TOP(addrs[switchpoint + 1], null));

-    assertTrue(checkSubsCapacity(m, 64, 128));

-    

-    m.clear();

-    assertTrue(checkSubsCapacity(m, 64, 128));

-

-

-    fill(switchpoint, m);

-    assertTrue(checkSubsCapacity(m, 64, 128));

-    m.put(new TOP(addrs[switchpoint + 1], null));

-    assertTrue(checkSubsCapacity(m, 64, 128));

-

-    m.clear();  // size is above switchpoint, so no shrinkage

-    assertTrue(checkSubsCapacity(m, 64, 128));

-    m.clear();  // size is 0, so first time shrinkage a possibility

-    assertTrue(checkSubsCapacity(m, 64, 128)); // but we don't shrink on first time

-    m.clear(); 

-    assertTrue(checkSubsCapacity(m, 64, 64));  // but we do on second time

-    m.clear(); 

-    assertTrue(checkSubsCapacity(m, 64, 64));

-    m.clear(); 

-    assertTrue(checkSubsCapacity(m, 64, 64));  // don't shrink below minimum

+    for (int th = 2; th <= 128; th *= 2) {

+      JCasHashMap.setDEFAULT_CONCURRENCY_LEVEL(th);

+      double loadfactor = .6;  // from JCasHashMap impl

+      int sub_capacity = 32;   // from JCasHashMap impl

+      int subs = th;

+      int agg_capacity = subs * sub_capacity;

+      JCasHashMap m = new JCasHashMap(agg_capacity, true); // true = do use cache 

+      assertEquals(0, m.getApproximateSize());

+      assertEquals(agg_capacity, m.getCapacity());

+       

+      int switchpoint = (int)Math.floor(agg_capacity * loadfactor);

+      fill(switchpoint, m);

+      System.out.print("JCasHashMapTest: after fill to switch point: ");

+      assertTrue(checkSubsCapacity(m, sub_capacity));

+      System.out.print("JCasHashMapTest: after 1 past switch point:  ");

+      m.put(new TOP(addrs[switchpoint + 1], null));

+      assertTrue(checkSubsCapacity(m, sub_capacity));

+      

+      m.clear();

+      System.out.print("JCasHashMapTest: after clear:                ");

+      assertTrue(checkSubsCapacity(m, sub_capacity));

+  

+  

+      fill(switchpoint, m);

+      System.out.print("JCasHashMapTest: after fill to switch point: ");

+      assertTrue(checkSubsCapacity(m, sub_capacity));

+      m.put(new TOP(addrs[switchpoint + 1], null));

+      System.out.print("JCasHashMapTest: after 1 past switch point:  ");

+      assertTrue(checkSubsCapacity(m, sub_capacity));

+  

+      m.clear();  // size is above switchpoint, so no shrinkage

+      System.out.print("JCasHashMapTest: after clear (size above sp: ");

+      assertTrue(checkSubsCapacity(m, sub_capacity));

+      m.clear();  // size is 0, so first time shrinkage a possibility

+      System.out.print("JCasHashMapTest: clear (size below sp:       ");

+      assertTrue(checkSubsCapacity(m, sub_capacity)); // but we don't shrink on first time

+      m.clear(); 

+      System.out.print("JCasHashMapTest: clear (size below 2nd time: ");

+      assertTrue(checkSubsCapacity(m, sub_capacity, sub_capacity));  // but we do on second time

+//      m.clear(); 

+//      System.out.print("JCasHashMapTest: clear (size below 3rd time: ");

+//      assertTrue(checkSubsCapacity(m, sub_capacity, sub_capacity));

+//      m.clear(); 

+//      System.out.print("JCasHashMapTest: clear (size below 4th time: ");

+//      assertTrue(checkSubsCapacity(m, sub_capacity, sub_capacity));  // don't shrink below minimum

+    }

   }

 

+  private boolean checkSubsCapacity(JCasHashMap m, int v) {

+    return checkSubsCapacity(m, v, v * 2);

+  }

+  

+  // check: the subMaps should be mostly of size v, but some might be of size v*2.

   private boolean checkSubsCapacity(JCasHashMap m, int v, int v2) {

     int[] caps = m.getCapacities();

     for (int i : caps) {

       if (i == v || i == v2 ) {

         continue;

       }

-      System.err.format("JCasHashMapTest: expected %d or %d, but got %s%n", v, v2, intList(caps));

+      System.err.format("expected %d or %d, but got %s%n", v, v2, intList(caps));

       return false;

     }

-    System.out.format("JCasHashMapTest: capacities are: %s%n", intList(caps));

+    System.out.format("%s%n", intListPm(caps, v));

     return true;

   }

   

@@ -381,6 +405,14 @@
     return sb.toString();

   }

   

+  private String intListPm(int[] a, int smaller) {

+    StringBuilder sb = new StringBuilder(a.length);

+    for (int i : a) {

+      sb.append(i == smaller ? '.' : '+');

+    }

+    return sb.toString();

+  }

+  

   private String intList(FeatureStructureImpl[] a) {

     StringBuilder sb = new StringBuilder();

     for (FeatureStructureImpl i : a) {

diff --git a/uimaj-tools/src/main/java/org/apache/uima/tools/jcasgen/Jg.java b/uimaj-tools/src/main/java/org/apache/uima/tools/jcasgen/Jg.java
index af0fbed..7dc1ffa 100644
--- a/uimaj-tools/src/main/java/org/apache/uima/tools/jcasgen/Jg.java
+++ b/uimaj-tools/src/main/java/org/apache/uima/tools/jcasgen/Jg.java
@@ -150,28 +150,25 @@
         continue;
       }
       String typeName = type.getName();
-      List fs = type.getFeatures();
-      List features = new ArrayList(fs.size());
-      if (null != fs) {
-        for (int i = 0; i < fs.size(); i++) {
-          Feature f = (Feature) fs.get(i);
-          String fName = f.getName();
-          String fTypeName = fName.substring(0, fName.indexOf(':'));
-          if (typeName.equals(fTypeName))
-            features.add(f);
-        }
-        FeatureDescription[] fds = new FeatureDescription[features.size()];
-        for (int i = 0; i < features.size(); i++) {
-          FeatureDescription fd = UIMAFramework.getResourceSpecifierFactory()
-                  .createFeatureDescription();
-          Feature f = (Feature) features.get(i);
-          fd.setName(f.getShortName());
-          fd.setRangeTypeName(f.getRange().getName());
-          fds[i] = fd;
-        }
-        extendableBuiltInTypes.put(typeName, fds);
-      } else
-        extendableBuiltInTypes.put(typeName, emptyFds);
+      List<Feature> fs = type.getFeatures();
+      List<Feature> features = new ArrayList<Feature>(fs.size());
+      for (int i = 0; i < fs.size(); i++) {
+        Feature f = fs.get(i);
+        String fName = f.getName();
+        String fTypeName = fName.substring(0, fName.indexOf(':'));
+        if (typeName.equals(fTypeName))
+          features.add(f);
+      }
+      FeatureDescription[] fds = new FeatureDescription[features.size()];
+      for (int i = 0; i < features.size(); i++) {
+        FeatureDescription fd = UIMAFramework.getResourceSpecifierFactory()
+                .createFeatureDescription();
+        Feature f = (Feature) features.get(i);
+        fd.setName(f.getShortName());
+        fd.setRangeTypeName(f.getRange().getName());
+        fds[i] = fd;
+      }
+      extendableBuiltInTypes.put(typeName, fds);
     }
   }