[UIMA-6115] copy uv3/uimaj-v3/tags to uimaj/tags

git-svn-id: https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0@1865573 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/PearPackagingMavenPlugin/pom.xml b/PearPackagingMavenPlugin/pom.xml
index aec4c43..a9d2e18 100644
--- a/PearPackagingMavenPlugin/pom.xml
+++ b/PearPackagingMavenPlugin/pom.xml
@@ -44,13 +44,13 @@
        element, and just changing the following two properties -->  

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/PearPackagingMavenPlugin

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/PearPackagingMavenPlugin

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/PearPackagingMavenPlugin

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/PearPackagingMavenPlugin

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/PearPackagingMavenPlugin

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/PearPackagingMavenPlugin

     </url>

   </scm>

   

diff --git a/PearPackagingMavenPlugin/src/main/java/org/apache/uima/pear/tools/PearPackagingMojo.java b/PearPackagingMavenPlugin/src/main/java/org/apache/uima/pear/tools/PearPackagingMojo.java
index 302e51b..c9a7db3 100644
--- a/PearPackagingMavenPlugin/src/main/java/org/apache/uima/pear/tools/PearPackagingMojo.java
+++ b/PearPackagingMavenPlugin/src/main/java/org/apache/uima/pear/tools/PearPackagingMojo.java
@@ -94,7 +94,7 @@
   /**
    * The maven project.
    */
-  @Component
+  @Parameter( defaultValue = "${project}", readonly = true )
   private MavenProject      project;
 
   // the PEAR packaging directory contains all the stuff that is added to
diff --git a/README b/README
index b1c1a2a..a161c14 100644
--- a/README
+++ b/README
@@ -2,14 +2,15 @@
       Apache UIMA (Unstructured Information Management Architecture) 
       --------------------------------------------------------------
       
-This file applies to UIMA-SDK version 3.0.0-alpha1 and subsequent versions.
+This file applies to UIMA-SDK version 3.0.0 and subsequent versions.
+Java 8 is required.
 
 Backwards Compatibility
 -----------------------
 
 Version 3 is a major new release, and many APIs have been augmented.
 Existing version 2 UIMA Pipelines are expected to run with Version 3,
-after any JCas classes have been migrated.  
+after any non-built-in JCas classes have been migrated.  
 
 The documentation contains a new book, "UIMA Version 3 User's Guide",
 which explains the new features, the migration process and tool,
@@ -44,14 +45,14 @@
 Supported Platforms
 --------------------
 
-Apache UIMA v3.0.0 requires Java version 8 or later; it has been tested with Sun/Oracle Java 8, 
-and IBM 8.
+Apache UIMA v3.0.0 requires Java version 8; it has been tested with Oracle Java 8, 
+and IBM Java 8.
 
 Running the Eclipse plugin tooling for UIMA requires you start Eclipse using a Java 8 or later, as well.
 
 Running the migration tool requires running with a Java JDK, not a Java JRE.
 
-The supported platforms are: Windows, Linux, and Mac OS X. Other platforms and Java (8+) 
+The supported platforms are: Windows, Linux, and Mac OS X. Other platform 
 implementations should work, but have not been significantly tested.
 
 Many of the scripts in the /bin directory invoke Java. They use the value of the environment variable, JAVA_HOME, 
@@ -97,5 +98,6 @@
 Getting Started
 ----------------
 
-Version 3 requires migration for existing Version 2 deployments that use JCas.  For instructions on this, please
+For existing Version 2 deployments that use non-built-in JCas classes, Version 3 requires migration 
+or regeneration of these classes.  For instructions on how to do this migration, please
 read the documentation for Version 3 located in the docs subdirectory.  
\ No newline at end of file
diff --git a/RELEASE_NOTES.html b/RELEASE_NOTES.html
index 41b66b3..ef7a9ef 100644
--- a/RELEASE_NOTES.html
+++ b/RELEASE_NOTES.html
@@ -20,31 +20,20 @@
    -->
 <html>
 <head>
-  <title>Apache UIMA v3.0.0-alpha Release Notes</title>
+  <title>Apache UIMA v3.0.0 Release Notes</title>
 </head>
 <body>
-<h1>Apache UIMA (Unstructured Information Management Architecture) v3.0.0-alpha Release Notes</h1>
+<h1>Apache UIMA (Unstructured Information Management Architecture) v3.0.0 Release Notes</h1>
 
 <h2>Contents</h2>
 <p>
-<a href="#alpha">Alpha release status notice</a><br/>
 <a href="#what.is.uima">What is UIMA?</a><br/>
 <a href="#major.changes">Major Changes in this Release</a><br/>
 <a href="#get.involved">How to Get Involved</a><br/>
 <a href="#report.issues">How to Report Issues</a><br/>
 <a href="#list.issues">List of JIRA Issues Fixed in this Release</a><br/>
 </p>  
-   
-<h2><a id="alpha">0. Alpha release status</a></h2>
-  <p>This is an alpha release, done in order to expand the 
-     community of people doing initial testing on this new release.
-     As such, it is possible that bugs or deficiencies may be found
-     which might require changes to APIs.</p>
-     
-  <p>Following a period of alpha testing, depending on the results,
-     we will proceed to more official releases.
-     </p>
-     
+        
 <h2><a id="what.is.uima">1. What is UIMA?</a></h2>
 
      <p>
@@ -92,45 +81,57 @@
 
 <h2><a id="major.changes">Major Changes in this Release</a></h2>
 
-<p>Version 3 is a major reimplementation of the internals of UIMA,
-with many significant changes.  A one-time migration step is required if 
-JCas cover classes are being used.  
+<p>Version 3 is a major reimplementation of the internals of 
+the Java version of UIMA to support better integration with
+Java 8, alignment with modern memory hierarchies for 
+better performance, and multiple functional enhancements and
+improvements.</p>
+<p>
+If non-built-in JCas cover classes are being used,
+a one-time regeneration or migration step is required for these.  
 Please read the Version 3 users guide located in the docs directory
-for information on these changes and the migration tool.
+for information on these changes and the migration tool which can
+aid in migrating existing JCas class definitions.
 </p>
 
-<p>A very brief summary of Version 3:
+<p>A very brief summary of Version 3:</p>
 <ul><li>Feature Structures become Java Objects, 
-and may be Garbage Collected.</li>
-<li>Many performance improvements</li>
+subject to Garbage Collection, just like any other objects, 
+when no longer reachable.</li>
 <li>Iterating over indexes no longer throws 
-ConcurrentModificationException</li>
-<li>Support for arbitrary Java Objects in the CAS</li>
-<li>Using above, new built-ins for ArrayList style
-lists of Feature Structures and ints, and a FSHashSet</li>
+ConcurrentModificationException.</li>
+<li>Support for arbitrary Java Objects in the CAS, 
+using special custom implementations of JCas cover classes for those.</li>
+<li>Using the above new capability, new semi-built-ins for three new types: ArrayList style
+lists of Feature Structures and ints, and an FSHashSet</li>
 <li>New "select" framework for flexible 
-access to Feature Structures</li>
+access to Feature Structures, that can ignore typeOrdering keys in indexes.</li>
 <li>Integration with Java 8 facilities such as Streams</li>
-</p>
+<li>Logging framework upgraded, supporting embedding UIMA in other frameworks using 
+popular logging APIs</li>
+<li>There are many performance improvements</li>
+</ul>
 
-<p>Please read the overview section of the Version 3 
-users guide for more.</p>
+
+<p>Please read the Version 3 users guide for more details.</p>
+
+<p>Specific changes in this release versus the previous beta release include</p>
+<ul>
+  <li>Support of a v2 id compatibility mode, for backwards compatibility, enables use of the LowLevelCAS API getFSForRef(int)
+  <li>Improved support for sharing a set of loaded JCas classes with different, but somewhat compatible type systems
+  <li>New semi-builtin types: a FSLinkedHashSet, and a map from "int"s to Feature Structures
+</ul>
  
 <h3>API changes</h3>
- <p>Many APIs were changed, typically by adding new capability.  
- However, we attempt to preserve existing APIs, for backward compatibility. 
+ <p>There is an API compatibility report covering the non-internal APIs;
+   see <a href="api-change-report.html">change report</a> for the list of API changes
+   since version 2.10.2.
  </p>
  
 <h2><a id="list.issues">Full list of JIRA Issues affecting this Release</a></h2>
 Click <a href="issuesFixed/jira-report.html">issuesFixed/jira-report.hmtl</a> for the list of 
 issues affecting this release.  
    
-<h2><a id="alpha">Alpha Release</a></h2>
-<p>Because this release makes major changes to UIMA internals,
-this is an alpha release of version 3.  It is being made to get 
-wider community involvement in testing and feedback.  
-The APIs may change, and features
-may be added or altered.<\p>
 
 <p>Please use the mailing lists 
 ( http://uima.apache.org/mail-lists.html ) 
diff --git a/aggregate-uimaj-docbooks/pom.xml b/aggregate-uimaj-docbooks/pom.xml
index 5b9d5e2..9ccabde 100644
--- a/aggregate-uimaj-docbooks/pom.xml
+++ b/aggregate-uimaj-docbooks/pom.xml
@@ -42,13 +42,13 @@
        element, and just changing the following two properties -->  

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/aggregate-uimaj-docbooks

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/aggregate-uimaj-docbooks

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/aggregate-uimaj-docbooks

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/aggregate-uimaj-docbooks

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/aggregate-uimaj-docbooks

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/aggregate-uimaj-docbooks

     </url>

   </scm>

   

diff --git a/aggregate-uimaj-eclipse-plugins/pom.xml b/aggregate-uimaj-eclipse-plugins/pom.xml
index 9e72f30..eabda18 100644
--- a/aggregate-uimaj-eclipse-plugins/pom.xml
+++ b/aggregate-uimaj-eclipse-plugins/pom.xml
@@ -44,13 +44,13 @@
        element, and just changing the following two properties -->

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/aggregate-uimaj-eclipse-plugins

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/aggregate-uimaj-eclipse-plugins

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/aggregate-uimaj-eclipse-plugins

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/aggregate-uimaj-eclipse-plugins

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/aggregate-uimaj-eclipse-plugins

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/aggregate-uimaj-eclipse-plugins

     </url>

   </scm>

 

diff --git a/aggregate-uimaj/pom.xml b/aggregate-uimaj/pom.xml
index 2d83671..eb2a1c4 100644
--- a/aggregate-uimaj/pom.xml
+++ b/aggregate-uimaj/pom.xml
@@ -43,13 +43,13 @@
        element, and just changing the following two properties -->  

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/aggregate-uimaj

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/aggregate-uimaj

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/aggregate-uimaj

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/aggregate-uimaj

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/aggregate-uimaj

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/aggregate-uimaj

     </url>

   </scm>

   

diff --git a/api-change-report.html b/api-change-report.html
new file mode 100644
index 0000000..2976d26
--- /dev/null
+++ b/api-change-report.html
@@ -0,0 +1,60 @@
+	<!--

+    ***************************************************************

+    * Licensed to the Apache Software Foundation (ASF) under one

+    * or more contributor license agreements.  See the NOTICE file

+    * distributed with this work for additional information

+    * regarding copyright ownership.  The ASF licenses this file

+    * to you under the Apache License, Version 2.0 (the

+    * "License"); you may not use this file except in compliance

+    * with the License.  You may obtain a copy of the License at

+    *

+    *   http://www.apache.org/licenses/LICENSE-2.0

+    * 

+    * Unless required by applicable law or agreed to in writing,

+    * software distributed under the License is distributed on an

+    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+    * KIND, either express or implied.  See the License for the

+    * specific language governing permissions and limitations

+    * under the License.

+    ***************************************************************

+   -->

+<html>

+<head>

+  <title>API Change Report - Apache UIMA</title>

+</head>

+<body>

+<h1>Apache UIMA (Unstructured Information Management Architecture) API Change Report</h1>

+

+<h2>Contents</h2>

+<p>

+<a href="#description">What is an API change report?</a><br/>

+<a target="_blank" href="uimaj-core/api-change-report/japicmp.html">API Changes: uimaj-core</a><br/>

+<a target="_blank" href="uimaj-cpe/api-change-report/japicmp.html">API Changes: uimaj-cpe</a><br/>

+<a target="_blank" href="uimaj-json/api-change-report/japicmp.html">API Changes: uimaj-json</a><br/>

+<a href-"#running-more-reports">Running your own custom reports</a>

+</p>  

+   

+<h2><a id="description">What is an API change report?</a></h2>

+

+     <p>

+  			Three of the modules in the UIMA Java SDK track API changes from version to version.

+  			The changes between this current version and the last previously released version are

+  			reported below.  Each report includes a summary of Classes that were changed, together with

+  			a flag indicating if the change was a source or binary incompatible change.

+  			More details about each change are available further down in the report.

+  	 </p>

+  	 

+  	 <p>

+  	   Follow the links above to get the report for each of the 3 modules.		

+  	 </p>

+  	 

+ 

+<h2><a id="running-more-reports">Running additional change reports</a></h2>

+<p>The reports are generated by an open source tool, 

+<a target="_blank" href="http://siom79.github.io/japicmp/">japicmp</a>, which compares two versions of

+a Java Jar and generates the report.  See that website for details on how to run this for arbitrary versions, if you

+want to compare other versions.

+</p> 

+    

+</body>

+</html>
\ No newline at end of file
diff --git a/jVinci/pom.xml b/jVinci/pom.xml
index ada659b..d3232a3 100644
--- a/jVinci/pom.xml
+++ b/jVinci/pom.xml
@@ -46,13 +46,13 @@
        element, and just changing the following two properties -->  
   <scm>
     <connection>
-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/jVinci
+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/jVinci
     </connection>
     <developerConnection>
-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/jVinci
+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/jVinci
     </developerConnection>
     <url>
-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/jVinci
+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/jVinci
     </url>
   </scm>
   
diff --git a/jVinci/src/main/java/org/apache/vinci/transport/document/XMLToVinci.java b/jVinci/src/main/java/org/apache/vinci/transport/document/XMLToVinci.java
index 278410d..bf640ed 100644
--- a/jVinci/src/main/java/org/apache/vinci/transport/document/XMLToVinci.java
+++ b/jVinci/src/main/java/org/apache/vinci/transport/document/XMLToVinci.java
@@ -29,6 +29,8 @@
 
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
 import org.xml.sax.XMLReader;
 import org.xml.sax.helpers.DefaultHandler;
 
@@ -48,6 +50,15 @@
  */
 public class XMLToVinci {
 
+  private static final SAXParserFactory spf = SAXParserFactory.newInstance();
+  static {
+    try {
+      spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+    } catch (SAXNotRecognizedException | SAXNotSupportedException
+        | ParserConfigurationException e) {
+      System.err.println("Warning: SAXParserFactory didn't recognized the feature http://apache.org/xml/features/disallow-doctype-decl");
+    }
+  }
   /**
    * Utility class not intended to be instantiated.
    */
@@ -243,7 +254,9 @@
   public static VinciFrame xmlToVinciFrame(Reader r) throws ServiceException {
     XMLReader xr;
     try {
-      xr = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
+      synchronized(spf) {
+        xr = spf.newSAXParser().getXMLReader();
+      }
     } catch (SAXException e) {
       throw new ServiceException("Error creating SAX Parser: " + e);
     } catch (ParserConfigurationException e) {
@@ -251,7 +264,13 @@
     }
     // prevent undeclared namespace warnings.
     try {
-      xr.setFeature("http://xml.org/sax/features/namespaces", false);
+      try {
+        xr.setFeature("http://xml.org/sax/features/namespaces", false);
+      } catch (SAXNotRecognizedException e) {
+        System.err.println("Warning: XMLReader didn't recognize the feature http://xml.org/sax/features/namespaces");
+      } catch (SAXNotSupportedException e) {
+        System.err.println("Warning: XMLReader doesn't support the feature http://xml.org/sax/features/namespaces");
+      }
       VinciFrameHandler handler = new VinciFrameHandler();
       xr.setContentHandler(handler);
       xr.setErrorHandler(handler);
@@ -284,7 +303,9 @@
   public static AFrame xmlToAFrame(Reader r) throws ServiceException {
     XMLReader xr;
     try {
-      xr = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
+      synchronized (spf) {
+        xr = spf.newSAXParser().getXMLReader();
+      }
     } catch (SAXException e) {
       throw new ServiceException("Error creating SAX Parser: " + e);
     } catch (ParserConfigurationException e) {
diff --git a/jVinci/src/main/java/org/apache/vinci/transport/document/XMLToXTalk.java b/jVinci/src/main/java/org/apache/vinci/transport/document/XMLToXTalk.java
index 54d4202..dd11c81 100644
--- a/jVinci/src/main/java/org/apache/vinci/transport/document/XMLToXTalk.java
+++ b/jVinci/src/main/java/org/apache/vinci/transport/document/XMLToXTalk.java
@@ -37,16 +37,17 @@
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParserFactory;
 
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.DefaultHandler;
-
 import org.apache.vinci.debug.Debug;
 import org.apache.vinci.debug.FatalException;
 import org.apache.vinci.transport.ServiceException;
 import org.apache.vinci.transport.XTalkTransporter;
 import org.apache.vinci.transport.util.XMLConverter;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
 
 /**
  * Class for parsing an XML document and converting directly to XTalk.
@@ -215,7 +216,15 @@
       XTalkTransporter.writeInt(1, os);
       XMLReader xr;
       try {
-        xr = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
+        SAXParserFactory spf = SAXParserFactory.newInstance();
+        try {
+          spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+        } catch (SAXNotRecognizedException e) {
+          System.err.println("Warning: SAXParserFactory didn't recognized feature http://apache.org/xml/features/disallow-doctype-decl");
+        } catch (SAXNotSupportedException e) {
+          System.err.println("Warning: SAXParserFactory doesn't support feature http://apache.org/xml/features/disallow-doctype-decl");
+        }
+        xr = spf.newSAXParser().getXMLReader();
       } catch (SAXException e) {
         throw new ServiceException("Error creating SAX Parser: " + e);
       } catch (ParserConfigurationException e) {
diff --git a/jVinci/src/main/java/org/apache/vinci/transport/vns/service/ServiceRegistry.java b/jVinci/src/main/java/org/apache/vinci/transport/vns/service/ServiceRegistry.java
index cf09299..e7eac20 100644
--- a/jVinci/src/main/java/org/apache/vinci/transport/vns/service/ServiceRegistry.java
+++ b/jVinci/src/main/java/org/apache/vinci/transport/vns/service/ServiceRegistry.java
@@ -29,6 +29,7 @@
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
 
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -407,7 +408,15 @@
   /* Methods to load and save registry info */
   public void load(String fname) throws Exception {
 
-    DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+    try {
+      dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+    } catch (ParserConfigurationException e) {
+      System.err.println("Warning: DocumentBuilderFactory doesn't support the feature http://apache.org/xml/features/disallow-doctype-decl");
+    }
+  
+    DocumentBuilder docBuilder = dbf.newDocumentBuilder();
+
 
     FileReader readme = new FileReader(fname);
     Document doc;
diff --git a/jcasgen-maven-plugin/pom.xml b/jcasgen-maven-plugin/pom.xml
index 77e08fd..ae76ead 100644
--- a/jcasgen-maven-plugin/pom.xml
+++ b/jcasgen-maven-plugin/pom.xml
@@ -44,13 +44,13 @@
        element, and just changing the following two properties -->
   <scm>
     <connection>
-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/jcasgen-maven-plugin
+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/jcasgen-maven-plugin
     </connection>
     <developerConnection>
-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/jcasgen-maven-plugin
+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/jcasgen-maven-plugin
     </developerConnection>
     <url>
-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/jcasgen-maven-plugin
+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/jcasgen-maven-plugin
     </url>
   </scm>
 
@@ -92,6 +92,11 @@
 			<version>2.0</version>
 			<scope>test</scope>
 		</dependency>
+		<dependency>
+		  <groupId>org.slf4j</groupId>
+		  <artifactId>slf4j-jdk14</artifactId>
+		  <scope>test</scope>
+		</dependency>
 	</dependencies>
 	<build>
 	  <pluginManagement>
diff --git a/jcasgen-maven-plugin/src/it/classpath/pom.xml b/jcasgen-maven-plugin/src/it/classpath/pom.xml
index 111a061..a76f930 100644
--- a/jcasgen-maven-plugin/src/it/classpath/pom.xml
+++ b/jcasgen-maven-plugin/src/it/classpath/pom.xml
@@ -20,17 +20,23 @@
 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 	<modelVersion>4.0.0</modelVersion>
 
-  <parent>
-    <groupId>org.apache.uima</groupId>
-    <artifactId>parent-pom</artifactId>
-    <version>4</version>
-    <relativePath />
-  </parent>
-
 	<groupId>test</groupId>
 	<artifactId>classpath</artifactId>
 	<version>1.0.0-SNAPSHOT</version>
 	<build>
+    <!-- https://issues.apache.org/jira/browse/UIMA-5368 -->
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.1</version>
+          <configuration>
+            <source>1.7</source>
+            <target>1.7</target>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>    
 		<plugins>
 			<plugin>
 				<groupId>org.apache.uima</groupId>
diff --git a/jcasgen-maven-plugin/src/it/m2e/pom.xml b/jcasgen-maven-plugin/src/it/m2e/pom.xml
index 9e01ce4..e85457d 100644
--- a/jcasgen-maven-plugin/src/it/m2e/pom.xml
+++ b/jcasgen-maven-plugin/src/it/m2e/pom.xml
@@ -22,13 +22,6 @@
 	xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 	<modelVersion>4.0.0</modelVersion>
 
-  <parent>
-    <groupId>org.apache.uima</groupId>
-    <artifactId>parent-pom</artifactId>
-    <version>4</version>
-    <relativePath />
-  </parent>
-
 	<groupId>org.apache.uima</groupId>
 	<artifactId>org.apache.uima.tools.jcasgen.maven.tests.m2e</artifactId>
 	<version>0.9.2-SNAPSHOT</version>
@@ -53,6 +46,19 @@
 		<main.localRepositoryUrl>@localRepositoryUrl@</main.localRepositoryUrl>
 	</properties>
 	<build>
+    <!-- https://issues.apache.org/jira/browse/UIMA-5368 -->
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.1</version>
+          <configuration>
+            <source>1.7</source>
+            <target>1.7</target>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>    
 		<plugins>
 			<plugin>
 				<groupId>org.eclipse.tycho</groupId>
diff --git a/jcasgen-maven-plugin/src/it/m2e/projects/jcasgen/classpath/pom.xml b/jcasgen-maven-plugin/src/it/m2e/projects/jcasgen/classpath/pom.xml
index be04637..13ae329 100644
--- a/jcasgen-maven-plugin/src/it/m2e/projects/jcasgen/classpath/pom.xml
+++ b/jcasgen-maven-plugin/src/it/m2e/projects/jcasgen/classpath/pom.xml
@@ -23,6 +23,19 @@
 	<artifactId>classpath</artifactId>
 	<version>1.0.0-SNAPSHOT</version>
 	<build>
+    <!-- https://issues.apache.org/jira/browse/UIMA-5368 -->
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.1</version>
+          <configuration>
+            <source>1.7</source>
+            <target>1.7</target>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>    
 		<plugins>
 			<plugin>
 				<groupId>org.apache.uima</groupId>
diff --git a/jcasgen-maven-plugin/src/it/m2e/projects/jcasgen/crossref1/pom.xml b/jcasgen-maven-plugin/src/it/m2e/projects/jcasgen/crossref1/pom.xml
index b7d60e2..5091373 100644
--- a/jcasgen-maven-plugin/src/it/m2e/projects/jcasgen/crossref1/pom.xml
+++ b/jcasgen-maven-plugin/src/it/m2e/projects/jcasgen/crossref1/pom.xml
@@ -23,6 +23,19 @@
 	<artifactId>crossref1</artifactId>
 	<version>1.0.0-SNAPSHOT</version>
 	<build>
+    <!-- https://issues.apache.org/jira/browse/UIMA-5368 -->
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.1</version>
+          <configuration>
+            <source>1.7</source>
+            <target>1.7</target>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>    
 		<plugins>
 			<plugin>
 				<groupId>org.apache.uima</groupId>
diff --git a/jcasgen-maven-plugin/src/it/m2e/projects/jcasgen/crossref2/pom.xml b/jcasgen-maven-plugin/src/it/m2e/projects/jcasgen/crossref2/pom.xml
index a0a7213..c1507a1 100644
--- a/jcasgen-maven-plugin/src/it/m2e/projects/jcasgen/crossref2/pom.xml
+++ b/jcasgen-maven-plugin/src/it/m2e/projects/jcasgen/crossref2/pom.xml
@@ -23,6 +23,19 @@
 	<artifactId>crossref2</artifactId>
 	<version>1.0.0-SNAPSHOT</version>
 	<build>
+    <!-- https://issues.apache.org/jira/browse/UIMA-5368 -->
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.1</version>
+          <configuration>
+            <source>1.7</source>
+            <target>1.7</target>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>    
 		<plugins>
 			<plugin>
 				<groupId>org.apache.uima</groupId>
diff --git a/jcasgen-maven-plugin/src/it/m2e/projects/jcasgen/simple/pom.xml b/jcasgen-maven-plugin/src/it/m2e/projects/jcasgen/simple/pom.xml
index a2681d5..d2eff0a 100644
--- a/jcasgen-maven-plugin/src/it/m2e/projects/jcasgen/simple/pom.xml
+++ b/jcasgen-maven-plugin/src/it/m2e/projects/jcasgen/simple/pom.xml
@@ -23,6 +23,19 @@
 	<artifactId>simple</artifactId>
 	<version>1.0.0-SNAPSHOT</version>
 	<build>
+    <!-- https://issues.apache.org/jira/browse/UIMA-5368 -->
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.1</version>
+          <configuration>
+            <source>1.7</source>
+            <target>1.7</target>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>    
 		<plugins>
 			<plugin>
 				<groupId>org.apache.uima</groupId>
diff --git a/jcasgen-maven-plugin/src/it/multimodule/crossref1/pom.xml b/jcasgen-maven-plugin/src/it/multimodule/crossref1/pom.xml
index da2a0c0..016706c 100644
--- a/jcasgen-maven-plugin/src/it/multimodule/crossref1/pom.xml
+++ b/jcasgen-maven-plugin/src/it/multimodule/crossref1/pom.xml
@@ -20,17 +20,23 @@
 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 	<modelVersion>4.0.0</modelVersion>
 
-  <parent>
-    <groupId>org.apache.uima</groupId>
-    <artifactId>parent-pom</artifactId>
-    <version>4</version>
-    <relativePath />
-  </parent>
-
 	<groupId>test</groupId>
 	<artifactId>crossref1</artifactId>
 	<version>1.0.0-SNAPSHOT</version>
 	<build>
+    <!-- https://issues.apache.org/jira/browse/UIMA-5368 -->
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.1</version>
+          <configuration>
+            <source>1.7</source>
+            <target>1.7</target>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>    
 		<plugins>
 			<plugin>
 				<groupId>org.apache.uima</groupId>
@@ -55,7 +61,7 @@
 		<dependency>
 			<groupId>org.apache.uima</groupId>
 			<artifactId>uimaj-core</artifactId>
-			<version>@project.version@</version>
+			<version>@project.version@</version>     
 		</dependency>
 	</dependencies>
 </project>
\ No newline at end of file
diff --git a/jcasgen-maven-plugin/src/it/multimodule/crossref2/pom.xml b/jcasgen-maven-plugin/src/it/multimodule/crossref2/pom.xml
index 63f2c66..1d22424 100644
--- a/jcasgen-maven-plugin/src/it/multimodule/crossref2/pom.xml
+++ b/jcasgen-maven-plugin/src/it/multimodule/crossref2/pom.xml
@@ -20,17 +20,23 @@
 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 	<modelVersion>4.0.0</modelVersion>
 
-  <parent>
-    <groupId>org.apache.uima</groupId>
-    <artifactId>parent-pom</artifactId>
-    <version>4</version>
-    <relativePath />
-  </parent>
-
 	<groupId>test</groupId>
 	<artifactId>crossref2</artifactId>
 	<version>1.0.0-SNAPSHOT</version>
 	<build>
+    <!-- https://issues.apache.org/jira/browse/UIMA-5368 -->
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.1</version>
+          <configuration>
+            <source>1.7</source>
+            <target>1.7</target>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>    
 		<plugins>
 			<plugin>
 				<groupId>org.apache.uima</groupId>
@@ -60,7 +66,7 @@
 		<dependency>
 			<groupId>org.apache.uima</groupId>
 			<artifactId>uimaj-core</artifactId>
-			<version>@project.version@</version>
+			<version>@project.version@</version>     
 		</dependency>
 	</dependencies>
 </project>
\ No newline at end of file
diff --git a/jcasgen-maven-plugin/src/it/multimodule/pom.xml b/jcasgen-maven-plugin/src/it/multimodule/pom.xml
index 6d62070..e8cad5e 100644
--- a/jcasgen-maven-plugin/src/it/multimodule/pom.xml
+++ b/jcasgen-maven-plugin/src/it/multimodule/pom.xml
@@ -20,13 +20,6 @@
 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 	<modelVersion>4.0.0</modelVersion>
 
-  <parent>
-    <groupId>org.apache.uima</groupId>
-    <artifactId>parent-pom</artifactId>
-    <version>4</version>
-    <relativePath />
-  </parent>
-
 	<groupId>test</groupId>
 	<artifactId>multimodule</artifactId>
 	<version>1.0.0-SNAPSHOT</version>
diff --git a/jcasgen-maven-plugin/src/it/simple/pom.xml b/jcasgen-maven-plugin/src/it/simple/pom.xml
index 2ef1d74..aeb2455 100644
--- a/jcasgen-maven-plugin/src/it/simple/pom.xml
+++ b/jcasgen-maven-plugin/src/it/simple/pom.xml
@@ -20,17 +20,23 @@
 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 	<modelVersion>4.0.0</modelVersion>
 
-  <parent>
-    <groupId>org.apache.uima</groupId>
-    <artifactId>parent-pom</artifactId>
-    <version>4</version>
-    <relativePath />
-  </parent>
-
 	<groupId>test</groupId>
 	<artifactId>simple</artifactId>
 	<version>1.0.0-SNAPSHOT</version>
 	<build>
+    <!-- https://issues.apache.org/jira/browse/UIMA-5368 -->
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.1</version>
+          <configuration>
+            <source>1.7</source>
+            <target>1.7</target>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>    
 		<plugins>
 			<plugin>
 				<groupId>org.apache.uima</groupId>
@@ -55,7 +61,7 @@
 		<dependency>
 			<groupId>org.apache.uima</groupId>
 			<artifactId>uimaj-core</artifactId>
-			<version>@project.version@</version>
+			<version>@project.version@</version>    
 		</dependency>
 	</dependencies>
 </project>
\ No newline at end of file
diff --git a/jcasgen-maven-plugin/src/main/java/org/apache/uima/tools/jcasgen/maven/JCasGenMojo.java b/jcasgen-maven-plugin/src/main/java/org/apache/uima/tools/jcasgen/maven/JCasGenMojo.java
index 17d8ea2..d6f5c98 100644
--- a/jcasgen-maven-plugin/src/main/java/org/apache/uima/tools/jcasgen/maven/JCasGenMojo.java
+++ b/jcasgen-maven-plugin/src/main/java/org/apache/uima/tools/jcasgen/maven/JCasGenMojo.java
@@ -69,7 +69,8 @@
  */
 @Mojo(name = "generate", defaultPhase = LifecyclePhase.PROCESS_RESOURCES, requiresDependencyResolution = ResolutionScope.COMPILE)
 public class JCasGenMojo extends AbstractMojo {
-  @Component
+  
+  @Parameter( defaultValue = "${project}", readonly = true ) 
   private MavenProject project;
 
   @Component
@@ -195,7 +196,7 @@
     } finally {
       IOUtil.close(typeSystemOs);
     }
-
+    
     // skip JCasGen if there are no changes in the type system file or the files it
     // references hasDelta resolves the imports!
     if (!contextDelta && !this.hasDelta(typeSystem, classpath)) {
diff --git a/pom.xml b/pom.xml
index ed201e9..89325a1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,19 +49,19 @@
        element, and just changing the following two properties -->
   <scm>
     <connection>
-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0
+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0
     </connection>
     <developerConnection>
-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0
+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0
     </developerConnection>
     <url>
-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0
+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0
     </url>
   </scm>
 
   <properties>
     <uimaScmProject>${project.artifactId}</uimaScmProject>
-    <jiraVersion>3.0.0SDK-alpha</jiraVersion>   
+    <jiraVersion>3.0.0SDK</jiraVersion>   
     <assemblyFinalName>uimaj-${project.version}</assemblyFinalName> 
     <assemblyBinDescriptor>src/main/assembly/bin-without-jackson.xml</assemblyBinDescriptor> 
     <postNoticeText>${ibmNoticeText}</postNoticeText>    
@@ -167,19 +167,43 @@
     <dependency>
       <groupId>org.bitbucket.mstrobel</groupId>
       <artifactId>procyon-core</artifactId>
-      <version>0.5.28</version>
+      <version>0.5.32</version>
     </dependency>  
     <dependency>
       <groupId>org.bitbucket.mstrobel</groupId>
       <artifactId>procyon-compilertools</artifactId>
-      <version>0.5.28</version>
+      <version>0.5.32</version>
     </dependency>  
     <dependency>    <!-- apache v2 license  2016 checked -->
       <groupId>com.github.javaparser</groupId>
       <artifactId>javaparser-core</artifactId>
-      <version>2.5.1</version>
+      <version>3.2.2</version>
     </dependency>
-      
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency> 
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-jdk14</artifactId>
+    </dependency>
+       
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-slf4j-impl</artifactId>
+      <version>${log4j.version}</version>
+    </dependency>    
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+      <version>${log4j.version}</version>
+    </dependency>    
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+      <version>${log4j.version}</version>
+    </dependency>    
+ 
   </dependencies>
 
   
@@ -189,6 +213,14 @@
   </modules>
   
   <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+            <artifactId>maven-release-plugin</artifactId>
+            <version>2.5.3</version>
+        </plugin>
+      </plugins>
+    </pluginManagement>
     <plugins>
 
       <!-- This java doc config is for building the ones distributed with the bin packaging, and also 
@@ -236,7 +268,7 @@
 							  <additionalDependency>
 							    <groupId>com.fasterxml.jackson.core</groupId>
 						      <artifactId>jackson-core</artifactId>
-						      <version>2.4.2</version>
+						      <version>${jackson.version}</version>
 							  </additionalDependency>
 							</additionalDependencies>
             </configuration>
@@ -305,12 +337,30 @@
               </execution>
             </executions>
           </plugin>
-    
-    </plugins>
+         
+     </plugins>
   </build>
 
   <profiles>
     <profile>
+      <id>dependency-checks</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.owasp</groupId>
+            <artifactId>dependency-check-maven</artifactId>
+            <version>2.1.1</version>
+            <executions>
+              <execution>
+               <goals><goal>check</goal></goals>
+               </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+    
+    <profile>
       <id>apache-release</id>
       
       <build>
diff --git a/src/main/assembly/bin-without-jackson.xml b/src/main/assembly/bin-without-jackson.xml
index dafe481..54b997e 100644
--- a/src/main/assembly/bin-without-jackson.xml
+++ b/src/main/assembly/bin-without-jackson.xml
@@ -152,43 +152,7 @@
       <fileMode>644</fileMode> 

       <directoryMode>755</directoryMode>        

     </dependencySet>

-    

-    <dependencySet>

-      <includes>

-        <include>org.bitbucket.mstrobel:procyon-compilertools</include>

-      </includes>

-      <unpack>false</unpack>

-      <scope>runtime</scope>

-      <outputDirectory>lib</outputDirectory>

-      <useProjectArtifact>false</useProjectArtifact>

-      <fileMode>644</fileMode> 

-      <directoryMode>755</directoryMode>        

-    </dependencySet>

-

-    <dependencySet>

-      <includes>

-        <include>org.bitbucket.mstrobel:procyon-core</include>

-      </includes>

-      <unpack>false</unpack>

-      <scope>runtime</scope>

-      <outputDirectory>lib</outputDirectory>

-      <useProjectArtifact>false</useProjectArtifact>

-      <fileMode>644</fileMode> 

-      <directoryMode>755</directoryMode>        

-    </dependencySet>

-    

-     <dependencySet>

-      <includes>

-        <include>com.github.javaparser:javaparser-core</include>

-      </includes>

-      <unpack>false</unpack>

-      <scope>runtime</scope>

-      <outputDirectory>lib</outputDirectory>

-      <useProjectArtifact>false</useProjectArtifact>

-      <fileMode>644</fileMode> 

-      <directoryMode>755</directoryMode>        

-    </dependencySet>

-    

+        

     <!-- Copy each eclipse plugin into the /eclipsePlugins dir of the distribution -->

     <dependencySet>

       <includes>

@@ -209,6 +173,29 @@
       <fileMode>644</fileMode> 

       <directoryMode>755</directoryMode>        

     </dependencySet>

+    

+    <!--  loggers and other lib 3rd party jars not renamed -->

+    <dependencySet>

+      <includes>

+        <include>org.bitbucket.mstrobel:procyon-compilertools</include>      

+        <include>org.bitbucket.mstrobel:procyon-core</include>

+        <include>com.github.javaparser:javaparser-core</include>

+        <include>org.slf4j:slf4j-api</include>

+                <!--  log4j not default included 

+        <include>org.apache.logging.log4j:log4j-slf4j-impl</include>

+        <include>org.apache.logging.log4j:log4j-core</include>

+        <include>org.apache.logging.log4j:log4j-api</include>

+         -->

+        <!-- hook to built-in Java backend for slf4j included -->

+        <include>org.slf4j:slf4j-jdk14</include> 

+      </includes>

+      <unpack>false</unpack>

+      <scope>runtime</scope>

+      <outputDirectory>lib</outputDirectory>

+      <useProjectArtifact>false</useProjectArtifact>

+      <fileMode>644</fileMode> 

+      <directoryMode>755</directoryMode>        

+    </dependencySet>

   </dependencySets>

   

   <!-- Add other files - scripts, documentation, examples -->

@@ -287,6 +274,12 @@
       <fileMode>644</fileMode>

       <directoryMode>755</directoryMode>        

     </fileSet>

+    <fileSet>

+      <directory>uima-docbook-v3-users-guide/target/site</directory>

+      <outputDirectory>docs</outputDirectory>

+      <fileMode>644</fileMode>

+      <directoryMode>755</directoryMode>        

+    </fileSet>

     

     <!-- examples -->

     <fileSet>

@@ -321,17 +314,32 @@
            and we want to eliminate failures due to write permissions -->

       <directoryMode>777</directoryMode>        

     </fileSet>

+    

+    <!-- Copy the API Change reports -->

+    <fileSet>

+      <directory>uimaj-core/api-change-report</directory>

+      <outputDirectory>uimaj-core/api-change-report</outputDirectory>

+      <fileMode>644</fileMode>

+      <directoryMode>755</directoryMode>        

+    </fileSet>

+    <fileSet>

+      <directory>uimaj-cpe/api-change-report</directory>

+      <outputDirectory>uimaj-cpe/api-change-report</outputDirectory>

+      <fileMode>644</fileMode>

+      <directoryMode>755</directoryMode>        

+    </fileSet>

+

   </fileSets>

  

   <files>

     <!-- copy bin distr license and notice -->

     <file>

-      <source>src/main/readme/LICENSE</source>

+      <source>src/main/bin_distr_license_notices/LICENSE</source>

       <outputDirectory></outputDirectory>

       <fileMode>644</fileMode>

     </file>

     <file> 

-      <source>src/main/readme/NOTICE-without-jackson</source>

+      <source>src/main/bin_distr_license_notices/NOTICE-without-jackson</source>

       <outputDirectory></outputDirectory>

       <destName>NOTICE</destName>

       <fileMode>644</fileMode>    

@@ -370,5 +378,9 @@
       <outputDirectory>examples/ecore_src/org/apache/uima/examples/xmi</outputDirectory>

       <fileMode>644</fileMode> 

     </file>

+    <file>

+      <source>api-change-report.html</source>

+      <outputDirectory>.</outputDirectory>

+    </file>

   </files>

 </assembly>
\ No newline at end of file
diff --git a/src/main/assembly/bin.xml b/src/main/assembly/bin.xml
index 9d3a6cd..6ed7138 100644
--- a/src/main/assembly/bin.xml
+++ b/src/main/assembly/bin.xml
@@ -121,7 +121,7 @@
       </includes>
       <unpack>false</unpack>
       <scope>runtime</scope>
-      <outputFileNameMapping> uima-adapter-vinci.jar</outputFileNameMapping>
+      <outputFileNameMapping>uima-adapter-vinci.jar</outputFileNameMapping>
       <outputDirectory>lib</outputDirectory>
       <useProjectArtifact>false</useProjectArtifact>
       <fileMode>644</fileMode> 
@@ -151,17 +151,6 @@
       <fileMode>644</fileMode> 
       <directoryMode>755</directoryMode>        
     </dependencySet>
-    <dependencySet>
-      <includes>
-        <include>com.fasterxml.jackson.core:jackson-core</include>
-      </includes>
-      <unpack>false</unpack>
-      <scope>runtime</scope>
-      <outputDirectory>lib</outputDirectory>
-      <useProjectArtifact>false</useProjectArtifact>
-      <fileMode>644</fileMode> 
-      <directoryMode>755</directoryMode>        
-    </dependencySet>
     
     <dependencySet>
       <includes>
@@ -175,43 +164,7 @@
       <fileMode>644</fileMode> 
       <directoryMode>755</directoryMode>        
     </dependencySet>
-
-    <dependencySet>
-      <includes>
-        <include>org.bitbucket.mstrobel:procyon-compilertools</include>
-      </includes>
-      <unpack>false</unpack>
-      <scope>runtime</scope>
-      <outputDirectory>lib</outputDirectory>
-      <useProjectArtifact>false</useProjectArtifact>
-      <fileMode>644</fileMode> 
-      <directoryMode>755</directoryMode>        
-    </dependencySet>
-
-    <dependencySet>
-      <includes>
-        <include>org.bitbucket.mstrobel:procyon-core</include>
-      </includes>
-      <unpack>false</unpack>
-      <scope>runtime</scope>
-      <outputDirectory>lib</outputDirectory>
-      <useProjectArtifact>false</useProjectArtifact>
-      <fileMode>644</fileMode> 
-      <directoryMode>755</directoryMode>        
-    </dependencySet>
-    
-     <dependencySet>
-      <includes>
-        <include>com.github.javaparser:javaparser-core</include>
-      </includes>
-      <unpack>false</unpack>
-      <scope>runtime</scope>
-      <outputDirectory>lib</outputDirectory>
-      <useProjectArtifact>false</useProjectArtifact>
-      <fileMode>644</fileMode> 
-      <directoryMode>755</directoryMode>        
-    </dependencySet>
-    
+        
     <!-- Copy each eclipse plugin into the /eclipsePlugins dir of the distribution -->
     <dependencySet>
       <includes>
@@ -232,6 +185,30 @@
       <fileMode>644</fileMode> 
       <directoryMode>755</directoryMode>        
     </dependencySet>
+    
+    <!--  loggers and other lib 3rd party jars not renamed -->
+    <dependencySet>
+      <includes>
+        <include>com.fasterxml.jackson.core:jackson-core</include>
+        <include>org.bitbucket.mstrobel:procyon-compilertools</include>      
+        <include>org.bitbucket.mstrobel:procyon-core</include>
+        <include>com.github.javaparser:javaparser-core</include>
+        <include>org.slf4j:slf4j-api</include>
+        <!--  log4j not default included 
+        <include>org.apache.logging.log4j:log4j-slf4j-impl</include>
+        <include>org.apache.logging.log4j:log4j-core</include>
+        <include>org.apache.logging.log4j:log4j-api</include>
+         -->
+        <!-- hook to built-in Java backend for slf4j included -->
+        <include>org.slf4j:slf4j-jdk14</include> 
+      </includes>
+      <unpack>false</unpack>
+      <scope>runtime</scope>
+      <outputDirectory>lib</outputDirectory>
+      <useProjectArtifact>false</useProjectArtifact>
+      <fileMode>644</fileMode> 
+      <directoryMode>755</directoryMode>        
+    </dependencySet>
   </dependencySets>
   
   <!-- Add other files - scripts, documentation, examples -->
@@ -351,6 +328,26 @@
            and we want to eliminate failures due to write permissions -->
       <directoryMode>777</directoryMode>        
     </fileSet>
+    
+    <!-- Copy the API Change reports -->
+    <fileSet>
+      <directory>uimaj-core/api-change-report</directory>
+      <outputDirectory>uimaj-core/api-change-report</outputDirectory>
+      <fileMode>644</fileMode>
+      <directoryMode>755</directoryMode>        
+    </fileSet>
+    <fileSet>
+      <directory>uimaj-cpe/api-change-report</directory>
+      <outputDirectory>uimaj-cpe/api-change-report</outputDirectory>
+      <fileMode>644</fileMode>
+      <directoryMode>755</directoryMode>        
+    </fileSet>
+    <fileSet>
+      <directory>uimaj-json/api-change-report</directory>
+      <outputDirectory>uimaj-json/api-change-report</outputDirectory>
+      <fileMode>644</fileMode>
+      <directoryMode>755</directoryMode>        
+    </fileSet>
   </fileSets>
  
   <files>
@@ -399,5 +396,9 @@
       <outputDirectory>examples/ecore_src/org/apache/uima/examples/xmi</outputDirectory>
       <fileMode>644</fileMode> 
     </file>
+    <file>
+      <source>api-change-report.html</source>
+      <outputDirectory>.</outputDirectory>
+    </file>
   </files>
 </assembly>
\ No newline at end of file
diff --git a/src/main/bin_distr_license_notices/LICENSE b/src/main/bin_distr_license_notices/LICENSE
index 7808490..4b48862 100644
--- a/src/main/bin_distr_license_notices/LICENSE
+++ b/src/main/bin_distr_license_notices/LICENSE
@@ -234,4 +234,30 @@
 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+====================================================================================================
+
+This product contains SLF4J, licensed and distirbuted under the MIT license:
+
+Copyright (c) 2004-2017 QOS.ch
+ All rights reserved.
+
+ Permission is hereby granted, free  of charge, to any person obtaining
+ a  copy  of this  software  and  associated  documentation files  (the
+ "Software"), to  deal in  the Software without  restriction, including
+ without limitation  the rights to  use, copy, modify,  merge, publish,
+ distribute,  sublicense, and/or sell  copies of  the Software,  and to
+ permit persons to whom the Software  is furnished to do so, subject to
+ the following conditions:
+ 
+ The  above  copyright  notice  and  this permission  notice  shall  be
+ included in all copies or substantial portions of the Software.
+ 
+ THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
+ EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
+ MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/src/main/bin_distr_license_notices/NOTICE b/src/main/bin_distr_license_notices/NOTICE
index 824e3b6..2003a38 100644
--- a/src/main/bin_distr_license_notices/NOTICE
+++ b/src/main/bin_distr_license_notices/NOTICE
@@ -11,6 +11,8 @@
 "IBM UIMA License Agreement".
 Copyright (c) 2003, 2006 IBM Corporation.
 
+ResolverUtil.java Copyright 2005-2006 Tim Fennell
+
 # Jackson JSON processor NOTICE from the Jackson Jar 2.4.2
 
   Jackson is a high-performance, Free/Open Source JSON processing library.
diff --git a/src/main/bin_distr_license_notices/NOTICE-without-jackson b/src/main/bin_distr_license_notices/NOTICE-without-jackson
index a6504f7..71398be 100644
--- a/src/main/bin_distr_license_notices/NOTICE-without-jackson
+++ b/src/main/bin_distr_license_notices/NOTICE-without-jackson
@@ -9,4 +9,6 @@
 licensed to the Apache Software Foundation under the
 "Software Grant License Agreement", informally known as the 
 "IBM UIMA License Agreement".
-Copyright (c) 2003, 2006 IBM Corporation.
\ No newline at end of file
+Copyright (c) 2003, 2006 IBM Corporation.
+
+ResolverUtil.java Copyright 2005-2006 Tim Fennell
\ No newline at end of file
diff --git a/src/main/license_notice_research.txt b/src/main/license_notice_research.txt
index 4e50593..3484f11 100644
--- a/src/main/license_notice_research.txt
+++ b/src/main/license_notice_research.txt
@@ -22,9 +22,18 @@
     Jars have no info in their manifest

     source has Apache license file, no notice file

     

+  (upgraded from this, see below) 

   javaparser-core 2.5.1 is dual licensed, one is Apache v2 license.  No notice file found.

+  javaparser-core 3.1.1 is dual licensed, one is Apache v2 license.  No notice file found.

     

   Note: ASM not depended on (Nov 2016). ASM is licensed under a BSD 3-clause style license.  

-  

+ 

+ Feb 14 2017

+   log4j jars included in binary distribution:

+     log4j-api-2.8 - ok

+     log4j-core-2.8 has Notice  ResolverUtil.java Copyright 2005-2006 Tim Fennell

+     log4j-slf4j-impl-2.8 OK

+     slf4j-api-1.7.22 - no info in the JAR

+       slf4j distributed under the MIT license.  added to bin_distr_license_notices

   

   
\ No newline at end of file
diff --git a/src/main/scripts/runUimaClass.bat b/src/main/scripts/runUimaClass.bat
index 7fdea8a..a27fde5 100644
--- a/src/main/scripts/runUimaClass.bat
+++ b/src/main/scripts/runUimaClass.bat
@@ -55,4 +55,4 @@
 @if "%UIMA_CVDMAN%"=="" set UIMA_CVDMAN=-Duima.tools.cvd.manpath.notset

 

 @rem Finally load the jars and run the class

-@"%UIMA_JAVA_CALL%" -DVNS_HOST=%VNS_HOST% -DVNS_PORT=%VNS_PORT% "-Duima.home=%UIMA_HOME%" "-Duima.datapath=%UIMA_DATAPATH%" "-Djava.util.logging.config.file=%UIMA_LOGGER_CONFIG_FILE%" "%UIMA_CVDMAN%" %UIMA_JVM_OPTS% "%LOG4J_CONFIG_FILE%" -DUimaBootstrapSuppressClassPathDisplay -Dorg.apache.uima.jarpath="%UIMA_CLASSPATH%" -jar "%UIMA_HOME%\lib\uimaj-bootstrap.jar" %*

+@"%UIMA_JAVA_CALL%" -DVNS_HOST=%VNS_HOST% -DVNS_PORT=%VNS_PORT% "-Duima.home=%UIMA_HOME%" "-Duima.datapath=%UIMA_DATAPATH%" "-Duima.use_jul_as_default_uima_logger" "-Djava.util.logging.config.file=%UIMA_LOGGER_CONFIG_FILE%" "%UIMA_CVDMAN%" %UIMA_JVM_OPTS% "%LOG4J_CONFIG_FILE%" -DUimaBootstrapSuppressClassPathDisplay -Dorg.apache.uima.jarpath="%UIMA_CLASSPATH%" -jar "%UIMA_HOME%\lib\uimaj-bootstrap.jar" %*

diff --git a/src/main/scripts/runUimaClass.sh b/src/main/scripts/runUimaClass.sh
index 48144da..76a33bd 100644
--- a/src/main/scripts/runUimaClass.sh
+++ b/src/main/scripts/runUimaClass.sh
@@ -80,7 +80,7 @@
 then
   VNS_PORT=9000
 fi
-#also set default vlaue for UIMA_LOGGER_CONFIG_FILE
+#also set default value for UIMA_LOGGER_CONFIG_FILE
 if [ "$UIMA_LOGGER_CONFIG_FILE" = "" ]
 then
   UIMA_LOGGER_CONFIG_FILE=$UIMA_HOME/config/Logger.properties
@@ -106,5 +106,5 @@
 fi
 
 # Finally load the jars and run the class
-"$UIMA_JAVA_CALL" -DVNS_HOST=$VNS_HOST -DVNS_PORT=$VNS_PORT "-Duima.home=$UIMA_HOME" "-Duima.datapath=$UIMA_DATAPATH" "-Djava.util.logging.config.file=$UIMA_LOGGER_CONFIG_FILE" "$UIMA_CVDMAN" $UIMA_JVM_OPTS "$LOG4J_CONFIG_FILE" -DUimaBootstrapSuppressClassPathDisplay -Dorg.apache.uima.jarpath="$UIMA_CLASSPATH" -jar "$UIMA_HOME/lib/uimaj-bootstrap.jar" $@
+"$UIMA_JAVA_CALL" -DVNS_HOST=$VNS_HOST -DVNS_PORT=$VNS_PORT "-Duima.home=$UIMA_HOME" "-Duima.datapath=$UIMA_DATAPATH" "-Djava.util.logging.config.file=$UIMA_LOGGER_CONFIG_FILE" "$UIMA_CVDMAN" $UIMA_JVM_OPTS "-Duima.use_jul_as_default_uima_logger" "$LOG4J_CONFIG_FILE" -DUimaBootstrapSuppressClassPathDisplay -Dorg.apache.uima.jarpath="$UIMA_CLASSPATH" -jar "$UIMA_HOME/lib/uimaj-bootstrap.jar" $@
 
diff --git a/uima-docbook-overview-and-setup/pom.xml b/uima-docbook-overview-and-setup/pom.xml
index c296b1f..03ea5e8 100644
--- a/uima-docbook-overview-and-setup/pom.xml
+++ b/uima-docbook-overview-and-setup/pom.xml
@@ -42,13 +42,13 @@
        element, and just changing the following two properties -->  

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uima-docbook-overview-and-setup

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uima-docbook-overview-and-setup

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uima-docbook-overview-and-setup

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uima-docbook-overview-and-setup

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uima-docbook-overview-and-setup

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uima-docbook-overview-and-setup

     </url>

   </scm>

   

diff --git a/uima-docbook-overview-and-setup/src/docbook/conceptual_overview.xml b/uima-docbook-overview-and-setup/src/docbook/conceptual_overview.xml
index 5b8299f..5d969e1 100644
--- a/uima-docbook-overview-and-setup/src/docbook/conceptual_overview.xml
+++ b/uima-docbook-overview-and-setup/src/docbook/conceptual_overview.xml
@@ -954,7 +954,7 @@
       of the same audio segment). A Sofa may

       be associated with CAS Views. A particular CAS will have one or more views, each view

       corresponding to a particular subject of analysis, together with a set of the defined

-      indexes that index the metadata created in that view.</para>

+      indexes that index the metadata (that is, Feature Structures) created in that view.</para>

     

     <para>Analysis results can be indexed in, or <quote>belong</quote> to, a specific view.

       UIMA components may be written in <quote>Multi-View</quote> mode - able to create and

diff --git a/uima-docbook-overview-and-setup/src/docbook/eclipse_setup.xml b/uima-docbook-overview-and-setup/src/docbook/eclipse_setup.xml
index abe859d..1c4371c 100644
--- a/uima-docbook-overview-and-setup/src/docbook/eclipse_setup.xml
+++ b/uima-docbook-overview-and-setup/src/docbook/eclipse_setup.xml
@@ -54,7 +54,7 @@
     later.

   </para>

   

-  <note><para>You will need to run Eclipse using a Java at the 1.5 or later level, in order

+  <note><para>You will need to run Eclipse using a Java at the 1.8 level, in order

   to use the UIMA Eclipse plugins.</para></note>

   

   <section id="ugr.ovv.eclipse_setup.installation">

@@ -66,8 +66,8 @@
           url="&url_eclipse;"/> and follow the instructions there to download Eclipse.

         </para></listitem>

         

-        <listitem><para>We recommend using the latest release level (not an

-          <quote>Integration level</quote>). Navigate to the Eclipse Release version you

+        <listitem><para>We recommend using the latest release level. 

+          Navigate to the Eclipse Release version you

           want and download the archive for your platform.</para></listitem>

         

         <listitem><para>Unzip the archive to install Eclipse somewhere, e.g., c:\</para>

@@ -87,7 +87,7 @@
     <section id="ugr.ovv.eclipse_setup.install_uima_eclipse_plugins">

       <title>Installing the UIMA Eclipse Plugins</title>

       

-      <para>The best way to do this is to use the Eclipse Update mechanism, because that will 

+      <para>The best way to do this is to use the Eclipse Install New Software mechanism, because that will 

         insure that all needed prerequisites are also installed.  See below for an alternative,

         manual approach.</para>

       

@@ -98,13 +98,18 @@
         information about your proxy. </para></note>

 

       

-      <para>To use the Eclipse Update mechanism, start Eclipse, and then pick the menu 

+      <para>To use the Eclipse Install New Software mechanism, start Eclipse, and then pick the menu 

         <command>Help &rarr; Install new software...</command>.  In the next page, enter

-        the following URL in the "Work with" box and press enter: 

-        http://www.apache.org/dist/uima/eclipse-update-site/.</para>

+        the following URL in the "Work with" box and press enter:

+        <itemizedlist>

+          <listitem><para></para><code>https://www.apache.org/dist/uima/eclipse-update-site/</code> or</listitem>

+          <listitem><para></para><code>https://www.apache.org/dist/uima/eclipse-update-site-uv3/</code>.</listitem>

+        </itemizedlist>

+        Choose the 2nd if you are working with core UIMA Java SDK at version 3 or later.

+       .</para>

       

       <para>Now select the plugin tools you wish to install, and click Next, and follow the 

-        remaining panels to install the UIMA plugins.</para>

+        remaining panels to install the UIMA plugins.  </para>

     </section>

 

     <!--      

@@ -206,7 +211,7 @@
       <para>If you are unable to use the Eclipse Update mechanism to install the UIMA plugins, you 

         can do this manually.  In the directory %UIMA_HOME%/eclipsePlugins (The environment variable

         %UIMA_HOME% is where you installed the UIMA SDK), you will see a set of folders. Copy these

-        to your %ECLIPSE_HOME%/eclipse/plugins directory (%ECLIPSE_HOME% is where you

+        to your %ECLIPSE_HOME%/dropins directory (%ECLIPSE_HOME% is where you

         installed Eclipse).</para>

       

     </section>

@@ -223,7 +228,7 @@
       <section id="ugr.ovv.eclipse_setup.special_startup_parameter_clean">

         <title>Special startup parameter for Eclipse: -clean</title>

         <para>If you have modified the plugin structure (by copying or files directly in the

-          file system) in Eclipse 3.x after you started it for the first time, please include

+          file system) after you started it for the first time, please include

           the <quote>-clean</quote> parameter in the startup arguments to Eclipse,

           <emphasis>one time</emphasis> (after any plugin modifications were done). This

           is needed because Eclipse may not notice the changes you made, otherwise. This

@@ -235,8 +240,8 @@
   </section>

   <section id="ugr.ovv.eclipse_setup.example_code">

     <title>Setting up Eclipse to view Example Code</title>

-    <para>Later chapters refer to example code. You can create a special project in Eclipse to

-      hold the examples. Here's how:</para>

+    <para>Later chapters refer to example code. Here's how to create a special project in Eclipse to

+      hold the examples.</para>

     

     <itemizedlist spacing="compact"><listitem><para>In Eclipse, if the Java

       perspective is not already open, switch to it by going to Window &rarr; Open Perspective

@@ -273,7 +278,7 @@
         the <quote>Next</quote> button.</para></listitem>

       

       <listitem><para>Click <quote>Browse</quote> and browse to the

-        %UIMA_HOME%/ directory</para></listitem>

+        %UIMA_HOME%/examples directory</para></listitem>

       

       <listitem><para>Click <quote>Finish.</quote> This will create a new project called

         <quote>uimaj-examples</quote> in your Eclipse workspace. There should be no

@@ -290,8 +295,8 @@
     <note><para>If you are running a current version of Eclipse, and have the m2e (Maven extensions for Eclipse) 

     plugin installed, Eclipse should be able to automatically download the source for the jars, so you may not need

     to do anything special (it does take a few seconds, and you need an internet connection).</para></note>

-    <para>If you would like to be able to jump to the UIMA source code in Eclipse or to step

-    through it with the debugger, you can add the UIMA source code to the jar files.  This is

+    <para>Otherwise, if you would like to be able to jump to the UIMA source code in Eclipse or to step

+    through it with the debugger, you can add the UIMA source code directly to the jar files.  This is

     done via a shell script that comes with the source distribution.  To add the source code

     to the jars, you need to:

     </para>

diff --git a/uima-docbook-overview-and-setup/src/docbook/faqs.xml b/uima-docbook-overview-and-setup/src/docbook/faqs.xml
index 4f66365..2c00e13 100644
--- a/uima-docbook-overview-and-setup/src/docbook/faqs.xml
+++ b/uima-docbook-overview-and-setup/src/docbook/faqs.xml
@@ -72,7 +72,8 @@
             machines for greater scale, flexibility and recoverability).</para>

             

           <para>The UIMA project has several significant subprojects, including UIMA-AS (for flexibly

-          scaling out UIMA pipelines over clusters of machines), UIMA-DUCC (for managing clusters of 

+          scaling out UIMA pipelines over clusters of machines), uimaFIT (for a way of using UIMA without the xml descriptors; also provides 

+          many convenience methods), UIMA-DUCC (for managing clusters of 

           machines running scaled-out UIMA "jobs" in a "fair" way), RUTA (Eclipse-based tooling and \

           a runtime framework for development of rule-based

           Annotators), Addons (where you can find many extensions), and uimaFIT supplying a Java centric

@@ -80,6 +81,7 @@
         </listitem>

       </varlistentry>

      

+      <!-- 

       <varlistentry id="ugr.faqs.include_semantic_search">

         <term><emphasis role="bold">

           Does UIMA include a semantic search engine?

@@ -94,6 +96,8 @@
           </para>

         </listitem>

       </varlistentry>

+      --> 

+      

       <varlistentry id="ugr.faqs.what_is_an_annotation">

         

         <term><emphasis role="bold">What is an Annotation?</emphasis></term>

@@ -149,6 +153,7 @@
             corresponds, etc.). For each version there is a separate instance of the results

             indices.</para></listitem>

       </varlistentry>

+      

       <varlistentry id="ugr.faqs.only_annotations">

         <term><emphasis role="bold">Does the CAS only contain Annotations?</emphasis></term>

         <listitem><para>No. The CAS contains the artifact being analyzed plus the analysis

@@ -161,6 +166,7 @@
           <para>The CAS may have multiple representations of the artifact being analyzed, each one

             represented in the CAS as a particular Subject of Analysis. or <link linkend="ugr.faqs.what_is_a_sofa">Sofa</link></para></listitem>

       </varlistentry>

+      

       <varlistentry id="ugr.faqs.just_xml">

         <term><emphasis role="bold">Is the CAS just XML?</emphasis></term>

         <listitem><para>No, in fact there are many possible representations of the CAS. If all

@@ -168,9 +174,11 @@
           data object is used. If a CAS must be sent to an analysis engine on a remote machine, it

           can be done via an XML or a binary serialization of the CAS. </para>

           

-          <para>The UIMA framework provides serialization and de-serialization methods

-            for a particular XML representation of the CAS named the XMI.</para></listitem>

+          <para>The UIMA framework provides multiple serialization and de-serialization methods

+            in various formats, including XML.  See the Javadocs for the CasIOUtils class.

+            </para></listitem>

       </varlistentry>

+      

       <varlistentry id="ugr.faqs.what_is_a_type_system">

         <term><emphasis role="bold">What is a Type System?</emphasis></term>

         <listitem><para>Think of a type system as a schema or class model for the <link linkend="ugr.faqs.what_is_the_cas">CAS</link>. It defines

@@ -182,6 +190,7 @@
             types (these can restrict the value of properties to other types) and

             single-inheritance hierarchy of types.</para></listitem>

       </varlistentry>

+      

       <varlistentry id="ugr.faqs.what_is_a_sofa">

         <term><emphasis role="bold">What is a Sofa?</emphasis></term>

         <listitem><para>Sofa stands for &ldquo;Subject of Analysis&quot;. A <link linkend="ugr.faqs.what_is_the_cas">CAS</link> is

@@ -195,7 +204,6 @@
           multi-modal analysis, where for example, one view of a video stream may be the video

           frames and the other the close-captions.</para></listitem>

       </varlistentry>

-

       

       <varlistentry id="ugr.faqs.annotator_versus_ae">

         <term><emphasis role="bold">What's the difference between an Annotator and an Analysis

@@ -215,12 +223,14 @@
             interacts with. An Annotator is a user-written class that implements the one of

             the supported Annotator interfaces.</para></listitem>

       </varlistentry>

+      

       <varlistentry id="ugr.faqs.web_services">

         <term><emphasis role="bold">Are UIMA analysis engines web services?</emphasis></term>

         <listitem><para>They can be deployed as such. Deploying an analysis engine as a web

           service is one of the deployment options supported by the UIMA framework.</para>

         </listitem>

       </varlistentry>

+      

       <varlistentry id="ugr.faqs.stateless_aes">

         <term><emphasis role="bold">Do Analysis Engines have to be

           &quot;stateless&quot;?</emphasis></term>

@@ -240,6 +250,7 @@
             documents that would prevent their engine from working as advertised if

             operated in a parallelized environment.</para></listitem>

       </varlistentry>

+      

       <varlistentry id="ugr.faqs.uddi">

         <term><emphasis role="bold">Is engine meta-data compatible with web services and

           UDDI?</emphasis></term>

@@ -249,22 +260,29 @@
           development tooling. In principle, UIMA component descriptors are compatible

           with web services and UDDI. However, the UIMA framework currently uses its own XML

           representation for component metadata. It would not be difficult to convert

-          between UIMA&apos;s XML representation and the WSDL and UDDI standards.</para>

+          between UIMA&apos;s XML representation and other standard representations.</para>

         </listitem>

       </varlistentry>

-

       

       <varlistentry id="ugr.faqs.scaling">

         <term><emphasis role="bold">How do you scale a UIMA application?</emphasis></term>

-        <listitem><para>The UIMA framework allows components such as <link linkend="ugr.faqs.annotator_versus_ae">analysis engines</link> and

+        <listitem><para>The UIMA framework allows components such as 

+          <link linkend="ugr.faqs.annotator_versus_ae">analysis engines</link> and

           CAS Consumers to be easily deployed as services or in other containers and managed

           by systems middleware designed to scale. UIMA applications tend to naturally

           scale-out across documents allowing many documents to be analyzed in

           parallel.</para>

-          <para>A component in the UIMA framework called the CPM (Collection Processing

-            Manager) has a host of features and configuration settings for scaling an

-            application to increase its throughput and recoverability.</para></listitem>

+          <para>The UIMA-AS project has extensive capabilities to flexibly scale a UIMA

+            pipeline across multiple machines.  The UIMA-DUCC project supports a 

+            unified management of large clusters of machines running multiple "jobs" 

+            each consisting of a pipeline with data sources and sinks.</para>

+          <para>Within the core UIMA framework, there is a component called the CPM (Collection Processing

+            Manager) which has features and configuration settings for scaling an

+            application to increase its throughput and recoverability; 

+            the CPM was the earlier version of scaleout technology, and has been 

+            superceded by the UIMA-AS effort (although it is still supported).</para></listitem>

       </varlistentry>

+      

       <varlistentry id="ugr.faqs.embedding">

         <term><emphasis role="bold">What does it mean to embed UIMA in systems middleware?</emphasis></term>

         <listitem><para>An example of an embedding would be the deployment of a UIMA analysis

@@ -275,6 +293,7 @@
           <link linkend="ugr.faqs.annotator_versus_ae">analysis engines</link> could be deployed on other application servers as well.</para>

         </listitem>

       </varlistentry>

+      

       <varlistentry id="ugr.faqs.cpm_versus_cpe">

         <term><emphasis role="bold">How is the CPM different from a CPE?</emphasis></term>

         <listitem><para>These name complimentary aspects of collection processing. The CPM

@@ -296,6 +315,8 @@
             index, database etc). The CPM is the execution engine for a CPE.</para>

         </listitem>

       </varlistentry>

+      

+      <!-- 

       <varlistentry id="ugr.faqs.semantic_search">

         <term><emphasis role="bold">What is Semantic Search and what is its relationship to

           UIMA?</emphasis></term>

@@ -319,8 +340,11 @@
           documentation demonstrates how UIMA applications can be built using semantic

           search. It provides details about the XML Fragment Query language. This is the

           particular query language used by the semantic search engine that comes with the

-          SDK.</para></listitem>

+          SDK.</para>

+          </listitem>

       </varlistentry>

+       

+      

       <varlistentry id="ugr.faqs.xml_fragment_not_xml">

         <term><emphasis role="bold">Is an XML Fragment Query valid XML?</emphasis></term>

         <listitem><para>Not necessarily. The XML Fragment Query syntax is used to formulate

@@ -333,6 +357,8 @@
           For example, it admits notations in the query to indicate whether a keyword or an

           annotation is optional or required to match a document.</para></listitem>

       </varlistentry>

+      -->

+      

       <varlistentry id="ugr.faqs.modalities_other_than_text">

         <term><emphasis role="bold">Does UIMA support modalities other than text?</emphasis></term>

         <listitem><para>The UIMA architecture supports the development, discovery,

@@ -349,6 +375,7 @@
             closed-captions text. UIMA&apos;s multiple Sofa feature is included and

             described in this release of the SDK.</para></listitem>

       </varlistentry>

+      

       <varlistentry id="ugr.faqs.compare">

         <term><emphasis role="bold">How does UIMA compare to other similar work?</emphasis></term>

         <listitem><para>A number of different frameworks for NLP have preceded UIMA. Two of

@@ -370,6 +397,7 @@
             discovery and composition. (Please note that not all of these features are

             available in this release of the SDK.)</para></listitem>

       </varlistentry>

+      

       <varlistentry id="ugr.faqs.open_source">

         <term><emphasis role="bold">Is UIMA Open Source?</emphasis></term>

         <listitem><para>Yes. As of version 2, UIMA development has moved to Apache and is being

@@ -380,23 +408,24 @@
             <ulink url="http://uima-framework.sourceforge.net/"/>).</para>

         </listitem>

       </varlistentry>

+      

       <varlistentry id="ugr.faqs.levels_required">

         <term><emphasis role="bold">What Java level and OS are required for the UIMA SDK?</emphasis></term>

-        <listitem><para>As of release 2.6.0, the UIMA SDK requires Java 1.6 or later. Releases from 2.2.1 to

-        2.5.0 require Java 1.5 level (or later).  Releases prior to 2.2.1

-          require as a minimum the Java 1.4 level; they will not run on 1.3 (or earlier levels). 

-          We routinely test releases with the most modern Javas (e.g. Java 8) as well. 

+        <listitem><para>As of release 3.0.0, the UIMA SDK requires Java 1.8.  

           It has been tested on mainly on Windows and Linux platforms, with some

           testing on the MacOSX. Other

           platforms and JDK implementations will likely work, but have

           not been as significantly tested.</para></listitem>

       </varlistentry>

+      

       <varlistentry id="ugr.faqs.building_apps_on_top_of_uima">

         <term><emphasis role="bold">Can I build my UIM application on top of UIMA?</emphasis></term>

         <listitem><para>Yes. Apache UIMA is licensed under the Apache version 2 license,

           enabling you to build and distribute applications which include the framework.

           </para></listitem>

       </varlistentry>

+      

+      <!-- 

       <varlistentry id="ugr.faqs.commercial_products">

         <term><emphasis role="bold">Do any commercial products support the UIMA framework or include

           it as part of their product?</emphasis></term>

@@ -408,6 +437,7 @@
           processing pipeline. We are actively seeking other product embeddings. </para>

         </listitem>

       </varlistentry>

+       -->

       <!--

       <varlistentry>

       <term><emphasis role="bold"></emphasis></term>

diff --git a/uima-docbook-overview-and-setup/src/docbook/glossary.xml b/uima-docbook-overview-and-setup/src/docbook/glossary.xml
index 2a9b378..24e7ec8 100644
--- a/uima-docbook-overview-and-setup/src/docbook/glossary.xml
+++ b/uima-docbook-overview-and-setup/src/docbook/glossary.xml
@@ -71,7 +71,10 @@
 

 in a UIMA <glossterm linkend="ugr.glossary.type_system">type system</glossterm>.

            It is the type used to record

-the labeling of regions of a <glossterm linkend="ugr.glossary.sofa">Sofa</glossterm></para>

+the labeling of regions of a <glossterm linkend="ugr.glossary.sofa">Sofa</glossterm>.

+          Annotations are <glossterm linkend="ugr.glossary.feature_structure">Feature Structures</glossterm>

+          whose <glossterm linkend="ugr.glossary.type">Type</glossterm> is Annotation or a subtype

+          of that.</para>

       </glossdef>

     </glossentry>

   

@@ -266,7 +269,8 @@
           create and initialize a new <glossterm linkend="ugr.glossary.sofa">Sofa</glossterm>.</para>

       </glossdef>

     </glossentry>

-  

+

+<!--   

     <glossentry id="ugr.glossary.fact_search">

       <glossterm>Fact Search</glossterm>

       <glossdef>

@@ -275,7 +279,20 @@
 match the fact pattern.</para>

       </glossdef>

     </glossentry>

-  

+   -->

+   

+    <glossentry id="ugr.glossary.feature_structure">

+      <glossterm>Feature Structure</glossterm>

+      <glossdef>

+        <para>An instance of a <glossterm linkend="ugr.glossary.type">Type</glossterm>.

+        Feature Structures are kept in the <glossterm linkend="ugr.glossary.cas">CAS, and may

+        (optionally) be added to the defined <glossterm linkend="ugr.glossary.index">indexes</glossterm>.

+        Feature Structures may contain references to other Feature Structures.

+        Feature Structures whose type is Annotation or a subtype of that, are referred to as 

+        <glossterm linkend="ugr.glossary.annotation">annotations</glossterm>.</glossterm></para>

+      </glossdef>

+    </glossentry>

+    

     <glossentry id="ugr.glossary.feature">

       <glossterm>Feature</glossterm>

       <glossdef>

@@ -332,13 +349,14 @@
       <glossterm>JCas</glossterm>

       <glossdef>

         <para>A Java object interface to the contents of the CAS.  

-          This interface use additional generated Java classes, where each type in the CAS

+          This interface uses additional generated Java classes, where each type in the CAS

 is represented as a Java class with the same name, each feature is represented with

 a getter and setter method, and each instance of a type is represented as a

 Java object of the corresponding Java class.</para>

       </glossdef>

     </glossentry>

   

+<!-- 

     <glossentry id="ugr.glossary.keyword_search">

       <glossterm>Keyword Search</glossterm>

       <glossdef>

@@ -346,7 +364,8 @@
 and candidate documents are returned.</para>

       </glossdef>

     </glossentry>

-  

+ -->

+ <!--   

     <glossentry id="ugr.glossary.knowledge_base">

       <glossterm>Knowledge Base</glossterm>

       <glossdef>

@@ -354,7 +373,8 @@
 set of facts and rules considered true in a possible world.</para>

       </glossdef>

     </glossentry>

-  

+   -->

+   

     <glossentry id="ugr.glossary.loosely_coupled_analysis_engine">

       <glossterm>Loosely-Coupled &ae;</glossterm>

       <glossdef>

@@ -370,6 +390,7 @@
       </glossdef>

     </glossentry>

   

+<!--  -->

     <glossentry id="ugr.glossary.ontology">

       <glossterm></glossterm>

       <glossdef>

@@ -377,7 +398,8 @@
 axiomatically.</para>

       </glossdef>

     </glossentry>

-  

+ -->

+   

     <glossentry id="ugr.glossary.pear">

       <glossterm>PEAR</glossterm>

       <glossdef>

@@ -399,7 +421,8 @@
           <glossterm linkend="ugr.glossary.aggregate">&aae;</glossterm>.</para>

       </glossdef>

     </glossentry>

-  

+ 

+ <!--  

     <glossentry id="ugr.glossary.semantic_search">

       <glossterm>Semantic Search</glossterm>

       <glossdef>

@@ -410,7 +433,8 @@
 in your garden but rather just persons named Bush.</para>

       </glossdef>

     </glossentry>

-  

+ -->

+ 

     <glossentry id="ugr.glossary.structured_information">

       <glossterm>Structured Information</glossterm>

       <glossdef>

diff --git a/uima-docbook-overview-and-setup/src/docbook/project_overview.xml b/uima-docbook-overview-and-setup/src/docbook/project_overview.xml
index ca71646..bb4228b 100644
--- a/uima-docbook-overview-and-setup/src/docbook/project_overview.xml
+++ b/uima-docbook-overview-and-setup/src/docbook/project_overview.xml
@@ -98,10 +98,13 @@
         <listitem>

           <para> References </para>

         </listitem>

+        <listitem>

+          <para>Version 3 users-guide</para>

+        </listitem>

       </itemizedlist> </para>

     

     <para>

-    The first 2 parts make up this book; the last 3 have individual 

+    The first 2 parts make up this book; the last 4 have individual 

     books.  The books are provided both as

     (somewhat large) html files, viewable in browsers, and also as PDF files.  

     The documentation is fully hyperlinked, with tables of contents.  The PDF versions are set up to 

@@ -162,6 +165,7 @@
         </tgroup>

       </informaltable>

     </section>

+    

     <section id="ugr.project_overview_setup">

       <title>Eclipse Tooling Installation and Setup</title>

       <para>Provides step-by-step instructions for installing Apache UIMA in the Eclipse Interactive

@@ -382,6 +386,13 @@
         </tgroup>

       </informaltable>

     </section>

+    

+    <section id="ugr.project_overview_v3">

+      <title>Version 3 User's guide</title>

+      <para>This book describes Version 3's features, capabilities, and differences with version 2.

+        </para>

+    </section>

+    

   </section>

   

   <section id="ugr.project_overview_doc_use">

@@ -766,6 +777,18 @@
   </section>

   </section>

 

+  <section id="ugr.project_overview_migrating_from_v2_to_v3">

+    <title>Migrating existing UIMA pipelines from Version 2 to Version 3</title>

+    <para>The format of JCas classes changed when going from version 2 to version 3. 

+          If you had JCas classes for user types, these need to be regenerated using the 

+          version 3 JCasGen tooling or Maven plugin.  Alternatively, these can be 

+          migrated without regenerating; the migration preserves any customation 

+          users may have added to the JCas classes.</para>

+          

+    <para>The Version 3 User's Guide has a chapter detailing the migration, including

+      a description of the migration tool to aid in this process.</para>

+  </section>

+  

   <section id="ugr.project_overview_migrating_from_ibm_uima">

     <title>Migrating from IBM UIMA to Apache UIMA</title>

     <para>In Apache UIMA, several things have changed that require changes to user code and descriptors.

@@ -1039,8 +1062,9 @@
           </row>

           <row>

             <entry>Saving and Restoring CAS contents</entry>

-            <entry>APIs in the core framework support saving and restoring the contents of a CAS to streams using an

-              XMI format. </entry>

+            <entry>APIs in the core framework support saving and restoring the contents of a CAS to streams 

+              in multiple formats, including XMI, binary, and compressed forms.  

+              These apis are collected into the CasIOUtils class.</entry>

           </row>

           <row>

             <entry>PEAR Packager for Eclipse</entry>

@@ -1081,6 +1105,14 @@
               viewer.</entry>

           </row>

           <row>

+            <entry>CAS Editor</entry>

+            <entry>Eclipse plug-in that lets you edit the contents of a CAS</entry>

+          </row>

+          <row>

+            <entry>UIMA Pipeline Eclipse Launcher</entry>

+            <entry>Eclipse plug-in that lets you configure Eclipse launchers for UIMA pipelines</entry>

+          </row>

+          <row>

             <entry namest="col1" nameend="col2" align="center" role="tableSubhead"> Example Analysis

               Components </entry>

           </row>

diff --git a/uima-docbook-references/pom.xml b/uima-docbook-references/pom.xml
index 4d35693..3818ad9 100644
--- a/uima-docbook-references/pom.xml
+++ b/uima-docbook-references/pom.xml
@@ -42,13 +42,13 @@
        element, and just changing the following two properties -->  

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uima-docbook-references

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uima-docbook-references

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uima-docbook-references

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uima-docbook-references

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uima-docbook-references

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uima-docbook-references

     </url>

   </scm>

   

diff --git a/uima-docbook-references/src/docbook/ref.cas.xml b/uima-docbook-references/src/docbook/ref.cas.xml
index 4889054..00a0c86 100644
--- a/uima-docbook-references/src/docbook/ref.cas.xml
+++ b/uima-docbook-references/src/docbook/ref.cas.xml
@@ -149,14 +149,14 @@
     <section id="ugr.ref.cas.creating_using_indexes">

       <title>Creating and using indexes</title>

       

-      <para>Each view of a CAS provides a set of indexes for that view. Instances of feature

-        structures can be added to a view&apos;s indexes. These indexes provide

-        the only way for other annotators to locate existing data in the CAS. The only way for an

-        annotator to use data that another annotator has created is by using an index (or the

+      <para>Each view of a CAS provides a set of indexes for that view. Instances of Types (that is, Feature

+        Structures) can be added to a view&apos;s indexes. These indexes provide

+        a way for annotators to locate existing data in the CAS, using a specific index (or the

         method <literal>getAllIndexedFS</literal> of the object <literal>FSIndexRepository</literal>) to

-        retrieve feature structures the first annotator created. If you want the data you

-        create to be visible to other annotators, you must explicitly call methods which

-        add it to the indexes &mdash; you must index it.</para>

+        retrieve the Feature Structures that were previously created. If you want the data you

+        Newly created Feature Structures are not automatically added to the indexes; you choose which

+        Feature Structures to add and use one of several APIs to add them. 

+        </para>

       

       <para>Indexes are named and are associated with a CAS Type; they are used to index

         instances of that CAS type (including instances of that type&apos;s subtypes). If

@@ -169,6 +169,34 @@
         query for indexes for that view. Once you have a handle to an index, you can get

         information about the feature structures in the index, the size of the index, as well

         as an iterator over the feature structures.</para>

+        

+      <para>There are three kinds of indexes:

+        <itemizedlist spacing="compact">

+          <listitem>

+            <para>bag - no ordering</para>

+          </listitem>

+          <listitem>

+            <para>set - uses a user-specfied set of keys to define equality; holds one instance of the set of equal items.</para>

+          </listitem>

+          <listitem>

+            <para>sorted - uses a user-specified set of keys to define ordering.</para>

+          </listitem>          

+        </itemizedlist>

+      </para>

+      

+      <para>For set indexes, the comparator keys are augmented with an implicit additional field - the type of the

+        feature structure.  This means that an index over Annotations, having subtype Token, and a key of the "begin" value,

+        will behave as follows:

+        

+        <itemizedlist>

+          <listitem><para>If you make two Tokens (or two Annotations), both having a begin value of 17, and add both of them to the indexes,

+            only one of them will be in the index.</para>

+          </listitem>

+          <listitem><para>If you make 1 Token and 1 Annotation, both having a begin value of 17, and add both of them to the indexes,

+            both of them will be in the index (because the types are different).

+          </para></listitem>

+        </itemizedlist> 

+      </para>

       

       <para>Indexes are defined in the XML descriptor metadata for the application. Each CAS

         View has its own, separate instantiation of indexes based on these definitions, 

@@ -178,29 +206,40 @@
         belongs, within just the view's repository. You can specify different repositories

         (associated with different CAS views) to use; a given Feature Structure instance 

         may be indexed in more than one CAS View (unless it is a subtype of AnnotationBase).</para>

-      

-      <para>Iterators allow you to enumerate the feature structures in an index.  FS iterators

-        provide two kinds of APIs: the regular Java iterator API, and a specific FS iterator API

+

+      <para>Indexes implement the Iterable interface, so you may use the Java enhanced for loop to iterate over them.</para>

+            

+      <para>You can also get iterators from indexes; 

+        iterators allow you to enumerate the feature structures in an index.  There are two kinds of iterators supported:

+        the regular Java iterator API, and a specific FS iterator API

         where the usual Java iterator APIs (<literal>hasNext()</literal> and <literal>next()</literal>)

-        are replaced by <literal>isValid()</literal>, <literal>moveToNext()</literal> (which does

-        not return an element) and <literal>get()</literal>.  Which API style you use is up to you,

+        are augmented by <literal>isValid()</literal>, <literal>moveToNext() / moveToPrevious()</literal> (which does

+        not return an element) and <literal>get()</literal>.  Finally, there is a <literal>moveTo(FeatureStructure)</literal>

+        API, which, for sorted indexes, moves the iteration point to the left-most (among otherwise "equal") item

+        in the index which compares "equal" to the given FeatureStructure, using the index's defined comparator.

+      </para>

+      

+      <para>  

+        Which API style you use is up to you,

         but we do not recommend mixing the styles as the results are sometimes unexpected.  If you

         just want to iterate over an index from start to finish, either style is equally appropriate.

         If you also use <literal>moveTo(FeatureStructure fs)</literal> and 

         <literal>moveToPrevious()</literal>, it is better to use the special FS iterator style.

       </para>

+      

       <note><para>The reason to not mix these styles is that you might be thinking that

         next() followed by moveToPrevious() would always work.  This is not true, because

         next() returns the "current" element, and advances to the next position, which might be

-        beyond the last element.  At that point, the interator becomes "invalid", and by the iterator

-        contracts, moveToNext and moveToPrevious are not allowed on "invalid" iterators; 

-        when an iterator is not valid, all bets are off.  But you can

+        beyond the last element.  At that point, the iterator becomes "invalid", and 

+        moveToNext and moveToPrevious no longer move the iterator.  But you can

         call these methods on the iterator &mdash; moveToFirst(), moveToLast(), or moveTo(FS) &mdash; to reset it.</para></note>

       

       <para>Indexes are created by specifying them in the annotator&apos;s or

         aggregate&apos;s resource descriptor. An index specification includes its name,

-        the CAS type being indexed, the kind of index it is, and an (optional) ordering

-        relation on the feature structures to be indexed. At startup time, all index

+        the CAS type being indexed, the kind (bag, set or sorted) of index it is, and an (optional) set of keys.

+        The keys are used for set and sorted indexes, and specify what values are used for 

+        ordering, or (for sets) what values are used to determine set equality. 

+        When a CAS pipeline is created, all index

         specifications are combined; duplicate definitions (having the same name) are

         allowed only if their definitions are the same. </para>

       

@@ -226,6 +265,10 @@
         Type Priority. This ordering insures that

         longer annotations starting at the same spot come before shorter ones. For Subjects

         of Analysis other than Text, this may not be an appropriate index.</para>

+        

+      <para>In addition to normal iterators, there is a <literal>select</literal> API, documented

+       in the Version 3 Users guide, which provides additional capabilities for accessing

+       Feature Structures via the indexes.</para>  

       

     </section>

   </section>

@@ -284,9 +327,9 @@
       

     <para>The JCas cover classes for the array types support the Iterable API, so you may

     write extended for loops over instances of these.  For example:

-    <programlisting>FSArray myArray = ...

-for (TOP fs : myArray) {

-  somemethod(fs);

+    <programlisting>FSArray&lt;MyType&gt; myArray = ...

+for (MyType fs : myArray) {

+  some_method(fs);

 }</programlisting>

     </para>

     

@@ -381,7 +424,7 @@
     The iterator stops when it gets to the end of the list, determined by either the tail being null or 

     the element being one of the EmptyXXXList elements.

     Here's a StringList example:

-    <programlisting>StringList sl = new EmptyStringList(jcas);

+    <programlisting>StringList sl = jcas.emptyStringList();

 sl = sl.push("2");

 sl = sl.push("1");

 

@@ -433,22 +476,15 @@
       <programlisting>// Get all type names from the type system

 // and print them to stdout.

 private void listTypes1(TypeSystem ts) {

-  // Get an iterator over types

-  Iterator typeIterator = ts.getTypeIterator();

-  Type t;

-  System.out.println("Types in the type system:");

-  while (typeIterator.hasNext()) {

-    // Retrieve a type...

-    t = (Type) typeIterator.next();

-    // ...and print its name.

+  for (Type t : ts) {

+    // print its name.

     System.out.println(t.getName());

   }

-  System.out.println();

 }</programlisting>

       

       <para>This method is passed the type system as a parameter.  From the type system, we can 

         get an iterator

-        over all known types. If you run this against a CAS created with no additional

+        over all the types. If you run this against a CAS created with no additional

         user-defined types, we should see something like this on the console:</para>

       

       <programlisting>Types in the type system: 

@@ -721,9 +757,9 @@
       sort ordering (or set membership), without removing and re-adding back to the index.

       </para></note>

       

-    <para>To completely remove an item from the indexes may entail removing it multiple times, if it was 

+    <!-- <para>To completely remove an item from the indexes may entail removing it multiple times, if it was 

     added multiple times and (as of version 2.7.0) the JVM global property 

-    <code>uima.allow_duplicate_add_to_indexes</code> is true.</para>

+    <code>uima.allow_duplicate_add_to_indexes</code> is true.</para> -->

     

     <para>The automatic protection checks for updates of

     features being used as keys, and if it finds an update like this for a feature structure that

@@ -747,8 +783,7 @@
   ac.close();

 }

 

-// if Java 8 is in use, 

-// this can be written using the auto-close feature of try:

+// This can more compactly be written using the auto-close feature of try:

 

 try (AutoCloseable ac = my_cas.protectIndexes()) {

    ...  arbitrary user code which updates features 

@@ -841,7 +876,7 @@
     <title>Indexes and Iterators</title>

     

     <para>Each CAS can have many indexes associated with it; each CAS View contains 

-      a complete set of instantions of the indexes.   Each index is represented by an

+      a complete set of instantiations of the indexes.   Each index is represented by an

       instance of the type org.apache.uima.cas.FSIndex. You use the object

       org.apache.uima.cas.FSIndexRepository, accessible via a method on a CAS object, to

       retrieve instances of indexes. There are methods that let you select the index

@@ -861,29 +896,30 @@
       the Component Descriptor, see <olink targetdoc="&uima_docs_ref;"

         targetptr="ugr.ref.xml.component_descriptor.aes.index"/>.</para>

        

-    <para>Feature structures should not be added to or removed from indexes while iterating

-      over them; a ConcurrentModificationException is thrown when this is detected (but see the following paragraph).

-      Certain operations are allowed with the iterators after modification, which can

-      <quote>reset</quote> this condition, such as moving to beginning, end, or moving to a

-      particular feature structure. So - if you have to modify the index, you can move it back to

-      the last FS you had retrieved from the iterator, and then continue, if that makes sense in

-      your application.</para>

+    <para>In UIMA V3, Feature structures may be added to or removed from indexes while iterating

+      over them.  If this happens, any iterators already created will continue to operate over the

+      before-modification version of the index, unless or until the iterator is re-synchronized with the current

+      value of the index via one of the following specific 3 iterator API calls: 

+      moveToFirst, moveToLast, or moveTo(FeatureStructure).

+      ConcurrentModificationException is no longer thrown in UIMA v3.

+    </para>

+    

+    <para>Feature structures being iterated over may have features which are used as the "keys" of an index, updated.

+    If this is done, UIMA will protect the indexes (to prevent index corruption) by automatically removing the 

+    Feature Structure from the indexes, 

+    updating the field, and adding the FS back to the index (possibly in a new position).  

+    This automatic remove / add-back operation no longer makes the iterator throw a ConcurrentModificationException

+    (as it did in UIMA Version 2) if the iterator is incremented or decremented;

+    existing iterators will continue to operate as if no index modification occurred.

+    </para>   

       

-    <para>Feature structures being iterated over should not have features which are used as the "keys" of an index, updated.

-    If this is done, UIMA, to prevent index corruption, will recover by automatically removing the FS from the indexes, 

-    updating the field, and adding the FS back to the index.  This recovery operation, because it updates the index, 

-    will make the iterator throw a ConcurrentModificationException if the iterator is incremented or decremented;

-    this exception will likely be unexpected because because it is hidden and automatic.  

-    If you must do this kind of operation, consider using Snapshot iterators (see next),

-    which don't throw ConcurrentModificationException.</para>   

-      

-    <para>As of version 2.7.0, a new method on FSIndex, <code>withSnapshotIterators(),</code> 

+    <!-- <para>As of version 2.7.0, a new method on FSIndex, <code>withSnapshotIterators(),</code> 

     allows creating a light-weight FSIndex based on the original FSIndex 

     that supports doing arbitrary index operations while iterating, and will not throw 

     <code>ConcurrentModificationException</code>.  Iterators obtained from this instance use a 

     <emphasis>snapshot</emphasis> technique - they create a snapshot of the original index when the 

     iterator is created, and then use that snapshot while operating, so the iteration is unaffected by any

-    modifications to the actual index.</para>

+    modifications to the actual index.</para>  -->

 

     <section id="ugr.ref.cas.index.built_in_indexes">

       <title>Built-in Indexes</title>

@@ -896,7 +932,8 @@
         annotations in the order in which they appear in the document. Annotations are sorted first by increasing

         <literal>begin</literal> position. Ties are then broken by <emphasis>decreasing</emphasis>

         <literal>end</literal> position (so that longer annotations come first). Annotations that match in both

-        their <literal>begin</literal> and <literal>end</literal> features are sorted using the Type Priority

+        their <literal>begin</literal> and <literal>end</literal> features are sorted using the Type Priority,

+        if any are defined

         (see <olink targetdoc="&uima_docs_ref;"

           targetptr="ugr.ref.xml.component_descriptor.aes.type_priority"/> )</para>

     </section>

@@ -904,26 +941,51 @@
     

     <section id="ugr.ref.cas.index.adding_to_indexes">

       <title>Adding Feature Structures to the Indexes</title>

-      

-      <para>Feature Structures are added to the indexes by calling the

-        <literal>FSIndexRepository.addFS(FeatureStructure)</literal> method or the equivalent convenience

-        method <literal>CAS.addFsToIndexes(FeatureStructure)</literal>. This adds the Feature Structure to

+

+      <para>Feature Structures are added to the indexes by various APIs. These add the Feature Structure to

         <emphasis>all</emphasis> indexes that are defined for the type of that FeatureStructure (or any of its

-        supertypes). Note that you should not add a Feature Structure to the indexes until you have set values for all

+        supertypes), in a particular view. 

+        Note that you should not add a Feature Structure to the indexes until you have set values for all

         of the features that may be used as sort keys in an index.</para>

+      

+      <para>There are multiple APIs for adding FSs to the index.

+        <itemizedlist>

+          <listitem><para>(preferred) myFeatureStructure.addToIndexes(). This adds the feature structure instance to the

+          view in which it was originally created.</para>

+          </listitem>

+          <listitem><para>(preferred) myFeatureStructure.addToIndexes(JCas or CAS). This adds the feature structure instance to the

+            view represented by the argument.</para>

+          </listitem>

+          <listitem><para>(older form) casView.addFsToIndexes(myFeatureStructure) or jcasView.addFsToIndexes(myFeatureStructure). 

+            This adds the feature structure instance to the

+            view represented by the cas (or jcas).</para>

+          </listitem>

+          <listitem><para>(older form) fsIndexRepositoryView.addFsToIndexes(myFeatureStructure). 

+            This adds the feature structure instance to the

+            view represented by the fsIndexRepository instance.</para>

+          </listitem>

+        </itemizedlist>

+      </para>

     </section>

         

     <section id="ugr.ref.cas.index.iterators">

-      <title>Iterators</title>

+      <title>Iterators over UIMA Indexes</title>

+

       

       <para>Iterators are objects of class <literal>org.apache.uima.cas.FSIterator.</literal> This class

         extends <literal>java.util.Iterator</literal> and implements the normal Java iterator methods, plus

-        additional ones that allow moving both forwards and backwards.</para>  

+        additional ones that allow moving both forwards and backwards.</para>

+        

+      <para>UIMA Indexes implement iterable, so you can use the index directly in a Java extended for loop.</para>

+        

     </section>

     

     <section id="ugr.ref.cas.index.annotation_index">

       <title>Special iterators for Annotation types</title>

       

+      <para>Note: we recommend using the UIMA V3 select framework, instead of the following.

+        It implements all of the following capabilities, and more, in a uniform manner.</para>

+      

       <para>The built-in index over the <literal>uima.tcas.Annotation</literal> type

         named <quote><literal>AnnotationIndex</literal></quote> has additional

         capabilities. To use them, you first get a reference to this built-in index using

@@ -959,6 +1021,9 @@
     <section id="ugr.ref.cas.index.constraints_and_filtered_iterators">

       <title>Constraints and Filtered iterators</title>

       

+      <para>Note: for new code, consider using the select framework plus Streams, instead of

+        the following.</para>

+        

       <para>There is a set of API calls that build constraint objects. These objects can be

         used directly to test if a particular feature structure matches (satisfies) the

         constraint, or they can be passed to the createFilteredIterator method to create an

diff --git a/uima-docbook-references/src/docbook/ref.config.xml b/uima-docbook-references/src/docbook/ref.config.xml
index a18dbf8..8be7efb 100644
--- a/uima-docbook-references/src/docbook/ref.config.xml
+++ b/uima-docbook-references/src/docbook/ref.config.xml
@@ -104,6 +104,26 @@
 

          <!-- ******************************************************************************* -->

          <row>

+           <entry><para>Use built-in Java Logger as default back-end</para></entry>

+           

+           <entry><para><code>uima.use_jul_as_default_uima_logger</code></para>

+           

+                  <para>See <ulink url="https://issues.apache.org/jira/browse/UIMA-5381">UIMA-5381</ulink>.

+                  The standard UIMA logger uses an slf4j implementation, which, in turn hooks up to 

+                  a back end implementation based on what can be found in the class path (see slf4j documentation).

+                  If no backend implementation is found, the slf4j default is to use a NOP logger back end 

+                  which discards all logging.</para>

+                  

+                  <para>When this flag is specified, the behavior of the UIMA logger 

+                        is altered to use the built-in-to-Java logging implementation 

+                        as the back end for the UIMA logger.

+                  </para></entry>

+           <entry><para>3.0.0</para></entry>

+         </row>

+

+         <!-- ******************************************************************************* -->

+         <!-- 

+         <row>

            <entry><para>Allow duplicate addToIndexes for identical Feature Structures</para></entry>

            

            <entry><para><code>uima.allow_duplicate_add_to_indexes</code> (default is false)</para>

@@ -115,8 +135,10 @@
                         may be restored by this property.</para></entry>

            <entry><para>2.7.0</para></entry>

          </row>

+         -->

          

          <!-- ******************************************************************************* -->

+         <!-- 

          <row>

            <entry><para>adding Annotation to wrong View</para></entry>

            

@@ -130,7 +152,8 @@
                         for backward compatibility.</para></entry>

            <entry><para>2.7.0</para></entry>

          </row>

-

+         -->

+         

          <row>

            <entry spanname="fullwidth"><emphasis role="bold">Index protection properties</emphasis></entry>

          </row>         

@@ -204,11 +227,30 @@
            <entry><para>2.7.0</para></entry>

          </row>

 

+

          <row>

-           <entry spanname="fullwidth"><emphasis role="bold">Measurement properties</emphasis></entry>

+           <entry spanname="fullwidth"><emphasis role="bold">Measurement / Tracing properties</emphasis></entry>

          </row>         

          <!-- ******************************************************************************* -->

-         <!--   DISABLED FOR NOW 

+      

+         <row>

+           <entry><para>Trace Feature Structure Creation/Updating</para></entry>

+           

+           <entry><para><code>uima.trace_fs_creation_and_updating</code></para>

+                  <para>This causes a trace file to be produced in the current working directory.

+                  The file has one line for each Feature Structure that is created, and include

+                  information on the cas/cas-view, and the features that are set for the Feature Structure.

+                  There is, additionally, one line for each Feature Structure update.

+                  Updates that occur next-to trace information for the same Feature Structure are combined.

+                  </para>

+           

+                  <para>This can generate a lot of output, and definitely slows down execution.</para>

+            </entry>

+            

+            <entry><para>2.10.1</para></entry>

+         </row>    

+         

+                    

          <row>

            <entry><para>Measure index flattening optimization</para></entry>

            

@@ -228,7 +270,7 @@
        </tbody>

      </tgroup>

    </informaltable>

-    

+   <para>Some additional global flags intended for helping v3 migration are documented in the V3 user's guide.</para> 

   </section>

   

 </chapter>
\ No newline at end of file
diff --git a/uima-docbook-references/src/docbook/ref.javadocs.xml b/uima-docbook-references/src/docbook/ref.javadocs.xml
index bf7ad81..9718940 100644
--- a/uima-docbook-references/src/docbook/ref.javadocs.xml
+++ b/uima-docbook-references/src/docbook/ref.javadocs.xml
@@ -45,7 +45,7 @@
   

   <para>To add the Javadocs, open a project which is referring to the UIMA APIs in its class path, and open the project properties. Then pick

     Java Build Path. Pick the "Libraries" tab and select one of the UIMA library entries (if you don't have, for

-    instance, uima-core.jar in this list, it's unlikely your code will compile). Each library entry has a small "+"

+    instance, uima-core.jar in this list, it's unlikely your code will compile). Each library entry has a small ">"

     sign on its left - click that to expand the view to see the Javadoc location. If you highlight that and press edit - you

     can add a reference to the Javadocs, in the following dialog:

     

diff --git a/uima-docbook-references/src/docbook/ref.jcas.xml b/uima-docbook-references/src/docbook/ref.jcas.xml
index 8605f76..52158ae 100644
--- a/uima-docbook-references/src/docbook/ref.jcas.xml
+++ b/uima-docbook-references/src/docbook/ref.jcas.xml
@@ -46,28 +46,23 @@
   <para>The data in the CAS are typed objects having fields. JCas uses a set of generated Java

     classes (each corresponding to a particular CAS type) with <quote>getter</quote> and

     <quote>setter</quote> methods for the features, plus a constructor so new instances can

-    be made. The Java classes don&apos;t actually store the data in the class instance;

-    instead, the getters and setters forward to the underlying CAS data representation.

-    Because of this, applications which use the JCas interface can share data with annotators

-    using plain CAS (i.e., not using the JCas approach). </para>

+    be made. The Java classes stores the data in the class instance.</para>

   

     <para>Users can modify the JCas generated

     Java classes by adding fields to them; this allows arbitrary non-CAS data to also be

     represented within the JCas objects, as well; however, the non-CAS data stored in the JCas

-    object instances cannot be shared with annotators using the plain CAS.</para>

-  

-  <para>Data in the CAS initially has no corresponding JCas type instances; these are created

-    as needed at the first reference. This means, if your annotator is passed a large CAS having

-    millions of CAS feature structures, but you only reference a few of them, and no previously

-    created Java JCas object instances were created by upstream annotators, the only Java

-    objects that will be created will be those that correspond to the CAS feature structures

-    that you reference.</para>

+    object instances cannot be shared with annotators using the plain CAS, unless special

+    provision is made - see the chapter in the v3 user's guide on storing arbitrary

+    Java objects in the CAS.</para>

   

   <para>The JCas class Java source files are generated from XML type system descriptions. The

     JCasGen utility does the work of generating the corresponding Java Class Model for the CAS

     types. There are a variety of ways JCasGen can be run; these are described later. You

     include the generated classes with your UIMA component, and you can publish these classes

     for others who might want to use your type system.</para>

+    

+  <para>JCas classes are not required for all UIMA types.  Those types which don&apos;t have 

+    corresponding JCas classes use the nearest JCas class corresponding to a type in their superchain.</para>

   

   <para>The specification of the type system in XML can be written using a conventional text

     editor, an XML editor, or using the Eclipse plug-in that supports editing UIMA

@@ -81,8 +76,7 @@
   

   <para>A separate Java class is generated for each type; this type implements the CAS

     FeatureStructure interface, as well as having the special getters and setters for the

-    included features. In the current implementation, an additional helper class per type is

-    also generated. The generated Java classes have methods (getters and setters) for the

+    included features. The generated Java classes have methods (getters and setters) for the

     fields as defined in the XML type specification. Descriptor comments are reflected in the

     generated Java code as Java-doc style comments.</para>

   

@@ -171,6 +165,7 @@
     + ", size right mods: " + getrMods().size();

 }</programlisting>

  

+   <!-- does not apply for v3

     <section id="ugr.ref.jcas.data_persistence">

       <title>Persistence of additional data</title>

       <para>If you add custom instance fields to JCas cover classes, these exist in the JCas cover object instance,

@@ -188,6 +183,8 @@
         prevents them from being garbage collected, it is normally recommended running with the

         JCAS_CACHE_ENABLE set to "false".</para>

     </section>   

+     -->

+     

     <section id="ugr.ref.jcas.keeping_augmentations_when_regenerating">

       <title>Keeping hand-coded augmentations when regenerating</title>

       

@@ -485,7 +482,9 @@
 ir.getIndex(name-of-index, Foo.type) // filtered by specific type

 

 ir.getAnnotationIndex()      // get AnnotationIndex

+jcas.getAnnotationIndex()    // get directly from jcas

 ir.getAnnotationIndex(Foo.type)      // filtered by specific type</programlisting>

+jcas.getAnnotationIndex(Foo.class)   // better

       

       <para>For convenience, the getAnnotationIndex method is available directly on the JCas object

       instance; the implementation merely forwards to the associated index repository.</para>

@@ -494,7 +493,7 @@
         index specification. They can be written as either Foo.type or if you have an instance

         of Foo, you can write</para>

       

-      <programlisting>fooInstance.jcasType.casType.  </programlisting>

+      <programlisting>fooInstance.getClass()</programlisting>

       

       <para>Foo is (of course) an example of the name of the type.</para>

       

@@ -510,10 +509,10 @@
       <programlisting>myInstance.addToIndexes();</programlisting>

       

       <para>Do this after setting all features in the instance <emphasis role="bold-italic">which could be used in indexing</emphasis>, 

-        for example, in determining the sorting order.  Changing the value of a feature used in a key,

-        after the feature structure has been added to the indexes, is inefficient, and must be done carefully,

-        in order to protect the indexes from corruption.  See <xref linkend="ugr.ref.cas.updating_indexed_feature_structures"/>;

-        the <code>protectIndexes</code> method is available on the JCas as well as the CAS.</para>

+        for example, in determining the sorting order.   

+        See <xref linkend="ugr.ref.cas.updating_indexed_feature_structures"/> for details

+        on updating indexed feature structures.

+      </para>

         

       <para>When writing a Multi-View component, you may need to index instances in multiple

         CAS views. The methods above use the indexes associated with the current JCas object.

@@ -567,6 +566,9 @@
     <section id="ugr.ref.jcas.using_iterators">

       <title>Using Iterators</title>

       

+      <para>This chapter describes obtaining and using iterators.  However, it is recommended that instead 

+        you use the select framework, described in a chapter in the version 3 user's guide.</para>

+        

       <para>Once you have an index obtained from the JCas, you can get an iterator from the

         index; here is an example:</para>

       

diff --git a/uima-docbook-references/src/docbook/ref.xml.component_descriptor.xml b/uima-docbook-references/src/docbook/ref.xml.component_descriptor.xml
index f86dd86..9609c53 100644
--- a/uima-docbook-references/src/docbook/ref.xml.component_descriptor.xml
+++ b/uima-docbook-references/src/docbook/ref.xml.component_descriptor.xml
@@ -154,16 +154,25 @@
       <programlisting>

 ResourceManager resMgr = UIMAFramework.newDefaultResourceManager();

 resMgr.setDataPath(yourPathString);

-AnalysisEngine ae = UIMAFramework.produceAE(desc, resMgr, null);

+AnalysisEngine ae = 

+  UIMAFramework.produceAnalysisEngine(desc, resMgr, null);

 </programlisting></para>

     

     <para>The default datapath for the entire JVM can be set via the

       <literal>uima.datapath</literal> Java system property, but this feature should

       only be used for standalone applications that don&apos;t need to run in the same JVM as

       other code that may need a different datapath.</para>

+

+    <para>The value of a name or location attribute may be parameterized with references to external

+    override variables using the <literal>${variable-name}</literal> syntax.

+    <programlisting>&lt;import location="Annotator${with}ExternalOverrides.xml" /&gt;</programlisting>

+	If a variable is undefined the value is left unmodified and a warning message identifies the missing

+	variable.</para>

+

     <para>Previous versions of UIMA also supported XInclude. That support didn't work in

       many situations, and it is no longer supported. To include other files, please use

       &lt;import&gt;.</para>

+

     <!--

     <para>The UIMA SDK also supports XInclude, a W3C candidate recommendation,

     to include XML files within other XML files.  However, it is recommended that the import syntax be used instead, as it

@@ -682,7 +691,8 @@
               Information in the CAS is always accessed through an index. There is a built-in default annotation

               index declared which can be used to access instances of type

               <literal>uima.tcas.Annotation</literal> (or its subtypes), sorted based on their

-              <literal>begin</literal> and <literal>end</literal> features. For all other types, there is a

+              <literal>begin</literal> and <literal>end</literal> features, and the type priority ordering (if specified). 

+              For all other types, there is a

               default, unsorted (bag) index. If there is a need for a specialized index it must be declared in this

               element of the descriptor. See <olink targetdoc="&uima_docs_ref;"

                 targetptr="ugr.ref.cas.indexes_and_iterators"/> for details on FS indexes.</para>

@@ -731,7 +741,7 @@
               <literal>&lt;kind&gt;</literal> of index. Sorted indexes enforce an

               ordering of feature structures, based on defined keys.  Bag indexes do

               not enforce ordering, and have no defined keys. Set indexes do not

-              enforce ordering, but use defined keys to specify equivalnce classes; 

+              enforce ordering, but use defined keys to specify equivalence classes; 

               addToIndexes will not add a Feature Structure to a set index if its keys 

               match those of an entry of the same type already in the index.

               If the <literal>&lt;kind&gt;</literal>element is omitted, it will default to

@@ -1101,6 +1111,13 @@
               it will complain that it can&apos;t connect to the host <quote>org</quote>

               </para>

             

+			<para>The URL value may contain references to external override variables using the

+ 		      <literal>${variable-name}</literal> syntax, 

+			  e.g. <literal>file:com/${dictUrl}.txt</literal>.

+			  If a variable is undefined the value is left unmodified and a warning message

+ 		      identifies the missing variable.

+			  </para>

+

             <para>Another option is a

               <literal>&lt;fileLanguageResourceSpecifier&gt;</literal>, which is

               intended to support resources, such as dictionaries, that depend on the

@@ -1945,9 +1962,12 @@
             <para>

             The settings for all descriptors in a pipeline are usually loaded from one or more files

             whose names are obtained from the Java system property <emphasis>UimaExternalOverrides</emphasis>.

-            The value of the property must be a list of file names, each separated by a single comma 

-            e.g. <literal>&minus;DUimaExternalOverrides=file1.settings,file2.settings</literal>.

-            If a file is not in the filesystem and is a relative reference, both the datapath and classpath are searched.

+            The value of the property must be a comma-separated list of resource names.  If the name

+            has a prefix of "file:" or no prefix, the filesystem is searched.  If the name has a

+            prefix of "path:" the rest must be a Java-style dotted name, similar to the name

+            attribute for descriptor imports.  The dots are replaced by file separators and a suffix

+            of ".settings" is appended before searching the datapath and classpath.

+            e.g. <literal>&minus;DUimaExternalOverrides=/data/file1.settings,file:relative/file2.settings,path:org.apache.uima.resources.file3</literal>.

             </para>

 

             <para>

@@ -2072,6 +2092,16 @@
             </para>

           </section>

 

+          <section id="&tp;aes.other_uses_for_external_configuration_parameters">

+            <title>Other Uses for External Configuration Parameters</title>

+			<para>

+            Explicit references to shared configuration parameters can be specified as part of the

+            value of the name and location attributes of the <literal>import</literal> element

+			and in the value of the fileUrl for a <literal>fileResourceSpecifier</literal>

+			(see <xref linkend="&tp;imports"/> and <xref linkend="&tp;aes.primitive.resource_manager_configuration"/>).

+            </para>

+		  </section>

+

         </section>

       </section>

  

@@ -2120,7 +2150,7 @@
       <literal>resourceManagerConfiguration</literal> elements are exactly the same as

       in Primitive Analysis Engine Descriptors (see <xref

         linkend="&tp;aes.primitive.external_resource_dependencies"/> and <xref

-        linkend="&tp;aes.primitive.resource_manager_configuration"/>.</para>

+        linkend="&tp;aes.primitive.resource_manager_configuration"/>).</para>

     

   </section>

   

@@ -2216,7 +2246,7 @@
         <literal>resourceManagerConfiguration</literal> elements are exactly the same

         as in the Primitive Analysis Engine Descriptors (see <xref

           linkend="&tp;aes.primitive.external_resource_dependencies"/> and <xref

-          linkend="&tp;aes.primitive.resource_manager_configuration"/>.</para>

+          linkend="&tp;aes.primitive.resource_manager_configuration"/>).</para>

       

     </section>

     <section id="&tp;collection_processing_parts.cas_initializer">

@@ -2360,7 +2390,7 @@
         <literal>resourceManagerConfiguration</literal> elements are exactly the same

         as in Primitive Analysis Engine Descriptors (see <xref

           linkend="&tp;aes.primitive.external_resource_dependencies"/> and <xref

-          linkend="&tp;aes.primitive.resource_manager_configuration"/>.</para>

+          linkend="&tp;aes.primitive.resource_manager_configuration"/>).</para>

       

     </section>

   </section>

diff --git a/uima-docbook-tools/pom.xml b/uima-docbook-tools/pom.xml
index 23ca7a2..b329e6e 100644
--- a/uima-docbook-tools/pom.xml
+++ b/uima-docbook-tools/pom.xml
@@ -42,13 +42,13 @@
        element, and just changing the following two properties -->  

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uima-docbook-tools

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uima-docbook-tools

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uima-docbook-tools

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uima-docbook-tools

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uima-docbook-tools

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uima-docbook-tools

     </url>

   </scm>

   

diff --git a/uima-docbook-tutorials-and-users-guides/pom.xml b/uima-docbook-tutorials-and-users-guides/pom.xml
index 77da087..d43acef 100644
--- a/uima-docbook-tutorials-and-users-guides/pom.xml
+++ b/uima-docbook-tutorials-and-users-guides/pom.xml
@@ -42,13 +42,13 @@
        element, and just changing the following two properties -->  

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uima-docbook-tutorials-and-users-guides

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uima-docbook-tutorials-and-users-guides

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uima-docbook-tutorials-and-users-guides

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uima-docbook-tutorials-and-users-guides

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uima-docbook-tutorials-and-users-guides

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uima-docbook-tutorials-and-users-guides

     </url>

   </scm>

   

diff --git a/uima-docbook-tutorials-and-users-guides/src/docbook/annotator_analysis_engine_guide.xml b/uima-docbook-tutorials-and-users-guides/src/docbook/annotator_analysis_engine_guide.xml
index 8f2fe7a..9944a3f 100644
--- a/uima-docbook-tutorials-and-users-guides/src/docbook/annotator_analysis_engine_guide.xml
+++ b/uima-docbook-tutorials-and-users-guides/src/docbook/annotator_analysis_engine_guide.xml
@@ -70,12 +70,20 @@
     easy-to-use, native Java interface to the CAS called the <emphasis>JCas</emphasis>.

     The JCas represents each feature structure as a Java object; the example feature

     structure from the previous paragraph would be an instance of a Java class Person with

-    getFullName() and setFullName() methods. Though the examples in this guide all use the

-    JCas, it is also possible to directly access the underlying CAS system; for more

-    information see <olink targetdoc="&uima_docs_ref;"/>

-    <olink targetdoc="&uima_docs_ref;" targetptr="ugr.ref.cas"/>

-    .</para>

+    getFullName() and setFullName() methods. 

+  </para>

   

+  <para>The CAS interface for accessing feature structures uses UIMA Type an Feature object instances,

+    which are computed at run time, depending on the type system being used.  This interface supports

+    writing general annotators which can work for all type systems.  It is used, for example, internally,

+    in the CasCopier implementation, to copy the content of one CAS to another.

+  </para>

+  

+  <para>The JCas interface can take advantage of knowing ahead of time the particular Types and Features

+    a pipeline is using.  The JCas Classes correspond to a particular UIMA type, and the class includes 

+    special setters and getters whose names match the features.

+  </para>

+    

   <para>The remainder of this chapter will refer to the analysis of text documents and the

     creation of annotations that are attached to spans of text in those documents. Keep in mind

     that the CAS can represent arbitrary types of feature structures, and feature structures

@@ -153,9 +161,8 @@
       Also you may wish to refer to the UIMA SDK Javadocs located in the <ulink

         url="api/index.html">docs/api/index.html</ulink> directory.</para>

     

-        <note><para>In Eclipse 3.1, if you highlight a UIMA class or method defined in the UIMA SDK

-    Javadocs, you can conveniently have Eclipse open the corresponding Javadoc for that

-    class or method in a browser, by pressing Shift + F2.</para></note>

+        <note><para>If you hover over a UIMA class or method defined in the UIMA SDK

+    Javadocs, the Javadocs appear after a short delay. </para></note>

     <note><para>If you downloaded the source distribution for UIMA, you can attach that as

     well to the library Jar files; for information on how to do this, see

     <olink targetdoc="&uima_docs_ref;"/>

@@ -453,28 +460,25 @@
   // get document text

   String docText = aJCas.getDocumentText();

   // search for Yorktown room numbers

-  Matcher matcher = mYorktownPattern.matcher(docText);

+  Matcher m = mYorktownPattern.matcher(docText);

   int pos = 0;

-  while (matcher.find(pos)) {

-    // found one - create annotation

-    RoomNumber annotation = new RoomNumber(aJCas);

-    annotation.setBegin(matcher.start());

-    annotation.setEnd(matcher.end());

+  while (m.find(pos)) {

+    // found one - create annotation, with the begin/end positions

+    RoomNumber annotation = new RoomNumber(aJCas, m.start(), m.end());

     annotation.setBuilding("Yorktown");

     annotation.addToIndexes();

-    pos = matcher.end();

+    pos = m.end();

   }

+  

   // search for Hawthorne room numbers

-  matcher = mHawthornePattern.matcher(docText);

+  m = mHawthornePattern.matcher(docText);

   pos = 0;

-  while (matcher.find(pos)) {

-    // found one - create annotation

-    RoomNumber annotation = new RoomNumber(aJCas);

-    annotation.setBegin(matcher.start());

-    annotation.setEnd(matcher.end());

+  while (m.find(pos)) {

+    // found one - create annotation, with the begin/end positions

+    RoomNumber annotation = new RoomNumber(aJCas, m.start(), m.end());

     annotation.setBuilding("Hawthorne");

     annotation.addToIndexes();

-    pos = matcher.end();

+    pos = m.end();

   }

 }</programlisting>

       

@@ -483,9 +487,7 @@
         calling some set methods:</para>

       

       

-      <programlisting>RoomNumber annotation = new RoomNumber(aJCas);

-annotation.setBegin(matcher.start());

-annotation.setEnd(matcher.end());

+      <programlisting>RoomNumber annotation = new RoomNumber(aJCas, m.start(), m.end());

 annotation.setBuilding("Yorktown");</programlisting>

       

       <para>The <literal>RoomNumber</literal> class was generated from the type system description by the

@@ -929,40 +931,101 @@
       <title>Logging</title>

       

       <para>The UIMA SDK provides a logging facility, which is very similar to the

-        java.util.logging.Logger class that was introduced in Java 1.4.</para>

+        java.util.logging.Logger class that was introduced in Java 1.4.

+        In addition, it includes the SLF4j framework <ulink url="https://www.slf4j.org/"/>

+        and all the methods in that framework's <code>Logger</code> API, plus

+        the Java 8 specific API extensions that take <code>Supplier</code> parameters.</para>

       

-      <para>In the Java architecture, each logger instance is associated with a name. By

-        convention, this name is often the fully qualified class name of the component

-        issuing the logging call. The name can be referenced in a configuration file when

-        specifying which kinds of log messages to actually log, and where they should

-        go.</para>

+      <para>Each logger instance is associated with a name. By

+        convention, this name is usually a hierarchy of simple names connected with periods, 

+        often the fully qualified class name of the component

+        issuing the logging call. The name (or any of its parents - starting prefixes up to a period) 

+        can be referenced in a configuration file which can then configure for each logger

+        various things such as the logging level and where messages should go.</para>

       

       <para>The UIMA framework supports this convention using the

         <literal>UimaContext</literal> object. If you access a logger instance using

-        <literal>getContext().getLogger()</literal> within an Annotator, the logger

+        <literal>getContext().getLogger()</literal> or the shorter, but equivalent

+        <literal>getLogger()</literal>

+        within an Annotator, the logger

         name will be the fully qualified name of the Annotator implementation class.</para>

-      

+              

       <para>Here is an example from the process method of

         <literal>org.apache.uima.tutorial.ex2.RoomNumberAnnotator</literal>:

         

+        <programlisting>getLogger().trace("Found: {}", () -> annotation.toString());</programlisting>

+      </para>

+

+      <para>The <code>trace</code> call 

+        indicates that this is a tracing message. This is useful for tracing program flow, but it is a low level which

+        is not usually enabled. 

+      </para>

         

-        <programlisting>getContext().getLogger().log(Level.FINEST,"Found: " + annotation);</programlisting>

+      <para>

+        The first parameter is the message, with substitutable parts.  The convention for where those parts go is

+        written as either {} or {n}, where "n" is an integer, specifying the argument number.  

+        The modern logging APIs use the {} style, with API calls such as 

+        <code>logger.**level**( msg-using-{}-convention, substitutable-arguments)</code>, while the older

+        java.util.logger framework uses <code>logger.log(**level**, msg-using-{n} convention, substitutable-arguments)</code>.

+      </para>

+        

+      <para>

+        UIMA supports both styles.  

+        For new code, it is recommended to use the first style, together with the Java 8 lambda method for the arguments, which 

+        insures that the work of turning the <code>annotation</code>

+        argument into a printable string only will happen if tracing is enabled.

+      </para>

+         

+      <para>Log statements are "filtered" according to the logging configuration, by Level, and sometimes by

+        additional indicators, such as Markers.  Levels work in a hierarchy.  A given level of 

+        filtering passes that level and all higher levels.  Some levels have two names, due to the 

+        way the different logger back ends name things.  Most levels are also used as method names on 

+        the logger, to indicate logging for that level.  For example, you could say <code>aLogger.log(Level.INFO, message)</code>

+        but you can also say <code>aLogger.info(message)</code>). The level ordering, highest to lowest, 

+        and the associated method names are as follows:

+        <itemizedlist spacing="compact">

+          <listitem><para>SEVERE or ERROR; error(...)</para></listitem>

+          <listitem><para>WARN or WARNING; warn(...)</para></listitem>

+          <listitem><para>INFO; info(...)</para></listitem>

+          <listitem><para>CONFIG; info(UIMA_MARKER_CONFIG, ...)</para></listitem>

+          <listitem><para>FINE or DEBUG; debug(...)</para></listitem>

+          <listitem><para>FINER or TRACE; trace(...)</para></listitem>

+          <listitem><para>FINEST; trace(UIMA_MARKER_FINEST, ...)</para></listitem>

+        </itemizedlist>

         </para>

+        

+        <para>The CONFIG and FINEST levels are merged with other levels, but are distinguished by having 

+        <code>Markers</code>.  If the filtering is configured to pass CONFIG level, then it will pass also the

+        INFO/WARN/ERROR  (or their alternative names WARNING/SEVERE) levels as well.

+        </para>

+       

       

-      <para>The first argument to the log method is the level of the log output. Here, a value of

-        FINEST indicates that this is a highly-detailed tracing message. While useful for

-        debugging, it is likely that real applications will not output log messages at this

-        level, in order to improve their performance. Other defined levels, from lowest to

-        highest importance, are FINER, FINE, CONFIG, INFO, WARNING, and SEVERE.</para>

+      <para>Each logging backend has its own documentation for how 

+        to configure loggers at run time, via configuration files or APIs in some cases.

+        Some backends even allow dynamic reconfiguration

+        while running, just by updating the configuration file (it is re-loaded every so often, if changed).

+      </para>

       

-      <para>If no logging configuration file is provided (see next section), the Java

-        Virtual Machine defaults would be used, which typically set the level to INFO and

+      <para>For the built-in-to-Java logging back end, if no logging configuration file is provided (see next section), 

+        the Java Virtual Machine defaults would be used, which typically set the level to INFO and

         higher messages, and direct output to the console.</para>

-      

-      <para>If you specify the standard UIMA SDK <literal>Logger.properties,</literal>

+                

+      <para>The UIMA logger is by default implemented using an SLF4J implementation; this (in turn) connects to

+        a logging back end, determined via a search of the classpath for a connector.  If none can be found,

+        then a message to that effect will be printed to System.err, and no logging will be done.

+        The binary distribution for UIMA includes, in its <code>lib</code> directory, the 

+        Jar which connects SLF4j to the Java-built-in logger to use as

+        its back end, so if you use the standard launchers, you will get this logging back end. 

+        </para>

+        

+      <para>Assuming you are using the Java-built-in-logger as the back-end, 

+        if you specify the configuration using the standard UIMA SDK <literal>Logger.properties</literal>

+        (found in <code>UIMA_HOME/config/</code>),

         the output will be directed to a file named uima.log, in the current working directory

         (often the <quote>project</quote> directory when running from Eclipse, for

-        instance).</para> <note><para>When using Eclipse, the uima.log file, if written

+        instance).</para> 

+        

+        <note><para>When using Eclipse, the uima.log file, if written

       into the Eclipse workspace in the project uimaj-examples, for example, may not appear

       in the Eclipse package explorer view until you right-click the uimaj-examples project

       with the mouse, and select <quote>Refresh</quote>. This operation refreshes the

@@ -971,12 +1034,15 @@
       Preferences &rarr; General &rarr; Workspace, then click the <quote>refresh

       automatically</quote> checkbox.</para></note>

       

+      <para>The next several sections mainly describe how to configure the built-in

+        Java logger.  See the documentation for other logging back ends for 

+        details on how to configure those.</para>

+         

       <section id="ugr.tug.aae.logging.configuring">

-        <title>Specifying the Logging Configuration</title>

+        <title>Specifying the Logging Configuration when using Java's built-in logger</title>

         

-        <para>The standard UIMA logger uses the underlying Java 1.4 logging mechanism. You

-          can use the APIs that come with that to configure the logging. In addition, the

-          standard Java 1.4 logging initialization mechanisms will look for a Java System

+        <para>The

+          standard Java built-in logging initialization mechanisms will look for a Java System

           Property named <literal>java.util.logging.config.file</literal> and if

           found, will use the value of this property as the name of a standard

           <quote>properties</quote> file, for setting the logging level. Please refer to

@@ -991,7 +1057,7 @@
           to the console. You can edit these files, or create additional ones, as described

           below, to change the logging behavior.</para>

         

-        <para>When running your own Java application, you can specify the location of the

+        <para>When running your own Java application, you can specify the location of this

           logging configuration file on your Java command line by setting the Java system

           property <literal>java.util.logging.config.file</literal> to be the logging

           configuration filename. This file specification can be either absolute or

@@ -1018,7 +1084,7 @@
       </section>

       

       <section id="ugr.tug.aae.logging.setting_logging_levels">

-        <title>Setting Logging Levels</title>

+        <title>Setting Logging Levels when using Java's built-in logger</title>

         

         <para>Within the logging control file, the default global logging level specifies

           which kinds of events are logged across all loggers. For any given facility this

@@ -1045,7 +1111,7 @@
       </section>

       

       <section id="ugr.tug.aae.logging.output_format">

-        <title>Format of logging output</title>

+        <title>Configuring the format of logging output when using Java's built-in logger</title>

         

         <para>The logging output is formatted by handlers specified in the properties file

           for configuring logging, described above. The default formatter that comes with

@@ -1062,7 +1128,7 @@
       </section>

       

       <section id="ugr.tug.aae.logging.meaning_of_severity_levels">

-        <title>Meaning of the logging severity levels</title>

+        <title>Meaning of the logging severity levels used by the UIMA logger</title>

         

         <para>These levels are defined by the Java logging framework, which was

           incorporated into Java as of the 1.4 release level. The levels are defined in the

@@ -1104,42 +1170,70 @@
       </section>

       

       <section id="ugr.tug.aae.logging.using_outside_of_an_annotator">

-        <title>Using the logger outside of an annotator</title>

+        <title>Using loggers outside of an annotator</title>

         

         <para>An application using UIMA may want to log its messages using the same logging

-          framework. This can be done by getting a reference to the UIMA logger, as follows:

+          framework. This can be done by getting a reference to the UIMA logger, as follows:                  

+          <programlisting>Logger logger = UIMAFramework.getLogger(TestClass.class);</programlisting>.

+        </para>

           

-          

-          <programlisting>Logger logger = UIMAFramework.getLogger(TestClass.class);</programlisting>

-          </para>

+        <para>You can also simply get a direct reference to an Slf4j logger using the standard approach:

+          <programlisting>org.slf4j.Logger logger = org.slf4j.LogFactory.getLogger(TestClass.class);</programlisting>

+        </para>

         

-        <para>The optional class argument allows filtering by class (if the log handler

-          supports this). If not specified, the name of the returned logger instance is

+        <para>The class argument specifies the name of the logger, using the fully qualified class name. 

+          For UIMA loggers, if not specified, the name of the returned logger instance is

           <quote>org.apache.uima</quote>.</para>

       </section>

       

       <section id="ugr.tug.aae.logging.change_logger_implementation">

         <title>Changing the underlying UIMA logging implementation</title>

         

-        <para>By default the UIMA framework use, under the hood of the UIMA Logger interface, the Java logging framework 

-        to do logging. But it is possible to change the logging implementation that UIMA use from Java logging to 

-        an arbitrary logging system when specifying the system property  

-          <programlisting>-Dorg.apache.uima.logger.class=&lt;loggerClass></programlisting>

-        when the UIMA framework is started.

-        </para>

-        <para>

-          The specified logger class must be available in the classpath and have to implement the 

-          <code>org.apache.uima.util.Logger</code> interface. 

+        <para>By default the UIMA framework uses, under the hood of the UIMA Logger interface, the 

+        SLF4J logging framework to do logging. This allows UIMA, when running embedded inside other frameworks,

+        to defer the choice of back-end logging frameworks to those applications.

         </para>

         

-        <para>

-          UIMA also provides a logging implementation that use Apache Log4j instead of Java logging. To

-          use Log4j you have to provide the Log4j jars in the classpath and your application 

-          must specify the logging configuration as shown below. 

-          <programlisting><?db-font-size 80% ?>-Dorg.apache.uima.logger.class=org.apache.uima.util.impl.Log4jLogger_impl</programlisting>

+        <para>For backwards compatibility with Version 2, the older methods (prior to Slf4j) for switching the

+        logger implementation remains.     

+        You do this by specifying the system property  

+          <programlisting>-Dorg.apache.uima.logger.class=&lt;loggerClass></programlisting>

+        when the UIMA framework is started.  

         </para>

+        <para>

+          The specified logger class must be available in the classpath and has to subclass the 

+          <code>org.apache.uima.util.Logger_common_impl</code> class. 

+        </para>

+

+        <para>For backwards compatibility, V3 continues to provide the class

+           <code>org.apache.uima.util.impl.Log4jLogger_impl</code> as an alternative

+           which can be specified this way by this JVM argument:

+           <programlisting><?db-font-size 80% ?>-Dorg.apache.uima.logger.class=org.apache.uima.util.impl.Log4jLogger_impl</programlisting>

+           to switch to the log4j back end.  This has been updated in V3 to <code>log4j 2</code>

+           (see <ulink url="https://logging.apache.org/log4j"/>).

+           If you use this, you must provide the required <code>Log4j 2</code> jars in the classpath.

+         </para>        

+                 

       </section>

       

+      <section id="uv3.logging.suppress_annotator_logging">

+        <title>Throttling excessive logging from Annotators</title>

+        

+        <para>Sometimes, in production, you may find annotators are logging excessively, and you wish to throttle 

+          this. But you may not have access to logging settings to control this,

+          perhaps because UIMA is running as a library component within another framework. 

+          For this special case,

+          you can limit logging done by Annotators by passing an additional parameter to the UIMA Framework's 

+          produceAnalysisEngine API, using the key name 

+          <code>AnalysisEngine.PARAM_THROTTLE_EXCESSIVE_ANNOTATOR_LOGGING</code>

+          and setting the value to an Integer object equal to the the limit.  Using 0 will suppress all logging.

+          Any positive number allows that many log records to be logged, per level.  A limit of 10 would allow 

+          10 Errors, 10 Warnings, etc.  The limit is enforced separately, per logger instance.</para>

+          

+          <note><para>This only works if the logger used by Annotators is obtained from the 

+          Annotator base implementation class via the <code>getLogger()</code> method.</para></note>

+            

+      </section>  

       

     </section>

   </section>  

@@ -1306,35 +1400,38 @@
       <para>So far, we have been looking at annotators that look directly at the document text. However, annotators

         can also use the results of other annotators. One useful thing we can do at this point is look for the

         co-occurrence of a Date, a RoomNumber, and two Times &ndash; and annotate that as a Meeting.</para>

+        

+      <para>The <code>select</code> API, available on the CAS, JCas, and individual UIMA indexes, 

+        is the preferred way to get 

+        feature structures from the CAS and work with them.</para>  

       

       <para>The CAS maintains <emphasis>indexes</emphasis> of annotations, and from an index you can obtain an

-        iterator that allows you to step through all annotations of a particular type. Here&apos;s some example code

-        that would iterate over all of the TimeAnnot annotations in the JCas:

+        iterator that allows you to step through all annotations of a particular type in that index.

+        Indexes are optional; they allow you to specify a sorting order or can specify set-inclusion

+        criteria.  One built-in index is the Annotation index; this contains sorted instances of type Annotation 

+        or its subtypes.

+      </para> 

+      

+      <para>

+        Here&apos;s some example code

+        that would iterate over all of the TimeAnnot annotations in the JCas, in some unspecified order:

         

-        

-        <programlisting>for (TimeAnnot : aJCas.&lt;TimeAnnot&gt;select(TimeAnnot.class)) {

+        <programlisting>for (TimeAnnot : aJCas.select(TimeAnnot.class)) {

   //do something

 }</programlisting></para>

       

-      <note>

-      <para>You can also use the method

-        <literal>aJCas.getAllIndexedFS(YourClass.type)</literal>, which returns an iterator

-        over instances of <literal>YourClass</literal> in no particular order. 

+      <para>

+        The same code, but using the Annotation index to specify an ordering (assuming that

+        TimeAnnot is a subtype of Annotation):

         

-        <!-- Fixed by UIMA-4111 But beware - if you've defined

-        a <literal>set</literal> index for this type, and haven't defined any non-set indexes for this type, then,

-        the method would return only those instances in the set.  So, in a pathological case, if you defined the

-        set so that the key was some particular field, and all instances of this type had the same key, then 

-        only one instance of this type would be found.</para>

-        <para>To guarantee the existance of an index that would have an entry for all unique indexed 

-        Feature Structures, define a bag or sorted index for the type.

-        </para>.

-        

-

-        <para>All types which are subtypes of the built-in Annotation type have a sorted index, and so all instances of those

-        types are guaranteed to be found (at least once) by this iterator.   -->

-        

-        </para>

+        <programlisting>for (TimeAnnot : aJCas.getAnnotationIndex().select(TimeAnnot.class)) {

+  //do something

+}

+  // or

+for (TimeAnnot : aJCas.getAnnotationIndex(TimeAnnot.class).select()) {

+  //do something

+}

+</programlisting></para>

         

       <para>Also, if you've defined your own custom index as described in <olink targetdoc="&uima_docs_ref;"/>

         <olink targetdoc="&uima_docs_ref;"

@@ -1345,7 +1442,12 @@
       if you defined an index called "allEvents" over the type <literal>Event</literal>, and wanted 

       to get an index over just a particular subtype of event, say, <literal>TimeEvent</literal>,

       you can ask for that index using 

-        <literal>aJCas.getIndex("allEvents", TimeEvent.class)</literal>.</para></note>

+        <literal>aJCas.getIndex("allEvents", TimeEvent.class)</literal>.</para>

+      

+      

+      <para>Whereever the type is specified by TimeEvent.class, the APIs also allow the non-JCas 

+        specification of the type by passing an instance of a UIMA Type class. This alternative enables

+        writing code that can be used for any type, discovered at run time.</para>

       

       <para>Now that we&apos;ve explained the basics, let&apos;s take a look at the process method for

         <literal>org.apache.uima.tutorial.ex4.MeetingAnnotator</literal>. Since we&apos;re looking for a

@@ -2325,10 +2427,11 @@
     

     <para>Here are some things to avoid doing in your annotator code:</para>

     

-    <para><emphasis role="bold">Retaining references to JCas objects between calls to

-      process()</emphasis></para>

+    <para><emphasis role="bold">Do not retain references to JCas objects between calls to

+      process() for different CASes</emphasis></para>

     

-    <para>The JCas will be cleared between calls to your annotator&apos;s process() method.

+    <para>The JCas will be cleared between calls to your annotator&apos;s process() method

+      for each new CAS.

       All of the analysis results related to the previous document will be deleted to make way

       for analysis of a new document. Therefore, you should never save a reference to a JCas

       Feature Structure object (i.e. an instance of a class created using JCasGen) and

@@ -2355,7 +2458,7 @@
     <title>Viewing UIMA objects in the Eclipse debugger</title>

     <titleabbrev>UIMA Objects in Eclipse Debugger</titleabbrev>

     

-    <para>Eclipse (as of version 3.1 or later) has a new feature for viewing Java Logical

+    <para>Eclipse has a feature for viewing Java Logical

       Structures. When enabled, it will permit you to see a view of UIMA objects (such as

       feature structure instances, CAS or JCas instances, etc.) which displays the logical

       subparts. For example, here is a view of a feature structure for the RoomNumber

@@ -2372,8 +2475,8 @@
     </mediaobject>

   </screenshot></para>

     

-    <para>The <quote>annotation</quote> object in Java shows as a 2 element object, not very

-      convenient for seeing the features or the part of the input that is being annotatoed. But

+    <para>The <quote>annotation</quote> object in Java shows the internals of the JCas object, not very

+      convenient for seeing the features or the part of the input that is being annotated. But

       if you turn on the Java Logical Structure mode by pushing this button:

       

       

diff --git a/uima-docbook-tutorials-and-users-guides/src/docbook/tug.application.xml b/uima-docbook-tutorials-and-users-guides/src/docbook/tug.application.xml
index 7dccf03..a353d61 100644
--- a/uima-docbook-tutorials-and-users-guides/src/docbook/tug.application.xml
+++ b/uima-docbook-tutorials-and-users-guides/src/docbook/tug.application.xml
@@ -529,14 +529,14 @@
        <table frame="all" id="ugr.tug.tbl.serialization_capabilities">

           <title>Serialization Capabilities</title>

           <tgroup cols="8" rowsep="1" colsep="1">

-            <colspec colname="c1"/>

-            <colspec colname="c2"/>

-            <colspec colname="c3"/>

-            <colspec colname="c4"/>

-            <colspec colname="c5"/>

-            <colspec colname="c6"/>

-            <colspec colname="c7"/>

-            <colspec colname="c8"/>

+            <colspec colname="c1" colwidth="6*"/>

+            <colspec colname="c2" colwidth="5*"/>

+            <colspec colname="c3" colwidth="5*"/>

+            <colspec colname="c4" colwidth="5*"/>

+            <colspec colname="c5" colwidth="5*"/>

+            <colspec colname="c6" colwidth="5*"/>

+            <colspec colname="c7" colwidth="5*"/>

+            <colspec colname="c8" colwidth="5*"/>

             <thead>

               <row>

                 <entry align="center"></entry>

@@ -561,7 +561,7 @@
                 <entry>-</entry>

               </row>

               <row>

-                <entry>Lists/Arrays inline fmtng?</entry>

+                <entry>Lists/Arrays inline formating?</entry>

                 <entry>-</entry>

                 <entry>Yes</entry>

                 <entry>Yes</entry>

@@ -571,7 +571,7 @@
                 <entry>-</entry>

               </row>

               <row>

-                <entry>Fmtd?</entry>

+                <entry>Formated?</entry>

                 <entry>-</entry>

                 <entry>Yes</entry>

                 <entry>Yes</entry>

@@ -1196,6 +1196,7 @@
         

       </section>

     </section>

+    <!-- 

     <section id="ugr.tug.application.search.query_tool">

       <title>Semantic Search Query Tool</title>

       

@@ -1264,8 +1265,10 @@
         Engine query language and interface, see the documentation for the semantic search engine component on

           <ulink url="http://www.alphaworks.ibm.com/tech/uima"/>.</para>

     </section>

+       -->

   </section>

-  

+

+   

   <section id="ugr.tug.application.remote_services">

     <title>Working with Remote Services</title>

     

@@ -2079,10 +2082,6 @@
 	      performanceTuningSettings.setProperty(

 	            UIMAFramework.CAS_INITIAL_HEAP_SIZE, 

 	            "1000000");

-	      // Disable JCas cache.

-	      performanceTuningSettings.setProperty(

-	            UIMAFramework.JCAS_CACHE_ENABLED, 

-	            "false");

 	      // Create a wrapper properties object that can

 	      // be passed to the framework.

 	      Properties additionalParams = new Properties();

@@ -2103,26 +2102,15 @@
 	  <para>

 		  The following options are supported:

 		  <itemizedlist>

+        <!-- not used in v3

 		    <listitem>

-		      <para><literal>UIMAFramework.JCAS_CACHE_ENABLED</literal>: allows you to disable

-				  the JCas cache (true/false).  The JCas cache is an internal datastructure that caches any JCas 

-				  object created

-				  by the CAS.  This may result in better performance for applications that make extensive use of

-				  the JCas, but also incurs a steep memory overhead.  If you're processing large documents and have

-				  memory issues, you should disable this option.  In general, just try running a few experiments to

-				  see what setting works better for your application.  The JCas cache is enabled by default.  

-				  </para>

-		    </listitem>

-		    <listitem>

-				  <para><literal>UIMAFramework.CAS_INITIAL_HEAP_SIZE</literal>: set the initial CAS heap size in

-				  number of cells (integer valued).  The CAS uses 32bit integer cells, so four times the initial 

-				  size is the

-				  approximate minimum size of the CAS in bytes.  This is another space/time trade-off as growing

-				  the CAS heap is relatively expensive.  On the other hand, setting the initial size too high is

-				  wasting memory.  Unless you know you are processing very small or very large documents, you should

-				  probably leave this option unchanged.

+				  <para><literal>UIMAFramework.CAS_INITIAL_HEAP_SIZE</literal>:  

+            This is only used to help initialize the sizes of some internal tables.

+            You can leave it unspecified; but if you know the approximate number of feature structures

+            a pipeline will have, you can specify it.

 				  </para>

 		   </listitem>

+        -->

 		    <listitem>

 				  <para><literal>UIMAFramework.PROCESS_TRACE_ENABLED</literal>: enable the process trace mechanism

 				  (true/false).  When enabled, UIMA tracks the time spent in individual components of an aggregate 

diff --git a/uima-docbook-tutorials-and-users-guides/src/docbook/tug.multi_views.xml b/uima-docbook-tutorials-and-users-guides/src/docbook/tug.multi_views.xml
index d97a825..8943b32 100644
--- a/uima-docbook-tutorials-and-users-guides/src/docbook/tug.multi_views.xml
+++ b/uima-docbook-tutorials-and-users-guides/src/docbook/tug.multi_views.xml
@@ -566,15 +566,10 @@
         annotations for each associated CAS view. For the English Sofa:</para>

       

       

-      <programlisting>//get annotation iterator for this CAS

-FSIndex anIndex = aView.getAnnotationIndex();

-FSIterator anIter = anIndex.iterator();

-while (anIter.isValid()) {

-  AnnotationFS annot = (AnnotationFS) anIter.get();

+      <programlisting>for (Annotation annot : aView.getAnnotationIndex()) {

   System.out.println(" " + annot.getType().getName()

                          + ": " + annot.getCoveredText());

-  anIter.moveToNext();

-}</programlisting>

+}</programlisting>      

       

       <para>Iterating over all German annotations looks the same, except for the

         following:</para>

diff --git a/uima-docbook-v3-users-guide/pom.xml b/uima-docbook-v3-users-guide/pom.xml
index ee96b27..218d3d9 100644
--- a/uima-docbook-v3-users-guide/pom.xml
+++ b/uima-docbook-v3-users-guide/pom.xml
@@ -42,13 +42,13 @@
        element, and just changing the following two properties -->  

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uima-docbook-v3-users-guide

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uima-docbook-v3-users-guide

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uima-docbook-v3-users-guide

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uima-docbook-v3-users-guide

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uima-docbook-v3-users-guide

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uima-docbook-v3-users-guide

     </url>

   </scm>

   

diff --git a/uima-docbook-v3-users-guide/src/docbook/images/version_3_users_guide/custom_java_objects/5_steps.png b/uima-docbook-v3-users-guide/src/docbook/images/version_3_users_guide/custom_java_objects/5_steps.png
index f67f906..cd1b236 100644
--- a/uima-docbook-v3-users-guide/src/docbook/images/version_3_users_guide/custom_java_objects/5_steps.png
+++ b/uima-docbook-v3-users-guide/src/docbook/images/version_3_users_guide/custom_java_objects/5_steps.png
Binary files differ
diff --git a/uima-docbook-v3-users-guide/src/docbook/images/version_3_users_guide/migrate/multiples.png b/uima-docbook-v3-users-guide/src/docbook/images/version_3_users_guide/migrate/multiples.png
new file mode 100644
index 0000000..e2bb19e
--- /dev/null
+++ b/uima-docbook-v3-users-guide/src/docbook/images/version_3_users_guide/migrate/multiples.png
Binary files differ
diff --git a/uima-docbook-v3-users-guide/src/docbook/images/version_3_users_guide/select/select_selection_and_ordering.png b/uima-docbook-v3-users-guide/src/docbook/images/version_3_users_guide/select/select_selection_and_ordering.png
index ebdaaac..2d92ec9 100644
--- a/uima-docbook-v3-users-guide/src/docbook/images/version_3_users_guide/select/select_selection_and_ordering.png
+++ b/uima-docbook-v3-users-guide/src/docbook/images/version_3_users_guide/select/select_selection_and_ordering.png
Binary files differ
diff --git a/uima-docbook-v3-users-guide/src/docbook/images/version_3_users_guide/select/select_source_type.png b/uima-docbook-v3-users-guide/src/docbook/images/version_3_users_guide/select/select_source_type.png
index 0a9569e..544abe5 100644
--- a/uima-docbook-v3-users-guide/src/docbook/images/version_3_users_guide/select/select_source_type.png
+++ b/uima-docbook-v3-users-guide/src/docbook/images/version_3_users_guide/select/select_source_type.png
Binary files differ
diff --git a/uima-docbook-v3-users-guide/src/docbook/uv3.backwards_compatibility.xml b/uima-docbook-v3-users-guide/src/docbook/uv3.backwards_compatibility.xml
index d4e808a..90417c5 100644
--- a/uima-docbook-v3-users-guide/src/docbook/uv3.backwards_compatibility.xml
+++ b/uima-docbook-v3-users-guide/src/docbook/uv3.backwards_compatibility.xml
@@ -28,14 +28,25 @@
   <titleabbrev>Backwards Compatibility</titleabbrev>

   

   <para>Because users have made substantial investment in developing

-  applications using the UIMA framework, a goal is to protect this investment, by enabling

+  applications using the UIMA framework, a goal of version 3 is to protect this investment, by enabling

   Annotators and applications developed under previous versions to be able to be used in 

   subsequent versions of the framework.</para>

   

   <para>To this end, version 3 is designed to be backwards compatible, 

-  except for needing a new set of JCas classes (if these were

-  previously being used).  The creation of this new set of JCas classes is mostly automated via a 

-  migration tool that handles converting the existing JCas classes, described in a later chapter.

+  except for needing:

+  <itemizedlist>

+    <listitem>

+     <para>possibly a recompilation (due to some rearrangements of many classes and interfaces)</para>

+    </listitem>

+    <listitem>

+      <para>a new set of User-defined JCas classes (if these were

+        previously being used). The creation of these Cas classes

+        can be done by regenerating them using JCasGen, or by 

+        using a migration tool that handles converting the existing JCas classes.

+        A later chapter covers how to upgrade the JCas classes.</para>

+    </listitem>

+  </itemizedlist>

+  There are some additional exceptions, described in the following sections.

   </para>

   

   <section id="uv3.backwards_compatibility.jcas">  

@@ -45,19 +56,22 @@
       sister classes for each main JCas class.  User code is unlikely to access these sister classes.

       The JCas API method to access this sister class now throws a UnsupportedOperation exception.

     </para>

-    

-    <para>

-      New internal-use methods and fields have been added to the JCas classes.  The 

-      names for these have been carefully designed to reduce the likelihood of collision with previously

-      existing user code names; the usual technique is to start the names with a leading underscore character.

-      Users should consider these methods as internal use and subject to change with new releases.

-    </para>

-    

+        

     <para>The non-JCas Java cover classes for the built-in UIMA types remain, for backwards compatibility.

       So, if you have code that casts a Feature Structure instance to AnnotationImpl (a now deprecated 

-      version 2 non-JCas Java cover class), that will continue to work.

-      

-      </para>

+      version 2 non-JCas Java cover class), that will continue to work.  

+    </para>

+    

+    <section id="uv3.backwards_compatibility.jcas.names">  

+    <title>Additional reserved names in the JCas generated classes</title>

+    <titleabbrev>JCas reserved names</titleabbrev>

+

+    <para>Names beginning with "_" (underscore) are being used by the new JCas implementation, so you should not

+      name things with this convention.  If you do, please insure your names are not colliding with the names

+      being used by the generated JCas files.

+    </para>

+    

+    </section>

   </section>

   

   

@@ -69,35 +83,28 @@
 	  possible to have a UIMA-AS services working with a client, where the client is a version 3 instance, but the

 	  server is still a version 2 (or vice versa).</para>

 	  

-	  <para>Some formats like Binary and BinaryCompressedForm4 require the type systems match exactly.

-	  Version 3 adds some new built-in types, so the type systems won't match exactly; an accommodation is made

-	  when the version 3 deserialization detects that the serialized CAS was serialized with version 2, that

-	  enables version 3 to load version 2 serialized CASs, even for binary formats.  A planned extension for 

-	  UIMA-AS will allow version 3 clients to detect when a service is running version 2 code, and have the 

-	  serialization altered to be compatible with version 2 (provided that the new, built-in, types are not being used).

-	  </para>

-	  

 	  <section id="uv3.backwards_compatibility.serialization.deltas">  

 	    <title>Delta CAS Version 2 Binary deserialization not supported</title>

 	    

 	    <para>The binary serialization forms, including Compressed Binary Form 4, build an

 	      internal model of the v2 CAS in order to be able to deserialize v2 generated

-	      versions.  For delta CAS, this model cannot be accurately built, because version 3

+	      versions.  For <emphasis role="strong">delta</emphasis> CAS, this model cannot be accurately built, because version 3

 	      excludes from the model all unreachable Feature Structures, so in most cases it

 	      won't match the version 2 layout.  

 	    </para>

 	    

 	    <para>Version 3 will throw an exception if delta CAS deserialization of a version 2

-	      delta CAS is attempted.

+	      binary delta CAS is attempted.

 	    </para>

     </section>

 	  

   </section>

   

-  <section id="uv3.backards_compatibility.low_level_apis">

+  <section id="uv3.backwards_compatibility.low_level_apis">

     <title>APIs for creating and modifying Feature Structures</title>

     

-    <para>There are 3 sets of APIs for creating and modifying Feature Structures.

+    <para>There are 3 sets of APIs for creating and modifying Feature Structures;

+      all are supported in V3.

     <itemizedlist spacing="compact">

       <listitem>

         <para>Using the JCas classes</para>

@@ -113,10 +120,11 @@
     

     <para>Version 3 retains all 3 sets, to enable backward compatibility.</para>

     <para>The low level CAS interface was originally provided to enable a extra-high-performance

-      (but without type safety checks) mode.  In Version 3, this mode is actually somewhat slower than the others,

-      and no longer has any advantages.      

+      (but without compile-time type safety checks) mode.  

+      In Version 3, this mode is actually somewhat slower than the others, and no longer has any advantages.      

     </para>

-    <para>Using the low level CAS interface also blocks one of the new features of Version 3 - namely, automatic

+    <para>Using the low level CAS interface also sometimes blocks one of the new features of Version 3 - 

+    namely, automatic

     garbage collection of unreachable Feature Structures.  This is because creating a Feature Structure using the

     low level API creates the Java object for that Feature Structure, but returns an "int" handle to it.  

     In order to be able to find the Feature Structure, given that int handle, an entry is made in an internal map.

@@ -129,7 +137,109 @@
     

   </section>

   

-  <section id="uv3.backards_compatibility.PEARs">

+  <section id="uv3.backwards_compatibility.preserve_v2_ids">

+    <title>Preserving V2 ids, with low level CAS Api accessibility</title>

+    <titleabbrev>Preserving V2 Ids</titleabbrev> 

+    

+    <para>

+      Some V2 applications make use of the Feature Structure address, using these as an integer identifier

+      and using the low level CAS APIs to access the Feature Structure, given this integer.  These applications 

+       also often use the stability of these ids across some serialization/deserializations.

+    </para>

+    

+    <para>

+      Normally in V3, deserialization of CASs having these IDs occurs without preserving the IDs, and without setting

+      up the low level CAS APIs to be able to access these using them.  If an existing application depends

+      on the low level access via the address, a special mode, called <code>V2IdRefs</code>, can be specified, which will support this.

+      It comes at a cost however, which is that all new Feature Structures created (or deserialized) will be added to

+      an internal table to enable the low level CAS getFSForRef(int) method to work.  As a result, these Feature Structures

+      are not eligible for garbage collection. 

+    </para>

+    

+    <para>This mode is set on individual CASs via a new API; a default value may optionally be specified.

+      Once set on a CAS, it remains until set to a different value;

+      CAS Reset does not affect the setting, nor does checking it into / out of a CAS Pool.  

+    </para>

+    

+    <para>When a new CAS is created, this mode is set according to two sources:

+      <itemizedlist>

+        <listitem><para>a <code>-Duima.default_v2_id_references</code> system property, read once when the 

+        UIMA framework classes are loaded.</para>

+        </listitem>

+        <listitem><para>A run-time value kept per thread, managed by an API on the LowLevelCAS interface.  The 

+          setting is inherited by any child threads the thread creates, and 

+          overrides the system property if used.</para></listitem>

+        <listitem><para>If neither of these are used, then the default is to not be in the sepcial v2-mode.</para></listitem>

+      </itemizedlist> 

+    </para>

+    

+    <para>The APIs for this are part of the LowLevelCAS.  The controlling APIs all return an instance

+      of AutoClosableNoException, which can be used to reset the setting to its previous value.

+      A recommended way of using these is with the Java <code>try with resources</code> construct: 

+    <programlisting>try (AutoClosableNoException w = llcas.ll_enableV2IdRefs) {

+  ... some operations

+} // automatically restores previous value 

+</programlisting>   

+    </para>

+    

+    <para>LowLevelCas instance APIs for enabling/disabling this mode on a particular CAS:</para>

+    <programlisting>// set the mode    

+AutoClosable ll_enableV2IdRefs()

+

+// same, but with explicit set or reset of the mode

+AutoClosableNoException ll_enableV2IdRefs(true/false)

+

+// return true if the mode is enabled

+boolean is_ll_enableV2IdRefs() 

+</programlisting>

+

+    <para>Static LowLevelCas APIs for setting the default value for this mode for new CASs on a particular thread:</para>

+    <programlisting>

+// set the default    

+AutoClosableNoException LowLeveCas.ll_defaultV2IdRefs()

+

+// same, but with explicit set or reset of the mode

+AutoClosableNoException LowLeveCas.ll_defaultV2IdRefs(true/false)

+

+// return true if the mode is enabled

+boolean LowLeveCas.is_ll_defaultV2IdRefs() 

+</programlisting>   

+    

+    <para>This mode modifies multiple things in the operation of UIMA V3.</para>

+    <itemizedlist>

+      <listitem><para>Newly created Feature structures

+          have IDs which match what UIMA V2 references (the "addresses")

+          would be.  For serialized forms (except Xmi), these IDs

+          match the (imputed) v2 IDs of the serialized form.

+        </para>

+        

+        <para>Newly created Feature Structures, including those created when deserializing,

+          are added to an internal map which maps the ID to the Feature Structure instance.

+          Feature Structures may be located by ID using the LowLevelCAS API 

+          <code>getFSForRef().</code>

+        </para>

+        

+        <para>

+          In order for this to work correctly, the mode must be set while the CAS is empty.

+          If the mode is attempted to be set on a non-empty CAS, an IllegalStateException

+          is thrown.  

+          <!-- Serialized forms like Xmi and XCAS have the ids 

+          included in the external form;

+           -->

+        </para>

+      </listitem>

+      <listitem>

+        <para>This mode modifies serialization (except for XCas, Xmi, and Compressed form 6, which in V2 are

+          implemented to just serialize reachable Feature Structures) to include non-reachable FSs.

+        </para>            

+      </listitem>

+      <listitem><para>Note: This does not affect the <code>select</code> framework results - unreachable Feature Structures

+        are not included.</para></listitem>

+    </itemizedlist>

+         

+  </section>

+  

+  <section id="uv3.backwards_compatibility.PEARs">

     <title>PEAR support</title>   

     

     <para>Pears are supported in Version 3.  If they use JCas, their JCas classes need to be migrated.

@@ -166,9 +276,11 @@
       UIMA Type, inside and outside of the PEAR context.  

       If this is detected, a runtime exception is thrown.

     </para>

+    

+    <para>The workaround for this is to manually merge any JCas class definitions for the same class.</para>

   </section>

   

-  <section id="uv3.backards_compatibility.toString">

+  <section id="uv3.backwards_compatibility.toString">

     <title>toString()</title>   

     

     <para>

@@ -177,30 +289,83 @@
       situations such as testing, where the exact string representations

       are being compared.

     </para>

+    

+    <para>A special global Java property, -Duima.v2_pretty_print_format can be set to have the toString() operation

+      for Feature Sructures print in the V2 style.

+    </para>

   </section>

   

-  <section id="uv3.backards_compatibility.typesystem_sharing">

+  <section id="uv3.backwards_compatibility.logging">

+    <title>Logging configuration is somewhat different</title>   

+    

+    <para>The default logging configuration in v2 was to use Java Util Logging (the logger built into Java).

+    For v3, the default is to use SLF4J which, in turn, picks a back-end logger, depending on what it finds

+    in the class path.</para>

+    

+    <para>This change was done to permit easier integration of UIMA as a library running within other frameworks.

+    </para>

+    

+    <para>V3 UIMA logger includes the APIs like info(..), warn(..) etc., that are part of the 

+      SLF4j APIs.  In addition, these are augmented with the Java 8 style lambda arguments that

+      were introduced in log4j-2, for more concise and efficient log message computation.</para>

+      

+    <para>The new UIMA Logger APIs (e.g. logger.info(...), logger.warn(...)) 

+      use the SLF4j and other modern logger substitutable notation of "{}", as opposed

+      to the style adopted by the original Java logger, of "{nnn}".  All modern loggers have switched to

+      this. </para>  

+      

+    <para>The technique for (optionally) reporting the class and method (and sometimes, line number) 

+    was changed to conform to current logger conventions - whereby the loggers themselves obtain this

+    information from the call stack.  The V2 calls which pass in the sourceClass and sourceMethod information

+    have this information ignored, but replaced with what the loggers obtain from the stack track.

+    In some cases, where the callers in V2 were not actually passing in the correct class/method information,

+    this will result in a different log record.</para>

+    

+    <para>

+      For more details, please see the logging chapter.

+    </para>

+  </section>

+    

+  <section id="uv3.backwards_compatibility.typesystem_sharing">

     <title>Type System sharing</title>   

     

     <para>Type System definitions are shared when they are equal.  After type systems 

-    have been built up from type definitions, and are committed, a check is made to see if an

-    identical type system already exists.  This is often the case when a UIMA application is

+    have been built up from type definitions, at "commit" time, a check is made to see if an

+    identical type system already exists (same types and features).  

+    This is often the case when a UIMA application is

     scaling up by adding multiple pipelines, all using the same type system.  

     </para>

     

-    <para>If an identical type system is already created, then the commit operation returns 

-    the already created one, and the one just built is discarded.  Normally, this is not an issue.

-    However, some application code (for example, test cases) may construct type systems

-    programmatically, and along the way save references to defined types and features.  These

-    references can then become invalid when the type system is created and perhaps replaced with

-    an already existing one.</para>

+    <para>If an identical committed type system already exists, then the commit operation returns 

+    it, and the one just built is discarded.  Normally, this is not an issue.

+    However, some application code may save references to the type system object or to defined types and features.  

+    These references end up pointing to the discarded version, when the commit operation finds an already 

+    committed equal version.</para>

     

-    <para>Application code may code around this by re-acquiring references to type and feature

-    objects, if the type system returned from <code>commit</code> is not identical (==) to the

-    one being committed.</para>

+    <para>Application code may code around this by re-acquiring references to the type system object, and to any type and feature

+    objects, if the type system instance object returned from <code>commit</code> is not identical (==) to the

+    one being committed.

+    The type system commit APIs are changed to return the type system - either the one being committed, or an

+    already existing equal committed type system.  So when coding

+    <code>myTypesystem.commit();</code> if you later refer to <code>myTypesystem</code>, change this to

+    <code>myTypesystem = myTypesystem.commit();</code>, to keep the variable <code>myTypesystem</code> always

+    referring to to the committed type system.

+    </para>

   </section>

   

-  <section id="uv3.backards_compatibility.checking">

+  <!--  Not implemented

+  <section id="uv3.backwards_compatibility.deserializing_0_length">

+    <title>Deserializing 0 length items in a CAS</title>   

+    

+    <para>In V3, 0-length arrays and lists belonging to one CAS are deserialized into a shared Java object.  Since 

+      0-length arrays and lists are

+      immutable, this should normally not matter.  It could cause problems if the application somehow is

+      depending on object non-identity equality for these items.

+    </para>

+  </section>

+   -->

+   

+  <section id="uv3.backwards_compatibility.checking">

     <title>Some checks moved to native Java</title>   

     

     <para>In the interest of performance, some duplicate checks, such as whether an array index is within bounds, 

@@ -210,7 +375,7 @@
     </para>

   </section>

   

-  <section id="uv3.backards_compatibility.class_hierarchy">

+  <section id="uv3.backwards_compatibility.class_hierarchy">

     <title>Some class hierarchies have been modified</title>   

     

     <para>The various JCas Classes implementing the built-ins for arrays have some additional

@@ -218,4 +383,36 @@
       <code>CommonArray</code>.  These changes are internal, and should not affect users.

     </para>

   </section>

+  

+  <section id="uv3.backwards_compatibility.multiple_type_systems_with_common_jcas">

+    <title>Enabling multiple versions of type systems to work with a single common JCas class</title>

+    <titleabbrev>Multi-TypeSystems single JCas</titleabbrev>   

+    

+    <para>Some applications may use a JCas class definition, defining for type T features f1, f2, f3 (for example), in a mode

+      where under a single class loader (for example, in one Java application), multiple CASs are loaded and processed,

+      where each CAS might have other versions of the type system, defining for type T a subset of the features in the JCas. 

+    </para>

+    

+    <para>In order to make this scenario possible, v3 takes an extra step, right before type system commit time, of 

+      loading the JCas classes corresponding to the types, and then augmenting the type definitions with additional

+      features defined in the JCas but not in the type description.  After this is done, the type system is committed, 

+      and offsets are assigned to the JCas class that are constant, even when a subsequent type system is loaded

+      that defines more features (provided that no new features are introduced).</para>

+      

+    <para>This feature represents a trade-off between highly efficient, locked-down offsets for features, and 

+      some limited flexibility to handle a somewhat common use case where additional features exist in the JCas.

+      The JCas loading code always checks to insure compatibility between the offsets in the JCas classes, as first set up,

+      and any subsequent type system being used with that JCas.

+    </para> 

+    

+    <para>This accommodation doesn't handle many possible scenarios. Some of these include situations where a

+      supertype might subsequently add extra feature slots, or the features end up after merging to have a different

+      ordering.</para> 

+    

+    <para>For cases where this accommodation is insufficient, the workaround is to run separate UIMA applications, each

+      under its own class loader, for the incompatible situations.</para>

+      

+    <para>PEARs, because they are loaded lazily after the type system has been committed, do not support this kind of

+      augmentation of types from the Pear-specific JCas class definition.</para>  

+  </section>

   </chapter>
\ No newline at end of file
diff --git a/uima-docbook-v3-users-guide/src/docbook/uv3.custom_java_objects.xml b/uima-docbook-v3-users-guide/src/docbook/uv3.custom_java_objects.xml
index 67ae64a..e38b913 100644
--- a/uima-docbook-v3-users-guide/src/docbook/uv3.custom_java_objects.xml
+++ b/uima-docbook-v3-users-guide/src/docbook/uv3.custom_java_objects.xml
@@ -90,12 +90,14 @@
     </para>

     

     <para>Step 4 is to run JCasGen on this class to get an initial version of the class.  Of course, it will be missing

-    the Java Hashmap, but we'll add that in the next step.</para>

+    the Java HashMap, but we'll add that in the next step.</para>

     

-    <para>Step 5: modify 3 aspects of the generated JCas class.

+    <variablelist><varlistentry><term>Step 5: modify 3 aspects of the generated JCas class.</term>

+      <listitem>

+        <para>

     <variablelist>

        <varlistentry>

-          <term>Mark the class with one of two interfaces:</term>

+          <term>1. Mark the class with one of two interfaces:</term>

           <listitem>

             <itemizedlist  spacing="compact">

               <listitem><para><code>UimaSerializable</code></para></listitem>

@@ -108,15 +110,19 @@
           </listitem>

        </varlistentry>

        <varlistentry>

-          <term>Add the Java Object as a field to the class</term>

+          <term>2. Add the Java Object as a field to the class</term>

           <listitem>

+            <!-- create a blank line -->

+            <variablelist><varlistentry><term></term><listitem><para></para></listitem></varlistentry></variablelist>

             <para>We'll define a new field:

     <programlisting>final private Map&lt;TOP, TOP&gt; fs2fsMap = new HashMap&lt;&gt;();</programlisting></para>

           </listitem>

        </varlistentry>

        <varlistentry>

-          <term>Implement two methods to marshal/unmarshal the Java Object data to the CAS Data Features</term>

+          <term>3. Implement two methods to marshal/unmarshal the Java Object data to the CAS Data Features</term>

           <listitem>

+            <!-- create a blank line -->

+            <variablelist><varlistentry><term></term><listitem><para></para></listitem></varlistentry></variablelist>

             <para>Now, we need to add the code that translates between the two UIMA Features 

                   "keys" and "values" and the map, and vice-versa.  We put this code into two methods, 

                   called <code>_init_from_cas_data</code> and <code>_save_to_cas_data</code>. 

@@ -158,34 +164,45 @@
             case (but one which might occur frequently), and in that case having the

             _save_to_cas_data operation do nothing, since the original CAS data is still valid.</para>

             

-            <para>One additional "boilerplate" method is required for all of these classes:            

-            <blockquote><para>public FeatureStructureImplC _superClone() {return clone();}</para></blockquote></para>

+            <para>One additional "boilerplate" method is required for all of these classes:</para>            

+            <para><code>  public FeatureStructureImplC _superClone() {return clone();}</code></para>

           </listitem>

        </varlistentry>

     </variablelist>

-    </para>

+

+        </para>

+      </listitem>

+    </varlistentry></variablelist>

+  

     

-    <para>For more examples, please see the implementations of the built-in classes described in the

+    <para>For custom types which hold collections of Feature Structures, you can have those participate in the 

+       <code>Select</code> framework, by implementing the optional Interface <code>SelectViaCopyToArray</code>.</para>

+       

+    <para>For more examples, please see the implementations of the semi-built-in classes described in the

     following section.</para>

   </section>

   

   <section id="uv3.custom_java_objects.new_semibuiltins">

-	  <title>Additional Semi-Built-in UIMA Types for some common Java Objects</title>

-	  <titleabbrev>Semi-Built-in UIMA Types for Java Objects</titleabbrev>

+	  <title>Additional semi-built-in UIMA Types for some common Java Objects</title>

+	  <titleabbrev>semi-built-in UIMA Types</titleabbrev>

 	  

 	  <para>Some additional semi-built-in UIMA types are defined in Version 3 using this new mechanism.  They work fully in

-	  Java, and are transported to non-Java frameworks as ordinary CAS objects.</para>

+	  Java, and are serialized or transported to non-Java frameworks as ordinary CAS objects.</para>

 	  

     <para>Semi-built-in means that the JCas cover classes for these are defined as part of the core Java classes,

       but the types themselves are not "built-in".  They may be added to any tyupe system by importing them by name using the import statement:

       <programlisting>&lt;import name="org.apache.uima.semibuiltins"/&gt;</programlisting>

+      If you have a Java project whose classpath includes uimaj-core, and you run the Component Descriptor Editor

+      Eclipse plugin tool on a descriptor which includes a type system, you can configure this import by selecting

+      the Add on the Import type system subpanel, and import by name, and selecting org.apache.uima.semibuiltins.

+      (Note: this will not show up if your project doesn't include uimaj-core on its build path.)

     </para>

     

 	  <section id="uv3.custom_java_objects.semibuiltin_fsarraylist">

 	    <title>FSArrayList</title>

 	    <titleabbrev>FSArrayList</titleabbrev>

 	    

-	    <para>This is like the current FSArray, except that it implements the List API and supports 

+	    <para><code>org.apache.uima.jcas.cas.FSArrayList</code> is like the current FSArray, except that it implements the List API and supports 

 	    adding to the array, with automatic resizing, like an ArrayList in Java.  It is implemented internally

 	    using a Java ArrayList.</para>

 	    

@@ -202,7 +219,7 @@
       <title>IntegerArrayList</title>

       <titleabbrev>IntegerArrayList</titleabbrev>

       

-      <para>This is like the current IntegerArray, except that it implements the List API and supports 

+      <para><code>org.apache.uima.jcas.cas.IntegerArrayList</code> is like the current IntegerArray, except that it implements the List API and supports 

       adding to the array, with automatic resizing, like an ArrayList in Java.</para>

       

       <para>The CAS data form is held in a plain IntegerArray feature.</para>

@@ -221,11 +238,12 @@
     </section>

     

     <section id="uv3.custom_java_objects.semibuiltin_FSHashSet">

-      <title>FSHashSet</title>

-      <titleabbrev>FSHashSet</titleabbrev>

+      <title>FSHashSet and FSLinkedHashSet</title>

       

-      <para>This type stores Feature Structures in a HashSet, using whatever is defined

-      as the Feature Structure's <code>equals</code> and <code>hashcode</code>.

+      

+      <para><code>org.apache.uima.jcas.cas.FSHashSet</code> and <code>org.apache.uima.jcas.cas.FSLinkedHashSet</code>

+        store Feature Structures in a (Linked) HashSet, using whatever is defined

+        as the Feature Structure's <code>equals</code> and <code>hashcode</code>.

       

       <blockquote>

 	      <para>You may customize the particular equals and hashcode by creating a wrapper class that

@@ -236,9 +254,35 @@
       </para>

             

       <para>The CAS data form is held in an FSArray consisting of the members of the set.</para>

+      

+      <para>If you want a predictable iteratation order, use FSLinkedHashSet instead of FSHashSet.

+      </para>

             

     </section>

     

+    <section id="uv3.custom_java_objects.semibuiltin_Int2FS">

+      <title>Int2FS Int to Feature Structure map</title>

+      

+      <para>Some applications find it convenient to have a map from ints to Feature Structures.

+        In UIMA V2, they made use of the low level CAS APIs that allowed

+        getting an Feature Structure from an int id using <code>ll_getFSForRef(int)</code>.

+      </para>

+      

+      <para>In v3, use of the low level APIs in this manner 

+        can be enabled, but is discouraged, because it prevents garbage collection of non-reachable Feature Structures.

+      </para>  

+

+      <para><code>org.apache.uima.jcas.cas.Int2FS&lt;T&gt;</code> maps from <code>int</code>s to <code>Feature Structure</code>s

+        of type T.

+        This provides an alternative way to have int -> FS maps, 

+        under user control of what exactly gets added to them, 

+        supporting removes and clearing, under application control

+      </para>

+      

+      <para>The <code>iterator()</code> method returns an Iterator over <code>IntEntry&lt;T&gt;</code> objects - these

+        are like java <code>Entry&lt;K, V&gt;</code> objects except the key is an int.</para>

+    </section>

+    

   </section>

   

   <section id="uv3.custom_java_objects.design">

diff --git a/uima-docbook-v3-users-guide/src/docbook/uv3.logging.xml b/uima-docbook-v3-users-guide/src/docbook/uv3.logging.xml
new file mode 100644
index 0000000..5b4c9fc
--- /dev/null
+++ b/uima-docbook-v3-users-guide/src/docbook/uv3.logging.xml
@@ -0,0 +1,308 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"

+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"[

+<!ENTITY imgroot "images/version_3_users_guide/uv3.logging/">

+<!ENTITY tp "uv3.migration.aids.">

+<!ENTITY % uimaents SYSTEM "../../target/docbook-shared/entities.ent" >  

+%uimaents;

+]>

+<!--

+Licensed to the Apache Software Foundation (ASF) under one

+or more contributor license agreements.  See the NOTICE file

+distributed with this work for additional information

+regarding copyright ownership.  The ASF licenses this file

+to you under the Apache License, Version 2.0 (the

+"License"); you may not use this file except in compliance

+with the License.  You may obtain a copy of the License at

+

+   http://www.apache.org/licenses/LICENSE-2.0

+

+Unless required by applicable law or agreed to in writing,

+software distributed under the License is distributed on an

+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+KIND, either express or implied.  See the License for the

+specific language governing permissions and limitations

+under the License.

+-->

+<chapter id="uv3.logging">

+  <title>Logging</title>

+    

+    <para>Logging has evolved; two major changes now supported by V3 are

+      <itemizedlist spacing="compact">

+        <listitem>

+          <para>using a popular open-source standard logging facade, SLF4j, 

+                that can at run time discover and hook to 

+                a user specified logging framework.</para>

+        </listitem>

+        <listitem>

+          <para>Support for both old-style and new style substitutable parameter specification.</para>

+        </listitem>

+      </itemizedlist>

+    </para>

+    

+    <para>For backwards compatibilit, V3 retains the existing V2 logging facade, so

+      existing code will continue to work.

+      The APIs have been augmented by the methods available in the SLF4j <code>Logger</code> API,

+      plus the Java 8 enabled APIs from the Log4j implementation that support the 

+      <code>Supplier</code> Functional Interface.

+    </para>

+    

+    <para>The old APIs support messages using the standard Java Util Logging style of writing substitutable

+      parameters using an integer, e.g., {0}, {1}, etc.  The new APIs support messages using the

+      modern substitutable parameters without an integer, e.g. {}.</para>

+    

+    <para>The implementation of this facade in V2 was the built-in-to-Java (java.util) logging framework.

+    For V3, this is changed to be the SLF4j facade.  This is an open source, standard facade

+    which allows deferring until deployment time, the specific logging back end to use.

+    </para>

+    

+    <para>If, at initialization time, SLF4J gets configured to use a back end which is either the 

+    built-in Java logger, or Log4j-2, then the UIMA logger implementation is switched to

+    UIMA's implementation of those APIs (bypassing SLF4j, for efficiency).</para>

+

+    <!--             

+    <para>The v2 loggers support internationalization using resource bundles.  The logger

+      gets the classpath via a handle to a ResourceManager, and uses that Resource Manager's Extension Classpath

+      when looking up resource bundles.

+    </para>

+    

+    <para>V2 loggers have logging methods <code>logrb</code> which take bundle keys and substitutable parameters.

+      To do the equivalent using SLF4j logging, 

+      a new method on the UIMA logger, <code>rb(String bundleName, String bundleKey, Object ... params)</code>

+      will do the conversion to an internationalized string which can then be passed to 

+      SLF4j.  This should be done using a Java 8 lambda <code>Supplier&lt;String&gt;</code>, 

+      to avoid computing the value if logging is not enabled. 

+    </para>

+     -->

+    

+    <para> 

+      The SLF4j and other documentation (e.g.,  

+      <ulink url="https://logging.apache.org/log4j/2.x/log4j-slf4j-impl/index.html"/> for log4j-2) describe 

+      how to connect various logging back ends to SLF4j, by 

+      putting logging back-end implementations into the classpath at run time.  For example, 

+      to use the back end logger built into Java,  you would

+      include the <code>slf4j-jdk14</code> Jar.  This Jar is included in the UIMA binary distribution, so that

+      out-of-the-box, logging is available and configured the same as it was for V2.

+    </para>

+    

+    <para>The Eclipse UIMA Runtime plugin bundle excludes the slf4j api Jar and back ends, but will 

+      "hook up" the needed implementations from other bundles.   

+    </para> 

+

+  <section id="uv3.logging.levels">

+    <title>Logging Levels</title>

+    

+    <para>There are 2 logging level schemes, and there is a mapping between them.  Either of them may be used

+      when using the UIMA logger.  One of the schemes is the original UIMA v2 level set, which is the same 

+      as the built-in-to-java logger levels.  The other is the scheme adopted by SLF4J and many of its back ends.

+    </para>

+          

+   <para>Log statements are "filtered" according to the logging configuration, by Level, and sometimes by

+    additional indicators, such as Markers.  Levels work in a hierarchy.  A given level of 

+    filtering passes that level and all higher levels.  Some levels have two names, due to the 

+    way the different logger back-ends name things.  Most levels are also used as method names on 

+    the logger, to indicate logging for that level.  

+    For example, you could say <code>aLogger.log(Level.INFO, message)</code>

+    but you can also say <code>aLogger.info(message)</code>). The level ordering, highest to lowest, 

+    and the associated method names are as follows:

+    <itemizedlist spacing="compact">

+      <listitem><para>SEVERE or ERROR; error(...)</para></listitem>

+      <listitem><para>WARN or WARNING; warn(...)</para></listitem>

+      <listitem><para>INFO; info(...)</para></listitem>

+      <listitem><para>CONFIG; info(UIMA_MARKER_CONFIG, ...)</para></listitem>

+      <listitem><para>FINE or DEBUG; debug(...)</para></listitem>

+      <listitem><para>FINER or TRACE; trace(...)</para></listitem>

+      <listitem><para>FINEST; trace(UIMA_MARKER_FINEST, ...)</para></listitem>

+    </itemizedlist>

+    </para>

+    

+    <para>The CONFIG and FINEST levels are merged with other levels, but distinguished by having 

+    <code>Markers</code>.  If the filtering is configured to pass CONFIG level, then it will pass 

+    the higher levels (i.e., the INFO/WARN/ERROR or their alternative names WARNING/SEVERE) levels as well.

+    </para>

+      

+  </section>  

+  <section id="uv3.logging.new_recorded_context_data">

+    <title>Context Data</title>

+    

+    <para>

+      Context data is kept in SLF4j MDC maps; there is a separate map per thread.  

+      This information is set before calling Annotator's process or initialize methods. 

+      The following table lists the keys and the values recorded in the

+      contexts; these can be retrieved by the logging layouts and included in log messages.      

+    </para>

+    

+    <para>Because the keys for context data are global, the ones UIMA uses internally are prefixed with "uima_".</para>   

+    

+    <informaltable frame="all" rowsep="1" colsep="1">

+     <tgroup cols="2">

+       <colspec colnum="1" colname="key" colwidth="3*"/>

+       <colspec colnum="2" colname="description" colwidth="5*"/>

+       

+       <spanspec spanname="fullwidth" namest="key" nameend="description" align="center"/>

+        

+       <tbody>

+         <row>

+           <entry><emphasis role="bold">Key Name</emphasis></entry>

+           <entry><emphasis role="bold">Description</emphasis></entry>

+         </row>

+

+         <!-- ******************************************************************************* -->

+         <row>

+           <entry><para>uima_annotator</para></entry>         

+           <entry><para>the annotator implementation name.</para></entry>

+         </row>

+

+         <row>

+           <entry><para>uima_annotator_context_name</para></entry>         

+           <entry><para>the fully qualified annotator context name within the pipeline.

+                        A top level (not contained within any aggregate) annotator will have

+                        a context of "/".</para></entry>

+         </row>

+         

+         <row>

+           <entry><para>uima_root_context_id</para></entry>

+           <entry><para>A unique id representing the pipeline being run. 

+                This is unique within a class-loader for the UIMA-framework.

+                </para></entry>

+         </row>

+         

+         <row>

+           <entry><para>uima_cas_id</para></entry>

+           <entry><para>A unique id representing the CAS being currently processed in the pipeline.

+           This is unique within a class-loader for the UIMA-framework.

+           </para></entry>

+         </row>

+

+         <!-- <row>

+           <entry><para>op_state</para></entry>

+           <entry><para>An NDC, the operational state.  Could be in_annotator, in_flowController, in_serializer, etc.</para></entry>

+         </row>   -->                

+       </tbody>

+     </tgroup>

+   </informaltable>

+    

+  </section>

+

+  <section id="uv3.logging.markers">

+    <title>Markers used in UIMA Java core logging</title>

+    

+    <note><para><emphasis role="bold">Not (yet) implemented; for planning purposes only.</emphasis></para></note>

+   <!--      

+    <para>

+      Markers are used to group log calls associated with specific kinds of things together,

+      so they can be enabled/disabled as a group.  The Marker can also be included in a trace record.

+      The following table lists the keys and a description of which logging they are associated with.

+    </para>

+

+    <informaltable frame="all" rowsep="1" colsep="1">

+     <tgroup cols="2">

+       <colspec colnum="1" colname="key" colwidth="20*"/>

+       <colspec colnum="2" colname="description" colwidth="30*"/>

+       

+       <spanspec spanname="fullwidth" namest="key" nameend="description" align="center"/>

+        

+       <tbody>

+         <row>

+           <entry><emphasis role="bold">Marker Name</emphasis></entry>

+           <entry><emphasis role="bold">Description of logging</emphasis></entry>

+         </row>

+

+         <row>

+           <entry spanname="fullwidth"><emphasis role="bold">Markers used to classify CONFIG and FINEST </emphasis></entry>

+         </row>

+         <row>

+           <entry><para>org.apache.uima.config</para></entry>

+           <entry><para>configuration log record</para></entry>

+         </row>

+         <row>

+           <entry><para>org.apache.uima.finest</para></entry>

+           <entry><para>sub category of trace, corresponds to FINEST</para></entry>

+         </row>

+         --> 

+         <!-- ******************************************************************************* -->

+         

+         <!-- 

+         <row>

+           <entry spanname="fullwidth"><emphasis role="bold">Markers used to classify some tracing logging</emphasis></entry>

+         </row>

+         <row>

+           <entry><para>uima_annotator</para></entry>

+           <entry><para>for tracing when annotators are entered, exited</para></entry>

+         </row>

+

+         <row>

+           <entry><para>uima_flow_controller</para></entry>

+           <entry><para>for tracing when flow controllers are computing</para></entry>

+         </row>

+

+         <row>

+           <entry><para>uima_feature_structure</para></entry>

+           <entry><para>for tracing Feature Structure Creation and updating</para></entry>

+         </row>

+

+         <row>

+           <entry><para>uima_index</para></entry>

+           <entry><para>for tracing when indexes are added to or removed from</para></entry>

+         </row>

+          

+         <row>

+           <entry><para>uima_index_copy_on_write</para></entry>         

+           <entry><para>for tracing when an index part is copied, due to it being updated while an iterator might be iterating.</para></entry>

+         </row>

+

+         <row>

+           <entry><para>uima_index_auto_rmv_add</para></entry>         

+           <entry><para>for tracing when index corruption avoidance done</para></entry>

+         </row>

+            

+         <row>

+           <entry><para>uima_serialization_deserialization</para></entry>

+           <entry><para>for tracing when serialization or deserialization is done</para></entry>

+         </row>

+                  

+       </tbody>

+     </tgroup>

+   </informaltable>

+    -->

+        

+  </section>

+  

+  <section id="uv3.logging.defaults_configuration">

+    <title>Defaults and Configuration</title>

+    

+    <para>By default, UIMA is configured so that the UIMA logger is hooked up to the SLF4j facade, which

+      may or may not have a logging back-end.  If it doesn't, then any use of the UIMA logger will produce 

+      one warning message stating that SLF4j has no back-end logger configured, and so no logging will be done. 

+    </para>

+        

+    <para>When UIMA is run as an embedded library in other applications, slf4j will use those other application's

+      logging frameworks.</para>

+      

+    <para>Each logging back-end has its own way of being configured; 

+      please consult the proper back-end documentation for details.</para>

+    

+    <para>For backwards compatibility, the binary distribution of UIMA includes the slf4j back-end 

+      which hooks to the standard built-in Java logging framework, so out-of-the-box, UIMA should

+      be configured and log by default as V2 did.</para>  

+      

+    <section id="uv3.logging.throttling_annotator_logging">

+      <title>Throttling logging from Annotators</title>

+      

+       <para>Sometimes, in production, you may find annotators are logging excessively, and you wish to throttle 

+          this. But you may not have access to logging settings to control this,

+          perhaps because UIMA is running as a library component within another framework. 

+          For this special case,

+          you can limit logging done by Annotators by passing an additional parameter to the UIMA Framework's 

+          produceAnalysisEngine API, using the key name 

+          <code>AnalysisEngine.PARAM_THROTTLE_EXCESSIVE_ANNOTATOR_LOGGING</code>

+          and setting the value to an Integer object equal to the the limit.  Using 0 will suppress all logging.

+          Any positive number allows that many log records to be logged, per level.  A limit of 10 would allow 

+          10 Errors, 10 Warnings, etc.  The limit is enforced separately, per logger instance.</para>

+          

+          <note><para>This only works if the logger used by Annotators is obtained from the 

+          Annotator base implementation class via the <code>getLogger()</code> method.</para></note>

+          

+    </section>  

+  </section>  

+</chapter>
\ No newline at end of file
diff --git a/uima-docbook-v3-users-guide/src/docbook/uv3.migration.aids.xml b/uima-docbook-v3-users-guide/src/docbook/uv3.migration.aids.xml
index 16e4d31..2cfee05 100644
--- a/uima-docbook-v3-users-guide/src/docbook/uv3.migration.aids.xml
+++ b/uima-docbook-v3-users-guide/src/docbook/uv3.migration.aids.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>

 <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"

 "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"[

-<!ENTITY imgroot "images/references/uv3.migration.aids/">

+<!ENTITY imgroot "images/version_3_users_guide/uv3.migration.aids/">

 <!ENTITY tp "uv3.migration.aids.">

 <!ENTITY % uimaents SYSTEM "../../target/docbook-shared/entities.ent" >  

 %uimaents;

@@ -41,10 +41,10 @@
     <title>Properties Table</title>

       

     <para>This table describes the various JVM defined properties; specify these on the Java command line

-    using -Dxxxxxx, where the xxxxxx is one of

+    using <code>-Dxxxxxx</code>, where the <code>xxxxxx</code> is one of

     the properties starting with <code>uima.</code> from the table below.</para>  

     <informaltable frame="all" rowsep="1" colsep="1">

-     <tgroup cols="3">

+     <tgroup cols="2">

        <colspec colnum="1" colname="Title" colwidth="1*"/>

        <colspec colnum="2" colname="Description" colwidth="3*"/>

        

@@ -58,9 +58,21 @@
 

          <!-- ******************************************************************************* -->

          <row>

+           <entry><para>Use UIMA V2 format for toString() for Feature Structures</para></entry>

+           

+           <entry><para><code>uima.v2_pretty_print_format</code></para>

+           

+                  <para>The native v3 format for pretty printing feature structures

+                    includes an id number with each FS, and some other minor improvements.

+                    If you have code which depends on the exact format that v2 UIMA produced

+                    for the toString() operation on Feature Structures, then include this

+                    flag to revert to that format.</para></entry>

+         </row>

+         <!-- ******************************************************************************* -->

+         <row>

            <entry><para>Disable Type System consolidation</para></entry>

            

-           <entry><para>uima.disable_typesystem_consolidation</para>

+           <entry><para><code>uima.disable_typesystem_consolidation</code></para>

            

                   <para>Default: equal Type Systems are consolidated.</para>

                   <para>When type systems are committed, the resulting Type System (Java object) 

@@ -72,15 +84,46 @@
 

          <!-- ******************************************************************************* -->

          <row>

-           <entry><para>Enable finding all Feature Structures by their int ID</para></entry>

+           <entry><para>Default CASs to support V2 ID references</para></entry>

            

-           <entry><para>uima.enable_id_to_feature_structure_map_for_all_fss</para>

+           <entry><para><code>uima.default_v2_id_references</code></para>

            

-                  <para>Default: normally created Feature Structures are not kept in a map.</para>

-                  <para>In version 3, normally, Feature Structures are not added to the 

-                        map used by the Low Level CAS API to map from int ids to Feature Structures.

-                        This has the benefit that no longer referenced Feature Structures may be 

-                        garbaged collected.  This behavior may be overridden by this property.</para></entry>

+                  <para>In version 3, Feature Structures are managed somewhat differently from V2.</para>

+                  <itemizedlist>

+                    <listitem><para>Feature Structure creation doesn't remember a map from the id to the FS,

+                      so the LowLevelCas method getFSForRef(int) isn't supported.  (Exception: Feature Structures

+                      created with the low level API calls are findable using this).</para>

+                    </listitem>

+                    <listitem>

+                      <para>Creation of Feature Structures assign "ids" as incrementing integers.  In V2, the 

+                        "id" is the address of the Feature Structure in the v2 Heap; these ids increment by 

+                        the size of the Feature Structure on the heap.</para>

+                    </listitem>

+                    <listitem>

+                      <para>Serialization only serializes "reachable" Feature Structures.</para>

+                    </listitem>

+                  </itemizedlist>

+                  

+                  <para>When this mode is set, the behavior is modified to emulate V2's.</para>

+                  <itemizedlist>

+                    <listitem><para>Feature Structures are added to an id-to-featureStructure map.</para>

+                    </listitem>

+                    <listitem>

+                      <para>IDs are assign incrementing by the size of what the Feature Structure would have been in V2.

+                      </para>

+                    </listitem>

+                    <listitem>

+                      <para>Serialization includes unreachable Feature Structures (except for Xmi and XCAS - because

+                        this is how V2 operates))</para>

+                    </listitem>

+                  </itemizedlist>

+                  <para>This property sets the default value, per CAS, for that CAS's 

+                    <code>ll_enableV2IdRefs</code> mode to true.  This mode is is also programmatically

+                      settable, which overrides this default.</para>

+                  <para>For more details on how this setting operates and interacts with the associated APIs, 

+                    see <xref linkend="uv3.backwards_compatibility.preserve_v2_ids"/>

+                  </para>                     

+           </entry>

          </row>

          

          <!-- ******************************************************************************* -->

@@ -91,7 +134,7 @@
          <row>

            <entry><para>Disabling runtime feature validation</para></entry>

            

-           <entry><para>uima.uima.disable_runtime_feature_validation</para>

+           <entry><para><code>uima.uima.disable_runtime_feature_validation</code></para>

            

                   <para>Once code is running correctly, you may remove this check for performance

                     reasons by setting this property.</para></entry>

@@ -100,7 +143,7 @@
          <row>

            <entry><para>Disabling runtime feature <emphasis>value</emphasis> validation</para></entry>

            

-           <entry><para>uima.disable_runtime_feature_value_validation</para>

+           <entry><para><code>uima.disable_runtime_feature_value_validation</code></para>

            

                   <para>Default: features being set into FS features which are FSs are checked for proper type subsumption.</para>

                   <para>Once code is running correctly, you may remove this check for performance

diff --git a/uima-docbook-v3-users-guide/src/docbook/uv3.migration.xml b/uima-docbook-v3-users-guide/src/docbook/uv3.migration.xml
index e8ca881..970a8db 100644
--- a/uima-docbook-v3-users-guide/src/docbook/uv3.migration.xml
+++ b/uima-docbook-v3-users-guide/src/docbook/uv3.migration.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>

 <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"

 "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"[

-<!ENTITY imgroot "images/version_3_users_guide/migration/">

+<!ENTITY imgroot "images/version_3_users_guide/migrate/">

 <!ENTITY % uimaents SYSTEM "../../target/docbook-shared/entities.ent">  

 %uimaents;

 ]>

@@ -24,38 +24,80 @@
 under the License.

 -->

 <chapter id="uv3.migration">

-  <title>Migrating JCas classes from Version 2 to 3</title>

-  <titleabbrev>Migrating JCas</titleabbrev>

+  <title>Migrating to UIMA Version 3</title>

+  <titleabbrev>Migrating to V3</titleabbrev>

   

   <section id="uv3.migration.big_picture">

+    <title>Migrating: the big picture</title>

+    

+    <para>Although UIMA V3 is designed to be backwards compatible with UIMA V2, there are some migration steps

+      needed.  These fall into two broad use cases: 

+      <itemizedlist>

+        <listitem><para>if you have an existing UIMA pipeline / application you wish to upgrade to use V3</para></listitem>

+        <listitem><para>if you are "consuming" the Maven artifacts for the core SDK, as part of another project</para></listitem>

+      </itemizedlist> 

+    </para>

+    

+  </section>

+  

+  

+  <section id="uv3.migration.migrating_pipeline">

     <title>How to migrate an existing UIMA pipeline to V3</title>

     <titleabbrev>How to migrate</titleabbrev>

     

     <para>

       UIMA V3 is designed to be binary compatible with existing UIMA V2 pipelines, so compiled and/or JAR-ed up classes 

-      representing a V2 pipeline should run with UIMA v3, with two changes:

-      <itemizedlist spacing="compact">

+      representing a V2 pipeline should run with UIMA v3, with three changes:

+      <itemizedlist>

         <listitem><para>Java 8 is required. (If you're already using Java 8, nothing need be done.)</para></listitem>

         <listitem><para>Any defined JCas cover classes must be migrated or regenerated, and used instead.

-        (If you do not define any JCas classes or don't use JCas in your pipeline, then nothing need be done.)</para></listitem>

+        (If you do not define any JCas classes or don't use JCas in your pipeline, then nothing need be done.)

+        A quick way to do this is to create a Jar with the migrated JCas classes, and put it into the classpath

+        ahead of the other JCas class definitions.</para></listitem>

+        <listitem><para>The runtime classpath needs to include the slf4j-api Jar, and an appropriate slf4j bridging Jar,

+          for details, see next.

+          </para></listitem>

       </itemizedlist>

     </para>

     

-    <para>Some Maven projects use the JCasGen maven plugin; these project's JCasGen maven plugin,

-     if switched to UIMA V3, automatically generate the V3 versions.

+    <para>Some adjustments may need to be made to logging setup, typically by including additional Jars 

+      (provided in the UIMA Binary distribution) in your 

+      application's classpath.  If you are using the standard UIMA Launch scripts, this is already done.

+      For custom application setups, insure that the classpath includes the (now) required jar 

+      "slf4j-api-xxxx.jar" (replace xxxx with the version).  

+      If you were using the standard UIMA based logging,

+      to get the similar behavior, include the slf4j-jdk14-xxxx.jar; this 

+      enables the standard Java Utility Logging facility. 

     </para>

     

-    <para>You can use any of the methods of invoking JCasGen to generate the new V3 versions.  If you already have

-    the source or class files, you can also migrate those using the migration tool described in this section.</para>

+    <para>Some Maven projects use the JCasGen maven plugin; these projects' JCasGen maven plugin,

+     if switched to UIMA V3, automatically generate the V3 versions.  For proper operation, please run

+     maven clean install; the clean operation ought to remove the previously generated JCas class, including the

+     UIMA V2 <code>xxx_Type</code> classes.  These are no longer used, and won't compile in V3. 

+    </para>

+    

+    <para>You can use any of the methods of invoking JCasGen to generate the new V3 versions.  

+      If using the Eclipse plugins (i.e., pushing the <code>JCasGen</code>) button in the 

+      configuration editor, etc.), the V3 version of the plugin must be the one installed into Eclipse.

+    </para>

+    

+    <para>    

+      If you have the source or class files, you can also migrate those using the migration tool described in this section.

+      This approach is useful when you've customized the JCas class, and wish to preserve those customizations,

+      while converting the v2 style to the v3 style.

+    </para>

      

+    <!-- 

     <para>For simple testing, after users have migrated or generated any user-supplied JCas classes, 

       users typically will JAR-up these migrated classes,

       and then place that JAR in the class path ahead of the original V2 pipeline's classes so these will replace

       the corresponding classes.

     </para>

+     -->

     

+    <!-- 

     <section id="uv3.migration.maven-cookbook">

-      <title>How to modify a Maven project to support both v2 and v3</title>

+      <title>Modifying a Maven project to support both v2 &amp; v3</title>

       <titleabbrev>Maven v2/v3 simultaneous support</titleabbrev>

       

       <para>When migrating an existing Maven project to v3, you can of course, just change the dependencies, upgrade

@@ -73,26 +115,106 @@
       wanting to use V3, they would need to place ahead of the original artifacts in the running pipeline's classpath.

       </para>

     </section>

+     -->

   </section>

+  

+  

   <section id="uv3.migration.jcas">

     <title>Migrating JCas classes</title>

-    

+   

+  <!-- repetitious 

   <para>Some projects are built using Maven, and use the JCasGen Maven plugin as part of the build.

   These builds, when switched to depend on version 3, will automatically generate the new JCas

   class definitions, so nothing special need be done.

   </para>

-  

+   -->

+   

   <para>If you have customized JCasGen classes, these can be migrated by running the migration tool, which is available

 	  as a stand-alone command line tool (<code>runV3migrateJCas.sh or ...bat</code>), or 

-	  as an Eclipse launch configuration.</para>

+	  as Eclipse launch configurations.</para>

 	  

-  <para>This tool is run against a directory tree, and scans all the files in the tree, looking for 

-     JCas cover classes.  It can process either source files, or, if those are not available, compiled

-     class files.  It can process these inside directories, as well as inside Jar files within those directories.</para>

+  <para>This tool can migrate either sets of

+    <itemizedlist>

+      <listitem><para>Java source files (xxx.java) or </para></listitem>

+      <listitem><para>Compiled Java class files (including those contained in JARs or PEARs)</para></listitem>

+    </itemizedlist>

+    

+    Usually, if you have the source code it is best to migrate the sources.  Otherwise, you can migrate the compiled classes.

+  </para> 

+  

+  <para>When migrating <emphasis role="strong">source</emphasis> files, you specify one or more "roots" - places in a file directory, 

+    and the tool scans those  

+    directories recursively (including inside Jars and PEARs), looking for JCas source files.  When it finds one, it copies it to the output spot 

+    and migrates it. The output is arranged in parallel directories (before and after migration), 

+    for easy side-by-side comparing in a tool such as Eclipse file compare.</para>

+    

+  <para>After checking the migration results, including comparing the files, you replace the original source with

+    the migrated versions.  Also, the original V2 source would contain a source file for each JCas class ending in

+    "_Type"; these are not used in version 3 and should be deleted.</para>

+    

+  <para>You may also migrate <emphasis role="strong">class</emphasis> files; this can be used when the source files are not available.

+    This option has a decompilation step, to produce the source to be migrated and requires

+    a classpath (passed as the <code>migrationClasspath</code> parameter);

+    this classpath is used to resolve symbols during the decompilation, and should be the classpath used when running those classes.

+    For class files, the migration tool 

+    attempts to compile the results and, for Jars and PEARs, to update those migrated classes 

+    in a copy of the original packaging (meaning, within Jars or PEARs): 

+    

+    <itemizedlist spacing="compact">

+      <listitem><para>The <emphasis role="strong">classesRoots</emphasis> are used to locate .class files, perhaps within Jars and PEARs.</para></listitem>

+      <listitem><para>These are decompiled, using special versions of the migrateClasspath.</para></listitem>

+      <listitem><para>The resultant sources are migrated.</para></listitem>

+      <listitem><para>The migrated sources are compiled.</para></listitem>

+      <listitem><para>If the original classes came from Jars or PEARs, copies of these are made with the 

+        migrated classes replaced.</para></listitem>

+    </itemizedlist>

+  </para>

+  

+  <!-- 

+  <para>The migration tool makes a list of all the places in the sourcesRoots or classRoots which contain

+    one or more JCas classes.  It outputs a table of these places with numbered entries called 

+    <emphasis role="strong">root-ids</emphasis>; the root-ids are used

+    when outputting the results, so that output can be tied to where it originated in the 

+    directory roots.  Root-ids are sequentially incrementing integers starting with 1, and are suffixed

+    with a J or a P, if the root-id is for a Jar or a Pear. 

+    </para>

+    

+  <para>Each root-id has an associated value, consisting of a path plus 0 or more other root ids, preceding the path.

+    The root-id's value is the location of the Java class (excluding its package prefix).  For example, the

+    location for a class in a directory tree at /a/b/c/x/y/z/classname.java, where the fully qualified class name was

+    <code>x.y.z.classname</code>, would be /a/b/c.

+    </para>  

+    

+   <para>The value of a root-id may include 0 or more other root-ids; these additional root-ids are for the purpose of

+     identifying a containing Jar or PEAR location;  a PEAR containing a Jar would have two additional root-ids.</para>

+ -->      

+  <para>When scanning directories from source or class roots, if a Jar or a PEAR is encountered, it is recursively scanned.</para>

+    

+  <para>When migrating from compiled classes:

+    <itemizedlist>      

+      <listitem><para>The class is decompiled, and the resulting source is migrated.</para>

+      </listitem>

+      

+      <listitem><para>The next 2 steps are skipped if no Java compiler is available.  A compiler is available if

+        the migrate utility is being run using a JDK (as opposed to a JRE version of Java).</para></listitem>

+      

+      <listitem><para>The migrated classes are compiled. 

+        During this processes, the classpath used is the same as the decompile classpath, except

+        that the uima-core Jar for version 3 (from the classpath used to run the migration tool) is prepended

+        so that the migrated version can be compiled.

+        </para></listitem>

+        

+      <listitem><para>Finally, if the original "packaging" of the class files is a Jar or PEAR, it 

+        is copied and updated with the migrated classes (provided there was no compile error).

+        </para>

+      </listitem>  

+            

+    </itemizedlist>

+  </para>

                 

-	<para>Run this tool using a Java 8 JDK (as opposed to a Java JRE) in order to have the Java compiler available.</para>

-

-  <para>The results of the migration include the migrated class files and a set of logs, summarized in the console

+  <para>The results of the migration include the migrated files, a set of logs, and for classesRoots: the 

+    compiled classes, and repackaging of them into copies of original Jars and/or PEARs.

+    The migration operation is summarized in the console

     output, detailing anything that might need inspection to verify the migration was done correctly.

   </para>

   

@@ -100,23 +222,17 @@
     If all is OK, the migration will say that it "finished with no unusual conditions", at the end.

   </para></blockquote> 	  

 

-  <para>To complete the migration, update your UIMA application to use these classes in place of the version 2 JCas classes.

+  <para>To complete the migration, fix any reported issues that need fixing, and then 

+    update your UIMA application to use these classes/Jars/PEARs 

+    in place of the version 2 ones.

   </para>

-    

-  <para>The migration tool is able to scan multiple directory trees, looking for existing Java

-	  source (.java) or class (.class) files, even inside Jars and PEAR archives. If compiled class files

-	  are used as input, a Java decompiler is used to decompile these to source.

-	  For PEARs and Jars, it replaces the migrated and compiled classes in copies of the PEARs and Jars.

-	</para>

-	

+    	

 	<para>  

-	  The actual migration step is a source-to-source transformation, done using a Java parse of the source files.

-	  The parts in the source which are version 2 specific with the equivalent

-	  version 3 code.

+	  The actual migration step is a source-to-source transformation, done using a parse of the source files.

+	  The parts in the source which are version 2 specific are replaced with the equivalent version 3 code.

 	  Only those parts which need updating are modified;

     other code and comments which are part of the source file are left unchanged.  This is intended to preserve

     any user customization that may have been done.  

-    Detailed reports detailing any issues encountered are written to log files. 

   </para>

     

 <!--    <section id="uv3.migration.automatic">

@@ -136,11 +252,7 @@
     </para>

   </section>

  --> 

- 		 

-		 <note><para>The compilation step (done after the source-to-source transformation) requires that a Java compiler is available 

-		   (which will be the case if you're running with a Java JDK, not a JRE).

-		 </para></note>

-		 

+ 		 		 

 		 <note><para>After running the tool, it is important to examining the console output and logs.

        You can confirm that the migration completed without any unusual conditions, or, if something 

        unusual was encountered, you can take corrective action.

@@ -148,13 +260,15 @@
 		  

 		<section id="uv3.migration.tool_guide.running">

 	    <title>Running the migration tool</title>

+      

 	    <para>The tool can be run as a stand-alone command, using the launcher scripts <code>runV3migrateJCas</code>; 

-	      there are two versions of this &mdash; one for windows (ending it ".bat") and one for linux / mac (ending in ".sh").

+	      there are two versions of this &mdash; one for windows (ending it ".bat") 

+        and one for linux / mac (ending in ".sh").

 		    If you run this without any arguments, it will show a brief help for the arguments.

 		  </para>

 		  

 		  <para>There are also a pair of Eclipse launch configurations 

-        (one for source files, the other for compiled classes), 

+        (one for migrating source files, the other for compiled classes and JARs and PEARs), 

         which are available if you have the uimaj-examples project

         (included in the binary distribution of UIMA) in your Eclipse workspace.

       </para>

@@ -168,31 +282,36 @@
             <listitem><para>UIMA Run V3 migrate JCas from sources roots</para></listitem>

             <listitem><para>UIMA Run V3 migrate JCas from classes roots</para></listitem>

           </itemizedlist>

-          When running from classes roots, the classes must not have compile errors, and may contain Jars and PEARs. 

+          When running from class directory roots, the classes must not have compile errors, and may contain Jars and PEARs.

+          Both launchers write their output to a temporary directory, whose name is printed in the Eclipse console log.

         </para>

       

         <para>

-          To use these launchers,

+          To use the Eclipse launcher to migrate from source code,

             <itemizedlist spacing="compact">

-              <listitem><para>First select the eclipse project; this project's "build path" will supply the 

-                classpath used during migration for decompiling and compiling the sources.</para></listitem>

-              <listitem><para>run the launcher - it will prompt for two values:

-                <itemizedlist spacing="compact">

-                  <listitem><para>the root directory to scan recursively looking for JCas sources or classes/Jars/Pears to be converted</para></listitem>

-                  <listitem><para>an output directory - a writable folder, such as /temp/migrate</para></listitem>

-                </itemizedlist>

+              <listitem><para>First select the eclipse project containing the source code to transform; 

+                this project's "build path" will also supply the 

+                classpath used during migration.</para></listitem>

+              <listitem><para>run the migrate-from-sources launcher.

               </para></listitem>

             </itemizedlist>

+            This will scan the directory tree of the project, looking for source files which are JCas files, and 

+            migrate them.  No existing files are modified; everything is written to the output directory.

   		  </para>

-  	    

-  	    <para>No matter how the tool is started, the input to the tool is one or more directory tree roots; 

-  	      the tool will scan the file system under these roots (including inside Jars and PEARs when running from

-          compiled classes), looking for definitions to migrate.  

-  	    </para>

-		    

-	      <!-- <blockquote><para>It can also be run with a list of specific JCas classes

-	      to migrate.</para></blockquote> -->

         

+        <para>

+          To use the launcher for compiled code,

+            <itemizedlist spacing="compact">

+              <listitem><para>First select the eclipse project that provides the classpath for the compiled code. 

+                This is required for proper "decompiling" of the classes and

+                recompiling the transformed results.

+                </para></listitem>

+              <listitem><para>The launcher will additionally prompt you for another directory 

+                which the migration tool will use as the top of a tree to scan for compiled Java JCas classes to be migrated.

+              </para></listitem> 

+            </itemizedlist>

+        </para>

+  	            

       </section>

 		  

       

@@ -229,18 +348,29 @@
   	          </listitem>

   	        </varlistentry>

   	        

-  		    </variablelist>  

+  		    </variablelist>

+          You can specify either of these, but not both.  

   	    </para>

         </section>

         	    

   	    <section id="uv3.migration.tool_guide.classpath">

   	      <title>Command line: Specifying a classpath for the migration</title>

-  	      <para>A classpath is required for the proper operation of the decompiling and compiling steps of 

-  	        the migration.  This is provided using the argument <code>-migrateClasspath</code>.

+  	      <para>When migrating from compiled classes, a classpath is required to locate and decompile

+            the JCas classes to be migrated.  This classpath should include the JCas classes 

+            to be decompiled. The compiled classes must not have compile errors.

+          </para>

+          

+          <para>When migrating from sourcesRoots, this argument is required only if the JCas classes

+            have references to other non-migrated classes (other than core UIMA classes).  For example,

+            if your JCas class had a reference to a user defined Utility class, that would need to be in the classpath.

+            For plain, non-customized JCas classes, this argument is unnecessary.

+          </para>

+          

+          <para>To specify this parameter, use the argument <code>-migrateClasspath</code>.

   	        The Eclipse launcher "UIMA run V3 migrate JCas from classes roots" sets this argument using

   	        the selected Eclipse project's classpath.

-  	        When migrating within a PEAR, the migration tool automatically adds the PEAR classes to the 

-  	        classpath.

+  	        When migrating within a PEAR, the migration tool automatically adds the 

+            classpath specified by the PEAR (if any) to the classpath.

   	      </para>

   	    </section>

 

@@ -249,12 +379,26 @@
 	    <section id="uv3.migration.tool_guide.duplicates">

 	      <title>Handling duplicate definitions</title>

 	      <para>Sometimes, a classpath or directory tree may contain multiple instances of the same JCas class.

-	        These might be identical, or they might be different versions.  The migration utility detects this, 

-	        and migrates all non-identical instances, using a convention to store them in the output directory in a manner

-	        where different versions can be conveniently compared using tooling such as Eclipse's file compare.

+	        These might be identical, or they might be different versions.  

+        </para>

+        

+        <para>The migration utility handles this by migrating each instance.  

+        <!-- 

+        detects this, except for this case:

+          <itemizedlist spacing="compact">

+            <listitem><para>migrating from classes (meaning the classes are decompiled), and</para></listitem>

+            <listitem><para>the multiple instances defining the classes are not in a Jar or a PEAR, or</para></listitem>

+            <listitem><para>if in a PEAR, the multiple instances are not in a Jar within the PEAR</para></listitem>

+          </itemizedlist>

+          In this case, the decompilation gets the definition from the migrateClasspath, by classname, which means 

+          that even though there may be multiple definitions, only the one (the first one in the classpath) is found.

+        </para>

+         -->

+        

+        The migrated forms are 

+          stored in the output directory prefixed by the root-id (see above), as the parent directory.

+          The different versions can then be conveniently compared using tooling such as Eclipse's file compare.

 	      </para>

-	      <blockquote><para>When there are non-identical duplicate definitions, 

-	        the user must manually compare these and decide which version to use.</para></blockquote>

 	      

 	    </section>

 	  </section>  

@@ -268,57 +412,105 @@
       <para>Each file translated has both a v2 source and a v3 source.  When the input is ".class" files, 

         the v2 source is the result of the decompilation step, prior to any migration.

       </para>

+              

+      <para>The process of scanning directories to find JCas class to migrate may come across multiple instances of

+        the same class.  There are two subcases:

+        <itemizedlist>

+          <listitem><para>The instances are the same.</para></listitem>

+          <listitem><para>The instances are different (two non-identical definitions for the same class).

+          Sometimes these arise when migrating from compiled classes, where the compilation was done by different

+          versions of the Java compiler, and the resulting decompilations are logically equal but have some fields or

+          methods in a different order.</para></listitem>

+        </itemizedlist></para>

       

-      <blockquote><para>

-        These are arranged in parallel directories, allowing Eclipse's multi-file directory "compare" to work on both directory

-        collections and conveniently show for all the migrated files the change details.

-      </para></blockquote>

+      <para>This diagram illustrates some of the potentials for identical and non-identical duplicate definitions

+        for the same classname, that the tool may encounter.  The blue boxes represent ordinary file directories

+        or Jars, and the other boxes with labels Cn1 and Cn2 represent the definitions for a classes named Cn1 

+        and Cn2; the different colors represent non-identical definitions, as an example.  Note that a definition

+        for a class might appear sometimes not within a Jar (or a PEAR, not shown here), as well as with that.

+         <mediaobject>

+            <imageobject>

+              <imagedata width="5.7in" format="PNG" fileref="&imgroot;multiples.png"/>

+            </imageobject>

+            <textobject><phrase>Example of some possible duplicate class definitions</phrase>

+            </textobject>

+          </mediaobject>

         

-      <para>In the case of non-identical duplicates, an increasing integer 

-        starting with 1 is inserted into the output directory tree

-        for each migrated class.</para>

+        The migration tool allows for all of these variants.  It will 

+        migrate all versions, and will (when migrating from compiled Jars and PEARs) compile and reassemble these.</para>

         

+      <para>The output directories prefix the package/classname holding the source code with a prefix of 

+        "a0", "a1", etc.  The "a" stands for alternative, and the 0 is for the first alternative, and the 1, 2, ...

+        are for other non-equal alternatives.</para>

+        

+      <para>When the migration is run from compiled classes, then, if possible,

+      the resulting migrated classes are recompiled and if from Jars or PEARs, reassembled into copies of those artifacts.

+      The compilation for the same classname, with the same sourcecode, could be different for different containers

+      because each compilation is done with that container's classpath (e.g. Jar or Pear) and with respect to the

+      compilation units of that container.  

+      </para>

+      

+      <para>Because of this, the compiled results for a given source instance, are done separately, and kept in output

+      directories, indexed additionally by the container number, as "c0", "c1", ... .

+      A list of all container numbers and the migrated      

+      classes within those containers, is printed out to enable correlating these by hand when necessary.

+      </para>

+             

       <para>The overall directory output directory tree looks like:

         <programlisting>Directory structure, starting at -outputDirectory

    converted/

      v2/

-       x/y/z/javapath/.../Classname.java

-       x/y/z/javapath/.../Classname.java

+       a0/pkg/name.../Classname.java   

+                           /Classname2.java etc.

+       a1/pkg/name.../Classname.java  if there are multiple

+                                              different versions 

        ...

      v3/

-       x/y/z/javapath/.../Classname.java

-       x/y/z/javapath/.../Classname.java

+       a0/pkg/name.../Classname.java

+                     /Classname2.java etc.

+       a1/pkg/name.../Classname.java  if there are multiple

+                                              different versions

        ...

        

-       

-       1/     &lt;&lt; for non identical duplicates

-         x/y/z/javapath/.../Classname.java    

-         x/y/z/javapath/.../Classname.java  

-         ...                                    

-       2/     &lt;&lt; for non identical duplicates

-         x/y/z/javapath/.../Classname.java

-         x/y/z/javapath/.../Classname.java

-         ...

-     v3-classes/

+     v3-classes/   for Jars and PEARs, the compiled class

+       // xyz is the path in the container to the

+       //       start of the pkg/name.../Classname.class

+       // the "a0", "a1", ... is extra but serves to 

+       //      identify which alternative of the source

+       23/a0/xyz/pkg/name.../Classname.class

+       33/a0/xyz/pkg/name.../Classname.class

+       42/a0/xyz/pkg/name.../Classname.class

          ...    

+

+     pears/

+       // xyz_updated_pear_copy is the path

+       //    relative to the container, of the PEAR

+       33/xyz_updated_pear_copy.pear  

+         ...

+     

+     jars/

+       // xyz_updated_jar_copy is the path

+       //    relative to the container, of the Jar

+       42/xyz_updated_jar_copy.jar

+         ...

        

    not-converted/

+   

    logs/

      processed.txt

      failed.txt

      skippedBuiltins.txt

-     NonJCasFiles.txt

+     nonJCasFiles.txt

      workaroundDir.txt

      deletedCheckModified.txt

      manualInspection.txt

-     pearsFileUpdates.txt

-     jarsFileUpdates.txt

-   pears/

-     xyz_converted_pear.pear  

-     ...

-   jars/

-     ...</programlisting>

+     pearFileUpdates.txt

+     jarFileUpdates.txt

      

+     ...</programlisting>

+      </para>

+    

+      <para>

         The converted subtree holds all the sources and migrated versions that were successfully migrated.

         The not-converted subtree hold the sources that failed in some way the migration.

         The logs contain many kinds of entries for different issues encountered:

@@ -372,6 +564,7 @@
               </para>

             </listitem>

           </varlistentry>

+          <!-- 

           <varlistentry>

             <term><emphasis role="strong">workaroundDir.txt</emphasis></term>

 	          <listitem>

@@ -382,6 +575,7 @@
 	            </para>

 	          </listitem>

           </varlistentry>

+           -->

           <varlistentry>

             <term><emphasis role="strong">jarsFileUpdates.txt</emphasis></term>

             <listitem>

@@ -398,7 +592,6 @@
           </varlistentry>

         </variablelist>    

       </para>

-      

            

     </section>

     

@@ -419,24 +612,57 @@
       </para>

       

       <para>Run the Eclipse launcher:</para>

+      <para>First, make sure you've installed the V3 UIMA plugins into Eclipse!</para>

       

-      <programlisting>Load Eclipse workspace containing the project to be migrated,

-  and the version 3 uimaj-migration project.

+      <programlisting>Startup an Eclipse workspace containing the project 

+with JCas source files to be migrated.

       

-Select the Java project having the classpath used when running.

+Select the Java project with the JCas sources to be migrated.

 

 Eclipse -&gt; menu -&gt; Run -&gt; Run configurations

-  Use the search box to find "Migrate JCas" launcher, and launch that.

-

-In the first prompt, 

-  enter the path to the root of the compiled classes or Jar or PEAR

-In the second prompt, 

-  enter a path to where you want the output, e.g. /temp/migrateJCas

+  Use the search box to find 

+  "UIMA run V3 migrate JCas from sources" launcher.

 </programlisting>

     

-    <para>Please read the console output summarization to see about any 

+    <para>Please read the console output summarization to see where the output went, and about any 

       conditions found during migration which need manual inspection and fixup.</para>

     </section>

     

   </section>

+  

+    <section id="uv3.migration.consuming">

+    <title>Consuming V3 Maven artifacts</title>

+    

+    <!-- 

+    <para>There are two issues which may affect other projects which consume V3:

+      <itemizedlist spacing="compact">

+        <listitem><para>default logging is now a no-op slf4j logger, and </para></listitem>

+        <listitem><para>issues using the <code>maven-bundle-plugin.</code></para></listitem>

+      </itemizedlist>

+    </para>

+     -->

+     

+    <para>Projects may have tests which write to the UIMA log.  Because V3 switched to SLF4J as the default logger,

+      unless SLF4J can find an adapter to some back-end logger, it will issue a message and substitute a "NO-OP" 

+      back-end logger.  If your test cases depend on having the V2 default logger (which is the one built into Java), 

+      you need to add a "test" dependency that specifies the SLF4J-to-JDK14 adapter to your POM.  Here's the xml for that:</para>

+    <programlisting><![CDATA[<dependency>

+  <groupId>org.slf4j</groupId>

+  <artifactId>slf4j-jdk14</artifactId>

+  <version>1.7.24</version>  <!-- or some version you need -->

+  <scope>test</scope>

+</dependency>]]></programlisting>

+

+    <!--     

+    <para>If you build OSGi or Eclipse plugins using the <code>maven-bundle-plugin</code>, it will by default

+       look to include the slf4j artifacts.  Instead of this, your run-time OSGi environment could frequenly

+       already include these artifacts, and you can instruct OSGi to "hook up" to them.

+       You can block the attempt to include slf4j directly in your plugin by adding a line to your

+       bundle commands such as &lt;import-package&gt; that exclude this package by adding</para>

+       <programlisting>!org.slf4j</programlisting>

+       <para>to the package list; the "!" says to exclude it.</para>

+    <para>Alternatively, you can include it in the bundle by adding a dependency to the version you which to include.</para>

+     -->

+  </section>

+  

 </chapter>
\ No newline at end of file
diff --git a/uima-docbook-v3-users-guide/src/docbook/uv3.new_extended_apis.xml b/uima-docbook-v3-users-guide/src/docbook/uv3.new_extended_apis.xml
index a90fa2d..608b65c 100644
--- a/uima-docbook-v3-users-guide/src/docbook/uv3.new_extended_apis.xml
+++ b/uima-docbook-v3-users-guide/src/docbook/uv3.new_extended_apis.xml
@@ -26,59 +26,19 @@
 <chapter id="uv3.new_extended_apis">

   <title>New and Extended APIs</title>

   <titleabbrev>New/Extended APIs</titleabbrev>

-  

-  <section id="uv3.new_extended_apis.jcas_static_fields">

-    <title>JCas additional static fields</title>

+      

+  <section id="uv3.new_extended_apis.index_and_iterator_improvements">

+    <title>UIMA FSIndex and FSIterators improvements</title>

     

-    <para>(Also in UIMA Version 2 after release 2.10.0) Static final string fields are declared for each JCas cover class

-      and for each feature that is part of that UIMA type.  The fields look like

-      this example, taken from the Sofa class:

-      <programlisting>public final static String _TypeName = "org.apache.uima.jcas.cas.Sofa";

-public final static String _FeatName_sofaNum    = "sofaNum";

-public final static String _FeatName_sofaID     = "sofaID";

-public final static String _FeatName_mimeType   = "mimeType";

-public final static String _FeatName_sofaArray  = "sofaArray";

-public final static String _FeatName_sofaString = "sofaString";

-public final static String _FeatName_sofaURI    = "sofaURI";</programlisting>

-       Each string has a generated name corresponding to the name of the type or the feature, and

-       a string value constant which of the type or feature name. These can be useful in

-       Java Annotations.

-    </para>

-  </section>

-  

-  <section id="uv3.new_extended_apis.java8">

-    <title>Java 8 integrations</title>

-    

-    <para>Several of the the JCas cover classes provide additional

-      integrations with Java 8 facilities.</para>

-      

-    <section id="uv3.new_extended_apis.java8.lists">

-      <title>Built-in UIMA Arrays and Lists integration with Java 8</title>

-      

-      <para>The <code>iterator()</code> methods for <code>IntegerList

-        IntegerArrayList, IntegerArray, 

-        DoubleArray,</code> and <code>LongArray</code> return

-        an <code>OfInt / OfDouble / OfLong</code> instances.  These are a subtype of 

-        <code>Iterator</code> with an additional methods nextInt / nextLong / nextDouble which avoid the

-        boxing of the normal iterator.

-      </para>

-      

-      <para>The built-in collection types support a <code>stream()</code> method

-      returning a Stream or a type-specialized sub interface of Stream for primitives 

-      (IntStream, LongStream, DoubleStream) 

-      over the objects in the collection.</para>

-      

-      <para>The new <code>select</code> framework supports stream operations; see the "select" chapter for details.

-      </para> 

-           

-    </section>

-  </section>

-  

-  <section id="uv3.new_extended_apis.fsiterator_implements_list">

-    <title>UIMA FSIterators improvements</title>

-    

-    <para>To enable more seamless integration with popular Java idioms, the UIMA iterators for iterating 

-    over UIMA Indexes (the FSIterator interface) now implements the Java ListIterator Interface.

+    <para>The FSIndex interface implements Collection, so you can now write <code>for (MyType item : myIndex)</code> to

+       iterate over an index.</para>

+       

+    <para>Because it implements Collection, the FSIndex interface includes a <code>stream()</code> method, so you can now write <code>myIndex.stream().any-stream-operations</code>,

+      which will use the items in the index as the source of the stream.</para>

+         

+    <para>The FSIterator interface now implements the Java ListIterator Interface, and supports the methods there

+      except for add, nextIndex, previousIndex, and set; the remove() method's meaning is changed to remove the item

+      from all of the UIMA indexes.

     </para>

     

     <para>The iterators over indexes no longer throw concurrent modification exceptions if the index is modified

@@ -97,9 +57,24 @@
     </para>

     

     <para>Note that the phrase <emphasis>Concurrent Modification</emphasis> is being used here in a single threading

-      context, to mean that within a single thread, while an iterator is active, some modifications are being done

       to the indexes.  UIMA does not support multi-threaded write access to the CAS; it does support multi-threaded

-      read access to a set of CAS Views, concurrent with one thread having write access (to different views).</para>

+      read access to a set of CAS Views, concurrent with one thread having write access (to different views).

+    </para>

+    

+    <para>The <code>remove()</code> API for iterators is now implemented for FSIterators.  Its meaning is slightly

+    different from the normal Java meaning - it doesn't remove the item from the collection being iterated over; rather

+    it removes the Feature Structure returned by <code>get()</code> from all indexes in the view.

+    </para>

+    

+    <para>The FSIterator methods that normally check for iterator validity have versions which skip that check.  This

+    may be a performance optimization in cases where you can guarantee the iterator is valid, for example if

+    you have a loop which is checking <code>hasNext()</code> and following it with a <code>next()</code>, 

+    which is only executed if the

+    <code>hasNext()</code> was true.  The non-checking versions are suffixed with Nvc (stands for No Validity Check).</para>

+    

+    <para>The FSIndex API has a new method, <code>subType(type-spec)</code>, which returns an FSIndex for the same

+      index, but specialized to elements which are a subtype of the original index.  The type-spec can be either a 

+      JCas class, e.g. <code>MyToken.class</code>, or a UIMA type instance.</para>

   </section>

 

   <section id="uv3.new_extended_apis.select">

@@ -115,7 +90,7 @@
     <title>New custom Java objects in the CAS framework</title>

     

     <para>There is a new framework that supports allowing you to add your own custom Java objects as

-      objects transportable in the CAS.  The following chapter describes this facility, and some new

+      objects transportable in the CAS.  A following chapter describes this facility, and some new

       semi-built-in types that make use of it.  

     </para>

   </section>  

@@ -123,47 +98,172 @@
   <section id="uv3.new_extended_apis.lists_and_arrays">

     <title>Built-in lists and arrays</title>

     

+    <para>The built-in FSArray JCas class is now parameterized with the type of its

+      elements.</para>

+    

+    <para>UIMA Array and List types implement Iterable, so you can use them

+      like this: <code>for (MyType item : myArray) ...</code>.</para>

+      

+    <para>UIMA Arrays and Lists support <code>contains(element)</code> and <code>isEmpty()</code>.</para>

+

+    <para>UIMA Array and List types support a <code>stream()</code> method

+    returning a Stream or a type-specialized sub interface of Stream for primitives 

+    (IntStream, LongStream, DoubleStream) 

+    over the objects in the collection.  Omitted are stream types where boxing would

+    occur - Arrays of Byte, Short, Float, Boolean.</para>

+

+    <para>The <code>iterator()</code> methods for <code>IntegerList

+      IntegerArrayList, IntegerArray, 

+      DoubleArray,</code> and <code>LongArray</code> return

+      an <code>OfInt / OfDouble / OfLong</code> instances.  These are subtypes of 

+      <code>Iterator</code> with an additional methods nextInt / nextLong / nextDouble which avoid the

+      boxing of the normal iterator.

+    </para>

+       

+    <para>The new <code>select</code> framework supports stream operations; see the "select" chapter for details.

+    </para> 

+    

+    <para>

+      A new set of methods on UIMA built-in lists, <code>createNonEmptyNode() and emptyList()</code>, 

+      creates a non-empty node of the type, or retrieves a (shared) empty node of the type.  

+      These methods are not static, and create or get the instance in the same CAS as the object instance.

+      These methods are callable on both the empty and non-empty node instances, or on their shared

+      super interface, for example, on NonEmptyFloatList, EmptyFloatList, and FloatList (the common super interface).

+    </para>

+    

     <para>

       A new set of static methods on UIMA built-in lists and arrays, <code>create(jcas, array_source)</code>

-      is available; these take a Java array of items, and creates

+      take a Java array of items, and creates

       a corresponding UIMA built-in list or array populated with items from the array_source.

     </para>

     

-    <para>For lists, new static methods <code>getEmptyList(JCas jcas)</code> on each of the 4

-      kinds of built-in lists (FS, Integer, Float, and String) retrieve a 

-      shared, common instance of the EmptyXxxList for a CAS.

+    <para>For UIMA Lists and Arrays, the CAS and JCas has emptyXXXList/Array methods, which return

+      a shared instance of the immutable empty object.

+      The Cas and JCas have generic emptyArray/List, taking an argument JCas class identifying the type, 

+      e.g.  FloatArray.class, StringList.class, etc.

     </para>

-    

-    <para>For lists, a new <code>push(item)</code> API on an existing list node creates a new

-      non-empty node, sets its head to <code>item</code> and its tail to the existing list node.

-      This allows easy construction of a list in backwards order.

-      There is also a <code>pushNode()</code> which just creates and links in a new node to the front of the list.

-      And finally, there's a <code>createNonEmptyNode()</code>, which just creates a node of the 

-      same type, in the same CAS, without linking it.</para>

+        

+    <para>For lists, there are some new common APIs for all list kinds.

+      <itemizedlist>

+        <listitem>

+          <para>

+            <code>push(item)</code> pushes the item onto an existing list node, creates a new

+            non-empty node, setting its head to <code>item</code> and its tail to the existing list node.

+            This allows easy construction of a list in backwards order.

+          </para>

+        </listitem>

+        <listitem>

+          <para>

+            <code>pushNode()</code> creates and links in a new node in front of this node.

+          </para>

+        </listitem>

+        <listitem>

+          <para>

+            <code>insertNode()</code> creates and links in a new node following this node.

+          </para>

+        </listitem>

+        <listitem>

+          <para>

+            <code>createNonEmptyNode()</code> creates a node of the 

+                 same type, in the same CAS, without linking it.

+          </para>

+        </listitem>

+        <listitem>

+          <para>

+            <code>getCommonTail()</code> gets the tail of the node

+          </para>

+        </listitem>

+        <listitem>

+          <para>

+            <code>setTail()</code> sets the tail of the node

+          </para>

+        </listitem>

+        <listitem>

+          <para>

+            <code>walkList()</code> walks the list applying a consumer to each item

+          </para>

+        </listitem>

+        <listitem>

+          <para>

+            <code>getLength()</code> walks the list to compute its length

+          </para>

+        </listitem>

+        <listitem>

+          <para>

+            <code>emptyList</code> returns a shared instance of the empty list of the same type, in the same CAS

+          </para>

+        </listitem>

+      </itemizedlist>

+      

+    </para>

       

     <section id="uv3.new_extended_apis.reorganized.lists_and_arrays">

       <title>Built-in lists and arrays have common super classes / interfaces</title>

         <para>Some methods common to multiple implements were moved to the super classes,

           some classes were made abstract (to prevent them from being instantiated, which would be an error).

           For arrays, a new method common to all arrays, <code>copyValuesFrom()</code> copies values from arrays of the same type.

-        </para>

+        </para>        

     </section> 

-  </section>     

+    

+  </section>    

   

+  <section id="uv3.new_extended_apis.collections">

+    <title>Many UIMA objects implement Stream or Collection</title>

+      <para>In Java 8, classes which implement Collection can be converted to streams using the <code>xxx.sream()</code>

+        method.  To better integrate with Java 8, the following UIMA classes and interfaces now implement Stream or Collection:

+        <itemizedlist>

+          <listitem><para>FSIndex (implements Collection)</para></listitem>

+          <listitem><para>all of the built-in Arrays, e.g. FloatArray implement Stream, the Integer/long/double arrays implement the non-boxing version</para></listitem>

+          <listitem><para>all of the built-in Lists implement Stream, the IntegerList implements the non boxing version</para></listitem>

+        </itemizedlist>

+      </para>

+  </section> 

+ 

+  <!--  

   <section id="uv3.new_extended_apis.annotation">

     <title>Annotation comparator methods</title>

     

     <para>The built-in type Annotation has 4 new methods to allow comparing two annotations.

       The first method (<code>compareAnnotation</code>) uses

-      the standard annotation comparator (two keys: begin (ascending) and end (descending)). 

+      the standard annotation comparator (two keys: begin (ascending) and end (descending)); types can be different. 

       A second method (<code>compareAnnotation(other, linear_type_order)</code>) adds a 3rd comparison,

       used if the Annotations compare equal), which uses a linear_type_order to compare the two types.

       Another two methods extend these two methods with an additional key - the Annotation's ID,

-      used only if the previous comparsions are all equal.

+      used only if the previous comparisons are all equal.

       All of these return the standard Java compare result allowing discrimination between equal, &gt;, and &lt;.

+      

+      <variablelist>

+        <varlistentry>

+          <term>Here's a summary, by compare arguments:</term>

+          <listitem>

+            <variablelist>

+              <varlistentry>

+                <term>begin, end</term>

+                <listitem><para>compares using just the begin and end values, the types can be arbitrary</para></listitem>

+              </varlistentry>

+              <varlistentry>

+                <term>begin, end, type-order</term>

+                <listitem><para>adds ordering of the types based on the global linear type order</para></listitem>

+              </varlistentry>

+              

+              <varlistentry>

+                <term>begin, end, fs.id()</term>

+                <listitem><para>like the first, but adds a compare of the ids if all else equal</para></listitem>

+              </varlistentry>

+              <varlistentry>

+                <term>begin, end, type-order, fs.id()</term>

+                <listitem><para>like the second, but adds a compare of the ids if all else equal</para></listitem>

+              </varlistentry>

+            </variablelist>

+          </listitem>

+        </varlistentry>

+      </variablelist>

+      

+        

       </para>

   </section>

-

+ -->

+ 

   <section id="uv3.new_extended_apis.reorganized">

     <title>Reorganized APIs</title>

     

@@ -179,18 +279,127 @@
     the other (<code>org.apache.uima.cas.impl.AnnotationImpl</code>)otherwise.  In version 3, there's only one implementation;

     the other (AnnotationImpl) is converted to an interface.  Annotation now "implements AnnotationImpl.</para>

   </section>

+ 

+  <section id="uv3.new_extended_apis.class">

+    <title>Use of JCas Class to specify a UIMA type</title>

+    

+    <para>Several APIs require a UIMA type to be specified.  For instance, the API to remove all Feature Structures

+    of a particular type requires the type to be specified.  Instead of a UIMA Type object, if there is a JCas

+    cover class for that type, you can pass that as well, as (for example) <code>Annotation.class</code>.

+    </para>

+  </section>

+    

+  <section id="uv3.new_extended_apis.jcasgen">

+    <title>JCasGen changes</title>

+    

+    <para>JCasgen is modified to generate the v3 style of JCas cover classes. 

+      It no longer generates the the xxx_Type.java classes, as these are 

+      not used by UIMA Version 3.</para>

+      

+    <section id="uv3.new_extended_apis.jcas_static_fields">

+    <title>JCas additional static fields</title>

+    

+    <para>Static final string fields are declared for each JCas cover class

+      and for each feature that is part of that UIMA type.  The fields look like

+      this example, taken from the Sofa class:

+      <programlisting>public final static String _TypeName = "org.apache.uima.jcas.cas.Sofa";

+public final static String _FeatName_sofaNum    = "sofaNum";

+public final static String _FeatName_sofaID     = "sofaID";

+public final static String _FeatName_mimeType   = "mimeType";

+public final static String _FeatName_sofaArray  = "sofaArray";

+public final static String _FeatName_sofaString = "sofaString";

+public final static String _FeatName_sofaURI    = "sofaURI";</programlisting>

+       Each string has a generated name corresponding to the name of the type or the feature, and

+       a string value constant which of the type or feature name. These can be useful in

+       Java Annotations.

+    </para>

+  </section>

+          

+  </section>

+  

+  <section id="uv3.new_extended_apis.generics">

+    <title>Generics added</title>

+    

+    <para>Version 3 adds generic typing to several structures, and makes use of this to enable users to

+      unclutter their code by taking advantage of Java's type inferencing, in many cases.

+    </para>

+    

+    <para>Generic types are added to:

+      <itemizedlist>

+        <listitem>

+          <para><emphasis>FSIndex</emphasis> &lt;T extends FeatureStructure&gt; the type the index is over.</para>

+        </listitem>

+        <listitem>

+          <para><emphasis>FSArray</emphasis> &lt;T extends FeatureStructure&gt; the type the FSArray holds.</para>

+        </listitem>

+        <listitem>

+          <para><emphasis>FSList</emphasis> &lt;T extends TOP&gt; the type the FSList holds.</para>

+        </listitem>

+        <listitem>

+          <para><emphasis>SelectFSs</emphasis> &lt;T extends FeatureStructure&gt; the type the select is producing.</para>

+        </listitem>

+      </itemizedlist>

+    </para>

+  </section>

   

   <section id="uv3.new_extended_apis.other">

     <title>Other changes</title>

     

+    <para>The convenience methods in the JCas have been duplicated in the CAS, e.g. <code>getAllIndexFS</code>.</para>

+    

+    <para>New methods <code>getIndexedFSs(myUimaType)</code> and <code>getIndexedFSs(MyJCas.class)</code> return 

+    unmodifiable, unordered Collections of all indexed Feature Structures of the specified type and its subtypes in 

+    this CAS's view.  This collection can be

+    used in a Java extended-for loop construction. <code>getIndexedFSs()</code> is the same but is for all Feature Structures,

+    regardless of type.  These are methods on the CAS, JCas, FSIndexRepository

+    interfaces, and return the Feature Structures of the specified type (including subtypes).</para>

+    

+    <para>The TypeSystemMgr Interface has a variation of the <code>commit</code> method, which has a parameter 

+      that specifies the class loader to be used when loading JCas class.  This should be used whenever there are

+      user-specified JCas classes associated with the type system.  If not specified, it defaults to the class

+      loader used to load the UIMA framework.

+    </para>

+        

     <para>The utility class <code>org.apache.uima.util.FileUtils</code> has a new method

       <code>writeToFile(path, string)</code>, which efficiently writes a string using UTF-8 encoding to 

       <code>path</code>.

     </para>

     

+    <para>The StringArray class has a new <code>contains(a_string)</code> method.</para>

+    

+    <para>The CAS <code>protectIndexes</code> method returns an instance of AutoClosableNoException which is 

+      a subtype where the close method doesn't throw an exception.  This allows writing the try-with-resources

+      form without a catch block for Exception.</para>

+    

+    <para>

+      Sometimes Annotators may log excessively, causing problems in production settings.

+      Although this could be controlled using logging configuration, sometimes when

+      UIMA is embedded into other applications, you may not have easy access to modify those.

+     </para><para>

+      For this case, the produceAnalysisEngine's "additionalParameters" map supports a new key,  

+      AnalysisEngine.PARAM_THROTTLE_EXCESSIVE_ANNOTATOR_LOGGING.  

+      This key specifies that throttling should be applied to messages

+      produced by annotators using loggers obtained by Annotator code using the getLogger() API.

+    </para><para>

+      The value specified must be an Integer, and is the number of messages allowed before

+      logging is suppressed.  This number is applied to each logging level, separately.

+      To suppress all logging, use 0.  

+    </para>

+    

+    <para>The Type interface has new methods <code>subsumes(another_type), isStringOrStringSubtype()</code>, 

+        and <code>isStringSubtype().</code></para>

+

+    <para>The FlowController_ImplBase supports a getLogger() API, which is shorthand for getContext().getLogger().</para>

+    

     <para>Many error messages were changed or added, causing changes to localization classes.

       For coding efficiency, some of the structure of the internal error reporting calls was changed

       to make use of Java's variable number of arguments syntax.</para>

+      

+    <para>The UIMA Logger implementation has been extended with both the SLF4J logger APIs and the 

+       Log4j APIs which support Java 8's <code>Supplier</code> Functional Interfaces.</para>

+ 

+    <para>The TypeSystem and Type object implementations implement <code>Iterable</code> and will iterate over

+      all the defined types, or, for a type, all the defined Features for that type.</para>        

   </section> 

    

 </chapter>
\ No newline at end of file
diff --git a/uima-docbook-v3-users-guide/src/docbook/uv3.overview.xml b/uima-docbook-v3-users-guide/src/docbook/uv3.overview.xml
index 3c98b84..0068594 100644
--- a/uima-docbook-v3-users-guide/src/docbook/uv3.overview.xml
+++ b/uima-docbook-v3-users-guide/src/docbook/uv3.overview.xml
@@ -112,11 +112,10 @@
 	    </varlistentry>

 	    

 	    <varlistentry>

-	      <term><emphasis role="strong">New UIMA built-in types, built using the custom Java object support</emphasis></term>

+	      <term><emphasis role="strong">New UIMA semi-built-in types, built using the custom Java object support</emphasis></term>

 	      <listitem>

 	        <para>The new support that allows custom serialization of arbitrary Java objects so they can be transported

-            in the CAS (above) is used to implement several new built-in UIMA types.  These are implemented in a 

-            "lazy" style, avoiding extra computation until needed. 

+            in the CAS (above) is used to implement several new semi-built-in UIMA types.  

 	        <variablelist>

 	          <varlistentry>

 	            <term><emphasis role="strong">FSArrayList</emphasis></term>

@@ -131,9 +130,9 @@
 	            </listitem>

 	          </varlistentry>

     	      <varlistentry>

-	            <term><emphasis role="strong">FSHashSet</emphasis></term>

+	            <term><emphasis role="strong">FSHashSet, FSLinkedHashSet</emphasis></term>

 	            <listitem>

-	              <para>a Java HashSet containing Feature Structures. This JCas class implements the Set API.</para>

+	              <para>a Java HashSet or LinkedHashSet containing Feature Structures. This JCas class implements the Set API.</para>

 	            </listitem>

 	          </varlistentry>

  

@@ -152,6 +151,11 @@
             both forwards and backwards while iterating, moving to specific positions, and doing various kinds

             of specialized Annotation selection such as working with Annotations spanned by another annotation.

           </para>

+          <para>By default, when sorted iterators are set up by the select framework, they ignore typePriorities;

+            this addresses a need of many use cases, and makes operation when there are many annotations spanning

+            the same begin and end more reliable.  Each select can specify to use typePriority as

+            part of the ordering when required.</para>

+            

           <para>This user's guide has a chapter devoted to this new framework.

           </para>

         </listitem>

@@ -166,12 +170,42 @@
           <para>Note that the automatic index corruption avoidance introduced in more recent versions of UIMA could

           be automatically removing Feature Structures from indexes and adding them back, if the user was updating

           some Feature of a Feature Structure that was part of an index specification for inclusion or ordering purposes.</para>

+          

           <blockquote><para>In version 2, you would accomplish this using a two pass scheme:

           Pass 1 would iterate and merely collect the Feature Structures to be updated into a Java collection of some kind.

           Pass 2 would use a plain Java iterator over that collection and modify the Feature Structures and/or the UIMA indexes.

           This is no longer needed in version 3; UIMA iterators use a copy-on-write technique to allow index updating,

           while doing whatever minimal copying is needed to continue iteration over the original index.</para>

           </blockquote>

+          

+          <para>In both version 2 and 3, there are 3 iterator movement APIs which have a side effect of insuring the

+            iterator is operating correctly over the current index contents.  These are the <code>moveToFirst, 

+            moveToLast, and moveTo(some_feature_structure)</code> API calls.  In version 3, using these will

+            reinitialize the iterator (if needed) so that it is iterating over the current index contents;

+            if the index has not been modified, no reinitialization is needed (or done).</para>

+            

+          <para>CAS reset and index removeAll operations clear the index without preserving any existing

+            iteration.  If you try to continue an iteration over an index cleared by these operations, the results

+            are undefined, and may throw exceptions.</para>  

+        </listitem>

+      </varlistentry>

+      

+      <varlistentry>

+        <term><emphasis role="strong">Logging updated</emphasis></term>

+        <listitem>

+          <para>The UIMA logger is a facade that can be hooked up at deploy time to one of several logging backends.

+          It has been extended to implement all of the Logger API calls provided in the SLF4j <code>Logger</code>

+          interface, and has been changed to use SLF4j as its back-end.  SLF4j, in turn, 

+          requires a logging back-end which it 

+          determines by examining what's available in the classpath, at deploy time.  This design

+          allows UIMA to be more easily embedded in other systems which have their own logging frameworks.</para>

+          

+          <para>Modern loggers support MDC/NDC and Markers; these are supported now via the slf4j facade.  

+          UIMA itself is extended to use these to provide contexts around logging.

+          </para> 

+

+          <para>See the following chapter on logging for details.</para>

+                  

         </listitem>

       </varlistentry>

 

@@ -238,6 +272,16 @@
         </listitem>

       </varlistentry>

 

+      <varlistentry>

+        <term><emphasis role="strong">Programming convenience</emphasis></term>

+        <listitem>

+          <para>Many APIs have been made more consistent and better integrated; see the chapter on new and extended APIs.

+            Examples:  UIMA Indexes now implement Iterable, so you can use the Java "extended for" construct directly;

+            UIMA Lists have new push and pushNode methods to create and link a new node onto the front of a list;

+            there are new methods on the CAS and JCas to get a shared instance of common immutable objects, like

+            0-length arrays and empty lists.</para>

+        </listitem>

+      </varlistentry>

 	  </variablelist>

   </para>

   

@@ -287,6 +331,6 @@
 

 <section id="uv3.overview.java8">

   <title>Java 8 is required</title>

-  <para>The UIMA Java SDK Version 3 requires Java 8 or later.</para>

+  <para>The UIMA Java SDK Version 3 requires Java 8.</para>

 </section>      

 </chapter>
\ No newline at end of file
diff --git a/uima-docbook-v3-users-guide/src/docbook/uv3.pears.xml b/uima-docbook-v3-users-guide/src/docbook/uv3.pears.xml
index bf5e4db..d532c23 100644
--- a/uima-docbook-v3-users-guide/src/docbook/uv3.pears.xml
+++ b/uima-docbook-v3-users-guide/src/docbook/uv3.pears.xml
@@ -88,7 +88,7 @@
       Version 3 has special support for the case where there are different definitions of JCas classes 

       for the same UIMA type, inside and outside the PEAR.  It does this using what are called

       PEAR Trampolines.  When there are multiple JCas definitions, the one defined outside of the PEAR is

-      the one stored internally in UIMA's indexes and built-in types that have references to Feature Structures.

+      the one stored internally in UIMA's indexes and types that have references to Feature Structures.

       Accessing the Feature Structures checks (by asking the CAS) to see if its in a particular PEAR context

       (there may be several in one pipeline), and if so, a trampoline instance of the Feature Structure is

       created / used / accessed.  The trampoline instance shares internally the CAS data with the

@@ -105,18 +105,12 @@
       these inside a PEAR, and yet have the references work outside a PEAR, the implementor of these must

       insure that the actual stored JCas class for a Feature Structure is the base version, not the PEAR version,

       and also insure that any references are properly converted (while within a PEAR context).  

-    </para>  

+    </para> 

     

-    <para>The new built-in types that reference Feature Structures <emphasis>do not</emphasis> include 

-      the extra facility to support this conversion; they store whatever they're given.  This means that

-      they may be used inside or outside a PEAR, but cannot be used to hold onto Feature Structures set in

-      one context, but referenced in the other.

-    </para>

+    <para>Refer to the implementation of <code>FSHashSet</code> and <code>FSArrayList</code> to see what

+      needs to be done to make these "Pear aware".

+    </para> 

     

-    <para>If there is interest or need, additional documentation can be written describing how the 

-      core framework handles this, and providing a cookbook for others to implement this capability

-      for custom Java objects.

-    </para>

   </section>

     

   </chapter>

diff --git a/uima-docbook-v3-users-guide/src/docbook/uv3.select.xml b/uima-docbook-v3-users-guide/src/docbook/uv3.select.xml
index 1e239ce..e3f6cf9 100644
--- a/uima-docbook-v3-users-guide/src/docbook/uv3.select.xml
+++ b/uima-docbook-v3-users-guide/src/docbook/uv3.select.xml
@@ -101,7 +101,8 @@
     <para>  

     Feature Structures may, additionally, be kept in <code>FSArrays</code>, <code>FSLists</code>,

     and many additional collection-style objects that implement <code>SelectViaCopyToArray</code> interface.

-    This interface is implemented by the new built-in types <code>FSArrayList</code> and <code>FSHashSet</code>;

+    This interface is implemented by the new semi-built-in types <code>FSArrayList</code>, 

+    <code>FSHashSet</code> and <code>FSLinkedHashSet</code>;

     user-defined JCas classes for user types may also choose to implement this.

     All of these sources may be used with <code>select</code>.</para>

     

@@ -167,7 +168,7 @@
 	      </para>

 	    </listitem>

 	    <listitem>

-	      <para>Feature Structures from a built-in UIMA Collection instance, such as instances of the types

+	      <para>Feature Structures from a (semi) built-in UIMA Collection instance, such as instances of the types

 	      <code>FSArray, FSArrayList, FSHashSet,</code> etc.

 	      </para>

 	    </listitem>

@@ -428,7 +429,8 @@
       

       <para>When selecting Annotations, frequently you may want to select only those which have

       a relation to a bounding Annotation.  A commonly done selection is to select all Annotations 

-      (of a particular type) within the span of another, bounding Annotation, such as all <code>Tokens</code>

+      (of a particular type including its subtypes) within the span of another bounding Annotation, 

+      for example, all <code>Tokens</code>

       within a <code>Sentence</code>.</para>

       

       <para>There are four varieties of sub-selection within an annotation index.  They all are based on a 

@@ -459,7 +461,7 @@
         <varlistentry>

           <term><emphasis role="strong">covering</emphasis></term>

           <listitem>

-            <para>iterates over Annotations that span (or are equal to) the bound.

+            <para>iterates over Annotations that span the bound.

             </para>

           </listitem>

         </varlistentry>

@@ -501,9 +503,16 @@
             </para>

           </listitem>

         </varlistentry>

+        

+        

+        <!-- 

         <varlistentry>

           <term><emphasis role="strong">positionUsesType</emphasis></term>

           <listitem>

+            <para>This only has a meaning when typePriority is false.</para>

+            

+                           This next is a fanciful idea that has no reasonable implementation, so delete it.

+                

             <para>When type priorities are not being used, Annotations with the same begin and end and type

             will be together in the index.  The starting position, when there are many Annotations 

             which might compare equal, is the left-most (earliest) one of these.  In this comparison for 

@@ -511,8 +520,18 @@
             only its begin and end values are used. 

             If you want to include the type of the bounding Annotation in the equal comparison, set this to true.

             </para>

+            

+             

+            <para>This setting only applies for bounded iterators with skipSameBeginEndType == true and typePriority false.

+            Bounded iterators skip over annotations which are "equal" to the bounding annotation.  The meaning of

+            "equal" is altered when this is set true: items whose type is not == to the bounds type will not be skipped.

+            </para>

+            

           </listitem>

         </varlistentry>

+        -->

+        

+        

         <varlistentry>

           <term><emphasis role="strong">nonOverlapping</emphasis></term>

           <listitem>

@@ -537,17 +556,14 @@
           </listitem>

         </varlistentry>

         <varlistentry>

-          <term><emphasis role="strong">useAnnotationEquals</emphasis></term>

+          <term><emphasis role="strong">skipSameBeginEndType</emphasis></term>

           <listitem>

             <para>While doing bounded iteration, if the Annotation being returned is identical (has the same

-            _id()) with the bounding Annotation, it is always skipped.</para>

+            _id()) with the bounding Annotation, it is always skipped. But other annotations, which might 

+            have the same begin, end, and type values, are included by default.</para>

             

             <para>  

-            When this variant is specified, in addition to

-            that, any Annotation which has the same begin, end, and (maybe) type is also skipped.  

-            The <code>positionUsesType</code> setting is used to specify in this variant whether or not the 

-            type is included when doing the equals test.  Note that <code>typePriority</code> implies

-            <code>positionUsesType</code>.

+            When this configuration is specified, any Annotation which has the same begin, end, and type is also skipped.  

             </para>

           </listitem>

         </varlistentry>

@@ -568,19 +584,25 @@
           <varlistentry>

             <term><emphasis role="strong">typePriority</emphasis></term>

             <listitem>

-              <para>default: type priorites are not used when determining bounds in bounded selects.

-              Subiterators, in contrast, use type priorities.

+              <para>default: false; type priorities are not used when moving to left-most among equal items.

+              Subiterators created using the AnnotationIndex, in contrast, use type priorities.

               </para>

             </listitem>

           </varlistentry>

+          

+          <!-- 

           <varlistentry>

             <term><emphasis role="strong">positionUsesType</emphasis></term>

             <listitem>

-              <para>default: the type of the bounding Annotation is ignored 

-               when determining bounds in bounded selects; only its begin and end position are used

+              <para>default: false; the type of the bounding Annotation is ignored 

+               when skipSameBeginEndType == true, for skipping equal-to-bound; 

+               only its begin and end position are used

               </para>

             </listitem>

           </varlistentry>

+           -->

+           

+           

           <varlistentry>

             <term><emphasis role="strong">nonOverlapping</emphasis></term>

             <listitem>

@@ -599,11 +621,12 @@
             </listitem>

           </varlistentry>

           <varlistentry>

-            <term><emphasis role="strong">useAnnotationEquals</emphasis></term>

+            <term><emphasis role="strong">skipSameBeginEndType</emphasis></term>

             <listitem>

-              <para>default: only the single Annotation with the same _id() is skipped when doing sub selecting.

+              <para>default: only the single Annotation with the same _id() is skipped when using 

+                a bounded iteration.

                 Use this setting to expand the set of skipped Annotations to include all those equal to the 

-                bound's begin and end (and maybe, type, if positionUsesType or typePriority specified).   

+                bound's begin, end and type.   

               </para>

             </listitem>

           </varlistentry>

@@ -614,8 +637,8 @@
     <section id="uv3.select.annot.follow_precede">

       <title>Following or Preceding</title>

       

-      <para>For an sorted Index, you can specify all Feature Structures following or preceding a position.

-      The position can be specified either as a Feature Structure, or (for AnnotationIndexes only) 

+      <para>For an Annotation Index, you can specify all Feature Structures following or preceding a position.

+      The position can be specified either as a Feature Structure, or 

       by using begin and end values.

       The arguments are identical to those of the <code>startAt</code> specification, but are interpreted 

       differently.    

@@ -642,6 +665,7 @@
         </varlistentry>

       </variablelist>

       

+      <para>The <code>preceding</code> iteration skips annotations whose <code>end</code> values are &gt; the saved <code>begin</code>.</para>

     </section>  

   </section>

   

diff --git a/uima-docbook-v3-users-guide/src/docbook/version_3_users_guide.xml b/uima-docbook-v3-users-guide/src/docbook/version_3_users_guide.xml
index 47e5c40..349ec43 100644
--- a/uima-docbook-v3-users-guide/src/docbook/version_3_users_guide.xml
+++ b/uima-docbook-v3-users-guide/src/docbook/version_3_users_guide.xml
@@ -30,6 +30,7 @@
   <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="uv3.new_extended_apis.xml"/>

   <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="uv3.select.xml"/>

   <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="uv3.custom_java_objects.xml"/> 

+  <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="uv3.logging.xml"/> 

   <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="uv3.migration.xml"/>

   <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="uv3.pears.xml"/>

   <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="uv3.migration.aids.xml"/>

diff --git a/uima-docbook-v3-users-guide/src/image-source/source.pptx b/uima-docbook-v3-users-guide/src/image-source/source.pptx
index 007328d..0504a06 100644
--- a/uima-docbook-v3-users-guide/src/image-source/source.pptx
+++ b/uima-docbook-v3-users-guide/src/image-source/source.pptx
Binary files differ
diff --git a/uimaj-adapter-soap/pom.xml b/uimaj-adapter-soap/pom.xml
index 85c5f39..8dd5eec 100644
--- a/uimaj-adapter-soap/pom.xml
+++ b/uimaj-adapter-soap/pom.xml
@@ -44,13 +44,13 @@
        element, and just changing the following two properties -->  
   <scm>
     <connection>
-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-adapter-soap
+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-adapter-soap
     </connection>
     <developerConnection>
-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-adapter-soap
+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-adapter-soap
     </developerConnection>
     <url>
-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-adapter-soap
+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-adapter-soap
     </url>
   </scm>
   
diff --git a/uimaj-adapter-vinci/pom.xml b/uimaj-adapter-vinci/pom.xml
index 2793766..26f6c9f 100644
--- a/uimaj-adapter-vinci/pom.xml
+++ b/uimaj-adapter-vinci/pom.xml
@@ -44,13 +44,13 @@
        element, and just changing the following two properties -->  
   <scm>
     <connection>
-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-adapter-vinci
+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-adapter-vinci
     </connection>
     <developerConnection>
-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-adapter-vinci
+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-adapter-vinci
     </developerConnection>
     <url>
-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-adapter-vinci
+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-adapter-vinci
     </url>
   </scm>
   
@@ -77,7 +77,12 @@
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <scope>test</scope>
-    </dependency>      
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-jdk14</artifactId>
+      <scope>test</scope>
+    </dependency>
 	</dependencies>
 	<build>
 		<finalName>uima-adapter-vinci</finalName>
diff --git a/uimaj-adapter-vinci/src/main/java/org/apache/uima/adapter/vinci/util/Descriptor.java b/uimaj-adapter-vinci/src/main/java/org/apache/uima/adapter/vinci/util/Descriptor.java
index c2bb9d2..b446b77 100644
--- a/uimaj-adapter-vinci/src/main/java/org/apache/uima/adapter/vinci/util/Descriptor.java
+++ b/uimaj-adapter-vinci/src/main/java/org/apache/uima/adapter/vinci/util/Descriptor.java
@@ -19,17 +19,16 @@
 
 package org.apache.uima.adapter.vinci.util;
 
-import java.io.File;
-
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
 
+import org.apache.uima.UIMAFramework;
+import org.apache.uima.internal.util.XMLUtils;
+import org.apache.uima.util.Level;
 import org.w3c.dom.Document;
 import org.xml.sax.Attributes;
 import org.xml.sax.helpers.DefaultHandler;
 
-import org.apache.uima.UIMAFramework;
-import org.apache.uima.util.Level;
 
 // TODO: Auto-generated Javadoc
 /**
@@ -87,8 +86,7 @@
   private Document parse(String configFile) {
     Document doc = null;
     try {
-
-      SAXParserFactory factory = SAXParserFactory.newInstance();
+      SAXParserFactory factory = XMLUtils.createSAXParserFactory();
       factory.setValidating(false);
 
       // Create the builder and parse the file
diff --git a/uimaj-bootstrap/pom.xml b/uimaj-bootstrap/pom.xml
index 7e4aa29..c71f643 100644
--- a/uimaj-bootstrap/pom.xml
+++ b/uimaj-bootstrap/pom.xml
@@ -36,13 +36,13 @@
   

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-bootstrap

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-bootstrap

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-bootstrap

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-bootstrap

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-bootstrap

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-bootstrap

     </url>

   </scm>

   

diff --git a/uimaj-bootstrap/src/main/java/org/apache/uima/bootstrap/UimaBootstrap.java b/uimaj-bootstrap/src/main/java/org/apache/uima/bootstrap/UimaBootstrap.java
index 4e76fdb..85f1e7e 100644
--- a/uimaj-bootstrap/src/main/java/org/apache/uima/bootstrap/UimaBootstrap.java
+++ b/uimaj-bootstrap/src/main/java/org/apache/uima/bootstrap/UimaBootstrap.java
@@ -112,6 +112,11 @@
   };

   

   private static void addUrlsFromPath(String p, List<URL> urls) throws MalformedURLException, IOException, URISyntaxException {

+    // handle case where the path part is written x/y/z/*  by dropping the /* at the end

+    // This is the form used by Java itself for classpath

+    if (p.endsWith("*") && p.length() > 2 && p.charAt(p.length() - 2) == File.separatorChar) {

+      p = p.substring(0, p.length() - 2);

+    }

     File pf = new File(p);

     if (pf.isDirectory()) {

       File[] jars = pf.listFiles(jarFilter);

diff --git a/uimaj-component-test-util/pom.xml b/uimaj-component-test-util/pom.xml
index c5b4b8a..d02086b 100644
--- a/uimaj-component-test-util/pom.xml
+++ b/uimaj-component-test-util/pom.xml
@@ -43,13 +43,13 @@
        element, and just changing the following two properties -->  
   <scm>
     <connection>
-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-component-test-util
+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-component-test-util
     </connection>
     <developerConnection>
-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-component-test-util
+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-component-test-util
     </developerConnection>
     <url>
-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-component-test-util
+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-component-test-util
     </url>
   </scm>
   
diff --git a/uimaj-component-test-util/src/main/java/org/apache/uima/test/junit_extension/AnnotatorTester.java b/uimaj-component-test-util/src/main/java/org/apache/uima/test/junit_extension/AnnotatorTester.java
index 4fbb1d4..e5548ff 100644
--- a/uimaj-component-test-util/src/main/java/org/apache/uima/test/junit_extension/AnnotatorTester.java
+++ b/uimaj-component-test-util/src/main/java/org/apache/uima/test/junit_extension/AnnotatorTester.java
@@ -31,6 +31,7 @@
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.impl.XCASDeserializer;
 import org.apache.uima.collection.CasConsumer;
+import org.apache.uima.internal.util.XMLUtils;
 import org.apache.uima.resource.ResourceConfigurationException;
 import org.apache.uima.resource.ResourceInitializationException;
 import org.apache.uima.resource.ResourceManager;
@@ -360,7 +361,7 @@
          CAS cas = CasCreationUtils.createCas(tsDesc, null,
                new FsIndexDescription[0]);
 
-         SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
+         SAXParser parser = XMLUtils.createSAXParserFactory().newSAXParser();
          XCASDeserializer xcasDeserializer = new XCASDeserializer(cas
                .getTypeSystem());
          parser.parse(xcasFile, xcasDeserializer.getXCASHandler(cas));
diff --git a/uimaj-core/pom.xml b/uimaj-core/pom.xml
index 9977362..1c655eb 100644
--- a/uimaj-core/pom.xml
+++ b/uimaj-core/pom.xml
@@ -43,13 +43,13 @@
        element, and just changing the following two properties -->  
   <scm>
     <connection>
-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-core
+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-core
     </connection>
     <developerConnection>
-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-core
+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-core
     </developerConnection>
     <url>
-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-core
+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-core
     </url>
   </scm>
   
@@ -57,25 +57,81 @@
     <uimaScmProject>${project.artifactId}</uimaScmProject>
     <postNoticeText>${ibmNoticeText}</postNoticeText>
     <maven.surefire.heap>650M</maven.surefire.heap>
-    
-    <!-- 
-     BACKWARD_COMPATIBLE_IMPLEMENTER - patch version (=.=.+)
-     BACKWARD_COMPATIBLE_USER        - minor version (=.+.0)
-     NON_BACKWARD_COMPATIBLE         - major version (+.0.0)
-     -->
-    <compat.level>NON_BACKWARD_COMPATIBLE</compat.level>
-    <compat.previous.version>2.9.0</compat.previous.version>
-    
   </properties>
   
 	<dependencies>
-	  <dependency>
-      <groupId>log4j</groupId>
-      <artifactId>log4j</artifactId>
-      <version>1.2.8</version>
+    
+    <!-- Loggers -->
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>  <!-- core, not api, because need to set log level via api -->
+      <version>${log4j.version}</version>
+      <!--  "provided" fails in maven test - says cannot initialize class that makes ref to classes in this jar 
+            "test" fails in maven compile - cannot compile -->
       <scope>provided</scope>
-      <optional>true</optional>
     </dependency>
+
+    <!-- dependency>  moved to surefire configuration
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId-->  <!-- core, not api, because need to set log level via api -->
+      <!-- version>${log4j.version}</version-->
+      <!--  "provided" fails in maven test - says cannot initialize class that makes ref to classes in this jar 
+            "test" fails in maven compile - cannot compile -->
+      <!-- scope>test</scope>
+    </dependency-->
+
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+      <version>${log4j.version}</version>
+      <!--  "provided" fails in maven test - says cannot initialize class that makes ref to classes in this jar 
+            "test" fails in maven compile - cannot compile -->
+      <scope>provided</scope>  
+    </dependency>
+
+     <!-- dependency>  moved to surefire configuration
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+      <version>${log4j.version}</version>
+      <scope>test</scope>  
+    </dependency-->
+    
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    
+    <!-- needed to convert slf4j markers into log4j markers 
+         and for running the test --> 
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-slf4j-impl</artifactId>
+      <version>${log4j.version}</version>
+      <!-- scope provided: put in compile classpath, excluded from test classpath, not passed along -->
+      <scope>provided</scope> 
+    </dependency>
+
+     <!-- dependency>  moved to surefire configuration  
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-slf4j-impl</artifactId>
+      <version>${log4j.version}</version>
+      <scope>test</scope> 
+    </dependency-->
+
+    <!--  causes build error: package org.apache.logging.slf4j does not exist
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-slf4j-impl</artifactId>
+      <version>${log4j.version}</version>
+      <scope>test</scope>
+    </dependency>
+                     -->
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-jdk14</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
 		<dependency>
 			<groupId>org.apache.uima</groupId>
 			<artifactId>uimaj-test-util</artifactId>
@@ -124,7 +180,7 @@
     <dependency>  <!-- Apache v2 license  2016 checked -->
       <groupId>org.bitbucket.mstrobel</groupId>
       <artifactId>procyon-compilertools</artifactId>
-      <version>0.5.28</version>
+      <version>0.5.32</version>
     </dependency>
     
     <!-- Apache v2 license  2016 checked. Also transitive include from above, 
@@ -132,7 +188,7 @@
     <dependency>  
       <groupId>org.bitbucket.mstrobel</groupId>
       <artifactId>procyon-core</artifactId>
-      <version>0.5.28</version>
+      <version>0.5.32</version>
     </dependency>
     
     <!-- for reading / transforming / generating JCas cover classes -->
@@ -261,8 +317,17 @@
 				<groupId>org.apache.maven.plugins</groupId>
 				<artifactId>maven-surefire-plugin</artifactId>
 				<configuration>
-          <!-- testing on 64 bit Linux requires larger heap -->
-					<argLine>-Xmx650M</argLine>
+          <!-- set the heap using the property maven.surefire.heap -->
+          <!--  include dependencies that are for logging but specified as "provided" -->
+          <additionalClasspathElements>
+            <additionalClasspathElement>${settings.localRepository}/org/apache/logging/log4j/log4j-core/${log4j.version}/log4j-core-${log4j.version}.jar</additionalClasspathElement>
+            <additionalClasspathElement>${settings.localRepository}/org/apache/logging/log4j/log4j-api/${log4j.version}/log4j-api-${log4j.version}.jar</additionalClasspathElement>
+            <additionalClasspathElement>${settings.localRepository}/org/apache/logging/log4j/log4j-slf4j-impl/${log4j.version}/log4j-slf4j-impl-${log4j.version}.jar</additionalClasspathElement>
+          </additionalClasspathElements>
+          <!-- exclude log4j slf bridge for testing 
+          <classpathDependencyExcludes>
+            <classpathDependencyExclude>org.apache.logging.log4j:log4j-slf4j-impl</classpathDependencyExclude>
+          </classpathDependencyExcludes>          -->
 				</configuration>
 			</plugin>
 		</plugins>
diff --git a/uimaj-core/src/main/java/org/apache/uima/InternationalizedException.java b/uimaj-core/src/main/java/org/apache/uima/InternationalizedException.java
index 5d10dcc..ac32aed 100644
--- a/uimaj-core/src/main/java/org/apache/uima/InternationalizedException.java
+++ b/uimaj-core/src/main/java/org/apache/uima/InternationalizedException.java
@@ -71,8 +71,10 @@
    
    /**
     * the thread local class loader at creation time, see UIMA-4793
+    * Transient to allow exceptions to be serialized.
+    * Deserialized versions have null as their value, which is handled by the users
     */
-   final private ClassLoader originalContextClassLoader;
+   final transient private ClassLoader originalContextClassLoader;
 
    /**
     * Creates a new <code>InternationalizedException</code> with a null
diff --git a/uimaj-core/src/main/java/org/apache/uima/InternationalizedRuntimeException.java b/uimaj-core/src/main/java/org/apache/uima/InternationalizedRuntimeException.java
index e768dc6..281d24f 100644
--- a/uimaj-core/src/main/java/org/apache/uima/InternationalizedRuntimeException.java
+++ b/uimaj-core/src/main/java/org/apache/uima/InternationalizedRuntimeException.java
@@ -73,10 +73,12 @@
 
   /**
    * the thread local class loader at creation time, see UIMA-4793
+   * Transient to allow exceptions to be serialized.
+   * Deserialized versions have null as their value, which is handled by the users
    */
-  final private ClassLoader originalContextClassLoader;
+  final transient private ClassLoader originalContextClassLoader;
 
-  /**
+   /**
    * Creates a new <code>InternationalizedRuntimeException</code> with a null message.
    */
   public InternationalizedRuntimeException() {
diff --git a/uimaj-core/src/main/java/org/apache/uima/List_of_ints.java b/uimaj-core/src/main/java/org/apache/uima/List_of_ints.java
index 9f15663..ea25f70 100644
--- a/uimaj-core/src/main/java/org/apache/uima/List_of_ints.java
+++ b/uimaj-core/src/main/java/org/apache/uima/List_of_ints.java
@@ -20,7 +20,6 @@
 package org.apache.uima;

 

 import java.util.Arrays;

-import java.util.Iterator;

 import java.util.NoSuchElementException;

 import java.util.PrimitiveIterator.OfInt;

 

@@ -209,11 +208,11 @@
           @Override

           public boolean hasNext() {return false;}

           @Override

-          public int next() throws NoSuchElementException {throw new NoSuchElementException();}

+          public int nextNvc() {throw new IllegalStateException();}

           @Override

           public boolean hasPrevious() {return false;}

           @Override

-          public int previous() {throw new NoSuchElementException();}

+          public int previousNvc() {throw new IllegalStateException();}

           @Override

           public void moveToStart() {}

           @Override

@@ -359,28 +358,21 @@
           public boolean hasNext() {

             return pos >= 0 && pos < size();

           }

-

+          

           @Override

-          public int next() throws NoSuchElementException {

-            if (!hasNext()) {

-              throw new NoSuchElementException();

-            }

+          public int nextNvc() {

             return get(pos++);

           }

 

           @Override

           public boolean hasPrevious() {

-            return pos >= 0 && pos < size();  // same as has next

+            return pos > 0 && pos < size(); 

           }

 

           @Override

-          public int previous() {

-            if (!hasPrevious()) {

-              throw new NoSuchElementException();

-            }

-            return get(pos--);

+          public int previousNvc() {

+            return get(--pos);

           }

-

           @Override

           public void moveToStart() {

             pos = 0;

diff --git a/uimaj-core/src/main/java/org/apache/uima/UIMAFramework.java b/uimaj-core/src/main/java/org/apache/uima/UIMAFramework.java
index da99b7d..1c85283 100644
--- a/uimaj-core/src/main/java/org/apache/uima/UIMAFramework.java
+++ b/uimaj-core/src/main/java/org/apache/uima/UIMAFramework.java
@@ -91,6 +91,16 @@
    * disables the cache; any other value leaves the default setting of true.
    */
   public static final String JCAS_CACHE_ENABLED = "jcas_cache_enabled";
+  
+  /**
+   * Key to be used in the Properties object returned by
+   * {@link #getDefaultPerformanceTuningProperties()}. The value of this key indicates whether 
+   * user-defined JCas classes should be loaded or skipped, during type system commit.
+   * The default is false; set to "true" to skip.  
+   * This is used by the Component Descriptor Editor when manipulating type systems, to avoid any
+   * issues with loading and working with different type systems where any JCas classes might not match.
+   */
+  public static final String SKIP_USER_JCAS_LOADING = "SKIP_USER_JCAS_LOADING";
 
   /**
    * To be implemented by subclasses; this should return a Properties object representing the
@@ -1330,6 +1340,8 @@
       mInstance._initialize();
     } catch (Exception e) {
       // could not load reference implementation
+      System.err.println("Could not create UIMA framework, using framework class name: " + frameworkClassName);
+      e.printStackTrace();
       throw new UIMA_IllegalStateException(UIMA_IllegalStateException.COULD_NOT_CREATE_FRAMEWORK,
               new Object[] { frameworkClassName }, e);
     }
diff --git a/uimaj-core/src/main/java/org/apache/uima/UIMARuntimeException.java b/uimaj-core/src/main/java/org/apache/uima/UIMARuntimeException.java
index 835b9e6..df0daca 100644
--- a/uimaj-core/src/main/java/org/apache/uima/UIMARuntimeException.java
+++ b/uimaj-core/src/main/java/org/apache/uima/UIMARuntimeException.java
@@ -22,7 +22,7 @@
 import java.util.Locale;
 
 /**
- * This is the superclass for all checked exceptions in UIMA.
+ * This is the superclass for all unchecked exceptions in UIMA.
  * 
  * It adds use of a "standard" bundle resource, if the subclasses don't define this.
  * 
@@ -236,6 +236,11 @@
     mMessageBundle = messageBundle;
   }
   
+  public UIMARuntimeException(Throwable aCause, String messageBundle, String messageKey, Object ... aArguments) {
+    this(aCause, messageKey, aArguments);
+    mMessageBundle = messageBundle;
+  }
+  
   /**
    * Creates a new exception with the specified message and cause.
    * 
diff --git a/uimaj-core/src/main/java/org/apache/uima/UIMASaxException.java b/uimaj-core/src/main/java/org/apache/uima/UIMASaxException.java
deleted file mode 100644
index b205d4f..0000000
--- a/uimaj-core/src/main/java/org/apache/uima/UIMASaxException.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*

- * Licensed to the Apache Software Foundation (ASF) under one

- * or more contributor license agreements.  See the NOTICE file

- * distributed with this work for additional information

- * regarding copyright ownership.  The ASF licenses this file

- * to you under the Apache License, Version 2.0 (the

- * "License"); you may not use this file except in compliance

- * with the License.  You may obtain a copy of the License at

- * 

- *   http://www.apache.org/licenses/LICENSE-2.0

- * 

- * Unless required by applicable law or agreed to in writing,

- * software distributed under the License is distributed on an

- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

- * KIND, either express or implied.  See the License for the

- * specific language governing permissions and limitations

- * under the License.

- */

-

-package org.apache.uima;

-

-import java.util.Locale;

-

-import org.xml.sax.SAXException;

-

-/**

- * This is the superclass for all SaxExceptions in UIMA.

- * It provides the link to common implementation in i18nExceptionI (via default methods), and

- * extends SAXException.

- * 

- * <p>It supplies a messages properties file org.apache.uima.UIMASaxException_Messages</p>

- */

-public class UIMASaxException extends SAXException implements I18nExceptionI {

-

-  private static final long serialVersionUID = 1L;

-

-  /**

-   * The name of the {@link java.util.ResourceBundle ResourceBundle} containing the standard UIMA

-   * Exception messages.

-   */

-  public static final String STANDARD_MESSAGE_CATALOG = "org.apache.uima.UIMASaxException_Messages";

-

-  /**

-   * The base name of the resource bundle in which the message for this

-   * exception is located.

-   */

-  private String mResourceBundleName;

-

-  /**

-   * An identifier that maps to the message for this exception.

-   */

-  private String mMessageKey;

-

-  /**

-   * The arguments to this exception's message, if any. This allows an

-   * <code>InternationalizedException</code> to have a compound message, made

-   * up of multiple parts that are concatenated in a language-neutral way.

-   */

-  private Object[] mArguments;

-

-  /**

-   * The exception that caused this exception to occur.

-   */

-  private Throwable mCause;

-

-  /**

-   * Creates a new exception with a null message.

-   */

-  public UIMASaxException() {

-    super();

-  }

-

-  /**

-   * Creates a new exception with the specified cause and a null message.

-   * 

-   * @param aCause

-   *          the original exception that caused this exception to be thrown, if any

-   */

-  public UIMASaxException(Exception aCause) {

-    super(aCause);

-  }

-

-  /**

-   * Creates a new exception with a the specified message.

-   * 

-   * @param aResourceBundleName

-   *          the base name of the resource bundle in which the message for this exception is

-   *          located.

-   * @param aMessageKey

-   *          an identifier that maps to the message for this exception. The message may contain

-   *          placeholders for arguments as defined by the

-   *          {@link java.text.MessageFormat MessageFormat} class.

-   * @param aArguments

-   *          The arguments to the message. <code>null</code> may be used if the message has no

-   *          arguments.

-   */

-  public UIMASaxException(String aResourceBundleName, String aMessageKey, Object[] aArguments) {

-    this(aResourceBundleName, aMessageKey, aArguments, null);

-  }

-

-  /**

-   * Creates a new exception with the specified message and cause.

-   * 

-   * @param aResourceBundleName

-   *          the base name of the resource bundle in which the message for this exception is

-   *          located.

-   * @param aMessageKey

-   *          an identifier that maps to the message for this exception. The message may contain

-   *          placeholders for arguments as defined by the

-   *          {@link java.text.MessageFormat MessageFormat} class.

-   * @param aArguments

-   *          The arguments to the message. <code>null</code> may be used if the message has no

-   *          arguments.

-   * @param aCause

-   *          the original exception that caused this exception to be thrown, if any

-   */

-  public UIMASaxException(String aResourceBundleName, String aMessageKey, Object[] aArguments,

-          Throwable aCause) {

-    super();

-    this.mResourceBundleName = aResourceBundleName;

-    this.mMessageKey = aMessageKey;

-    this.mArguments = aArguments;

-    this.mCause = aCause;

-  }

-

-  /**

-   * Creates a new exception with a message from the {@link #STANDARD_MESSAGE_CATALOG}.

-   * 

-   * @param aMessageKey

-   *          an identifier that maps to the message for this exception. The message may contain

-   *          placeholders for arguments as defined by the

-   *          {@link java.text.MessageFormat MessageFormat} class.

-   * @param aArguments

-   *          The arguments to the message. <code>null</code> may be used if the message has no

-   *          arguments.

-   */

-  public UIMASaxException(String aMessageKey, Object[] aArguments) {

-    this(STANDARD_MESSAGE_CATALOG, aMessageKey, aArguments, null);

-  }

-

-  /**

-   * Creates a new exception with the specified cause and a message from the

-   * {@link #STANDARD_MESSAGE_CATALOG}.

-   * 

-   * @param aMessageKey

-   *          an identifier that maps to the message for this exception. The message may contain

-   *          placeholders for arguments as defined by the

-   *          {@link java.text.MessageFormat MessageFormat} class.

-   * @param aArguments

-   *          The arguments to the message. <code>null</code> may be used if the message has no

-   *          arguments.

-   * @param aCause

-   *          the original exception that caused this exception to be thrown, if any

-   */

-  public UIMASaxException(String aMessageKey, Object[] aArguments, Throwable aCause) {

-    this(STANDARD_MESSAGE_CATALOG, aMessageKey, aArguments, aCause);

-  }

-  

-  /**

-   * Gets the cause of this Exception.

-   * 

-   * @return the Throwable that caused this Exception to occur, if any. Returns

-   *         <code>null</code> if there is no such cause.

-   */

-  public Throwable getCause() {

-     return mCause;

-  }

-

-  public synchronized Throwable initCause(Throwable cause) {

-     mCause = cause;

-     return this;

-  }

-  

-  /**

-   * Gets the base name of the resource bundle in which the message for this

-   * exception is located.

-   * 

-   * @return the resource bundle base name. May return <code>null</code> if

-   *         this exception has no message.

-   */

-  public String getResourceBundleName() {

-     return mResourceBundleName;

-  }

-

-  /**

-   * Gets the identifier for this exception's message. This identifier can be

-   * looked up in this exception's

-   * {@link java.util.ResourceBundle ResourceBundle} to get the locale-specific

-   * message for this exception.

-   * 

-   * @return the resource identifier for this exception's message. May return

-   *         <code>null</code> if this exception has no message.

-   */

-  public String getMessageKey() {

-     return mMessageKey;

-  }

-

-  /**

-   * Gets the arguments to this exception's message. Arguments allow a

-   * <code>InternationalizedException</code> to have a compound message, made

-   * up of multiple parts that are concatenated in a language-neutral way.

-   * 

-   * @return the arguments to this exception's message.

-   */

-  public Object[] getArguments() {

-     if (mArguments == null)

-        return new Object[0];

-     return mArguments.clone();

-  }

-  /**

-   * @return The message of the exception. Useful for including the text in

-   *         another exception.

-   */

-  public String getMessage() {

-    return getLocalizedMessage(Locale.ENGLISH);

-  }

-

-  /**

-   * Gets the localized detail message for this exception. This uses the default

-   * Locale for this JVM. A Locale may be specified using

-   * {@link #getLocalizedMessage(Locale)}.

-   * 

-   * @return this exception's detail message, localized for the default Locale.

-   */

-  public String getLocalizedMessage() {

-    return getLocalizedMessage(Locale.getDefault());

-  }

-}

diff --git a/uimaj-core/src/main/java/org/apache/uima/UIMA_IllegalArgumentException.java b/uimaj-core/src/main/java/org/apache/uima/UIMA_IllegalArgumentException.java
index ff389b4..f00969c 100644
--- a/uimaj-core/src/main/java/org/apache/uima/UIMA_IllegalArgumentException.java
+++ b/uimaj-core/src/main/java/org/apache/uima/UIMA_IllegalArgumentException.java
@@ -100,7 +100,7 @@
    */
   public UIMA_IllegalArgumentException(String aResourceBundleName, String aMessageKey,
           Object[] aArguments, Throwable aCause) {
-    super(aResourceBundleName, aMessageKey, aArguments, aCause);
+    super(aCause, aResourceBundleName, aMessageKey, aArguments);
   }
 
   /**
@@ -133,6 +133,6 @@
    *          the original exception that caused this exception to be thrown, if any
    */
   public UIMA_IllegalArgumentException(String aMessageKey, Object[] aArguments, Throwable aCause) {
-    super(aMessageKey, aArguments, aCause);
+    super(aCause, aMessageKey, aArguments);
   }
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/UIMA_IllegalStateException.java b/uimaj-core/src/main/java/org/apache/uima/UIMA_IllegalStateException.java
index c01906b..6179ddf 100644
--- a/uimaj-core/src/main/java/org/apache/uima/UIMA_IllegalStateException.java
+++ b/uimaj-core/src/main/java/org/apache/uima/UIMA_IllegalStateException.java
@@ -81,6 +81,12 @@
    */
   public static final String CANNOT_SET_CAS_MANAGER = "cannot_set_cas_manager";
   
+  /** Cannot do feature accessing for JCas class {0}, because it is not associated with a committed UIMA Type, either because the type doesn''t exist, or hasn''t been committed.*/
+  public static final String JCAS_NO_TYPE = "JCAS_NO_TYPE";
+  
+  /** Loaded JCas Type {0} has feature {1} with two different type systems having different offsets; this is not supported. */
+  public static final String JCAS_INCOMPATIBLE_TYPE_SYSTEMS = "JCAS_INCOMPATIBLE_TYPE_SYSTEMS";
+
   /**
    * Creates a new exception with a null message.
    */
@@ -135,7 +141,7 @@
    */
   public UIMA_IllegalStateException(String aResourceBundleName, String aMessageKey,
           Object[] aArguments, Throwable aCause) {
-    super(aResourceBundleName, aMessageKey, aArguments, aCause);
+    super(aCause, aResourceBundleName, aMessageKey, aArguments);
   }
 
   /**
@@ -168,6 +174,6 @@
    *          the original exception that caused this exception to be thrown, if any
    */
   public UIMA_IllegalStateException(String aMessageKey, Object[] aArguments, Throwable aCause) {
-    super(aMessageKey, aArguments, aCause);
+    super(aCause, aMessageKey, aArguments);
   }
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/UIMA_UnsupportedOperationException.java b/uimaj-core/src/main/java/org/apache/uima/UIMA_UnsupportedOperationException.java
index b98257c..9413cb4 100644
--- a/uimaj-core/src/main/java/org/apache/uima/UIMA_UnsupportedOperationException.java
+++ b/uimaj-core/src/main/java/org/apache/uima/UIMA_UnsupportedOperationException.java
@@ -108,7 +108,7 @@
    */
   public UIMA_UnsupportedOperationException(String aResourceBundleName, String aMessageKey,
           Object[] aArguments, Throwable aCause) {
-    super(aResourceBundleName, aMessageKey, aArguments, aCause);
+    super(aCause, aResourceBundleName, aMessageKey, aArguments);
   }
 
   /**
diff --git a/uimaj-core/src/main/java/org/apache/uima/UimaContextHolder.java b/uimaj-core/src/main/java/org/apache/uima/UimaContextHolder.java
index ce291f1..5629c1e 100644
--- a/uimaj-core/src/main/java/org/apache/uima/UimaContextHolder.java
+++ b/uimaj-core/src/main/java/org/apache/uima/UimaContextHolder.java
@@ -45,10 +45,13 @@
    * <p>
    * NOTE - Should be used only by the UIMA Framework.
    * 
-   * @param uimaContext -
+   * @param uimaContext - new UimaContext for this thread
+   * @return - previous UimaContext for this thread
    */
-  public static void setContext(UimaContext uimaContext) {
-    threadLocalContext.set(uimaContext);;
+  public static UimaContext setContext(UimaContext uimaContext) {
+    UimaContext prevContext = threadLocalContext.get();
+    threadLocalContext.set(uimaContext);
+    return prevContext;
   }
   
   /**
diff --git a/uimaj-core/src/main/java/org/apache/uima/analysis_component/AnalysisComponent_ImplBase.java b/uimaj-core/src/main/java/org/apache/uima/analysis_component/AnalysisComponent_ImplBase.java
index 2f89071..9cb1ebe 100644
--- a/uimaj-core/src/main/java/org/apache/uima/analysis_component/AnalysisComponent_ImplBase.java
+++ b/uimaj-core/src/main/java/org/apache/uima/analysis_component/AnalysisComponent_ImplBase.java
@@ -25,6 +25,7 @@
 import org.apache.uima.analysis_engine.ResultSpecification;
 import org.apache.uima.resource.ResourceConfigurationException;
 import org.apache.uima.resource.ResourceInitializationException;
+import org.apache.uima.util.Logger;
 
 /**
  * Implementation base class for AnalysisComponents. Normally developers do not extend this class
@@ -117,7 +118,15 @@
     }    
     return mContext;
   }
-
+  
+  /**
+   * 
+   * @return the Logger associated with this uima Analysis Engine component
+   */
+  protected Logger getLogger() {
+    return getContext().getLogger();
+  }
+  
   /**
    * Gets the ResultSpecification for this AnalysisComponent. The ResultSpecification is a set of
    * types and features that this AnalysisComponent is asked to produce. An Analysis Component may
diff --git a/uimaj-core/src/main/java/org/apache/uima/analysis_engine/AnalysisEngine.java b/uimaj-core/src/main/java/org/apache/uima/analysis_engine/AnalysisEngine.java
index a201996..d20b90f 100644
--- a/uimaj-core/src/main/java/org/apache/uima/analysis_engine/AnalysisEngine.java
+++ b/uimaj-core/src/main/java/org/apache/uima/analysis_engine/AnalysisEngine.java
@@ -168,6 +168,27 @@
   public static final String PARAM_MBEAN_NAME_PREFIX = "MBEAN_NAME_PREFIX";
   
   /**
+   * Sometimes Annotators may log excessively, causing problems in production settings.
+   * Although this could be controlled using logging configuration, sometimes when
+   * UIMA is embedded into other applications, you may not have easy access to modify those.
+   * <p>
+   * For this case, this key specifies that throttling should be applied to messages
+   * produced by annotators using loggers obtained by Annotator code using the getLogger() API.
+   * <p>
+   * The value specified should be an integer, and is the number of messages allowed before
+   * logging is suppressed.  This number is applied to each logging level, separately.
+   * To suppress all logging, use 0.  
+   */
+  public static final String PARAM_THROTTLE_EXCESSIVE_ANNOTATOR_LOGGING = 
+      "PARAM_THROTTLE_EXCESSIVE_ANNOTATOR_LOGGING";
+  
+  public static final String MDC_ANNOTATOR_IMPL_NAME = "uima_annotator";
+  public static final String MDC_ANNOTATOR_CONTEXT_NAME = "uima_annotator_context_name";
+  public static final String MDC_ROOT_CONTEXT_ID = "uima_root_context_id";
+  public static final String MDC_CAS_ID = "uima_cas_id";
+  
+  
+  /**
    * Initializes this <code>Resource</code> from a <code>ResourceSpecifier</code>. Applications
    * do not need to call this method. It is called automatically by the <code>ResourceFactory</code>
    * and cannot be called a second time.
diff --git a/uimaj-core/src/main/java/org/apache/uima/analysis_engine/asb/impl/FlowControllerContainer.java b/uimaj-core/src/main/java/org/apache/uima/analysis_engine/asb/impl/FlowControllerContainer.java
index 50f7846..f7ec6a3 100644
--- a/uimaj-core/src/main/java/org/apache/uima/analysis_engine/asb/impl/FlowControllerContainer.java
+++ b/uimaj-core/src/main/java/org/apache/uima/analysis_engine/asb/impl/FlowControllerContainer.java
@@ -24,6 +24,7 @@
 
 import org.apache.uima.Constants;
 import org.apache.uima.UIMAFramework;
+import org.apache.uima.UimaContext;
 import org.apache.uima.UimaContextAdmin;
 import org.apache.uima.UimaContextHolder;
 import org.apache.uima.analysis_engine.AnalysisEngine;
@@ -73,9 +74,12 @@
    * 
    * @see org.apache.uima.resource.Resource_ImplBase#initialize(org.apache.uima.resource.ResourceSpecifier,
    *      java.util.Map)
+   *      
+   * UIMA-5043 Set & restore the UimaContextHolder around calls to user code so it can be used to access the External Settings
    */
   public boolean initialize(ResourceSpecifier aSpecifier, Map<String, Object> aAdditionalParams)
           throws ResourceInitializationException {
+    UimaContext prevContext = setContextHolder();   // Get this early so the restore in correct
     try {
       // specifier must be a FlowControllerDescription. (Eventually, we
       // might support remote specifiers, but not yet)
@@ -125,7 +129,6 @@
               "UIMA_flow_controller_init_begin__CONFIG", getMetaData().getName());
       
       // initialize FlowController
-      UimaContextHolder.setContext(getFlowControllerContext());  // for use by POJOs
       mFlowController.initialize(getFlowControllerContext());
 
       mMBeanServer = null;
@@ -149,7 +152,7 @@
     } catch (ResourceConfigurationException e) {
       throw new ResourceInitializationException(e);
     } finally {
-      UimaContextHolder.clearContext();
+      UimaContextHolder.setContext(prevContext);
     }
   }
 
@@ -178,13 +181,13 @@
    * @see org.apache.uima.resource.ConfigurableResource_ImplBase#reconfigure()
    */
   public void reconfigure() throws ResourceConfigurationException {
+    UimaContext prevContext = setContextHolder();  // for use by POJOs
     try {
-      UimaContextHolder.setContext(getFlowControllerContext());  // for use by POJOs
       mFlowController.reconfigure();
     } catch (ResourceInitializationException e) {
       throw new ResourceConfigurationException(e);
     } finally {
-      UimaContextHolder.clearContext();
+      UimaContextHolder.setContext(prevContext);
     }
   }
 
@@ -194,9 +197,7 @@
    * @see org.apache.uima.resource.Resource_ImplBase#destroy()
    */
   public void destroy() {
-    UimaContextHolder.setContext(getFlowControllerContext());  // for use by POJOs
-    mFlowController.destroy();
-    UimaContextHolder.clearContext();
+    withContextHolder(() -> mFlowController.destroy());
     super.destroy();
   }
 
@@ -215,11 +216,11 @@
   public FlowContainer computeFlow(CAS aCAS) throws AnalysisEngineProcessException {
     mTimer.startIt();
     CAS view = null;
+    UimaContext prevContext = setContextHolder();  // for use by POJOs
     try {
       view = Util.getStartingView(aCAS, mSofaAware, getUimaContextAdmin().getComponentInfo());
 
       // now get the right interface(e.g. CAS or JCAS)
-      UimaContextHolder.setContext(getFlowControllerContext());  // for use by POJOs
       Class<? extends AbstractCas> requiredInterface = mFlowController.getRequiredCasInterface();
       AbstractCas casToPass = getCasManager().getCasInterface(view, requiredInterface);    
       ((CASImpl)view).switchClassLoaderLockCasCL(this.getResourceManager().getExtensionClassLoader());
@@ -241,7 +242,7 @@
       mTimer.stopIt();
       getMBean().reportAnalysisTime(mTimer.getDuration());
       getMBean().incrementCASesProcessed();
-      UimaContextHolder.clearContext();
+      UimaContextHolder.setContext(prevContext);
     }
   }
 
@@ -249,12 +250,12 @@
    * @return  the required CAS interface of the FlowController
    */
   public Class<? extends AbstractCas> getRequiredCasInterface() {
-    try {
-      UimaContextHolder.setContext(getFlowControllerContext());  // for use by POJOs
-      return mFlowController.getRequiredCasInterface();
-    } finally {
-      UimaContextHolder.clearContext();
-    }
+//    UimaContext prevContext = setContextHolder();  // for use by POJOs
+//    try {
+      return mFlowController.getRequiredCasInterface(); // not likely to have user code
+//    } finally {
+//      UimaContextHolder.setContext(prevContext);
+//    }
   }
 
   public ProcessingResourceMetaData getProcessingResourceMetaData() {
@@ -274,9 +275,7 @@
    * @param aKeys the keys for the delegates
    */
   public void addAnalysisEngines(Collection<String> aKeys) {
-    UimaContextHolder.setContext(getFlowControllerContext());  // for use by POJOs
-    mFlowController.addAnalysisEngines(aKeys);
-    UimaContextHolder.clearContext();
+    withContextHolder(() -> mFlowController.addAnalysisEngines(aKeys));
   }
 
   /**
@@ -286,11 +285,11 @@
    * @throws AnalysisEngineProcessException - 
    */
   public void removeAnalysisEngines(Collection<String> aKeys) throws AnalysisEngineProcessException {
+    UimaContext prevContext = setContextHolder();  // for use by POJOs
     try {
-      UimaContextHolder.setContext(getFlowControllerContext());  // for use by POJOs
       mFlowController.removeAnalysisEngines(aKeys);
     } finally {
-      UimaContextHolder.clearContext();
+      UimaContextHolder.setContext(prevContext);
     }
   }
 
@@ -332,11 +331,11 @@
   }
   public void collectionProcessComplete() throws AnalysisEngineProcessException {
     if ( mFlowController != null ) {
+      UimaContext prevContext = setContextHolder();  // for use by POJOs
       try {
-        UimaContextHolder.setContext(getFlowControllerContext());  // for use by POJOs
         mFlowController.collectionProcessComplete();
       } finally {
-        UimaContextHolder.clearContext();
+        UimaContextHolder.setContext(prevContext);
       }
     }
   }
diff --git a/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/AggregateAnalysisEngine_impl.java b/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/AggregateAnalysisEngine_impl.java
index 794a309..12938ac 100644
--- a/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/AggregateAnalysisEngine_impl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/AggregateAnalysisEngine_impl.java
@@ -28,6 +28,8 @@
 
 import org.apache.uima.Constants;
 import org.apache.uima.UIMARuntimeException;
+import org.apache.uima.UimaContext;
+import org.apache.uima.UimaContextHolder;
 import org.apache.uima.analysis_engine.AnalysisEngine;
 import org.apache.uima.analysis_engine.AnalysisEngineDescription;
 import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
@@ -144,6 +146,8 @@
       setMetaData(mdCopy);
 
       // resolve component AnalysisEngine and FlowController specifiers
+      // UIMA-5274  Set & restore the UimaContextHolder so that AEs created on this thread can use the Settings
+      UimaContext prevContext = setContextHolder();
       try {
         // next call only done for side effect of resolving imports
         mDescription.getDelegateAnalysisEngineSpecifiers(getResourceManager());
@@ -159,6 +163,8 @@
         }
       } catch (InvalidXMLException e) {
         throw new ResourceInitializationException(e);
+      } finally {
+        UimaContextHolder.setContext(prevContext);
       }
 
       // validate the AnalysisEngineDescription and throw a
diff --git a/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/AnalysisEngineImplBase.java b/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/AnalysisEngineImplBase.java
index 40e4d47..456d902 100644
--- a/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/AnalysisEngineImplBase.java
+++ b/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/AnalysisEngineImplBase.java
@@ -20,12 +20,13 @@
 package org.apache.uima.analysis_engine.impl;
 
 import java.io.IOException;
-import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
 import org.apache.uima.UIMAFramework;
+import org.apache.uima.UimaContext;
 import org.apache.uima.UimaContextAdmin;
+import org.apache.uima.analysis_component.AnalysisComponent;
 import org.apache.uima.analysis_engine.AnalysisEngine;
 import org.apache.uima.analysis_engine.AnalysisEngineManagement;
 import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
@@ -35,18 +36,19 @@
 import org.apache.uima.analysis_engine.ResultSpecification;
 import org.apache.uima.analysis_engine.TextAnalysisEngine;
 import org.apache.uima.analysis_engine.metadata.AnalysisEngineMetaData;
+import org.apache.uima.cas.AbstractCas;
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASException;
-import org.apache.uima.cas.Feature;
-import org.apache.uima.cas.Type;
 import org.apache.uima.cas.TypeSystem;
 import org.apache.uima.cas.impl.CASImpl;
-import org.apache.uima.cas.impl.FeatureImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
 import org.apache.uima.cas.text.Language;
+import org.apache.uima.impl.UimaContext_ImplBase;
 import org.apache.uima.internal.util.JmxMBeanAgent;
+import org.apache.uima.internal.util.function.Runnable_withException;
 import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.impl.JCasImpl;
 import org.apache.uima.resource.CasDefinition;
 import org.apache.uima.resource.ConfigurableResource_ImplBase;
 import org.apache.uima.resource.ResourceInitializationException;
@@ -62,6 +64,7 @@
 import org.apache.uima.util.UimaTimer;
 import org.apache.uima.util.impl.ProcessTraceEvent_impl;
 import org.apache.uima.util.impl.ProcessTrace_impl;
+import org.slf4j.MDC;
 
 /**
  * Provides functionality common to Analysis Engine implementations.
@@ -596,4 +599,77 @@
   protected String getMBeanNamePrefix() {
     return mMBeanNamePrefix;
   }
+  
+  private static final boolean isMDC;
+  static {
+    MDC.put("uima_test", "uima_test");
+    isMDC = null != MDC.get("uima_test");
+    MDC.remove("uima_test");
+  }
+  protected void callInitializeMethod(AnalysisComponent component, UimaContext context) throws ResourceInitializationException {
+//    component.initialize(context);
+    try {
+      withContexts(component, context, null, () -> component.initialize(context));
+    } catch (Exception e) {
+      throw (e instanceof ResourceInitializationException)
+              ? ((ResourceInitializationException)e) 
+              : new ResourceInitializationException(e);
+    }
+  }
+  
+  protected void callProcessMethod(AnalysisComponent component, AbstractCas cas) throws Exception {
+//    component.process(cas);
+//    getMBean().incrementCASesProcessed();
+    withContexts(component, 
+                getUimaContext(), 
+                cas,
+                 () -> {component.process(cas); 
+                        getMBean().incrementCASesProcessed();});
+  }
+  
+  private void withContexts(AnalysisComponent component, UimaContext context, AbstractCas cas, Runnable_withException r) throws Exception {
+    if (isMDC) {
+    UimaContext_ImplBase ucib = (UimaContext_ImplBase)context;
+    String prevCN = pushMDCstring(MDC_ANNOTATOR_CONTEXT_NAME, ucib.getQualifiedContextName());
+    String prevAN = pushMDCstring(MDC_ANNOTATOR_IMPL_NAME, component.getClass().getName());
+    String prevRID = pushMDCstring(MDC_ROOT_CONTEXT_ID, ((UimaContext_ImplBase)ucib.getRootContext())
+                                                     .getMdcId());
+    String prevCAS = null;
+    if (cas != null) {
+      CASImpl casImpl = (cas instanceof JCas) ? ((JCasImpl)cas).getCasImpl() : (CASImpl)cas;
+      prevCAS = pushMDCstring(MDC_CAS_ID, casImpl.getCasId());
+    }
+    try {
+      r.run();
+    } finally {
+      popMDCstring(MDC_ANNOTATOR_CONTEXT_NAME, prevCN);
+      popMDCstring(MDC_ANNOTATOR_IMPL_NAME, prevAN);
+      popMDCstring(MDC_ROOT_CONTEXT_ID, prevRID);
+      if (cas != null) {
+        popMDCstring(MDC_CAS_ID, prevCAS);
+      }
+    }
+    } else {
+      r.run();
+    }
+  }
+    
+  private String pushMDCstring(String key, String value) {
+    if (value == null) value = "";  // protect against failures if no value
+    String v = MDC.get(key);
+    if (value.equals(v)) return value;
+    MDC.put(key, (v == null) ? value : v + " : " + value);
+    return v;
+  }
+  
+  private void popMDCstring(String key, String prev) {
+    String v = MDC.get(key);
+    if (v.equals(prev)) return;
+    if (prev != null) {
+      MDC.put(key,  prev);
+    } else {
+      MDC.remove(key);
+    }
+  }
+
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/PearAnalysisEngineWrapper.java b/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/PearAnalysisEngineWrapper.java
index a07f34f..c8b4a29 100644
--- a/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/PearAnalysisEngineWrapper.java
+++ b/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/PearAnalysisEngineWrapper.java
@@ -51,6 +51,7 @@
 import org.apache.uima.resource.metadata.ResourceMetaData;
 import org.apache.uima.util.InvalidXMLException;
 import org.apache.uima.util.Level;
+import org.apache.uima.util.Logger;
 import org.apache.uima.util.ProcessTrace;
 import org.apache.uima.util.XMLInputSource;
 
@@ -119,7 +120,9 @@
 //       ((ResourceManagerPearWrapper)rsrcMgr).initializeFromParentResourceManager(parentResourceManager);
      }
      rsrcMgr.setExtensionClassPath(sp.classPath, true);
-     rsrcMgr.setCasManager(parentResourceManager.getCasManager());  // shares the same merged type system
+     if (parentResourceManager != null) {
+       rsrcMgr.setCasManager(parentResourceManager.getCasManager());  // shares the same merged type system
+     }
      UIMAFramework.getLogger(this.getClass()).logrb(
             Level.CONFIG,
             this.getClass().getName(),
@@ -337,20 +340,23 @@
   public CasIterator processAndOutputNewCASes(CAS aCAS)
          throws AnalysisEngineProcessException {
 
+    Logger logger = UIMAFramework.getLogger(this.getClass()); 
+    if (logger.isLoggable(Level.FINE)) {
       UIMAFramework.getLogger(this.getClass()).logrb(Level.FINE,
             this.getClass().getName(), "processAndOutputNewCASes",
             LOG_RESOURCE_BUNDLE, "UIMA_analysis_engine_process_begin__FINE",
             new Object[] { this.ae.getAnalysisEngineMetaData().getName() });
-
-      CasIterator result = this.ae.processAndOutputNewCASes(aCAS);
-
+    }
+    
+    CasIterator result = this.ae.processAndOutputNewCASes(aCAS);
+    if (logger.isLoggable(Level.FINE)) {    
       UIMAFramework.getLogger(this.getClass()).logrb(Level.FINE,
             this.getClass().getName(), "processAndOutputNewCASes",
             LOG_RESOURCE_BUNDLE, "UIMA_analysis_engine_process_end__FINE",
             new Object[] { this.ae.getAnalysisEngineMetaData().getName() });
-
-      return result;
-   }
+    }
+    return result;
+  }
 
    /**
     * @see org.apache.uima.resource.Resource#destroy()
diff --git a/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/PrimitiveAnalysisEngine_impl.java b/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/PrimitiveAnalysisEngine_impl.java
index 9d81305..0913b93 100644
--- a/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/PrimitiveAnalysisEngine_impl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/PrimitiveAnalysisEngine_impl.java
@@ -25,6 +25,7 @@
 import org.apache.uima.Constants;
 import org.apache.uima.UIMAFramework;
 import org.apache.uima.UIMA_IllegalStateException;
+import org.apache.uima.UimaContext;
 import org.apache.uima.UimaContextAdmin;
 import org.apache.uima.UimaContextHolder;
 import org.apache.uima.analysis_component.AnalysisComponent;
@@ -51,6 +52,7 @@
 import org.apache.uima.resource.metadata.ResourceMetaData;
 import org.apache.uima.util.Level;
 import org.apache.uima.util.Logger;
+import org.slf4j.MDC;
 
 /**
  * Reference implementation of {@link AnalysisEngine}.
@@ -59,9 +61,10 @@
  */
 public class PrimitiveAnalysisEngine_impl extends AnalysisEngineImplBase implements AnalysisEngine {
   /**
-   * current class
+   * UIMA-5043 Set & restore the UimaContextHolder around calls to user code so it can be used to access the External Settings
    */
   
+  
   private static final Class<PrimitiveAnalysisEngine_impl> CLASS_NAME = PrimitiveAnalysisEngine_impl.class;
  
   /**
@@ -220,7 +223,6 @@
       return;
     }
 
-    UimaContextHolder.setContext(getUimaContext());  // for use by POJOs
     try {
       Object userObject = annotatorClass.newInstance();
       if (userObject instanceof AnalysisComponent) {
@@ -230,10 +232,9 @@
                 getAnalysisEngineMetaData(), aAdditionalParams);
       }
     } catch (ResourceInitializationException e) {
-      UimaContextHolder.clearContext();
       throw e;
     } catch (Exception e) {
-      UimaContextHolder.clearContext();
+      
       throw new ResourceInitializationException(
               ResourceInitializationException.COULD_NOT_INSTANTIATE_ANNOTATOR, new Object[] {
                   annotatorClassName, mDescription.getSourceUrlString() }, e);
@@ -246,8 +247,10 @@
     uimaContext.setLogger(logger);
 
     // initialize AnalysisComponent
+    UimaContext prevContext = setContextHolder();  // for use by POJOs
     try {
-      mAnalysisComponent.initialize(getUimaContext());
+      callInitializeMethod(mAnalysisComponent, getUimaContext());
+//      mAnalysisComponent.initialize(getUimaContext());
       // set up the CAS pool for this AE (this won't do anything if mAnalysisComponent.getCasInstancesRequired() == 0)
       getUimaContextAdmin().defineCasPool(mAnalysisComponent.getCasInstancesRequired(),
               getPerformanceTuningSettings(), mSofaAware);
@@ -256,7 +259,7 @@
               ResourceInitializationException.ANNOTATOR_INITIALIZATION_FAILED, new Object[] {
                   annotatorClassName, mDescription.getSourceUrlString() }, e);
     } finally {
-      UimaContextHolder.clearContext();
+      UimaContextHolder.setContext(prevContext);
     }
   }
 
@@ -265,9 +268,7 @@
    */
   public void destroy() {
     if (mAnalysisComponent != null) {
-      UimaContextHolder.setContext(getUimaContext());  // for use by POJOs
-      mAnalysisComponent.destroy();
-      UimaContextHolder.clearContext();
+      withContextHolder(() -> mAnalysisComponent.destroy());
       getLogger().logrb(Level.CONFIG, CLASS_NAME.getName(), "destroy", LOG_RESOURCE_BUNDLE,
               "UIMA_analysis_engine_destroyed__CONFIG", getMetaData().getName());
     }
@@ -307,22 +308,22 @@
 
   public void batchProcessComplete() throws AnalysisEngineProcessException {
     enterBatchProcessComplete();
+    UimaContext prevContext = setContextHolder();  // for use by POJOs
     try {
-      UimaContextHolder.setContext(getUimaContext());  // for use by POJOs
       getAnalysisComponent().batchProcessComplete();
     } finally {
-      UimaContextHolder.clearContext();
+      UimaContextHolder.setContext(prevContext);
       exitBatchProcessComplete();
     }
   }
 
   public void collectionProcessComplete() throws AnalysisEngineProcessException {
     enterCollectionProcessComplete();
+    UimaContext prevContext = setContextHolder();  // for use by POJOs
     try {
-      UimaContextHolder.setContext(getUimaContext());  // for use by POJOs
       getAnalysisComponent().collectionProcessComplete();
     } finally {
-      UimaContextHolder.clearContext();
+      UimaContextHolder.setContext(prevContext);
       exitCollectionProcessComplete();
     }
   }
@@ -342,6 +343,7 @@
             "UIMA_analysis_engine_process_begin__FINE", resourceName);
     try {
       CAS view = null;
+      UimaContext prevContext = setContextHolder();  // for use by POJOs
       // call Annotator's process method
       try {
 
@@ -350,7 +352,6 @@
         view = Util.getStartingView(aCAS, mSofaAware, getUimaContextAdmin().getComponentInfo());
         // now get the right interface(e.g. CAS or JCAS)
         // must precede the switchClassLoader call below UIMA-2211
-        UimaContextHolder.setContext(getUimaContext());  // for use by POJOs
         Class<? extends AbstractCas> requiredInterface = mAnalysisComponent.getRequiredCasInterface();
         AbstractCas casToPass = getCasManager().getCasInterface(view, requiredInterface);
 
@@ -375,10 +376,19 @@
        
         // insure view is passed to switch / restore class loader https://issues.apache.org/jira/browse/UIMA-2211
         ((CASImpl)view).switchClassLoaderLockCasCL(this.getResourceManager().getExtensionClassLoader());
-
-        // call the process method
-        mAnalysisComponent.process(casToPass);
-        getMBean().incrementCASesProcessed();
+          
+        
+        callProcessMethod(mAnalysisComponent, casToPass);
+//        // call the process method
+//        MDC.put(MDC_ANNOTATOR_CONTEXT_NAME, ((UimaContext_ImplBase)getUimaContext()).getQualifiedContextName());
+//        MDC.put(MDC_ANNOTATOR_IMPL_NAME, mAnalysisComponent.getClass().getName());
+//        try {
+//        mAnalysisComponent.process(casToPass);
+//        } finally {
+//          MDC.remove(MDC_ANNOTATOR_CONTEXT_NAME);
+//          MDC.remove(MDC_ANNOTATOR_IMPL_NAME);
+//        }
+//        getMBean().incrementCASesProcessed();
         
         //note we do not clear the CAS's currentComponentInfo at this time
         // nor do we unlock the cas and switch it back (class loader-wise).  The AnalysisComponents still
@@ -403,7 +413,7 @@
         }
         throw e;
       } finally {
-        UimaContextHolder.clearContext();
+        UimaContextHolder.setContext(prevContext);
       }
 
       // log end of event
@@ -505,8 +515,8 @@
    */
   protected CAS callAnalysisComponentNext() throws AnalysisEngineProcessException,
           ResultNotSupportedException {
+    UimaContext prevContext = setContextHolder();  // for use by POJOs
     try {
-      UimaContextHolder.setContext(getUimaContext());  // for use by POJOs
       AbstractCas absCas = mAnalysisComponent.next();
       getMBean().incrementCASesProcessed();
       // notify UimaContext that a CAS was returned -- it uses
@@ -536,7 +546,7 @@
       else
         throw new AnalysisEngineProcessException(e);
     } finally {
-      UimaContextHolder.clearContext();
+      UimaContextHolder.setContext(prevContext);
     }
   }
 
@@ -548,13 +558,13 @@
     super.reconfigure();
 
     // inform the annotator
+    UimaContext prevContext = setContextHolder();  // for use by POJOs
     try {
-      UimaContextHolder.setContext(getUimaContext());  // for use by POJOs
       mAnalysisComponent.reconfigure();
     } catch (ResourceInitializationException e) {
       throw new ResourceConfigurationException(e);
     } finally {
-      UimaContextHolder.clearContext();
+      UimaContextHolder.setContext(prevContext);
     }
   }
 
@@ -586,8 +596,8 @@
       if (casAvailable) {
         return true;
       }
+      UimaContext prevContext = setContextHolder();  // for use by POJOs
       try {
-        UimaContextHolder.setContext(getUimaContext());  // for use by POJOs
         casAvailable = mMyAnalysisComponent.hasNext();
         if (!casAvailable) {
           //when hasNext returns false, by contract the AnalysisComponent is done processing its
@@ -606,7 +616,7 @@
       }
  
       finally {
-        UimaContextHolder.clearContext();
+        UimaContextHolder.setContext(prevContext);
         exitProcess();
       }
     }
diff --git a/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/UimacppAnalysisEngineImpl.java b/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/UimacppAnalysisEngineImpl.java
index a48a3df..32f38da 100644
--- a/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/UimacppAnalysisEngineImpl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/analysis_engine/impl/UimacppAnalysisEngineImpl.java
@@ -55,6 +55,7 @@
 import org.apache.uima.util.CasCreationUtils;
 import org.apache.uima.util.InvalidXMLException;
 import org.apache.uima.util.Level;
+import org.slf4j.MDC;
 
 /**
  * Reference implementation of {@link AnalysisEngine}.
@@ -279,8 +280,19 @@
         // process method
         Class<CAS> requiredInterface = mAnnotator.getRequiredCasInterface();
         AbstractCas casToPass = getCasManager().getCasInterface(view, requiredInterface);
-        mAnnotator.process(casToPass);
-        getMBean().incrementCASesProcessed();
+        
+        callProcessMethod(mAnnotator, casToPass);
+//        
+//        MDC.put(MDC_ANNOTATOR_CONTEXT_NAME, ((UimaContext_ImplBase)getUimaContext()).getQualifiedContextName());
+//        MDC.put(MDC_ANNOTATOR_IMPL_NAME, mAnnotator.getClass().getName());
+//        try {       
+//          mAnnotator.process(casToPass);
+//        } finally {
+//          MDC.remove(MDC_ANNOTATOR_CONTEXT_NAME);
+//          MDC.remove(MDC_ANNOTATOR_IMPL_NAME);
+//        }
+
+//        getMBean().incrementCASesProcessed();
       } catch (Exception e) {
         if (e instanceof AnalysisEngineProcessException) {
           throw e;
@@ -325,7 +337,8 @@
       getUimaContextAdmin().defineCasPool(mAnnotator.getCasInstancesRequired(),
               getPerformanceTuningSettings(), mSofaAware);
 
-      mAnnotator.initialize(uimaContext);
+      callInitializeMethod(mAnnotator, uimaContext);
+//      mAnnotator.initialize(uimaContext);
     }
   }
 
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/ArrayFS.java b/uimaj-core/src/main/java/org/apache/uima/cas/ArrayFS.java
index ae99948..b2bbc1e 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/ArrayFS.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/ArrayFS.java
@@ -19,22 +19,24 @@
 
 package org.apache.uima.cas;
 
+import org.apache.uima.jcas.cas.TOP;
+
 /**
  * Feature structure array interface. To create a FS array object, use
- * {@link org.apache.uima.cas.CAS#createArrayFS CAS.createArrayFS()}.
- * 
- * 
+ * {@link org.apache.uima.cas.CAS#createArrayFS(int length)} or
+ * new FSArray(aJCas, length)
  */
-public interface ArrayFS extends CommonArrayFS {
+public interface ArrayFS<E extends FeatureStructure> extends CommonArrayFS<E> {
 
   /**
    * Get the i-th feature structure from the array.
    * @param i index
+   * @param <U> The class of the item being obtained by the get
    * @return The i-th feature structure.
    * @exception ArrayIndexOutOfBoundsException
    *              If the index is out of bounds.
    */
-  FeatureStructure get(int i) throws ArrayIndexOutOfBoundsException;
+  <U extends TOP> U get(int i) throws ArrayIndexOutOfBoundsException;
 
   /**
    * Set the i-th value.
@@ -46,7 +48,7 @@
    * @exception ArrayIndexOutOfBoundsException
    *              If <code>i</code> is out of bounds.
    */
-  void set(int i, FeatureStructure fs) throws ArrayIndexOutOfBoundsException;
+  void set(int i, E fs) throws ArrayIndexOutOfBoundsException;
 
   /**
    * Copy the contents of the array from <code>start</code> to <code>end</code> to the
@@ -60,11 +62,12 @@
    *          Where to start copying into <code>dest</code>.
    * @param length
    *          The number of elements to copy.
+   * @param <U> the type of the array element
    * @exception ArrayIndexOutOfBoundsException
    *              If <code>srcOffset &lt; 0</code> or <code>length &gt; size()</code> or
    *              <code>destOffset + length &gt; destArray.length</code>.
    */
-  void copyToArray(int srcOffset, FeatureStructure[] dest, int destOffset, int length)
+  <U extends FeatureStructure> void copyToArray(int srcOffset, U[] dest, int destOffset, int length)
       throws ArrayIndexOutOfBoundsException;
 
   /**
@@ -78,18 +81,27 @@
    *          Where to start copying to in the destination array.
    * @param length
    *          The number of elements to copy.
+   * @param <T> the class of the array being copied into
    * @exception ArrayIndexOutOfBoundsException
    *              If <code>srcOffset &lt; 0</code> or <code>length &gt; size()</code> or
    *              <code>destOffset + length &gt; destArray.length</code>.
    */
-  void copyFromArray(FeatureStructure[] src, int srcOffset, int destOffset, int length)
+  <T extends FeatureStructure> void copyFromArray(T[] src, int srcOffset, int destOffset, int length)
       throws ArrayIndexOutOfBoundsException;
 
   /**
    * Creates a new array the this array is copied to.
-   * 
+   * Return type is FeatureStructure to be backwards compatible with V2
    * @return A Java array copy of this FS array.
    */
   FeatureStructure[] toArray();
+  
+  /**
+   * Populates an existing array from this FS Array.
+   * @param a the existing array
+   * @param <T> the type of the element
+   * @return the populated array
+   */
+  <T extends TOP> T[] toArray(T[] a);
 
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/BooleanArrayFS.java b/uimaj-core/src/main/java/org/apache/uima/cas/BooleanArrayFS.java
index 9822f7b..5f1fa67 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/BooleanArrayFS.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/BooleanArrayFS.java
@@ -21,11 +21,10 @@
 
 /**
  * Boolean array interface. To create a boolean array object, use
- * {@link org.apache.uima.cas.CAS#createBooleanArrayFS CAS.createBooleanArrayFS()}.
- * 
- * 
+ * {@link org.apache.uima.cas.CAS#createBooleanArrayFS CAS.createBooleanArrayFS(int)} or
+ * new BooleanArray(aJCas, length) 
  */
-public interface BooleanArrayFS extends CommonArrayFS {
+public interface BooleanArrayFS extends CommonArrayFS<Boolean> {
 
   /**
    * Get the i-th string from the array.
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/ByteArrayFS.java b/uimaj-core/src/main/java/org/apache/uima/cas/ByteArrayFS.java
index 1a761d5..e9e191a 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/ByteArrayFS.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/ByteArrayFS.java
@@ -21,11 +21,10 @@
 
 /**
  * Byte array interface. To create a byte array object, use
- * {@link org.apache.uima.cas.CAS#createByteArrayFS CAS.createByteArrayFS()}.
- * 
- * 
+ * {@link org.apache.uima.cas.CAS#createByteArrayFS CAS.createByteArrayFS(int)}
+ * or new ByteArray(aJCas, length)
  */
-public interface ByteArrayFS extends CommonArrayFS {
+public interface ByteArrayFS extends CommonArrayFS<Byte> {
 
   /**
    * Get the i-th string from the array.
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/CAS.java b/uimaj-core/src/main/java/org/apache/uima/cas/CAS.java
index bc94ae5..6630caa 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/CAS.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/CAS.java
@@ -20,15 +20,34 @@
 package org.apache.uima.cas;
 
 import java.io.InputStream;
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.ListIterator;
 
 import org.apache.uima.cas.admin.CASAdminException;
+import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.LowLevelCAS;
 import org.apache.uima.cas.impl.SelectFSs_impl;
+import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.text.AnnotationFS;
 import org.apache.uima.cas.text.AnnotationIndex;
 import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.cas.BooleanArray;
+import org.apache.uima.jcas.cas.ByteArray;
+import org.apache.uima.jcas.cas.DoubleArray;
+import org.apache.uima.jcas.cas.EmptyFSList;
+import org.apache.uima.jcas.cas.EmptyFloatList;
+import org.apache.uima.jcas.cas.EmptyIntegerList;
+import org.apache.uima.jcas.cas.EmptyList;
+import org.apache.uima.jcas.cas.EmptyStringList;
+import org.apache.uima.jcas.cas.FSArray;
+import org.apache.uima.jcas.cas.FloatArray;
+import org.apache.uima.jcas.cas.IntegerArray;
+import org.apache.uima.jcas.cas.LongArray;
+import org.apache.uima.jcas.cas.ShortArray;
+import org.apache.uima.jcas.cas.StringArray;
+import org.apache.uima.jcas.cas.TOP;
+import org.apache.uima.jcas.impl.JCasImpl;
 
 /**
  * Object-oriented CAS (Common Analysis System) API.
@@ -61,9 +80,6 @@
  * {@link TypeSystem TypeSystem} object, you can access the {@link Type Type} and
  * {@link Feature Feature} objects for the CAS built-in types. Note that this interface also
  * provides constants for the names of the built-in types and features.
- * 
- * 
- * 
  */
 public interface CAS extends AbstractCas {
 
@@ -513,6 +529,12 @@
    */
   <T extends FeatureStructure> T createFS(Type type) throws CASRuntimeException;
 
+  /* 
+   * ===============  These next methods might be deprecated in favor of
+   * ===============  new FSArray(jcas, length) etc.
+   * ===============  except that these run with the CAS, not JCas 
+   */
+  
   /**
    * Create a new feature structure array.
    * 
@@ -595,14 +617,22 @@
   DoubleArrayFS createDoubleArrayFS(int length) throws CASRuntimeException;
 
   /**
-   * Get the JCas for this CAS.
+   * Get the JCas view for this CAS view
    * 
-   * @return The JCas for this CAS.
-   * @throws CASException -
+   * @return The JCas view for this CAS view
+   * @throws CASException not thrown in v3, but kept for backwards compatibility
    */
   JCas getJCas() throws CASException;
 
   /**
+   * Get the JCasImpl view for this CAS view
+   * @return the JCasImpl view for this CAS view
+   */
+  default JCasImpl getJCasImpl() {
+    return ((CASImpl)this.getLowLevelCAS()).getJCasImpl();
+  }
+  
+  /**
    * Get the Cas view that the current component should use.  This
    * should only be used by single-view components.
    * 
@@ -759,6 +789,20 @@
   <T extends AnnotationFS> AnnotationIndex<T> getAnnotationIndex(Type type) throws CASRuntimeException;
   
   /**
+   * Get the standard annotation index restricted to a specific annotation type.
+   * 
+   * @param clazz
+   *          The annotation type the index is restricted to, specified as a JCas class
+   * @param <T> the topmost Java class corresponding to the type
+   * @return The standard annotation index, restricted to <code>type</code>.
+   * @exception CASRuntimeException When <code>type</code> is not an annotation type.
+   */
+  default <T extends AnnotationFS> AnnotationIndex<T> getAnnotationIndex(Class<T> clazz) 
+      throws CASRuntimeException {
+    return getAnnotationIndex(getCasType((Class) clazz));
+  }
+  
+  /**
    * Create a new annotation. Note that you still need to insert the annotation into the index
    * repository yourself.
    * 
@@ -774,7 +818,7 @@
   <T extends AnnotationFS> AnnotationFS createAnnotation(Type type, int begin, int end);
 
   /**
-   * Get the document annotation. The document has a string-valued feature called "language" where
+   * Get the Document Annotation. The Document Annotation has a string-valued feature called "language" where
    * the document language is specified.
    * 
    * @param <T> the Java class for the document annotation.  Could be the JCas cover class or FeatureStructure
@@ -1122,23 +1166,234 @@
    */
   void protectIndexes(Runnable runnable);
 
-  default <T extends FeatureStructure> SelectFSs<T> select() {
+  /**
+   * @param <T> the Type of the elements being accessed
+   * @return a newly created selection object for accessing feature structures
+   */  
+  default <T extends TOP> SelectFSs<T> select() {
     return new SelectFSs_impl<>(this);
   }
 
-  default <T extends FeatureStructure> SelectFSs<T> select(Type type) {
+  /**
+   * @param type specifies the type (and subtypes of that type) to access
+   * @param <T> the Type of the elements being accessed
+   * @return a newly created selection object for accessing feature structures of that type and its subtypes
+   */
+  default <T extends TOP> SelectFSs<T> select(Type type) {
     return new SelectFSs_impl<>(this).type(type);
   }
 
-  default <T extends FeatureStructure> SelectFSs<T> select(Class<T> clazz) {
+  /**
+   * @param clazz a JCas class corresponding to the type (and subtypes of that type) to access
+   * @param <T> the Type of the elements being accessed
+   * @return a newly created selection object for accessing feature structures of that type and its subtypes
+   */
+  default <T extends TOP> SelectFSs<T> select(Class<T> clazz) {
     return new SelectFSs_impl<>(this).type(clazz);
   }
 
-  default <T extends FeatureStructure> SelectFSs<T> select(int jcasType) {
+  /**
+   * @param jcasType the "type" field from the JCas class corresponding to the type (and subtypes of that type) to access
+   * @param <T> the Type of the elements being accessed
+   * @return a newly created selection object for accessing feature structures of that type and its subtypes
+   */
+  default <T extends TOP> SelectFSs<T> select(int jcasType) {
     return new SelectFSs_impl<>(this).type(jcasType);
   }
 
-  default <T extends FeatureStructure> SelectFSs<T> select(String fullyQualifiedTypeName) {
+  /**
+   * @param fullyQualifiedTypeName the string name of the type to access
+   * @param <T> the Type of the elements being accessed
+   * @return a newly created selection object for accessing feature structures of that type and its subtypes
+   */
+  default <T extends TOP> SelectFSs<T> select(String fullyQualifiedTypeName) {
     return new SelectFSs_impl<>(this).type(fullyQualifiedTypeName);
   }
+  
+  /**
+   * @param <T> the type of the element of the list
+   * @param clazz a JCas class corresponding to the type (and subtypes of that type) to access
+   * @return a lazily created shared (for this CAS) empty list
+   */
+  default <T extends TOP> EmptyList emptyList(Class<T> clazz) {
+    return ((CASImpl)this.getLowLevelCAS()).emptyListFromTypeCode(((TypeImpl)getCasType(clazz)).getCode());
+  }
+  
+  /** 
+   * @return a lazily created shared (for this CAS) empty list
+   */
+  default EmptyFloatList emptyFloatList() {
+    return ((CASImpl)getLowLevelCAS()).emptyFloatList();
+  };
+  
+  /** 
+   * @param <T> the type of the elements of the FSList
+   * @return a lazily created shared (for this CAS) empty list
+   */
+  default <T extends TOP> EmptyFSList<T> emptyFSList() {
+    return ((CASImpl)getLowLevelCAS()).emptyFSList();
+  };
+  
+  /** 
+   * @return a lazily created shared (for this CAS) empty list
+   */
+  default EmptyIntegerList emptyIntegerList() {
+    return ((CASImpl)getLowLevelCAS()).emptyIntegerList();
+  };
+
+  /** 
+   * @return a lazily created shared (for this CAS) empty list
+   */
+  default EmptyStringList emptyStringList() {
+    return ((CASImpl)getLowLevelCAS()).emptyStringList();
+  };
+
+  /**
+   * @param <T> the type of the elements of the array
+   * @param clazz the class of the elements of the array
+   * @return a lazily created shared (for this CAS) 0-length array
+   */
+  default <T extends TOP> CommonArrayFS<T> emptyArray(Class<T> clazz) {
+    return ((CASImpl)getLowLevelCAS()).emptyArray(getCasType(clazz));
+  }
+  
+  /** 
+   * @return a lazily created shared (for this CAS) 0-length array
+   */
+  default FloatArray emptyFloatArray() {
+    return ((CASImpl)getLowLevelCAS()).emptyFloatArray();
+  };
+
+  /** 
+   * @param <T> the type of the lements of the FSArray
+   * @return a lazily created shared (for this CAS) 0-length array
+   */
+  default <T extends FeatureStructure> FSArray<T> emptyFSArray() {
+    return ((CASImpl)getLowLevelCAS()).emptyFSArray();
+  };
+
+  /** 
+   * @return a lazily created shared (for this CAS) 0-length array
+   */
+  default IntegerArray emptyIntegerArray() {
+    return ((CASImpl)getLowLevelCAS()).emptyIntegerArray();
+  };
+
+  /** 
+   * @return a lazily created shared (for this CAS) 0-length array
+   */
+  default StringArray emptyStringArray() {
+    return ((CASImpl)getLowLevelCAS()).emptyStringArray();
+  };
+
+  /** 
+   * @return a lazily created shared (for this CAS) 0-length array
+   */
+  default DoubleArray emptyDoubleArray() {
+    return ((CASImpl)getLowLevelCAS()).emptyDoubleArray();
+  };
+
+  /** 
+   * @return a lazily created shared (for this CAS) 0-length array
+   */
+  default LongArray emptyLongArray() {
+    return ((CASImpl)getLowLevelCAS()).emptyLongArray();
+  };
+
+  /** 
+   * @return a lazily created shared (for this CAS) 0-length array
+   */
+  default ShortArray emptyShortArray() {
+    return ((CASImpl)getLowLevelCAS()).emptyShortArray();
+  };
+
+  /** 
+   * @return a lazily created shared (for this CAS) 0-length array
+   */
+  default ByteArray emptyByteArray() {
+    return ((CASImpl)getLowLevelCAS()).emptyByteArray();
+  };
+
+  /** 
+   * @return a lazily created shared (for this CAS) 0-length array
+   */
+  default BooleanArray emptyBooleanArray() {
+    return ((CASImpl)getLowLevelCAS()).emptyBooleanArray();
+  };
+  
+  /**
+   * @param clazz - a JCas class
+   * @param <T> the type of the JCas class
+   * @return the corresponding Type, for this CAS
+   */
+  default <T extends TOP> Type getCasType(Class<T> clazz) {
+    return this.getJCasImpl().getCasType(clazz);
+  }
+  
+  /**
+   * Gets an iterator over all indexed (in this CAS view) FeatureStructures of the specified Type (and any of its
+   * subtypes).  The elements are returned in arbitrary order, and duplicates (if they exist)
+   * are not removed.
+   *
+   * @param clazz - the JCas Java class specifing which type and subtypes are included
+   * @param <T> the Java clazz
+   *  
+   * @return An iterator that returns all indexed FeatureStructures of the Type and its subtypes, 
+   *    corresponding to the JCas clazz, in no particular order.
+   */
+  default <T extends TOP> FSIterator<T> getAllIndexedFS(Class<T> clazz) {
+    return getAllIndexedFS(getCasType(clazz));
+  }
+  
+  /**
+   * Gets an iterator over all indexed (in this CAS view) FeatureStructures of the specified Type (and any of its
+   * subtypes).  The elements are returned in arbitrary order, and duplicates (if they exist)
+   * are not removed.
+   *
+   * @param type the type of Feature Structures to include (including subtypes)
+   * @param <T> the JCas class the iterator uses
+   *  
+   * @return An iterator that returns all indexed FeatureStructures of the Type and its subtypes, 
+   *    corresponding to the JCas clazz, in no particular order.
+   */
+  default <T extends TOP> FSIterator<T> getAllIndexedFS(Type type) {
+    return this.getIndexRepository().getAllIndexedFS(type);
+  }
+
+  /**
+   * Returns an unmodifiable collection of all the FSs that are indexed in this view, in an arbitrary order.  
+   * Subsequent modifications to the indexes do not affect this collection.
+   * @param type the type of Feature Structures to include (including subtypes)
+   * @param <T> The Java class associated with type
+   * @return an unmodifiable, unordered collection of all indexed (in this view) Feature Structures
+   *         of the specified type (including subtypes)
+   */
+  default <T extends TOP> Collection<T> getIndexedFSs(Type type) {
+    return this.getIndexRepository().getIndexedFSs(type);
+  }
+  
+  /**
+   * Returns an unmodifiable collection of all of the FSs
+   * that are indexed in this view, in an arbitrary order.  
+   * Subsequent modifications to the indexes do not affect this collection.
+   * @return an unmodifiable, unordered collection of all indexed (in this view) Feature Structures
+   *         of the specified type (including subtypes)
+   */
+  default Collection<TOP> getIndexedFSs() { 
+    return this.getIndexRepository().getIndexedFSs();
+  }
+
+  
+  /**
+   * Returns a collection of all the FSs that are indexed in this view, in an arbitrary order.  
+   * Subsequent modifications to the indexes do not affect this collection.
+   * @param clazz
+   *          The JCas class corresponding to the type
+   * @param <T> The Java class associated with type
+   * @return an unmodifiable, unordered collection of all indexed (in this view) Feature Structures
+   *         of the specified type (including subtypes)
+   */
+  default <T extends TOP> Collection<T> getIndexedFSs(Class<T> clazz) {
+    return this.getIndexRepository().getIndexedFSs(clazz);
+  }
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/CASRuntimeException.java b/uimaj-core/src/main/java/org/apache/uima/cas/CASRuntimeException.java
index db4a7c9..8d80b33 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/CASRuntimeException.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/CASRuntimeException.java
@@ -102,7 +102,7 @@
 	/** JCas Class's supertypes for "{0}", "{1}" and the corresponding UIMA Supertypes for "{2}", "{3}" don't have an intersection. */
   public static final String JCAS_CAS_MISMATCH_SUPERTYPE = "JCAS_CAS_MISMATCH_SUPERTYPE";
 
-  /** The JCas class: "{0}" has supertype: "{1}" which doesn't match the UIMA type "{2}"''s supertype "{3}". */
+  /** The JCas class: "{0}" has supertypes: "{1}" which do not match the UIMA type "{2}"''s supertypes "{3}". */
   public static final String JCAS_MISMATCH_SUPERTYPE = "JCAS_MISMATCH_SUPERTYPE";
 	/**
    * JCas type "{0}" used in Java code, but was not declared in the XML type descriptor.
@@ -123,11 +123,18 @@
    * this component.
    */
 	public static final String JCAS_UNKNOWN_TYPE_NOT_IN_CAS = "JCAS_UNKNOWN_TYPE_NOT_IN_CAS";
-
-	/*A JCas class field "{0}" is being initialized by non-framework (user) code before Type System Commit 
-	 * for a type system with a corresponding type. 
-	 * Either change the user load code to not do initialize, or to defer it until after the type system commit.*/
-	public static final String JCAS_CLASS_INITIALIZED_BEFORE_TYPE_SYSTEM_COMMIT = "JCAS_CLASS_INITIALIZED_BEFORE_TYPE_SYSTEM_COMMIT";
+	
+	/* The JCas class being loaded was generated for the "alpha" level of UIMA v3,
+   * and is not supported for Beta and later levels.
+   * 
+   * This can be fixed by regenerating this using the current v3 version of UIMA tooling
+   * (JCasgen, or the migration tooling to migrate from v2).
+   */
+	public static final String JCAS_ALPHA_LEVEL_NOT_SUPPORTED = "JCAS_ALPHA_LEVEL_NOT_SUPPORTED";
+	
+	/** Cas class {0} with feature {1} but is mssing a 0 argument getter.  This feature will not be used to maybe expand the type's feature set.*/
+	public static final String JCAS_MISSING_GETTER = "JCAS_MISSING_GETTER";
+	
 	/**
    * JCas getNthElement method called via invalid object - an empty list: {0}.
    */
@@ -158,6 +165,9 @@
    * a CAS, but rather just with a base CAS.
    */
 	public static final String JCAS_UNSUPPORTED_OP_NOT_CAS = "JCAS_UNSUPPORTED_OP_NOT_CAS";
+	
+	/** The Class "{0}" matches a UIMA Type, and is a subtype of uima.cas.TOP, but is missing the JCas typeIndexId.*/
+	public static final String JCAS_MISSING_TYPEINDEX = "JCAS_MISSING_TYPEINDEX";
 
 	/** A sofaFS with name {0} has already been created. */
 	public static final String SOFANAME_ALREADY_EXISTS = "SOFANAME_ALREADY_EXISTS";
@@ -310,6 +320,9 @@
   
   /** Subiterator {0} has bound type: {1}, begin: {2}, end: {3}, for coveredBy, not using type priorities, matching FS with same begin end and different type {4}, cannot order these*/
   public static final String SUBITERATOR_AMBIGUOUS_POSITION_DIFFERENT_TYPES = "SUBITERATOR_AMBIGUOUS_POSITION_DIFFERENT_TYPES";
+  
+  /** Deserializing Compressed Form 6, a type code: {0} has no corresponding type. currentFsId: {1} nbrFSs: {2} nextFsAddr: {3} */
+  public static final String DESER_FORM_6_BAD_TYPE_CODE = "DESER_FORM_6_BAD_TYPE_CODE";
   /**
    * The constructors are organized
    * 
@@ -327,7 +340,7 @@
 	}
 	
 	public CASRuntimeException(String aMessageKey, Object[] aArguments, Throwable aCause) {
-		super(aMessageKey, aArguments, aCause);
+		super(aCause, aMessageKey, aArguments);
 	}
 	
   public CASRuntimeException(Throwable aCause, String aMessageKey, Object ... aArguments) {
@@ -340,7 +353,7 @@
 
 	public CASRuntimeException(String aResourceBundleName, String aMessageKey, Object[] aArguments,
 			Throwable aCause) {
-		super(aResourceBundleName, aMessageKey, aArguments, aCause);
+		super(aCause, aResourceBundleName, aMessageKey, aArguments);
 	}
 
 	/**
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/CommonArrayFS.java b/uimaj-core/src/main/java/org/apache/uima/cas/CommonArrayFS.java
index 6f494c5..66aec1b 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/CommonArrayFS.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/CommonArrayFS.java
@@ -21,8 +21,10 @@
 
 /**
  * Common parts of the Array interfaces.
+ * Doesn't implement AbstactNonModifiableCollection because
+ *   the specializations of things like toArray using primitives don't work
  */
-public interface CommonArrayFS extends FeatureStructure {
+public interface CommonArrayFS<E> extends FeatureStructure {
 
   /**
    * Return the size of the array.
@@ -105,5 +107,12 @@
    * Copy values from another array of the same kind
    * @param v the other array
    */
-  void copyValuesFrom(CommonArrayFS v);
+  void copyValuesFrom(CommonArrayFS<E> v);
+  
+  /**
+   * @return true if the array is empty
+   */
+  default boolean isEmpty() {
+    return size() == 0;
+  }
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/DoubleArrayFS.java b/uimaj-core/src/main/java/org/apache/uima/cas/DoubleArrayFS.java
index 6145945..0bf5ef4 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/DoubleArrayFS.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/DoubleArrayFS.java
@@ -25,7 +25,7 @@
  * 
  * 
  */
-public interface DoubleArrayFS extends CommonArrayFS {
+public interface DoubleArrayFS extends CommonArrayFS<Double> {
 
   /**
    * Get the i-th element from the array.
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl_javaObject.java b/uimaj-core/src/main/java/org/apache/uima/cas/FSComparators.java
similarity index 60%
copy from uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl_javaObject.java
copy to uimaj-core/src/main/java/org/apache/uima/cas/FSComparators.java
index 47c1228..73ba6bb 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl_javaObject.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/FSComparators.java
@@ -16,19 +16,17 @@
  * specific language governing permissions and limitations

  * under the License.

  */

-

-package org.apache.uima.cas.impl;

+package org.apache.uima.cas;

 

 /**

- * A version of TypeImpl for types that are JavaObject types

- * Note: these are non-creatable (as FeatureStructures), but they may be the

- * values of Feature slots.

- *

+ * There are 4 kinds of comparators

+ *   for the combinations of comparing

+ *     - with or without the "id"

+ *     - with or without type order (with only includes typeOrder if there is such a key included) 

  */

-public class TypeImpl_javaObject extends TypeImpl_primitive {

-  

-  public TypeImpl_javaObject(String name, TypeSystemImpl tsi, TypeImpl supertype, Class<?> javaClass) {

-    super(name, tsi, supertype, javaClass);

-  }

-  

+public enum FSComparators {

+    WITH_ID,             // include the id in the comparator

+    WITHOUT_ID,          // no          id in the comparator

+    WITH_TYPE_ORDER,     // include the typeOrder in the comparator

+    WITHOUT_TYPE_ORDER   // no          typeOrder in the comparator

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/FSIndex.java b/uimaj-core/src/main/java/org/apache/uima/cas/FSIndex.java
index a42b502..87dab2d 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/FSIndex.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/FSIndex.java
@@ -19,6 +19,13 @@
 
 package org.apache.uima.cas;
 
+import java.util.Collection;
+import java.util.stream.Stream;
+
+import org.apache.uima.cas.impl.LowLevelIndex;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.jcas.cas.TOP;
+
 /**
  * Feature structure index access interface.
  * 
@@ -62,7 +69,7 @@
  * @param T the topmost type in this Index
  * 
  */
-public interface FSIndex<T extends FeatureStructure> extends Iterable<T> {
+public interface FSIndex<T extends FeatureStructure> extends Collection<T> {
 
   /**
    * Indexing strategy: sorted index. A sorted index contains all elements, including duplicates.
@@ -131,7 +138,7 @@
    * 
    * If there are multiple different FSs in the index which compare equal with the 
    * given feature structure, an arbitrary one is returned. This differs from the moveTo(fs)
-   * operation which guarantees to move to the first feature structure occuring in the index
+   * operation which guarantees to move to the first feature structure occurring in the index
    * in this case.
    * 
    * @param fs A Feature Structure used a template to match with the Feature Structures in the index.
@@ -206,13 +213,62 @@
    */
   FSIndex<T> withSnapshotIterators();
 
-  <N extends FeatureStructure> SelectFSs<N> select();
+  /**
+    * @return a newly created selection object for accessing feature structures
+   */
+ SelectFSs<T> select();
+
+  /**
+   * @param type specifies the type (and subtypes of that type) to access
+   * @param <N> the Type of the elements being accessed
+   * @return a newly created selection object for accessing feature structures of that type and its subtypes
+   */
+  <N extends T> SelectFSs<N> select(Type type);
   
-  <N extends FeatureStructure> SelectFSs<N> select(Type type);
+  /**
+   * @param clazz a JCas class corresponding to the type (and subtypes of that type) to access
+   * @param <N> the Type of the elements being accessed
+   * @return a newly created selection object for accessing feature structures of that type and its subtypes
+   */
+  <N extends T> SelectFSs<N> select(Class<N> clazz);
   
-  <N extends FeatureStructure> SelectFSs<N> select(Class<N> clazz);
+  /**
+   * @param jcasType the "type" field from the JCas class corresponding to the type (and subtypes of that type) to access
+   * @param <N> the Type of the elements being accessed
+   * @return a newly created selection object for accessing feature structures of that type and its subtypes
+   */
+  <N extends T> SelectFSs<N> select(int jcasType);
   
-  <N extends FeatureStructure> SelectFSs<N> select(int jcasType);
+  /**
+   * @param fullyQualifiedTypeName the string name of the type to access
+   * @param <N> the Type of the elements being accessed
+   * @return a newly created selection object for accessing feature structures of that type and its subtypes
+   */
+  <N extends T> SelectFSs<N> select(String fullyQualifiedTypeName);
   
-  <N extends FeatureStructure> SelectFSs<N> select(String fullyQualifiedTypeName);
+  /**
+   * @return a Stream over all the elements in the index (including subtypes)
+   */
+  default Stream<T> stream() {
+    return this.select();
+  }
+  
+  /**
+   * @param clazz - the subtype
+   * @param <U> the subtype
+   * @return an instance of this index specialized to a subtype
+   */
+  default <U extends T> FSIndex<U> subType(Class<? extends TOP> clazz) {
+    return ((LowLevelIndex<T>)this).getSubIndex(clazz);
+  }
+  
+  /**
+   * @param type - the subtype
+   * @param <U> the subtype
+   * @return an instance of this index specialized to a subtype
+   */
+  default <U extends T> FSIndex<U> subType(Type type) {
+    return ((LowLevelIndex<T>)this).getSubIndex(type);
+  }
+  
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/FSIndexRepository.java b/uimaj-core/src/main/java/org/apache/uima/cas/FSIndexRepository.java
index a6ebb0f..e4042f5 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/FSIndexRepository.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/FSIndexRepository.java
@@ -19,9 +19,12 @@
 
 package org.apache.uima.cas;
 
+import java.util.Collection;
 import java.util.Iterator;
 
+import org.apache.uima.cas.impl.FSIndexRepositoryImpl;
 import org.apache.uima.cas.impl.LowLevelIndex;
+import org.apache.uima.jcas.cas.TOP;
 
 /**
  * Repository of indexes over feature structures. Use this interface to access previously defined
@@ -107,7 +110,8 @@
    * Remove a feature structure from all indexes in the repository.
    * 
    * @param fs
-   *          The FS to be removed.
+   *          The FS to be removed.  The fs must be the exact FS to remove, not just one
+   *          which compares "equal" using the index's comparator.
    * @param <T> the generic type of the FeatureStructure
    * @exception NullPointerException
    *              If the <code>fs</code> parameter is <code>null</code>.
@@ -122,14 +126,34 @@
   void removeAllIncludingSubtypes(Type type);
   
   /**
+   * Remove all instances of type, including all subtypes from all indexes in the repository view.
+   * @param clazz the JCas class of the type to remove.  To remove all use TOP.class
+   * @param <T> the type to remove
+   * @exception NullPointerException if the <code>clazz</code> parameter is <code>null</code>.
+  */
+  default <T extends TOP> void removeAllIncludingSubtypes(Class<T> clazz) {
+    removeAllIncludingSubtypes(((FSIndexRepositoryImpl)this).getCasImpl().getJCasImpl().getCasType(clazz));
+  }
+  
+  /**
    * Remove all instances of just this type, excluding subtypes, from all indexes in the repository view.
    * @param type the type to remove
    * @exception NullPointerException if the <code>type</code> parameter is <code>null</code>.
   */
   void removeAllExcludingSubtypes(Type type);
-  
+
   /**
-   * Gets an iterator over all indexed FeatureStructures of the specified Type (and any of its
+   * Remove all instances of just this type, excluding subtypes, from all indexes in the repository view.
+   * @param clazz the JCas Class of the type to remove
+   * @param <T> the type to remove
+   * @exception NullPointerException if the <code>type</code> parameter is <code>null</code>.
+  */
+  default <T extends TOP> void removeAllExcludingSubtypes(Class<T> clazz) {
+    removeAllExcludingSubtypes(((FSIndexRepositoryImpl)this).getCasImpl().getJCasImpl().getCasType(clazz));
+  }
+
+  /**
+   * Gets an iterator over all indexed (in this View) FeatureStructures of the specified Type (and any of its
    * subtypes).  The elements are returned in arbitrary order.
    *
    * Generics: T is the Java class for aType.
@@ -141,4 +165,52 @@
    */
   <T extends FeatureStructure> FSIterator<T> getAllIndexedFS(Type aType);
   
+  /**
+   * Gets an FSIterator over all indexed (in this view) FeatureStructures of the specified Type (and any of its
+   * subtypes).  The elements are returned in arbitrary order.
+   *
+   * Generics: T is the Java class for aType.
+   * @param clazz
+   *          The JCas class corresponding to the type
+   * @param <T> The Java class associated with aType
+   * @return An iterator that returns all indexed FeatureStructures of the specified type
+   *         and its subtypes, in no particular order.
+   */
+  default <T extends FeatureStructure> FSIterator<T> getAllIndexedFS(Class<T> clazz) {
+    return getAllIndexedFS(((FSIndexRepositoryImpl)this).getCasImpl().getCasType((Class<TOP>) clazz));
+  }
+  
+  /**
+   * Returns an unmodifiable collection of all the FSs of this type and its subtypes, 
+   * that are indexed in this view, in an arbitrary order.  
+   * Subsequent modifications to the indexes do not affect this collection.
+   * @param type the type of Feature Structures to include (including subtypes)
+   * @param <T> The Java class associated with type
+   * @return an unmodifiable, unordered collection of all indexed (in this view) Feature Structures
+   *         of the specified type (including subtypes)
+   */
+  public <T extends TOP> Collection<T> getIndexedFSs(Type type);
+  
+  /**
+   * Returns an unmodifiable collection of all the FSs of this type and its subtypes, 
+   * that are indexed in this view, in an arbitrary order.  
+   * Subsequent modifications to the indexes do not affect this collection.
+   * @param clazz
+   *          The JCas class corresponding to the type
+   * @param <T> The Java class associated with type
+   * @return an unmodifiable, unordered collection of all indexed (in this view) Feature Structures
+   *         of the specified type (including subtypes)
+   */
+  public <T extends TOP> Collection<T> getIndexedFSs(Class<T> clazz);
+ 
+  /**
+   * Returns an unmodifiable collection of all of the FSs
+   * that are indexed in this view, in an arbitrary order.  
+   * Subsequent modifications to the indexes do not affect this collection.
+   * @param <T> The Java class associated with type
+   * @return an unmodifiable, unordered collection of all indexed (in this view) Feature Structures
+   *         of the specified type (including subtypes)
+   */
+  public <T extends TOP> Collection<T> getIndexedFSs();
+
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/FSIterator.java b/uimaj-core/src/main/java/org/apache/uima/cas/FSIterator.java
index dbb4308..8e66ae6 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/FSIterator.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/FSIterator.java
@@ -33,9 +33,11 @@
  * Iterator over feature structures.
  * 
  * <p>
- * This iterator interface extends {@link java.util.Iterator}, and supports the
- * standard <code>hasNext</code> and <code>next</code> methods. If finer control, including
- * reverse iteration, is needed, see below.
+ * This iterator interface extends {@link java.util.ListIterator} which, in turn,
+ * extends {@link java.util.Iterator}.  It supports all the methods of those APIs
+ * except nextIndex, previousIndex, set, and add.  remove meaning is changed to mean
+ * remove the item obtained by a get() from all the indexes in this view.
+ * If finer control, including reverse iteration, is needed, see below.
  * 
  * <p>Note: do not use the APIs described below *together* with the standard Java iterator methods
  * <code>next()</code> and <code>hasNext()</code>.  On any given iterator, use either the one or the
@@ -54,10 +56,9 @@
  * <code>next()</code> would return, but does not advance the iterator.
  * 
  * <p>
- * Implementations of this interface are not required to be fail-fast. That is, if the iterator's
- * collection is modified, the effects on the iterator are in general undefined. Some collections
- * may handle this more gracefully than others, but in general, concurrent modification of the
- * collection you're iterating over is a bad idea.
+ * If the iterator's underlying UIMA Indexes are modified, the iterator continues as if 
+ * it doesn't see these modifications.  Three operations cause the iterator to "see" any modifications:
+ * moveToFirst, moveToLast, and moveTo(featureStructure).
  * 
  * <p>
  * If the iterator is moved past the boundaries of the collection, the behavior of subsequent calls
@@ -68,8 +69,6 @@
  * the iterator back to the last element in the collection. Always use
  * {@link FSIterator#moveToLast() moveToLast()} in such cases.
  * 
- * 
- * 
  */
 public interface FSIterator<T extends FeatureStructure> extends ListIterator<T> {
 
@@ -87,79 +86,104 @@
    * @exception NoSuchElementException
    *              If the iterator is not valid.
    */
-  T get() throws NoSuchElementException;
+  default T get() throws NoSuchElementException {
+    if (!isValid()) {
+      throw new NoSuchElementException();
+    }
+    return getNvc();
+  }
 
   /**
    * Get the structure the iterator is pointing at.
    * Throws various unchecked exceptions, if the iterator is not valid
    * @return The structure the iterator is pointing at.
    */
-  default T getNvc() {
-    return get();
-  }
+  T getNvc();
   
   /**
    * Advance the iterator. This may invalidate the iterator.
-   * @exception ConcurrentModificationException if the underlying indexes being iterated over were modified
    */
-  void moveToNext();
+  default void moveToNext() {
+    if (!isValid()) {
+      return;
+    }
+    moveToNextNvc();
+  }
 
   /**
    * version of moveToNext which bypasses the isValid check - call only if you've just done this check yourself
    */
-  default void moveToNextNvc() {
-    moveToNext();
-  }
+  void moveToNextNvc();
   
   /**
    * Move the iterator one element back. This may invalidate the iterator.
    * @exception ConcurrentModificationException if the underlying indexes being iterated over were modified
    */
-  void moveToPrevious();
+  default void moveToPrevious() {
+    if (!isValid()) {
+      return;
+    }
+    moveToPreviousNvc();
+  }
 
   /**
    * version of moveToPrevious which bypasses the isValid check - call only if you've just done this check yourself
    */
-  default void moveToPreviousNvc() {
-    moveToPrevious();
-  }
+  void moveToPreviousNvc();
 
   /**
    * Move the iterator to the first element. The iterator will be valid iff the underlying
    * collection is non-empty.  Allowed even if the underlying indexes being iterated over were modified.
    */
   void moveToFirst();
-
+  
   /**
    * Move the iterator to the last element. The iterator will be valid iff the underlying collection
    * is non-empty.  Allowed even if the underlying indexes being iterated over were modified.
    */
   void moveToLast();
-
+  
   /**
-   * Move the iterator to the first Feature Structure that is equal to <code>fs</code>. 
-   * First means the earliest one occurring in the index, in case multiple FSs that are "equal" to fs
+   * Move the iterator to the first Feature Structure that matches the <code>fs</code>. 
+   * First means the earliest one occurring in the index, in case multiple FSs matching the fs
    * are in the index.  If no
-   * such feature structure exists in the underlying collection, set the iterator to the "insertion
-   * point" for <code>fs</code>, i.e., to a point where the current feature structure is greater
-   * than <code>fs</code>, and the previous one is less than <code>fs</code>.
+   * such feature structure exists in the underlying collection, and the iterator is over a sorted index,
+   * set the iterator to the "insertion point" for <code>fs</code>, i.e., 
+   * to a point where the current feature structure compares greater
+   * than <code>fs</code>, and the previous one compares less than <code>fs</code>, using this
+   * sorted index's comparator.
    * <p>
    * If the fs is greater than all of the entries in the index, the moveTo cannot set the iterator to an insertion point
    * where the current feature structure is greater than fs, so it marks the iterator "invalid".
+   * 
    * <p>
-   * If the underlying index is a bag index, no ordering is present, and the moveTo operation moves to the
-   * fs which is the same identical fs as the key. If no such fs is in the index, the iterator is marked 
-   * invalid.
+   * If the underlying index is a set or bag index, or an unordered form of iteration 
+   * is configured (for example using the <code>select</code> API, 
+   * no ordering is present, and the moveTo operation moves to a matching item,
+   * if one exists.  The match is done using the index's comparator.
+   * If none exist, the index is left if possible in some valid (but non-matching) position.
+   * 
+   * <p>When the iterator is over a sorted index whose keys include the typeOrder key, this can cause
+   * unexpected operation, depending on type priorities.  For example, consider the Annotation Index,
+   * which includes this key.  If there are many indexed instances of the type "Foo" with the same begin and end,
+   * and a moveTo operation is specified using an Annotation instance with the same begin and end,
+   * then the Foo elements might or might not be seen going forwards, depending on the relative type 
+   * priorities of "Foo" and "Annotation".
+   * 
+   * <p>If you are not making use of typeOrdering, the "select" APIs can create iterators which will
+   * ignore the typeOrdering key when doing the moveTo operation, which will result in all the instances
+   * of type "Foo" being seen going forwards, independent of the type priorities.  See the 
+   * select documentation in the version 3 users guide.
    * 
    * @param fs
    *          The feature structure the iterator that supplies the 
-   *          comparison information.  It can be a supertype of T as long as it can supply the keys needed.
+   *          comparison information.  It doesn't need to be in the index; it is just being
+   *          used as a comparison template.  It can be a supertype of T as long as it can supply the keys needed.
    *          A typical example is a subtype of Annotation, and using an annotation instance to specify 
    *          the begin / end.
-   * @exception ConcurrentModificationException if the underlying indexes being iterated over were modified
    */
    void  moveTo(FeatureStructure fs);
-
+   
   /**
    * Copy this iterator.
    * 
@@ -195,9 +219,10 @@
    */
   @Override
   default T next() {
-    T result = get();
-    moveToNext();
-    return result;
+    if (!isValid()) {
+      throw new NoSuchElementException();
+    }
+    return nextNvc();
   }
   
   default T nextNvc() {
@@ -205,16 +230,6 @@
     moveToNextNvc();
     return result;
   }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see java.util.Iterator#remove()
-   */
-  @Override
-  default void remove() {
-    throw new UnsupportedOperationException();
-  } 
   
   @Override
   default boolean hasPrevious() {
@@ -223,11 +238,17 @@
 
   @Override
   default T previous() {
-    T result = get();
-    moveToPrevious();
-    return result;
-
+    if (!isValid()) {
+      throw new NoSuchElementException();
+    }
+    return previousNvc();
   }
+  
+  default T previousNvc() {
+    moveToPreviousNvc();
+    return getNvc();
+  }
+
 
   @Override
   default int nextIndex() {
@@ -261,16 +282,31 @@
   default Spliterator<T> spliterator() {
     return Spliterators.spliterator(
         this, 
-        ((LowLevelIterator<T>)this).ll_indexSize(), 
+        ((LowLevelIterator<T>)this).ll_indexSizeMaybeNotCurrent(), 
 
         Spliterator.DISTINCT |
         Spliterator.SIZED    |
         Spliterator.SUBSIZED);
   }
   
+  /**
+   * @return a Stream consisting of the items being iterated over by this iterator, 
+   *           starting from the current position.
+   */
   default Stream<T> stream() {
     return StreamSupport.stream(spliterator(),  false);
   }
 
-  
+  /**
+   * Removes from all the indexes associated with this view, the 
+   * "current" Feature Structure (the one that would be returned by a 
+   * "get()" operation).  
+   *
+   * @throws NoSuchElementException if the iterator is invalid.
+   */
+  @Override
+  default void remove() {
+    ((LowLevelIterator<T>)this).ll_remove();
+  } 
+
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/FeatureStructure.java b/uimaj-core/src/main/java/org/apache/uima/cas/FeatureStructure.java
index 0007dde..3c0d19b 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/FeatureStructure.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/FeatureStructure.java
@@ -19,7 +19,7 @@
 
 package org.apache.uima.cas;
 
-import org.apache.uima.cas.impl.FeatureStructureImplC;
+import org.apache.uima.jcas.JCas;
 
 /**
  * Interface for feature structures.
@@ -295,13 +295,18 @@
   void setFeatureValueFromString(Feature feat, String s) throws CASRuntimeException;
 
   /**
-   * Return the CAS that this FS belongs to.
-   *
-   * @return The CAS.
+   * @return The CAS view where this Feature Structure was created
    */
   CAS getCAS();
 
   /**
+   * @return the JCas view where this Feature Structure was created
+   */
+  default JCas getJCas() {
+    return getCAS().getJCasImpl();  // getJCas defined (from v2) to throw exception, this one doesn't
+  };
+  
+  /**
    * return the unique (to this CAS) id of this feature structure
    * @return the id
    */
@@ -321,7 +326,7 @@
    * @return a FeatureStructure that is the cloned copy of this FeatureStructure.
    * @throws CASRuntimeException passthru
    */
-  FeatureStructureImplC clone() throws CASRuntimeException;
+  Object clone() throws CASRuntimeException;
   
   /**
    * Compatibility for v2 code.
@@ -332,5 +337,22 @@
    */
   int getAddress(); 
   
+  /**
+   * A feature structure is equal to another feature structure iff it is identical in the underlying
+   * representation.
+   * 
+   * @exception ClassCastException
+   *              If <code>o</code> is not a FS.
+   */
+  boolean equals(Object o) throws ClassCastException;
+
+  /**
+   * Will return a hash code that's consistent with equality, i.e., if two FSs are equal, they will
+   * also return the same hash code.
+   * 
+   * @return The hash code.
+   */
+  int hashCode();
+
 }
 
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/FloatArrayFS.java b/uimaj-core/src/main/java/org/apache/uima/cas/FloatArrayFS.java
index ef3c900..b67ecea 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/FloatArrayFS.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/FloatArrayFS.java
@@ -21,11 +21,12 @@
 
 /**
  * Interface for CAS float arrays. To create a float array object, use
- * {@link org.apache.uima.cas.CAS#createFloatArrayFS CAS.createFloatArrayFS()}.
+ * {@link org.apache.uima.cas.CAS#createFloatArrayFS CAS.createFloatArrayFS()}
+ * or new FloatArray(aJCas, length)
  * 
  * 
  */
-public interface FloatArrayFS extends CommonArrayFS {
+public interface FloatArrayFS extends CommonArrayFS<Float> {
 
   /**
    * Get the element at position <code>index</code>.
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/IntArrayFS.java b/uimaj-core/src/main/java/org/apache/uima/cas/IntArrayFS.java
index 6e53a8b..690d938 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/IntArrayFS.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/IntArrayFS.java
@@ -21,11 +21,10 @@
 
 /**
  * Interface for CAS int arrays. To create an int array object, use
- * {@link org.apache.uima.cas.CAS#createIntArrayFS CAS.createIntArrayFS()}.
- * 
- * 
+ * {@link org.apache.uima.cas.CAS#createIntArrayFS CAS.createIntArrayFS(int)} or
+ * new IntegerArray(aJCas, length)
  */
-public interface IntArrayFS extends CommonArrayFS {
+public interface IntArrayFS extends CommonArrayFS<Integer> {
 
   /**
    * Get the element at position <code>index</code>.
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/LongArrayFS.java b/uimaj-core/src/main/java/org/apache/uima/cas/LongArrayFS.java
index 44cf213..c8deba6 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/LongArrayFS.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/LongArrayFS.java
@@ -21,11 +21,10 @@
 
 /**
  * Long array interface. To create a long array object, use
- * {@link org.apache.uima.cas.CAS#createLongArrayFS CAS.createLongArrayFS()}.
- * 
- * 
+ * {@link org.apache.uima.cas.CAS#createLongArrayFS CAS.createLongArrayFS(int)}
+ * or new LongArray(aJCas, length)
  */
-public interface LongArrayFS extends CommonArrayFS {
+public interface LongArrayFS extends CommonArrayFS<Long> {
 
   /**
    * Get the i-th element from the array.
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/SelectFSs.java b/uimaj-core/src/main/java/org/apache/uima/cas/SelectFSs.java
index a6161b8..57838b2 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/SelectFSs.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/SelectFSs.java
@@ -26,75 +26,156 @@
 

 import org.apache.uima.cas.text.AnnotationFS;

 import org.apache.uima.jcas.cas.TOP;

+import org.apache.uima.jcas.tcas.Annotation;

 

 /**

  * Collection of builder style methods to specify selection of FSs from indexes

- * Comment codes:

- *   AI = implies AnnotationIndex

- *   Ordered = implies an ordered index not necessarily AnnotationIndex

- *   BI = bounded iterator (boundedBy or bounding)

+ * Documentation is in a chapter in the UIMA Version 3 User's Guide.

  */

 public interface SelectFSs<T extends FeatureStructure> extends Iterable<T>, Stream<T> {

   

-  // Stream and Iterable both define forEach, with Iterable supplying a default.

-  @Override

-  default void forEach(Consumer<? super T> action) {

-    Iterable.super.forEach(action);

-  }

-  

-  

-  

-//  // If not specified, defaults to all FSs (unordered) unless AnnotationIndex implied

-//    // Methods take their generic type from the variable to which they are assigned except for

-//    // index(class) which takes it from its argument.

-//  <N extends FeatureStructure> SelectFSs<N> index(String indexName);  

-//  <N extends FeatureStructure> SelectFSs<N> index(FSIndex<N> index);

-//

-//  // If not specified defaults to the index's uppermost type.

-//  // Methods take their generic type from the variable to which they are assigned except for

-//  // type(class) which takes it from its argument.

-//  <N extends FeatureStructure> SelectFSs<N> type(Type uimaType);

-//  <N extends FeatureStructure> SelectFSs<N> type(String fullyQualifiedTypeName);

-//  <N extends FeatureStructure> SelectFSs<N> type(int jcasClass_dot_type);

-//  <N extends FeatureStructure> SelectFSs<N> type(Class<N> jcasClass_dot_class);

-    

-//  SelectFSs<T> shift(int amount); // incorporated into startAt 

-  

-  // ---------------------------------

-  // boolean operations

-  // ---------------------------------

-

-//  SelectFSs<T> matchType();      // exact type match (no subtypes)

-//  SelectFSs<T> matchType(boolean matchType); // exact type match (no subtypes)

-  

-  // only for AnnotationIndex

+  /**

+   * Specify that type priority should be included when comparing two Feature Structures 

+   * when moving to the leftmost among otherwise equal items for moveTo(fs).

+   * <p>

+   * Default is to not include type priority.

+   * @return the updated SelectFSs object

+   */

   SelectFSs<T> typePriority();

+  

+  /**

+   * Specify that type priority should or should not be included when comparing two Feature Structures while positioning an iterator

+   * <p>

+   * Default is to not include type priority.

+   * @param typePriority if true says to include the type priority

+   * @return the updated SelectFSs object

+   */

   SelectFSs<T> typePriority(boolean typePriority);

 

-  SelectFSs<T> positionUsesType();           // ignored if not ordered index

-  SelectFSs<T> positionUsesType(boolean positionUsesType); // ignored if not ordered index

-  

   // Filters while iterating over Annotations

-  SelectFSs<T> nonOverlapping();  // AI known as unambiguous

-  SelectFSs<T> nonOverlapping(boolean nonOverlapping); // AI

   

-  SelectFSs<T> includeAnnotationsWithEndBeyondBounds();  // AI known as "strict"

-  SelectFSs<T> includeAnnotationsWithEndBeyondBounds(boolean endWithinBounds); // AI

+  /**

+   * Meaningful only for Annotation Indexes, specifies that iteration should return 

+   * only annotations which don't overlap with each other.  Also known as "unambiguous".

+   * <p>

+   * Default is to not have this filter.

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> nonOverlapping();  // requires Annotation Index, known as unambiguous

+  /**

+   * Meaningful only for Annotation Indexes, specifies that iteration should or should not return 

+   * only annotations which don't overlap with each other.  Also known as "unambiguous".

+   * <p>

+   * Default is to not have this filter.

+   * @param nonOverlapping true to specify filtering for only non-overlapping annotations.

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> nonOverlapping(boolean nonOverlapping); // requires Annotation Index

+  

+  /**

+   * Meaningful only for coveredBy, includes annotations where the end exceeds the bounding annotation's end.

+   * <p>

+   * Default is to NOT include annotations whose end exceeds the bounding annotation's end.

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> includeAnnotationsWithEndBeyondBounds();  // requires Annotation Index, known as "not strict"

+  /**

+   * Meaningful only for coveredBy, includes or filters out annotations where the end exceeds the bounding annotation's end.

+   * <p>

+   * Default is to NOT include annotations whose end exceeds the bounding annotation's end.

+   * @param includeAnnotationsWithEndBeyondBounds false to filter out annotations whose end exceeds the bounding annotation's end

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> includeAnnotationsWithEndBeyondBounds(boolean includeAnnotationsWithEndBeyondBounds); // requires Annotation Index

 

-  SelectFSs<T> useAnnotationEquals();                 

+  /**

+   * Meaningful only for coveredBy and covering: if true, then returned annotations are compared equal to 

+   * the bounding annotation, and if equal, they are skipped.

+   * <p>

+   * Default is to use feature structure identity comparison (same id()s), not equals, when 

+   * doing the test to see if an annotation should be skipped.

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> skipWhenSameBeginEndType();                 

+  /**

+   * Meaningful only for coveredBy: if true, then returned annotations are compared 

+   * to the bounding annotation

+   * using the specified kind of equal comparison,  

+   * and if equal, they are skipped.

+   * <p>

+   * Default is to use feature structure identity comparison (same id()s), not equals, when 

+   * doing the test to see if an annotation should be skipped.

+   * @param useAnnotationEquals if true, use equals, if false, use id() ==.

+   * @return the updated SelectFSs object

+   */

   SelectFSs<T> useAnnotationEquals(boolean useAnnotationEquals);

   

   // Miscellaneous

+  /**

+   * Extend the selection to be over all the CAS views, not just a single view.

+   * <p>

+   * Default is that the selection is just for one CAS view

+   * @return the updated SelectFSs object

+   */

   SelectFSs<T> allViews();

+  /**

+   * Extend or not extend the selection to be over all the CAS views, not just a single view.

+   * <p>

+   * Default is that the selection is just for one CAS view

+   * @param allViews true to extend the selection.

+   * @return the updated SelectFSs object

+   */

   SelectFSs<T> allViews(boolean allViews);

   

-  SelectFSs<T> nullOK();  // applies to get()

+  /**

+   * Applies to the various argument forms of the get method.

+   * Indicates that a null value should not throw an exception.

+   * <p>

+   * Default: null is not OK as a value 

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> nullOK();  

+  /**

+   * Applies to the various argument forms of the get method.

+   * Indicates that a null value should or should not throw an exception.

+   * <p>

+   * Default: null is not OK as a value 

+   * @param nullOk true if null is an ok value.

+   * @return the updated SelectFSs object

+   */

   SelectFSs<T> nullOK(boolean nullOk);  // applies to get()

     

+  /**

+   * Specifies that order is not required while iterating over an otherwise ordered index.

+   * This can be a performance boost for hierarchically nested types.

+   * <p>

+   * Default: order is required by default, when iterating over an ordered index. 

+   * @return the updated SelectFSs object

+   */

   SelectFSs<T> orderNotNeeded();                  // ignored if not ordered index

+  /**

+   * Specifies that order is or is not required while iterating over an otherwise ordered index.

+   * This can be a performance boost for hierarchically nested types.

+   * <p>

+   * Default: order is required by default, when iterating over an ordered index.

+   * @param unordered true means order is not needed. 

+   * @return the updated SelectFSs object

+   */

   SelectFSs<T> orderNotNeeded(boolean unordered); // ignored if not ordered index

   

+  /**

+   * Specifies that the iteration should run in reverse order from normal.

+   * Note that this does not compose; 

+   * two calls to this will still result in the iteration running in reverse order.

+   * @return the updated SelectFSs object

+   */

   SelectFSs<T> backwards();                  // ignored if not ordered index

+  /**

+   * Specifies that the iteration should run in the normal or reverse order.

+   * Note that this does not compose. 

+   * @param backwards true to run in reverse order

+   * @return the updated SelectFSs object

+   */

   SelectFSs<T> backwards(boolean backwards); // ignored if not ordered index

 

 //  SelectFSs<T> noSubtypes();

@@ -106,43 +187,155 @@
   // 

   // Variations, controlled by: 

   //   * typePriority

-  //   * positionUsesType

+  //   * useAnnotationEquals

+  //     * positionUsesType

   //   

   // The positional specs imply starting at the 

   //   - left-most (if multiple) FS at that position, or

   //   - if no FS at the position, the next higher FS

   //   - if !typePriority, equal test is only begin/end 

-  //     -- types ignored or not depending on positionUsesType 

   //    

   // shifts, if any, occur afterwards

   //   - can be positive or negative

   // ---------------------------------

+  /**

+   * Starting Position specification - Shifts the normal start position by the shiftAmount, which may be negative.

+   * Repeated calls to this just replaces the requested shift amount; a single shift only occurs when a 

+   * result is obtained.

+   * @param shiftAmount the amount to shift; this many Feature Structures which 

+   *                      normally would be returned are instead skipped.

+   * @return the updated SelectFSs object

+   */

   SelectFSs<T> shifted(int shiftAmount); 

   

-  SelectFSs<T> startAt(TOP fs);  // Ordered

-  SelectFSs<T> startAt(int begin, int end);   // AI

+  /**

+   * Starting Position specification - For ordered sources, specifies which FS to start at. 

+   * Requires an ordered index not necessarily AnnotationIndex, not necessarily sorted

+   * @param fs a Feature Structure specifying a starting position.

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> startAt(TOP fs);  // an ordered index not necessarily AnnotationIndex, not necessarily sorted

   

-  SelectFSs<T> startAt(TOP fs, int shift);        // Ordered

-  SelectFSs<T> startAt(int begin, int end, int shift);   // AI

+  /**

+   * Starting Position specification - For Annotation Indexes, specifies which FS to start at. 

+   * @param begin the begin bound

+   * @param end the end bound

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> startAt(int begin, int end);   // requires Annotation Index

+  

+  /**

+   * Starting Position specification - A combination of startAt followed by a shift

+   * 

+   * Requires an ordered index not necessarily AnnotationIndex, not necessarily sorted

+   * @param fs a Feature Structure specifying a starting position.

+   * @param shift the amount to shift; this many Feature Structures which 

+   *               normally would be returned are instead skipped.

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> startAt(TOP fs, int shift);        // an ordered index not necessarily AnnotationIndex, not necessarily sorted

+  

+  /**

+   * Starting Position specification - A combination of startAt followed by a shift

+   * Requires an Annotation Index.

+   * @param begin the begin bound

+   * @param end the end bound

+   * @param shift the amount to shift; this many Feature Structures which 

+   *               normally would be returned are instead skipped.

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> startAt(int begin, int end, int shift);   // requires Annotation Index

     

-  SelectFSs<T> limit(int n); 

+  /**

+   * Limits the number of Feature Structures returned by this select

+   * @param n the maximum number of feature structures returned.

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> limit(int n);

+  

   // ---------------------------------

   // subselection based on bounds

   //   - uses 

   //     -- typePriority, 

   //     -- positionUsesType, 

-  //     -- skipEquals

+  //     -- useAnnotationEquals

   // ---------------------------------

-  SelectFSs<T> at(AnnotationFS fs);  // AI

-  SelectFSs<T> at(int begin, int end);  // AI

+  /**

+   * Subselection - specifies selecting Feature Structures having the same begin and end

+   *   - influenced by typePriority, positionUsesType, and useAnnotationEquals

+   * Requires an Annotation Index.

+   * @param fs specifies the bounds.

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> at(AnnotationFS fs);  // requires Annotation Index

   

-  SelectFSs<T> coveredBy(AnnotationFS fs);       // AI

-  SelectFSs<T> coveredBy(int begin, int end);       // AI

+  /**

+   * Subselection - specifies selecting Feature Structures having the same begin and end

+   * Requires an Annotation Index.

+   *   - influenced by typePriority, positionUsesType, and useAnnotationEquals

+   * @param begin the begin bound

+   * @param end  the end bound

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> at(int begin, int end);  // requires Annotation Index

+

+  /**

+   * Subselection - specifies selecting Feature Structures 

+   *   starting (and maybe ending) within a bounding Feature Structure

+   *   - influenced by typePriority, positionUsesType, useAnnotationEquals,

+   *     includeAnnotationsWithEndBeyondBounds

+   * Requires an Annotation Index.

+   * @param fs specifies the bounds.

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> coveredBy(AnnotationFS fs);       // requires Annotation Index

   

-  SelectFSs<T> covering(AnnotationFS fs);      // AI

-  SelectFSs<T> covering(int begin, int end);      // AI

+  /**

+   * Subselection - specifies selecting Feature Structures 

+   *   starting (and maybe ending) within a bounding Feature Structure

+   * Requires an Annotation Index.

+   * @param begin the begin bound

+   * @param end  the end bound

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> coveredBy(int begin, int end);       // requires Annotation Index

   

-  SelectFSs<T> between(AnnotationFS fs1, AnnotationFS fs2);  // AI implies a coveredBy style

+  /**

+   * Subselection - specifies selecting Feature Structures 

+   *   starting before or equal to bounding Feature Structure

+   *   and ending at or beyond the bounding Feature Structure

+   *   - influenced by typePriority, positionUsesType, useAnnotationEquals

+   * Requires an Annotation Index.

+   * @param fs specifies the bounds.

+   * @return the updated SelectFSs object

+   */  

+  SelectFSs<T> covering(AnnotationFS fs);      // requires Annotation Index

+  

+  /**

+   * Subselection - specifies selecting Feature Structures 

+   *   starting before or equal to bounding Feature Structure's begin

+   *   and ending at or beyond the bounding Feature Structure's end

+   * Requires an Annotation Index.

+   * @param begin the begin bound

+   * @param end  the end bound

+   * @return the updated SelectFSs object

+   */  

+  SelectFSs<T> covering(int begin, int end);      // requires Annotation Index

+  

+  /**

+   * Subselection - specifies selecting Feature Structures 

+   *   which lie between two annotations.

+   *   A bounding Annotation is constructed whose begin

+   *   is the end of fs1, and whose end is the begin of fs2.

+   * Requires an Annotation Index.

+   * <p> 

+   * If fs1 &gt; fs2, they are swapped, and the selected values are returned in reverse order.

+   * 

+   * @param fs1 the beginning bound

+   * @param fs2 the ending bound

+   * @return the updated SelectFSs object

+   */  

+  SelectFSs<T> between(AnnotationFS fs1, AnnotationFS fs2);  // requires Annotation Index, implies a coveredBy style

  

   /* ---------------------------------

   * Semantics: 

@@ -155,47 +348,311 @@
   *   - for preceding, return in forward order (unless backward is specified)

   *   - for preceding, skips FSs whose end >= begin (adjusted by offset)

   * ---------------------------------*/

-  SelectFSs<T> following(TOP fs);

-  SelectFSs<T> following(int begin, int end);

-  SelectFSs<T> following(TOP fs, int offset);

-  SelectFSs<T> following(int begin, int end, int offset);

+  /**

+   * For AnnotationIndex, position to first Annotation 

+   * whose begin &gt; fs.getEnd();

+   * @param annotation the Annotation to follow

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> following(Annotation annotation);

+  /**

+   * For AnnotationIndex, position to first Annotation whose begin &gt; fs.getEnd();

+   * @param position start following this position

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> following(int position);

+  /**

+   * For AnnotationIndex, position to first Annotation whose begin &gt; fs.getEnd()

+   *   and then adjust position by the offset

+   * @param annotation start following this Annotation, adjusted for the offset

+   * @param offset positive or negative shift amount to adjust starting position 

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> following(Annotation annotation, int offset);

+  /**

+   * For AnnotationIndex, position to first Annotation whose begin &gt; position

+   *   and then adjust position by the offset.

+   * @param position start following this position, adjusted for the offset

+   * @param offset positive or negative shift amount to adjust starting position 

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> following(int position, int offset);

 

-  SelectFSs<T> preceding(TOP fs);

-  SelectFSs<T> preceding(int begin, int end);

-  SelectFSs<T> preceding(TOP fs, int offset);

-  SelectFSs<T> preceding(int begin, int end, int offset);

+  /**

+   * For AnnotationIndex, set up a selection that will proceed backwards, 

+   * starting at the first Annotation whose end &lt;= fs.getBegin().

+   * Annotations whose end &gt; fs.getBegin() are skipped.

+   * @param annotation the Annotation to use as the position to start before.

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> preceding(Annotation annotation);

+  /**

+   * For AnnotationIndex, set up a selection that will proceed backwards, 

+   * starting at the first Annotation whose end &lt;= position.

+   * Annotations whose end &gt; position are skipped.

+   * @param position the position to start before.

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> preceding(int position);

+  /**

+   * For AnnotationIndex, set up a selection that will proceed backwards, 

+   * starting at the first Annotation whose end &lt;= fs.getBegin(),

+   * after adjusting by offset items.

+   * Annotations whose end &gt; fs.getBegin() are skipped (including during the offset positioning)

+   * @param annotation the Annotation to use as the position to start before.

+   * @param offset the offset adjustment, positive or negative.  Positive moves backwards.

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> preceding(Annotation annotation, int offset);

+  /**

+   * For AnnotationIndex, set up a selection that will proceed backwards, 

+   * starting at the first Annotation whose end &lt;= position.

+   * after adjusting by offset items.

+   * Annotations whose end &gt; fs.getBegin() are skipped (including during the offset positioning)

+   * @param position the position to start before.

+   * @param offset the offset adjustment, positive or negative.  Positive moves backwards.

+   * @return the updated SelectFSs object

+   */

+  SelectFSs<T> preceding(int position, int offset);

   // ---------------------------------

   // terminal operations

   // returning other than SelectFSs

   // 

   // ---------------------------------

+  /**

+   * @return an FSIterator over the selection.  The iterator is set up depending on 

+   *         preceding configuration calls to this SelectFSs instance.

+   */

   FSIterator<T> fsIterator();

 //  Iterator<T> iterator();  // inherited, not needed here

+  /**

+   * @param <N> the generic type argument of the elements of the list

+   * @return a List object whose elements represent the selection.

+   */

   <N extends T> List<N> asList();

+  /**

+   * @param clazz the class of the type of the elements

+   * @param <N> the generic type argument of the elements of the array

+   * @return a Array object representation of the elements of the selection.

+   */

   <N extends T> N[] asArray(Class<N> clazz);

 //  Spliterator<T> spliterator(); // inherited, not needed here 

   

   // returning one item

   

+  /**

+   * Get the first element or null if empty or the element at the first position is null. 

+   * if nullOK is false, then throws CASRuntimeException if null would have been returned. 

+   * @return first element or null if empty

+   * @throws CASRuntimeException conditioned on nullOK == false, and null being returned or the selection is empty.

+   */

   T get();          // returns first element or null if empty (unless nullOK(false) specified)

+  /**

+   * @return first element, which must be not null

+   * @throws CASRuntimeException if element is null or 

+   *          if there is more than 1 element in the selection,

+   *          or if the selection is empty

+   */

   T single();       // throws if not exactly 1 element, throws if null

+  /**

+   * @return first element, which may be null, or null if selection is empty.

+   * @throws CASRuntimeException if there is more than 1 element in the selection.

+   */

   T singleOrNull(); // throws if more than 1 element, returns single or null

    // next are positioning alternatives

    // get(...) throws if null (unless nullOK specified)

+  /**

+   * Get the offset element or null if empty or the offset went outside the

+   *    the selected elements.

+   * <p> 

+   * If nullOK is false, then throws CASRuntimeException if null would have been returned, or 

+   *   the selection is empty, or doesn't have enough elements to satisfy the positioning. 

+   * @param offset the offset adjustment, positive or negative.

+   * @return the selected element or null

+   * @throws CASRuntimeException conditioned on nullOK == false, and null being returned 

+   *                   or the selection is empty,

+   *                   or the offset positioning going outside the elements in the selection.

+   */

   T get(int offset);          // returns first element or null if empty after positioning

+  /**

+   * Get the offset element or null if empty or the offset went outside the

+   *    the selected elements.

+   * <p>

+   * If, after positioning, there is another element next to the one being returned 

+   *   (in the forward direction if offset is positive, reverse direction if offset is negative)

+   *   then throw an exception.

+   * <p>

+   * If nullOK is false, then throws CASRuntimeException if null would have been returned, or 

+   *   the selection is empty, or doesn't have enough elements to satisfy the positioning. 

+   * @param offset the offset adjustment, positive or negative.

+   * @return the selected element or null

+   * @throws CASRuntimeException if, after positioning, there is another element next to the one being returned 

+   *   (in the forward direction if offset is positive, reverse direction if offset is negative)

+   *   or (conditioned on nullOK == false) null being returned 

+   *                   or the selection is empty,

+   *                   or the offset positioning going outside the elements in the selection.

+   */

   T single(int offset);       // throws if not exactly 1 element

+  /**

+   * Get the offset element or null if empty or the offset went outside the

+   *    the selected elements.

+   * <p>

+   * If, after positioning, there is another element next to the one being returned 

+   *   (in the forward direction if offset is positive, reverse direction if offset is negative)

+   *   then throw an exception.

+   * <p>

+   * @param offset the offset adjustment, positive or negative.

+   * @return the selected element or null

+   * @throws CASRuntimeException if, after positioning, there is another element next to the one being returned 

+   *   (in the forward direction if offset is positive, reverse direction if offset is negative)

+   */

   T singleOrNull(int offset); // throws if more than 1 element, returns single or null  

+  /**

+   * Positions to the fs using moveTo(fs).

+   * Get the element at that position or null if empty or the element at that position is null. 

+   * if nullOK is false, then throws CASRuntimeException if null would have been returned. 

+   * @param fs the positioning Feature Structure 

+   * @return first element or null if empty

+   * @throws CASRuntimeException (conditioned on nullOK == false) null being returned or the selection is empty.

+   */

   T get(TOP fs);          // returns first element or null if empty after positioning

+  /**

+   * Positions to the fs using moveTo(fs).

+   * Get the element at that position or null if empty or the element at that position is null. 

+   * if nullOK is false, then throws CASRuntimeException if null would have been returned. 

+   * @param fs the positioning Feature Structure 

+   * @return first element or null if empty

+   * @throws CASRuntimeException if, after positioning, there is another element following the one being returned 

+   *     or (conditioned on nullOK == false) and null being returned or the selection is empty.

+   */

   T single(TOP fs);       // throws if not exactly 1 element

+  /**

+   * Positions to the fs using moveTo(fs).

+   * Get the element at that position or null if empty or the element at that position is null. 

+   * @param fs the positioning Feature Structure 

+   * @return first element or null if empty

+   * @throws CASRuntimeException if, after positioning, there is another element following the one being returned 

+   */

   T singleOrNull(TOP fs); // throws if more than 1 element, returns single or null

+  /**

+   * Positions to the fs using moveTo(fs), followed by a shifted(offset).

+   * Gets the element at that position or null if empty or the element at that position is null. 

+   * if nullOK is false, then throws CASRuntimeException if null would have been returned. 

+   * @param fs where to move to

+   * @param offset the offset move after positioning to fs, may be 0 or positive or negative

+   * @return the selected element or null if empty

+   * @throws CASRuntimeException (conditioned on nullOK == false) null being returned or the selection is empty.

+   */

   T get(TOP fs, int offset);          // returns first element or null if empty

+  /**

+   * Positions to the fs using moveTo(fs), followed by a shifted(offset).

+   * Gets the element at that position or null if empty or the element at that position is null.

+   * <p>

+   * If, after positioning, there is another element next to the one being returned 

+   *   (in the forward direction if offset is positive or 0, reverse direction if offset is negative)

+   *   then throw an exception.

+   * <p>

+   * If nullOK is false, then throws CASRuntimeException if null would have been returned.

+   * @param fs the positioning Feature Structure 

+   * @param offset the offset adjustment, positive or negative.

+   * @return the selected element or null if empty

+   * @throws CASRuntimeException if, after positioning, there is another element following the one being returned

+   *     or (conditioned on nullOK == false) null being returned or the selection is empty.

+   */

   T single(TOP fs, int offset);       // throws if not exactly 1 element

+  /**

+   * Positions to the fs using moveTo(fs), followed by a shifted(offset).

+   * Gets the element at that position or null if empty or the element at that position is null.

+   * <p>

+   * If, after positioning, there is another element next to the one being returned 

+   *   (in the forward direction if offset is positive or 0, reverse direction if offset is negative)

+   *   then throw an exception.

+   * <p>

+   * @param fs the positioning Feature Structure 

+   * @param offset the offset adjustment, positive or negative.

+   * @return the selected element or null if empty

+   * @throws CASRuntimeException if, after positioning, there is another element next to the one being returned 

+   */

   T singleOrNull(TOP fs, int offset); // throws if more than 1 element, returns single or null

+  /**

+   * Position using a temporary Annotation with its begin and end set to the arguments.

+   * Gets the element at that position or null if empty or the element at that position is null.

+   * if nullOK is false, then throws CASRuntimeException if null would have been returned. 

+   * @param begin the begin position of the temporary Annotation

+   * @param end the end position of the temporary Annotation 

+   * @return the selected element or null if empty

+   * @throws CASRuntimeException conditioned on nullOK == false, and null being returned or the selection is empty.

+   */

   T get(int begin, int end);          // returns first element or null if empty

+  /**

+   * Position using a temporary Annotation with its begin and end set to the arguments.

+   * Gets the element at that position or null if empty or the element at that position is null.

+   * <p>

+   * If, after positioning, there is another element following the one being returned 

+   *   then throw an exception.

+   * <p>

+   * if nullOK is false, then throws CASRuntimeException if null would have been returned. 

+   * @param begin the begin position of the temporary Annotation

+   * @param end the end position of the temporary Annotation 

+   * @return the selected element or null if empty

+   * @throws CASRuntimeException if, after positioning, there is another element following the one being returned

+   *             or (conditioned on nullOK == false) null being returned or the selection is empty.

+   */

   T single(int begin, int end);       // throws if not exactly 1 element

+  /**

+   * Position using a temporary Annotation with its begin and end set to the arguments.

+   * Gets the element at that position or null if empty or the element at that position is null.

+   * <p>

+   * If, after positioning, there is another element following the one being returned 

+   *   then throw an exception.

+   * @param begin the begin position of the temporary Annotation

+   * @param end the end position of the temporary Annotation 

+   * @return the selected element or null if empty

+   * @throws CASRuntimeException if, after positioning, there is another element following the one being returned

+   */

   T singleOrNull(int begin, int end); // throws if more than 1 element, returns single or null

+  /**

+   * Position using a temporary Annotation with its begin and end set to the arguments,

+   * followed by shifted(offset).

+   * Gets the element at that position or null if empty or the element at that position is null.

+   * <p>

+   * @param begin the begin position of the temporary Annotation

+   * @param end the end position of the temporary Annotation

+   * @param offset the amount (positive or negative or 0) passed as an argument to shifted(int) 

+   * @return the selected element or null if empty

+   * @throws CASRuntimeException (conditioned on nullOK == false) if null being returned or the selection is empty.

+   */

   T get(int begin, int end, int offset);          // returns first element or null if empty

+  /**

+   * Position using a temporary Annotation with its begin and end set to the arguments,

+   * followed by shifted(offset).

+   * Gets the element at that position or null if empty or the element at that position is null.

+   * <p>

+   * If, after positioning, there is another element next to the one being returned 

+   *   (in the forward direction if offset is positive or 0, reverse direction if offset is negative)

+   *   then throw an exception.

+   * @param begin the begin position of the temporary Annotation

+   * @param end the end position of the temporary Annotation

+   * @param offset the amount (positive or negative or 0) passed as an argument to shifted(int) 

+   * @return the selected element or null if empty

+   * @throws CASRuntimeException if, after positioning, there is another element next to the one being returned

+   *        or (conditioned on nullOK == false) if null being returned or the selection is empty.

+   */

   T single(int begin, int end, int offset);       // throws if not exactly 1 element

+  /**

+   * Position using a temporary Annotation with its begin and end set to the arguments,

+   * followed by shifted(offset).

+   * Gets the element at that position or null if empty or the element at that position is null.

+   * <p>

+   * If, after positioning, there is another element next to the one being returned 

+   *   (in the forward direction if offset is positive or 0, reverse direction if offset is negative)

+   *   then throw an exception.

+   * @param begin the begin position of the temporary Annotation

+   * @param end the end position of the temporary Annotation

+   * @param offset the amount (positive or negative or 0) passed as an argument to shifted(int) 

+   * @return the selected element or null if empty

+   * @throws CASRuntimeException if, after positioning, there is another element next to the one being returned

+   */

   T singleOrNull(int begin, int end, int offset); // throws if more than 1 element, returns single or null

   

   

@@ -208,16 +665,26 @@
 

 

   /**

-   * static methods that more effectively capture the generic argument  

-   * @param index -

+   * Use this static method to capture the generic argument  

+   * @param index - the index to select over as a source

    * @param <U> generic type of index

-   * @param <V> generic type of returned select

-   * @return -

+   * @return - a SelectFSs instance

    */

-  static <U extends FeatureStructure, V extends U> SelectFSs<V> select(FSIndex<U> index) {

+  

+  static <U extends FeatureStructure> SelectFSs<U> select(FSIndex<U> index) {

     return index.select();    

   } 

   

+  /**

+   * This method is required, because the 2 interfaces inherited both define this

+   * and this is needed to disambiguate

+   * Otherwise, get a compile error (but not on Eclipse...)

+   */

+  @Override

+  default void forEach(Consumer<? super T> action) {

+    Iterable.super.forEach(action);

+  }

+

 //  /**

 //   * DON'T USE THIS, use index.select(XXX.class) instead

 //   * @param index the index to use

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/ShortArrayFS.java b/uimaj-core/src/main/java/org/apache/uima/cas/ShortArrayFS.java
index f0c1036..c68fa97 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/ShortArrayFS.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/ShortArrayFS.java
@@ -21,11 +21,10 @@
 
 /**
  * Short array interface. To create a short array object, use
- * {@link org.apache.uima.cas.CAS#createShortArrayFS CAS.createShortArrayFS()}.
- * 
- * 
+ * {@link org.apache.uima.cas.CAS#createShortArrayFS CAS.createShortArrayFS(int)} or
+ * new ShortArray(aJCas, length)
  */
-public interface ShortArrayFS extends CommonArrayFS {
+public interface ShortArrayFS extends CommonArrayFS<Short> {
 
   /**
    * Get the i-th element from the array.
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/StringArrayFS.java b/uimaj-core/src/main/java/org/apache/uima/cas/StringArrayFS.java
index 5bd62d0..1c38c72 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/StringArrayFS.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/StringArrayFS.java
@@ -21,11 +21,10 @@
 
 /**
  * String array interface. To create a string array object, use
- * {@link org.apache.uima.cas.CAS#createStringArrayFS CAS.createStringArrayFS()}.
- * 
- * 
+ * {@link org.apache.uima.cas.CAS#createStringArrayFS CAS.createStringArrayFS(int)}
+ * or new StringArray(aJCas, length)
  */
-public interface StringArrayFS extends CommonArrayFS {
+public interface StringArrayFS extends CommonArrayFS<String> {
 
   /**
    * Get the i-th string from the array.
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/Type.java b/uimaj-core/src/main/java/org/apache/uima/cas/Type.java
index d83a529..a61e05d 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/Type.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/Type.java
@@ -22,6 +22,8 @@
 import java.util.List;
 import java.util.Vector;
 
+import org.apache.uima.cas.impl.TypeImpl;
+
 /**
  * The interface describing types in the type system.
  * 
@@ -39,9 +41,10 @@
  * A type name is then a non-empty sequence of identifiers separated by periods. See also <a
  * href="./Feature.html#names">Feature names</a>.
  * 
- * 
+ * <p>
+ * Implements Iterable over all the features defined for this type.
  */
-public interface Type {
+public interface Type extends Iterable<Feature> {
 
   /**
    * Get the <a href="#names">fully qualified name</a> of the type.
@@ -143,4 +146,11 @@
    */
   Type getComponentType();
 
+  /**
+   * @param subtype - a UIMA Type
+   * @return true if this type subsumes (is equal or a supertype of) the subtype argument
+   */
+  default boolean subsumes(Type subtype) {
+    return ((TypeImpl)this).subsumes((TypeImpl) subtype);
+  }
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/TypeSystem.java b/uimaj-core/src/main/java/org/apache/uima/cas/TypeSystem.java
index 31db5af..5c40574 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/TypeSystem.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/TypeSystem.java
@@ -22,6 +22,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Vector;
+
 import org.apache.uima.cas.impl.LowLevelTypeSystem;
 
 /**
@@ -42,8 +43,10 @@
  * feature is appropriate for which type is available through the {@link Type Type} and
  * {@link Feature Feature} classes.
  * 
+ * Implements Iterable to allow iterating over all types
+ * 
  */
-public interface TypeSystem {
+public interface TypeSystem extends Iterable<Type> {
 
   /**
    * This is the character that separates a type name from a feature name. Ex.:
@@ -80,7 +83,7 @@
    *          The type of the elements of the resulting array type. This can be any type, even
    *          another array type.
    * @return The array type with the corresponding component type.
-   *         If it doesn't exist, a new TypeImplArray is created for it.
+   *         If it doesn't exist, a new TypeImpl_array is created for it.
    */
   Type getArrayType(Type componentType);
 
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/admin/CASAdminException.java b/uimaj-core/src/main/java/org/apache/uima/cas/admin/CASAdminException.java
index e1c968d..ef0f153 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/admin/CASAdminException.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/admin/CASAdminException.java
@@ -105,8 +105,7 @@
   private String resourceBundleName = DEFAULT_RESOURCE_BUNDLE_NAME;
     
   public CASAdminException(String aResourceBundleName, Throwable aCause, String aMessageKey, Object ... aArguments) {
-    super(aCause, aMessageKey, aArguments);
-    resourceBundleName = aResourceBundleName;
+    super(aCause, aResourceBundleName, aMessageKey, aArguments);
   }
 
   public CASAdminException(String aMessageKey, Object ... aArguments) {
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/admin/FSIndexComparator.java b/uimaj-core/src/main/java/org/apache/uima/cas/admin/FSIndexComparator.java
index 02fbe09..dcadb29 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/admin/FSIndexComparator.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/admin/FSIndexComparator.java
@@ -73,6 +73,12 @@
    */
   int addKey(Feature feat, int compareKey);
 
+  /**
+   * 
+   * @param typeOrder the type order
+   * @param compareKey the direction
+   * @return the number of the key
+   */
   int addKey(LinearTypeOrder typeOrder, int compareKey);
 
   /**
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/admin/LinearTypeOrder.java b/uimaj-core/src/main/java/org/apache/uima/cas/admin/LinearTypeOrder.java
index 0b9daf7..2714286 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/admin/LinearTypeOrder.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/admin/LinearTypeOrder.java
@@ -59,5 +59,10 @@
    * @return The type order as array of type codes in ascending order.
    */
   int[] getOrder();
+  
+  /**
+   * @return true if there is no type order defined for this pipeline
+   */
+  boolean isEmptyTypeOrder();
 
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/admin/TypeSystemMgr.java b/uimaj-core/src/main/java/org/apache/uima/cas/admin/TypeSystemMgr.java
index e5e3f4b..7018c46 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/admin/TypeSystemMgr.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/admin/TypeSystemMgr.java
@@ -117,15 +117,40 @@
           boolean multipleReferencesAllowed) throws CASAdminException;
 
   /**
-   * Commit the type system. The type system will be locked and no longer writable. WARNING: Users
+   * Commit the type system, and load JCas Classes from the UIMA Framework's classloader. 
+   * The type system will be locked and no longer writable. 
+   * 
+   * WARNING: Users
    * should not call this, but instead call ((CASImpl) theAssociatedCAS).commitTypeSystem() in order
    * to set up the parts of the CAS that should be set up when the type system is committed.
    * 
+   * WARNING: This API will use the UIMA Framework's class loader to find a load JCas classes.
+   * If you have JCas classes under some other class loader you wish to use (perhaps you are 
+   * setting a ResourceManager's extension classpath, which creates a class loader), use the
+   * commit which takes a class loader as an argument, and pass in the class loader where the
+   * JCas classes are.  
+   * 
    * @return the committed type system.  Note that this may be the same object as "this" or a 
    *         different (but equal) object.  Type systems are cached and recreating the exact same type system
    *         repeatedly will return the original one.
    */
   TypeSystem commit();
+  
+  /**
+   * Commit the type system, and load JCas classes from the passed in classloader. 
+   * The type system will be locked and no longer writable. 
+   * 
+   * WARNING: Users
+   * should not call this, but instead call ((CASImpl) theAssociatedCAS).commitTypeSystem() in order
+   * to set up the parts of the CAS that should be set up when the type system is committed.
+   * 
+   * @param cl the JCas class loader
+   *  
+   * @return the committed type system.  Note that this may be the same object as "this" or a 
+   *         different (but equal) object.  Type systems are cached and recreating the exact same type system
+   *         repeatedly will return the original one.
+   */
+  TypeSystem commit(ClassLoader cl);
 
   /**
    * Check if this instance has been committed.
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/AllFSs.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/AllFSs.java
index bd6d41a..023bfa9 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/AllFSs.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/AllFSs.java
@@ -20,9 +20,9 @@
 package org.apache.uima.cas.impl;

 

 import java.util.ArrayList;

+import java.util.Collection;

 import java.util.Collections;

 import java.util.function.Predicate;

-import java.util.stream.Stream;

 

 import org.apache.uima.UimaSerializableFSs;

 import org.apache.uima.cas.CommonArrayFS;

@@ -30,11 +30,12 @@
 import org.apache.uima.internal.util.PositiveIntSet_impl;

 import org.apache.uima.jcas.cas.FSArray;

 import org.apache.uima.jcas.cas.TOP;

+import org.apache.uima.util.IteratorNvc;

 

 /**

  * support for collecting all FSs in a CAS

  *   -  over all views

- *   -  both indexed, and reachable

+ *   -  both indexed, and (optionally) reachable

  */

 class AllFSs {

   

@@ -52,10 +53,8 @@
     foundFSsBelowMark = (mark != null) ? new PositiveIntSet_impl(1024, 1, 1024) : null;

     this.includeFilter = includeFilter;

     this.typeMapper = typeMapper;

-    

-    getAllIndexedFSsAllViews();

   }

-  

+    

   PositiveIntSet getAllBelowMark() {

     return foundFSsBelowMark;

   }

@@ -82,32 +81,42 @@
     this.mark = null;

     foundFSsBelowMark = null;

     this.includeFilter = null;

-    this.typeMapper = null;

-    getAllIndexedFSsAllViews();    

+    this.typeMapper = null; 

   }

-  

-  void getAllIndexedFSsAllViews() {

+

+  private AllFSs getAllFSsAllViews_sofas() {

     cas.forAllSofas(sofa -> enqueueFS(sofa));

-    cas.forAllViews(view -> 

-       getFSsForView(view.indexRepository.<TOP>getAllIndexedFS(cas.getTypeSystemImpl().topType).stream()));

+    cas.forAllViews(view -> getFSsForView(view.indexRepository.getIndexedFSs()));

+    return this;

+  }

+

+  

+  public AllFSs getAllFSsAllViews_sofas_reachable() {

+    getAllFSsAllViews_sofas();

+    

     for (int i = 0; i < toBeScanned.size(); i++) {

       enqueueFeatures(toBeScanned.get(i));

     }

     

-//    // add FSs that are in the CAS and held-on-to explicitly

-     // maybe needed for a test case - SerDesTest4 for delta CAS with previous v2 data ?

-//    Int2ObjHashMap<TOP> allKeptFSs = cas.getId2FSs();

-//    if (null != allKeptFSs && allKeptFSs.size() > 0) {

-//      Iterator<TOP> it = allKeptFSs.values();

-//      while (it.hasNext()) {

-//        enqueueFS(it.next());

-//      }

-//    }

-

+    // https://issues.apache.org/jira/browse/UIMA-5662  include kept fss if mode is set

+    if (cas.isId2Fs()) {

+      // add FSs that are in the CAS and held-on-to explicitly

+      Id2FS table = cas.getId2FSs();

+      if (null != table) {

+        IteratorNvc<TOP> it = cas.getId2FSs().iterator();

+        while (it.hasNext()) {

+          enqueueFS(it.nextNvc());

+        }

+      }

+      

+    }

+    return this;

   }

   

-  private void getFSsForView(Stream<TOP> fss) {

-    fss.forEach(fs -> enqueueFS(fs));

+  private void getFSsForView(Collection<TOP> fss) {

+    for (TOP fs : fss) {

+      enqueueFS(fs);

+    }

   }

   

   private void enqueueFS(TOP fs) {

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/AnnotationImplException.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/AnnotationImplException.java
index ef69fb6..a492779 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/AnnotationImplException.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/AnnotationImplException.java
@@ -100,6 +100,7 @@
   /**
    * @return The message of the exception. Useful for including the text in another exception.
    */
+  @Override
   public String getMessage() {
     if (this.resource == null) {
       try {
@@ -116,6 +117,7 @@
   }
 
   /** @return The same as getMessage(), but prefixed with <code>"AnnotationImplException: "</code>. */
+  @Override
   public String toString() {
     return this.getClass().getSimpleName() + ": " + this.getMessage();
   }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/BinaryCasSerDes.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/BinaryCasSerDes.java
index b650ce2..cb3bf00 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/BinaryCasSerDes.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/BinaryCasSerDes.java
@@ -46,7 +46,6 @@
 import org.apache.uima.internal.util.Misc;

 import org.apache.uima.internal.util.Obj2IntIdentityHashMap;

 import org.apache.uima.internal.util.function.Consumer_T_int_withIOException;

-import org.apache.uima.internal.util.function.DeserBinaryIndexes;

 import org.apache.uima.jcas.cas.BooleanArray;

 import org.apache.uima.jcas.cas.ByteArray;

 import org.apache.uima.jcas.cas.DoubleArray;

@@ -172,7 +171,7 @@
 //   * For delta, the addr is the modeled addr for the full CAS including both above and below the line.

 //   * 

 //   */

-//  final Int2ObjHashMap<TOP> addr2fs;  

+//  final Int2ObjHashMap<TOP, TOP> addr2fs;  

     

 //  /**

 //   * a map from a fs array of boolean/byte/short/long/double to its addr in the modeled aux heap

@@ -192,17 +191,15 @@
    * updated when delta deserializing.

    * reset at end of delta deserializings because multiple mods not supported

    */

-  final private Int2ObjHashMap<TOP> byteAuxAddr2fsa = new Int2ObjHashMap<>(TOP.class);  

-  final private Int2ObjHashMap<TOP> shortAuxAddr2fsa = new Int2ObjHashMap<>(TOP.class);  

-  final private Int2ObjHashMap<TOP> longAuxAddr2fsa = new Int2ObjHashMap<>(TOP.class);      

+  final private Int2ObjHashMap<TOP, TOP> byteAuxAddr2fsa = new Int2ObjHashMap<>(TOP.class);  

+  final private Int2ObjHashMap<TOP, TOP> shortAuxAddr2fsa = new Int2ObjHashMap<>(TOP.class);  

+  final private Int2ObjHashMap<TOP, TOP> longAuxAddr2fsa = new Int2ObjHashMap<>(TOP.class);   

   

   /**

-   * If true, adjust type codes in serialized forms

-   * to allow v2 type codes to be correctly read by v3 impls,

-   * because v3 impls have a greater number of built-in types 

+   *  used to calculate total heap size

    */

   boolean isBeforeV3 = false;  

-

+  

   public BinaryCasSerDes(CASImpl baseCAS) {

     this.baseCas = baseCAS;

   }

@@ -225,6 +222,8 @@
   /**

    * This is for deserializing (never delta) from a serialized java object representation or maybe from the JNI bridge

    * 

+   * both callers do a cas reset of some kind

+   * 

    * @param heapMetadata -

    * @param heapArray -

    * @param stringTable -

@@ -285,7 +284,7 @@
   

       // freshen the initial view

       initialView.refreshView(baseCas, null);

-      baseCas.setViewForSofaNbr(1, initialView);

+      baseCas.svd.setViewForSofaNbr(1, initialView);

       baseCas.svd.viewCount = 1;

     }

     return baseCas;

@@ -298,7 +297,17 @@
    */

   public void reinit(CASCompleteSerializer casCompSer) {

     TypeSystemImpl ts = casCompSer.getCASMgrSerializer().getTypeSystem();

-    baseCas.svd.clear();   

+    

+    /*

+     * Special clearing:

+     *   Skips the resetNoQuestions operation of flushing the indexes, 

+     *   since these will be reinitialized with potentially new definitions.

+     *   

+     *   Clears additional data related to having the

+     *   - type system potentially change

+     *   - the features belonging to indexes change

+     */

+    baseCas.svd.clear();  // does all clearing except index repositories which will be wiped out   

     baseCas.installTypeSystemInAllViews(ts);  // the commit (next) re-installs it if it changes

     baseCas.commitTypeSystem();

 

@@ -311,7 +320,7 @@
 

     // freshen the initial view

     initialView.refreshView(baseCas, null);  // sets jcas to null for the view, too

-    baseCas.setViewForSofaNbr(1, initialView);

+    baseCas.svd.setViewForSofaNbr(1, initialView);

     baseCas.svd.viewCount = 1;

 

     // deserialize heap

@@ -390,7 +399,7 @@
      * and then maybe remove the new one (and remember which views to re-add to).

      * @param heapAddr

      */

-    private void maybeAddBackAndRemoveFs(int heapAddr, Int2ObjHashMap<TOP> addr2fs) {

+    private void maybeAddBackAndRemoveFs(int heapAddr, Int2ObjHashMap<TOP, TOP> addr2fs) {

       if (fsStartAddr == -1) {

         fssIndex = -1;

         addrOfFsToBeAddedBack = -1;

@@ -415,7 +424,7 @@
      * @param heapAddr - the heap addr

      * @param bds -

      */

-    private void findCorrespondingFs(int heapAddr, Int2ObjHashMap<TOP> addr2fs) {

+    private void findCorrespondingFs(int heapAddr, Int2ObjHashMap<TOP, TOP> addr2fs) {

       if (fsStartAddr < heapAddr && heapAddr < fsEndAddr) {

         return;

       }

@@ -516,7 +525,7 @@
                              TypeSystemImpl ts) throws CASRuntimeException {

   

     final DataInputStream dis = CommonSerDes.maybeWrapToDataInputStream(istream);

-

+    

     if (!h.isV3) {

       if (h.getSeqVersionNbr() < 2) {

         isBeforeV3 = true; // adjusts binary type numbers 

@@ -556,14 +565,15 @@
           System.out.format("BinDeser version = %d%n", Integer.valueOf(h.v));

         }

         if (h.form4) {

-          (new BinaryCasSerDes4(baseCas.getTypeSystemImpl(), false))

-            .deserialize(baseCas, dis, delta, h);

+          BinaryCasSerDes4 bcsd4 = new BinaryCasSerDes4(baseCas.getTypeSystemImpl(), false);

+          bcsd4.deserialize(baseCas, dis, delta, h);

           return h.typeSystemIndexDefIncluded ? SerialFormat.COMPRESSED_TSI : SerialFormat.COMPRESSED;

         } else {

+          // is form 6

           CASMgrSerializer cms = (embeddedCasMgrSerializer != null) ? embeddedCasMgrSerializer : casMgrSerializer; 

           TypeSystemImpl tsRead = (cms != null) ? cms.getTypeSystem() : null;

           if (null != tsRead) {

-            tsRead = tsRead.commit();  // no generators set up

+            tsRead = tsRead.commit(baseCas.getJCasClassLoader()); // https://issues.apache.org/jira/browse/UIMA-5598

           }

             

           TypeSystemImpl ts_for_decoding =

@@ -903,7 +913,7 @@
         IntListIterator it = csds.addr2fs.keyIterator();

         int iaa = 0;

         while (it.hasNext()) {

-          bds.fssAddrArray[iaa++] = it.next();

+          bds.fssAddrArray[iaa++] = it.nextNvc();

         }

         // iaa at this point refs the last entry in the table

         bds.fssAddrArray[iaa] = heap.getCellsUsed();

@@ -985,7 +995,7 @@
    * @return heapsz (used by caller to do word alignment)

    * @throws IOException 

    */

-  int updateAuxArrayMods(Reading r, Int2ObjHashMap<TOP> auxAddr2fsa, 

+  int updateAuxArrayMods(Reading r, Int2ObjHashMap<TOP, TOP> auxAddr2fsa, 

       Consumer_T_int_withIOException<TOP> setter) throws IOException {

     final int heapsz = r.readInt();

     if (heapsz > 0) {

@@ -1014,57 +1024,57 @@
     return heapsz;

   }

 

-  /**

-   * gets number of views, number of sofas,

-   * For all sofas, 

-   *   adds them to the index repo in the base index

-   *   registers the sofa

-   * insures initial view created

-   * for all views:

-   *   does the view action and updates the documentannotation

-   * @param fsIndex the index info except for the actual list of FSs to reindex

-   * @param fss the lists of FSs to reindex (concatenated add/remove, or just adds if not delta)

-   * @param viewAction

-   */

-  void reinitIndexedFSs_common(int[] fsIndex, List<TOP> fss, DeserBinaryIndexes viewAction) {

-    // Add FSs to index repository for base CAS

-    int numViews = fsIndex[0];

-    int loopLen = fsIndex[1]; // number of sofas, not necessarily the same as

-    // number of views

-    // because the initial view may not have a sofa

-    for (int i = 0; i < loopLen; i++) { // iterate over all the sofas,

-      baseCas.indexRepository.addFS(fss.get(i)); // add to base index

-    }

-    

-

-    baseCas.forAllSofas(sofa -> {

-      String id = sofa.getSofaID();

-      if (CAS.NAME_DEFAULT_SOFA.equals(id)) { // _InitialView

-        baseCas.registerInitialSofa();

-        baseCas.addSofaViewName(id);

-      }

-      // next line the getView as a side effect

-      // checks for dupl sofa name, and if not,

-      // adds the name to the sofaNameSet

-      ((CASImpl) baseCas.getView(sofa)).registerView(sofa);

-    });

-    

-    baseCas.getInitialView();  // done for side effect of creating the initial view if not present

-    // must be done before the next line, because it sets the

-    // viewCount to 1.

-    baseCas.setViewCount(numViews); // total number of views

-    

-    int fsIndexIdx = 2;

-    for (int viewNbr = 1; viewNbr <= numViews; viewNbr++) {

-      CASImpl view = (viewNbr == 1) ? (CASImpl) baseCas.getInitialView() : (CASImpl) baseCas.getView(viewNbr);

-      if (view != null) {

-        fsIndexIdx += (1 + viewAction.apply(fsIndexIdx, view));

-        view.updateDocumentAnnotation();   // noop if sofa local data string == null

-      } else {

-        fsIndexIdx += 1;

-      }

-    }

-  }

+//  /**

+//   * gets number of views, number of sofas,

+//   * For all sofas, 

+//   *   adds them to the index repo in the base index

+//   *   registers the sofa

+//   * insures initial view created

+//   * for all views:

+//   *   does the view action and updates the documentannotation

+//   * @param fsIndex the index info except for the actual list of FSs to reindex

+//   * @param fss the lists of FSs to reindex (concatenated add/remove, or just adds if not delta)

+//   * @param viewAction

+//   */

+//  void reinitIndexedFSs_common(int[] fsIndex, List<TOP> fss, DeserBinaryIndexes viewAction) {

+//    // Add FSs to index repository for base CAS

+//    int numViews = fsIndex[0];

+//    int loopLen = fsIndex[1]; // number of sofas, not necessarily the same as

+//    // number of views

+//    // because the initial view may not have a sofa

+//    for (int i = 0; i < loopLen; i++) { // iterate over all the sofas,

+//      baseCas.indexRepository.addFS(fss.get(i)); // add to base index

+//    }

+//    

+//

+//    baseCas.forAllSofas(sofa -> {

+//      String id = sofa.getSofaID();

+//      if (CAS.NAME_DEFAULT_SOFA.equals(id)) { // _InitialView

+//        baseCas.registerInitialSofa();

+//        baseCas.addSofaViewName(id);

+//      }

+//      // next line the getView as a side effect

+//      // checks for dupl sofa name, and if not,

+//      // adds the name to the sofaNameSet

+//      ((CASImpl) baseCas.getView(sofa)).registerView(sofa);

+//    });

+//    

+//    baseCas.getInitialView();  // done for side effect of creating the initial view if not present

+//    // must be done before the next line, because it sets the

+//    // viewCount to 1.

+//    baseCas.setViewCount(numViews); // total number of views

+//    

+//    int fsIndexIdx = 2;

+//    for (int viewNbr = 1; viewNbr <= numViews; viewNbr++) {

+//      CASImpl view = (viewNbr == 1) ? (CASImpl) baseCas.getInitialView() : (CASImpl) baseCas.getView(viewNbr);

+//      if (view != null) {

+//        fsIndexIdx += (1 + viewAction.apply(fsIndexIdx, view));

+//        view.updateDocumentAnnotation();   // noop if sofa local data string == null

+//      } else {

+//        fsIndexIdx += 1;

+//      }

+//    }

+//  }

   

   

   /**

@@ -1084,15 +1094,27 @@
    * @param fsIndex - array of fsRefs and counts, for sofas, and all views

    * @param isDeltaMods - true for calls which are for delta mods - these have adds/removes

    */

-  void reinitIndexedFSs(int[] fsIndex, boolean isDeltaMods, IntFunction<TOP> getFsFromAddr) {

-    int numViews = fsIndex[0];

+  void reinitIndexedFSs(int[] fsIndex, boolean isDeltaMods, IntFunction<TOP> getFsFromAddr) {   

+    int idx = reinitIndexedFSsSofas(fsIndex, isDeltaMods, getFsFromAddr);

+    reinitIndexedFSs(fsIndex, isDeltaMods, getFsFromAddr, fsIndex[0], idx);

+  }

+  

+  void reinitIndexedFSs(int[] fsIndex, boolean isDeltaMods, IntFunction<TOP> getFsFromAddr, IntFunction<TOP> getSofaFromAddr) {

+    int idx = reinitIndexedFSsSofas(fsIndex, isDeltaMods, getSofaFromAddr);

+    reinitIndexedFSs(fsIndex, isDeltaMods, getFsFromAddr, fsIndex[0], idx);

+  }

+  

+  int reinitIndexedFSsSofas(int[] fsIndex, boolean isDeltaMods, IntFunction<TOP> getFsFromAddr ) {

     int numSofas = fsIndex[1]; // number of sofas, not necessarily the same as number of views (initial view may not have a sofa)

     int idx = 2;

     int end1 = 2 + numSofas;

     for (; idx < end1; idx++) { // iterate over all the sofas,

       baseCas.indexRepository.addFS(getFsFromAddr.apply(fsIndex[idx])); // add to base index

     }

- 

+    return idx;

+  }

+  

+  void reinitIndexedFSs(int[] fsIndex, boolean isDeltaMods, IntFunction<TOP> getFsFromAddr, int numViews, int idx) {    

     baseCas.forAllSofas(sofa -> {

       String id = sofa.getSofaID();

       if (CAS.NAME_DEFAULT_SOFA.equals(id)) { // _InitialView

@@ -1216,7 +1238,7 @@
   // etc.

   int[] getIndexedFSs(Obj2IntIdentityHashMap<TOP> fs2addr) {

     IntVector v = new IntVector();

-    List<TOP> fss;

+    Collection<TOP> fss;

 

     int numViews = baseCas.getViewCount();

     v.add(numViews);

@@ -1228,7 +1250,7 @@
 

     // Get indexes for each view in the CAS

     baseCas.forAllViews(view -> 

-        addIdsToIntVector(view.indexRepository.getIndexedFSs(), v, fs2addr));

+        addIdsToIntVector(view.getIndexedFSs(), v, fs2addr));

     return v.toArray();

   }

 

@@ -1574,7 +1596,7 @@
    */

   private void createFSsFromHeaps(boolean isDelta, int startPos, CommonSerDesSequential csds) {

     final int heapsz = heap.getCellsUsed();

-    final Int2ObjHashMap<TOP> addr2fs = csds.addr2fs;

+    final Int2ObjHashMap<TOP, TOP> addr2fs = csds.addr2fs;

     tsi = baseCas.getTypeSystemImpl();

     TOP fs;

     TypeImpl type;

@@ -1763,7 +1785,7 @@
       FeatureImpl feat, 

       List<Runnable> fixups4forwardFsRefs, 

       Consumer<TOP> setter,

-      Int2ObjHashMap<TOP> addr2fs) {

+      Int2ObjHashMap<TOP, TOP> addr2fs) {

     int a = heapFeat(heapIndex, feat);

     if (a == 0) {

       return;

@@ -1785,7 +1807,7 @@
     return heap.heap[nextFsAddr + 1 + feat.getOffset()];

   }

   

-  private Sofa getSofaFromAnnotBase(int annotBaseAddr, StringHeap stringHeap2, Int2ObjHashMap<TOP> addr2fs,

+  private Sofa getSofaFromAnnotBase(int annotBaseAddr, StringHeap stringHeap2, Int2ObjHashMap<TOP, TOP> addr2fs,

                                     CommonSerDesSequential csds) {

     int sofaAddr = heapFeat(annotBaseAddr, tsi.annotBaseSofaFeat);

     if (0 == sofaAddr) {

@@ -1830,7 +1852,7 @@
    * @param slotAddr - the main heap slot addr being updated

    * @param slotValue - the new value

    */

-  private void updateHeapSlot(BinDeserSupport bds, int slotAddr, int slotValue, Int2ObjHashMap<TOP> addr2fs) {

+  private void updateHeapSlot(BinDeserSupport bds, int slotAddr, int slotValue, Int2ObjHashMap<TOP, TOP> addr2fs) {

     TOP fs = bds.fs;

     TypeImpl type = fs._getTypeImpl();

     if (type.isArray()) {

@@ -1902,9 +1924,10 @@
       if (feat == tsi.sofaString) {

         if (fixups4forwardFsRefs != null) {

           // has to be deferred because it updates docAnnot which might not be deser yet.

+          //   TODO no longer needed, calls the version which doesn't update docAnnot 9/2017

           Sofa capturedSofa = sofa;

           String capturedString = s;

-          fixups4forwardFsRefs.add(() -> capturedSofa.setLocalSofaData(capturedString));

+          fixups4forwardFsRefs.add(() -> capturedSofa.setLocalSofaDataNoDocAnnotUpdate(capturedString));

         } else {

           sofa.setLocalSofaData(s);

         }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/BinaryCasSerDes4.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/BinaryCasSerDes4.java
index 4229fa3..80c9964 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/BinaryCasSerDes4.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/BinaryCasSerDes4.java
@@ -69,7 +69,6 @@
 import org.apache.uima.jcas.cas.Sofa;
 import org.apache.uima.jcas.cas.StringArray;
 import org.apache.uima.jcas.cas.TOP;
-import org.apache.uima.resource.ResourceInitializationException;
 import org.apache.uima.util.CasIOUtils;
 import org.apache.uima.util.impl.DataIO;
 import org.apache.uima.util.impl.OptimizeStrings;
@@ -120,7 +119,8 @@
  *   create appropriate unzip data input streams for these
  *   
  * Properties of Form 4:
- *   1) (Change from V2) Indexes are used to determine what gets serialized, because there's no "heap" to walk.
+ *   1) (Change from V2) Indexes are used to determine what gets serialized, because there's no "heap" to walk,
+ *      unless the v2-id-mode is in effect.
  *      
  *   2) The number used for references to FSs is a sequentially incrementing one, starting at 1
  *       This allows better compression.
@@ -205,77 +205,7 @@
       this.strat = strat;
     }
   }
-  
-//  /**
-//   * Define all the slot kinds.
-//   */
-//  public enum SlotKind {
-//    Slot_ArrayLength(! IS_DIFF_ENCODE, ! CAN_BE_NEGATIVE, 4, IN_MAIN_HEAP),
-//    Slot_HeapRef(    IS_DIFF_ENCODE,             IGNORED, 4, IN_MAIN_HEAP),
-//    Slot_Int(        IS_DIFF_ENCODE,             IGNORED, 4, IN_MAIN_HEAP),
-//    Slot_Byte(       ! IS_DIFF_ENCODE, ! CAN_BE_NEGATIVE, 4, IN_MAIN_HEAP),
-//    Slot_Short(      IS_DIFF_ENCODE,             IGNORED, 4, IN_MAIN_HEAP),
-//    Slot_TypeCode(   ! IS_DIFF_ENCODE, ! CAN_BE_NEGATIVE, 4, IN_MAIN_HEAP),
-//
-//    Slot_StrOffset(  ! IS_DIFF_ENCODE, ! CAN_BE_NEGATIVE, 4, !IN_MAIN_HEAP),
-//    Slot_StrLength(  ! IS_DIFF_ENCODE, ! CAN_BE_NEGATIVE, 4, !IN_MAIN_HEAP),
-//    Slot_Long_High(    IS_DIFF_ENCODE,           IGNORED, 0, !IN_MAIN_HEAP),
-//    Slot_Long_Low (    IS_DIFF_ENCODE,           IGNORED, 0, !IN_MAIN_HEAP),
-//
-//    // the next are not actual slot kinds, but instead
-//    // are codes used to control encoding of Floats and Doubles.
-//    Slot_Float_Mantissa_Sign( ! IS_DIFF_ENCODE, CAN_BE_NEGATIVE, 0, !IN_MAIN_HEAP),
-//    // exponent is 8 bits, and shifted in the expectation
-//    // that many values may be between 1 and 0 (e.g., normalized values)
-//    //   -- so sign moving is needed
-//    Slot_Float_Exponent(      ! IS_DIFF_ENCODE, CAN_BE_NEGATIVE, 0, !IN_MAIN_HEAP),
-//    
-//    Slot_Double_Mantissa_Sign(! IS_DIFF_ENCODE, CAN_BE_NEGATIVE, 0, !IN_MAIN_HEAP),
-//    Slot_Double_Exponent(     ! IS_DIFF_ENCODE, CAN_BE_NEGATIVE, 0, !IN_MAIN_HEAP),
-//    Slot_FsIndexes(             IS_DIFF_ENCODE,         IGNORED, 4, !IN_MAIN_HEAP),
-//    
-//    Slot_StrChars(            IGNORED,          IGNORED, 2, !IN_MAIN_HEAP),
-//    
-//    Slot_Control(             IGNORED,          IGNORED, 0, !IN_MAIN_HEAP),
-//    Slot_StrSeg(              ! IS_DIFF_ENCODE, ! CAN_BE_NEGATIVE, 0, ! IN_MAIN_HEAP),
-//    
-//    // the next slots are not serialized
-//    Slot_StrRef(     IS_DIFF_ENCODE,             IGNORED, 4, IN_MAIN_HEAP),
-//    Slot_BooleanRef( ! IS_DIFF_ENCODE, ! CAN_BE_NEGATIVE, 4, IN_MAIN_HEAP),
-//    Slot_ByteRef(    IS_DIFF_ENCODE,             IGNORED, 4, IN_MAIN_HEAP),
-//    Slot_ShortRef(   IS_DIFF_ENCODE,             IGNORED, 4, IN_MAIN_HEAP),
-//    Slot_LongRef(    IS_DIFF_ENCODE,             IGNORED, 4, IN_MAIN_HEAP),
-//    Slot_DoubleRef(  IS_DIFF_ENCODE,             IGNORED, 4, IN_MAIN_HEAP),
-//    Slot_Float(      ! IS_DIFF_ENCODE, ! CAN_BE_NEGATIVE, 4, IN_MAIN_HEAP),
-//    Slot_Boolean(    ! IS_DIFF_ENCODE, ! CAN_BE_NEGATIVE, 4, IN_MAIN_HEAP),
-//    // next used to capture original heap size
-//    Slot_MainHeap(   IGNORED,          IGNORED,           4, !IN_MAIN_HEAP),
-//
-//  //TODO fix this 
-//    Slot_JavaObjectRef(  IGNORED,      CAN_BE_NEGATIVE,   4, IN_MAIN_HEAP);
-//    ;
-//
-//    public final int i;
-//    public final boolean isDiffEncode;
-//    public final boolean canBeNegative;
-//    public final boolean inMainHeap;
-//    public final int elementSize;
-//    
-//    public static final int NBR_SLOT_KIND_ZIP_STREAMS;
-//    static {NBR_SLOT_KIND_ZIP_STREAMS = Slot_StrRef.i;}
-//    
-//    SlotKind(boolean isDiffEncode, 
-//             boolean canBeNegative, 
-//             int elementSize,
-//             boolean inMainHeap) {
-//      this.i = this.ordinal();
-//      this.isDiffEncode = isDiffEncode;
-//      this.canBeNegative = isDiffEncode ? true : canBeNegative;
-//      this.elementSize = elementSize; 
-//      this.inMainHeap = inMainHeap;
-//    }
-//  }
-  
+    
   /**
    * Things set up for one instance of this class, and
    * reuse-able
@@ -284,32 +214,11 @@
   final private boolean doMeasurements;
   
   final TypeImpl fsArrayType;
-
   
   /** 
    * Things shared between serialization and deserialization
    */
-    
-  // speedups
-//  final private static int arrayLength_i = Slot_ArrayLength.i;
-//  final private static int heapRef_i = Slot_HeapRef.i;
-//  final private static int int_i = Slot_Int.i;
-//  final private static int byte_i = Slot_Byte.ordinal();
-//  final private static int short_i = Slot_Short.i;
-//  final private static int typeCode_i = Slot_TypeCode.i;
-//  final private static int strOffset_i = Slot_StrOffset.i;
-//  final private static int strLength_i = Slot_StrLength.i;
-//  final private static int long_High_i = Slot_Long_High.i;
-//  final private static int long_Low_i = Slot_Long_Low.i;
-//  final private static int float_Mantissa_Sign_i = Slot_Float_Mantissa_Sign.i;
-//  final private static int float_Exponent_i = Slot_Float_Exponent.i;
-//  final private static int double_Mantissa_Sign_i = Slot_Double_Mantissa_Sign.i;
-//  final private static int double_Exponent_i = Slot_Double_Exponent.i;
-//  final private static int fsIndexes_i = Slot_FsIndexes.i;
-//  final private static int strChars_i = Slot_StrChars.i;
-//  final private static int control_i = Slot_Control.i;
-//  final private static int strSeg_i = Slot_StrSeg.i;
-  
+      
   /**
    * 
    * @param ts the type system
@@ -371,7 +280,7 @@
     Deserializer deserializer = new Deserializer(cas, in, isDelta);    
     deserializer.deserialize(h);
   }
-
+  
   /**
    * Class instantiated once per serialization
    * Multiple serializations in parallel supported, with
@@ -454,7 +363,7 @@
      * Contrast with fs2addr and addr2fs in csds - these use the pseudo v2 addresses as the int
      */    
     private final Obj2IntIdentityHashMap<TOP> fs2seq = new Obj2IntIdentityHashMap<TOP>(TOP.class, TOP._singleton);
-//    private final Int2ObjHashMap<TOP> seq2fs = new Int2ObjHashMap<>(TOP.class);
+//    private final Int2ObjHashMap<TOP, TOP> seq2fs = new Int2ObjHashMap<>(TOP.class);
     /**
      * 
      * @param cas -
@@ -568,7 +477,7 @@
        *   addr2fs - address to feature structure
        *   sortedFSs - sorted by addr (sorted by id)
        *******************************************************************************/
-      final int origHeapEnd = (null == csds) ? 0 : csds.getHeapEnd();
+      final int origHeapEnd = csds.getHeapEnd();  // csds guaranteed non-null by constructor
       if (isDelta) {
         csds.setup(mark, origHeapEnd);  // add additional above the line items to csds
       } // otherwise was initialized when initially set up 
@@ -580,6 +489,7 @@
       fs2seq.clear();
 //      seq2fs.clear();
       int seq = 1;  // origin 1
+      
       final List<TOP> localSortedFSs = csds.getSortedFSs();
       for (TOP fs : localSortedFSs) {
         fs2seq.put(fs, seq++);
@@ -589,6 +499,7 @@
         }
       }
       
+      // the sort order is on the id (e.g. creation order)
       List<TOP> newSortedFSs = CASImpl.filterAboveMark(csds.getSortedFSs(), mark);  // returns all if mark not set            
             
       /**************************
@@ -776,7 +687,7 @@
       int fi = 2;
       final int end1 = nbrSofas + 2;
       for (; fi < end1; fi++) {
-        writeVnumber(control_i, fsIndexes[fi]);
+        writeVnumber(control_i, fsIndexes[fi]);  // not converted to sequential
         
         if (doMeasurement) {
           sm.statDetails[fsIndexes_i].incr(DataIO.lengthVnumber(fsIndexes[fi]));
@@ -1456,7 +1367,7 @@
           
           IntListIterator it = fsChange.arrayUpdates.iterator();
           while (it.hasNext()) {
-            int i = it.next();
+            int i = it.nextNvc();
             // write the offset of the of the modified entry
             //   from the beginning of the fs addr
             //   i is already the 0 based offset, make it a 2 based one
@@ -1503,7 +1414,7 @@
         
         IntListIterator it = fsChange.arrayUpdates.iterator();
         while (it.hasNext()) {
-          int i = it.next();
+          int i = it.nextNvc();
                     
           writeVnumber(fsIndexes_dos, i - iPrevOffset);
           iPrevOffset = i;
@@ -1547,9 +1458,9 @@
 //      return (s == 0) ? null : seq2fs.get(s);
 //    }
   
-    private int fs2addr(TOP fs) {
-      return (fs == null) ? 0 : csds.fs2addr.get(fs);
-    }
+//    private int fs2addr(TOP fs) {
+//      return (fs == null) ? 0 : csds.fs2addr.get(fs);
+//    }
     
   }  // end of class definition for Serializer
   
@@ -1573,9 +1484,10 @@
     private TOP currentFs;
 
     /** 
-     * the deferrals needed when deserializing a subtype of AnnotationBase before the sofa is known
-     * Also for Sofa creation where some fields are final
-     * */
+    * Deferred actions to set Feature Slots of feature structures.
+    * the deferrals needed when deserializing a subtype of AnnotationBase before the sofa is known
+    * Also for Sofa creation where some fields are final
+    */
     final private List<Runnable> singleFsDefer = new ArrayList<>(); 
     
     /** used for deferred creation */
@@ -1587,7 +1499,9 @@
     private int heapStart;
     private int heapEnd;
     
-    /** the "fixups" for relative heap refs */
+    /** the "fixups" for relative heap refs
+     *  actions set slot values 
+     */
     final private List<Runnable> fixupsNeeded = new ArrayList<>();
     final private List<Runnable> uimaSerializableFixups = new ArrayList<>();
     
@@ -1661,7 +1575,7 @@
      * Note: This may be identity map, but may not in the case for V3 where some FSs are GC'd
      */    
 //    private final Obj2IntIdentityHashMap<TOP> fs2seq = new Obj2IntIdentityHashMap<TOP>(TOP.class, TOP.singleton);
-    private final Int2ObjHashMap<TOP> seq2fs = new Int2ObjHashMap<>(TOP.class);
+    private final Int2ObjHashMap<TOP, TOP> seq2fs = new Int2ObjHashMap<>(TOP.class);
 
     /**
      * Called after header was read and determined that
@@ -1777,6 +1691,10 @@
 
       /*******************************
        * walk main heap - deserialize
+       *   FS Creation:
+       *     - creatCurrentFs -> createFs
+       *     - createSofa
+       *     - createArray
        *******************************/
       TypeImpl type;
       int arraySize = 0;
@@ -1784,97 +1702,96 @@
       
       if (TRACE_DES) System.out.println("Form4Deser heapStart: " + heapStart + "  heapEnd: " + heapEnd);
       for (int iHeap = heapStart; iHeap < heapEnd; iHeap += type.getFsSpaceReq(arraySize)) {
-        final int typeCode = readVnumber(typeCode_dis);
-//        final int adjTypeCode = typeCode + ((this.bcsd.isBeforeV3 && typeCode > TypeSystemConstants.lastBuiltinV2TypeCode) 
-//            ? TypeSystemConstants.numberOfNewBuiltInsSinceV2
-//            : 0);
-         type = ts.getTypeForCode(typeCode);
-        
-        prevFs = prevFsByType[typeCode]; // could be null;
-        prevFsRefs = getPrevFsRef(type); // null or int[], only for things having fsrefs (array or not)
-        
-        if (type.isArray()) {
-          currentFs = readArray(iHeap, type);
-          arraySize = ((CommonArrayFS)currentFs).size();
-        } else {
-          if (!ts.annotBaseType.subsumes(type) &&  // defer subtypes of AnnotationBase
-              !(ts.sofaType == type)) {            // defer sofa types
-            currentFs = ivCas.createFS(type);
-            if (currentFs instanceof UimaSerializable) {
-              UimaSerializable ufs = (UimaSerializable) currentFs;
-              uimaSerializableFixups.add(() -> ufs._init_from_cas_data());
-            }
-              
-          } else {
-            currentFs = null;
-            singleFsDefer.clear();
-            sofaRef = null;
-            sofaNum = -1;
-            sofaName = null;
-          }
-          for (FeatureImpl feat : type.getFeatureImpls()) {
-            readByKind(feat, type);
-          }
-//          for (int i = 1; i < typeInfo.slotKinds.length + 1; i++) {
-//            readByKind(iHeap, i);
-//          }
-        }
-        
-        if (currentFs == null) {
+          final int typeCode = readVnumber(typeCode_dis);
+  //        final int adjTypeCode = typeCode + ((this.bcsd.isBeforeV3 && typeCode > TypeSystemConstants.lastBuiltinV2TypeCode) 
+  //            ? TypeSystemConstants.numberOfNewBuiltInsSinceV2
+  //            : 0);
+           type = ts.getTypeForCode(typeCode);
           
-          /**
-           * Create single deferred FS
-           *   Either: Sofa (has final fields) or
-           *           Subtype of AnnotationBase - needs to be in the right view
-           *   
-           *   For the latter, handle document annotation specially
-           */
-
-          if (ts.sofaType == type) {
-            currentFs = baseCas.createSofa(sofaNum, sofaName, null);  
+          prevFs = prevFsByType[typeCode]; // could be null;
+          prevFsRefs = getPrevFsRef(type); // null or int[], only for things having fsrefs (array or not)
+          
+          if (type.isArray()) {
+            currentFs = readArray(iHeap, type);
+            arraySize = ((CommonArrayFS)currentFs).size();
           } else {
-            CASImpl view = (CASImpl) baseCas.getView(sofaRef);
-            if (type.getCode() == TypeSystemConstants.docTypeCode) {
-              currentFs = view.getDocumentAnnotation();  // creates the document annotation if it doesn't exist
-              // we could remove this from the indexes until deserialization is over, but then, other calls to getDocumentAnnotation
-              // would end up creating additional instances
+            if (!ts.annotBaseType.subsumes(type) &&  // defer subtypes of AnnotationBase
+                !(ts.sofaType == type)) {            // defer sofa types
+              createCurrentFs(type, ivCas);              
             } else {
-              currentFs = view.createFS(type);
-              if (currentFs instanceof UimaSerializable) {
-                UimaSerializable ufs = (UimaSerializable) currentFs;
-                uimaSerializableFixups.add(() -> ufs._init_from_cas_data());
+              currentFs = null;
+              singleFsDefer.clear();
+              sofaRef = null;
+              sofaNum = -1;
+              sofaName = null;
+            }
+            for (FeatureImpl feat : type.getFeatureImpls()) {
+              readByKind(feat, type);
+            }
+  //          for (int i = 1; i < typeInfo.slotKinds.length + 1; i++) {
+  //            readByKind(iHeap, i);
+  //          }
+          }
+          
+          if (currentFs == null) {
+            
+            /**
+             * Create single deferred FS
+             *   Either: Sofa (has final fields) or
+             *           Subtype of AnnotationBase - needs to be in the right view
+             *   
+             *   For the latter, handle document annotation specially
+             */
+  
+            if (ts.sofaType == type) {
+              if (baseCas.hasView(sofaName)) {
+                // sofa was already created, by an annotationBase subtype deserialized prior to this one
+                currentFs = (TOP) baseCas.getView(sofaName).getSofa();
+              } else {
+                currentFs = baseCas.createSofa(sofaNum, sofaName, null);
+              }
+            } else {
+              
+              CASImpl view = (null == sofaRef) 
+                               ? baseCas.getInitialView() // https://issues.apache.org/jira/browse/UIMA-5588
+                               : baseCas.getView(sofaRef);
+                               
+  //            if (type.getCode() == TypeSystemConstants.docTypeCode) {
+  //              currentFs = view.getDocumentAnnotation();  // creates the document annotation if it doesn't exist
+  //              // we could remove this from the indexes until deserialization is over, but then, other calls to getDocumentAnnotation
+  //              // would end up creating additional instances
+  //            } else {
+                createCurrentFs(type, view);
+  //            }
+            }
+            if (type.getCode() == TypeSystemConstants.docTypeCode) { 
+              boolean wasRemoved = baseCas.checkForInvalidFeatureSetting(currentFs, baseCas.getAddbackSingle());
+              for (Runnable r : singleFsDefer) {
+                r.run();
+              }
+              baseCas.addbackSingleIfWasRemoved(wasRemoved, currentFs);
+            } else {
+              for (Runnable r : singleFsDefer) {
+                r.run();
               }
             }
           }
-          if (type.getCode() == TypeSystemConstants.docTypeCode) { 
-            boolean wasRemoved = baseCas.checkForInvalidFeatureSetting(currentFs, baseCas.getAddbackSingle());
-            for (Runnable r : singleFsDefer) {
-              r.run();
-            }
-            baseCas.addbackSingleIfWasRemoved(wasRemoved, currentFs);
-          } else {
-            for (Runnable r : singleFsDefer) {
-              r.run();
-            }
-          }
-        }
-        
-        assert(currentFs != null);
-//        System.out.format("Adding %,d to csds%n", iHeap);
-//        if (isDelta) {
-//          System.out.format("debug adding iHeap: %,d afterAdd: %,d%n", iHeap, iHeap + nextHeapAddrAfterMark);
-//        }
-        csds.addFS(currentFs, iHeap);
-        int s2 = 1 + seq2fs.size();  
-//        fs2seq.put(currentFs, s2);  // 1 origin to match v2
-        seq2fs.put(s2, currentFs);
-        
-        prevFsByType[typeCode] = currentFs;
+          
+          assert(currentFs != null);
+  //        System.out.format("Adding %,d to csds%n", iHeap);
+  //        if (isDelta) {
+  //          System.out.format("debug adding iHeap: %,d afterAdd: %,d%n", iHeap, iHeap + nextHeapAddrAfterMark);
+  //        }
+          csds.addFS(currentFs, iHeap);
+          int s2 = 1 + seq2fs.size();  
+  //        fs2seq.put(currentFs, s2);  // 1 origin to match v2
+          seq2fs.put(s2, currentFs);
+          
+          prevFsByType[typeCode] = currentFs;
       }
-      
       csds.setHeapEnd(heapEnd);
-      
-      if (TRACE_DES) System.out.println("Form4Deser running deferred fixups after all FSs deserialized");
+
+//      if (TRACE_DES) System.out.println("Form4Deser running deferred fixups after all FSs deserialized");
       for (Runnable r : fixupsNeeded) {
         r.run();
       }
@@ -1895,9 +1812,17 @@
 //      System.out.format("Deserialize took %,d ms%n", System.currentTimeMillis() - startTime1);
     }
     
+    private void createCurrentFs(TypeImpl type, CASImpl view) {
+      currentFs = view.createFS(type);
+      if (currentFs instanceof UimaSerializable) {
+        UimaSerializable ufs = (UimaSerializable) currentFs;
+        uimaSerializableFixups.add(() -> ufs._init_from_cas_data());
+      }
+    }
+    
     private TOP readArray(int iHeap, TypeImpl type) throws IOException { 
       final int length = readArrayLength();
-      TOP fs = ivCas.createArray(type, length);
+      TOP fs = ivCas.createArray(type, length); // create in default view - initial view (iv)cas
       if (length == 0) {
         return fs;
       }
@@ -2032,10 +1957,11 @@
       case Slot_HeapRef:
         final int vh = readDiffWithPrevTypeSlot(kind, feat);
         if (ts.annotBaseSofaFeat == feat) {
-          sofaRef = (Sofa) seq2fs(vh);  // invalid if returns null
-                                                  // forward refs are not possible for sofas
-          assert(sofaRef != null);
-        } else {
+          sofaRef = (Sofa) seq2fs(vh);  // if sofa hasn't yet been deserialized, will be null
+                            // use case: create annot , without sofa - causes create sofa
+                            // but binary serialization keeps creation order
+        }
+        if (ts.annotBaseSofaFeat != feat || sofaRef == null) { https://issues.apache.org/jira/browse/UIMA-5588
           maybeStoreOrDefer(lfs -> {
             // in addition to deferring if currentFs is null, 
             // heap refs may need deferring if forward refs
@@ -2067,7 +1993,7 @@
             break;
           }
           if (feat == ts.sofaString) {
-            maybeStoreOrDefer(lfs -> ((Sofa)lfs).setLocalSofaData(s));
+            maybeStoreOrDefer(lfs -> ((Sofa)lfs).setLocalSofaDataNoDocAnnotUpdate(s));
             break;
           }
         }
@@ -2103,7 +2029,7 @@
       fsIndexes.add(nbrViews);
       fsIndexes.add(nbrSofas);
       for (int i = 0; i < nbrSofas; i++) {
-        fsIndexes.add(readVnumber(control_dis));
+        fsIndexes.add(readVnumber(control_dis));  // this is the v2 addr style
       }
         
       for (int i = 0; i < nbrViews; i++) {
@@ -2116,7 +2042,10 @@
       
       bcsd.reinitIndexedFSs(fsIndexes.getArray(), isDelta,
           i ->  
-               seq2fs.get(i)); // written on separate line for Eclipse breakpoint control
+              seq2fs.get(i),  // written on separate line for Eclipse breakpoint control
+          i -> 
+              csds.addr2fs.get(i)  // https://issues.apache.org/jira/browse/UIMA-5593
+                 ); 
     }
 
     /** 
@@ -2341,7 +2270,7 @@
     
       final int vh = readDiff(long_High_dis, (int) (prev >>> 32));
       final int vl = readDiff(long_Low_dis, (int) prev);
-      final long v = (((long)vh) << 32) | (0xffffffffL & (long)vl);
+      final long v = (((long)vh) << 32) | (0xffffffffL & vl);
       return v;
     }
     
@@ -2650,9 +2579,9 @@
       return (s == 0) ? null : seq2fs.get(s);
     }
     
-    private TOP addr2fs(int s) {
-      return (s == 0) ? null : csds.addr2fs.get(s);
-    }
+//    private TOP addr2fs(int s) {
+//      return (s == 0) ? null : csds.addr2fs.get(s);
+//    }
   }
 
   /* ******************************************************************
@@ -2682,284 +2611,26 @@
 //    }
 //    fsStartIndexes.finishSetup();
 //  }  
-
-  // this method is required, instead of merely making
-  // a "new" instance, so that
-  // the containing instance of BinaryCasSerDes4 can be
-  // accessed for the type info
   
-  public CasCompare getCasCompare() {
-    return new CasCompare();
-  }
-  
-  public class CasCompare {
-//    /** 
-//     * Compare 2 CASes for equal
-//     * The layout of refs to aux heaps does not have to match
-//     */
-//      private CASImpl c1;
-//      private CASImpl c2;
-//      private Heap c1HO;
-//      private Heap c2HO;
-//      private int[] c1heap;
-//      private int[] c2heap;
-//      private int iHeap;
-
-    /**
-     * Trampolines to Form6 compare
-     * There's no reliable way to get the set of FSs for 2 different form4 CASs, since the 
-     * method used is to take the FSs from the id2fs weakReferences, and therefore some 
-     * unreferenced items may appear in one and not the other.
-     * @param c1 a cas to compare
-     * @param c2 the cas to compare to
-     * @return true if they compare equal
-     */
-    public boolean compareCASes(CASImpl c1, CASImpl c2) {
-      BinaryCasSerDes6 bcsd6;
-      try {
-        bcsd6 = new BinaryCasSerDes6(c1);
-      } catch (ResourceInitializationException e) {
-        // never thrown
-        throw new RuntimeException(e);
-      }
-      return bcsd6.compareCASes(c1,  c2);
-//      this.c1 = c1;
-//      this.c2 = c2;
-//      c1HO = c1.getHeap();
-//      c2HO = c2.getHeap();
-//      final int endi = c1HO.getCellsUsed();
-//      final int end2 = c2HO.getCellsUsed();
-//      if (endi != end2) {
-//        System.err.format("CASes have different heap cells used: %,d %,d%n", endi, end2);
-//      }
-//      c1heap = c1HO.heap;
-//      c2heap = c2HO.heap;
-      
-//      final ComprItemRefs fsStartIndexes = new ComprItemRefs();
-//      initFsStartIndexes(fsStartIndexes, c1heap, 1, endi, null);
-      
-//      final int endsi = fsStartIndexes.getNbrOfItems();
-//      for (int i = 1; i < endsi; i++) {
-//        iHeap = fsStartIndexes.getItemAddr(i);
-////        System.out.println("");
-//        if (!compareFss()) {
-//          return false;
-//        }
-//      }
-//      
-//      int[] ifs1 = c1.getIndexedFSs();
-//      int[] ifs2 = c2.getIndexedFSs();
-//      
-//      return Arrays.equals(ifs1, ifs2);
-//    }
+//  public CasCompare getCasCompare() {
+//    return new CasCompare();
+//  }
+//  
+//  public class CasCompare {
 //
-//    private boolean compareFss() {
-//      int tCode = c1heap[iHeap];
-//      typeInfo = getTypeInfo(tCode);
-//      if (tCode != c2heap[iHeap]) {
-//        return mismatchFs();
-//      }
-//      if (typeInfo.isArray) {
-//        return compareFssArray();
-//      } else {
-//        for (int i = 1; i < typeInfo.slotKinds.length + 1; i++) {
-//          if (!compareSlot(i)) {
-//            return mismatchFs();
-//          }
-//        }
-//        return true;
-//      }
+//    /**
+//     * Trampolines to CasCompare 
+//     * There's no reliable way to get the set of FSs for 2 different form4 CASs, since the 
+//     * method used is to take the FSs from the id2fs weakReferences, and therefore some 
+//     * unreferenced items may appear in one and not the other.
+//     * @param c1 a cas to compare
+//     * @param c2 the cas to compare to
+//     * @return true if they compare equal
+//     */
+//    public boolean compareCASes(CASImpl c1, CASImpl c2) {
+//      return org.apache.uima.cas.impl.CasCompare.compareCASes(c1, c2);
 //    }
-//      
-//    private boolean compareFssArray() {
-//      int len1 = c1heap[iHeap + 1];
-//      int len2 = c2heap[iHeap + 1];
-//      if (len1 != len2) {
-//        return false;
-//      }
-//      for (int i = 0; i < len1; i++) {
-//        SlotKind kind = typeInfo.getSlotKind(2);
-//        if (typeInfo.isHeapStoredArray) {
-//          if (kind == Slot_StrRef) {
-//            if (! compareStrings(c1.getStringForCode(c1heap[iHeap + 2 + i]),
-//                                 c2.getStringForCode(c2heap[iHeap + 2 + i]))) {
-//              return mismatchFs();
-//            }
-//          } else if (c1heap[iHeap + 2 + i] != c2heap[iHeap + 2 + i]) {
-//            return mismatchFs();
-//          }
-//        } else {  // not heap stored array
-//          switch (kind) {
-//          case Slot_BooleanRef: case Slot_ByteRef:
-//            if (c1.getByteHeap().getHeapValue(c1heap[iHeap + 2] + i) !=
-//                c2.getByteHeap().getHeapValue(c2heap[iHeap + 2] + i)) {
-//              return mismatchFs(); 
-//            }
-//            break;
-//          case Slot_ShortRef:
-//            if (c1.getShortHeap().getHeapValue(c1heap[iHeap + 2] + i) !=
-//                c2.getShortHeap().getHeapValue(c2heap[iHeap + 2] + i)) {
-//              return mismatchFs();
-//            }
-//            break;
-//          case Slot_LongRef: case Slot_DoubleRef: {
-//            if (c1.getLongHeap().getHeapValue(c1heap[iHeap + 2] + i)  !=
-//                c2.getLongHeap().getHeapValue(c2heap[iHeap + 2] + i)) {
-//              return mismatchFs();
-//            }
-//            break;
-//          }
-//          default: throw new RuntimeException("internal error");
-//          }
-//        }
-//      } // end of for
-//      return true;
-//    }
-//    
-//    private boolean compareSlot(int offset) {
-//      SlotKind kind = typeInfo.getSlotKind(offset);
-//      switch (kind) {
-//      case Slot_Int: case Slot_Short: case Slot_Boolean: case Slot_Byte: 
-//      case Slot_Float: case Slot_HeapRef:
-//        return c1heap[iHeap + offset] == c2heap[iHeap + offset];
-//      case Slot_StrRef:
-//        return compareStrings(c1.getStringForCode(c1heap[iHeap + offset]),
-//                              c2.getStringForCode(c2heap[iHeap + offset]));
-//      case Slot_LongRef: case Slot_DoubleRef:
-//        return c1.getLongHeap().getHeapValue(c1heap[iHeap + offset]) ==
-//               c2.getLongHeap().getHeapValue(c2heap[iHeap + offset]);
-//      default: throw new RuntimeException("internal error");      
-//      }
-//    }
-//    
-//    private boolean compareStrings(String s1, String s2) {
-//      if (null == s1) {
-//        return null == s2;
-//      }
-//      return s1.equals(s2);
-//    }
-//     
-//    private boolean mismatchFs() {
-//      System.err.format("Mismatched Feature Structures:%n %s%n %s%n", 
-//          dumpHeapFs(c1), dumpHeapFs(c2));
-//      return false;
-//    }
-//    
-//    private StringBuilder dumpHeapFs(CASImpl cas) {
-//      StringBuilder sb = new StringBuilder();
-//      typeInfo = getTypeInfo(cas.getHeap().heap[iHeap]);
-//      sb.append(typeInfo);
-//  
-//      if (typeInfo.isHeapStoredArray) {
-//        sb.append(dumpHeapStoredArray(cas));
-//      } else if (typeInfo.isArray) {
-//        sb.append(dumpNonHeapStoredArray(cas));
-//      } else {
-//        sb.append("   Slots:\n");
-//        for (int i = 1; i < typeInfo.slotKinds.length + 1; i++) {
-//          sb.append("  ").append(typeInfo.getSlotKind(i)).append(": ")
-//              .append(dumpByKind(cas, i)).append('\n');
-//        }
-//      }
-//      return sb;
-//    }
-//    
-//    private StringBuilder dumpHeapStoredArray(CASImpl cas) {
-//      StringBuilder sb = new StringBuilder();
-//      int[] heap = cas.getHeap().heap;
-//      final int length = heap[iHeap + 1];
-//      sb.append("Array Length: ").append(length).append('[');
-//      SlotKind arrayElementKind = typeInfo.slotKinds[1];
-//      switch (arrayElementKind) {
-//      case Slot_HeapRef: case Slot_Int: case Slot_Short: case Slot_Byte: 
-//      case Slot_Boolean: case Slot_Float:
-//        for (int i = iHeap + 2; i < iHeap + length + 2; i++) {
-//          if (i > iHeap + 2) {
-//            sb.append(", ");
-//          }
-//          sb.append(heap[i]);
-//        }
-//        break;   
-//      case Slot_StrRef:
-//        StringHeap sh = cas.getStringHeap();
-//        for (int i = iHeap + 2; i < iHeap + length + 2; i++) {
-//          if (i > iHeap + 2) {
-//            sb.append(", ");
-//          }
-//          sb.append(sh.getStringForCode(heap[i]));        
-//        }
-//        break;
-//      default: throw new RuntimeException("internal error");
-//      }
-//      sb.append("] ");
-//      return sb;
-//    }
-//  
-//    private StringBuilder dumpNonHeapStoredArray(CASImpl cas) {
-//      StringBuilder sb = new StringBuilder();
-//      int[] heap = cas.getHeap().heap;
-//      final int length = heap[iHeap + 1];
-//      sb.append("Array Length: ").append(length).append('[');
-//      SlotKind arrayElementKind = typeInfo.slotKinds[1];
-//      
-//      for (int i = 0; i < length; i++) {
-//        if (i > 0) {
-//          sb.append(", ");
-//        }
-//        switch (arrayElementKind) {
-//        case Slot_BooleanRef: case Slot_ByteRef:
-//          sb.append(cas.getByteHeap().getHeapValue(heap[iHeap + 2 + i]));
-//          break;
-//        case Slot_ShortRef:
-//          sb.append(cas.getShortHeap().getHeapValue(heap[iHeap + 2 + i]));
-//          break;
-//        case Slot_LongRef: case Slot_DoubleRef: {
-//          long v = cas.getLongHeap().getHeapValue(heap[iHeap + 2 + i]);
-//          if (arrayElementKind == Slot_DoubleRef) {
-//            sb.append(CASImpl.long2double(v));
-//          } else {
-//            sb.append(String.format("%,d", v));
-//          }
-//          break;
-//        }
-//        default: throw new RuntimeException("internal error");
-//        }
-//      }
-//      sb.append("] ");
-//      return sb;      
-//    }
-//  
-//    private StringBuilder dumpByKind(CASImpl cas, int offset) {
-//      StringBuilder sb = new StringBuilder();
-//      int[] heap = cas.getHeap().heap;
-//      SlotKind kind = typeInfo.getSlotKind(offset);
-//      switch (kind) {
-//      case Slot_Int:
-//        return sb.append(heap[iHeap + offset]);
-//      case Slot_Short: 
-//        return sb.append((short)heap[iHeap + offset]);
-//      case Slot_Byte: 
-//        return sb.append((byte)heap[iHeap + offset]);
-//      case Slot_Boolean:  
-//        return sb.append(((heap[iHeap + offset]) == 0) ? false : true);
-//      case Slot_Float: {
-//        int v = heap[iHeap + offset];
-//        return sb.append(Float.intBitsToFloat(v)).append(' ').append(Integer.toHexString(v));
-//      }
-//      case Slot_HeapRef:
-//        return sb.append("HeapRef[").append(heap[iHeap + offset]).append(']');
-//      case Slot_StrRef:
-//        return sb.append(cas.getStringForCode(heap[iHeap + offset]));
-//      case Slot_LongRef:
-//        return sb.append(String.format("%,d", cas.getLongHeap().getHeapValue(heap[iHeap + offset])));
-//      case Slot_DoubleRef: {
-//        long v = cas.getLongHeap().getHeapValue(heap[iHeap + offset]);
-//        return sb.append(CASImpl.long2double(v)).append(' ').append(Long.toHexString(v));
-//      }
-//      default: throw new RuntimeException("internal error");      
-//      }
-    }
-  }
+//  }
   
   /**
    * 
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/BinaryCasSerDes6.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/BinaryCasSerDes6.java
index eecc789..cfa9e8e 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/BinaryCasSerDes6.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/BinaryCasSerDes6.java
@@ -40,13 +40,9 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Set;
 import java.util.function.Consumer;
 import java.util.function.IntFunction;
-import java.util.function.IntPredicate;
 import java.util.stream.Stream;
 import java.util.zip.Deflater;
 import java.util.zip.DeflaterOutputStream;
@@ -58,7 +54,6 @@
 import org.apache.uima.cas.CASRuntimeException;
 import org.apache.uima.cas.CommonArrayFS;
 import org.apache.uima.cas.FSIterator;
-import org.apache.uima.cas.Feature;
 import org.apache.uima.cas.impl.CASImpl.FsChange;
 import org.apache.uima.cas.impl.CommonSerDes.Header;
 import org.apache.uima.cas.impl.FSsTobeAddedback.FSsTobeAddedbackSingle;
@@ -67,7 +62,6 @@
 import org.apache.uima.internal.util.IntListIterator;
 import org.apache.uima.internal.util.IntVector;
 import org.apache.uima.internal.util.Misc;
-import org.apache.uima.internal.util.Pair;
 import org.apache.uima.internal.util.PositiveIntSet;
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.cas.BooleanArray;
@@ -82,6 +76,7 @@
 import org.apache.uima.jcas.cas.StringArray;
 import org.apache.uima.jcas.cas.TOP;
 import org.apache.uima.resource.ResourceInitializationException;
+import org.apache.uima.util.AutoCloseableNoException;
 import org.apache.uima.util.CasIOUtils;
 import org.apache.uima.util.CasLoadMode;
 import org.apache.uima.util.impl.DataIO;
@@ -373,7 +368,7 @@
    * first index: key is type code
    * 2nd index: key is slot-offset number (0-based) 
    */
-  final private Int2ObjHashMap<long[]> prevFsWithLongValues;
+  final private Int2ObjHashMap<long[], long[]> prevFsWithLongValues;
   
   /**
    * ordered set of FSs found in indexes or linked from other found FSs.
@@ -445,16 +440,19 @@
   final private DataInputStream[] dataInputs = new DataInputStream[NBR_SLOT_KIND_ZIP_STREAMS];
   final private Inflater[] inflaters = new Inflater               [NBR_SLOT_KIND_ZIP_STREAMS];
 
-  /** the "fixups" for relative heap refs */
+  /** the "fixups" for relative heap refs
+   *  actions set slot values 
+   */
   final private List<Runnable> fixupsNeeded = new ArrayList<>();
   final private List<Runnable> uimaSerializableFixups = new ArrayList<>();
 //  /** hold on to FS prior to getting them indexed to prevent them from being GC'd */
 //  final private List<TOP> preventFsGc = new ArrayList<>();
 
   /** 
+   * Deferred actions to set Feature Slots of feature structures.
    * the deferrals needed when deserializing a subtype of AnnotationBase before the sofa is known
    * Also for Sofa creation where some fields are final
-   * */
+   */
   final private List<Runnable> singleFsDefer = new ArrayList<>(); 
   
   /** used for deferred creation */
@@ -1486,7 +1484,7 @@
             String[] strings = ((StringArray)fs)._getTheArray();
             IntListIterator it = changedFs.arrayUpdates.iterator();
             while (it.hasNext()) {
-              os.add(strings[it.next()]);
+              os.add(strings[it.nextNvc()]);
             }
           }
         } else {
@@ -1586,7 +1584,7 @@
         }
         
         while (it.hasNext()) {
-          int index = it.next();
+          int index = it.nextNvc();
           writeVnumber(fsIndexes_dos, index - prevIndex);
           prevIndex = index;
 
@@ -1760,7 +1758,7 @@
     }
     
 //    stringTableOffset = isReadingDelta ? (stringHeapObj.getSize() - 1) : 0;
-    nextFsId = isReadingDelta ? (cas.getLastUsedFsId() + 1) : 0;
+    nextFsId = isReadingDelta ? cas.peekNextFsId() : 0;
     
 //    if (!isReadingDelta) {
 //      heapObj.reinitSizeOnly(1);
@@ -1798,7 +1796,13 @@
     /**********************************************************
      * Read in new FSs being deserialized and add them to heap
      **********************************************************/
-    // currentFsId used when debugging, only
+    
+    // currentFsId is ID of next to be deserialized FS
+    //   only incremented when something is "stored", not skipped
+    // nextFsAddr only used for loop  termination , pre v3
+    //   could be gt than fsId, because some FSs are "skipped" in deserialization
+    
+    // currentFsId only used in error message
     for (int currentFsId = nextFsId, nbrFSs = 0, nextFsAddr = 1; 
          this.bcsd.isBeforeV3 
            ? nextFsAddr < totalMappedHeapSize
@@ -1807,11 +1811,17 @@
          nextFsAddr += this.bcsd.isBeforeV3 
                          ? tgtType.getFsSpaceReq(lastArrayLength)
                          : 0) {
+     
       final int tgtTypeCode = readVnumber(typeCode_dis); // get type code
 //      final int adjTgtTypeCode = tgtTypeCode + ((this.bcsd.isBeforeV3 && tgtTypeCode > TypeSystemConstants.lastBuiltinV2TypeCode) 
 //          ? TypeSystemConstants.numberOfNewBuiltInsSinceV2
 //          : 0);
       tgtType = (isTypeMapping ? tgtTs : srcTs).getTypeForCode(tgtTypeCode); 
+      if (tgtType == null) {
+        /** Deserializing Compressed Form 6, a type code: {0} has no corresponding type. currentFsId: {1} nbrFSs: {2} nextFsAddr: {3} */
+        throw new CASRuntimeException(CASRuntimeException.DESER_FORM_6_BAD_TYPE_CODE, tgtTypeCode,
+            currentFsId, nbrFSs, nextFsAddr);
+      }
       final TypeImpl srcType = isTypeMapping ? typeMapper.mapTypeCodeTgt2Src(tgtTypeCode) : tgtType;
       
       final boolean storeIt = (srcType != null);
@@ -1855,11 +1865,7 @@
         if (storeIt) {
           if (!srcTs.annotBaseType.subsumes(srcType) &&  // defer subtypes of AnnotationBase
               !(srcTs.sofaType == srcType)) {            // defer sofa types
-            currentFs = cas.createFS(srcType);
-            if (currentFs instanceof UimaSerializable) {
-              UimaSerializable ufs = (UimaSerializable) currentFs;
-              uimaSerializableFixups.add(() -> ufs._init_from_cas_data());
-            }
+            createCurrentFs(srcType, cas);
           } else {
             currentFs = null;
             singleFsDefer.clear();
@@ -1893,20 +1899,26 @@
            */
 
           if (srcTs.sofaType == srcType) {
-            currentFs = cas.createSofa(sofaNum, sofaName, sofaMimeType);  
-          } else {
-            CASImpl view = (CASImpl) cas.getView(sofaRef);
-            if (srcType.getCode() == TypeSystemConstants.docTypeCode) {
-              currentFs = view.getDocumentAnnotation();  // creates the document annotation if it doesn't exist
-              // we could remove this from the indexes until deserialization is over, but then, other calls to getDocumentAnnotation
-              // would end up creating additional instances
+            if (cas.hasView(sofaName)) {
+              // sofa was already created, by an annotationBase subtype deserialized prior to this one
+              currentFs = (TOP) cas.getView(sofaName).getSofa();
             } else {
-              currentFs = view.createFS(srcType);
-              if (currentFs instanceof UimaSerializable) {
-                UimaSerializable ufs = (UimaSerializable) currentFs;
-                uimaSerializableFixups.add(() -> ufs._init_from_cas_data());
-              }
+              currentFs = cas.createSofa(sofaNum, sofaName, sofaMimeType);
             }
+          } else {
+            
+            CASImpl view = (null == sofaRef) 
+                             ? cas.getInitialView()  // https://issues.apache.org/jira/browse/UIMA-5588
+                             : (CASImpl) cas.getView(sofaRef);
+                             
+//            if (srcType.getCode() == TypeSystemConstants.docTypeCode) {
+//              currentFs = view.getDocumentAnnotation();  // creates the document annotation if it doesn't exist
+//              
+//              // we could remove this from the indexes until deserialization is over, but then, other calls to getDocumentAnnotation
+//              // would end up creating additional instances
+//            } else {
+              createCurrentFs(srcType, view);
+//            }
           }
           if (srcType.getCode() == TypeSystemConstants.docTypeCode) { 
             boolean wasRemoved = cas.removeFromCorruptableIndexAnyView(currentFs, cas.getAddbackSingle());
@@ -1919,8 +1931,8 @@
               r.run();
             }
           }
-        }
-      }
+        }  // end of handling deferred current fs
+      } // of not-an-array
 //      if (storeIt) {
 //        prevFsByType[srcType.getCode()] = currentFs;  // make this one the "prev" one for subsequent testing
 //        //debug
@@ -1932,9 +1944,10 @@
 //                 need to have read skip slots not present in src
 //      targetHeapUsed += incrToNextFs(heap, currentFsId, tgtTypeInfo);  // typeInfo is target type info
       fsStartIndexes.addSrcFsForTgt(currentFs, storeIt);
-      currentFsId += storeIt ? 1 : 0;
-    }
+      currentFsId += storeIt ? cas.lastV2IdIncr() : 0;
+    } // end of for loop over items in main heap
 
+   
     for (Runnable r : fixupsNeeded) {
       r.run();
     }
@@ -1956,6 +1969,15 @@
 //      System.out.format("Deserialize took %,d ms%n", System.currentTimeMillis() - startTime1);
   }
   
+  private void createCurrentFs(TypeImpl type, CASImpl view) {
+    currentFs = view.createFS(type);
+    if (currentFs instanceof UimaSerializable) {
+      UimaSerializable ufs = (UimaSerializable) currentFs;
+      uimaSerializableFixups.add(() -> ufs._init_from_cas_data());
+    }
+  }
+
+  
   /**
    * 
    * @param storeIt
@@ -2109,8 +2131,10 @@
     case Slot_HeapRef:
       final int vh = readDiffIntSlot(storeIt, tgtFeatOffset, kind, tgtType);
       if (srcTs.annotBaseSofaFeat == srcFeat) {
-        sofaRef = (Sofa) getRefVal(vh);
-      } else {
+        sofaRef = (Sofa) getRefVal(vh);  // if sofa hasn't yet been deserialized, will be null
+      }
+      
+      if (srcTs.annotBaseSofaFeat != srcFeat || sofaRef == null) { https://issues.apache.org/jira/browse/UIMA-5588
         maybeStoreOrDefer(storeIt, fs, (lfs) -> { 
         
           // outer defer done if fs is null; it is a one-feature-structure defer for sofa or subtypes of annotationbase
@@ -2160,7 +2184,7 @@
             break;
           }
           if (srcFeat == srcTs.sofaString) {
-            maybeStoreOrDefer(storeIt, fs, lfs -> ((Sofa)lfs).setLocalSofaData(vString));
+            maybeStoreOrDefer(storeIt, fs, lfs -> ((Sofa)lfs).setLocalSofaDataNoDocAnnotUpdate(vString));
             break;
           }
         }
@@ -2570,7 +2594,7 @@
           // never happen because in the delta CAS ts system use-case, the 
           //   target is always a subset of the source
           //   due to type system merging
-          Misc.internalError();
+          throw Misc.internalError();
         }
         
         TypeImpl srcType = fs._getTypeImpl();
@@ -2801,10 +2825,18 @@
    * The cas is passed in so that the Compare can use this for two different CASes
    * 
    */
-  private void processIndexedFeatureStructures(final CASImpl cas, boolean isWrite) throws IOException {
+  private void processIndexedFeatureStructures(final CASImpl cas1, boolean isWrite) throws IOException {
     if (!isWrite) {
-      AllFSs allFSs = new AllFSs(cas, mark, isTypeMapping ? fs -> isTypeInTgt(fs) : null, 
-                                            isTypeMapping ? typeMapper            : null);
+      // always have form 6 do just reachables, to mimic what v2 did
+      AllFSs allFSs;
+      try (AutoCloseableNoException a = LowLevelCAS.ll_defaultV2IdRefs(false)) {
+        allFSs = new AllFSs(cas1, 
+                            mark, 
+                            isTypeMapping ? fs -> isTypeInTgt(fs) : null, 
+                            isTypeMapping ? typeMapper            : null)
+                  .getAllFSsAllViews_sofas_reachable();
+            ;
+      }
       fssToSerialize = CASImpl.filterAboveMark(allFSs.getAllFSsSorted(), mark);
       foundFSs = allFSs.getAllNew();
       foundFSsBelowMark = allFSs.getAllBelowMark();
@@ -2816,15 +2848,15 @@
 //      if (doMeasurements) {
 //        sm.statDetails[fsIndexes_i].original = fsIndexes.length * 4 + 1;      
 //      }
-    writeVnumber(control_i, cas.getNumberOfViews());
-    writeVnumber(control_i, cas.getNumberOfSofas());
+    writeVnumber(control_i, cas1.getNumberOfViews());
+    writeVnumber(control_i, cas1.getNumberOfSofas());
     if (doMeasurements) {
       sm.statDetails[fsIndexes_i].incr(1); // an approximation - probably correct
       sm.statDetails[fsIndexes_i].incr(1);
     }
 
     // write or enqueue the sofas
-    final FSIterator<Sofa> it = cas.getSofaIterator();
+    final FSIterator<Sofa> it = cas1.getSofaIterator();
     while (it.hasNext()) {
       Sofa sofa = it.nextNvc();
       // for delta only write new sofas
@@ -2838,14 +2870,14 @@
         }
       }
     }
-    TypeImpl topType = (TypeImpl) cas.getTypeSystemImpl().getTopType();
+    TypeImpl topType = (TypeImpl) cas1.getTypeSystemImpl().getTopType();
 
     // write (id's only, for index info) and/or enqueue indexed FSs, either all, or (for delta writes) the added/deleted/reindexed ones
-    cas.forAllViews(view -> {
+    cas1.forAllViews(view -> {
       processFSsForView(true,  // is enqueue
         isSerializingDelta 
           ? view.indexRepository.getAddedFSs().stream()
-          : view.indexRepository.<TOP>getAllIndexedFS(topType).stream());
+          : view.indexRepository.<TOP>getIndexedFSs(topType).stream());
       if (isSerializingDelta) {
         // for write/delta, write out (but don't enqueue) the deleted/reindexed FSs
         processFSsForView(false, view.indexRepository.getDeletedFSs().stream());
@@ -2945,42 +2977,42 @@
 //    return !isTypeMapping || (null != typeMapper.mapTypeSrc2Tgt(typecode));
 //  }
   
-  private void processRefedFSs() {
-    for (int i = 0; i < toBeScanned.size(); i++) {
-      enqueueFeatures(toBeScanned.get(i));
-    }
-  }
+//  private void processRefedFSs() {
+//    for (int i = 0; i < toBeScanned.size(); i++) {
+//      enqueueFeatures(toBeScanned.get(i));
+//    }
+//  }
   
   
-  /**
-   * Enqueue all FSs reachable from features of the given FS.
-   */
-  private void enqueueFeatures(TOP fs) {
-    if (fs instanceof FSArray) {
-      for (TOP item : ((FSArray)fs)._getTheArray()) {
-        enqueueFS(item);
-      }
-      return;
-    }
-    
-    // not an FS Array
-    if (fs instanceof CommonArrayFS) {
-      return;
-    }
-  
-    final TypeImpl srcType = fs._getTypeImpl();
-    for (FeatureImpl srcFeat : srcType.getFeatureImpls()) {
-      if (isTypeMapping) {
-        FeatureImpl tgtFeat = typeMapper.getTgtFeature(srcType, srcFeat);
-        if (tgtFeat == null) {
-          continue;  // skip enqueue if not in target
-        }
-      } 
-      if (srcFeat.getRangeImpl().isRefType) {
-        enqueueFS(fs._getFeatureValueNc(srcFeat));
-      }
-    }
-  }
+//  /**
+//   * Enqueue all FSs reachable from features of the given FS.
+//   */
+//  private void enqueueFeatures(TOP fs) {
+//    if (fs instanceof FSArray) {
+//      for (TOP item : ((FSArray)fs)._getTheArray()) {
+//        enqueueFS(item);
+//      }
+//      return;
+//    }
+//    
+//    // not an FS Array
+//    if (fs instanceof CommonArrayFS) {
+//      return;
+//    }
+//  
+//    final TypeImpl srcType = fs._getTypeImpl();
+//    for (FeatureImpl srcFeat : srcType.getFeatureImpls()) {
+//      if (isTypeMapping) {
+//        FeatureImpl tgtFeat = typeMapper.getTgtFeature(srcType, srcFeat);
+//        if (tgtFeat == null) {
+//          continue;  // skip enqueue if not in target
+//        }
+//      } 
+//      if (srcFeat.getRangeImpl().isRefType) {
+//        enqueueFS(fs._getFeatureValueNc(srcFeat));
+//      }
+//    }
+//  }
   
     
   /**
@@ -3062,609 +3094,7 @@
   public boolean compareCASes(CASImpl c1, CASImpl c2) {
     return new CasCompare(c1, c2).compareCASes();
   }
-  
-  private class CasCompare {
-    /** 
-     * Compare 2 CASes for equal
-     */
-      final private CASImpl c1;
-      final private CASImpl c2;
-      final private TypeSystemImpl ts1;      
-      final private TypeSystemImpl ts2;
-      
-      /**
-       * This is used for two things:
-       *   First, used twice while sorting individual FS collections to be compared.
-       *   Second, used when doing the comparison to break recursion if asked to compare the same two things while comaring them.
-       */
-      final Set<Pair<TOP, TOP>> prevCompare = Collections.newSetFromMap(new HashMap<>());
-            
-      private TOP fs1, fs2;
-      private boolean isSrcCas;  // used for sorting with a CAS, to differentiate between src and target CASes
-            
-    public CasCompare(CASImpl c1, CASImpl c2) {
-      this.c1 = c1;
-      this.c2 = c2;
-      ts1 = c1.getTypeSystemImpl();
-      ts2 = c2.getTypeSystemImpl();
-    }
-      
-    public boolean compareCASes() {
-      
-      final List<TOP> c1FoundFSs;
-      final List<TOP> c2FoundFSs;
-      final boolean savedIsTypeMapping= isTypeMapping;
-      try {
-        assert(ts1 == srcTs);
-        // sometimes the tgtTs is null, indicating no type mapping
-        //   the CASs being compared are then both of type srcTs
-        assert(ts2 == srcTs || ts2 == tgtTs);
-//        srcTs = ts1;
-        processIndexedFeatureStructures(c1, false);
-        c1FoundFSs = fssToSerialize;  // all reachable FSs, filtered by CAS1 -> CAS2 type systems.
-
-        isTypeMapping = false;   // when scanning CAS2, don't use type mapping
-        srcTs = ts2;
-        
-        processIndexedFeatureStructures(c2, false);
-        
-        isTypeMapping = savedIsTypeMapping;  // restore
-        srcTs = ts1; 
-
-        c2FoundFSs = fssToSerialize; // all reachable FSs in cas 2
-
-        // if type systems are "isEqual()" still need to map because of feature validation testing
-          
-        int i1 = 0;
-        int i2 = 0;
-        final int sz1 = c1FoundFSs.size();
-        final int sz2 = c2FoundFSs.size();
-        
-        isSrcCas = true;   // avoids sorting on types/features not present in ts2
-        sort(c1FoundFSs);
-        
-        isSrcCas = false;  // avoids sorting on types/features not present in ts1
-        sort(c2FoundFSs);
-        prevCompare.clear();
-        
-        while (i1 < sz1 && i2 < sz2) {
-          fs1 = c1FoundFSs.get(i1);  // assumes the elements are in same order??
-          fs2 = c2FoundFSs.get(i2);
-          
-          if (isTypeMapping) {
-            // skip compares for types that are missing in the other type system
-            final boolean typeMissingIn1 = typeMapper.mapTypeTgt2Src(fs2._getTypeImpl()) == null;
-            final boolean typeMissingIn2 = typeMapper.mapTypeSrc2Tgt(fs1._getTypeImpl()) == null;
-            if (!typeMissingIn1 && !typeMissingIn2) {
-              if (!compareFss()) {
-                return false;
-              }
-              i1++;
-              i2++;
-              continue;
-            }
-            if (typeMissingIn1 && typeMissingIn2) {
-              Misc.internalError();
-              i1++;
-              i2++;
-              continue;
-            }
-            if (typeMissingIn1) {
-              System.out.println("debug - type missing in 1, but test fails for refs");
-              i2++;
-              continue;
-            }
-            if (typeMissingIn2) {
-              Misc.internalError(); 
-              i1++;
-              continue;
-            }
-          } else {  // not type mapping
-            if (!compareFss()) {
-              return false;
-            }
-            i1++;
-            i2++;
-            continue;
-          }
-        }
-        
-        if (i1 == sz1 && i2 == sz2) {
-          return true;  // end, everything compared
-        }
-        
-        if (isTypeMapping) {
-          if (i1 < sz1) {
-            System.err.format("%,d Feature Structures in CAS1 with no matches in CAS2, e.g. %s%n",
-                sz1 - i1, c1FoundFSs.get(i1));
-            return false;
-          }
-
-          while (i2 < sz2) {
-            TOP fs = c2FoundFSs.get(i2);
-            if (isTypeMapping && typeMapper.mapTypeTgt2Src(fs._getTypeImpl()) != null) {  // not a complete test, misses refs
-              return false;  // have more FSs in c2 than in c1
-            }
-            i2++;
-          }
-          return true;
-        }
-        
-        // not type mapping, and number of FS didn't match
-        if (i1 < sz1) {
-          System.err.format("CAS1 had %,d additional Feature Structures, e.g.: %s%n", sz1 - i1, c1FoundFSs.get(i1));
-        } else {
-          System.err.format("CAS2 had %,d additional Feature Structures, e.g.: %s%n", sz2 - i2, c2FoundFSs.get(i2));
-        }
-        return false;
-      } catch (IOException e) {
-        throw new RuntimeException(e);  // never happen
-      } finally {
-        isTypeMapping = savedIsTypeMapping;
-      }
-    }
-
-    private boolean compareFss() {
-      TypeImpl ti1 = fs1._getTypeImpl();
-      TypeImpl ti2 = fs2._getTypeImpl();  // even if not type mapping, may be "equal" but not ==
-      
-      if (isTypeMapping) {
-        if (ti1 != typeMapper.mapTypeTgt2Src(ti2)) {
-          return mismatchFs("Different Types"); // types mismatch
-        }
-      } else {
-        if (!ti1.getName().equals(ti2.getName())) {
-          return mismatchFs("Type names miscompare"); // types mismatch
-        }
-      }
-          
-      if (ti1.isArray()) {
-        return compareFssArray();
-      } else {
-        if (isTypeMapping) {
-          for (FeatureImpl fi1 : ti1.getFeatureImpls()) {
-            FeatureImpl fi2 = typeMapper.getTgtFeature(ti1, fi1);
-            if (fi2 != null) {
-              if (!compareSlot(fi1, fi2)) {
-                return mismatchFs(fi1, fi2);
-              }
-            } // else we skip the compare - no slot in tgt for src
-          }
-        } else { // not type mapping
-          for (FeatureImpl fi1 : ti1.getFeatureImpls()) {
-            if (!compareSlot(fi1, fi1)) {
-              return mismatchFs(fi1);
-            }
-          }
-        }
-        return true;
-      }
-    }
-      
-    private boolean compareFssArray() {
-      CommonArrayFS a1 = (CommonArrayFS) fs1;
-      CommonArrayFS a2 = (CommonArrayFS) fs2;
-      int len1 = a1.size();
-      int len2 = a2.size();
-      if (len1 != len2) {
-        return mismatchFs();
-      }
-      
-      TypeImpl ti = fs1._getTypeImpl();
-      SlotKind kind = ti.getComponentSlotKind();
-      
-      switch(kind) {
-      case Slot_BooleanRef: return compareAllArrayElements(len1, i -> ((BooleanArray)a1).get(i) == ((BooleanArray)a2).get(i));
-      case Slot_ByteRef:    return compareAllArrayElements(len1, i -> ((ByteArray   )a1).get(i) == ((ByteArray   )a2).get(i));
-      case Slot_ShortRef:   return compareAllArrayElements(len1, i -> ((ShortArray  )a1).get(i) == ((ShortArray  )a2).get(i));
-      case Slot_Int:     return compareAllArrayElements(len1, i -> ((IntegerArray)a1).get(i) == ((IntegerArray)a2).get(i));
-      case Slot_LongRef:    return compareAllArrayElements(len1, i -> ((LongArray   )a1).get(i) == ((LongArray   )a2).get(i));
-      case Slot_Float:   return compareAllArrayElements(len1, i -> CASImpl.float2int(((FloatArray  )a1).get(i)) == 
-                                                                   CASImpl.float2int(((FloatArray  )a2).get(i)));
-      case Slot_DoubleRef:  return compareAllArrayElements(len1, i -> Double.doubleToRawLongBits(((DoubleArray)a1).get(i)) == 
-                                                                      Double.doubleToRawLongBits(((DoubleArray)a2).get(i)));
-      case Slot_HeapRef: return compareAllArrayElements(len1, i -> compareRefs(((FSArray)a1).get(i), ((FSArray)a2).get(i), null));
-      case Slot_StrRef:  return compareAllArrayElements(len1, i -> areStringsEqual(((StringArray)a1).get(i), ((StringArray)a2).get(i)));
-      default: 
-        Misc.internalError(); return true;  // only to avoid a compile error
-      }
-    }
-        
-    private boolean compareSlot(FeatureImpl fi1, FeatureImpl fi2) {
-      SlotKind kind = fi1.getSlotKind();
-      switch (kind) {
-      case Slot_Int: return fs1._getIntValueNc(fi1) == fs2._getIntValueNc(fi2); 
-      case Slot_Short: return fs1._getShortValueNc(fi1) == fs2._getShortValueNc(fi2);
-      case Slot_Boolean: return fs1._getBooleanValueNc(fi1) == fs2._getBooleanValueNc(fi2);
-      case Slot_Byte: return fs1._getByteValueNc(fi1) == fs2._getByteValueNc(fi2);
-            // don't compare floats directly - the NaN is defined to miscompare
-      case Slot_Float: return CASImpl.float2int(fs1._getFloatValueNc(fi1)) == CASImpl.float2int(fs2._getFloatValueNc(fi2));
-      case Slot_HeapRef: return compareRefs(fs1._getFeatureValueNc(fi1), fs2._getFeatureValueNc(fi2), fi1);
-      case Slot_StrRef: return areStringsEqual(fs1._getStringValueNc(fi1), fs2._getStringValueNc(fi2));
-      case Slot_LongRef: return fs1._getLongValueNc(fi1) == fs2._getLongValueNc(fi2);
-            // don't compare doubles directly - the NaN is defined to miscompare
-      case Slot_DoubleRef: return Double.doubleToRawLongBits(fs1._getDoubleValueNc(fi1)) == Double.doubleToRawLongBits(fs2._getDoubleValueNc(fi2));
-      default: Misc.internalError(); return true;     
-      }
-    }
-          
-    private boolean compareRefs(TOP rfs1, TOP rfs2, FeatureImpl fi) {
-      if (rfs1 == null) {
-        if (rfs2 != null){
-          System.err.format("For feature \"%s\", original fs1 ref feature is null, but target ref is not null: %s%n", 
-              (fi == null) ? "(notFeature) FSArray" : fi.getShortName(), rfs2);
-          return false;
-        }
-        return true; // both are null
-      }
-      
-      if (!isTypeInTgt(rfs1)) {
-        // source ref is for type not in target.  Target value should be 0
-        if (rfs2 != null) {
-          System.err.format("HeapRef original %s%n is for a type not in target ts, target should be null but has %s%n", rfs1, rfs2);
-          return false;
-        }
-        return true;
-      }
-      
-      // rfs1 != null at this point
-      if (rfs2 == null) {
-        System.err.format("For feature \"%s\" original fs1 ref is not null: %s%n, but target ref is null%n", 
-            (fi == null) ? "(notFeature) FSArray" : fi.getShortName(), rfs1);
-        return false;
-      }
-    
-//      final int seq1 = addr2seq1.getMostlyClose(c1ref);
-//      final int seq2 = addr2seq2.getMostlyClose(c2ref);
-      
-      if (rfs1._id == rfs2._id) {
-        return true;
-      }
-      
-      // ids mismatch, but might have the same "value"
-      // do a recursive check 
-      
-      Pair<TOP, TOP> refs = new Pair<TOP, TOP>(rfs1, rfs2);      
-      if (!prevCompare.add(refs)) {
-        return true; // consider these FSs to be equal, since we hit this while comparing them, to break recursion.
-                     // if there are other slots to compare, they will be compared subsequentially, at the higher level.
-      }
-            
-      TOP savedFs1 = fs1;
-      TOP savedFs2 = fs2;
-      
-      fs1 = rfs1;
-      fs2 = rfs2;
-      try {
-        return compareFss();
-      } finally {
-        fs1 = savedFs1;
-        fs2 = savedFs2;
-        prevCompare.remove(refs);
-      }
-    }
-        
-    private boolean compareAllArrayElements(int len, IntPredicate c) {
-      for (int i = 0; i < len; i++) {
-        if (!c.test(i)) {
-          mismatchFs("Comparing array of length " + len);
-          return false;
-        }
-      }
-      return true;
-    }
-    
-    
-    
-    private boolean areStringsEqual(String s1, String s2) {
-      if (null == s1) {
-        return null == s2;
-      }
-      return (null == s2) ? false : s1.equals(s2);
-    }     
-    
-//    private int skipOverTgtFSsNotInSrc(
-//        int[] heap, int heapEnd, int nextFsIndex, CasTypeSystemMapper typeMapper) {
-//      final TypeSystemImpl ts = typeMapper.tsTgt;
-//      for (; nextFsIndex < heapEnd;) {
-//        final int tCode = heap[nextFsIndex];
-//        if (typeMapper.mapTypeCodeTgt2Src(tCode) != 0) { 
-//          break;
-//        }
-//        nextFsIndex += incrToNextFs(heap, nextFsIndex, ts.getTypeInfo(tCode));
-//      }
-//      return nextFsIndex;
-//    }
-//    
-//    public void initSrcTgtIdMapsAndStringsCompare () {
-//
-//      int iTgtHeap = isTypeMapping ? skipOverTgtFSsNotInSrc(c2heap, c2end, 1, typeMapper) : 1;
-//      
-//      
-//      for (int iSrcHeap = 1; iSrcHeap < c1end;) {
-//        final int tCode = c1heap[iSrcHeap];
-//        final int tgtTypeCode = isTypeMapping ? typeMapper.mapTypeCodeSrc2Tgt(tCode) : tCode;
-//        final boolean isIncludedType = (tgtTypeCode != 0);
-//        
-//        // record info for type
-//        fsStartIndexes.addItemId(iSrcHeap, iTgtHeap, isIncludedType);  // maps src heap to tgt seq
-//        
-//        // for features in type - 
-//        //    strings: accumulate those strings that are in the target, if optimizeStrings != null
-//        //      strings either in array, or in individual values
-//        //    byte (array), short (array), long/double (instance or array): record if entries in aux array are skipped
-//        //      (not in the target).  Note the recording will be in a non-ordered manner (due to possible updates by
-//        //       previous delta deserialization)
-//        final TypeInfo srcTypeInfo = ts1.getTypeInfo(tCode);
-//        final TypeInfo tgtTypeInfo = (isTypeMapping && isIncludedType) ? ts2.getTypeInfo(tgtTypeCode) : srcTypeInfo;
-//              
-//        // Advance to next Feature Structure, in both source and target heap frame of reference
-//        if (isIncludedType) {
-//          final int deltaTgtHeap = incrToNextFs(c1heap, iSrcHeap, tgtTypeInfo);
-//          iTgtHeap += deltaTgtHeap;
-//          if (isTypeMapping) {
-//            iTgtHeap = skipOverTgtFSsNotInSrc(c2heap, c2end, iTgtHeap, typeMapper);
-//          }
-//        }
-//        iSrcHeap += incrToNextFs(c1heap, iSrcHeap, srcTypeInfo);
-//      }
-//    } 
-
-    private boolean mismatchFs() {
-      System.err.format("Mismatched Feature Structures:%n %s%n %s%n", 
-          fs1, fs2);
-      return false;
-    }
-
-//    private boolean mismatchFs(int i1, int i2) {
-//      System.err.format("Mismatched Feature Structures in srcSlot %d, tgtSlot %d%n %s%n %s%n", 
-//          i1, i2, dumpHeapFs(c1, c1heapIndex, ts1), dumpHeapFs(c2, c2heapIndex, ts2));
-//      return false;
-//    }
-    
-    private boolean mismatchFs(Feature fi) {
-      System.err.format("Mismatched Feature Structures in feature %s%n %s%n %s%n", 
-          fi.getShortName(), fs1, fs2);
-      return false;
-    }
-    
-    private boolean mismatchFs(Feature fi, Feature fi2) {
-      System.err.format("Mismatched Feature Structures in feature %s which mapped to target feature %s%n %s%n %s%n", 
-          fi.getShortName(), fi2.getShortName(), fs1, fs2);
-      return false;
-    }
-    
-    private boolean mismatchFs(String msg) {
-      System.err.format("Mismatched Feature Structures, %s%n %s%n %s%n", 
-          msg, fs1, fs2);
-      return false;
-    }
-        
-    private void sort(List<TOP> fss) {
-      prevCompare.clear();
-      Collections.sort(fss,  (afs1, afs2) -> sortCompare(afs1, afs2));
-    }
-    
-    /**
-     * Used for sorting within one type system, for two instances of the same type
-     * 
-     * Uses field isSrcCas (boolean) to differentiate when being used to sort for srcCas vs tgtCas
-     * 
-     * When sorting where type mapping is happening between source and target CASs, skip compares for
-     * features which are not in the opposite CAS.
-     * 
-     * @param scFs1
-     * @param scFs2
-     * @return
-     */
-    private int sortCompare(TOP scFs1, TOP scFs2) {
-      // sort by type code first
-      final TypeImpl fs1Type = scFs1._getTypeImpl();
-      int c = fs1Type.getName().compareTo(scFs2._getTypeImpl().getName());
-      if (c != 0) return c;
-      
-      // same type: compare on features, or if array, on length, then content
-      
-      if (fs1Type.isArray()) {
-        return sortArray(scFs1, scFs2);
-      }
-      
-      FeatureImpl[] fis = fs1Type.getFeatureImpls();
-      for (FeatureImpl fi : fis) {
-        if (isTypeMapping) {
-          if (isSrcCas && typeMapper.getTgtFeature(fs1Type, fi) == null) {
-            continue; // don't sort on features not in target type
-          } else if ((!isSrcCas) && typeMapper.getSrcFeature(fs1Type,  fi) == null) {
-            continue;  // don't sort on features not in source type
-          }
-        }
-        SlotKind kind = fi.getSlotKind();
-        switch(kind) {    // ...Ref are either long/double/str 
-        case Slot_Boolean: 
-          c = Boolean.compare(scFs1._getBooleanValueNc(fi),  scFs2._getBooleanValueNc(fi));
-          if (c != 0) return c; continue;
-        case Slot_Byte: 
-          c = Byte.compare(scFs1._getByteValueNc(fi),  scFs2._getByteValueNc(fi));
-          if (c != 0) return c; continue;
-        case Slot_Short: 
-          c = Short.compare(scFs1._getShortValueNc(fi),  scFs2._getShortValueNc(fi));
-          if (c != 0) return c; continue;
-        case Slot_Int:     
-          c = Integer.compare(scFs1._getIntValueNc(fi),  scFs2._getIntValueNc(fi));
-          if (c != 0) return c; continue;
-        case Slot_Float:                               
-          c = Integer.compare(CASImpl.float2int(scFs1._getFloatValueNc(fi)),  
-                              CASImpl.float2int(scFs2._getFloatValueNc(fi)));
-          if (c != 0) return c; continue;
-        case Slot_LongRef:   
-          c = Long.compare(scFs1._getLongValueNc(fi),  scFs2._getLongValueNc(fi));
-          if (c != 0) return c; continue;
-        case Slot_DoubleRef:   
-          c = Long.compare(Double.doubleToRawLongBits(scFs1._getDoubleValueNc(fi)),  
-                           Double.doubleToRawLongBits(scFs2._getDoubleValueNc(fi)));
-          if (c != 0) return c; continue;
-        case Slot_StrRef:  
-          c = Misc.compareStrings(scFs1._getStringValueNc(fi), scFs2._getStringValueNc(fi));
-          if (c != 0) return c; 
-          continue;
-          
-        case Slot_HeapRef: 
-          TOP refFs1 = scFs1._getFeatureValueNc(fi);
-          TOP refFs2 = scFs2._getFeatureValueNc(fi);
-          if (null == refFs1) {
-            if (null == refFs2) {
-              continue;
-            }
-            return -1;
-          } else if (null == refFs2) {
-            return 1;
-          }
-          if (refFs1._getTypeCode() == TypeSystemConstants.sofaTypeCode) {
-            c = Integer.compare(refFs1._id,  refFs2._id);
-            if (c != 0) return c; // approximate
-            continue; 
-          }
-          // refFS1 != null; refFs2 != null; type is not sofaTypeCode
-          if (!prevCompare.add(new Pair<TOP, TOP>(scFs1, scFs2))) {
-            continue; // skip recursion if previously were in the middle of sort-comparing these two elements
-          }
-          return sortCompare(refFs1, refFs2);
-          
-        default: 
-          Misc.internalError(); 
-          return 0;
-        } // end of switch
-      } // end of for loop
-      return 0;
-    } // end of sort compare
-      
-    private int sortArray(TOP afs1, TOP afs2) {
-      int sz1 = ((CommonArrayFS)afs1).size();
-      int sz2 = ((CommonArrayFS)afs2).size();
-      int c = Integer.compare(sz1, sz2);
-      if (c != 0) return c;
-      
-      return Integer.compare(afs1._id, afs2._id);  // an approximation
-    }
-    
-//    private StringBuilder dumpHeapFs(CASImpl cas, final int iHeap, final TypeSystemImpl ts) {
-//      StringBuilder sb = new StringBuilder();
-//      typeInfo = ts.getTypeInfo(cas.getHeap().heap[iHeap]);
-//      sb.append("Heap Addr: ").append(iHeap).append(' ');
-//      sb.append(typeInfo).append(' ');
-//  
-//      if (typeInfo.isHeapStoredArray) {
-//        sb.append(dumpHeapStoredArray(cas, iHeap));
-//      } else if (typeInfo.isArray) {
-//        sb.append(dumpNonHeapStoredArray(cas, iHeap));
-//      } else {
-//        sb.append("   Slots:\n");
-//        for (int i = 1; i < typeInfo.slotKinds.length + 1; i++) {
-//          sb.append("  ").append(typeInfo.getSlotKind(i)).append(": ")
-//              .append(dumpByKind(cas, i, iHeap)).append('\n');
-//        }
-//      }
-//      return sb;
-//    }
-    
-//    private StringBuilder dumpHeapStoredArray(CASImpl cas, final int iHeap) {
-//      StringBuilder sb = new StringBuilder();
-//      int[] heap = cas.getHeap().heap;
-//      final int length = heap[iHeap + 1];
-//      sb.append("Array Length: ").append(length).append('[');
-//      SlotKind arrayElementKind = typeInfo.slotKinds[1];
-//      switch (arrayElementKind) {
-//      case Slot_HeapRef: case Slot_Int: case Slot_Short: case Slot_Byte: 
-//      case Slot_Boolean: case Slot_Float:
-//        for (int i = iHeap + 2; i < iHeap + length + 2; i++) {
-//          if (i > iHeap + 2) {
-//            sb.append(", ");
-//          }
-//          sb.append(heap[i]);
-//        }
-//        break;   
-//      case Slot_StrRef:
-//        StringHeap sh = cas.getStringHeap();
-//        for (int i = iHeap + 2; i < iHeap + length + 2; i++) {
-//          if (i > iHeap + 2) {
-//            sb.append(", ");
-//          }
-//          sb.append(sh.getStringForCode(heap[i]));        
-//        }
-//        break;
-//      default: throw new RuntimeException("internal error");
-//      }
-//      sb.append("] ");
-//      return sb;
-//    }
-//  
-//    private StringBuilder dumpNonHeapStoredArray(CASImpl cas, final int iHeap) {
-//      StringBuilder sb = new StringBuilder();
-//      int[] heap = cas.getHeap().heap;
-//      final int length = heap[iHeap + 1];
-//      sb.append("Array Length: ").append(length).append('[');
-//      SlotKind arrayElementKind = typeInfo.slotKinds[1];
-//      
-//      for (int i = 0; i < length; i++) {
-//        if (i > 0) {
-//          sb.append(", ");
-//        }
-//        switch (arrayElementKind) {
-//        case Slot_BooleanRef: case Slot_ByteRef:
-//          sb.append(cas.getByteHeap().getHeapValue(heap[iHeap + 2 + i]));
-//          break;
-//        case Slot_ShortRef:
-//          sb.append(cas.getShortHeap().getHeapValue(heap[iHeap + 2 + i]));
-//          break;
-//        case Slot_LongRef: case Slot_DoubleRef: {
-//          long v = cas.getLongHeap().getHeapValue(heap[iHeap + 2 + i]);
-//          if (arrayElementKind == Slot_DoubleRef) {
-//            sb.append(CASImpl.long2double(v));
-//          } else {
-//            sb.append(String.format("%,d", v));
-//          }
-//          break;
-//        }
-//        default: throw new RuntimeException("internal error");
-//        }
-//      }
-//      sb.append("] ");
-//      return sb;      
-//    }
-//  
-//    private StringBuilder dumpByKind(CASImpl cas, int offset, final int iHeap) {
-//      StringBuilder sb = new StringBuilder();
-//      int[] heap = cas.getHeap().heap;
-//      SlotKind kind = typeInfo.getSlotKind(offset);
-//      switch (kind) {
-//      case Slot_Int:
-//        return sb.append(heap[iHeap + offset]);
-//      case Slot_Short: 
-//        return sb.append((short)heap[iHeap + offset]);
-//      case Slot_Byte: 
-//        return sb.append((byte)heap[iHeap + offset]);
-//      case Slot_Boolean:  
-//        return sb.append(((heap[iHeap + offset]) == 0) ? false : true);
-//      case Slot_Float: {
-//        int v = heap[iHeap + offset];
-//        return sb.append(Float.intBitsToFloat(v)).append(' ').append(Integer.toHexString(v));
-//      }
-//      case Slot_HeapRef:
-//        return sb.append("HeapRef[").append(heap[iHeap + offset]).append(']');
-//      case Slot_StrRef:
-//        return sb.append(cas.getStringForCode(heap[iHeap + offset]));
-//      case Slot_LongRef:
-//        return sb.append(String.format("%,d", cas.getLongHeap().getHeapValue(heap[iHeap + offset])));
-//      case Slot_DoubleRef: {
-//        long v = cas.getLongHeap().getHeapValue(heap[iHeap + offset]);
-//        return sb.append(CASImpl.long2double(v)).append(' ').append(Long.toHexString(v));
-//      }
-//      default: throw new RuntimeException("internal error");      
-//      }
-//    }
-    
-  } // end of CasCompare class
-  
+   
   /**
    * 
    * @param f can be a DataOutputStream,
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/BuiltinTypeKinds.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/BuiltinTypeKinds.java
similarity index 60%
rename from uimaj-core/src/main/java/org/apache/uima/cas/BuiltinTypeKinds.java
rename to uimaj-core/src/main/java/org/apache/uima/cas/impl/BuiltinTypeKinds.java
index 1c782be..c404f7a 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/BuiltinTypeKinds.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/BuiltinTypeKinds.java
@@ -1,9 +1,35 @@
-package org.apache.uima.cas;

+package org.apache.uima.cas.impl;

 

 import java.util.HashSet;

 import java.util.Set;

 

+import org.apache.uima.cas.CAS;

 import org.apache.uima.internal.util.Misc;

+import org.apache.uima.jcas.cas.AnnotationBase;

+import org.apache.uima.jcas.cas.BooleanArray;

+import org.apache.uima.jcas.cas.ByteArray;

+import org.apache.uima.jcas.cas.DoubleArray;

+import org.apache.uima.jcas.cas.EmptyFSList;

+import org.apache.uima.jcas.cas.EmptyFloatList;

+import org.apache.uima.jcas.cas.EmptyIntegerList;

+import org.apache.uima.jcas.cas.EmptyStringList;

+import org.apache.uima.jcas.cas.FSArray;

+import org.apache.uima.jcas.cas.FSList;

+import org.apache.uima.jcas.cas.FloatArray;

+import org.apache.uima.jcas.cas.FloatList;

+import org.apache.uima.jcas.cas.IntegerArray;

+import org.apache.uima.jcas.cas.IntegerList;

+import org.apache.uima.jcas.cas.LongArray;

+import org.apache.uima.jcas.cas.NonEmptyFSList;

+import org.apache.uima.jcas.cas.NonEmptyFloatList;

+import org.apache.uima.jcas.cas.NonEmptyIntegerList;

+import org.apache.uima.jcas.cas.NonEmptyStringList;

+import org.apache.uima.jcas.cas.ShortArray;

+import org.apache.uima.jcas.cas.Sofa;

+import org.apache.uima.jcas.cas.StringArray;

+import org.apache.uima.jcas.cas.StringList;

+import org.apache.uima.jcas.cas.TOP;

+import org.apache.uima.jcas.tcas.Annotation;

 

 /*

  * Licensed to the Apache Software Foundation (ASF) under one

@@ -50,13 +76,50 @@
    */

   public static final Set<String> nonCreatableTypesAndBuiltinArrays = new HashSet<String>();

   

+  public static final Set<String> creatableBuiltinJCasClassNames = new HashSet<>();

+  

+  static {

+    Misc.addAll( creatableBuiltinJCasClassNames, 

+        BooleanArray.class.getName(),

+        ByteArray.class.getName(),

+        ShortArray.class.getName(),

+        IntegerArray.class.getName(),

+        LongArray.class.getName(),

+        FloatArray.class.getName(),

+        DoubleArray.class.getName(),

+        StringArray.class.getName(),

+        FSArray.class.getName(),

+        

+        EmptyFloatList.class.getName(),

+        NonEmptyFloatList.class.getName(),

+        FloatList.class.getName(),

+        EmptyIntegerList.class.getName(),

+        NonEmptyIntegerList.class.getName(),

+        IntegerList.class.getName(),

+        EmptyStringList.class.getName(),

+        NonEmptyStringList.class.getName(),

+        StringList.class.getName(),

+        EmptyFSList.class.getName(),

+        NonEmptyFSList.class.getName(),

+        FSList.class.getName(),

+        

+        TOP.class.getName(),

+        AnnotationBase.class.getName(),

+        Annotation.class.getName(),

+        

+        Sofa.class.getName(),

+        // no default class for next in the classpath

+        "org.apache.uima.jcas.tcas.DocumentAnnotation"

+        );

+  }

+  

   /**

    * These types are

    *   - builtin, but could be extended by user 

    *   - creatable - so they need a generator.

    *     -- non-creatable built-in types are not generated 

    */

-  public static final Set<String> creatableBuiltinJCas = new HashSet<String>();

+  public static final Set<String> creatableBuiltinJCas = new HashSet<>();

 

   static {

     Misc.addAll(primitiveTypeNames, 

@@ -96,6 +159,8 @@
         CAS.TYPE_NAME_TOP,

         CAS.TYPE_NAME_ANNOTATION_BASE,

         CAS.TYPE_NAME_ANNOTATION

+//        CAS.TYPE_NAME_DOCUMENT_ANNOTATION  // https://issues.apache.org/jira/browse/UIMA-5586

+         // these are semi-builtin (for backwards compatibility - not to change users type system codes if not used)

 //        CAS.TYPE_NAME_FS_ARRAY_LIST,

 //        CAS.TYPE_NAME_INT_ARRAY_LIST,

 //        CAS.TYPE_NAME_FS_HASH_SET

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java
index c82e3c9..6c6556d 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java
@@ -33,6 +33,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -42,6 +43,7 @@
 import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
+import java.util.Spliterator;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
@@ -116,6 +118,7 @@
 import org.apache.uima.jcas.impl.JCasHashMap;
 import org.apache.uima.jcas.impl.JCasImpl;
 import org.apache.uima.jcas.tcas.Annotation;
+import org.apache.uima.util.AutoCloseableNoException;
 import org.apache.uima.util.Level;
 
 /**
@@ -125,10 +128,13 @@
  * 
  */
 public class CASImpl extends AbstractCas_ImplBase implements CAS, CASMgr, LowLevelCAS, TypeSystemConstants {
-  
-  public static final boolean IS_USE_V2_IDS = false;  // if false, ids increment by 1
+
+  private static final String TRACE_FSS = "uima.trace_fs_creation_and_updating";
+//  public static final boolean IS_USE_V2_IDS = false;  // if false, ids increment by 1
   private static final boolean trace = false; // debug
-  public static final boolean traceFSs = false;  // debug - trace FS creation and update
+  public static final boolean traceFSs = // false;  // debug - trace FS creation and update
+      Misc.getNoValueSystemProperty(TRACE_FSS);
+  
   public static final boolean traceCow = false;  // debug - trace copy on write actions, index adds / deletes 
   private static final String traceFile = "traceFSs.log.txt";
   private static final PrintStream traceOut;
@@ -217,8 +223,8 @@
       !IS_REPORT_FS_UPDATE_CORRUPTS_INDEX &&
       !IS_THROW_EXCEPTION_CORRUPT_INDEX;
  
-  public static final String ALWAYS_HOLD_ONTO_FSS = "uima.enable_id_to_feature_structure_map_for_all_fss";
-  static final boolean IS_ALWAYS_HOLD_ONTO_FSS =    // debug
+  public static final String ALWAYS_HOLD_ONTO_FSS = "uima.default_v2_id_references";
+  static final boolean IS_ALWAYS_HOLD_ONTO_FSS =    // debug and users of low-level cas apis with deserialization
       Misc.getNoValueSystemProperty(ALWAYS_HOLD_ONTO_FSS);
 //  private static final int REF_DATA_FOR_ALLOC_SIZE = 1024;
 //  private static final int INT_DATA_FOR_ALLOC_SIZE = 1024;
@@ -232,7 +238,14 @@
     new DebugNameValuePair(null, null);
     new DebugFSLogicalStructure();
   }
-
+  
+  private final static ThreadLocal<Boolean> defaultV2IdRefs = 
+      InheritableThreadLocal.withInitial(() -> null);
+  
+  public static ThreadLocal<Boolean> getDefaultV2IdRefs() {
+    return defaultV2IdRefs;
+  }
+  
   // Static classes representing shared instance data
   // - shared data is computed once for all views
   
@@ -460,7 +473,7 @@
      * The version 2 size on the main heap of the last created FS
      */
     private int lastFsV2Size = 1;
-    
+
     /**
      * used to "capture" the fsIdGenerator value for a read-only CAS to be visible in
      * other threads
@@ -472,7 +485,7 @@
     private final AtomicInteger casResets = new AtomicInteger(0);
     
     // unique ID for a created CAS view, not updated if CAS is reset and reused
-    private final int casId = casIdProvider.incrementAndGet();
+    private final String casId = String.valueOf(casIdProvider.incrementAndGet());
     
     // shared singltons, created at type system commit
     
@@ -480,6 +493,16 @@
     private EmptyFloatList emptyFloatList;
     private EmptyIntegerList emptyIntegerList;
     private EmptyStringList emptyStringList;
+    
+    private FloatArray emptyFloatArray;
+    private FSArray emptyFSArray;
+    private IntegerArray emptyIntegerArray;
+    private StringArray emptyStringArray;
+    private DoubleArray emptyDoubleArray;
+    private LongArray emptyLongArray;
+    private ShortArray emptyShortArray;
+    private ByteArray emptyByteArray;
+    private BooleanArray emptyBooleanArray;
 
     /**
      * Created at startup time, lives as long as the CAS lives
@@ -521,7 +544,14 @@
     private final IntVector id2addr = traceFSs ? new IntVector() : null;
     private int nextId2Addr = 1;  // only for tracing, to convert id's to v2 addresses
     final private int initialHeapSize;
-    
+    /** if true, 
+     *    modify fs creation to save in id2fs map
+     *    modify deserializers to create fss with ids the same as the serialized form (
+     *      or the V2 "address" imputed from that)
+     *    modify serializers to include reachables only found via id2fs table
+     */
+    private boolean isId2Fs;
+                
     private SharedViewData(CASImpl baseCAS, int initialHeapSize, TypeSystemImpl tsi) {
       this.baseCAS = baseCAS;
       this.tsi = tsi;
@@ -529,11 +559,17 @@
       bcsd = new BinaryCasSerDes(baseCAS);
       id2fs = new Id2FS(initialHeapSize);
       if (traceFSs) id2addr.add(0);
+      
+      Boolean v = getDefaultV2IdRefs().get();
+      isId2Fs = (v == null) 
+                  ? IS_ALWAYS_HOLD_ONTO_FSS
+                  : v;
     }
     
     void clearCasReset() {
       // fss
       fsIdGenerator = 0;
+      lastFsV2Size = 1;
       id2fs.clear();
       
       // pear caches
@@ -562,6 +598,23 @@
         id2addr.add(0);
         nextId2Addr = 1;
       }
+      
+      emptyFloatList = null; // these cleared in case new ts redefines?
+      emptyFSList = null;
+      emptyIntegerList = null;
+      emptyStringList = null;
+      
+      emptyFloatArray = null;
+      emptyFSArray = null;
+      emptyIntegerArray = null;
+      emptyStringArray = null;
+      emptyDoubleArray = null;
+      emptyLongArray = null;
+      emptyShortArray = null;
+      emptyByteArray = null;
+      emptyBooleanArray = null;
+  
+      clearNonSharedInstanceData();
     }
     
     /**
@@ -584,19 +637,13 @@
      *   
      */
     void clear() {
-      clearCasReset();
-      clearTrackingMarks();
-      
+      resetNoQuestions(false);  // false - skip flushing the index repos
+
       // type system + index spec
       tsi = null;
       featureCodesInIndexKeys.clear();
 //      featureJiInIndexKeys.clear();
-      emptyFloatList = null; // these cleared in case new ts redefines?
-      emptyFSList = null;
-      emptyIntegerList = null;
-      emptyStringList = null;
       
-      clearSofaInfo();
       
       /**
        * Clear the existing views, except keep the info for the initial view
@@ -613,8 +660,57 @@
         sofaNbr2ViewMap.clear();
         viewCount = 0;
       }
+      
     }
     
+    private void resetNoQuestions(boolean flushIndexRepos) {
+      casResets.incrementAndGet();
+      if (trace) {
+        System.out.println("CAS Reset in thread " + Thread.currentThread().getName() +
+           " for CasId = " + casId + ", new reset count = " + casResets.get());
+      }
+
+      clearCasReset(); // also clears cached FSs
+       
+      if (flushIndexRepos) {
+        flushIndexRepositoriesAllViews();
+      }
+      
+      clearTrackingMarks();
+      
+      clearSofaInfo();  // but keep initial view, and other views
+                                 // because setting up the index infrastructure is expensive
+      viewCount = 1;  // initial view
+      
+      traceFSid = 0;
+      if (traceFSs) traceFScreationSb.setLength(0);
+      componentInfo = null; // https://issues.apache.org/jira/browse/UIMA-5097
+    }
+    
+    private void flushIndexRepositoriesAllViews() {
+      int numViews = viewCount;
+      for (int view = 1; view <= numViews; view++) {
+        CASImpl tcas = (CASImpl) ((view == 1) ? getInitialView() : getViewFromSofaNbr(view));
+        if (tcas != null) {
+          tcas.indexRepository.flush();
+        }
+      }
+      
+   // safety : in case this public method is called on other than the base cas 
+      baseCAS.indexRepository.flush();  // for base view, other views flushed above
+    }
+    
+    private void clearNonSharedInstanceData() {
+      int numViews = viewCount;
+      for (int view = 1; view <= numViews; view++) {
+        CASImpl tcas = (CASImpl) ((view == 1) ? getInitialView() : getViewFromSofaNbr(view));
+        if (tcas != null) {         
+          tcas.mySofaRef = null;  // was in v2: (1 == view) ? -1 : 0;
+          tcas.docAnnotIter = null;
+        }
+      }      
+    }
+       
     private void clearTrackingMarks() {
       // resets all markers that might be held by things outside the Cas
       // Currently (2009) this list has a max of 1 element
@@ -670,10 +766,29 @@
       id2tramp = null;
     }
     
+    /**
+     * The logic for this is:
+     *   - normal - add 1 to the value of the previous 
+     *              which is kept in fsIdGenerator
+     *              Update fsIdGenerator to be this id.
+     *              (maybe) set lastFsV2Size to the size of this FS in v2
+     *   - pear trampolines: use the exact same id as the main fs.
+     *            This value is in reuseId.  
+     *            In this case, no computation of "next" is done
+     *   - isId2Fs This is set if in special mode to emulate v2 addresses.  
+     *       - used for backwards compatibility when LowLevelCas getFSForRef calls in use
+     *       - used for debugging v2 vs v3 runs
+     *       - causes fsId to be set to a value which should match the v2 address
+     * Side effect: when doing v2 emulation, updates the lastFsV2Size
+     * @param fs - the fs, used to compute its "size" on the v2 heap when emulating v2 addresses
+     * @return the id to use
+     */
     private int getNextFsId(TOP fs) {
-      if (reuseId != 0) {
+      if (reuseId != 0) {  // for pear use
 //      l.setStrongRef(fs, reuseId);
-      return reuseId;
+        int r = reuseId;
+        reuseId = 0;
+        return r;  // reuseId reset to 0 by callers' try/finally block
       } 
       
   //    l.add(fs);
@@ -683,19 +798,58 @@
   //    assert(l.size() == (2 + fsIdGenerator));
       final int p = fsIdGenerator;
       
-      final int r = fsIdGenerator += IS_USE_V2_IDS 
-                                       ? lastFsV2Size
-                                       : 1;
+      final int r = fsIdGenerator = peekNextFsId();
+      
       if (r < p) { 
         throw new RuntimeException("UIMA Cas Internal id value overflowed maximum int value");
       }
-      if (IS_USE_V2_IDS) {
+      
+      if (isId2Fs) {
         // this computation is partial - misses length of arrays stored on heap
-        // because that info not yet available
+        // because that info not yet available  
+        // It is added later via call to adjustLastFsV2size(int)
         lastFsV2Size = fs._getTypeImpl().getFsSpaceReq();
       }
       return r;
     }
+    
+    /**
+     * @return the lastUsedFsId + the size of that or 1
+     */
+    int peekNextFsId() {
+      return fsIdGenerator + lastFsV2IdIncr();
+    }
+    
+    int lastFsV2IdIncr() {
+      return (isId2Fs ? lastFsV2Size : 1);
+    }
+    
+    private CASImpl getViewFromSofaNbr(int nbr) {
+      final ArrayList<CASImpl> sn2v = sofaNbr2ViewMap;
+      if (nbr < sn2v.size()) {
+        return sn2v.get(nbr);
+      }
+      return null;
+    }
+    
+    // For internal platform use only
+    CASImpl getInitialView() {
+      CASImpl couldBeThis = getViewFromSofaNbr(1);
+      if (couldBeThis != null) {
+        return couldBeThis;
+      }
+      // create the initial view, without a Sofa
+      CASImpl aView = new CASImpl(baseCAS, (SofaFS) null);
+      setViewForSofaNbr(1, aView);
+      assert (viewCount <= 1);
+      viewCount = 1;
+      return aView;
+    }
+    
+    void setViewForSofaNbr(int nbr, CASImpl view) {
+      Misc.setWithExpand(sofaNbr2ViewMap, nbr, view);
+    }
+
   }
   
   /*****************************************************************
@@ -743,6 +897,13 @@
    */
   FeatureStructureImplC pearBaseFs = null;
   
+  /**
+   * Optimization - keep a documentAnnotationIterator handy for getting a ref to the doc annot
+   *   Initialized lazily, synchronized
+   *   One per cas view
+   */
+  private volatile FSIterator<Annotation> docAnnotIter = null;
+  
 //  private StackTraceElement[] addbackSingleTrace = null;  // for debug use only, normally commented out  
 
   // CASImpl(TypeSystemImpl typeSystem) {
@@ -892,6 +1053,30 @@
   // ----------------------------------------
   //   accessors for data in SharedViewData
   // ----------------------------------------
+   
+  public boolean isId2Fs() {
+    return svd.isId2Fs;
+  }
+  
+  Id2FS getId2FSs() {
+    return svd.id2fs;
+  }
+  
+  void set_id2fs(TOP fs) {
+    svd.id2fs.put(fs);
+  }
+  
+  void set_reuseId(int id) {
+    svd.reuseId = id;
+  }
+  
+  void setLastUsedFsId(int id) {
+    svd.fsIdGenerator = id;
+  }
+  
+  void setLastFsV2Size(int size) {
+    svd.lastFsV2Size = size;
+  }
   
   void addSofaViewName(String id) {
     svd.sofaNameSet.add(id);
@@ -949,11 +1134,11 @@
   }
 
   @Override
-  public TypeSystem getTypeSystem() {
+  public final TypeSystem getTypeSystem() {
     return getTypeSystemImpl();
   }
 
-  public TypeSystemImpl getTypeSystemImpl() {
+  public final TypeSystemImpl getTypeSystemImpl() {
     if (tsi_local == null) {
       tsi_local = this.svd.tsi;
     }
@@ -1056,17 +1241,9 @@
   }
  
   private TOP createFsFromGenerator(FsGenerator3[] gs, TypeImpl ti) {
-//    if (ti == null || gs == null || gs[ti.getCode()] == null) {
-//      System.out.println("debug");
-//    }
     return gs[ti.getCode()].createFS(ti, this);
   }
   
-//  public int ll_createFSAnnotCheck(int typeCode) {
-//    TOP fs = createFSAnnotCheck(getTypeFromCode(typeCode));
-//    svd.id2fs.put(fs);  // required for low level, in order to "hold onto" / prevent GC of FS
-//    return fs._id;
-//  }
   
   public TOP createArray(TypeImpl array_type, int arrayLength) {
     TypeImpl_array tia = (TypeImpl_array) array_type;
@@ -1082,15 +1259,19 @@
       case longTypeCode: return new LongArray(array_type, this, arrayLength);
       case doubleTypeCode: return new DoubleArray(array_type, this, arrayLength);
       case stringTypeCode: return new StringArray(array_type, this, arrayLength);
-//      case javaObjectTypeCode: return new JavaObjectArray(array_type, this, arrayLength);
-      default: Misc.internalError();
+      default: throw Misc.internalError();
       }
-//      return tia.getGeneratorArray().createFS(type, this, arrayLength); 
-//      return (((FsGeneratorArray)getFsGenerator(type.getCode())).createFS(type, this, arrayLength));
     }
     return (TOP) createArrayFS(array_type, arrayLength);
   }
 
+  /* 
+   * ===============  These methods might be deprecated in favor of
+   *                  new FSArray(jcas, length) etc.
+   *                  except that these run with the CAS, not JCas 
+   * (non-Javadoc)
+   * @see org.apache.uima.cas.CAS#createArrayFS(int)
+   */
   @Override
   public ArrayFS createArrayFS(int length) {
     return createArrayFS(getTypeSystemImpl().fsArrayType, length);
@@ -1099,8 +1280,6 @@
   private ArrayFS createArrayFS(TypeImpl type, int length) {
     checkArrayPreconditions(length);
     return new FSArray(type, this, length);         
-//        getTypeSystemImpl().fsArrayType.getGeneratorArray()         // (((FsGeneratorArray)getFsGenerator(fsArrayTypeCode))
-//        .createFS(type, this, length);
   }
   
   @Override
@@ -1121,11 +1300,6 @@
     return new StringArray(getTypeSystemImpl().stringArrayType, this, length);
   }
   
-//  public JavaObjectArray createJavaObjectArrayFS(int length) {
-//    checkArrayPreconditions(length);
-//    return new JavaObjectArray(getTypeSystemImpl().javaObjectArrayType, this, length);
-//  }
-
 
   // return true if only one sofa and it is the default text sofa
   public boolean isBackwardCompatibleCas() {
@@ -1233,6 +1407,10 @@
     }
     return sofa;
   }
+  
+  boolean hasView(String name) {
+    return this.svd.sofaNameSet.contains(name);
+  }
 
   Sofa createInitialSofa(String mimeType) { 
     Sofa sofa = createSofa(1, CAS.NAME_DEFAULT_SOFA, mimeType);
@@ -1388,7 +1566,7 @@
       }
 
       default:
-        Misc.internalError();
+        throw Misc.internalError();
       }
       
       ByteArrayInputStream bis = new ByteArrayInputStream(buf.array());
@@ -1411,7 +1589,7 @@
     return new FilteredIterator<T>(it, cons);
   }
 
-  public TypeSystemImpl commitTypeSystem() {
+  public TypeSystemImpl commitTypeSystem(boolean skip_loading_user_jcas) {
     TypeSystemImpl ts = getTypeSystemImpl();
     // For CAS pools, the type system could have already been committed
     // Skip the initFSClassReg if so, because it may have been updated to a JCas
@@ -1423,19 +1601,28 @@
     // at the same time
     final ClassLoader cl = getJCasClassLoader();
     synchronized (ts) {
+//      //debug
+//      System.out.format("debug committing ts %s classLoader %s%n", ts.hashCode(), cl);
       if (!ts.isCommitted()) {
+        ts.set_skip_loading_user_jcas(skip_loading_user_jcas);
         TypeSystemImpl tsc = ts.commit(getJCasClassLoader());
         if (tsc != ts) {
           installTypeSystemInAllViews(tsc);
           ts = tsc;
         }
-      }
-    }       
-    svd.baseGenerators = svd.generators = ts.getGeneratorsForClassLoader(cl, false);  // false - not PEAR
+      } 
+    } 
+    svd.baseGenerators = svd.generators = ts.getGeneratorsForClassLoader(cl, false);  // false - not PEAR            
+        
     createIndexRepository();
     return ts;
+    
   }
-
+  
+  public TypeSystemImpl commitTypeSystem() {
+    return commitTypeSystem(false);
+  }
+  
   private void createIndexRepository() {
     if (!this.getTypeSystemMgr().isCommitted()) {
       throw new CASAdminException(CASAdminException.MUST_COMMIT_TYPE_SYSTEM);
@@ -1490,41 +1677,7 @@
   }
 
   public void resetNoQuestions() {
-    svd.casResets.incrementAndGet();
-    svd.clearCasReset();
-    if (trace) {
-      System.out.println("CAS Reset in thread " + Thread.currentThread().getName() +
-         " for CasId = " + getCasId() + ", new reset count = " + svd.casResets.get());
-    }
-    
-    int numViews = this.getViewCount();
-    // Flush indexRepository for all views
-    for (int view = 1; view <= numViews; view++) {
-      CASImpl tcas = (CASImpl) ((view == 1) ? getInitialView() : getView(view));
-      if (tcas != null) {
-        tcas.indexRepository.flush();
-        
-        // mySofaRef = -1 is a flag in initial view that sofa has not been set.
-        // For the initial view, it is possible to not have a sofa - it is set
-        // "lazily" upon the first need.
-        // all other views always have a sofa set. The sofaRef is set to 0,
-        // but will be set to the actual sofa addr in the cas when the view is
-        // initialized.
-        
-        tcas.mySofaRef = null;  // was in v2: (1 == view) ? -1 : 0;
-      }
-    }
-    this.svd.clearTrackingMarks();
-    
-    // safety : in case this public method is called on other than the base cas 
-    this.getBaseCAS().indexRepository.flush();  // for base view, other views flushed above
-    this.svd.clearSofaInfo();  // but keep initial view, and other views
-                               // because setting up the index infrastructure is expensive
-    this.svd.viewCount = 1;  // initial view
-    
-    svd.traceFSid = 0;
-    if (traceFSs) svd.traceFScreationSb.setLength(0);
-    this.svd.componentInfo = null; // https://issues.apache.org/jira/browse/UIMA-5097
+    svd.resetNoQuestions(true);
   }
 
   /**
@@ -1573,7 +1726,8 @@
    */
   @Override
   public <T extends FeatureStructure> ListIterator<T> fs2listIterator(FSIterator<T> it) {
-    return new FSListIteratorImpl<T>(it);
+//    return new FSListIteratorImpl<T>(it);
+    return it;  // in v3, FSIterator extends listIterator
   }
 
   /**
@@ -1719,12 +1873,12 @@
    * @param fi -
    * @param setter -
    */
-  public void setWithJournal(FeatureStructureImplC fs, FeatureImpl fi, Runnable setter) {
+  public final void setWithJournal(FeatureStructureImplC fs, FeatureImpl fi, Runnable setter) {
     setter.run();
     maybeLogUpdate(fs, fi);
   }
   
-  public boolean isLoggingNeeded(FeatureStructureImplC fs) {
+  public final boolean isLoggingNeeded(FeatureStructureImplC fs) {
     return this.svd.trackingMark != null && !this.svd.trackingMark.isNew(fs._id);
   }
   
@@ -1754,7 +1908,7 @@
    * @param startingIndex -
    * @param length number of consequtive items
    */
-  public void maybeLogArrayUpdates(FeatureStructureImplC fs, int startingIndex, int length) {
+  public final void maybeLogArrayUpdates(FeatureStructureImplC fs, int startingIndex, int length) {
     if (isLoggingNeeded(fs)) {
       this.logFSUpdate((TOP) fs, null, startingIndex, length);
     }
@@ -1831,12 +1985,44 @@
   }
   
   /**
+   * internal use - special setter for setting feature values, including
+   *   special handling if the feature is for the sofaArray,
+   *   when deserializing
+   * @param fs - 
+   * @param feat -
+   * @param value -
+   */
+  public static void setFeatureValueMaybeSofa(TOP fs, FeatureImpl feat, TOP value) {
+    if (fs instanceof Sofa) {
+      assert feat.getCode() == sofaArrayFeatCode;
+      ((Sofa)fs).setLocalSofaData(value);
+    } else {
+      fs.setFeatureValue(feat, value);
+    }
+  }
+  
+  /**
+   * Internal use, for cases where deserializing - special case setting sofString to skip updating the document annotation
+   * @param fs -
+   * @param feat -
+   * @param s -
+   */
+  public static void setFeatureValueFromStringNoDocAnnotUpdate(FeatureStructureImplC fs, FeatureImpl feat, String s) {
+    if (fs instanceof Sofa && 
+        feat.getCode() == sofaStringFeatCode) {
+      ((Sofa)fs).setLocalSofaDataNoDocAnnotUpdate(s);
+    } else {
+      setFeatureValueFromString(fs, feat, s);
+    }
+  }
+  
+  /**
    * Supports setting slots to "0" for null values
    * @param fs The feature structure to update
    * @param feat the feature to update-
    * @param s the string representation of the value, could be null
    */
-  public void setFeatureValueFromString(FeatureStructureImplC fs, FeatureImpl feat, String s) {
+  public static void setFeatureValueFromString(FeatureStructureImplC fs, FeatureImpl feat, String s) {
     final TypeImpl range = feat.getRangeImpl();
     if (fs instanceof Sofa) {
       // sofa has special setters
@@ -1907,79 +2093,83 @@
   }
 
   // Type access methods.
-  public boolean isStringType(Type type) {
+  public final boolean isStringType(Type type) {
     return type instanceof TypeImpl_string;
   }
 
-  public boolean isArrayOfFsType(Type type) {
+  public final boolean isAbstractArrayType(Type type) {
+    return isArrayType(type); 
+  }
+  
+  public final boolean isArrayType(Type type) {
     return ((TypeImpl) type).isArray();
   }
 
-  public boolean isPrimitiveArrayType(Type type) {
+  public final boolean isPrimitiveArrayType(Type type) {
     return (type instanceof TypeImpl_array) && ! type.getComponentType().isPrimitive();
   }
 
-  public boolean isIntArrayType(Type type) {
+  public final boolean isIntArrayType(Type type) {
     return (type == getTypeSystemImpl().intArrayType);
   }
 
-  public boolean isFloatArrayType(Type type) {
+  public final boolean isFloatArrayType(Type type) {
     return ((TypeImpl)type).getCode() == floatArrayTypeCode;
   }
 
-  public boolean isStringArrayType(Type type) {
+  public final boolean isStringArrayType(Type type) {
     return ((TypeImpl)type).getCode() == stringArrayTypeCode;
   }
 
-  public boolean isBooleanArrayType(Type type) {
+  public final boolean isBooleanArrayType(Type type) {
     return ((TypeImpl)type).getCode() == booleanArrayTypeCode;
   }
 
-  public boolean isByteArrayType(Type type) {
+  public final boolean isByteArrayType(Type type) {
     return ((TypeImpl)type).getCode() == byteArrayTypeCode;
   }
 
-  public boolean isShortArrayType(Type type) {
+  public final boolean isShortArrayType(Type type) {
     return ((TypeImpl)type).getCode() == byteArrayTypeCode;
   }
 
-  public boolean isLongArrayType(Type type) {
+  public final boolean isLongArrayType(Type type) {
     return ((TypeImpl)type).getCode() == longArrayTypeCode;
   }
 
-  public boolean isDoubleArrayType(Type type) {
+  public final boolean isDoubleArrayType(Type type) {
     return ((TypeImpl)type).getCode() == doubleArrayTypeCode;
   }
 
-  public boolean isFSArrayType(Type type) {
+  public final boolean isFSArrayType(Type type) {
     return ((TypeImpl)type).getCode() == fsArrayTypeCode;
   }
 
-  public boolean isIntType(Type type) {
+  public final boolean isIntType(Type type) {
     return ((TypeImpl)type).getCode() == intTypeCode;
   }
 
-  public boolean isFloatType(Type type) {
+  public final boolean isFloatType(Type type) {
     return ((TypeImpl)type).getCode() == floatTypeCode;
   }
 
-  public boolean isByteType(Type type) {
+  public final boolean isByteType(Type type) {
     return ((TypeImpl)type).getCode() == byteTypeCode;
   }
 
-  public boolean isBooleanType(Type type) {
+  public final boolean isBooleanType(Type type) {
     return ((TypeImpl)type).getCode() == floatTypeCode;
   }
 
-  public boolean isShortType(Type type) {
+  public final boolean isShortType(Type type) {
     return ((TypeImpl)type).getCode() == shortTypeCode;
   }
 
-  public boolean isLongType(Type type) {
+  public final boolean isLongType(Type type) {
     return ((TypeImpl)type).getCode() == longTypeCode;
   }
 
-  public boolean isDoubleType(Type type) {
+  public final boolean isDoubleType(Type type) {
     return ((TypeImpl)type).getCode() == doubleTypeCode;
   }
 
@@ -2014,7 +2204,7 @@
 
   // For internal use only
   public CAS getView(int sofaNum) {
-    return getViewFromSofaNbr(sofaNum);
+    return svd.getViewFromSofaNbr(sofaNum);
   }
 
   
@@ -2079,30 +2269,9 @@
     return getJCas(sofa);
   }
   
-  private CASImpl getViewFromSofaNbr(int nbr) {
-    final ArrayList<CASImpl> sn2v = this.svd.sofaNbr2ViewMap;
-    if (nbr < sn2v.size()) {
-      return sn2v.get(nbr);
-    }
-    return null;
-  }
-  
-  void setViewForSofaNbr(int nbr, CASImpl view) {
-    Misc.setWithExpand(this.svd.sofaNbr2ViewMap, nbr, view);
-  }
-
   // For internal platform use only
   CASImpl getInitialView() {
-    CASImpl couldBeThis = getViewFromSofaNbr(1);
-    if (couldBeThis != null) {
-      return couldBeThis;
-    }
-    // create the initial view, without a Sofa
-    CASImpl aView = new CASImpl(this.svd.baseCAS, (SofaFS) null);
-    setViewForSofaNbr(1, aView);
-    assert (this.svd.viewCount <= 1);
-    this.svd.viewCount = 1;
-    return aView;
+    return svd.getInitialView();
   }
 
   @Override
@@ -2176,7 +2345,7 @@
     final int sofaNbr = sofa.getSofaRef();
 //    final Integer sofaNbrInteger = Integer.valueOf(sofaNbr);
 
-    CASImpl aView = getViewFromSofaNbr(sofaNbr);
+    CASImpl aView = svd.getViewFromSofaNbr(sofaNbr);
     if (null == aView) {
       // This is the deserializer case, or the case where an older API created a
       // sofa,
@@ -2184,7 +2353,7 @@
 
       // create a new CAS view
       aView = new CASImpl(this.svd.baseCAS, sofa);
-      setViewForSofaNbr(sofaNbr, aView);
+      svd.setViewForSofaNbr(sofaNbr, aView);
       verifySofaNameUniqueIfDeserializedViewAdded(sofaNbr, sofa);
       return aView;
     }
@@ -2389,11 +2558,7 @@
     }
     TOP fs = (TOP) createFS(ti);
     if (!fs._isPearTrampoline()) {
-      if (IS_ALWAYS_HOLD_ONTO_FSS) {
-        svd.id2fs.putUnconditionally(fs);  // hold on to it if nothing else is
-      } else {
-        svd.id2fs.put(fs);
-      }
+      setId2FsMaybeUnconditionally(fs);
     }
     return fs._id;
   }
@@ -2425,11 +2590,7 @@
   @Override
   public int ll_createArray(int typeCode, int arrayLength) {
     TOP fs = createArray(getTypeFromCode_checked(typeCode), arrayLength);
-    if (IS_ALWAYS_HOLD_ONTO_FSS) {
-      svd.id2fs.putUnconditionally(fs);
-    } else {
-      svd.id2fs.put(fs);
-    }
+    setId2FsMaybeUnconditionally(fs);
     return fs._id;      
   }
 
@@ -2456,7 +2617,7 @@
   @Override
   public int ll_createByteArray(int arrayLength) {
     TOP fs = createArray(getTypeSystemImpl().byteArrayType, arrayLength);
-    svd.id2fs.put(fs);
+    set_id2fs(fs);
     return fs._id;
   }
 
@@ -2467,7 +2628,7 @@
   @Override
   public int ll_createBooleanArray(int arrayLength) {
     TOP fs = createArray(getTypeSystemImpl().booleanArrayType, arrayLength);
-    svd.id2fs.put(fs);
+    set_id2fs(fs);
     return fs._id;
   }
 
@@ -2478,7 +2639,7 @@
   @Override
   public int ll_createShortArray(int arrayLength) {
     TOP fs = createArray(getTypeSystemImpl().shortArrayType, arrayLength);
-    svd.id2fs.put(fs);
+    set_id2fs(fs);
     return fs._id;
   }
 
@@ -2489,7 +2650,7 @@
   @Override
   public int ll_createLongArray(int arrayLength) {
     TOP fs = createArray(getTypeSystemImpl().longArrayType, arrayLength);
-    svd.id2fs.put(fs);
+    set_id2fs(fs);
     return fs._id;
   }
 
@@ -2500,7 +2661,7 @@
   @Override
   public int ll_createDoubleArray(int arrayLength) {
     TOP fs = createArray(getTypeSystemImpl().doubleArrayType, arrayLength);
-    svd.id2fs.put(fs);
+    set_id2fs(fs);
     return fs._id;
   }
 
@@ -2520,7 +2681,7 @@
       }
     }
     TOP fs = createArray(ti, arrayLength);
-    svd.id2fs.put(fs);
+    set_id2fs(fs);
     return fs._id;
   }
   
@@ -3857,7 +4018,7 @@
   
   public int ll_createAnnotation(int typeCode, int begin, int end) {
     TOP fs = createAnnotation(getTypeFromCode(typeCode), begin, end);
-    svd.id2fs.put(fs); // to prevent gc from reclaiming
+    set_id2fs(fs); // to prevent gc from reclaiming
     return fs._id();
   }
   
@@ -3984,7 +4145,7 @@
   
   /**
    * Generic issue:  The returned document annotation could be either an instance of 
-   *   DocumentAnnotation or an instance of Annotation - the Java cover class used for 
+   *   DocumentAnnotation or a subclass of it, or an instance of Annotation - the Java cover class used for 
    *   annotations when JCas is not being used.
    */
   @Override
@@ -4002,28 +4163,37 @@
       // base CAS has no document
       return null;
     }
-    FSIterator<T> it = this.<T>getAnnotationIndex(getTypeSystemImpl().docType).iterator();
+    FSIterator<Annotation> it = getDocAnnotIter();
+    it.moveToFirst();  // revalidate in case index updated
     if (it.isValid()) {
-      return it.get();
+      Annotation r = it.get();
+      return (T) (inPearContext() 
+                  ? pearConvert(r)
+                  : r);
     }
     return null;
   }
-  
+
+  private FSIterator<Annotation> getDocAnnotIter() {
+    if (docAnnotIter != null) {
+      return docAnnotIter;
+    }
+    synchronized (this) {
+      if (docAnnotIter == null) {
+        docAnnotIter = this.<Annotation>getAnnotationIndex(getTypeSystemImpl().docType).iterator();
+      }
+      return docAnnotIter;
+    }
+  }
   /**
    * 
    * @return the fs addr of the document annotation found via the index, or 0 if not there
    */
   public int ll_getDocumentAnnotation() {
-    if (this == this.svd.baseCAS) {
-      // base CAS has no document
-      return 0;
-    }
-    
-    FSIterator<FeatureStructure> it = getIndexRepository().getIndex(CAS.STD_ANNOTATION_INDEX, getTypeSystemImpl().docType).iterator();
-    if (it.isValid()) {
-      return it.get()._id();
-    }
-    return 0;
+    AnnotationFS r = getDocumentAnnotationNoCreate();
+    return (r == null) 
+             ? 0
+             : r._id();
   }
   
   @Override
@@ -4102,7 +4272,7 @@
 
   @Override
   public String getViewName() {
-    return (this == getViewFromSofaNbr(1)) ? CAS.NAME_DEFAULT_SOFA :
+    return (this == svd.getViewFromSofaNbr(1)) ? CAS.NAME_DEFAULT_SOFA :
            mySofaIsValid() ? mySofaRef.getSofaID() : 
            null; 
   }
@@ -4113,8 +4283,8 @@
 
   void setDocTextFromDeserializtion(String text) {
     if (mySofaIsValid()) {
-      SofaFS sofa = getSofaRef();  // creates sofa if doesn't already exist
-      sofa.setLocalSofaData(text);
+      Sofa sofa = getSofaRef();  // creates sofa if doesn't already exist
+      sofa.setLocalSofaDataNoDocAnnotUpdate(text);
     }
   }
 
@@ -4405,15 +4575,15 @@
    * protectIndexes
    * 
    * Within the scope of protectIndexes, 
-   *   feature updates are checked, and if found to be a key, and the FS is in a corruptable index,
+   *   feature updates are checked, and if found to be a key, and the FS is in a corruptible index,
    *     then the FS is removed from the indexes (in all necessary views) (perhaps multiple times
    *     if the FS was added to the indexes multiple times), and this removal is recorded on
    *     an new instance of FSsTobeReindexed appended to fssTobeAddedback.
    *     
-   *   Later, when the protectIndexes is closed, the tobe items are added back to the indies.
+   *   Later, when the protectIndexes is closed, the tobe items are added back to the indexes.
    */
   @Override
-  public AutoCloseable protectIndexes() {
+  public AutoCloseableNoException protectIndexes() {
     FSsTobeAddedback r = FSsTobeAddedback.createMultiple(this);
     svd.fssTobeAddedback.add(r);
     return r;
@@ -4547,7 +4717,10 @@
     return svd.casResets.get();
   }
   
-  int getCasId() {
+  /**
+   * @return an identifier for this CAS, globally unique within the classloader
+   */
+  public String getCasId() {
     return svd.casId;
   }
   
@@ -4555,26 +4728,34 @@
     return svd.getNextFsId(fs);
   }
   
-  public void adjustLastFsV2size(int arrayLength) {
+  public void adjustLastFsV2Size_arrays(int arrayLength) {
     svd.lastFsV2Size += 1 + arrayLength;  // 1 is for array length value
   }
   
+  public void adjustLastFsV2size_nonHeapStoredArrays() {
+    svd.lastFsV2Size += 2;  // length and index into other special heap
+  }
+  
   /**
    * Test case use
    * @param fss the FSs to include in the id 2 fs map
    */
-  public void setId2FSs(FeatureStructure ... fss) {
+  public void setId2FSsMaybeUnconditionally(FeatureStructure ... fss) {
     for (FeatureStructure fs : fss) {
-      if (IS_ALWAYS_HOLD_ONTO_FSS) {
-        svd.id2fs.putUnconditionally((TOP)fs);
-      } else {
-        svd.id2fs.put((TOP)fs);
-      }
+      setId2FsMaybeUnconditionally((TOP) fs);
     }
   }
   
+  private void setId2FsMaybeUnconditionally(TOP fs) {
+    if (svd.isId2Fs) {
+      svd.id2fs.putUnconditionally(fs);
+    } else {
+      set_id2fs(fs);
+    }   
+  }
+  
 //  Not currently used
-//  public Int2ObjHashMap<TOP> getId2FSs() {
+//  public Int2ObjHashMap<TOP, TOP> getId2FSs() {
 //    return svd.id2fs.getId2fs();
 //  }
   
@@ -4586,6 +4767,14 @@
     return svd.fsIdGenerator;
   }
   
+  final public int peekNextFsId() {
+    return svd.peekNextFsId();
+  }
+  
+  final public int lastV2IdIncr() {
+    return svd.lastFsV2IdIncr();
+  }
+  
   /**
    * Call this to capture the current value of fsIdGenerator and make it 
    * available to other threads.
@@ -4632,7 +4821,7 @@
    */
   public List<TOP> walkReachablePlusFSsSorted(
     Consumer<TOP> action_filtered, MarkerImpl mark, Predicate<TOP> includeFilter, CasTypeSystemMapper typeMapper) {    
-    List<TOP> all = new AllFSs(this, mark, includeFilter, typeMapper).getAllFSsSorted();
+    List<TOP> all = new AllFSs(this, mark, includeFilter, typeMapper).getAllFSsAllViews_sofas_reachable().getAllFSsSorted();
     List<TOP> filtered = filterAboveMark(all, mark);
     for (TOP fs : filtered) {
       action_filtered.accept(fs);
@@ -4667,7 +4856,7 @@
 //    
 //  }
   
-  public static boolean isSameCAS(CAS c1, CAS c2) {
+  public final static boolean isSameCAS(CAS c1, CAS c2) {
     CASImpl ci1 = (CASImpl) c1.getLowLevelCAS();
     CASImpl ci2 = (CASImpl) c2.getLowLevelCAS();
     return ci1.getBaseCAS() == ci2.getBaseCAS();
@@ -4694,64 +4883,153 @@
     }
   }
 
-  public EmptyFSList getEmptyFSList() {
+  public <T extends TOP> EmptyFSList<T> emptyFSList() {
     if (null == svd.emptyFSList) {
-      svd.emptyFSList = new EmptyFSList(getTypeSystemImpl().fsEListType, this);
+      svd.emptyFSList = new EmptyFSList<>(getTypeSystemImpl().fsEListType, this);
     }
     return svd.emptyFSList;
   }
 
-  public EmptyFloatList getEmptyFloatList() {
+  /*
+   * @see org.apache.uima.cas.CAS#emptyFloatList()
+   */
+  public EmptyFloatList emptyFloatList() {
     if (null == svd.emptyFloatList) {
       svd.emptyFloatList = new EmptyFloatList(getTypeSystemImpl().floatEListType, this);
     }
     return svd.emptyFloatList;
   }
   
-  public EmptyIntegerList getEmptyIntegerList() {
+  public EmptyIntegerList emptyIntegerList() {
     if (null == svd.emptyIntegerList) {
       svd.emptyIntegerList = new EmptyIntegerList(getTypeSystemImpl().intEListType, this);
     }
     return svd.emptyIntegerList;
   }
   
-  public EmptyStringList getEmptyStringList() {
+  public EmptyStringList emptyStringList() {
     if (null == svd.emptyStringList) {
       svd.emptyStringList = new EmptyStringList(getTypeSystemImpl().stringEListType, this);
     }
     return svd.emptyStringList;
   }
   
+  public CommonArrayFS emptyArray(Type type) {
+    switch (((TypeImpl)type).getCode()) {
+    case TypeSystemConstants.booleanArrayTypeCode :
+      return emptyBooleanArray();
+    case TypeSystemConstants.byteArrayTypeCode :
+      return emptyByteArray();
+    case TypeSystemConstants.shortArrayTypeCode :
+      return emptyShortArray();
+    case TypeSystemConstants.intArrayTypeCode :
+      return emptyIntegerArray();
+    case TypeSystemConstants.floatArrayTypeCode :
+      return emptyFloatArray();
+    case TypeSystemConstants.longArrayTypeCode :
+      return emptyLongArray();
+    case TypeSystemConstants.doubleArrayTypeCode :
+      return emptyDoubleArray();
+    case TypeSystemConstants.stringArrayTypeCode :
+      return emptyStringArray();
+    default: // TypeSystemConstants.fsArrayTypeCode or any other type
+      return emptyFSArray();
+    }
+  }
+  
+  public FloatArray emptyFloatArray() {
+    if (null == svd.emptyFloatArray) {
+      svd.emptyFloatArray = new FloatArray(this.getJCas(), 0);
+    }
+    return svd.emptyFloatArray;
+  }
+
+  public <T extends FeatureStructure> FSArray<T> emptyFSArray() {
+    if (null == svd.emptyFSArray) {
+      svd.emptyFSArray = new FSArray<T>(this.getJCas(), 0);
+    }
+    return svd.emptyFSArray;
+  }
+  
+  public IntegerArray emptyIntegerArray() {
+    if (null == svd.emptyIntegerArray) {
+      svd.emptyIntegerArray = new IntegerArray(this.getJCas(), 0);
+    }
+    return svd.emptyIntegerArray;
+  }
+  
+  public StringArray emptyStringArray() {
+    if (null == svd.emptyStringArray) {
+      svd.emptyStringArray = new StringArray(this.getJCas(), 0);
+    }
+    return svd.emptyStringArray;
+  }
+  
+  public DoubleArray emptyDoubleArray() {
+    if (null == svd.emptyDoubleArray) {
+      svd.emptyDoubleArray = new DoubleArray(this.getJCas(), 0);
+    }
+    return svd.emptyDoubleArray;
+  }
+  
+  public LongArray emptyLongArray() {
+    if (null == svd.emptyLongArray) {
+      svd.emptyLongArray = new LongArray(this.getJCas(), 0);
+    }
+    return svd.emptyLongArray;
+  }
+  
+  public ShortArray emptyShortArray() {
+    if (null == svd.emptyShortArray) {
+      svd.emptyShortArray = new ShortArray(this.getJCas(), 0);
+    }
+    return svd.emptyShortArray;
+  }
+  
+  public ByteArray emptyByteArray() {
+    if (null == svd.emptyByteArray) {
+      svd.emptyByteArray = new ByteArray(this.getJCas(), 0);
+    }
+    return svd.emptyByteArray;
+  }
+  
+  public BooleanArray emptyBooleanArray() {
+    if (null == svd.emptyBooleanArray) {
+      svd.emptyBooleanArray = new BooleanArray(this.getJCas(), 0);
+    }
+    return svd.emptyBooleanArray;
+  }
+  
   /**
    * @param rangeCode special codes for serialization use only
    * @return the empty list (shared) corresponding to the type
    */
-  public EmptyList getEmptyList(int rangeCode) {
-    return (rangeCode == CasSerializerSupport.TYPE_CLASS_INTLIST) ? getEmptyIntegerList() :
-           (rangeCode == CasSerializerSupport.TYPE_CLASS_FLOATLIST) ? getEmptyFloatList() :
-           (rangeCode == CasSerializerSupport.TYPE_CLASS_STRINGLIST) ? getEmptyStringList() :
-                                                                       getEmptyFSList();
+  public EmptyList emptyList(int rangeCode) {
+    return (rangeCode == CasSerializerSupport.TYPE_CLASS_INTLIST) ? emptyIntegerList() :
+           (rangeCode == CasSerializerSupport.TYPE_CLASS_FLOATLIST) ? emptyFloatList() :
+           (rangeCode == CasSerializerSupport.TYPE_CLASS_STRINGLIST) ? emptyStringList() :
+                                                                       emptyFSList();
   }
   
   /**
    * Get an empty list from the type code of a list
-   * @param rangeCode -
+   * @param typeCode -
    * @return -
    */
-  public EmptyList getEmptyListFromTypeCode(int rangeCode) {
-    switch (rangeCode) {
+  public EmptyList emptyListFromTypeCode(int typeCode) {
+    switch (typeCode) {
     case fsListTypeCode:
     case fsEListTypeCode:
-    case fsNeListTypeCode: return getEmptyFSList();
+    case fsNeListTypeCode: return emptyFSList();
     case floatListTypeCode:
     case floatEListTypeCode:
-    case floatNeListTypeCode: return getEmptyFloatList();
+    case floatNeListTypeCode: return emptyFloatList();
     case intListTypeCode:
     case intEListTypeCode:
-    case intNeListTypeCode: return getEmptyIntegerList();
+    case intNeListTypeCode: return emptyIntegerList();
     case stringListTypeCode:
     case stringEListTypeCode:
-    case stringNeListTypeCode: return getEmptyStringList();
+    case stringNeListTypeCode: return emptyStringList();
     default: throw new IllegalArgumentException();
     }
   }
@@ -4946,7 +5224,7 @@
   void traceFSfs(FeatureStructureImplC fs) {
     StringBuilder b = svd.traceFScreationSb;
     svd.traceFSid = fs._id;
-    b.append("c:").append(String.format("%-3d", getCasId()));
+    b.append("c:").append(String.format("%-3s", getCasId()));
     String viewName = fs._casView.getViewName();
     if (null == viewName) {
       viewName = "base";
@@ -5074,7 +5352,7 @@
     //  - v.toString()
   }
   
-  private static int debug2cnt = 0;
+//  private static int debug2cnt = 0;
   
   /**
    * @param v
@@ -5325,11 +5603,84 @@
   }
   
   void maybeHoldOntoFS(FeatureStructureImplC fs) {
-    if (IS_ALWAYS_HOLD_ONTO_FSS) {
-      svd.id2fs.putUnconditionally((TOP)fs);
+    if (svd.isId2Fs) {
+      svd.id2fs.put((TOP)fs);  // does an assert - prev id should not be there
     }
   }
   
+  public void swapInPearVersion(Object[] a) {
+    if (!inPearContext()) {
+      return;
+    }
+  
+    for (int i = 0; i < a.length; i++) {
+      Object ao = a[i];
+      if (ao instanceof TOP) {
+        a[i] = pearConvert((TOP) ao);
+      }
+    }
+  }
+  
+  public Collection<?> collectNonPearVersions(Collection<?> c) {
+    if (c.size() == 0 || !inPearContext()) {
+      return c;
+    }
+    ArrayList<Object> items = new ArrayList<>(c.size());
+    for (Object o : c) {
+      if (o instanceof TOP) {
+        items.add(pearConvert((TOP) o));
+      }
+    }
+    return items;
+  }
+  
+  public <T> Spliterator<T> makePearAware(Spliterator<T> baseSi) {
+    if (!inPearContext()) {
+      return baseSi;
+    }
+    
+    return new Spliterator<T>() {
+
+      @Override
+      public boolean tryAdvance(Consumer<? super T> action) {
+        return baseSi.tryAdvance(item -> action.accept(
+            (item instanceof TOP) 
+              ? (T) pearConvert((TOP)item)
+              : item));
+      }
+
+      @Override
+      public Spliterator<T> trySplit() {
+        return baseSi.trySplit();
+      }
+
+      @Override
+      public long estimateSize() {
+        return baseSi.estimateSize();
+      }
+
+      @Override
+      public int characteristics() {
+        return baseSi.characteristics();
+      }
+      
+    };
+  }
+  
+  public boolean is_ll_enableV2IdRefs() {
+    return svd.isId2Fs;
+  }
+  
+  public AutoCloseableNoException ll_enableV2IdRefs(boolean enable) {
+    final boolean restoreState = svd.isId2Fs;
+    if (enable && !restoreState && svd.fsIdGenerator != 0) {
+      throw new IllegalStateException("CAS must be empty when switching to V2 ID References mode.");
+    }
+    AutoCloseableNoException r = () -> svd.isId2Fs = restoreState; 
+    svd.isId2Fs = enable;
+    return r;
+  }
+
 //  int allocIntData(int sz) {
 //    
 //    if (sz > INT_DATA_FOR_ALLOC_SIZE / 4) {
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasCompare.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasCompare.java
new file mode 100644
index 0000000..d3e679f
--- /dev/null
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasCompare.java
@@ -0,0 +1,1566 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+package org.apache.uima.cas.impl;

+

+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.Set;

+import java.util.function.IntUnaryOperator;

+import java.util.function.Predicate;

+

+import org.apache.uima.List_of_ints;

+import org.apache.uima.cas.CommonArrayFS;

+import org.apache.uima.cas.Feature;

+import org.apache.uima.cas.impl.SlotKinds.SlotKind;

+import org.apache.uima.internal.util.Int2ObjHashMap;

+import org.apache.uima.internal.util.Misc;

+import org.apache.uima.internal.util.Obj2IntIdentityHashMap;

+import org.apache.uima.internal.util.Pair;

+import org.apache.uima.internal.util.PositiveIntSet;

+import org.apache.uima.internal.util.PositiveIntSet_impl;

+import org.apache.uima.jcas.cas.BooleanArray;

+import org.apache.uima.jcas.cas.ByteArray;

+import org.apache.uima.jcas.cas.CommonList;

+import org.apache.uima.jcas.cas.DoubleArray;

+import org.apache.uima.jcas.cas.EmptyList;

+import org.apache.uima.jcas.cas.FSArray;

+import org.apache.uima.jcas.cas.FSList;

+import org.apache.uima.jcas.cas.FloatArray;

+import org.apache.uima.jcas.cas.FloatList;

+import org.apache.uima.jcas.cas.IntegerArray;

+import org.apache.uima.jcas.cas.IntegerList;

+import org.apache.uima.jcas.cas.LongArray;

+import org.apache.uima.jcas.cas.NonEmptyFSList;

+import org.apache.uima.jcas.cas.NonEmptyFloatList;

+import org.apache.uima.jcas.cas.NonEmptyIntegerList;

+import org.apache.uima.jcas.cas.NonEmptyStringList;

+import org.apache.uima.jcas.cas.ShortArray;

+import org.apache.uima.jcas.cas.StringArray;

+import org.apache.uima.jcas.cas.StringList;

+import org.apache.uima.jcas.cas.TOP;

+import org.apache.uima.util.IntEntry;

+

+/**

+ * Used by tests for Binary Compressed de/serialization code.

+ * Used by test app: XmiCompare.

+ * 

+ * Compare 2 CASes, with perhaps different type systems.

+ * If the type systems are different, construct a type mapper and use that

+ *   to selectively ignore types or features not in other type system

+ *   

+ * The Mapper is from CAS1 -&gt; CAS2  

+ * 

+ * When computing the things to compare from CAS1, filter to remove

+ * feature structures not reachable via indexes or refs

+ *   

+ * The index definitions are not compared.

+ * The indexes are used to locate the FSs to be compared.

+ *   

+ * Reports are produced to System.out and System.err as a side effect

+ *   System.out: status messages, type system comparison

+ *   System.err: mismatch comparison information

+ *   

+ * Usage:  

+ *   Use the static compareCASes method for default comparisons

+ *   Use the multi-step approach for more complex comparisons:

+ *     - Make an instance of this class, passing in the two CASes.

+ *     - Set any additional configuration 

+ *         cc.compareAll(true) - continue comparing if mismatch found

+ *         cc.compardIds(true) - compare ids (require ids to be ==)

+ *     - Do any transformations needed on the CASes to account for known but allowed differences:

+ *         -- These are transformations done on the CAS Feature Structures outside of this routine

+ *         -- example: for certain type:feature string values, normalize to the same canonical value

+ *         -- example: for certain type:feature string arrays, where the order is not important, sort them

+ *         -- example: for certain type:feature FSArrays, where the order is not important, sort them

+ *            --- using the sortFSArray method

+ *     - Do any configuration to specify congruence sets for String values

+ *        -- example: addStringCongruenceSet( type, feature, set-of-strings, -1 or int index if array)

+ *        -- these are specific to type / feature specs

+ *        -- range can be string or string array - if string array, the spec includes the index or -1

+ *           to indicate all indexes

+ *              

+ * How it works

+ *   Prepare arrays of all the FSs in the CAS

+ *     - for each of 2 CASes to be compared

+ *     - 2 arrays: 

+ *        -- all FSs in any index in any view

+ *        -- the above, plus all FSs reachable via references

+ *   

+ *   The comparison of FSs is done, one FS at a time.  

+ *     - in order to determine the right FSs to compare with each other, the FSs for each CAS

+ *       are sorted.

+ *   

+ *   The sort and the CAS compare both use a Compare method.

+ *     - sorting skips items not in the other type system, including features

+ *     -   (only possible if comparing two CASes with different type systems, of course)

+ *     

+ *   Compare

+ *     - used for two purposes:

+ *       a) sorting FSs belonging to one CAS

+ *          - can be used by caller to pre-sort any array values where the 

+ *            compare should be for set equality (in other words, ignore the order)

+ *       b) comparing a FS in one CAS with a FS in the other CAS

+ *         

+ *     sort keys, in order:

+ *       1) type

+ *       2) if primitive array: sort based on 

+ *           - size

+ *           - iterating thru all array items

+ *       3) All the features, considered in an order where non-refs are sorted before refs. 

+ *       

+ *     comparing values:

+ *       primitives - value comparison

+ *       refs - compare the ref'd FS, while recording reference paths

+ *            - stop when reach a compare point where the pair being compaired has been seen

+ *            - stop at any point if the two FSs compare unequal

+ *            - at the stop point, if compare is equal, check the reference paths, and 

+ *                report unequal reference paths (different cycle lengths, or different total lengths,

+ *                see the Prev data structure)

+ *                   

+ *     Context information, reused across compares:

+ *       prevCompare - if a particular pair of FSs compared equal

+ *                      -- used to speed up comparison

+ *                      -- used to stop recursive loops of references

+ *                       

+ *       prev1, prev2 - reset for each top level FS compare

+ *                    - not reset for inner FS compares of fs-reference values)

+ *                      holds information about the reference path for chains of FS references           

+ *     

+ */

+

+public class CasCompare {

+  

+  private final static boolean IS_DEBUG_STOP_ON_MISCOMPARE = true;

+  private final static boolean IS_MEAS_LIST_2_ARRAY = false;

+

+  /**

+   * Compare 2 CASes, with perhaps different type systems.

+   *   - using default configuration.

+   *   

+   * @param c1 CAS to compare

+   * @param c2 CAS to compare

+   * @return true if equal (for types / features in both)

+   */

+  

+  public static boolean compareCASes(CASImpl c1, CASImpl c2) {

+    return new CasCompare(c1, c2).compareCASes();

+  }

+  

+  /**

+   * hold info about previous compares, to break cycles in references

+   * The comparison records cycles and can distinguish different cyclic graphs.

+   * When a cycle exists, it looks like:

+   *    a b c d e f g h i     a cycle starting with a, with refs ending up at i

+   *              ^     v     and then looping back to f

+   *              *-----*

+   *              

+   * This data structure measures both the cycle Length (in this example, 4)

+   * and the size of the starting part before hitting the loop (in this case 5)  

+   * 

+   * Note: when using, if two FSs end up comparing equal, the instances must be

+   *       rolled back 1 item to allow further items to be compared in the chain.

+   *       Example:  a -&gt; b -> c -&gt; d

+   *         d's compared equal, c may have ref next to "e".

+   */

+  private static class Prev {

+

+    /** ordered list of traversed FSs, including duplicates */

+    private final ArrayList<TOP> fsList = new ArrayList<>();

+

+    /** length of the cycle, excluding any leading ref chain

+     *  -1 until some cycle is detected */

+    private int cycleLen = -1;

+    

+    /** length of the leading ref chain, excludes any cycle part 

+     *  -1 until some cycle is detected */

+    private int cycleStart = -1;

+    

+    /** ref to the top of the chain; used as a boolean flag */

+    TOP prevCompareTop; 

+    

+    void clear() {

+      fsList.clear();

+      cycleLen = -1;

+      cycleStart = -1;

+      prevCompareTop = null;

+    }

+    

+    int compareCycleLen(Prev other) {

+      return Integer.compare(cycleLen,  other.cycleLen);

+    }

+    

+    int compareUsize(Prev other) {

+      return Integer.compare(usize(), other.usize());

+    }

+    

+    /**

+     * called when returning from compare with equal result

+     * If a loop exists, and the item being removed is the one that started the loopback,

+     *   reset the loop info.

+     * @param fs

+     */

+    void rmvLast(TOP fs) {

+      int toBeRemoved = fsList.size() - 1;

+      if (toBeRemoved == usize()) { // means removing the 1st item that looped back

+        //  0 1 2 3 4 5 6

+        //  a b c d e f g (c d e f g c d)  fsList

+        //      ^              loop, cycleStart = 2 , cycleLength = 5

+        

+        //debug

+        if (cycleLen < 0) { // never true, because usize() >= 0  ==> there's a cycle

+          System.out.println("debug cycleLen");

+          throw Misc.internalError();

+        }

+        assert cycleLen >= 0; 

+        assert cycleStart >= 0;

+

+        cycleLen = -1;   // since the loop is no more, reset the loop info

+        cycleStart = -1;

+      }

+      fsList.remove(toBeRemoved);     

+    }

+    

+    void addTop() {

+      fsList.add(prevCompareTop);

+      prevCompareTop = null;

+    }

+    

+    void add(TOP fs) {

+      if (cycleLen < 0) {

+        int i = fsList.lastIndexOf(fs);

+        if (i >= 0) { // first instance of a cycle detected

+          cycleLen = fsList.size() - i;

+          //  0 1 2 3 4 5 6

+          //  a b c d e f g (c)

+          //      ^           i == 2 == length of start segment

+          cycleStart = i;  // cycleStart is length up to but not including the start of the cycle

+        }

+      }

+      fsList.add(fs);

+    }

+   

+    /** return size of ref chain including duplicates due to ref loops */

+    int size() {

+      return fsList.size();

+    }

+    

+    /** return -2 or the length of the cycle including 1 loop */

+    int usize() {

+      return cycleStart + cycleLen;

+    }

+  }

+  

+  /** key for StringCongruenceSet */

+  private static class ScsKey {

+

+    final TypeImpl type;

+    final FeatureImpl feature;

+    final int index;

+    

+    ScsKey(TypeImpl type, FeatureImpl feature, int index) {

+      this.type = type;

+      this.feature = feature;

+      this.index = index;

+    }

+    /* (non-Javadoc)

+     * @see java.lang.Object#hashCode()

+     */

+    @Override

+    public int hashCode() {

+      final int prime = 31;

+      int result = 1;

+      result = prime * result + ((feature == null) ? 0 : feature.hashCode());

+      result = prime * result + index;

+      result = prime * result + ((type == null) ? 0 : type.hashCode());

+      return result;

+    }

+

+    /* (non-Javadoc)

+     * @see java.lang.Object#equals(java.lang.Object)

+     */

+    @Override

+    public boolean equals(Object obj) {

+      if (this == obj)

+        return true;

+      if (obj == null)

+        return false;

+      if (getClass() != obj.getClass())

+        return false;

+      ScsKey other = (ScsKey) obj;

+      if (feature == null) {

+        if (other.feature != null)

+          return false;

+      } else if (!feature.equals(other.feature))

+        return false;

+      if (index != other.index)

+        return false;

+      if (type == null) {

+        if (other.type != null)

+          return false;

+      } else if (!type.equals(other.type))

+        return false;

+      return true;

+    }    

+  }

+

+  private static class FeatLists {

+    /**

+     * first index is easy, easyArrays, refs, refArrays

+     */

+    final FeatureImpl[][] featsByEase = new FeatureImpl[4][];

+    

+    FeatLists(List<FeatureImpl> easy, 

+              List<FeatureImpl> easyArrays, 

+              List<FeatureImpl> refs, 

+              List<FeatureImpl> refArrays) {

+      featsByEase[0] = (FeatureImpl[]) easy.toArray(new FeatureImpl[easy.size()]);

+      featsByEase[1] = (FeatureImpl[]) easyArrays.toArray(new FeatureImpl[easyArrays.size()]);

+      featsByEase[2] = (FeatureImpl[]) refs.toArray(new FeatureImpl[refs.size()]);

+      featsByEase[3] = (FeatureImpl[]) refArrays.toArray(new FeatureImpl[refArrays.size()]);

+    }

+  }

+    

+  // must always be true, need to rework convert lists to arrays if not

+  private static final boolean IS_CANONICAL_EMPTY_LISTS = true;

+

+  /* ****************************************************

+   * Data Structures for converting lists to arrays

+   * ****************************************************/

+  private static final CommonList removed_list_marker = new NonEmptyFSList<TOP>();

+  

+  /** 

+   * key = _id, value = arraylist holding well-formed list with this node in it 

+   */

+  final private Int2ObjHashMap<ArrayList<CommonList>, ArrayList<CommonList>> map_e_to_a_list = 

+            new Int2ObjHashMap(ArrayList.class);

+  

+  /** 

+   * set of list elements determined to be members of a non-linear structure 

+   */

+  final private PositiveIntSet non_linear_list_elements = new PositiveIntSet_impl();

+  

+  /**

+   * a map from list nodes which might be removed, to their place in the fss array list

+   *   The index is 1 more, to avoid colliding with the 0 value, used for missing value

+   */

+  final private Obj2IntIdentityHashMap<CommonList> node_indexes = 

+      new Obj2IntIdentityHashMap<CommonList>(CommonList.class, removed_list_marker);

+  

+  final private PositiveIntSet list_successor_seen = new PositiveIntSet_impl();

+  

+  final private Map<TypeImpl, FeatLists> type2featLists = new HashMap<>();

+  

+  final private CASImpl c1;

+  final private CASImpl c2;

+  final private TypeSystemImpl ts1;      

+  final private TypeSystemImpl ts2;

+    

+//    private boolean compareStringArraysAsSets = false;

+//    private boolean compareArraysByElement = false;

+    /** if true, continues comparison and reporting after finding the first miscompare */

+  private boolean isCompareAll = false;

+  private boolean isCompareIds = false;

+//    private boolean compareFSArraysAsSets = false;

+    

+//    /** true when that FS._id (an Array of some kind) has been sorted */

+//    final private BitSet alreadySorted1 = new BitSet();

+//    final private BitSet alreadySorted2 = new BitSet();

+    

+    /**

+     * This is used 

+     *   - to speed up the compare - avoid comparing the same things multiple times, instead just use previous result

+     *   - when doing the comparison to break recursion if asked to compare the same two things while comaring them.

+     *   

+     *   value is the result of previous comparison.

+     */

+  private final Map<Pair<TOP, TOP>, Integer> prevCompare = new HashMap<>();

+  private final Prev prev1 = new Prev();

+  private final Prev prev2 = new Prev();

+  

+//    private final Set<Pair<TOP, TOP>> miscompares = Collections.newSetFromMap(new HashMap<>());

+        

+//  private TOP fs1, fs2;

+  private boolean isSrcCas;  // used for sorting with a CAS, to differentiate between src and target CASes

+  final private StringBuilder mismatchSb = new StringBuilder();

+  private boolean inSortContext = false;

+  

+  private boolean isTypeMapping;

+  private final CasTypeSystemMapper typeMapper;

+  

+  private ArrayList<TOP> c1FoundFSs;

+  private ArrayList<TOP> c2FoundFSs;

+  

+  private final Map<ScsKey, String[]> stringCongruenceSets = new HashMap<>();

+  private boolean isUsingStringCongruenceSets = false;

+  private final TypeImpl fsArrayType;

+    

+  private int maxId1;

+  private int maxId2;

+

+          

+  public CasCompare(CASImpl c1, CASImpl c2) {

+    this.c1 = c1;

+    this.c2 = c2;

+    ts1 = c1.getTypeSystemImpl();

+    ts2 = c2.getTypeSystemImpl();

+    typeMapper = ts1.getTypeSystemMapper(ts2);

+    isTypeMapping = (null != typeMapper);

+    fsArrayType = ts1.fsArrayType;

+  }

+    

+//  public void compareStringArraysAsSets(boolean v) {

+//    compareStringArraysAsSets = v;

+//  }

+//  

+//  public void compareFSArraysAsSets(boolean v) {

+//    compareFSArraysAsSets = v;

+//  }

+//  

+//  public void compareArraysByElement(boolean v) {

+//    compareArraysByElement = v;

+//  }

+  

+  /**

+   * Continues the comparison after a miscompare (or not)

+   * @param v true to continue the comparison after a miscompare

+   */

+  public void compareAll(boolean v) {

+    isCompareAll = v;

+  }

+  

+  public void compareIds(boolean v) {

+    isCompareIds = v;

+  }

+  

+//  public void compareCanonicalEmptyLists(boolean v) {

+//    isCanonicalEmptyLists = v; 

+//  }

+  

+  /**

+   * Add a set of strings that should be considered equal when doing string comparisons.

+   * This is conditioned on the typename and feature name

+   * @param t the fully qualified type name

+   * @param f the feature short name

+   * @param set a set of strings that should compare equal, if testing the type / feature

+   * @param index if the item being compared is a reference to a string array, which index should be compared.

+   *              Use -1 if not applicable.

+   */

+  public void addStringCongruenceSet(String t, String f, String[] set, int index) {

+    TypeImpl t1 = ts1.getType(t);

+    stringCongruenceSets.put(

+        new ScsKey(t1, t1.getFeatureByBaseName(f), index),

+        set);

+    isUsingStringCongruenceSets = true;

+  }

+  

+  /**

+   * This does the actual comparison operation of the previously specified CASes

+   * @return true if compare is OK

+   */

+  public boolean compareCASes() {

+    boolean allOk = true;

+//    final List<TOP> c1FoundFSs;

+//    final List<TOP> c2FoundFSs;

+    final boolean savedIsTypeMapping= isTypeMapping;

+    mismatchSb.setLength(0);

+

+    try {

+      

+//        processIndexedFeatureStructures(c1, false);

+      Predicate<TOP> includeFilter = isTypeMapping ? (fs -> isTypeInTgt(fs)) : null;

+      // get just the indexed ones

+      c1FoundFSs = new AllFSs(c1, null, includeFilter, isTypeMapping ? typeMapper : null)

+                        .getAllFSsAllViews_sofas_reachable()

+                        .getAllFSs();

+      

+//        c1FoundFSs = fssToSerialize;  // all reachable FSs, filtered by CAS1 -> CAS2 type systems.

+      

+//        processIndexedFeatureStructures(c2, false);

+      c2FoundFSs = new AllFSs(c2, null, null, null)

+                     .getAllFSsAllViews_sofas_reachable()

+                     .getAllFSs(); // get just the indexed ones.

+      

+

+      // if type systems are "isEqual()" still need to map because of feature validation testing

+          

+      int i1 = 0;

+      int i2 = 0;

+

+      maxId1 = c1.peekNextFsId();

+      maxId2 = c2.peekNextFsId();

+          

+      // convert_linear_lists_to_arrays may add more items

+      

+      convert_linear_lists_to_arrays(c1FoundFSs);

+      convert_linear_lists_to_arrays(c2FoundFSs);

+ 

+      final int sz1 = c1FoundFSs.size();  // max size for comparing, includes added arrays converted from lists

+      final int sz2 = c2FoundFSs.size();

+

+      isSrcCas = true;   // avoids sorting on types/features not present in ts2

+      sort(c1FoundFSs);

+      

+      isSrcCas = false;  // avoids sorting on types/features not present in ts1

+      sort(c2FoundFSs);

+     

+//      miscompares.clear();

+      

+      while (i1 < sz1 && i2 < sz2) {

+        TOP fs1 = c1FoundFSs.get(i1);  // assumes the elements are in same order??

+        TOP fs2 = c2FoundFSs.get(i2);

+

+        if (null == fs1) {  // nulls at end indicate list elements converted to arrays

+          if (null != fs2) {

+            System.err.format("%,d Feature Structures in CAS2 with no matches in CAS2, e.g. %s%n",

+                sz2 - i2, fs2.toString(2));

+            return ! allOk;

+          } else {           

+            return allOk;

+          }

+        }

+        if (null == fs2) {  // nulls at end indicate list elements converted to arrays

+          System.err.format("%,d Feature Structures in CAS1 with no matches in CAS2, e.g. %s%n",

+              sz1 - i1, fs1.toString(2));

+          return ! allOk;

+        }

+        

+        

+        if (IS_CANONICAL_EMPTY_LISTS) {

+          if (fs1 instanceof EmptyList && !(fs2 instanceof EmptyList)) {

+            int start = i1;

+            while (true) {

+              i1++;

+              if (i1 >= sz1) break;

+              fs1 = c1FoundFSs.get(i1);

+              if (!(fs1 instanceof EmptyList)) break;

+            }

+            System.out.println("CasCompare skipping " + (i1 - start) + " emptylist FSs in 1st CAS to realign.");            

+          } else if (fs2 instanceof EmptyList && !(fs1 instanceof EmptyList)) {

+            int start = i2;

+            while (true) {

+              i2++;

+              if (i2 >= sz2) break;

+              fs2 = c2FoundFSs.get(i2);

+              if (!(fs2 instanceof EmptyList)) break;

+            }

+            System.out.println("CasCompare skipping " + (i2 - start) + " emptylist FSs in 2nd CAS to realign.");

+          }

+        }

+

+        clearPrevFss();

+        prev1.prevCompareTop = fs1;

+        prev2.prevCompareTop = fs2;

+

+        if (isTypeMapping) {

+          // skip compares for types that are missing in the other type system

+          final boolean typeMissingIn1 = typeMapper.mapTypeTgt2Src(fs2._getTypeImpl()) == null;

+          final boolean typeMissingIn2 = typeMapper.mapTypeSrc2Tgt(fs1._getTypeImpl()) == null;

+          if (!typeMissingIn1 && !typeMissingIn2) {

+            if (0 != compareFss(fs1, fs2, null, null)) {

+              mismatchFsDisplay();

+              if (!isCompareAll) return false;

+              allOk = false;

+              int tc = fs1._getTypeImpl().compareTo(fs2._getTypeImpl());

+              if (tc < 0) {

+                System.out.print("skiping first to align types ");

+                while (tc < 0 && i1 < sz1) {

+                  i1++;

+                  tc = c1FoundFSs.get(i1)._getTypeImpl().compareTo(fs2._getTypeImpl());

+                  System.out.print(".");

+                }

+                System.out.println("");

+              } else if (tc > 0) {

+                System.out.print("skiping second to align types ");

+                while (tc > 0 && i2 < sz2) {

+                  i2++;

+                  tc = fs1._getTypeImpl().compareTo(c2FoundFSs.get(i2)._getTypeImpl());

+                  System.out.print(".");

+                }

+                System.out.println("");

+              }

+            }

+            i1++;

+            i2++;

+            continue;

+          }

+          if (typeMissingIn1 && typeMissingIn2) {

+            Misc.internalError();

+            i1++;

+            i2++;

+            continue;

+          }

+          if (typeMissingIn1) {

+            System.out.println("debug - type missing in 1, but test fails for refs");

+            i2++;

+            continue;

+          }

+          if (typeMissingIn2) {

+            Misc.internalError(); 

+            i1++;

+            continue;

+          }

+        } else {  // not type mapping

+          if (0 != compareFss(fs1, fs2, null, null)) {

+            

+            mismatchFsDisplay();

+            if (!isCompareAll) return false;

+            allOk = false;

+            int tc = fs1._getTypeImpl().compareTo(fs2._getTypeImpl());

+            if (tc < 0) {

+              System.out.print("skiping first to align types ");

+              while (tc < 0 && i1 < sz1) {

+                i1++;

+                tc = c1FoundFSs.get(i1)._getTypeImpl().compareTo(fs2._getTypeImpl());

+                System.out.print(".");

+              }

+              System.out.println("");

+            } else if (tc > 0) {

+              System.out.print("skiping second to align types ");

+              while (tc > 0 && i2 < sz2) {

+                i2++;

+                tc = fs1._getTypeImpl().compareTo(c2FoundFSs.get(i2)._getTypeImpl());

+                System.out.print(".");

+              }

+              System.out.println("");

+            } 

+            //debug

+            else {

+              // debug - realign for case where c1 has 1 extra fs

+              if (i1 + 1 < sz1) {

+                fs1 = c1FoundFSs.get(i1 + 1);

+                clearPrevFss();

+                prev1.prevCompareTop = fs1;

+                prev2.prevCompareTop = fs2;

+                if (0 == compareFss(fs1, fs2, null, null)) {

+                  // realign

+                  System.out.println("Skipping 1 to realign within same type " + fs1._getTypeImpl().getName());

+                  i1++;

+                }

+              }

+            }

+          }

+          i1++;

+          i2++;

+          continue;

+        }

+      }

+      

+      if (i1 == sz1 && i2 == sz2) {

+        return allOk;  // end

+      }

+      

+      if (isTypeMapping) {

+        if (i1 < sz1) {

+          System.err.format("%,d Feature Structures in CAS1 with no matches in CAS2, e.g. %s%n",

+              sz1 - i1, c1FoundFSs.get(i1));

+          return false;

+        }

+

+        while (i2 < sz2) {

+          TOP fs = c2FoundFSs.get(i2);

+          if (isTypeMapping && typeMapper.mapTypeTgt2Src(fs._getTypeImpl()) != null) {  // not a complete test, misses refs

+            return false;  // have more FSs in c2 than in c1

+          }

+          i2++;

+        }

+        return true;

+      }

+      

+      // not type mapping, and number of FS didn't match

+      if (i1 < sz1) {

+        System.err.format("CAS1 had %,d additional Feature Structures, e.g.: %s%n", sz1 - i1, c1FoundFSs.get(i1));

+      } else {

+        System.err.format("CAS2 had %,d additional Feature Structures, e.g.: %s%n", sz2 - i2, c2FoundFSs.get(i2));

+      }

+      return false;

+    } finally {

+      isTypeMapping = savedIsTypeMapping;

+      clearPrevFss();

+    }

+  }

+  

+  /**

+   * Sort an fsArray.  During the sort, links are followed.

+   * The sorting is done in a clone of the array, and the original array is not updated.

+   * Instead, a Runnable is returned, which may be invoked later to update the original array with the sorted copy.

+   * This allows sorting to be done on the original item values.

+   * @param fsArray the array to be sorted

+   * @return a runnable, which (when invoked) updates the original array with the sorted result.

+   */

+  public Runnable sortFSArray(FSArray fsArray) {

+    if (fsArray == null || fsArray.size() < 2) {

+      return null;

+    }

+    TOP[] a = fsArray._getTheArray().clone();

+    clearPrevFss();

+    inSortContext = true;

+    Arrays.sort(a, (TOP afs1, TOP afs2) -> {

+      return compareRefs(afs1, afs2, null, null);

+    });

+    return () -> System.arraycopy(a, 0, fsArray._getTheArray(), 0, fsArray.size());

+  }

+  

+  /* ******************************************************************************* 

+   *     Convert UIMA Lists to arrays, to make the compare go faster

+   * *******************************************************************************/

+  

+  private void convert_linear_lists_to_arrays(ArrayList<TOP> fss) {

+    map_e_to_a_list.clear();

+    non_linear_list_elements.clear();

+    node_indexes.clear();

+    

+    int sz = fss.size();

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

+      TOP fs = fss.get(i);

+    

+      if (! (fs instanceof CommonList)) continue;                   // skip: not list node

+      CommonList node = (CommonList) fs;

+      if (node.isEmpty()) {

+        fss.set(i, null); // clear it, empty list elements don't need to be compared

+        continue;

+      }

+

+      if (non_linear_list_elements.contains(node._id())) continue;  // skip: in non-linear list

+      if (null !=  map_e_to_a_list.get(node._id())) {

+        node_indexes.put(node,  i + 1);                             // case: added as a successor

+        continue;                                                   // skip: already seen/processed

+      }

+ 

+      node_indexes.put(node, i + 1);                   // in case we have to remove this later

+      if (!node.isEmpty()) {

+        ArrayList<CommonList> al = new ArrayList<>();    // start a new arraylist

+        al.add(node);                                    // add this node

+        map_e_to_a_list.put(node._id(), al);

+

+        if (addSuccessors(node, al)) continue;  

+        

+        // some successor was in a non-linear situation        

+        move_to_non_linear(al);

+      }      

+    }

+    

+    if (IS_MEAS_LIST_2_ARRAY) {

+      System.out.format("CasCompare converting lists to Arrays, "

+          + "nbr of list elements considered: %,d, number of looped lists skipped: %,d%n",  

+          node_indexes.size(), non_linear_list_elements.size());

+    }

+    CASImpl view = fss.get(0)._casView;

+    TypeSystemImpl tsi = view.getTypeSystemImpl();

+    

+    Set<ArrayList<CommonList>> processed = Collections.newSetFromMap(new IdentityHashMap<>());

+    

+    for (IntEntry<ArrayList<CommonList>> ie : map_e_to_a_list) {

+      ArrayList<CommonList> e = ie.getValue();

+      if (processed.add(e)) {

+        convert_to_array(e, fss, view, tsi); // changes list element to highest pseudo fs, adds array elements

+      }

+    }

+    if (IS_MEAS_LIST_2_ARRAY) {

+      System.out.format("CasCompare converted %,d lists to Arrays%n", processed.size());            

+    }

+

+    // allow gc

+    map_e_to_a_list.clear();

+    non_linear_list_elements.clear();    

+    node_indexes.clear();

+  }

+  

+  /**

+   * Convert an array list to a uima array  (int, float, fs, string) 

+   *   - add to fss

+   *   - go thru fss and null out list elements

+   *   

+   * @param al -

+   * @param fss -

+   */

+  private void convert_to_array(

+      ArrayList<CommonList> al, 

+      ArrayList<TOP> fss,

+      CASImpl view,

+      TypeSystemImpl tsi) {

+    

+    CommonList e = al.get(0);  

+    if (e instanceof FSList) {

+      assert al.size() > 0;

+      FSArray<TOP> fsa = new FSArray<>(tsi.fsArrayType, view, al.size());

+      int i = 0;

+      for (CommonList n : al) {

+        assert !n.isEmpty();

+        fsa.set(i++, ((NonEmptyFSList)n).getHead());

+        fss.set(node_indexes.get(n) - 1, null);

+      }

+      fss.add(fsa);

+    } else if (e instanceof IntegerList) {

+      IntegerArray a = new IntegerArray(tsi.intArrayType, view, al.size());

+      int i = 0;

+      for (CommonList n : al) {

+        a.set(i++, (n instanceof EmptyList) 

+                       ? Integer.MIN_VALUE 

+                       : ((NonEmptyIntegerList)n).getHead());

+        fss.set(node_indexes.get(n) - 1, null);

+      }

+      fss.add(a);

+    } else if (e instanceof FloatList) {

+      FloatArray a = new FloatArray(tsi.floatArrayType, view, al.size());

+      int i = 0;

+      for (CommonList n : al) {

+        a.set(i++, (n instanceof EmptyList) 

+                       ? Float.MIN_VALUE 

+                       : ((NonEmptyFloatList)n).getHead());

+        fss.set(node_indexes.get(n) - 1, null);

+      }

+      fss.add(a);

+    } else if (e instanceof StringList) {

+      StringArray a = new StringArray(tsi.stringArrayType, view, al.size());

+      int i = 0;

+      for (CommonList n : al) {

+        a.set(i++, (n instanceof EmptyList) 

+                       ? null 

+                       : ((NonEmptyStringList)n).getHead());

+        fss.set(node_indexes.get(n) - 1, null);

+      }

+      fss.add(a);

+    } else Misc.internalError();

+    

+  }

+  

+  /**

+   * walk down list, adding successors, looking for loops

+   *   - each element is added to the array list, and also to the map from id -> array list

+   *   - if loop found, stop and return false

+   *   

+   *   - before adding element, see if already in map from id -> array list

+   *     -- if so, couple the array lists

+   * @param node -

+   * @param al -

+   * @return false if loop found

+   */

+  private boolean addSuccessors(CommonList node, ArrayList al) {

+    try {

+      list_successor_seen.add(node._id());  // starts reset, reset at end

+      

+      while (!node.isEmpty()) {

+        node = node.getCommonTail();

+        if (node == null || node.isEmpty()) break;

+        

+        if (!list_successor_seen.add(node._id())) return false;  // stop if loop is found

+  

+        ArrayList<CommonList> other = map_e_to_a_list.get(node._id());

+        if (null != other) { 

+          couple_array_lists(al, other, node);

+          return true;  // rest of list already walked

+        } else {

+          al.add(node);

+          map_e_to_a_list.put(node._id(), al);   // every element maps to containing al

+        }

+      }

+      return true;

+    } finally {

+      list_successor_seen.clear();

+    }

+  }

+  

+  /**

+   * merge a2 to follow a1, starting from position where commonNode is in a2

+   * @param a1 -

+   * @param a2 -

+   * @param commonNode -

+   */

+  private void couple_array_lists(ArrayList<CommonList> a1, ArrayList<CommonList> a2, CommonList commonNode) {

+    int i = 0;

+    int sz2 = a2.size();

+    for (; i < sz2; i++) {

+      if (commonNode == a2.get(i)) break;

+    }

+    

+    if (i == sz2) Misc.internalError();

+    

+    for (; i < sz2; i++) {

+      CommonList node = a2.get(i);

+      map_e_to_a_list.put(node._id(), a1);  // remove a2 value, put in a1 value

+      a1.add(node);

+    }    

+  }

+  

+  private void move_to_non_linear(ArrayList<CommonList> al) {

+    for (CommonList e : al) {

+      map_e_to_a_list.remove(e._id());

+      non_linear_list_elements.add(e._id());

+    }

+  }

+

+  

+  

+  

+  private void clearPrevFss() {

+    prevCompare.clear();

+    prev1.clear();

+    prev2.clear();

+  }

+  

+  /**

+   * To work with Java sort, must implement the comparator contract:

+   *   - compare(x, y) must be opposite compare(y, x)

+   *   - compare(x, y) < 0 && compare(y, z) < 0 implies compare(x, z) < 0

+   *   - compare(x, y) == 0 implies compare(x, z) same as compare(y, z) for any z

+   * 

+   * Inner part of compareRefs; that other method adds: 

+   *   null-check

+   *   type-mapping skips

+   *   loop determination 

+   *   

+   * If not in a sort context, a miscompare generates messaging information.

+   *   

+   * @param callerTi - the type of another FS referencing this one, or null, used in congruence set testing

+   * @param callerFi - the feature of the another FS referencing this one, or null, used in congruence set testing

+   * 

+   * @return the compare result

+   * 

+   */

+  private int compareFss(TOP fs1, TOP fs2, TypeImpl callerTi, FeatureImpl callerFi) {

+   

+    if (fs1 == fs2) {

+      return 0;

+    }

+    

+    TypeImpl ti1 = fs1._getTypeImpl();

+    TypeImpl ti2 = fs2._getTypeImpl();  // even if not type mapping, may be "equal" but not ==

+    int r = 0;

+    

+    if (!inSortContext && isTypeMapping) {

+      ti2 = typeMapper.mapTypeTgt2Src(ti2);

+    }

+

+    r = ti1.compareTo(ti2);

+    if (r != 0) {

+      if (!inSortContext) {

+        mismatchFs(fs1, fs2, "Different Types"); // types mismatch

+      }

+      return r;

+    }

+ 

+    if (isCompareIds && !inSortContext) {

+      if (fs1._id < maxId1 && fs2._id < maxId2 && fs1._id != fs2._id) {

+        mismatchFs(fs1, fs2, "IDs miscompare");        

+        return Integer.compare(fs1._id, fs2._id);

+      }

+    }

+

+    if (ti1.isArray()) {

+      return compareFssArray(fs1, fs2, callerTi, callerFi);

+    } 

+

+    FeatLists featLists = type2featLists.get(ti1);

+    if (featLists == null) {

+      type2featLists.put(ti1, featLists = computeFeatLists(ti1));

+    }

+

+    // compare features, non-refs first (for performance)

+    for (FeatureImpl[] featSet : featLists.featsByEase) {

+      for (FeatureImpl fi1 : featSet) {

+        if (0 != (r = compareFeature(fs1, fs2, ti1, fi1))) {

+          return r;

+        }

+      } 

+    }

+    return 0;

+  }

+     

+  private int compareFeature(TOP fs1, TOP fs2, TypeImpl ti1, FeatureImpl fi1) {

+    int r = 0;

+    if (inSortContext && isTypeMapping) {

+      if (isSrcCas && typeMapper.getTgtFeature(ti1, fi1) == null) {

+        return 0; // skip tests for features not in target type system

+                  // so when comparing CASs, the src value won't cause a miscompare

+      }

+      if (!isSrcCas && typeMapper.getSrcFeature(ti1,  fi1) == null) {

+        return 0; // types/features belong to target in this case

+      }

+    }

+    FeatureImpl fi2 = (!inSortContext && isTypeMapping) ? typeMapper.getTgtFeature(ti1, fi1) : fi1;

+    if (fi2 != null) {

+      r = compareSlot(fs1, fs2, fi1, fi2, ti1);

+      if (0 != r) {

+        if (!inSortContext) {

+//          // debug

+//          compareSlot(fs1, fs2, fi1, fi2, ti1);

+          mismatchFs(fs1, fs2, fi1, fi2);

+        }

+        return r;

+      }

+    } // else we skip the compare - no slot in tgt for src

+    return r;

+  }

+  

+  /**

+   * called during sort phase

+   * @param ti - type being sorted

+   * @return the feature lists for that type

+   */

+  private FeatLists computeFeatLists(TypeImpl ti) {

+    List<FeatureImpl> easy = new ArrayList<>();  

+    List<FeatureImpl> easyArrays = new ArrayList<>();  

+    List<FeatureImpl> ref = new ArrayList<>();  

+    List<FeatureImpl> refArrays = new ArrayList<>();

+    

+    for (FeatureImpl fi : ti.getFeatureImpls()) {

+      

+      if (isTypeMapping) {

+

+        if (isSrcCas && typeMapper.getTgtFeature(ti, fi) == null) {

+          continue; // skip for features not in target type system

+                    // so when comparing CASs, the src value won't cause a miscompare

+        }

+        

+        // probably not executed, since types discovered on first sort

+        // except for a type that exists only the the target

+        if (!isSrcCas && typeMapper.getSrcFeature(ti,  fi) == null) {

+          continue; // types/features belong to target in this case

+        }

+        

+      }

+            

+      TypeImpl range = fi.getRangeImpl();

+      if (range.isArray()) {

+        TypeImpl_array ra = (TypeImpl_array)range;

+        if (ra.getComponentType().isRefType) {

+          refArrays.add(fi);

+        } else {

+          easyArrays.add(fi);

+        }

+      } else {

+        if (range.isRefType) {

+          ref.add(fi);

+        } else {

+          easy.add(fi);

+        }

+      }

+    }

+    return new FeatLists(easy, easyArrays, ref, refArrays);

+  }

+  

+  

+//    private int compareFssArray() {

+//      int r = compareFssArray((CommonArrayFS) fs1, (CommonArrayFS) fs2);

+//      if (r != 0) {

+//        if (!inSortContext) mismatchFs();

+//      }

+//      return r;

+//    }

+  

+  private int compareFssArray(TOP fs1, TOP fs2, TypeImpl callerTi, FeatureImpl callerFi) {

+    CommonArrayFS a1 = (CommonArrayFS) fs1;

+    CommonArrayFS a2 = (CommonArrayFS) fs2;

+    int r;

+    

+    int len1 = a1.size();

+    int len2 = a2.size();

+    r = Integer.compare(len1,  len2);

+    if (r != 0) {

+      if (!inSortContext) {

+        mismatchFs(fs1, fs2);

+      }

+      return r;

+    }

+    

+//    if (inSortContext && !compareArraysByElement) {

+//      // quick approximate comparison of arrays, for sort purposes

+//      return Integer.compare(((FeatureStructureImplC)fs1)._id, 

+//                             ((FeatureStructureImplC)fs2)._id);

+//    }

+    TypeImpl ti = ((FeatureStructureImplC)a1)._getTypeImpl();

+    SlotKind kind = ti.getComponentSlotKind();

+    

+    switch(kind) {

+    case Slot_BooleanRef: r = compareAllArrayElements(fs1, fs2, len1, i -> Boolean.compare(

+                                                                    ((BooleanArray)a1).get(i),

+                                                                    ((BooleanArray)a2).get(i)));

+      break;

+    case Slot_ByteRef:    r = compareAllArrayElements(fs1, fs2, len1, i -> Byte.compare(

+                                                                    ((ByteArray   )a1).get(i),

+                                                                    ((ByteArray   )a2).get(i)));

+      break;

+    case Slot_ShortRef:   r = compareAllArrayElements(fs1, fs2, len1, i -> Short.compare(

+                                                                    ((ShortArray  )a1).get(i),

+                                                                    ((ShortArray  )a2).get(i)));

+      break;

+    case Slot_Int:     r = compareAllArrayElements(fs1, fs2, len1, i -> Integer.compare(

+                                                                    ((IntegerArray)a1).get(i),

+                                                                    ((IntegerArray)a2).get(i)));

+      break;

+    case Slot_LongRef:  r = compareAllArrayElements(fs1, fs2, len1, i -> Long.compare(

+                                                                    ((LongArray   )a1).get(i),

+                                                                    ((LongArray   )a2).get(i)));

+      break;

+

+    // don't compare floats / doubles directly - because two "equal" NaN are defined to miscompare

+    case Slot_Float: r = compareAllArrayElements(fs1, fs2, len1, i -> Integer.compare(

+                                                                    CASImpl.float2int(((FloatArray  )a1).get(i)), 

+                                                                    CASImpl.float2int(((FloatArray  )a2).get(i))));

+      break;

+

+    // don't compare floats / doubles directly - because two "equal" NaN are defined to miscompare

+    case Slot_DoubleRef: r = compareAllArrayElements(fs1, fs2, len1, i -> Long.compare(

+                                                                    CASImpl.double2long(((DoubleArray)a1).get(i)), 

+                                                                    CASImpl.double2long(((DoubleArray)a2).get(i))));

+      break;

+    case Slot_HeapRef: r = compareAllArrayElements(fs1, fs2, len1, i -> compareRefs( ((FSArray) a1).get(i), 

+                                                                           ((FSArray) a2).get(i), 

+                                                                           callerTi, 

+                                                                           callerFi));

+      break;

+    case Slot_StrRef: r = compareAllArrayElements(fs1, fs2, len1, i -> compareStringsWithNull(

+                                                                    ((StringArray)a1).get(i), 

+                                                                    ((StringArray)a2).get(i), 

+                                                                    callerTi, 

+                                                                    callerFi, 

+                                                                    i));

+      break;

+    default: 

+      throw Misc.internalError(); 

+    }

+    

+    return r;

+  }

+          

+  private int compareSlot(TOP fs1, TOP fs2, FeatureImpl fi1, FeatureImpl fi2, TypeImpl ti1) {

+    SlotKind kind = fi1.getSlotKind();

+    switch (kind) {

+    case Slot_Int: return Integer.compare(fs1._getIntValueNc(fi1), fs2._getIntValueNc(fi2)); 

+    case Slot_Short: return Short.compare(fs1._getShortValueNc(fi1), fs2._getShortValueNc(fi2));

+    case Slot_Boolean: return Boolean.compare(fs1._getBooleanValueNc(fi1), fs2._getBooleanValueNc(fi2));

+    case Slot_Byte: return Byte.compare(fs1._getByteValueNc(fi1), fs2._getByteValueNc(fi2));

+          // don't compare floats / doubles directly - the NaN is defined to miscompare

+    case Slot_Float: return Integer.compare(CASImpl.float2int(fs1._getFloatValueNc(fi1)), CASImpl.float2int(fs2._getFloatValueNc(fi2)));

+    case Slot_HeapRef: return compareRefs(fs1._getFeatureValueNc(fi1), fs2._getFeatureValueNc(fi2), ti1, fi1);

+    case Slot_StrRef: return compareStringsWithNull(fs1._getStringValueNc(fi1), fs2._getStringValueNc(fi2), ti1, fi1, -1);

+    case Slot_LongRef: return Long.compare(fs1._getLongValueNc(fi1), fs2._getLongValueNc(fi2));

+          // don't compare floats / doubles directly - the NaN is defined to miscompare

+    case Slot_DoubleRef: return Long.compare(Double.doubleToRawLongBits(fs1._getDoubleValueNc(fi1)), Double.doubleToRawLongBits(fs2._getDoubleValueNc(fi2)));

+    default: Misc.internalError(); return 0;     

+    }

+  }

+  

+  /**

+   * Two uses cases supported:

+   *   - comparing for sorting (within on type system)

+   *      -- goal is to be able to compare two CASes

+   *         --- ordering must guarantee that the equal FSs appear in the

+   *         --- same order

+   *   - comparing two FSs (maybe from different CASes)

+   *     -- supporting missing types and features 

+   *        -- happens when the two type systems are different

+   *        -- the missing types and features are ignored in the comparison

+   * 

+   * Different reference chains

+   *   This compare routine may be called recursively

+   *     - use case: FS(a) has slot which is ref to 

+   *                   FS(b) which has slot which is ref to

+   *                     FS(c) 

+   *       -- the type of a, b, c may all be different.

+   *   

+   *   Two reference chains for the two arguments may have different structures

+   *     - Difference in two ways:  

+   *       -- length of unique (same fs_id) FSs

+   *       -- length of loop (if one exists at the end reached so far)

+   *       

+   *   IMPORTANT: the following 2 chains have different lengths, but this

+   *   won't be discovered if the recursive descent stops too soon:

+   *     - a -> b -> c  ( -> b )

+   *     - c -> b ( -> c)

+   *   At the 2nd recursion, we have b vs b, but haven't explored the chain 

+   *   deeply enough to know the first one has length 3, and the 2nd length 2.            

+   *       

+   * Meaning of comparision of two refs:  

+   *   - recursively defined

+   *   - captures notion of reference chain differences

+   *     -- means if two refs compare 0, the result may still be

+   *        non-0 if the reference chains to get to these are different

+   *       -- first compare on length of unique FSs

+   *       -- if ==, compare on length of loop

+   *   - if comparing (use case 2, two different type systems) with 

+   *     type not existing in other type system, skip (treat as 0).

+   * 

+   * If comparing two FSs in 1 CAS, where there is type mapping, if the mapping to

+   *   the other CAS is null, change the value of the FS to null to match the sort order

+   *   the other CAS will haveand that mapping is

+   *   to null (because the type is missing), use null for the argument(s).

+   * 

+   * Complexities: the type rfs1 may not be in the target type system.

+   *   For this case - treat rfs2 == null as "equal", rfs2 != null as not equal (always gt)

+   *   Is assymetrical (?) - same logic isn't applied for reverse case.

+   * @param rfs1 -

+   * @param rfs2 -

+   * @param fi -

+   * @return -

+   */

+  private int compareRefs(TOP rfs1, TOP rfs2, TypeImpl callerTi, FeatureImpl callerFi) {

+    if (inSortContext && isTypeMapping) {

+      if (isSrcCas) {

+        if (rfs1 != null && typeMapper.mapTypeSrc2Tgt(rfs1._getTypeImpl()) == null) {

+          rfs1 = null;

+        }

+        if (rfs2 != null && typeMapper.mapTypeSrc2Tgt(rfs2._getTypeImpl()) == null) {

+          rfs2 = null;

+        }

+      } else {

+        if (rfs1 != null && typeMapper.mapTypeTgt2Src(rfs1._getTypeImpl()) == null) {

+          rfs1 = null;

+        }

+        if (rfs2 != null && typeMapper.mapTypeTgt2Src(rfs2._getTypeImpl()) == null) {

+          rfs2 = null;

+        }

+      }

+    }

+    

+    if (rfs1 == null) {

+      if (rfs2 != null) {

+        if (!inSortContext && isTypeMapping &&

+                typeMapper.mapTypeTgt2Src(rfs2._getTypeImpl()) == null) {

+          return 0;

+        } else {

+          if (IS_DEBUG_STOP_ON_MISCOMPARE && !inSortContext) {

+            System.out.println("debug stop");

+          }

+          return -1;

+        }

+//        return (!inSortContext && isTypeMapping &&

+//                typeMapper.mapTypeTgt2Src(rfs2._getTypeImpl()) == null)

+//                  ? 0   // no source type for this target type, treat as equal

+//                  : -1;

+      }

+      return 0;  // both are null.  no loops in ref chain possible 

+    }

+

+    // rfs1 != null at this point

+    

+     if (rfs2 == null) {

+       if (!inSortContext && isTypeMapping &&

+           typeMapper.mapTypeSrc2Tgt(rfs1._getTypeImpl()) == null) {

+         return 0;

+       } else {

+         if (IS_DEBUG_STOP_ON_MISCOMPARE && !inSortContext) {

+           System.out.println("debug stop");

+         } 

+         return 1;

+       }

+//      return (!inSortContext && isTypeMapping &&

+//              typeMapper.mapTypeSrc2Tgt(rfs1._getTypeImpl()) == null)

+//                ? 0 // no target type for this target type, treat as equal

+//                : 1;  

+    }

+     

+    if (rfs1 == rfs2) {

+      // only for inSortContext

+      return 0;

+    }

+    

+    // next commented out to enable finding length of chain      

+//      if (inSortContext && rfs1._id == rfs2._id) {  

+//        return compareRefResult(rfs1, rfs2);

+//      }

+    

+    // both are not null

+    // do a recursive check 

+    Pair<TOP, TOP> refs = new Pair<TOP, TOP>(rfs1, rfs2);

+    Integer prevComp = prevCompare.get(refs);

+     if (prevComp != null) {  

+       int v = prevComp.intValue();

+       if (v == 0) {

+         return compareRefResult(rfs1, rfs2); // stop recursion, return based on loops

+       } else {

+         if (IS_DEBUG_STOP_ON_MISCOMPARE && !inSortContext) {

+           System.out.println("debug stop");

+         }

+         return v;

+       }

+//       return (v == 0) 

+//               ? compareRefResult(rfs1, rfs2) // stop recursion, return based on loops

+//               : v;    

+    }

+    prevCompare.put(refs, 0); // preset in case recursion compares this again

+    

+    // need special handling to detect cycles lengths that are back to the original

+    if (prev1.prevCompareTop != null) {

+      prev1.addTop();

+      prev2.addTop();

+    }

+    

+    prev1.add(rfs1);

+    prev2.add(rfs2);

+    assert prev1.fsList.size() > 0;

+//    TOP savedFs1 = fs1;

+//    TOP savedFs2 = fs2;

+    

+//    fs1 = rfs1;

+//    fs2 = rfs2;

+    try {

+      int v = compareFss(rfs1, rfs2, callerTi, callerFi);

+      if (v != 0) {

+        prevCompare.put(refs, v);

+      }

+      return v;

+    } finally {

+      prev1.rmvLast(rfs1);

+      prev2.rmvLast(rfs2);

+      

+//      fs1 = savedFs1;

+//      fs2 = savedFs2;   

+    }

+  }

+  

+  /**

+   * Returning because recursion detected a loop.

+   * 

+   * @param rfs1 -

+   * @param rfs2 -

+   * @return - -1 if ref chain 1 length < ref chain 2 length or is the same length but loop length 1 < 2

+   *            1 if ref chain 1 length > ref chain 2 length or is the same length but loop length 1 > 2

+   *            0 if ref chain lengths are the same and loop length is the same

+   *            Exception: if one of the items is a canonical "empty" list element, and the other 

+   *              is a non-canonical one - treat as equal.

+   */

+  private int compareRefResult(TOP rfs1, TOP rfs2) {

+    

+    // exception: treat canonical empty lists

+    if (!inSortContext && IS_CANONICAL_EMPTY_LISTS && rfs1 instanceof EmptyList) {

+//      if (prev1.size() <= 0 || prev2.size() <= 0) {

+        return 0;

+//      }

+    }

+    

+    if (prev1.size() <= 0) { 

+      return 0;  // no recursion case

+    }

+    

+    // had some recursion

+    prev1.add(rfs1);

+    prev2.add(rfs2);

+    

+    try { // only for finally block

+      // compare cycleLen first, because if !=, all ref pairs in above chain are !=

+      //   but if ==, then all cycle pairs are compare ==.

+      int r = prev1.compareCycleLen(prev2);

+      

+      if (r != 0) {

+        if (IS_DEBUG_STOP_ON_MISCOMPARE && !inSortContext) {

+          System.out.println("debug stop");

+        }

+        return r;

+      }

+      

+      if (prev1.cycleLen > 0) {  // && is equal to prev2 cycle length

+        return 0;  // at this level, the FSs are equal

+      }

+      

+      return prev1.compareUsize(prev2);

+      

+    } finally {

+      prev1.rmvLast(rfs1);

+      prev2.rmvLast(rfs2);

+    }

+  }

+      

+  private int compareAllArrayElements(TOP fs1, TOP fs2, int len, IntUnaryOperator c) {

+    int r = 0;

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

+      r = c.applyAsInt(i);

+      if (r != 0) {

+        if (!inSortContext) {

+          mismatchFs(fs1, fs2, "Comparing array of length " + len);

+        }

+        return r;

+      }

+    }

+    // need to return 0 if == in sort context, otherwise violates the 

+    // comparator contract

+    return 0;

+  }

+  

+  private int compareStringsWithNull(String s1, String s2, TypeImpl t, FeatureImpl f, int index) {

+    if (isUsingStringCongruenceSets) {

+      String[] scs = stringCongruenceSets.get(new ScsKey(t, f, index));

+      

+      if (scs != null) {

+        if (Misc.contains(scs, s1) &&

+            Misc.contains(scs, s2)) {

+          return 0;

+        }

+      }

+    }

+    

+    if (null == s1) {

+      return (null == s2) ? 0 : -1;

+    }

+    if (null == s2) {

+      return 1;

+    }

+    return s1.compareTo(s2);

+  }

+  

+//    private int skipOverTgtFSsNotInSrc(

+//        int[] heap, int heapEnd, int nextFsIndex, CasTypeSystemMapper typeMapper) {

+//      final TypeSystemImpl ts = typeMapper.tsTgt;

+//      for (; nextFsIndex < heapEnd;) {

+//        final int tCode = heap[nextFsIndex];

+//        if (typeMapper.mapTypeCodeTgt2Src(tCode) != 0) { 

+//          break;

+//        }

+//        nextFsIndex += incrToNextFs(heap, nextFsIndex, ts.getTypeInfo(tCode));

+//      }

+//      return nextFsIndex;

+//    }

+//    

+//    public void initSrcTgtIdMapsAndStringsCompare () {

+//

+//      int iTgtHeap = isTypeMapping ? skipOverTgtFSsNotInSrc(c2heap, c2end, 1, typeMapper) : 1;

+//      

+//      

+//      for (int iSrcHeap = 1; iSrcHeap < c1end;) {

+//        final int tCode = c1heap[iSrcHeap];

+//        final int tgtTypeCode = isTypeMapping ? typeMapper.mapTypeCodeSrc2Tgt(tCode) : tCode;

+//        final boolean isIncludedType = (tgtTypeCode != 0);

+//        

+//        // record info for type

+//        fsStartIndexes.addItemId(iSrcHeap, iTgtHeap, isIncludedType);  // maps src heap to tgt seq

+//        

+//        // for features in type - 

+//        //    strings: accumulate those strings that are in the target, if optimizeStrings != null

+//        //      strings either in array, or in individual values

+//        //    byte (array), short (array), long/double (instance or array): record if entries in aux array are skipped

+//        //      (not in the target).  Note the recording will be in a non-ordered manner (due to possible updates by

+//        //       previous delta deserialization)

+//        final TypeInfo srcTypeInfo = ts1.getTypeInfo(tCode);

+//        final TypeInfo tgtTypeInfo = (isTypeMapping && isIncludedType) ? ts2.getTypeInfo(tgtTypeCode) : srcTypeInfo;

+//              

+//        // Advance to next Feature Structure, in both source and target heap frame of reference

+//        if (isIncludedType) {

+//          final int deltaTgtHeap = incrToNextFs(c1heap, iSrcHeap, tgtTypeInfo);

+//          iTgtHeap += deltaTgtHeap;

+//          if (isTypeMapping) {

+//            iTgtHeap = skipOverTgtFSsNotInSrc(c2heap, c2end, iTgtHeap, typeMapper);

+//          }

+//        }

+//        iSrcHeap += incrToNextFs(c1heap, iSrcHeap, srcTypeInfo);

+//      }

+//    } 

+

+  private void mismatchFsDisplay() {

+    String s = mismatchSb.toString();

+    System.err.println(s);

+    mismatchSb.setLength(0);

+  }

+  

+  private void mismatchFs(TOP fs1, TOP fs2) {

+    mismatchSb.append(String.format("Mismatched Feature Structures:%n %s%n %s%n", ps(fs1), ps(fs2)));

+//    // debug

+//    System.out.println("adding to miscompares: " + fs1._id + " " + fs2._id);

+//    miscompares.add(new Pair<>(fs1, fs2));

+  }

+

+//    private boolean mismatchFs(int i1, int i2) {

+//      System.err.format("Mismatched Feature Structures in srcSlot %d, tgtSlot %d%n %s%n %s%n", 

+//          i1, i2, dumpHeapFs(c1, c1heapIndex, ts1), dumpHeapFs(c2, c2heapIndex, ts2));

+//      return false;

+//    }

+  

+//    private void mismatchFs(Feature fi) {

+//      mismatchSb.append(String.format("Mismatched Feature Structures in feature %s%n %s%n %s%n", 

+//          fi.getShortName(), fs1, fs2));

+//    }

+  

+  private void mismatchFs(TOP fs1, TOP fs2, Feature fi, Feature fi2) {

+    String mapmsg = fi.equals(fi2) 

+                      ? ""

+                      : "which mapped to target feature " + fi2.getShortName() + " ";

+    mismatchSb.append(String.format("Mismatched Feature Structures in feature %s %s%n %s%n %s%n", 

+        fi.getShortName(), mapmsg, ps(fs1), ps(fs2)));

+  }

+  

+  private void mismatchFs(TOP fs1, TOP fs2, String msg) {

+    mismatchSb.append(String.format("Mismatched Feature Structures, %s%n %s%n %s%n", 

+        msg, ps(fs1), ps(fs2)));

+  }

+      

+  /** called to sort all the FSs before doing the equality compares */

+  private void sort(List<TOP> fss) {

+    inSortContext = true;

+    // do before sorting

+    clearPrevFss();

+

+    try {

+      Collections.sort(fss,  

+            (afs1, afs2) -> sortCompare(afs1, afs2));

+//            (afs1, afs2) -> Integer.compare(afs1._id, afs2._id));

+    } finally {

+      inSortContext = false;

+    }

+  }

+  

+  /**

+   * Used for sorting within one type system, for two instances of the same type

+   * 

+   * Uses field isSrcCas (boolean) to differentiate when being used to sort for srcCas vs tgtCas

+   * 

+   * When sorting where type mapping is happening between source and target CASs, skip compares for

+   * features which are not in the opposite CAS.

+   * 

+   * @param scFs1 -

+   * @param scFs2 -

+   * @return -

+   */

+  private int sortCompare(TOP scFs1, TOP scFs2) {  

+    

+    if (scFs1 == null) {

+      return (scFs2 == null) ? 0 : 1;

+    } 

+    if (scFs2 == null) {

+      return -1;

+    }

+    

+//    miscompares.clear();

+    prev1.clear();

+    prev2.clear();

+    

+    prev1.prevCompareTop = scFs1;

+    prev2.prevCompareTop = scFs2;

+    int r = compareFss(scFs1, scFs2, null, null);

+    prev1.prevCompareTop = null;

+    prev2.prevCompareTop = null;

+    if (r == 0) {

+      r = Integer.compare(scFs1._id, scFs2._id);

+    }

+    return r;

+  }

+      

+  private boolean isTypeInTgt(TOP fs) {

+    return !isTypeMapping || (null != typeMapper.mapTypeSrc2Tgt(fs._getTypeImpl()));

+  }

+  

+  private String ps(TOP fs) { 

+    StringBuilder sb = new StringBuilder();

+    fs.prettyPrintShort(sb);

+    return sb.toString();

+  }

+}

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasSeqAddrMaps.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasSeqAddrMaps.java
index 35bd27b..5b103a6 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasSeqAddrMaps.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasSeqAddrMaps.java
@@ -26,7 +26,7 @@
 import org.apache.uima.jcas.cas.TOP;
 
 /**
- * Used by Binary serialization form 6
+ * Used by Binary serialization form 4 and 6
  * 
  * Manage the conversion of FSs to relative sequential index number, and back 
  * Manage the difference in two type systems
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasSerializerSupport.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasSerializerSupport.java
index 9956373..77a4686 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasSerializerSupport.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasSerializerSupport.java
@@ -41,8 +41,11 @@
 import org.apache.uima.cas.CAS;

 import org.apache.uima.cas.CASRuntimeException;

 import org.apache.uima.cas.FSIndex;

+import org.apache.uima.internal.util.Misc;

 import org.apache.uima.internal.util.XmlElementName;

+import org.apache.uima.internal.util.function.Consumer_withSaxException;

 import org.apache.uima.jcas.cas.CommonList;

+import org.apache.uima.jcas.cas.CommonPrimitiveArray;

 import org.apache.uima.jcas.cas.FSArray;

 import org.apache.uima.jcas.cas.FSList;

 import org.apache.uima.jcas.cas.NonEmptyFSList;

@@ -51,7 +54,6 @@
 import org.apache.uima.jcas.cas.TOP;

 import org.apache.uima.jcas.tcas.Annotation;

 import org.apache.uima.util.Logger;

-import org.apache.uima.util.MessageReport;

 import org.xml.sax.ContentHandler;

 import org.xml.sax.ErrorHandler;

 import org.xml.sax.SAXException;

@@ -72,7 +74,7 @@
  * an inner class - one per serialize call.

  * 

  * These classes are the common parts of serialization between XMI and JSON, mainly having to do with

- *   1) enquuing the FS to be serialized

+ *   1) enqueueing the FS to be serialized

  *   2) serializing according to their types and features

  *     

  * 

@@ -109,8 +111,30 @@
  *       ** Could ** not do this if no oots elements, but could break some assumptions

  *       and this only would apply to non-delta - not worth doing

  *       

+ * Enqueuing:

+ *   There are two styles

+ *     - enqueueCommon: does **NOT** recursively enqueue features

+ *     - enqueue: calls enqueueCommon and then recursively enqueues features

+ *     

+ *   enqueueCommon is called (bypassing enqueue) to defer scanning references 

+ *   

+ *   Order and target of enqueuing:

+ *     - things in the index 

+ *       -- put on "queue"

+ *       -- first, the sofa's (which are the only things indexed in base view)

+ *       -- next, for each view, for each item, the FSs, but **NOT** following any feature/array refs

+ *     - things not in the index, but deserialized (incoming)

+ *       -- put on previouslySerializedFSs, no recursive descent for features  

+ *     - (delta) enqueueNonsharedMultivaluedFS (lists and arrays)

+ *       -- put on modifiedEmbeddedValueFSs, no recursive descent for features

  *       

- *                      

+ *     - recursive descent for        

+ *       -- things in previouslySerializedFSs,

+ *       -- things in modifiedEmbeddedValueFSs

+ *       -- things in the index

+ *

+ *       The recursive descent is recursive, and an arbitrary long chain can get stack overflow error.

+ *       TODO Probably should fix this someday. See https://issues.apache.org/jira/browse/UIMA-106 *                      

  */

 

 public class CasSerializerSupport {

@@ -270,18 +294,58 @@
     public final TypeSystemImpl tsi;

 

     /** 

-     * set of FSs that have been enqueued to be serialized

-     *  Computed during "enqueue" phase, prior to encoding

-     *  Used to prevent duplicate enqueuing

+     * set of FSs that have been visited and enqueued to be serialized

+     *   - exception: arrays and lists which are "inline" are put into this set,

+     *     but are not enqueued to be serialized.

+     *     

+     *   - FSs added to this, during "enqueue" phase, prior to encoding

+     *     

+     * uses:    

+     *   - for Arrays and Lists, used to detect multi-refs

+     *   - for Lists, used to detect loops

+     *   - during enqueuing phase, prevent multiple enqueuings

+     *   - during encoding phase, to prevent multiple encodings 

+     *  

+     *  Public for use by JsonCasSerializer

      */    

     public final Set<TOP> visited_not_yet_written = Collections.newSetFromMap(new IdentityHashMap<>()); 

+     

+    /**

+     * Set of array or list FSs referenced from features marked as multipleReferencesAllowed,

+     *   - which have previously been serialized "inline"

+     *   - which now need to be serialized as separate items

+     *   

+     * Set during enqueue scanning, to handle the case where the

+     * "visited_not_yet_written" set may have already recorded that this FS is 

+     * already processed for enqueueing, but it is an array or list item which was being

+     * put "in-line" and no element is being written.

+     * 

+     * It has array or list elements where the item needs to be enqueued onto the "queue" list.

+     * 

+     * Use: limit the put-onto-queue list to one time

+     */

+    private final Set<TOP> enqueued_multiRef_arrays_or_lists = Collections.newSetFromMap(new IdentityHashMap<>());

     

     /**

-     * set of FSs that have multiple references

+     * Set of FSs that have multiple references

+     * Has an entry for each FS (not just array or list FSs) which is (from some point on) being serialized as a multi-ref,

+     *   that is, is **not** being serialized (any more) using the special notation for arrays and lists

+     *   or, for JSON, **not** being serialized using the embedded notation

      * This is for JSON which is computing the multi-refs, not depending on the setting in a feature.

+     * This is also for xmi, to enable adding to "queue" (once) for each FSs of this kind.

+     * 

+     * Used: 

+     *   - limit the number of times this is put onto the queue to 1.

+     *   - skip encoding of items on "queue" if not in this Set (maybe not needed? 8/2017 mis)

+     *   - serialize if not in indexed set, dynamic ref == true, and in this set (otherwise serialize only from ref)

      */

     public final Set<TOP> multiRefFSs; 

     

+    /**

+     * Set to true for JSON configuration of using dynamic multi-ref detection for arrays and lists

+     */

+    public final boolean isDynamicMultiRef;

+

     /* *********************************************

      * FSs that need to be serialized because they're 

      *   a) in an index

@@ -402,7 +466,8 @@
   	    throw new CASRuntimeException(CASRuntimeException.INVALID_MARKER, "Invalid Marker.");

       }

       isDelta = marker != null;

-      multiRefFSs = (trackMultiRefs) ? Collections.newSetFromMap(new IdentityHashMap<>()) : null;

+      multiRefFSs = Collections.newSetFromMap(new IdentityHashMap<>());

+      isDynamicMultiRef = trackMultiRefs;

     }

         

     // TODO: internationalize

@@ -410,7 +475,7 @@
       String message = String.format("Feature %s is marked multipleReferencesAllowed=false, but it has"

           + " multiple references.  These will be serialized in duplicate.", 

           fi.getName());

-      MessageReport.decreasingWithTrace(errorCount, message, logger);

+      Misc.decreasingWithTrace(errorCount, message, logger);

       if (this.errorHandler2 != null) {

         this.errorHandler2.warning(new SAXParseException(message, null));

       }

@@ -491,14 +556,14 @@
         final Sofa sofa = getSofa(sofaNum);

         if (loopIR != null) {

           if (!isDelta) {

-            Collection<TOP> fsarray = loopIR.getIndexedFSs();

-            csss.writeView(sofa, fsarray);

+            Collection<TOP> fss = loopIR.getIndexedFSs();

+            csss.writeView(sofa, fss);

           } else { // is Delta Cas

         	  if (sofaNum != 1 && this.marker.isNew(sofa)) {

         	    // for views created after mark (initial view never is - it is always created with the CAS)

         	    // write out the view as new

-        	    List<TOP> fsarray = loopIR.getIndexedFSs();

-              csss.writeView(sofa, fsarray);

+        	    Collection<TOP> fss = loopIR.getIndexedFSs();

+              csss.writeView(sofa, fss);

         	  } else if (loopIR.isModified()) {

         	    csss.writeView(sofa, loopIR.getAddedFSs(), loopIR.getDeletedFSs(), loopIR.getReindexedFSs());

           	}

@@ -579,6 +644,7 @@
         }

                 

         // is the first instance, but skip if delta and not modified or above the line or filtered

+        // skip enqueuing incoming FS if already enqueued 

         int typeCode = enqueueCommon(fs);

         if (typeCode == -1) {

           continue;

@@ -594,10 +660,10 @@
      */

     private void enqueueIndexed()  {

       FSIndexRepositoryImpl ir = (FSIndexRepositoryImpl) cas.getBaseCAS().getBaseIndexRepository();

-      List<TOP> fss = ir.getIndexedFSs();  // only sofas

+      Collection<TOP> fss = ir.getIndexedFSs();  // only sofas

       try {

         for (TOP fs : fss) {

-          enqueue(fs);  // put Sofa on by-ref queue

+          enqueueFsAndMaybeFeatures(fs);  // put Sofa on by-ref queue

         }

       } catch (SAXException e) {

         throw new RuntimeException("Internal error - should never happen", e);

@@ -615,9 +681,9 @@
         FSIndexRepositoryImpl loopIR = (FSIndexRepositoryImpl) cas.getBaseCAS()

                 .getSofaIndexRepository(sofaNum);

         if (loopIR != null) {

-          List<TOP> items = loopIR.getIndexedFSs();

+          Collection<TOP> items = loopIR.getIndexedFSs();

           for (TOP item : items) {

-            enqueueIndexedFs(sofaNum, item);

+            enqueueIndexedFs_only_not_features(sofaNum, item);

           }

         }

       }

@@ -676,29 +742,12 @@
       return enqueueCommon(fs, false);

     }

     

+    /**

+     * @param fs -

+     * @param doDeltaAndFilteringCheck -

+     * @return true to have enqueue put onto "queue" and enqueue features

+     */

     private int enqueueCommon(TOP fs, boolean doDeltaAndFilteringCheck) {

-//      // debug 

-//      if (null == fs) {

-//        System.out.println("debug null fs");

-//        new Throwable().printStackTrace();

-//        int i = 0;

-//        while (true) {

-//          try {

-//            Thread.sleep(10000);

-//          } catch (InterruptedException e) {

-//            // TODO Auto-generated catch block

-//            e.printStackTrace();

-//          }

-//          i++;

-//          if (i % 10 == 0) {

-//            System.err.println("debug sleeping");

-//          }

-//        }

-//      }

-

-      

-//      final int typeCode = cas.getHeapValue(addr);

-//      assert(typeCode != 0);

       if (doDeltaAndFilteringCheck) {

         if (isDelta) {

           if (!marker.isNew(fs) && !marker.isModified(fs)) {

@@ -723,7 +772,8 @@
 

       if (!visited_not_yet_written.add(fs)) {

         // was already visited; means this FS has multiple references, either from FS feature(s) or indexes or both

-        if (null != multiRefFSs) {

+        // https://issues.apache.org/jira/browse/UIMA-5532

+        if (isDynamicMultiRef || isArrayOrList(fs)) {

           boolean wasAdded = multiRefFSs.add(fs);

           if (wasAdded) {

             queue.add(fs);  // if was in indexed set before, isn't in the queue set, but needs to be

@@ -746,12 +796,13 @@
         typeCode2namespaceNames[typeCode] = newXel;

       }  

       return typeCode;

-    }    

+    }   

+        

     /*

      * Enqueues an indexed FS. Does NOT enqueue features at this point.

      * Doesn't enqueue non-modified FS when delta

      */

-    void enqueueIndexedFs(int viewNumber, TOP fs) {

+    void enqueueIndexedFs_only_not_features(int viewNumber, TOP fs) {

       if (enqueueCommon(fs) != -1) {

         List<TOP> fss = indexedFSs[viewNumber - 1];

         if (null == fss) {

@@ -772,7 +823,7 @@
      *          The FS address.

      * @throws SAXException 

      */

-    private void enqueue(TOP fs) throws SAXException {  

+    private void enqueueFsAndMaybeFeatures(TOP fs) throws SAXException {  

       if (null == fs) {

         return;

       }

@@ -783,20 +834,30 @@
       }

       queue.add(fs);

       enqueueFeatures(fs);

-      // Also, for FSArrays enqueue the elements

-      if (fs instanceof FSArray) { //TODO: won't get parameterized arrays? no, there are no parameterized arrays in the impl

-        enqueueFSArrayElements((FSArray) fs);

-      }

+      // Also, for FSArrays enqueue the elements  -- not here, done by enqueueFeatures, 1 line above

+//      if (fs instanceof FSArray) { //TODO: won't get parameterized arrays? no, there are no parameterized arrays in the impl

+//        enqueueFSArrayElements((FSArray) fs);

+//      }

     }

             

     /**

-     * 

-     * @param curNode

-     * @param featCode

-     * @return true if OK, false if found cycle or multi-ref

-     * @throws SAXException

+     * For lists, 

+     *   see if this is a plain list

+     *     - no loops

+     *     - no other refs to list elements from outside the list

+     *     -- if so, return false;

+     *     

+     *   add all the elements of the list to visited_not_yet_written,

+     *     noting if they've already been added 

+     *     -- this indicates either a loop or another ref from outside,

+     *     -- in either case, return true - t

+     * @param curNode -

+     * @param featCode -

+     * @return false if no list element is multiply-referenced,

+     *         true if there is a loop or another ref from outside the list, for 

+     *         one or more list element nodes

      */

-    private boolean isListElementsMultiplyReferenced(TOP listNode) throws SAXException {

+    private boolean isListElementsMultiplyReferenced(TOP listNode) {

       boolean foundCycle = false;

       CommonList curNode = (CommonList) listNode;

       while (curNode instanceof NonEmptyList) {  // stop on end or 0

@@ -809,19 +870,44 @@
       return foundCycle;

     }

     

-    

+    /**

+     * ordinary FSs referenced as features are not checked by this routine;

+     * this is only called for FSlists of various kinds, and fs arrays of various kinds

+     * 

+     * Not all featValues should be enqueued;

+     *   list or array features which are marked **NOT** multiple-refs-allowed 

+     *     are serialized in-line

+     *   for JSON, when using dynamicMultiRef (the default), list / array FSs 

+     *     are serialized by ref (not in-line) if there are multiple refs to them

+     *   

+     *   for XMI and JSON, any FS ref marked as multiple-refs-allowed forces

+     *     the item onto the ref "queue".

+     *     

+     *   (not handled here: ordinary FSs are serialized in-line in JSON with isDynamicMultiRef)

+     * 

+     * @param fi - the feature, to look up the multiRefAllowed flag

+     * @param featVal - the List or array element

+     * @param alreadyVisited true if visited_not_yet_written contains the featVal

+     * @param isListNode -

+     * @param isListFeat -

+     * @return false if should skip enqueue because this array or list is being serialized inline

+     * @throws SAXException -

+     */

     private boolean isMultiRef_enqueue(FeatureImpl fi, TOP featVal, boolean alreadyVisited, boolean isListNode, boolean isListFeat) throws SAXException {

-      if (multiRefFSs == null) {

+      if (!isDynamicMultiRef) {

         

-        // dynamic embedding (a JSON feature) is turned off - compute static embedding just for lists and arrays

+        // not JSON dynamic embedding, or dynamic embedding is turned off - compute static embedding just for lists and arrays

         boolean multiRefAllowed = fi.isMultipleReferencesAllowed() || isListNode;

         if (!multiRefAllowed) {

           // two cases: a list or non-list

-          // if a list, check/mark all the nodes in the list

+          // if a list, check/mark all the nodes in the list for any being multiply referenced

           if ((isListFeat && isListElementsMultiplyReferenced(featVal)) ||

+              // say: multi-ref not allowed, but discovered a multi-ref, will be serialized as separate item

               (!isListFeat && alreadyVisited)) {

               reportMultiRefWarning(fi);              

           } else {

+            // multi-ref not allowed, and this item is not multiply referenced (so far) 

+            // expecting to serialize as embedded (if array or list, or JSON)

             if (!isListFeat) {  // already added visited for list nodes

               visited_not_yet_written.add(featVal);

             }

@@ -832,7 +918,7 @@
         }

       }

       

-      // doing dynamic determination of multi-refs

+      // doing JSON dynamic determination of multi-refs

       if (alreadyVisited) {

         return !multiRefFSs.contains(featVal); // enqueue in the "queue" section, first time this happens

       }

@@ -851,9 +937,6 @@
      *          true iff the enclosing FS (addr) is a list type

      */

     private void enqueueFeatures(TOP fs) throws SAXException {

-//    if (fs.id() == 65) {

-//      System.out.println("debug 356");

-//    }

 

       /**

        * Handle FSArrays

@@ -868,13 +951,11 @@
             continue;  // skip because not in filter type system

           }

           if (elem != null) {

-            enqueue(elem);

+            enqueueFsAndMaybeFeatures(elem);

           }

-        }

-        

+        }        

         return;

-      }

-      

+      }      

       

       boolean insideListNode = fs instanceof CommonList;

 

@@ -896,7 +977,7 @@
         final int fsClass = fi.rangeTypeClass;

         switch (fsClass) {

           case LowLevelCAS.TYPE_CLASS_FS: {

-            enqueue(fs.getFeatureValue(fi));

+            enqueueFsAndMaybeFeatures(fs.getFeatureValue(fi));

             break;

           }

           case LowLevelCAS.TYPE_CLASS_INTARRAY:

@@ -909,6 +990,9 @@
           case LowLevelCAS.TYPE_CLASS_DOUBLEARRAY:

           case LowLevelCAS.TYPE_CLASS_FSARRAY: {

             TOP array = fs.getFeatureValue(fi);  // can be null

+            if (null == array) {

+              continue;

+            }

             // we enqueue arrays if:

             //   when statically using multipleReferencesAllowed flag:

             //     when that says it's multiply referenced; 

@@ -918,7 +1002,19 @@
             //   unless already enqueued, in order to pick up any multiple refs

             final boolean alreadyVisited = visited_not_yet_written.contains(array);

             if (isMultiRef_enqueue(fi, array, alreadyVisited, false, false)) {

-              enqueue(array);  // will add to queue list 1st time multi-ref detected

+              if (enqueued_multiRef_arrays_or_lists.add(array)) {  // only do this once per item

+                enqueueFsAndMaybeFeatures(array);  // will add to queue list 1st time multi-ref detected

+                // or JSON isDynamicEmbedding is on (whether or not multi-ref)

+              } else {

+                // for isDynamicMultiRef, this is the first time we detect multiple refs

+                // do this here, because the enqueued_multiRef_arrays_or_lists.add above makes

+                //   the 2nd and subsequent multi-ref things bypass the enqueue call.

+                //   - only needed for isDynamicMultiRef, because only that returns true for isMultiRef_enqueue

+                //     for the "first" instance, when it isn't yet known.

+                if (isDynamicMultiRef) {

+                  multiRefFSs.add(array);  

+                }

+              }

             // otherwise, it is singly referenced (so far) and will be embedded

             //   (or has already been enqueued, in dynamic embedding mode), so don't enqueue

             } else if (array instanceof FSArray && !alreadyVisited) {

@@ -942,11 +1038,22 @@
             TOP startOfList_node = fs.getFeatureValue(fi);

             if (null == startOfList_node) {

               // the feature, whose type is one of the lists, has a null value, so there's nothing to enqueue

-              break;

+              continue;

             }

             final boolean alreadyVisited = visited_not_yet_written.contains(startOfList_node);

             if (isMultiRef_enqueue(fi, startOfList_node, alreadyVisited, insideListNode, true)) {

-              enqueue(startOfList_node);

+              if (enqueued_multiRef_arrays_or_lists.add(startOfList_node)) {  // only do this once per item

+                enqueueFsAndMaybeFeatures(startOfList_node);

+              } else {

+                // for isDynamicMultiRef, this is the first time we detect multiple refs

+                // do this here, because the enqueued_multiRef_arrays_or_lists.add above makes

+                //   the 2nd and subsequent multi-ref things bypass the enqueue call.

+                //   - only needed for isDynamicMultiRef, because only that returns true for isMultiRef_enqueue

+                //     for the "first" instance, when it isn't yet known.

+                if (isDynamicMultiRef) {

+                  multiRefFSs.add(startOfList_node);  

+                }

+              }              

             } else if (startOfList_node instanceof FSList && !alreadyVisited) {

               // also, we need to enqueue any FSs reachable from an FSList

               enqueueFSListElements((FSList) startOfList_node);

@@ -966,7 +1073,7 @@
     private void enqueueFSArrayElements(FSArray fsArray) throws SAXException {

        for (TOP elem : fsArray._getTheArray()) {

         if (elem != null) {

-          enqueue(elem);

+          enqueueFsAndMaybeFeatures(elem);

         }

       }

     }

@@ -978,8 +1085,8 @@
      * @param addr

      *          Address of an FSList

      */

-    private void enqueueFSListElements(FSList node) throws SAXException {

-      node.walkList( n -> enqueue(((NonEmptyFSList)n).getHead()), null);

+    private void enqueueFSListElements(FSList<TOP> node) throws SAXException {

+      node.walkList_saxException(n -> enqueueFsAndMaybeFeatures(((NonEmptyFSList<TOP>)n).getHead()), null);

     }

 

     /*

@@ -1022,8 +1129,9 @@
         // so check if already written, and if so, skip

         //    Case where this happens: JSON serialization with dynamically determined single ref embedding

         //    - have to enqueue to check if multiple refs, even if embedding eventually

-        if (visited_not_yet_written.contains(fs)) {

-          if (null != multiRefFSs && !multiRefFSs.contains(fs)) {

+        if (visited_not_yet_written.contains(fs)) {        

+          // skip if JSON dynamically computing whether or not to embed things and there's only one item - it will be embedded instead

+          if (isDynamicMultiRef && !multiRefFSs.contains(fs)) {

             continue;  // skip writing embeddable item (for JSON dynamic embedding) from Q; will be written from reference

           }

           encodeFS(fs);

@@ -1069,10 +1177,16 @@
             if (fs1 instanceof Annotation) {

               Annotation fs1a = (Annotation) fs1;

               Annotation fs2a = (Annotation) fs2;

+              

               c = Integer.compare(fs1a.getBegin(), fs2a.getBegin());

-              return (c != 0) ? c : Integer.compare(fs2a.getEnd(), fs1a.getEnd()); // reverse order

+              if (c != 0) return c;

+              

+              c = Integer.compare(fs2a.getEnd(), fs1a.getEnd()); // reverse order

+              if (c != 0) return c;

+              

+              // fall thru to do id compare

             }

-            // not annotation

+            // not annotation, or equal begin/end/type

             return Integer.compare(fs1._id, fs2._id);  // return in @id order

           }

       };

@@ -1102,9 +1216,16 @@
       final int typeCode = fs._getTypeImpl().getCode();

 

       final int typeClass = classifyType(fs._getTypeImpl());

+      // for JSON, the items reachable via indexes are written first,

+      //   and isIndexId = false

+      //   The items reachable via refs are written next, and 

+      //   isIndexId = true;

       boolean isIndexId = csss.writeFsStart(fs, typeCode);

       

-      if (!isIndexId && multiRefFSs != null && multiRefFSs.contains(fs)) {

+      // write the id if needed for reference

+      //   - if it is not ref'd via index, and JSON is computing dynamic refs, and it is multiply ref'd

+      //   - skip if not JSON dynamic ref, or in index, or not multiply ref'd

+      if (!isIndexId && isDynamicMultiRef && multiRefFSs.contains(fs)) {

         csss.writeFsRef(fs);        

       } else {

         visited_not_yet_written.remove(fs);  // mark as written

@@ -1256,4 +1377,11 @@
     default : return TypeSystemImpl.getTypeClass(ti);

     }

   }

+  

+  private static boolean isArrayOrList(TOP fs) {

+    return fs instanceof CommonPrimitiveArray ||

+           fs instanceof FSArray ||

+           fs instanceof CommonList;

+  }

+

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasTypeSystemMapper.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasTypeSystemMapper.java
index a227353..3045c77 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasTypeSystemMapper.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasTypeSystemMapper.java
@@ -75,7 +75,7 @@
   final private List<TypeImpl> tTgt2Src = new ArrayList<>();
   /**
    * Feature mapping from source to target
-   *   first key is the src type code, 2nd is the src feature offset 
+   *   first key is the src type code, 2nd is the src feature offset (origin 0)
    */
   final private FeatureImpl[][] fSrc2Tgt;
   
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/CommonAuxHeap.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/CommonAuxHeap.java
index 5b81a36..36ba3a9 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/CommonAuxHeap.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/CommonAuxHeap.java
@@ -24,7 +24,7 @@
  */

 abstract class CommonAuxHeap {

   

-  private static final boolean debugLogShrink = false;

+  private static final boolean DEBUG_LOG_SHRINK = false;

 //  static {

 //    debugLogShrink = System.getProperty("uima.debug.ihs") != null;

 //  }

@@ -92,7 +92,7 @@
    */

   void reset(boolean doFullReset) {

     if (doFullReset) {

-      if (debugLogShrink) System.out.format("Debug shrink CommonAux full reset from %,d to %,d for %s%n",

+      if (DEBUG_LOG_SHRINK) System.out.format("Debug shrink CommonAux full reset from %,d to %,d for %s%n",

           getCapacity(), heapBaseSize, this.getClass().getSimpleName());

       this.initMemory();

     } else {

@@ -103,7 +103,7 @@
       if (newSize == getCapacity()) { // means didn't shrink

         resetToZeros();

       } else {

-        if (debugLogShrink) System.out.format("Debug shrink CommonAux from %,d to %,d for %s%n",

+        if (DEBUG_LOG_SHRINK) System.out.format("Debug shrink CommonAux from %,d to %,d for %s%n",

             curCapacity, newSize, this.getClass().getSimpleName());

         initMemory(newSize);

       }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/CommonSerDesSequential.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/CommonSerDesSequential.java
index d090d98..2cd9d93 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/CommonSerDesSequential.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/CommonSerDesSequential.java
@@ -74,7 +74,7 @@
    * For delta, the addr is the modeled addr for the full CAS including both above and below the line.

    * 

    */

-  final Int2ObjHashMap<TOP> addr2fs = new Int2ObjHashMap<>(TOP.class);  

+  final Int2ObjHashMap<TOP, TOP> addr2fs = new Int2ObjHashMap<>(TOP.class);  

   

   /**

    * The FSs in this list are not necessarily sequential, but is in ascending (simulated heap) order,

@@ -153,7 +153,7 @@
     int nextAddr = fromAddr;

     if (TRACE_SETUP) System.out.println("Cmn serDes sequential setup called by: " + Misc.getCaller());

 

-    List<TOP> all =  new AllFSs(baseCas).getAllFSsSorted();

+    List<TOP> all =  new AllFSs(baseCas).getAllFSsAllViews_sofas_reachable().getAllFSsSorted();

     List<TOP> filtered = CASImpl.filterAboveMark(all, mark);

     for (TOP fs : filtered) {

       addFS1(fs, nextAddr);   // doesn't update sortedFSs, that will be done below in batch

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/ConstraintFactoryImpl.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/ConstraintFactoryImpl.java
index 0b2704e..cef4cb6 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/ConstraintFactoryImpl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/ConstraintFactoryImpl.java
@@ -38,27 +38,33 @@
  */
 public class ConstraintFactoryImpl extends ConstraintFactory {
 
-	public FSTypeConstraint createTypeConstraint() {
+	@Override
+  public FSTypeConstraint createTypeConstraint() {
 		return new FSTypeConstraintImpl();
 	}
 
-	public FSIntConstraint createIntConstraint() {
+	@Override
+  public FSIntConstraint createIntConstraint() {
 		return new FSIntConstraintImpl();
 	}
 
-	public FSFloatConstraint createFloatConstraint() {
+	@Override
+  public FSFloatConstraint createFloatConstraint() {
 		return new FSFloatConstraintImpl();
 	}
 
-	public FSStringConstraint createStringConstraint() {
+	@Override
+  public FSStringConstraint createStringConstraint() {
 		return new FSStringConstraintImpl();
 	}
 
-	public FSBooleanConstraint createBooleanConstraint() {
+	@Override
+  public FSBooleanConstraint createBooleanConstraint() {
 		return new FSBooleanConstraintImpl();
 	}
 
-	public FSMatchConstraint embedConstraint(FeaturePath featPath,
+	@Override
+  public FSMatchConstraint embedConstraint(FeaturePath featPath,
 			FSConstraint constraint) {
 		ArrayList<String> path = new ArrayList<String>();
 		for (int i = 0; i < featPath.size(); i++) {
@@ -79,7 +85,8 @@
 		}
 	}
 
-	public FSMatchConstraint embedConstraint(ArrayList<String> path,
+	@Override
+  public FSMatchConstraint embedConstraint(ArrayList<String> path,
 			FSConstraint constraint) {
 		if (constraint instanceof FSMatchConstraint) {
 			return new EmbeddedConstraint(path, constraint);
@@ -96,11 +103,13 @@
 		}
 	}
 
-	public FSMatchConstraint and(FSMatchConstraint c1, FSMatchConstraint c2) {
+	@Override
+  public FSMatchConstraint and(FSMatchConstraint c1, FSMatchConstraint c2) {
 		return new ConjunctiveConstraint(c1, c2);
 	}
 
-	public FSMatchConstraint or(FSMatchConstraint c1, FSMatchConstraint c2) {
+	@Override
+  public FSMatchConstraint or(FSMatchConstraint c1, FSMatchConstraint c2) {
 		return new DisjunctiveConstraint(c1, c2);
 	}
 
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/CopyOnWriteIndexPart.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/CopyOnWriteIndexPart.java
index c234c88..c19662d 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/CopyOnWriteIndexPart.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/CopyOnWriteIndexPart.java
@@ -19,11 +19,38 @@
 

 package org.apache.uima.cas.impl;

 

+import java.util.Iterator;

+

+import org.apache.uima.jcas.cas.TOP;

+

 /**

  * common APIs supporting the copy on write aspect of index parts

  */

-public interface CopyOnWriteIndexPart {

+public interface CopyOnWriteIndexPart<T> {

   

   void makeReadOnlyCopy();

   

+  /**

+   * @return true if this cow version is the same as the original.

+   *              true means the index has not been updated

+   */

+  boolean isOriginal();

+  

+  /**

+   * @return The number of elements in the index

+   */

+  int size();

+  

+  /**

+   * @return iterator over all the elements

+   */

+  Iterator<T> iterator();

+  

+  /**

+   * Copy FS refs to target from this index part

+   * @param target the target array to copy into

+   * @param startingIndexInTarget the starting index in the target array

+   * @return startingIndexInTarget + size

+   */

+  int copyToArray(TOP[] target, int startingIndexInTarget);

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/DebugFSLogicalStructure.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/DebugFSLogicalStructure.java
index 1d2cc17..6b5795e 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/DebugFSLogicalStructure.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/DebugFSLogicalStructure.java
@@ -303,6 +303,9 @@
         nv.setValue(fs.getStringValue(feat));
       else
         nv.setValue(fs.getFeatureValue(feat));
+      if (nv.getValue() == null) {
+        nv.setValue("null");
+      }
       result[i++] = nv;
     }
   }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSBooleanConstraintImpl.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSBooleanConstraintImpl.java
index 4dfac5a..eeb351a 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSBooleanConstraintImpl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSBooleanConstraintImpl.java
@@ -39,6 +39,7 @@
   /* (non-Javadoc)

    * @see org.apache.uima.cas.FSBooleanConstraint#eq(boolean)

    */

+  @Override

   public void eq(boolean cond) {

     this.condition = cond;

   }

@@ -46,10 +47,12 @@
   /* (non-Javadoc)

    * @see org.apache.uima.cas.FSBooleanConstraint#match(boolean)

    */

+  @Override

   public boolean match(boolean cond) {

     return (this.condition == cond);

   }

 

+  @Override

   public String toString() {

     // need to escape quotes and backslashes

     StringBuffer buf = new StringBuffer();

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java
index 3318f57..b05afda 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java
@@ -27,22 +27,22 @@
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.MethodType;
+import java.lang.invoke.MutableCallSite;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 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;
-import org.apache.uima.cas.BuiltinTypeKinds;
+import org.apache.uima.UIMA_IllegalStateException;
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASException;
 import org.apache.uima.cas.CASRuntimeException;
@@ -109,22 +109,66 @@
  */
 
 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           */
+  /*      kept in a thread local                               */
+  /* ========================================================= */
+  
+  /* ==========================++++++=== */
+  /*   Static final, not in thread local */
+  /*     not sync-ed                     */
+  /* ==========================++++++=== */
+
   // Used for the built-ins.
-  private static final MethodHandles.Lookup defaultLookup = MethodHandles.lookup();
-  
-  private static MethodHandles.Lookup lookup;
-  
+  private static final Lookup defaultLookup = MethodHandles.lookup();
+
   private static final MethodType findConstructorJCasCoverType      = methodType(void.class, TypeImpl.class, CASImpl.class);
-//  private static final MethodType findConstructorJCasCoverTypeArray = methodType(void.class, TypeImpl.class, CASImpl.class, int.class);
+  //private static final MethodType findConstructorJCasCoverTypeArray = methodType(void.class, TypeImpl.class, CASImpl.class, int.class);
   /**
    * The callsite has the return type, followed by capture arguments
    */
   private static final MethodType callsiteFsGenerator      = methodType(FsGenerator3.class);
-//  private static final MethodType callsiteFsGeneratorArray = methodType(FsGeneratorArray.class);  // NO LONGER USED
+  //private static final MethodType callsiteFsGeneratorArray = methodType(FsGeneratorArray.class);  // NO LONGER USED
   
   private static final MethodType fsGeneratorType      = methodType(TOP.class, TypeImpl.class, CASImpl.class);
-//  private static final MethodType fsGeneratorArrayType = methodType(TOP.class, TypeImpl.class, CASImpl.class, int.class); // NO LONGER USED
+  //private static final MethodType fsGeneratorArrayType = methodType(TOP.class, TypeImpl.class, CASImpl.class, int.class); // NO LONGER USED
+
+  /**
+   * precomputed generators for built-in types
+   * These instances are shared for all type systems
+   * Key = index = typecode
+   */
+  private static final JCasClassInfo[] jcasClassesInfoForBuiltins;
+
+  /* =================================== */
+  /*    not in thread local, sync-ed     */
+  /* =================================== */
+
+  /** a cache for constant int method handles */
+  private static final List<MethodHandle> methodHandlesForInt = new ArrayList<>();
+  
+  /**
+   * Map from class loaders used to load JCas Classes, both PEAR and non-Pear cases, to JCasClassInfo for that loaded JCas class instance.
+   *   key is the class loader
+   *   value is a plain HashMapmap from string form of typenames to JCasClassInfo corresponding to the JCas class covering that type
+   *     (which may be a supertype of the type name).
+   *     
+   *     Key is JCas fully qualified name (not UIMA type name).
+   *       Is a String, since different type systems may use the same JCas classes.
+   *     value is the JCasClassInfo for that class
+   *       - this may be for that actual JCas class, if one exists for that UIMA type name
+   *       - or it is null, signalling that there is no JCas for this type, and a supertype should be used
+   *         
+   * Cache of FsGenerator[]s kept in TypeSystemImpl instance, since it depends on type codes.
+   * Current FsGenerator[] kept in CASImpl shared view data, switched as needed for PEARs. 
+   */
+  private static final Map<ClassLoader, Map<String, JCasClassInfo>> cl_to_type2JCas = Collections.synchronizedMap(new IdentityHashMap<>());  // identity: key is classloader
+  
+//  private static final Map<ClassLoader, Map<String, JCasClassInfo>> cl_4pears_to_type2JCas = Collections.synchronizedMap(new IdentityHashMap<>()); // identity: key is classloader
 
   static private class ErrorReport {
     final Exception e;
@@ -137,16 +181,26 @@
   // must precede first (static) use
   static private ThreadLocal<List<ErrorReport>> errorSet = new ThreadLocal<>();
  
+//  /**
+//   * Map (per class loader) from JCas Classes, to all callSites in that JCas class 
+//   */
+//  public static final Map<Class<? extends TOP>, ArrayList<Entry<String, MutableCallSite>>> callSites_all_JCasClasses = new HashMap<>();
+
   /**
-   * One instance per JCas Class per class loader
+   * One instance per JCas class defined for it, per class loader
+   *   - per class loader, because different JCas class definitions for the same name are possible, per class loader
    * 
+   * Kept in maps, per class loader.  
    * Created when potentially loading JCas classes.
    * 
-   * Entries kept in potentially multiple global static hashmap, typename (string)
+   * Entries kept in potentially multiple global static hashmaps, with key = the string form of the typename
+   *   - string form of key allows sharing the same named JCas definition among different type system type-impls. 
    *   - one hashmap per classloader
    *   Entries reused potentially by multiple type systems.
    * 
-   * Info used for identifying the target of a "new" operator - could be generator for superclass.
+   * Info used for 
+   *   - identifying the target of a "new" operator - could be generator for superclass.
+   *   - remembering the results of getting all the features this JCas class defines
    * One entry per defined JCas class per classloader; no instance if no JCas class is defined.
    */
   public static class JCasClassInfo {
@@ -154,9 +208,10 @@
     final FsGenerator3 generator;
    
     /**
-     * The corresponding loaded JCas Class
+     * The corresponding loaded JCas Class for this UIMA type, may be a JCas class associated with a UIMA supertype
+     *   if no JCas class is found for this type.
      */
-    final Class<?> jcasClass;
+    final Class<? extends TOP> jcasClass;
     
     /**
      * NOT the TypeCode, but instead, the unique int assigned to the JCas class 
@@ -164,17 +219,20 @@
      * Might be -1 if the JCasClassInfo instance is for a non-JCas instantiable type
      */
     final int jcasType;
-        
-    JCasClassInfo(Class<?> jcasClass, FsGenerator3 generator, int jcasType) {
+    
+    final JCasClassFeatureInfo[] features;
+           
+    JCasClassInfo(Class<? extends TOP> jcasClass, FsGenerator3 generator, int jcasType) {
       this.generator = generator;
       this.jcasClass = jcasClass;
       this.jcasType = jcasType;    // typeId for jcas class, **NOT Typecode**
+      this.features = getJCasClassFeatureInfo(jcasClass);
       
 //      System.out.println("debug create jcci, class = " + jcasClass.getName() + ", typeint = " + jcasType);
     }
     
     boolean isCopydown(TypeImpl ti) {
-      return isCopydown(Misc.typeName2ClassName(ti.getName()));
+      return isCopydown(ti.getJCasClassName());
     }
   
     boolean isCopydown(String jcasClassName) {
@@ -184,102 +242,134 @@
     boolean isPearOverride(ClassLoader cl) {
       return jcasClass.getClassLoader().equals(cl);
     }
-  }
-
-  /**
-   * Map from class loaders used to load JCas Classes, both PEAR and non-Pear cases, to JCasClassInfo for that loaded JCas class instance.
-   *   Key is JCas fully qualified name (not UIMA type name).
-   *   Is String, since different type systems may use the same JCas classes.
-   * Cache of FsGenerator[]s kept in TypeSystemImpl instance, since it depends on type codes.
-   * Current FsGenerator[] kept in CASImpl shared view data, switched as needed for PEARs. 
-   */
-  private static final Map<ClassLoader, Map<String, JCasClassInfo>> cl2type2JCas = new IdentityHashMap<>();
     
+    TypeImpl getUimaType(TypeSystemImpl tsi) {
+      return tsi.getType(Misc.javaClassName2UimaTypeName(jcasClass.getName()));
+    }
+  }
+  
   /**
-   * precomputed generators for built-in types
-   * These instances are shared for all type systems
-   * Key = index = typecode
+   * Information about all features this JCas class defines
+   * Used to expand the type system when the JCas defines more features
+   * than the type system declares.
    */
-  private static final JCasClassInfo[] jcasClassesInfoForBuiltins;
+  static class JCasClassFeatureInfo {
+    final String shortName;
+    // rangename is byte.class, etc
+    // or x.y.z.JCasClassName
+    final String uimaRangeName;       
+    
+    JCasClassFeatureInfo(String shortName, String uimaRangeName) {
+      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);
+    }
+    
+    
+  }
+    
 
   static {
     TypeSystemImpl tsi = TypeSystemImpl.staticTsi;
     jcasClassesInfoForBuiltins = new JCasClassInfo[tsi.getTypeArraySize()]; 
-    lookup = defaultLookup;
+//    lookup = defaultLookup;
         
     // walk in subsumption order, supertype before subtype
     // Class loader used for builtins is the UIMA framework's class loader
-    loadBuiltins(tsi.topType, tsi.getClass().getClassLoader());
+    ArrayList<MutableCallSite> callSites_toSync = new ArrayList<>();
+    ClassLoader cl = tsi.getClass().getClassLoader();
+    loadBuiltins(tsi.topType, cl, cl_to_type2JCas.computeIfAbsent(cl, x -> new HashMap<>()), callSites_toSync);
     
+    MutableCallSite[] sync = callSites_toSync.toArray(new MutableCallSite[callSites_toSync.size()]);
+    MutableCallSite.syncAll(sync);
+
     reportErrors();
   }
-  
-  private static void loadBuiltins(TypeImpl ti, ClassLoader cl) {
+    
+  private static void loadBuiltins(TypeImpl ti, ClassLoader cl, Map<String, JCasClassInfo> type2jcci, ArrayList<MutableCallSite> callSites_toSync) {
     String typeName = ti.getName();
     
     if (BuiltinTypeKinds.creatableBuiltinJCas.contains(typeName) || typeName.equals(CAS.TYPE_NAME_SOFA)) {
-      Class<?> builtinClass = maybeLoadJCas(ti, cl);
-      assert (builtinClass != null);  // builtin types must be present
-      // copy down to subtypes, if needed, done later
-      int jcasType = Misc.getStaticIntFieldNoInherit(builtinClass, "typeIndexID");
-      JCasClassInfo jcasClassInfo = createJCasClassInfo(builtinClass, ti, jcasType); 
-      jcasClassesInfoForBuiltins[ti.getCode()] = jcasClassInfo; 
+      JCasClassInfo jcci = getOrCreateJCasClassInfo(ti, cl, type2jcci, defaultLookup);
+      assert jcci != null;
+      // done while beginning to commit the staticTsi (before committed flag is set), for builtins  
+      updateOrValidateAllCallSitesForJCasClass(jcci.jcasClass, ti, callSites_toSync);
+      jcasClassesInfoForBuiltins[ti.getCode()] = jcci;
+      
+//      Class<?> builtinClass = maybeLoadJCas(ti, cl);
+//      assert (builtinClass != null);  // builtin types must be present
+//      // copy down to subtypes, if needed, done later
+//      int jcasType = Misc.getStaticIntFieldNoInherit(builtinClass, "typeIndexID");
+//      JCasClassInfo jcasClassInfo = createJCasClassInfo(builtinClass, ti, jcasType); 
+//      jcasClassesInfoForBuiltins[ti.getCode()] = jcasClassInfo; 
     }
     
     for (TypeImpl subType : ti.getDirectSubtypes()) {
-      TypeSystemImpl.typeBeingLoadedThreadLocal.set(subType);
-      loadBuiltins(subType, cl);
+      loadBuiltins(subType, cl, type2jcci, callSites_toSync);
     }
   }
     
   /**
    * Load JCas types for some combination of class loader and type system
-   * These classes may have already been loaded for this type system
-   * These classes may have already been loaded (perhaps for another type system)
-   * @param ts 
-   * @param isDoUserJCasLoading
-   * @param cl
+   * Some of these classes may have already been loaded for this type system
+   * Some of these classes may have already been loaded (perhaps for another type system)
+   * @param ts the type system
+   * @param isDoUserJCasLoading always true, left in for experimentation in the future with dynamic generation of JCas classes
+   * @param cl the class loader. For Pears, is the pear class loader
    */
-  static void loadAtTypeSystemCommitTime(TypeSystemImpl ts, boolean isDoUserJCasLoading, ClassLoader cl) { 
+  private static synchronized void loadJCasForTSandClassLoader(
+      TypeSystemImpl ts, 
+      boolean isDoUserJCasLoading, 
+      ClassLoader cl, 
+      Map<String, JCasClassInfo> type2jcci) { 
 
-    boolean alreadyLoaded = false;
-    Map<String, JCasClassInfo> t2jcci;
+//    boolean alreadyPartiallyLoaded = false;  // true if any JCas types for this class loader have previously been loaded
 
-    synchronized (cl2type2JCas) {
-      t2jcci = cl2type2JCas.get(cl);
-    
-      if (null == t2jcci) {    
-        t2jcci = new HashMap<>();
-        cl2type2JCas.put(cl, t2jcci);
-      } else {
-        alreadyLoaded = true;
-      }
-    }
+//      synchronized (cl2t2j) {
+//      type2jcci = cl2t2j.get(cl);
+//    
+//      if (null == type2jcci) {    
+//        type2jcci = new HashMap<>();
+//        cl2t2j.put(cl, type2jcci);
+//      } else {
+//        alreadyPartiallyLoaded = true;
+//      }
+//    }
     
     /**
      * copy in built-ins
      *   update t2jcci (if not already loaded) with load info for type
      *   update type system's map from unique JCasID to the type in this type system
      */
-    lookup = defaultLookup;
+     
+    /* ============================== */
+    /*            BUILT-INS           */
+    /* ============================== */
     for (int typecode = 1; typecode < jcasClassesInfoForBuiltins.length; typecode++) {
   
       JCasClassInfo jcci = jcasClassesInfoForBuiltins[typecode];
       if (jcci != null) {
-        Class<?> jcasClass = jcci.jcasClass;  
-
-        if (!alreadyLoaded) {
-          t2jcci.put(jcasClass.getCanonicalName(), jcci);
-        }
+        Class<? extends TOP> jcasClass = jcci.jcasClass;  
+        type2jcci.putIfAbsent(jcasClass.getCanonicalName(), jcci);
         setTypeFromJCasIDforBuiltIns(jcci, ts, typecode);
+        // update call sites not called, was called when
+        // jcci was created.
+//        updateAllCallSitesForJCasClass(jcasClass, ts.getTypeForCode(typecode));
       }
     }  
-    
-    /**
-     * Add all user-defined JCas Types, in subsumption order
-     *   We add these now, in case JCas is turned on later - unless specifically
-     *   specified to run without user-defined JCas loading
-     */
+
+    /* ========================================================= */
+    /*   Add all user-defined JCas Types, in subsumption order   */
+    /* ========================================================= */
+
     
     if (isDoUserJCasLoading) {
       /**
@@ -290,16 +380,21 @@
        *     This depends on having the TypeImpl's javaClass field be accurate (reflect any loaded JCas types)
        */
       
-      try {
-        Class<?> clazz = Class.forName(UIMAClassLoader.MHLC, true, cl);
-        Method m = clazz.getMethod("getMethodHandlesLookup");
-        lookup = (Lookup) m.invoke(null);
-      } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-        throw new UIMARuntimeException(e, UIMARuntimeException.INTERNAL_ERROR);
-      }
+      // this is this here rather than in a static initializer, because 
+      // we want to use the "cl" parameter to get a version of the 
+      // getMethodHandlesLookup that will have the right (maybe more local) permissions checking.
+      // This is done by having the UIMA Class loader notice that the class being loaded is 
+      //   MHLC, and then dynamically loading in that class loader a copy of the byte code 
+      //   for that class.
+      Lookup lookup = getLookup(cl);
 
-      maybeLoadJCasAndSubtypes(ts, ts.topType, t2jcci.get(TOP.class.getCanonicalName()), cl, t2jcci);
-      checkConformance(ts, ts.topType, t2jcci);
+      ArrayList<MutableCallSite> callSites_toSync = new ArrayList<>();
+      maybeLoadJCasAndSubtypes(ts, ts.topType, type2jcci.get(TOP.class.getCanonicalName()), cl, type2jcci, callSites_toSync, lookup);
+      
+      MutableCallSite[] sync = callSites_toSync.toArray(new MutableCallSite[callSites_toSync.size()]);
+      MutableCallSite.syncAll(sync);
+
+      checkConformance(ts, ts.topType, type2jcci);
     }
         
     reportErrors();
@@ -318,69 +413,105 @@
    * Saves the results in two places
    *   type system independent spot: JCasClassInfo instance indexed by JCasClassName
    *   type system spot: the JCasIndexID -> type table in the type system
-   * @param ts the type system
+   *   
+   * Looks up by classname to see if there is an associated JCas class for this type.
+   *   - all types of that name (perhaps from different loaded type systems) will share that one JCas class
+   *   - copyDowns are excluded from this requirement - because there are no JCas class definitions
+   *     for this type (in that case).
+   *     
+   * @param tsi the type system
    * @param ti the type to process
    * @param copyDownDefault_jcasClassInfo
    * @param cl the loader used to load, and to save the results under the key of the class loader the results
    * @param type2JCas map holding the results of loading JCas classes
    */
   private static void maybeLoadJCasAndSubtypes(
-      TypeSystemImpl ts, 
+      TypeSystemImpl tsi, 
       TypeImpl ti, 
       JCasClassInfo copyDownDefault_jcasClassInfo,
       ClassLoader cl,
-      Map<String, JCasClassInfo> type2JCas) {
-        
-    String t2jcciKey = Misc.typeName2ClassName(ti.getName());
-    JCasClassInfo jcci = type2JCas.get(t2jcciKey);
-    boolean isCopyDown = true;
-
-    if (jcci == null) {
-
-      // not yet recorded as loaded under this class loader.
+      Map<String, JCasClassInfo> type2jcci,
+      ArrayList<MutableCallSite> callSites_toSync,
+      Lookup lookup) {
     
-      Class<?> clazz = maybeLoadJCas(ti, cl);
-      if (null != clazz && TOP.class.isAssignableFrom(clazz)) {
-        
-        int jcasType = -1;
-        if (!Modifier.isAbstract(clazz.getModifiers())) { // skip next for abstract classes
-          jcasType = Misc.getStaticIntFieldNoInherit(clazz, "typeIndexID");
-          // if jcasType is negative, this means there's no value for this field
-          assert(jcasType >= 0);
-        }         
-        jcci = createJCasClassInfo(clazz, ti, jcasType);
-        isCopyDown = false;
-        if (clazz != TOP.class) {  // TOP has no super class
-          validateSuperClass(jcci, ti);
-        }
-      } else {
-        jcci = copyDownDefault_jcasClassInfo;
-      }
-      
-      type2JCas.put(t2jcciKey, jcci);
-
-    } else {
-      // this UIMA type was set up (maybe loaded, maybe defaulted to a copy-down) previously
-      isCopyDown = jcci.isCopydown(t2jcciKey);
-
-      if (isCopyDown) {
-        // the "stored" version might have the wrong super class for this type system
-        type2JCas.put(t2jcciKey, jcci = copyDownDefault_jcasClassInfo);
-        
-      } else if (!ti.isTopType()) {
-        // strong test for non-copy-down case: supertype must match, with 2 exceptions
-        validateSuperClass(jcci, ti);
-      }
+    JCasClassInfo jcci = getOrCreateJCasClassInfo(ti, cl, type2jcci, lookup);
+    
+    if (null != jcci && tsi.isCommitted()) {      
+      updateOrValidateAllCallSitesForJCasClass(jcci.jcasClass, ti, callSites_toSync);
     }
+        
+//    String t2jcciKey = Misc.typeName2ClassName(ti.getName());
+//    JCasClassInfo jcci = type2jcci.get(t2jcciKey);
+//
+//    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, callSites_toSync, lookup); // does update of callsites if was able find JCas class
+//
+//      if (null != jcci) {
+//        validateSuperClass(jcci, ti);
+//        type2jcci.put(t2jcciKey, jcci);
+//        tsi.setJCasRegisteredType(jcci.jcasType, ti); 
+//      }
+//
+////      // not yet recorded as loaded under this class loader.
+////    
+////      Class<?> clazz = maybeLoadJCas(ti, cl);
+////      if (null != clazz && TOP.class.isAssignableFrom(clazz)) {
+////        
+////        int jcasType = -1;
+////        if (!Modifier.isAbstract(clazz.getModifiers())) { // skip next for abstract classes
+////          jcasType = Misc.getStaticIntFieldNoInherit(clazz, "typeIndexID");
+////          // if jcasType is negative, this means there's no value for this field
+////          assert(jcasType >= 0);
+////        }         
+////        jcci = createJCasClassInfo(clazz, ti, jcasType);
+////        isCopyDown = false;
+////        // don't do this call, caller will call conformance which has a weaker
+////        // test - passes if there is a shared
+////        // https://issues.apache.org/jira/browse/UIMA-5660
+//////        if (clazz != TOP.class) {  // TOP has no super class  
+//////          validateSuperClass(jcci, ti);
+//////        }
+////      } else {
+////        jcci = copyDownDefault_jcasClassInfo;
+////      }
+//      
+////      type2jcci.put(t2jcciKey, jcci);
+//
+//    } else {
+//      // have previously set up a jcci for this type name
+//      //   maybe for a different type instance (of the same name)
+//      //   next may be redundant?
+//      if (ti.getTypeSystem().isCommitted()) {
+//        updateOrValidateAllCallSitesForJCasClass(jcci.jcasClass, ti, callSites_toSync);
+//      }
+//      
+//    } 
+     
+//      // this UIMA type was set up (maybe loaded, maybe defaulted to a copy-down) previously
+//      isCopyDown = jcci.isCopydown(t2jcciKey);
+//
+//      if (isCopyDown) {
+//        // the "stored" version might have the wrong super class for this type system
+//        type2jcci.put(t2jcciKey, jcci = copyDownDefault_jcasClassInfo);
+//        
+//      } else if (!ti.isTopType()) {
+//        // strong test for non-copy-down case: supertype must match, with 2 exceptions
+//        // removed https://issues.apache.org/jira/browse/UIMA-5660
+////        validateSuperClass(jcci, ti);
+//      }
+//    }
        
     // this is done even after the class is first loaded, in case the type system changed.
     // don't set anything if copy down - otherwise was setting the copyed-down typeId ref to the 
     //   new ti
-//    System.out.println("debug set jcas regisered type " + jcci.jcasType + ",  type = " + ti.getName());
-
-    if (jcci.jcasType >= 0 && ! isCopyDown) {
-      ts.setJCasRegisteredType(jcci.jcasType, ti); 
-    }
+//    System.out.println("debug set jcas regisered type " + jcci.jcasType + ",  type = " + ti.getName());   
+    
+    JCasClassInfo jcci_or_copyDown  = (jcci == null) 
+                                        ? copyDownDefault_jcasClassInfo
+                                        : jcci;
     
     if (!ti.isPrimitive()) {  // bypass this for primitives because the jcasClassInfo is the "inherited one" of TOP
       /**
@@ -389,42 +520,300 @@
        * Other uses of this may get an arbitrary (the latest) version of the class
        * Currently the only other use is in backwards compatibility with low level type system "switching" an existing type.
        */
-      ti.setJavaClass(jcci.jcasClass);
+      ti.setJavaClass(jcci_or_copyDown.jcasClass);
     }
     
     
     for (TypeImpl subtype : ti.getDirectSubtypes()) {
-      TypeSystemImpl.typeBeingLoadedThreadLocal.set(subtype);
-      maybeLoadJCasAndSubtypes(ts, subtype, jcci, cl, type2JCas);
+      maybeLoadJCasAndSubtypes(tsi, subtype, jcci_or_copyDown, cl, type2jcci, callSites_toSync, lookup);
     }
   }
-
-  private static String superTypeJCasName(TypeImpl ti) {
-    return Misc.typeName2ClassName(ti.getSuperType().getName());
-  }
-  /**
-   * verify that the supertype class chain matches the type
-   * @param clazz -
+  
+  /** 
+   * For a particular type name, get the JCasClassInfo
+   *   - by fetching the cached value
+   *   - by loading the class
+   *   - return null if no JCas class for this name 
+   * only called for non-Pear callers
    * @param ti -
+   * @param cl -
+   * @param type2jcci -
+   * @param lookup -
+   * @return - jcci or null, if no JCas class for this type was able to be loaded
+   */
+  public static JCasClassInfo getOrCreateJCasClassInfo(
+      TypeImpl ti, 
+      ClassLoader cl, 
+      Map<String, JCasClassInfo> type2jcci, 
+      Lookup lookup) {
+    
+    
+    JCasClassInfo jcci = type2jcci.get(ti.getJCasClassName());
+
+    if (jcci == null) {
+      jcci = maybeCreateJCasClassInfo(ti, cl, type2jcci, lookup);
+    }
+    
+    // do this setup for new type systems using previously loaded jcci, as well as
+    // for new jccis
+    if (jcci != null && jcci.jcasType >= 0) {
+      ti.getTypeSystem().setJCasRegisteredType(jcci.jcasType, ti);
+    }
+    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, 
+      ClassLoader cl, 
+      Lookup lookup) {
+    Class<? extends TOP> clazz = maybeLoadJCas(ti, cl);
+    
+    if (null == clazz || ! TOP.class.isAssignableFrom(clazz)) {
+      return null;
+    }
+    
+    int jcasType = -1;
+    if (!Modifier.isAbstract(clazz.getModifiers())) { // skip next for abstract classes
+      jcasType = Misc.getStaticIntFieldNoInherit(clazz, "typeIndexID");
+      // if jcasType is negative, this means there's no value for this field
+      if (jcasType == -1) {
+        add2errors(errorSet, 
+                   /** The Class "{0}" matches a UIMA Type, and is a subtype of uima.cas.TOP, but is missing the JCas typeIndexId.*/
+                   new CASRuntimeException(CASRuntimeException.JCAS_MISSING_TYPEINDEX, clazz.getName()),
+                   false);  // not a fatal error
+        return null;
+      }
+    }         
+    return createJCasClassInfo(clazz, ti, jcasType, 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());
+//  }
+//  
+  
+  private static boolean compare_C_T(Class<?> clazz, TypeImpl ti) {
+    return ti.getJCasClassName().equals(clazz.getName());
+  }
+  
+  /**
+   * Changed https://issues.apache.org/jira/browse/UIMA-5660
+   *   to allow insertions of extra types/ classes into the superchain.
+   * verify that the supertype class chain matches the type
+   * @param clazz The JCas class, always below TOP
+   * @param ti - 
    */
   private static void validateSuperClass(JCasClassInfo jcci, TypeImpl ti) {
-    final Class<?> clazz = jcci.jcasClass; 
-    if (! clazz.getSuperclass().getCanonicalName().equals(superTypeJCasName(ti))) {
-      /** Special case exceptions */
-      TypeImpl superti = ti.getSuperType();
-      TypeSystemImpl tsi = ti.getTypeSystem();
-      if (superti == tsi.arrayBaseType ||
-          superti == tsi.listBaseType) return;
-      /** The JCas class: "{0}" has supertype: "{1}" which doesn''t  match the UIMA type "{2}"''s supertype "{3}". */
-      throw new CASRuntimeException(CASRuntimeException.JCAS_MISMATCH_SUPERTYPE,
-        clazz.getCanonicalName(), 
-        clazz.getSuperclass().getCanonicalName(),
-        ti.getName(),
-        ti.getSuperType().getName());
+    
+    final Class<?> superClass = jcci.jcasClass.getSuperclass(); 
+    
+    final TypeImpl superType = ti.getSuperType();
+    
+    if (compare_C_T(superClass, superType)) {
+      return;
     }
-
+    
+    for (TypeImpl st : ti.getAllSuperTypes()) {
+      if (compare_C_T(superClass, st)) {
+        return;
+      }      
+    }
+    
+    for (Class<?> sc = superClass.getSuperclass(); sc != Object.class && sc != FeatureStructureImplC.class; sc = sc.getSuperclass()) {
+      if (compare_C_T(sc, superType)) {
+        return;
+      }
+    }
+    
+    /** The JCas class: "{0}" has supertypes: "{1}" which do not match the UIMA type "{2}"''s supertypes "{3}". */
+    throw new CASRuntimeException(CASRuntimeException.JCAS_MISMATCH_SUPERTYPE,
+      jcci.jcasClass.getName(),
+      getAllSuperclassNames(jcci.jcasClass),
+      ti.getName(),
+      getAllSuperTypeNames(ti));
   }
   
+  private static String getAllSuperclassNames(Class<?> clazz) {
+    StringBuilder sb = new StringBuilder();
+
+    for (Class<?> sc = clazz.getSuperclass(); sc != null && sc != FeatureStructureImplC.class; sc = sc.getSuperclass()) {
+      if (sb.length() > 0) {
+        sb.append(", ");
+      }
+      sb.append(sc.getName());
+    }
+    return sb.toString();
+  }
+
+  private static String getAllSuperTypeNames(TypeImpl ti) {
+    StringBuilder sb = new StringBuilder();
+
+    for (TypeImpl st = ti.getSuperType(); st.getCode() != TypeSystemConstants.topTypeCode; st = st.getSuperType()) {
+      if (sb.length() > 0) {
+        sb.append(", ");
+      }
+      sb.append(st.getName());
+    }
+    if (sb.length() > 0) {
+      sb.append(", ");
+    }
+    sb.append("uima.cas.TOP");
+    return sb.toString();
+  }
+  
+//       
+// 
+//    if (! clazz.getSuperclass().getCanonicalName().equals(superTypeJCasName(ti))) {
+//      /** Special case exceptions */
+//      TypeImpl superti = ti.getSuperType();
+//      TypeSystemImpl tsi = ti.getTypeSystem();
+//      if (superti == tsi.arrayBaseType ||
+//          superti == tsi.listBaseType) return;
+//      /** The JCas class: "{0}" has supertype: "{1}" which doesn''t  match the UIMA type "{2}"''s supertype "{3}". */
+//      throw new CASRuntimeException(CASRuntimeException.JCAS_MISMATCH_SUPERTYPE,
+//        clazz.getCanonicalName(), 
+//        clazz.getSuperclass().getCanonicalName(),
+//        ti.getName(),
+//        ti.getSuperType().getName());
+//    }
+//
+//  }
+  
   /**
    * Called to load (if possible) a corresponding JCas class for a UIMA type.
    * Called at Class Init time for built-in types
@@ -437,21 +826,32 @@
    * @param cl the class loader to use
    * @return the loaded / resolved class
    */
-  private static Class<?> maybeLoadJCas(TypeImpl ti, ClassLoader cl) {
-    Class<?> clazz = null;
-    String className = Misc.typeName2ClassName(ti.getName());
+  private static Class<? extends TOP> maybeLoadJCas(TypeImpl ti, ClassLoader cl) {
+    Class<? extends TOP> clazz = null;
+    String className = ti.getJCasClassName();
     
-    try {
-      TypeSystemImpl.typeBeingLoadedThreadLocal.set(ti);
-      clazz = Class.forName(className, true, cl);
+    try { 
+      clazz = (Class<? extends TOP>) Class.forName(className, true, cl);
     } catch (ClassNotFoundException e) {
-      // This is normal, if there is no JCas for this class
-    } finally {
-      TypeSystemImpl.typeBeingLoadedThreadLocal.set(null);
+      // Class not found is normal, if there is no JCas for this class
+      return clazz;
+    } catch (ExceptionInInitializerError e) {
+      throw new RuntimeException("Exception while loading " +  className, e);
     }
+    
     return clazz;
   }
-        
+      
+  // SYNCHRONIZED 
+  
+  static synchronized MethodHandle getConstantIntMethodHandle(int i) {
+    MethodHandle mh = Misc.getWithExpand(methodHandlesForInt, i);
+    if (mh == null) {
+      methodHandlesForInt.set(i, mh = MethodHandles.constant(int.class, i));
+    }
+    return mh;    
+  }
+  
   /**
    * Return a Functional Interface for a generator for creating instances of a type.
    *   Function takes a casImpl arg, and returning an instance of the JCas type.
@@ -460,7 +860,7 @@
    * @return a Functional Interface whose createFS method takes a casImpl 
    *         and when subsequently invoked, returns a new instance of the class
    */
-  private static FsGenerator3 createGenerator(Class<?> jcasClass) {
+  private static FsGenerator3 createGenerator(Class<?> jcasClass, Lookup lookup) {
     try {
       
       MethodHandle mh = lookup.findConstructor(jcasClass, findConstructorJCasCoverType);
@@ -483,6 +883,7 @@
             ));
         return null;
       }
+      /** An internal error occurred, please report to the Apache UIMA project; nested exception if present: {0} */
       throw new UIMARuntimeException(e, UIMARuntimeException.INTERNAL_ERROR);
     }
   }
@@ -601,30 +1002,78 @@
    * @param ti the type
    * @return the info for this JCas that is shared across all type systems under this class loader
    */
-  private static JCasClassInfo createJCasClassInfo(Class<?> jcasClass, TypeImpl ti, int jcasType) {
+  private static JCasClassInfo createJCasClassInfo(
+      Class<? extends TOP> jcasClass, 
+      TypeImpl ti, 
+      int jcasType, 
+      Lookup lookup) {
     boolean noGenerator = ti.getCode() == TypeSystemConstants.sofaTypeCode ||
                           Modifier.isAbstract(jcasClass.getModifiers()) ||
                           ti.isArray(); 
-    FsGenerator3 generator = noGenerator ? null : createGenerator(jcasClass);
+    FsGenerator3 generator = noGenerator ? null : createGenerator(jcasClass, lookup);
     JCasClassInfo jcasClassInfo = new JCasClassInfo(jcasClass, generator, jcasType);
 //    System.out.println("debug creating jcci, classname = " + jcasClass.getName() + ", jcasTypeNumber: " + jcasType);
     return jcasClassInfo;
   }
   
+  private static JCasClassFeatureInfo[] getJCasClassFeatureInfo(Class<?> jcasClass) {
+    ArrayList<JCasClassFeatureInfo> features = new ArrayList<>();
+    
+    try {
+      for (Field f : jcasClass.getDeclaredFields()) {
+        String fname = f.getName();
+        if (fname.length() <= 5 || !fname.startsWith("_FC_")) continue;
+        String featName = fname.substring(4);
+        
+        // compute range by looking at get method
+        
+        String getterName = "get" + Character.toUpperCase(featName.charAt(0)) + featName.substring(1);
+        Method m;
+        try {
+          m = jcasClass.getDeclaredMethod(getterName); // get the getter with no args
+        } catch (NoSuchMethodException e) {
+          /** Cas class {0} with feature {1} but is mssing a 0 argument getter.  This feature will not be used to maybe expand the type's feature set.*/
+          Logger logger = UIMAFramework.getLogger(FSClassRegistry.class);
+          logger.warn( () -> logger.rb_ue(CASRuntimeException.JCAS_MISSING_GETTER, jcasClass.getName(), featName));
+          continue;  // skip this one
+        }
+        
+        String rangeClassName = m.getReturnType().getName();
+        String uimaRangeName = Misc.javaClassName2UimaTypeName(rangeClassName);
+        features.add(new JCasClassFeatureInfo(featName, uimaRangeName));
+      } // end of for loop
+      JCasClassFeatureInfo[] r = new JCasClassFeatureInfo[features.size()];
+      return features.toArray(r);
+    } catch (Throwable e) {
+      throw new RuntimeException(e);
+    }
+  }
+  
 //  static boolean isFieldInClass(Feature feat, Class<?> clazz) {
 //    try {
-//      return null != clazz.getDeclaredField("_FI_" + feat.getShortName());
+//      return null != clazz.getDeclaredField("_FC_" + feat.getShortName());
 //    } catch (NoSuchFieldException e) {
 //      return false;
 //    }    
 //  }
   
+  static void checkConformance(ClassLoader cl, TypeSystemImpl ts) {
+    Map<String, JCasClassInfo> type2jcci = get_className_to_jcci(cl, false);
+    checkConformance(ts, ts.topType, type2jcci);
+  }
   
   private static void checkConformance(TypeSystemImpl ts, TypeImpl ti, Map<String, JCasClassInfo> type2jcci) {
     if (ti.isPrimitive()) return;
-    JCasClassInfo jcasClassInfo = type2jcci.get(ti.getName());
-    if (null != jcasClassInfo) { // skip if the UIMA class has an abstract (non-creatable) JCas class)      
-      checkConformance(jcasClassInfo.jcasClass, ts, ti, type2jcci);
+    JCasClassInfo jcci = type2jcci.get(ti.getJCasClassName());
+    
+//    if (null == jcci) {
+//    if (!skipCheck && ti.isBuiltIn && jcci.isAlreadyCheckedBuiltIn) {
+//      skipCheck = true;
+//    }
+    
+    if (null != jcci && // skip if the UIMA class has an abstract (non-creatable) JCas class)
+        !(ti.isBuiltIn)) { // skip if builtin
+      checkConformance(jcci.jcasClass, ts, ti, type2jcci);
     }
     
     for (TypeImpl subtype : ti.getDirectSubtypes()) {
@@ -633,10 +1082,14 @@
   }
   
   /**
+   * Inner check
+   * 
+   * Never called for "built-ins", or for uima types not having a JCas loaded class
+   * 
    * Checks that a JCas class definition conforms to the current type in the current type system.
    * Checks that the superclass chain contains some match to the super type chain.
    * Checks that the return value for the getters for features matches the feature's range.
-   * Checks that static _FI_xxx values from the JCas class == the adjusted feature offsets in the type system
+   * Checks that static _FC_xxx values from the JCas class == the adjusted feature offsets in the type system
    * 
    * @param clazz - the JCas class to check
    * @param tsi -
@@ -644,40 +1097,74 @@
    */
   private static void checkConformance(Class<?> clazz, TypeSystemImpl tsi, TypeImpl ti, Map<String, JCasClassInfo> type2jcci) {
 
-    // skip the test if the jcasClassInfo is being inherited
-    //   because that has already been checked
-    if (!clazz.getName().equals(Misc.typeName2ClassName(ti.getName()))) {
-      return;
-    }
+//    // skip the test if the jcasClassInfo is being inherited
+//    //   because that has already been checked
+//    if (!clazz.getName().equals(ti.getJCasClassName())) {
+//      System.out.println("debug should never print");
+//      return;
+//    }
+    
+    
     
     // check supertype
-         
-    // one of the supertypes must match a superclass of the class
-    boolean isOk = false;
-    List<Class<?>> superClasses = new ArrayList<>();
-   outer:
-    for (TypeImpl superType : ti.getAllSuperTypes()) {
-      JCasClassInfo jci = type2jcci.get(superType.getName());
-      if (jci == null) continue;
-      Class<?> superClass = clazz.getSuperclass();
-      superClasses.add(superClass);
-      while (superClass != FeatureStructureImplC.class && superClass != Object.class) {
-        if (jci.jcasClass == superClass) {
-          isOk = true;
-          break outer;
-        }
-        superClass = superClass.getSuperclass();
-        superClasses.add(superClass);
-      }
-    }
     
-    if (!isOk && superClasses.size() > 0) {
-      /** JCas Class's supertypes for "{0}", "{1}" and the corresponding UIMA Supertypes for "{2}", "{3}" don't have an intersection. */
-      add2errors(errorSet, 
-                 new CASRuntimeException(CASRuntimeException.JCAS_CAS_MISMATCH_SUPERTYPE, 
-                     clazz.getName(), Misc.ppList(superClasses), ti.getName(), Misc.ppList(Arrays.asList(ti.getAllSuperTypes()))),
-                 true);  // throwable error
-    }
+    validateSuperClass(type2jcci.get(ti.getJCasClassName()), ti);
+    
+//    //   This is done by validateSuperClass, when JCasClass is loaded or looked up for a particular type system
+//    // one of the supertypes must match a superclass of the class
+//    //       (both of these should be OK)
+//    
+//    //   class:   X  ->  XS -> Annotation -> AnnotationBase -> TOP -> FeatureStructureImplC
+//    //   type:    X   -------> Annotation -> AnnotationBase -> TOP
+//    //      (if XS getters/setters used, have runtime error; if never used, OK)
+//    //
+//    //   class:   X  --------> Annotation -> AnnotationBase -> TOP -> FeatureStructureImplC
+//    //   type:    X  ->  XS -> Annotation -> AnnotationBase -> TOP
+//    boolean isOk = false;
+//    List<Class<?>> superClasses = new ArrayList<>();
+//    boolean isCheckImmediateSuper = true;
+//    Class<?> superClass = clazz.getSuperclass();
+//    
+//   outer:
+//    for (TypeImpl uimaSuperType : ti.getAllSuperTypes()) {        // iterate uimaSuperTypes
+//      JCasClassInfo jcci = type2jcci.get(uimaSuperType.getJCasClassName());
+//      if (jcci != null) {
+//        if (isCheckImmediateSuper) {
+//          if (jcci.jcasClass != superClass) {
+//            /** The JCas class: "{0}" has supertype: "{1}" which doesn''t  match the UIMA type "{2}"''s supertype "{3}". */
+//            add2errors(errorSet, 
+//                new CASRuntimeException(CASRuntimeException.JCAS_MISMATCH_SUPERTYPE, 
+//                    clazz.getCanonicalName(), 
+//                    clazz.getSuperclass().getCanonicalName(),
+//                    ti.getName(),
+//                    ti.getSuperType().getName()),
+//                false);  // not a throwable error, just a warning   
+//          }
+//        }
+//
+//        superClasses.add(superClass);
+//        while (superClass != FeatureStructureImplC.class && superClass != Object.class) {
+//          if (jcci.jcasClass == superClass) {
+//            isOk = true;
+//            break outer;
+//          }
+//          superClass = superClass.getSuperclass();
+//          superClasses.add(superClass);
+//        }
+//      } 
+//      
+//      isCheckImmediateSuper = false;
+//    }
+//    
+//    // This error only happens if the JCas type chain doesn't go thru "TOP" - so it isn't really a JCas class!
+//    
+//    if (!isOk && superClasses.size() > 0) {
+//      /** JCas Class's supertypes for "{0}", "{1}" and the corresponding UIMA Supertypes for "{2}", "{3}" don't have an intersection. */
+//      add2errors(errorSet, 
+//                 new CASRuntimeException(CASRuntimeException.JCAS_CAS_MISMATCH_SUPERTYPE, 
+//                     clazz.getName(), Misc.ppList(superClasses), ti.getName(), Misc.ppList(Arrays.asList(ti.getAllSuperTypes()))),
+//                 true);  // throwable error
+//    }
 
     // the range of all the features must match the getters
 
@@ -685,21 +1172,31 @@
       
       String mname = m.getName(); 
       if (mname.length() <= 3 || !mname.startsWith("get")) continue;
-      String suffix = (mname.length() == 4) ? "" : mname.substring(4); 
-      String fname = Character.toLowerCase(mname.charAt(3)) + suffix; 
+      String suffix = (mname.length() == 4) ? "" : mname.substring(4);  // one char past 1st letter of feature
+      String fname = Character.toLowerCase(mname.charAt(3)) + suffix;   // entire name, with first letter lower cased 
       FeatureImpl fi = ti.getFeatureByBaseName(fname);
-      if (fi == null) {
-        fname = mname.charAt(3) + suffix;
+      if (fi == null) {                            
+        fname = mname.charAt(3) + suffix;      // no feature, but look for one with captialized first letter
         fi = ti.getFeatureByBaseName(fname);
         if (fi == null) continue;
       }
       
+      // some users are writing getFeat(some other args) as additional signatures - skip checking these
+      // https://issues.apache.org/jira/projects/UIMA/issues/UIMA-5557
+      Parameter[] p = m.getParameters();
+      TypeImpl range = fi.getRangeImpl();
+
+      if (p.length > 1) continue;  // not a getter, which has either 0 or 1 arg(the index int for arrays)
+      if (p.length == 1 &&
+          ( ! range.isArray() ||
+            p[0].getType() != int.class)) {
+        continue;  // has 1 arg, but is not an array or the arg is not an int
+      }
+      
       // have the feature, check the range
       Class<?> returnClass = m.getReturnType(); // for primitive, is int.class, etc.
-      TypeImpl range = fi.getRangeImpl();
       Class<?> rangeClass = range.getJavaClass();
-      if (fi.getRangeImpl().isArray()) {
-        Parameter[] p = m.getParameters();
+      if (range.isArray()) {
         if (p.length == 1 && p[0].getType() == int.class) {
           rangeClass = range.getComponentType().getJavaClass();
         }
@@ -717,33 +1214,44 @@
                      false);  // should throw, but some code breaks!
         }
       }
-    }
+    } // end of checking methods
     
-    for (Field f : clazz.getDeclaredFields()) {
-      String fname = f.getName();
-      if (fname.length() <= 5 || !fname.startsWith("_FI_")) continue;
-      String featName = fname.substring(4);
-      FeatureImpl fi = ti.getFeatureByBaseName(featName);
-      if (fi == null) {
-        add2errors(errorSet, 
-                   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   
-       } else {
-        int staticOffsetInClass = Misc.getStaticIntFieldNoInherit(clazz, fname);
-        if (fi.getAdjustedOffset() != staticOffsetInClass) {
-          /** 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. */
+    try {
+      for (Field f : clazz.getDeclaredFields()) {
+        String fname = f.getName();
+        if (fname.length() <= 5 || !fname.startsWith("_FC_")) continue;
+        String featName = fname.substring(4);
+        FeatureImpl fi = ti.getFeatureByBaseName(featName);
+        if (fi == null) {
           add2errors(errorSet, 
-                     new CASRuntimeException(CASRuntimeException.JCAS_FIELD_ADJ_OFFSET_CHANGED,
-                        clazz.getName(), 
-                        fi.getName(), 
-                        Integer.valueOf(staticOffsetInClass), 
-                        Integer.valueOf(fi.getAdjustedOffset())),
-                     staticOffsetInClass != -1);  // throw unless static offset is -1, in that case, a runtime error will occur if it is usedd
-        }
-      }
+                     /** 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 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);
+          MethodHandle mh = (MethodHandle) mhf.get(null);
+          int staticOffsetInClass = (int) mh.invokeExact();
+          if (fi.getAdjustedOffset() != staticOffsetInClass) {
+             /** 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. */
+            add2errors(errorSet, 
+                       new CASRuntimeException(CASRuntimeException.JCAS_FIELD_ADJ_OFFSET_CHANGED,
+                          clazz.getName(), 
+                          fi.getName(), 
+                          Integer.valueOf(staticOffsetInClass), 
+                          Integer.valueOf(fi.getAdjustedOffset())),
+                       staticOffsetInClass != -1);  // throw unless static offset is -1, in that case, a runtime error will occur if it is usedd
+          }  // end of offset changed
+        }  // end of feature check
+      } // end of for loop
+    } catch (Throwable e) {
+      throw new RuntimeException(e);
     }
   }
   
@@ -765,7 +1273,7 @@
     List<ErrorReport> es = errorSet.get();
     if (es != null) {
       StringBuilder msg = new StringBuilder(100);
-      msg.append('\n');
+//      msg.append('\n');  // makes a break in the message at the beginning, unneeded
       for (ErrorReport f : es) {
         msg.append(f.e.getMessage());
         throwWhenDone = throwWhenDone || f.doThrow;
@@ -773,11 +1281,11 @@
       }
       errorSet.set(null); // reset after reporting
       if (throwWhenDone) {
-        throw new CASRuntimeException(CASException.JCAS_INIT_ERROR, msg);
+        throw new CASRuntimeException(CASException.JCAS_INIT_ERROR, "\n" + msg);
       } else {
         Logger logger = UIMAFramework.getLogger();
         if (null == logger) {
-          throw new CASRuntimeException(CASException.JCAS_INIT_ERROR, msg);
+          throw new CASRuntimeException(CASException.JCAS_INIT_ERROR, "\n" + msg);
         } else {
           logger.log(Level.WARNING, msg.toString());
         }          
@@ -800,30 +1308,72 @@
    * @return the generators for that set, as an array indexed by type code
    */
   static FsGenerator3[] getGeneratorsForClassLoader(ClassLoader cl, boolean isPear, TypeSystemImpl tsi) {
-    synchronized(cl2type2JCas) {
+    Map<String, JCasClassInfo> type2jcci = get_className_to_jcci(cl, isPear);
+//    final Map<ClassLoader, Map<String, JCasClassInfo>> cl2t2j = isPear ? cl_4pears_to_type2JCas : cl_to_type2JCas;
+//    synchronized(cl2t2j) {
+//      //debug
+//      System.out.format("debug loading JCas for type System %s ClassLoader %s, isPear: %b%n", 
+//                         tsi.hashCode(), cl, isPear);
       // This is the first time this class loader is being used - load the classes for this type system, or
       // This is the first time this class loader is being used with this particular type system
-      loadAtTypeSystemCommitTime(tsi, true, cl);      
 
-      FsGenerator3[] r = new FsGenerator3[tsi.getTypeArraySize()];
+    loadJCasForTSandClassLoader(tsi, true, cl, type2jcci);
+
+    FsGenerator3[] r = new FsGenerator3[tsi.getTypeArraySize()];
                           
-      Map<String, JCasClassInfo> t2jcci = cl2type2JCas.get(cl);
+//      Map<String, JCasClassInfo> t2jcci = cl2t2j.get(cl);
       // can't use values alone because many types have the same value (due to copy-down)
-      for (Entry<String, JCasClassInfo> e : t2jcci.entrySet()) {
-        TypeImpl ti = tsi.getType(Misc.javaClassName2UimaTypeName(e.getKey()));
-        if (null == ti) {
-          continue;  // JCas loaded some type in the past, but it's not in this type system
-        }
-        JCasClassInfo jcci = e.getValue();
-        
-        if (!isPear || jcci.isPearOverride(cl)) {
-          r[ti.getCode()] = (FsGenerator3) jcci.generator;
-        }      
-      }
-      return r;
-    }   
+    
+    // cannot iterate over type2jcci - that map only has types with found JCas classes
+    
+    getGeneratorsForTypeAndSubtypes(tsi.topType, type2jcci, isPear, cl, r);
+    
+//    for (Entry<String, JCasClassInfo> e : type2jcci.entrySet()) {
+//      TypeImpl ti = tsi.getType(Misc.javaClassName2UimaTypeName(e.getKey()));
+//      if (null == ti) {
+//        continue;  // JCas loaded some type in the past, but it's not in this type system
+//      }
+//      JCasClassInfo jcci = e.getValue();
+//      
+//      // skip entering a generator in the result if
+//      //    in a pear setup, and this cl is not the cl that loaded the JCas class.
+//      //    See method comment for why.
+//      if (!isPear || jcci.isPearOverride(cl)) {
+//        r[ti.getCode()] = (FsGenerator3) jcci.generator;
+//      }      
+//    }
+    return r;
   }
   
+  private static void getGeneratorsForTypeAndSubtypes(
+      TypeImpl ti, 
+      Map<String, 
+      JCasClassInfo> t2jcci, 
+      boolean isPear,
+      ClassLoader cl,
+      FsGenerator3[] r) {
+    
+    TypeImpl jti = ti;
+    JCasClassInfo jcci = t2jcci.get(jti.getJCasClassName());
+    while (jcci == null) {
+      jti = jti.getSuperType();
+      jcci = t2jcci.get(jti.getJCasClassName());
+    }
+    
+    // skip entering a generator in the result if
+    //    in a pear setup, and this cl is not the cl that loaded the JCas class.
+    //    See method comment for why.
+    if (!isPear || jcci.isPearOverride(cl)) {
+      r[ti.getCode()] = (FsGenerator3) jcci.generator;
+    }      
+    
+    for (TypeImpl subtype : ti.getDirectSubtypes()) {
+      getGeneratorsForTypeAndSubtypes(subtype, t2jcci, isPear, cl, r);
+    }
+
+  }
+  
+  
   private static boolean isAllNull(FsGenerator3[] r) {
     for (FsGenerator3 v : r) {
       if (v != null)
@@ -832,5 +1382,99 @@
     return true;
   }
 
+  /**
+   * Called once when the JCasClassInfo is created.
+   * Once set, the offsets are never changed (although they could be...)
+   * 
+   * New type systems are checked for conformance to existing settings in the JCas class.
+   * Type System types are augmented by features defined in the JCas
+   *   but missing in the type, before this routine is called.
+   * 
+   * Iterate over all fields named _FC_  followed by a feature name.  
+   *   If that feature doesn't exist in this type system - skip init, will cause runtime error if used
+   *   Else, set the callSite's method Handle to one that returns the int constant for type system's offset of that feature.
+   *     If already set, check that the offset didn't change.
+   *     
+   *  
+   * @param clazz -
+   * @param type -
+   */
+  private static void updateOrValidateAllCallSitesForJCasClass(Class<? extends TOP> clazz, TypeImpl type, ArrayList<MutableCallSite> callSites_toSync ) {
+    try {
+      Field[] fields = clazz.getDeclaredFields();
+     
+      for (Field field : fields) {
+        String fieldName = field.getName();
+        if (fieldName.startsWith("_FC_")) {
+  
+//          //debug
+//          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.
+                        // only happens for pear-loaded lazyily JCas classes
+                        // "Normal" loaded JCas classes (at start of type system commit)
+                        // have any extra features added to the type system
+                        // https://issues.apache.org/jira/browse/UIMA-5698
+          
+          MutableCallSite c;
+          field.setAccessible(true);
+          c = (MutableCallSite) field.get(null);
+          
+          if (c == null) { // happens when first load of TypeSystemImpl is from JCas class ref
+            continue;  // will be set later when type system is committed.
+          }
+          
+          int prev = (int) c.getTarget().invokeExact();
+          if (prev == -1) { // the static method in JCas classes, TypeSystemImpl.createCallSite,
+                            // initializes the call site with a method handle that returns -1
+            MethodHandle mh_constant = getConstantIntMethodHandle(index);
+            c.setTarget(mh_constant);
+            callSites_toSync.add(c);
+          } else if (prev != index) {
+            // This is one of two errors.  
+            // It could also be caused by the range type switching from ref array to the int array
+            checkConformance(clazz.getClassLoader(), type.getTypeSystem());
+            reportErrors();
+//            //debug
+//            System.err.format(
+//                "Debug incompat offset jcas, class = %s, type= %s, classIndex = %d, type index: %d%n",
+//                clazz.getName(), type.getName(), prev, index);
+//            System.err.flush();
+            throw new UIMA_IllegalStateException(UIMA_IllegalStateException.JCAS_INCOMPATIBLE_TYPE_SYSTEMS,
+                new Object[] {type.getName(), featureName});
+          }
+        }
+      }
+    } catch (Throwable e) {
+      Misc.internalError(e); // never happen
+    }
+  }
+  
+  static Map<String, JCasClassInfo> get_className_to_jcci(ClassLoader cl, boolean is_pear) {
+    final Map<ClassLoader, Map<String, JCasClassInfo>> cl2t2j = cl_to_type2JCas;   /*is_pear ? cl_4pears_to_type2JCas :*/
+    return cl2t2j.computeIfAbsent(cl, x -> new HashMap<>());
+  }
+  
+  static Lookup getLookup(ClassLoader cl) {
+    Lookup lookup = null;
+    try {
+      Class<?> clazz = Class.forName(UIMAClassLoader.MHLC, true, cl);
+      Method m = clazz.getMethod("getMethodHandlesLookup");
+      lookup = (Lookup) m.invoke(null);  
+    } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new UIMARuntimeException(e, UIMARuntimeException.INTERNAL_ERROR);
+    }
+    return lookup;
+  }
 }
   
\ No newline at end of file
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSComparator.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSComparator.java
index 45a72ac..a6e9729 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSComparator.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSComparator.java
@@ -22,6 +22,7 @@
 import org.apache.uima.cas.FeatureStructure;
 
 /**
+ * UNUSED V3 backwards compat only
  * Delete  REplace with Comparator&lt;FeatureStructure&gt; or the like.
  * Interface to compare two feature structures.
  * 
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSFloatConstraintImpl.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSFloatConstraintImpl.java
index ff005f0..58acbfe 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSFloatConstraintImpl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSFloatConstraintImpl.java
@@ -53,6 +53,7 @@
     this.values = new Vector<Float>();
   }
 
+  @Override
   public boolean match(float f) {
     final int max = this.codes.size();
     for (int i = 0; i < max; i++) {
@@ -102,6 +103,7 @@
    * @param f
    *          Matched value must be equal to this.
    */
+  @Override
   public void eq(float f) {
     this.codes.add(EQ);
     this.values.add(Float.valueOf(f));
@@ -113,6 +115,7 @@
    * @param f
    *          Matched value must be less than this.
    */
+  @Override
   public void lt(float f) {
     this.codes.add(LT);
     this.values.add(Float.valueOf(f));
@@ -124,6 +127,7 @@
    * @param f
    *          Matched value must be less than or equal to this.
    */
+  @Override
   public void leq(float f) {
     this.codes.add(LEQ);
     this.values.add(Float.valueOf(f));
@@ -135,6 +139,7 @@
    * @param f
    *          Matched value must be greater than this.
    */
+  @Override
   public void gt(float f) {
     this.codes.add(GT);
     this.values.add(Float.valueOf(f));
@@ -146,11 +151,13 @@
    * @param f
    *          Matched value must be greater than or equal to this.
    */
+  @Override
   public void geq(float f) {
     this.codes.add(GEQ);
     this.values.add(Float.valueOf(f));
   }
 
+  @Override
   public String toString() {
     if (this.codes.size() == 1) {
       return toString(this.codes.get(0)) + " " + this.values.get(0).toString();
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSImplComparator.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSImplComparator.java
index 82898a4..bb4aa1d 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSImplComparator.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSImplComparator.java
@@ -20,6 +20,7 @@
 package org.apache.uima.cas.impl;
 
 /**
+ * UNUSED V3, backwards compat only
  * Interface to compare two feature structures, represented by their addresses.
  * 
  */
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexComparatorImpl.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexComparatorImpl.java
index 223ef6d..4277fbc 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexComparatorImpl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexComparatorImpl.java
@@ -65,10 +65,12 @@
     return t.isPrimitive();
   }
 
+  @Override
   public void setType(Type type) {
     this.type = type;
   }
 
+  @Override
   public Type getType() {
     return this.type;
   }
@@ -77,6 +79,7 @@
     return ((TypeImpl)this.type).getCode();
   }
 
+  @Override
   public int addKey(Feature feat, int compareKey) {
     if (!checkType(feat.getRange())) {
       return -1;
@@ -87,6 +90,7 @@
     return rc;
   }
 
+  @Override
   public int addKey(LinearTypeOrder typeOrder, int compareKey) {
     final int rc = this.keySpecs.size();
     this.keySpecs.add(typeOrder);
@@ -94,16 +98,19 @@
     return rc;
   }
 
+  @Override
   public int getKeyType(int key) {
     return (this.keySpecs.get(key) instanceof Feature) 
         ? FEATURE_KEY 
         : TYPE_ORDER_KEY;
   }
 
+  @Override
   public int getNumberOfKeys() {
     return this.keySpecs.size();
   }
 
+  @Override
   public FeatureImpl getKeyFeature(int key) {
     if (getKeyType(key) == FEATURE_KEY) {
       return (FeatureImpl) this.keySpecs.get(key);
@@ -118,6 +125,7 @@
     return null;
   }
 
+  @Override
   public int getKeyComparator(int key) {
     return this.directions.get(key);
   }
@@ -125,6 +133,7 @@
   /**
    * Equals including the type of the comparator
    */
+  @Override
   public boolean equals(Object o) {
     if (this == o) {
       return true;
@@ -172,6 +181,7 @@
     return result;
   }
 
+  @Override
   public boolean isValid() {
     if (this.type == null) {
       return false;
@@ -204,6 +214,7 @@
    * 
    * @see java.lang.Comparable#compareTo(Object)
    */
+  @Override
   public int compareTo(FSIndexComparator o) {
     FSIndexComparator comp = o;
     final int thisSize = this.getNumberOfKeys();
@@ -211,7 +222,7 @@
     int i = 0;
     int feat1, feat2;
     while ((i < thisSize) && (i < compSize)) {
-      feat1 = ((FeatureImpl) this.getKeyFeature(i)).getCode();
+      feat1 = this.getKeyFeature(i).getCode();
       feat2 = ((FeatureImpl) comp.getKeyFeature(i)).getCode();
       if (feat1 < feat2) {
         return -1;
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexRepositoryImpl.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexRepositoryImpl.java
index 973e84d..007c621 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexRepositoryImpl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIndexRepositoryImpl.java
@@ -19,9 +19,10 @@
 
 package org.apache.uima.cas.impl;
 
+import java.util.AbstractCollection;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.BitSet;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -29,14 +30,16 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Set;
-import java.util.Vector;
 import java.util.function.Consumer;
+import java.util.stream.Stream;
 
 import org.apache.uima.UIMARuntimeException;
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASException;
 import org.apache.uima.cas.CASRuntimeException;
+import org.apache.uima.cas.FSComparators;
 import org.apache.uima.cas.FSIndex;
 import org.apache.uima.cas.FeatureStructure;
 import org.apache.uima.cas.Type;
@@ -80,6 +83,8 @@
   
   public final static boolean ITEM_ADDED_TO_INDEX = true;
   public final static boolean ITEM_REMOVED_FROM_INDEX = false;
+  /** set next to true to debug issues with different treatment of no type priorities in v3 */
+  public final static boolean V2_ANNOTATION_COMPARE_TYPE_ORDER = false;
   /**
    * The default size of an index.
    */
@@ -170,10 +175,14 @@
     /**
      * lazily created comparator using the built-in annotation index
      */
-    private Comparator<TOP> annotationFsComparator = null;
+    private Comparator<TOP> annotationFsComparatorWithoutId = null;
     
     private Comparator<TOP> annotationFsComparatorWithId = null;
     
+    private Comparator<TOP> annotationFsComparatorNoTypeWithoutId = null;
+    
+    private Comparator<TOP> annotationFsComparatorNoTypeWithId = null;
+
     /**
      * optimization only - bypasses some shared (among views) initialization if already done
      */
@@ -205,7 +214,7 @@
      * true if one or more of the indexes is a set index
      */
     boolean hasSetIndex; 
-    String typename;
+    final String typename;
     /**
      * index of any sorted index or -1 if no sorted index
      */
@@ -213,6 +222,10 @@
     int aBagIndex = -1;      // -1 or the position of an arbitrary bag index
     final ArrayList<FsIndex_iicp<TOP>> indexesForType = new ArrayList<>(0); 
     
+    IndexesForType(TypeImpl ti) {
+      this.typename = ti.getName();
+    }
+    
     <T extends TOP> FsIndex_iicp<T> getNonSetIndex() {
       if (aSortedIndex < 0 && aBagIndex < 0) { // index is empty!
         return null;
@@ -221,7 +234,7 @@
     }
     
     void add(FsIndex_iicp<TOP> iicp) {
-      typename = iicp.fsIndex_singletype.getType().getName();
+      assert typename.equals(iicp.fsIndex_singletype.getType().getName());
       final int kind = iicp.fsIndex_singletype.getIndexingStrategy();
       int i = indexesForType.size();
       switch (kind) {
@@ -497,7 +510,7 @@
     final int numTypes = ts.getNumberOfTypes() + 1; // Type counting starts at 1.
     // Can't instantiate arrays of generic types, but this is ok for ArrayList.
     for (int i = 1; i < numTypes; i++) {
-      this.indexArray[i] = new IndexesForType();
+      this.indexArray[i] = new IndexesForType(ts.types.get(i));
     }
     
 //    Arrays.fill(detectIllegalIndexUpdates, Integer.MIN_VALUE);
@@ -751,7 +764,7 @@
     switch (indexingStrategy) {
     
     case FSIndex.SET_INDEX: 
-      ind = new FsIndex_set_sorted<T>(this.cas, type, indexingStrategy, comparatorForIndexSpecs, false); // false = is set
+      ind = new FsIndex_set_sorted<T>(this.cas, type, indexingStrategy, comparatorForIndexSpecs); // false = is set
       break;
     
 //    case FSIndex.FLAT_INDEX: 
@@ -765,7 +778,7 @@
     
     default: 
       // SORTED_INDEX is the default. We don't throw any errors, if the code is unknown, we just create a sorted index.
-      ind = new FsIndex_set_sorted<T>(this.cas, type, FSIndex.SORTED_INDEX, comparatorForIndexSpecs, true); // true = is sorted
+      ind = new FsIndex_set_sorted<T>(this.cas, type, FSIndex.SORTED_INDEX, comparatorForIndexSpecs); // true = is sorted
       break;
  
     }
@@ -1021,8 +1034,8 @@
    * @see org.apache.uima.cas.FSIndexRepository#getIndex(String)
    */
   @SuppressWarnings("unchecked")
-  public <T extends FeatureStructure> FSIndex<T> getIndex(String label) {
-    return (FSIndex<T>) this.name2indexMap.get(label);
+  public <T extends FeatureStructure> LowLevelIndex<T> getIndex(String label) {
+    return (LowLevelIndex<T>) this.name2indexMap.get(label);
   }
   
   /**
@@ -1042,7 +1055,7 @@
   
   /**
    * Remove all instances of a particular type (including its subtypes) from all indexes
-   * @param type -
+   * @param type  Type to remove (including all its subtypes) from this particular view.
    */
   public void removeAllIncludingSubtypes(Type type) {
     removeAllExcludingSubtypes(type);
@@ -1078,36 +1091,36 @@
   // ///////////////////////////////////////////////////////////////////////////
   // Serialization support
 
-  /**
-   * For one particular view (the one associated with this instance of FsIndexRepositoryImpl),
-   * return an array containing all FSs in any defined index, in this view. 
-   * This is intended to be used for serialization.
-   * 
-   * The order in which FSs occur in the array does not reflect the order in which they
-   * were added to the repository. 
-   * 
-   * @param <T> type of Feature Structure
-   * @return a List of all FSs in any defined index, in this view.
-   */
-  public <T extends FeatureStructure> List<T> getIndexedFSs() {
-    
-    final ArrayList<TOP> v = new ArrayList<>();  // accumulates fsAddrs from various indexes
-    
-    /* Iterate over index by type, with something in there
-     * and dump all the fss found for that type (excluding subtypes) into v
-     *   bag preferred over sorted; 
-     */
-    for (int i = 0; i < this.usedIndexes.size(); i++) {
-//      // debug
-//      int vs1 = v.size();
-      getNonSetSingleIndexForUsedType(i).bulkAddTo(v);
-//      for (int di = vs1; di < v.size(); di ++) {  // debug
-//        assert v.get(di) != null;                 // debug verify not null
-//      }
-    }  
-   
-    return (List<T>) v;
-  }
+//  /**
+//   * For one particular view (the one associated with this instance of FsIndexRepositoryImpl),
+//   * return an array containing all FSs in any defined index, in this view. 
+//   * This is intended to be used for serialization.
+//   * 
+//   * The order in which FSs occur in the array does not reflect the order in which they
+//   * were added to the repository. 
+//   * 
+//   * @param <T> type of Feature Structure
+//   * @return a List of all FSs in any defined index, in this view.
+//   */
+//  public <T extends FeatureStructure> List<T> getIndexedFSs4Serializers() {
+//    
+//    final ArrayList<TOP> v = new ArrayList<>();  // accumulates fsAddrs from various indexes
+//    
+//    /* Iterate over index by type, with something in there
+//     * and dump all the fss found for that type (excluding subtypes) into v
+//     *   bag preferred over sorted; 
+//     */
+//    for (int i = 0; i < this.usedIndexes.size(); i++) {
+////      // debug
+////      int vs1 = v.size();
+//      getNonSetSingleIndexForUsedType(i).bulkAddTo(v);
+////      for (int di = vs1; di < v.size(); di ++) {  // debug
+////        assert v.get(di) != null;                 // debug verify not null
+////      }
+//    }  
+//   
+//    return (List<T>) v;
+//  }
   
   /**
    * For this view, walk the indexed FSs in arbitrary order.
@@ -1307,6 +1320,7 @@
     
     // Add fsRef to all indexes.
     boolean noIndexOrOnlySetindexes = true;
+    boolean setOrSorted = false;  // set to true if at least one set or sorted index found
     for (FsIndex_iicp<TOP> iicp : indexes) {
       
       // the indexes for the type are over the type and its subtypes.
@@ -1322,6 +1336,11 @@
       if (noIndexOrOnlySetindexes) {
         noIndexOrOnlySetindexes = indexingStrategy == FSIndex.SET_INDEX;
       }
+      
+      // remember if we get any set or sorted index by turning this true
+      if (setOrSorted == false && indexingStrategy != FSIndex.BAG_INDEX) {
+        setOrSorted = true;
+      }
     }
     
     // log even if added back, because remove logs remove, and might want to know it was "reindexed"
@@ -1329,7 +1348,10 @@
       logIndexOperation(fs, true);
     }
     
-    fs._setInSetSortedIndexed();
+    if (setOrSorted) { // only set this bit if this fs is in 1 or more set or sorted indexes
+      fs._setInSetSortedIndexed();
+    }
+    
     if (isAddback) { return; }
     
     // https://issues.apache.org/jira/browse/UIMA-4111
@@ -1441,24 +1463,8 @@
    */
   public <T extends FeatureStructure> LowLevelIterator<T> getAllIndexedFS(Type type) {
     final ArrayList<LowLevelIterator<T>> iteratorList = new ArrayList<>();
-    
-//    TypeImpl ti = (TypeImpl) type;
-//    if (!isUsedChanged && ti.isTopType()) {  
-//      // reuse previously computed iicps4allFSs
-//      for (FsIndex_iicp<?> iicp : iicps4allFSs) {
-//        if (iicp.cachedSubFsLeafIndexes[0].size() != 0) {
-//          LowLevelIterator<T> it = (iicp.getIndexingStrategy() == FSIndex.SORTED_INDEX) 
-//              ? (LowLevelIterator<T>)iicp.iteratorUnordered()
-//              : (LowLevelIterator<T>)iicp.iterator();
-//          iteratorList.add(it);
-//        }
-//      }
-//    } else {
-//      iicps4allFSs.clear();
-      getAllIndexedFS(type, iteratorList);
-//      this.isUsedChanged = false; // above call recomputed the cache  
-//    }    
 
+    getAllIndexedFS(type, iteratorList);
     
     final int iteratorListSize = iteratorList.size();
     if (iteratorListSize == 0) {
@@ -1469,7 +1475,7 @@
     }
     
     LowLevelIterator<T>[] ia = new LowLevelIterator[iteratorListSize];
-    return new FsIterator_aggregation_common<T>(iteratorList.toArray(ia), null);
+    return new FsIterator_aggregation_common<T>(iteratorList.toArray(ia), null, null);
   }
 
   private final <T extends FeatureStructure> void getAllIndexedFS(Type type, List<LowLevelIterator<T>> iteratorList) {
@@ -1490,12 +1496,12 @@
 
     TypeImpl ti = (TypeImpl)type;
     if (isUsed.get(ti.getCode())) {
-      FsIndex_iicp<TOP> iicp = getIndexesForType(ti.getCode()).getNonSetIndex();  
+      FsIndex_iicp<T> iicp = (FsIndex_iicp<T>) getIndexesForType(ti.getCode()).getNonSetIndex();  
       
 //      iicps4allFSs.add(iicp);
       if (null != iicp && !iicp.isEmpty()) {
         LowLevelIterator<T> it = (iicp.getIndexingStrategy() == FSIndex.SORTED_INDEX) 
-                                    ? (LowLevelIterator<T>)iicp.iteratorUnordered()
+                                    ? (LowLevelIterator<T>)iicp.iterator(true, true)  // order not needed, ignore type
                                     : (LowLevelIterator<T>)iicp.iterator();
         iteratorList.add(it);
         if (iicp.isDefaultBagIndex()) {
@@ -1522,6 +1528,186 @@
     }
 //    ((TypeImpl)type).getDirectSubtypes().stream().forEach(subType -> getAllIndexedFS(subType, iteratorList));
   }
+
+  // do this in index creation order 
+  // needed for backwards compatibility
+  // https://issues.apache.org/jira/browse/UIMA-5603 see comment toward end
+  
+  public Collection<TOP> getIndexedFSs() {
+    final ArrayList<CopyOnWriteIndexPart<TOP>> indexes = new ArrayList<>(); 
+    for (int i = 0; i < this.usedIndexes.size(); i++) {
+      FsIndex_singletype<TOP> idx = getNonSetSingleIndexForUsedType(i);
+      if (idx.size() > 0) {
+        indexes.add(idx.getNonNullCow());
+      }
+    }
+    return getCollectionFromCows(indexes);
+  }
+  
+  public <T extends TOP> Collection<T> getIndexedFSs(Class<T> clazz) {
+    return getIndexedFSs(cas.getCasType(clazz));
+  }
+  
+  /**
+   * @param type the type of Feature Structures to include (including subtypes)
+   * @return an unmodifiable, unordered set of all indexed (in this view) Feature Structures
+   *         of the specified type (including subtypes)
+   */
+  public <T extends TOP> Collection<T> getIndexedFSs(Type type) {
+    // collect CopyOnWriteIndexPart s for all index parts for type and its subtypes
+    final ArrayList<CopyOnWriteIndexPart<T>> indexes = new ArrayList<>(); 
+    TypeImpl ti = (TypeImpl) type;
+    
+    collectCowIndexParts(ti, indexes);
+    return getCollectionFromCows(indexes);
+  }
+    
+  private <T extends TOP> Collection<T> getCollectionFromCows(ArrayList<CopyOnWriteIndexPart<T>> indexes) {
+
+    if (indexes.size() == 0) {
+      return Collections.emptySet();
+    }
+
+    return new AbstractCollection<T>() {
+      
+      @Override
+      public Iterator<T> iterator() {
+        return new Iterator<T>() {
+          final int indexesSize = indexes.size();
+          int indexesIndex = 0;
+          Iterator<T> it = indexes.get(0).iterator();
+          
+          @Override
+          public boolean hasNext() {
+            return indexesIndex < indexesSize; 
+          }
+
+          @Override
+          public T next() {
+            if (!hasNext()) {
+              throw new NoSuchElementException();
+            }
+            T v = it.next();
+            
+            if (!it.hasNext()) {
+              indexesIndex++;
+              if (indexesIndex == indexesSize) {
+                return v;
+              }
+              it = indexes.get(indexesIndex).iterator();
+            }
+            return v;
+          }
+          
+        };
+      }
+
+      @Override
+      public int size() {
+        int r = 0;
+        for (CopyOnWriteIndexPart<T> cow : indexes) {
+          r += cow.size();
+        }
+        return r;
+      }
+      
+      @Override
+      public TOP[] toArray() {
+        TOP[] r = new TOP[size()];
+        
+        int i = 0;
+        for (CopyOnWriteIndexPart<T> idx : indexes) {
+          i = idx.copyToArray(r, i);
+        }
+        return r;
+      }
+
+      /* (non-Javadoc)
+       * @see java.util.AbstractCollection#toArray(java.lang.Object[])
+       */
+      @Override
+      public <U> U[] toArray(U[] r) {
+        
+        int i = 0;
+        for (CopyOnWriteIndexPart<T> idx : indexes) {
+          i = idx.copyToArray((TOP[]) r, i);
+        }
+        return r;
+      }
+
+      
+      
+      /* (non-Javadoc)
+       * @see java.util.AbstractCollection#isEmpty()
+       */
+      @Override
+      public boolean isEmpty() {
+        return indexes.isEmpty();
+      }
+      
+    };
+  }
+  
+  private <T extends TOP> void collectCowIndexParts(TypeImpl ti, ArrayList<CopyOnWriteIndexPart<T>> indexes) {
+    FsIndex_iicp<T> iicp;
+    
+    if (!isUsed.get(ti.getCode()) ||
+        (iicp = getIndexesForType(ti.getCode()).getNonSetIndex()) == null  || 
+        iicp.isEmpty()) {  // could be used, but now empty
+      // No index for this type was found at all. 
+      // Example:  You ask for an iterator over "TOP", but no instances of TOP are created,
+      //   and no index over TOP was ever created.
+      // Since the auto-indexes are created on demand for
+      //   each type, there may be gaps in the inheritance chain. So keep descending the inheritance
+      //   tree looking for relevant indexes.
+      ti.getDirectSubtypes().forEach(type -> collectCowIndexParts(type, indexes));
+      return;
+    }
+    
+    if (iicp.isDefaultBagIndex()) {
+      if (iicp.getFsIndex_singleType().size() > 0) {
+        indexes.add(iicp.getFsIndex_singleType().getNonNullCow());
+      }
+      ti.getDirectSubtypes().forEach(type -> collectCowIndexParts(type, indexes));
+    } else {
+      iicp.collectCowIndexParts(indexes);
+    }
+  }
+  
+  /**
+   * Stream instances of all of the non-empty indexes themselves
+   * @param type - the type to filter the indexes with
+   * @return all of the non-empty indexes, one for each sorted or default bag per type
+   */
+  public Stream<FsIndex_singletype<TOP>> streamNonEmptyIndexes(Type type) {
+    TypeImpl ti = (TypeImpl) type;
+    if (!isUsed.get(ti.getCode())) {
+      return streamNonEmptyDirectSubtypes(ti);
+    }
+    FsIndex_iicp<TOP> iicp = getIndexesForType(ti.getCode()).getNonSetIndex();
+    if (null == iicp || iicp.isEmpty()) {
+      return Stream.empty();
+    }
+    Stream<FsIndex_singletype<TOP>> iicpIndexesStream = iicp.streamNonEmptyIndexes();
+    return iicp.isDefaultBagIndex()
+             ? Stream.concat(iicpIndexesStream, streamNonEmptyDirectSubtypes(ti))
+             : iicpIndexesStream;
+  }
+  
+  public Stream<FsIndex_singletype<TOP>> streamNonEmptyIndexes(Class<? extends TOP> clazz) {
+    return streamNonEmptyIndexes(getCasImpl().getCasType(clazz));
+  }
+    
+  private Stream<FsIndex_singletype<TOP>> streamNonEmptyDirectSubtypes(TypeImpl ti) {
+    Stream<FsIndex_singletype<TOP>> r = null;
+    for (TypeImpl subType : ti.getDirectSubtypes()) {
+      r = (r == null) 
+            ? streamNonEmptyIndexes(subType)
+            : Stream.concat(r, streamNonEmptyIndexes(subType));
+    }
+    return (r == null) ? Stream.empty() : r;
+  }
+  
     
   // next method dropped - rather than seeing if something is in the index, and then 
   // later removing it (two lookups), we just conditionally remove it
@@ -1759,13 +1945,40 @@
 //    return this.sii.annotationComparator;
 //  }
   
-  Comparator<TOP> getAnnotationFsComparator() {
-    Comparator<TOP> r = this.sii.annotationFsComparator;
+  
+  public Comparator<TOP> getAnnotationFsComparator(FSComparators withId, FSComparators withTypeOrder) {
+    Comparator<TOP> r = getCachedComparator(withId, withTypeOrder);
+    if (r == null) {
+      r = createAnnotationFsComparator(withId, withTypeOrder);
+      setCachedComparator(withId, withTypeOrder, r);
+    }
+    return r; 
+  }
+
+  
+  private Comparator<TOP> createAnnotationFsComparator(FSComparators withId, FSComparators withTypeOrder) {
+    LinearTypeOrder lto = (withTypeOrder == FSComparators.WITH_TYPE_ORDER) ? getDefaultTypeOrder() : null;
+    if (withId == FSComparators.WITH_ID) {
+      if (withTypeOrder == FSComparators.WITH_TYPE_ORDER) {
+        return (fs1, fs2) -> (fs1 == fs2) ? 0 : ((Annotation) fs1).compareAnnotationWithId((Annotation) fs2, lto);
+      } else {
+        return (fs1, fs2) -> (fs1 == fs2) ? 0 : ((Annotation) fs1).compareAnnotationWithId((Annotation) fs2);
+      }
+    } else {
+      if (withTypeOrder == FSComparators.WITH_TYPE_ORDER) {
+        return (fs1, fs2) -> (fs1 == fs2) ? 0 : ((Annotation) fs1).compareAnnotation((Annotation) fs2, lto);
+      } else {
+        return (fs1, fs2) -> (fs1 == fs2) ? 0 : ((Annotation) fs1).compareAnnotation((Annotation) fs2);
+      }
+    }
+  }
+  
+  public Comparator<TOP> getAnnotationFsComparatorWithoutId() {
+    Comparator<TOP> r = this.sii.annotationFsComparatorWithoutId;
     // lazy creation
     if (null != r) {
       return r;
-    }
-    
+    }    
     return createAnnotationFsComparator();
   }
   
@@ -1774,37 +1987,58 @@
     // lazy creation
     if (null != r) {
       return r;
-    }
-    
+    }    
     return createAnnotationFsComparatorWithId();    
   }
   
+
   private Comparator<TOP> createAnnotationFsComparator() {
     final LinearTypeOrder lto = getDefaultTypeOrder();  // used as constant in comparator
     
-    return this.sii.annotationFsComparator = (fsx1, fsx2) -> {
-      if (fsx1 == fsx2) return 0;
-      Annotation fs1 = (Annotation) fsx1;
-      Annotation fs2 = (Annotation) fsx2;
+    if (!V2_ANNOTATION_COMPARE_TYPE_ORDER && lto.isEmptyTypeOrder()) {
+      return this.sii.annotationFsComparatorWithoutId = (fsx1, fsx2) -> {
+        if (fsx1 == fsx2) return 0;
+        Annotation fs1 = (Annotation) fsx1;
+        Annotation fs2 = (Annotation) fsx2;        
+        return fs1.compareAnnotation(fs2);
+      };
       
-      return fs1.compareAnnotation(fs2, lto);
-    };
+    } else {
+      return this.sii.annotationFsComparatorWithoutId = (fsx1, fsx2) -> {
+        if (fsx1 == fsx2) return 0;
+        Annotation fs1 = (Annotation) fsx1;
+        Annotation fs2 = (Annotation) fsx2;
+        
+        return fs1.compareAnnotation(fs2, lto);
+      };
+    }
   }
   
+//  public boolean isAnnotationComparator_usesTypeOrder() {
+//    final LinearTypeOrder lto = getDefaultTypeOrder(); 
+//    return V2_ANNOTATION_COMPARE_TYPE_ORDER || !lto.isEmptyTypeOrder();
+//  }
+  
   //unrolled because of high frequency use
   private Comparator<TOP> createAnnotationFsComparatorWithId() {
-
     final LinearTypeOrder lto = getDefaultTypeOrder();  // used as constant in comparator
 
-    this.sii.annotationFsComparatorWithId = (fsx1, fsx2) -> {
-      if (fsx1 == fsx2) return 0;
-
-      final Annotation fs1 = (Annotation) fsx1;
-      final Annotation fs2 = (Annotation) fsx2;
+    if (!V2_ANNOTATION_COMPARE_TYPE_ORDER && lto.isEmptyTypeOrder()) {
+      this.sii.annotationFsComparatorWithId = (fsx1, fsx2) -> {
+        if (fsx1 == fsx2) return 0;
+        final Annotation fs1 = (Annotation) fsx1;
+        final Annotation fs2 = (Annotation) fsx2;
+        return fs1.compareAnnotationWithId(fs2);
+      };
       
-      return fs1.compareAnnotationWithId(fs2, lto);
-    };
-    
+    } else {
+      this.sii.annotationFsComparatorWithId = (fsx1, fsx2) -> {
+        if (fsx1 == fsx2) return 0;
+        final Annotation fs1 = (Annotation) fsx1;
+        final Annotation fs2 = (Annotation) fsx2;
+        return fs1.compareAnnotationWithId(fs2, lto);
+      };
+    }
     return this.sii.annotationFsComparatorWithId;
   }
 
@@ -1827,4 +2061,41 @@
   public TypeSystemImpl getTypeSystemImpl() {
     return sii.tsi;
   }
+  
+  public CASImpl getCasImpl() {
+    return cas;
+  }
+  
+  private Comparator<TOP> getCachedComparator(FSComparators withId, FSComparators withTypeOrder) {
+    if (withId == FSComparators.WITH_ID) {
+      if (withTypeOrder == FSComparators.WITH_TYPE_ORDER) {
+        return this.sii.annotationFsComparatorWithId;
+      } else {
+        return this.sii.annotationFsComparatorNoTypeWithId;
+      }
+    } else {
+      if (withTypeOrder == FSComparators.WITH_TYPE_ORDER) {
+        return this.sii.annotationFsComparatorWithoutId;
+      } else {
+        return this.sii.annotationFsComparatorNoTypeWithoutId;
+      }
+    }
+  }
+
+  private void setCachedComparator(FSComparators withId, FSComparators withTypeOrder, Comparator<TOP> c) {
+    if (withId == FSComparators.WITH_ID) {
+      if (withTypeOrder == FSComparators.WITH_TYPE_ORDER) {
+        this.sii.annotationFsComparatorWithId = c;
+      } else {
+        this.sii.annotationFsComparatorNoTypeWithId = c;
+      }
+    } else {
+      if (withTypeOrder == FSComparators.WITH_TYPE_ORDER) {
+        this.sii.annotationFsComparatorWithoutId = c;
+      } else {
+        this.sii.annotationFsComparatorNoTypeWithoutId = c;
+      }
+    }
+  }
+
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorImplBase.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorImplBase.java
index 73d34ee..13a637d 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorImplBase.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSIteratorImplBase.java
@@ -19,9 +19,12 @@
 

 package org.apache.uima.cas.impl;

 

+import java.util.Comparator;

+

 import org.apache.uima.cas.FSIterator;

 import org.apache.uima.cas.FeatureStructure;

 import org.apache.uima.cas.text.AnnotationFS;

+import org.apache.uima.jcas.cas.TOP;

 

 /**

  * Version 2 compatibility only, not used internally in version 3 

@@ -29,7 +32,7 @@
  * by java.util.Iterator.

  * Users writing their own iterator implementations may extend this class

  */

-public abstract class FSIteratorImplBase<T extends FeatureStructure> implements FSIterator<T> {

+public abstract class FSIteratorImplBase<T extends FeatureStructure> implements LowLevelIterator<T> {

 

   // Jira UIMA-464: add annotation comparator to be able to use Collections.binarySearch() on

   // annotation list.

@@ -95,4 +98,11 @@
   <TT extends AnnotationFS> void moveTo(int begin, int end) {

     throw new UnsupportedOperationException();

   }

+  

+  /**

+   * default implementation of getComparator

+   */

+  public Comparator<TOP> getComparator() {

+    return ll_getIndex().getComparator();

+  }

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSStringConstraintImpl.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSStringConstraintImpl.java
index d457c06..69f2841 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSStringConstraintImpl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSStringConstraintImpl.java
@@ -41,10 +41,12 @@
     this.string = "";
   }
 
+  @Override
   public void equals(String s) {
     this.string = s;
   }
 
+  @Override
   public boolean match(String s) {
     if (this.string == null) {
       return (s == null);
@@ -52,6 +54,7 @@
     return (this.string.equals(s));
   }
 
+  @Override
   public String toString() {
     // need to escape quotes and backslashes
     StringBuffer buf = new StringBuffer();
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSsTobeAddedback.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSsTobeAddedback.java
index 2681686..8140458 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSsTobeAddedback.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSsTobeAddedback.java
@@ -27,6 +27,7 @@
 

 import org.apache.uima.cas.FSIndexRepository;

 import org.apache.uima.jcas.cas.TOP;

+import org.apache.uima.util.AutoCloseableNoException;

 

 

 /**

@@ -40,7 +41,7 @@
  *      a) without count

  *      b) with count   

  */

-abstract class FSsTobeAddedback implements AutoCloseable {

+abstract class FSsTobeAddedback implements AutoCloseableNoException {

   

   final static boolean SHOW = false;

   final static AtomicInteger removes = new AtomicInteger(0);

@@ -48,6 +49,7 @@
   /**

    * does an add back if needed 

    */

+  @Override

   public void close() { addback();}

 

   protected void logPart(FSIndexRepository view) {

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureImpl.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureImpl.java
index 921254f..e5bf5bf 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureImpl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureImpl.java
@@ -26,6 +26,7 @@
 import org.apache.uima.cas.Type;
 import org.apache.uima.cas.TypeSystem;
 import org.apache.uima.cas.impl.SlotKinds.SlotKind;
+import org.apache.uima.internal.util.Misc;
 
 /**
  * The implementation of features in the type system.
@@ -51,7 +52,7 @@
    * true if the range is a long or double
    */
   public final boolean isLongOrDouble; 
-  private TypeImpl highestDefiningType;  // not final, could change
+  private final TypeImpl highestDefiningType;  // if changed, this feature is thrown away and a replacement is made
   
   private final TypeImpl rangeType;
   
@@ -71,35 +72,52 @@
   /** type class of the range, including CasSerializer List constants */
   public  final int rangeTypeClass; // set from CasSerializerSupport.classifyType
 
+  private final long hashCodeLong;
+
+  /**
+   * used to make singleton which is used for "missing feature"
+   */
   private FeatureImpl() {
-    featureCode = 0;
-    isInInt = false;
-    rangeType = null;
-    isMultipleRefsAllowed = false;
-    isAnnotBaseSofaRef = false;
-    shortName = null;
-    slotKind = null;
-    rangeTypeClass = 0;
-    isLongOrDouble = false;
+    this.featureCode = 0;
+    this.isInInt = false;
+    this.rangeType = null;
+    this.isMultipleRefsAllowed = false;
+    this.isAnnotBaseSofaRef = false;
+    this.shortName = null;
+    this.slotKind = null;
+    this.rangeTypeClass = 0;
+    this.isLongOrDouble = false;
+    this.highestDefiningType = null;
+    this.hashCodeLong = computeHashCodeLong();
   }
 
   FeatureImpl(TypeImpl typeImpl, String shortName, TypeImpl rangeType, TypeSystemImpl tsi, boolean isMultipleRefsAllowed, SlotKind slotKind) {
-//  this.code = code;
-  this.highestDefiningType = typeImpl;  
-  List<FeatureImpl> feats = tsi.features;
-  featureCode = feats.size();
-  
-  this.rangeType = rangeType;
-  this.isLongOrDouble = rangeType.isLongOrDouble;
-  this.slotKind = slotKind;
-  this.shortName = shortName;
-  this.isMultipleRefsAllowed = isMultipleRefsAllowed;
-  this.isAnnotBaseSofaRef = (highestDefiningType.getCode() == TypeSystemConstants.annotBaseTypeCode) && shortName.equals(CAS.FEATURE_BASE_NAME_SOFA);
-  this.isInInt = tsi.isInInt(rangeType);
-  this.rangeTypeClass = CasSerializerSupport.classifyType(rangeType);
-  typeImpl.addFeature(this);  // might throw if existing feature with different range
-  feats.add(this);
-}
+  //  this.code = code;
+    this.highestDefiningType = typeImpl;  
+    List<FeatureImpl> feats = (tsi == null) ? null : tsi.features;
+    this.featureCode = (feats == null) ? -1 : feats.size();
+    
+    this.rangeType = rangeType;
+    this.isLongOrDouble = (rangeType == null) ? false : rangeType.isLongOrDouble;
+    this.slotKind = slotKind;
+    this.shortName = shortName;
+    this.isMultipleRefsAllowed = isMultipleRefsAllowed;
+    this.isAnnotBaseSofaRef = (highestDefiningType == null) 
+                                ? false
+                                : ((highestDefiningType.getCode() == TypeSystemConstants.annotBaseTypeCode) && shortName.equals(CAS.FEATURE_BASE_NAME_SOFA));
+    this.isInInt = (rangeType == null) 
+                     ? false 
+                     : (rangeType.getTypeSystem().isInInt(rangeType));
+    this.rangeTypeClass = (rangeType == null) 
+                     ? CASImpl.TYPE_CLASS_FS
+                     : CasSerializerSupport.classifyType(rangeType);
+    this.hashCodeLong = computeHashCodeLong();
+    if (typeImpl != null) {
+      // if typeImpl is null, this is a "jcas only" defined feature, not a real feature
+      typeImpl.addFeature(this);  // might throw if existing feature with different range
+      feats.add(this);
+    }
+  }
 
   /**
    * @return the internal code of this feature. Necessary when using low-level APIs.
@@ -225,9 +243,9 @@
     return highestDefiningType;
   }
   
-  void setHighestDefiningType(Type type) {
-    highestDefiningType = (TypeImpl) type;
-  }
+//  void setHighestDefiningType(Type type) {
+//    highestDefiningType = (TypeImpl) type;
+//  }
 
   /**
    * throw if v is not in the allowed value set of the range type
@@ -237,28 +255,33 @@
     TypeImpl_stringSubtype ti = (TypeImpl_stringSubtype) getRangeImpl();
     ti.validateIsInAllowedValues(v);
   }
-  
-  /**
-   * Used by CAS Copier to denote missing feature
-   */
-  public final static FeatureImpl singleton = new FeatureImpl();
 
+  @Override
+  public int hashCode() {
+    return (int) hashCodeLong;
+  }
+  
+  public long hashCodeLong() {
+    return hashCodeLong;
+  }
+  
   /**
    * Hashcode and equals are used, possibly for features in different type systems, 
    * where the features should be "equal".  Example: fitering during serialization.
+   * @return long version of hashcode
    */
-  @Override
-  public int hashCode() {
-    final int prime = 31;
-    int result = 1;
-//    return this.featureCode;  // can't use this across different type systems
-    result = prime * result + ((highestDefiningType == null) ? 0 : highestDefiningType.getName().hashCode());
+ 
+  public long computeHashCodeLong() {
+    final long prime = 31;
+    long result;
+ //    return this.featureCode;  // can't use this across different type systems
+    result = prime          +  Misc.hashStringLong(shortName);
+    result = prime * result + ((highestDefiningType == null) ? 0 : highestDefiningType.hashCodeNameLong());
     result = prime * result + (isMultipleRefsAllowed ? 1231 : 1237);
-    result = prime * result + ((rangeType == null) ? 0 : rangeType.getName().hashCode());
-    result = prime * result + ((shortName == null) ? 0 : shortName.hashCode());
+    result = prime * result + ((rangeType == null) ? 0 : rangeType.hashCodeNameLong());
     return result;
   }
-
+  
   /**
    * This should work across different type systems, for instance 
    * when using filtered serialization
@@ -268,7 +291,11 @@
     if (this == o) {
       return 0;
     }    
+    
     FeatureImpl other = (FeatureImpl) o;
+    if (hashCodeLong == other.hashCodeLong) return 0;
+    
+    // to preserve the compare contract, can't use hash for miscompare
 
     int c;
     c = this.shortName.compareTo(other.shortName);
@@ -280,7 +307,7 @@
     c = rangeType.getName().compareTo(other.rangeType.getName());
     if (c != 0) return c;
 
-    return 0;
+    throw Misc.internalError();
   }
 
   @Override
@@ -291,12 +318,18 @@
     
     FeatureImpl other = (FeatureImpl) obj;
 //    return this.featureCode == other.featureCode;  // can't use this across different type systems
-    if (!highestDefiningType.getName().equals(other.highestDefiningType.getName())) return false;
-    if (isMultipleRefsAllowed != other.isMultipleRefsAllowed) return false;
-    if (!rangeType.getName().equals(other.rangeType.getName())) return false;
-    if (!shortName.equals(other.shortName)) return false;
-    return true;
+    return hashCodeLong == other.hashCodeLong;
+//    if (!highestDefiningType.getName().equals(other.highestDefiningType.getName())) return false;
+//    if (isMultipleRefsAllowed != other.isMultipleRefsAllowed) return false;
+//    if (!rangeType.getName().equals(other.rangeType.getName())) return false;
+//    if (!shortName.equals(other.shortName)) return false;
+//    return true;
   }
-  
+
+  /**
+   * Used by CAS Copier to denote missing feature
+   */
+  public final static FeatureImpl singleton = new FeatureImpl();
+
   
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureImpl_jcas_only.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureImpl_jcas_only.java
new file mode 100644
index 0000000..51a7a78
--- /dev/null
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureImpl_jcas_only.java
@@ -0,0 +1,47 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.cas.impl;

+

+/**

+ * The implementation of jcas-only features in the type system.

+ * JCas-only features are not real features in the type system, but are features inferred

+ *   by the existence of JCas class information

+ * They cannot be set or referenced, but exist in order to properly set up the

+ *   "offsets" for the JCas class, so that 

+ *   that same JCas class can be used with a different type system which **does** define that feature.

+ */

+public class FeatureImpl_jcas_only extends FeatureImpl {

+        

+  FeatureImpl_jcas_only(String shortName, TypeImpl rangeType) {

+    super(null, shortName, rangeType, null, false, null);

+  }

+

+  /* (non-Javadoc)

+   * @see java.lang.Object#toString()

+   */

+  @Override

+  public String toString() {

+    return String.format("FeatureImpl_jcas_only [%s, range:=%s]",

+        getShortName(), getRangeImpl());

+  }

+  

+  

+        

+}

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeaturePathImpl.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeaturePathImpl.java
index da0fd1f..1cb7f4c 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeaturePathImpl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeaturePathImpl.java
@@ -454,7 +454,6 @@
     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);
         
@@ -466,7 +465,6 @@
     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);
@@ -612,7 +610,6 @@
       case LowLevelCAS.TYPE_CLASS_FLOAT:      
       case LowLevelCAS.TYPE_CLASS_LONG:       
       case LowLevelCAS.TYPE_CLASS_SHORT:      
-      case LowLevelCAS.TYPE_CLASS_JAVAOBJECT: 
       case LowLevelCAS.TYPE_CLASS_INVALID:    
         return currentFs;  // is the fs which has the feature which is the primitive value
 
@@ -625,7 +622,6 @@
       case LowLevelCAS.TYPE_CLASS_LONGARRAY:
       case LowLevelCAS.TYPE_CLASS_SHORTARRAY:
       case LowLevelCAS.TYPE_CLASS_STRINGARRAY:
-      case LowLevelCAS.TYPE_CLASS_JAVAOBJECTARRAY:
         return currentFs.getFeatureValue(targetFeature);
 
       case LowLevelCAS.TYPE_CLASS_FS:
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureStructureImplC.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureStructureImplC.java
index 7fd49ec..0cc597c 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureStructureImplC.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureStructureImplC.java
@@ -19,13 +19,16 @@
 
 package org.apache.uima.cas.impl;
 
+import java.lang.invoke.MethodHandle;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
-import java.util.function.IntFunction;
+import java.util.function.IntConsumer;
 
 import org.apache.uima.UIMARuntimeException;
+import org.apache.uima.UIMA_IllegalStateException;
+import org.apache.uima.UimaSerializableFSs;
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASRuntimeException;
 import org.apache.uima.cas.CommonArrayFS;
@@ -33,9 +36,9 @@
 import org.apache.uima.cas.FeatureStructure;
 import org.apache.uima.cas.SofaFS;
 import org.apache.uima.cas.Type;
+import org.apache.uima.cas.TypeSystem;
 import org.apache.uima.cas.impl.SlotKinds.SlotKind;
 import org.apache.uima.internal.util.Misc;
-import org.apache.uima.internal.util.StringUtils;
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.cas.BooleanArray;
 import org.apache.uima.jcas.cas.ByteArray;
@@ -45,6 +48,7 @@
 import org.apache.uima.jcas.cas.IntegerArray;
 import org.apache.uima.jcas.cas.LongArray;
 import org.apache.uima.jcas.cas.ShortArray;
+import org.apache.uima.jcas.cas.Sofa;
 import org.apache.uima.jcas.cas.StringArray;
 import org.apache.uima.jcas.cas.TOP;
 import org.apache.uima.jcas.impl.JCasImpl;
@@ -78,6 +82,10 @@
   public static final String DISABLE_RUNTIME_FEATURE_VALUE_VALIDATION = "uima.disable_runtime_feature_value_validation";
   public static final boolean IS_ENABLE_RUNTIME_FEATURE_VALUE_VALIDATION  = !Misc.getNoValueSystemProperty(DISABLE_RUNTIME_FEATURE_VALUE_VALIDATION);
  
+  public static final String V2_PRETTY_PRINT = "uima.v2_pretty_print_format";
+  public static final boolean IS_V2_PRETTY_PRINT = // debug true || 
+                                                   Misc.getNoValueSystemProperty(V2_PRETTY_PRINT);
+  
   private  static final boolean traceFSs = CASImpl.traceFSs;
     
   // next is for experiment (Not implemented) of allocating multiple int arrays for different fss
@@ -216,7 +224,7 @@
     if (null == _typeImpl) {
       throw new CASRuntimeException(CASRuntimeException.JCAS_TYPE_NOT_IN_CAS, this.getClass().getName());
     }
-
+    
     if (_casView.maybeMakeBaseVersionForPear(this, _typeImpl)) {
       _setPearTrampoline();
     }
@@ -399,8 +407,17 @@
    *          For JCas setters: convert offset to feature
    **************************************/
   
+  private void checkFeatRange(Feature feat, String shortRangeName) {
+    if ( ! (feat.getRange().getShortName().equals(shortRangeName))) {
+      /*Trying to access value of feature "{0}" as "{1}", but range of feature is "{2}".*/
+      throw new CASRuntimeException(CASRuntimeException.INAPPROP_RANGE, feat.getName(), "uima.cas." + shortRangeName, feat.getRange().getName());
+    }
+
+  }
+  
   @Override
   public void setBooleanValue(Feature feat, boolean v) {
+   checkFeatRange(feat, "Boolean");
     _setIntValueCJ((FeatureImpl) feat, v ? 1 : 0);
   }
   
@@ -412,6 +429,7 @@
  
   @Override
   public void setByteValue(Feature feat, byte v) {
+    checkFeatRange(feat, "Byte");
     _setIntValueCJ((FeatureImpl) feat, v);
   }
   
@@ -429,6 +447,7 @@
 
   @Override
   public void setShortValue(Feature feat, short v) {
+    checkFeatRange(feat, "Short");
     _setIntValueCJ((FeatureImpl) feat, v);
   }
   
@@ -446,6 +465,7 @@
 
   @Override
   public void setIntValue(Feature feat, int v) {
+    checkFeatRange(feat, "Integer");
     _setIntValueCJ((FeatureImpl) feat, v);
   }
   
@@ -463,6 +483,7 @@
 
   @Override
   public void setLongValue(Feature feat, long v) {
+    checkFeatRange(feat, "Long");
     _setLongValueCJ((FeatureImpl) feat, v);
   }
 
@@ -483,7 +504,10 @@
   }
 
   @Override
-  public void setFloatValue(Feature feat, float v) { setIntValue(feat, CASImpl.float2int(v)); }
+  public void setFloatValue(Feature feat, float v) {
+    checkFeatRange(feat, "Float");
+    _setIntValueCJ((FeatureImpl) feat, CASImpl.float2int(v));
+  }
   
   protected void _setFloatValueNfc(int adjOffset, float v) { _setIntValueNfc(adjOffset, CASImpl.float2int(v)); }
 
@@ -499,7 +523,8 @@
 
   @Override
   public void setDoubleValue(Feature feat, double v) {
-    setLongValue(feat, CASImpl.double2long(v)); 
+    checkFeatRange(feat, "Double");
+    _setLongValueCJ((FeatureImpl) feat, CASImpl.double2long(v));
   }
 
   protected void _setDoubleValueNfc(int adjOffset, double v) {
@@ -518,7 +543,7 @@
   public void setStringValue(Feature feat, String v) {
 //    if (IS_ENABLE_RUNTIME_FEATURE_VALIDATION) featureValidation(feat);  // done by _setRefValueCJ
 //    if (IS_ENABLE_RUNTIME_FEATURE_VALUE_VALIDATION) featureValueValidation(feat, v); // verifies feat can take a string
-    subStringRangeCheck(feat, v);
+    subStringRangeCheck(feat, v);  
     _setRefValueCJ((FeatureImpl) feat, v);
   }
   
@@ -547,8 +572,7 @@
     FeatureImpl fi = (FeatureImpl) feat;
     if (IS_ENABLE_RUNTIME_FEATURE_VALIDATION) featureValidation(feat);
     if (IS_ENABLE_RUNTIME_FEATURE_VALUE_VALIDATION) featureValueValidation(feat, v);
-
-    // no need to check for index corruption because fs refs can't be index keys
+     // no need to check for index corruption because fs refs can't be index keys
     _setRefValueCommon(fi, _maybeGetBaseForPearFs((TOP)v));
     _casView.maybeLogUpdate(this, fi);
   }
@@ -632,7 +656,7 @@
   @Override
   public void setFeatureValueFromString(Feature feat, String s) throws CASRuntimeException {
     if (IS_ENABLE_RUNTIME_FEATURE_VALIDATION) featureValidation(feat);
-    _casView.setFeatureValueFromString(this, (FeatureImpl) feat, s);
+    CASImpl.setFeatureValueFromString(this, (FeatureImpl) feat, s);
   }
 
   /**
@@ -718,6 +742,7 @@
   @Override
   public boolean getBooleanValue(Feature feat) {
     if (IS_ENABLE_RUNTIME_FEATURE_VALIDATION) featureValidation(feat);
+    checkFeatRange(feat, "Boolean");
     return _getBooleanValueNc((FeatureImpl) feat);
   }
 
@@ -727,14 +752,18 @@
   public boolean _getBooleanValueNc(int adjOffset) { return _getIntValueCommon(adjOffset) == 1; }
 
   @Override
-  public byte getByteValue(Feature feat) { return (byte) getIntValue(feat); }
+  public byte getByteValue(Feature feat) {
+    checkFeatRange(feat, "Byte");
+    return (byte) _getIntValueCommon((FeatureImpl)feat); }
 
   public byte _getByteValueNc(FeatureImpl feat) { return (byte) _getIntValueNc(feat); }
   
   public byte _getByteValueNc(int adjOffset) { return  (byte) _getIntValueNc(adjOffset); }
 
   @Override
-  public short getShortValue(Feature feat) { return (short) getIntValue(feat); }
+  public short getShortValue(Feature feat) {
+    checkFeatRange(feat, "Short");
+    return (short) _getIntValueCommon((FeatureImpl)feat); }
 
   public short _getShortValueNc(FeatureImpl feat) { return (short) _getIntValueNc(feat); }
 
@@ -743,6 +772,7 @@
   @Override
   public int getIntValue(Feature feat) {
     if (IS_ENABLE_RUNTIME_FEATURE_VALIDATION) featureValidation(feat);
+    checkFeatRange(feat, "Integer");
     return _getIntValueCommon((FeatureImpl)feat);
   }
     
@@ -754,6 +784,7 @@
   @Override
   public long getLongValue(Feature feat) {
     if (IS_ENABLE_RUNTIME_FEATURE_VALIDATION) featureValidation(feat);
+    checkFeatRange(feat, "Long");
     return _getLongValueNc((FeatureImpl) feat);
   }
   
@@ -772,6 +803,7 @@
   @Override
   public float getFloatValue(Feature feat) {
     if (IS_ENABLE_RUNTIME_FEATURE_VALIDATION) featureValidation(feat);
+    checkFeatRange(feat, "Float");
     return _getFloatValueNc(((FeatureImpl) feat).getAdjustedOffset());
   }
 
@@ -782,6 +814,7 @@
   @Override
   public double getDoubleValue(Feature feat) {
     if (IS_ENABLE_RUNTIME_FEATURE_VALIDATION) featureValidation(feat);
+    checkFeatRange(feat, "Double");
     return _getDoubleValueNc((FeatureImpl) feat); 
   }
   
@@ -792,6 +825,7 @@
   @Override
   public String getStringValue(Feature feat) {
     if (IS_ENABLE_RUNTIME_FEATURE_VALIDATION) featureValidation(feat);
+//    checkFeatRange(feat, "String");
     return _getStringValueNc((FeatureImpl) feat);
   }
 
@@ -883,6 +917,39 @@
   public int hashCode() {
     return _id;
   }
+  
+  
+
+  /* (non-Javadoc)
+   * @see java.lang.Object#equals(java.lang.Object)
+   * must match hashCode
+   * must match comparator == 0, equal == true
+   * Only valid for FSs in same CAS
+   */
+  @Override
+  public boolean equals(Object obj) {
+    if (obj instanceof FeatureStructureImplC) {
+      FeatureStructureImplC c2 = (FeatureStructureImplC) obj;
+      
+      if (c2._id != this._id) return false;
+
+      return (_casView == null && c2._casView == null) ||
+             (_casView != null && c2._casView != null &&   
+              (_casView == c2._casView || _casView.getBaseCAS() == c2._casView.getBaseCAS()));
+      
+//      if (_casView == null && c2._casView == null) {
+//        return true;  // special case for removed marker
+//      }
+//      if (_casView != null && c2._casView != null &&   
+//           (_casView == c2._casView ||
+//            _casView.getBaseCAS() == c2._casView.getBaseCAS())) {
+//        return true;
+//      }
+    }
+//        throw new IllegalArgumentException("Can't invoke equals on two FS from different CASes.");
+    return false;
+  }
+
 
   // ///////////////////////////////////////////////////////////////////////////
   // Pretty printing.
@@ -951,6 +1018,14 @@
     getPrintRefs(printRefs, this);
   }
 
+  /**
+   * This is called, once, at the top level thing being printed.
+   * It recursively descends any references, and updates the
+   * PrintReferences with info needed to handle circular structures 
+   * 
+   * @param printRefs the PrintReferences to update
+   * @param fs the top level FS being pretty printed, to descend if needed
+   */
   private final void getPrintRefs(PrintReferences printRefs, FeatureStructureImplC fs) {
     if (null == fs) {
       return;
@@ -962,11 +1037,15 @@
     
     final TypeImpl ti = fs._typeImpl;
     if (ti != null) { // null for REMOVED marker
-      if (ti.isArray() && (fs instanceof FSArray)) {
+      // for v2 style, don't descend fs arrays; these are omitted
+      if (!IS_V2_PRETTY_PRINT && ti.isArray() && (fs instanceof FSArray)) {
         for (TOP item : ((FSArray)fs)._getTheArray()) {
           getPrintRefs(printRefs, item);
         }
       } else {
+        if (fs instanceof UimaSerializableFSs) {
+          ((UimaSerializableFSs)fs)._save_fsRefs_to_cas_data();
+        }
         ti.getFeaturesAsStream()
           .filter(fi -> fi.getRangeImpl().isRefType)     // is ref type
           .map(fi -> fs.getFeatureValue(fi)) // get the feature value
@@ -1004,6 +1083,18 @@
     prettyPrint(indent, incr, buf, useShortNames, null);
   }
 
+  /**
+   * Top level, does computation of self-ref
+   * Pretty prints this Feature Structure, no trailing nl
+   * Old form - uses string buffer.
+   * @param indent the indent amount
+   * @param incr the amount the indent is increased for a level
+   * @param buf where the resulting string is built
+   * @param useShortNames true to use short name
+   * @param s extra string to print
+   * @deprecated use form with StringBuilder (not StringBuffer)
+   */
+  @Deprecated
   @Override
   public void prettyPrint(int indent, int incr, StringBuffer buf, boolean useShortNames, String s) {
     PrintReferences printRefs = new PrintReferences();
@@ -1011,16 +1102,25 @@
     prettyPrint(indent, incr, buf, useShortNames, s, printRefs);
   }
   
+  /**
+   * Top level, does computation of self-ref
+   * Pretty prints this Feature Structure, no trailing nl
+   * @param indent the indent amount
+   * @param incr the amount the indent is increased for a level
+   * @param buf where the resulting string is built
+   * @param useShortNames true to use short name
+   * @param s extra string to print
+   */
   @Override
   public void prettyPrint(int indent, int incr, StringBuilder buf, boolean useShortNames, String s) {
     PrintReferences printRefs = new PrintReferences();
     getPrintRefs(printRefs);
-    prettyPrint(indent, incr, buf, useShortNames, s, printRefs);
+    prettyPrint(indent, incr, buf, useShortNames, s, printRefs);    
   }
 
   // old version from v2 using StringBuffer
   /**
-   * 
+   * Internal Use Only, public only for backwards compatibility
    * @param indent -
    * @param incr -
    * @param buf -
@@ -1029,6 +1129,7 @@
    * @param printRefs -
    * @deprecated because uses StringBuffer, not builder, for version 2 compatibility only
    */
+  @Deprecated
   public void prettyPrint(
       int indent, 
       int incr, 
@@ -1045,18 +1146,58 @@
   }
   
   public void prettyPrint(
-      int indent, 
-      int incr, 
+      int indent,  // the current indent position
+      int incr,    // the delta to indent this FS printing
       StringBuilder buf, 
       boolean useShortNames, 
-      String s, 
+      String s, // carries the "#123" id refs for others to use, labels this fs with that.
       PrintReferences printRefs) {
+    prettyPrint(indent, incr, buf, useShortNames, s, printRefs, false);
+  }
+  
+  /**
+   * 
+   * @param sb -
+   */
+  public void prettyPrintShort(StringBuilder sb) {
+    prettyPrint(0, 2, sb, true, "", new PrintReferences(), true);
+  }
+  
+  /**
+   * recursively called by ppval
+   * @param indent -
+   * @param incr -
+   * @param buf -
+   * @param useShortNames -
+   * @param s -
+   * @param printRefs -
+   * @param isShortForm_arg -
+   */
+  private void prettyPrint(
+      int indent,  // the current indent position
+      int incr,    // the delta to indent this FS printing
+      final StringBuilder buf, 
+      boolean useShortNames, 
+      String s, // carries the "#123" id refs for others to use, labels this fs with that.
+      PrintReferences printRefs,
+      boolean isShortForm_arg) {  // short form only prints type:_id for refs
+    
+
+    final boolean isShortForm = 
+//        isShortForm_arg;
+        // debug
+//        (this._id == 2512)
+//          ? false
+//          : 
+            isShortForm_arg;
+    
     try {
     indent += incr;
-    if (indent > 20) {
-      buf.append(" ... past indent 20 ... ");
+    if (!IS_V2_PRETTY_PRINT && indent > 20 * incr) {
+      buf.append(" ... past indent limit ... ");
       return;
     }
+      
     final int printInfo = printRefs.printInfo(this);
     if (printInfo != PrintReferences.NO_LABEL) {
       String label = printRefs.getLabel(this);
@@ -1064,7 +1205,7 @@
         buf.append(printRefs.getLabel(this));
       }
       if (printInfo == PrintReferences.JUST_LABEL) {
-        buf.append('\n');
+        buf.append(IS_V2_PRETTY_PRINT ? ' ' : '\n');  
         return;
       }
       buf.append(' ');
@@ -1081,7 +1222,11 @@
       } else {
         buf.append(getType().getName());
       }
-      buf.append(':').append(_id);
+      
+      if (!IS_V2_PRETTY_PRINT) {
+        buf.append(':').append(_id);
+      }
+      
       if (s != null) {
         buf.append(" \"" + s + "\"");
       }
@@ -1096,80 +1241,108 @@
     switch (_getTypeCode()) {
     case TypeSystemConstants.stringArrayTypeCode: {
       StringArray a = (StringArray) this;
-      printArrayElements(a.size(), i -> a.get(i), indent, buf);
+      printArrayElements(a.size(), i -> appendOrNull(buf, a.get(i)), indent, incr, buf);
       return;
     }
     case TypeSystemConstants.intArrayTypeCode: {
       IntegerArray a = (IntegerArray) this;
-      printArrayElements(a.size(), i -> Integer.toString(a.get(i)), indent, buf);
+      printArrayElements(a.size(), i -> appendOrNull(buf, Integer.toString(a.get(i))), indent, incr, buf);
       return;
     }
     case TypeSystemConstants.floatArrayTypeCode: {
       FloatArray a = (FloatArray) this;
-      printArrayElements(a.size(), i -> Float.toString(a.get(i)), indent, buf);
+      printArrayElements(a.size(), i -> appendOrNull(buf, Float.toString(a.get(i))), indent, incr, buf);
       return;
     }
     case TypeSystemConstants.booleanArrayTypeCode: {
       BooleanArray a = (BooleanArray) this;
-      printArrayElements(a.size(), i -> Boolean.toString(a.get(i)), indent, buf);
+      printArrayElements(a.size(), i -> appendOrNull(buf, Boolean.toString(a.get(i))), indent, incr, buf);
       return;
     }
     case TypeSystemConstants.byteArrayTypeCode: {
       ByteArray a = (ByteArray) this;
-      printArrayElements(a.size(), i -> Byte.toString(a.get(i)), indent, buf);
+      printArrayElements(a.size(), i -> appendOrNull(buf, Byte.toString(a.get(i))), indent, incr, buf);
       return;
     }
     case TypeSystemConstants.shortArrayTypeCode: {
       ShortArray a = (ShortArray) this;
-      printArrayElements(a.size(), i -> Short.toString(a.get(i)), indent, buf);
+      printArrayElements(a.size(), i -> appendOrNull(buf, Short.toString(a.get(i))), indent, incr, buf);
       return;
     }
     case TypeSystemConstants.longArrayTypeCode: {
       LongArray a = (LongArray) this;
-      printArrayElements(a.size(), i -> Long.toString(a.get(i)), indent, buf);
+      printArrayElements(a.size(), i -> appendOrNull(buf, Long.toString(a.get(i))), indent, incr, buf);
       return;
     }
     case TypeSystemConstants.doubleArrayTypeCode: {
       DoubleArray a = (DoubleArray) this;
-      printArrayElements(a.size(), i -> Double.toString(a.get(i)), indent, buf);
+      printArrayElements(a.size(), i -> appendOrNull(buf, Double.toString(a.get(i))), indent, incr, buf);
       return;
     }
-    }    
+    case TypeSystemConstants.fsArrayTypeCode: {
+      if (IS_V2_PRETTY_PRINT) {
+        break;  // v2 did not descend to print FSArray contents
+      }
+      FSArray a = (FSArray) this;
+      printFSArrayElements(a, indent, incr, buf, useShortNames, printRefs, isShortForm);
+      
+      return;
+    }  // end of case
+    
+    }  // end of switch
+
+    // if get here, non of the cases in the above switch fit
+    
+    if (this instanceof FSArray) {  // catches instance of FSArrays which are "typed" to hold specific element types
+      if (IS_V2_PRETTY_PRINT) {
+        return; // v2 did not descend to print fs array contents
+      }
+      FSArray a = (FSArray) this;
+      printFSArrayElements(a, indent, incr, buf, useShortNames, printRefs, isShortForm);
+      return;
+    }
     
     for (FeatureImpl fi : _typeImpl.getFeatureImpls()) {
-      StringUtils.printSpaces(indent, buf);
+      Misc.indent(buf, indent);
       buf.append(fi.getShortName() + ": ");
       TypeImpl range = (TypeImpl) fi.getRange();
-      
-      if (range.isStringOrStringSubtype()) {
-        String stringVal = getStringValue(fi);
-        stringVal = (null == stringVal) ? "<null>" : "\"" + Misc.elideString(stringVal, 15) + "\"";
-        buf.append(stringVal + '\n');
+      if (range.isPrimitive()) {  // Strings and string subtypes are primitive
+        addStringOrPrimitive(buf, fi);
         continue;
       }
       
-      if (!range.isPrimitive()) {   
-        // not primitive
-        FeatureStructureImplC val = null;
-        boolean hadException = false;
-        try {
-          val = getFeatureValue(fi);
-        } catch (Exception e) {
-          buf.append("<exception ").append(e.getMessage()).append(">\n");
-          hadException = true;
-        }
-        if (!hadException) {
-          if (val != null && !val._typeImpl.getName().equals(CAS.TYPE_NAME_SOFA)) {
-            val.prettyPrint(indent, incr, buf, useShortNames, null, printRefs);
+      // not primitive
+      FeatureStructureImplC val = null;
+      boolean hadException = false;
+      try {
+        val = getFeatureValue(fi);
+      } catch (Exception e) {
+        buf.append("<exception ").append(e.getMessage()).append(">\n");
+        hadException = true;
+      }
+      if (!hadException) {
+        if (isShortForm) {
+          if (null == val) {
+            buf.append("<null>");
           } else {
-            buf.append((val == null) ? "<null>\n" : ((SofaFS) val).getSofaID() + '\n'); 
+            buf.append(val._getTypeImpl().getShortName()).append(':').append(val._id);
+          }
+        } else {
+          // treat sofa refs special, since they're pervasive
+          if (val instanceof Sofa) {
+            buf.append(((Sofa)val).getSofaID());
+          } else {
+            ppval(val, indent, incr, buf, useShortNames, printRefs, false);
           }
         }
-    
-      } else {  
-        // is primitive
-        buf.append(this.getFeatureValueAsString(fi) + "\n");
+        
+//          if (val != null && !val._typeImpl.getName().equals(CAS.TYPE_NAME_SOFA)) {
+//            val.prettyPrint(indent, incr, buf, useShortNames, null, printRefs);
+//          } else {
+//            buf.append((val == null) ? "<null>\n" : ((SofaFS) val).getSofaID() + '\n'); 
+//          }
       }
+    
     }
     } catch (Exception e) {
       buf.append("**Caught exception: ").append(e);
@@ -1178,32 +1351,106 @@
 //      buf.append(sw.toString());
     }    
   }
-
-  private void printArrayElements(int arrayLen, IntFunction<String> f, int indent, StringBuilder buf) {
-    StringUtils.printSpaces(indent, buf);
-    buf.append("Array length: " + arrayLen + "\n");
-    if (arrayLen > 0) {
-      StringUtils.printSpaces(indent, buf);
-      buf.append("Array elements: [");
-      int numToPrint = Math.min(15, arrayLen);  // print 15 or fewer elements
-
-      for (int i = 0; i < numToPrint; i++) {
-        if (i > 0) {
-          buf.append(", ");
-        }
-        String element = f.apply(i); //this._casView.ll_getStringArrayValue(this.getAddress(), i);
-        if (null == element) {
-          buf.append("null");
-        } else {
-          buf.append("\"" + Misc.elideString(element, 15) + "\"");
-        }
-      }
-      
-      if (arrayLen > numToPrint) {
-        buf.append(", ...");
-      }
-      buf.append("]\n");
+  
+  public StringBuilder addStringOrPrimitive(StringBuilder sb, FeatureImpl fi) {
+    TypeImpl range = (TypeImpl) fi.getRange();
+    
+    if (range.isStringOrStringSubtype()) {
+      String stringVal = getStringValue(fi);
+      stringVal = (null == stringVal) ? "<null>" : "\"" + Misc.elideString(stringVal, 80) + "\"";
+      sb.append(stringVal);  // caller adds nl
+    } else {
+      sb.append(this.getFeatureValueAsString(fi));
     }
+    return sb;
+  }
+  
+  private void ppval(FeatureStructureImplC val, 
+                     int indent, 
+                     int incr, 
+                     StringBuilder buf, 
+                     boolean useShortNames, 
+                     PrintReferences printRefs,
+                     boolean isShortForm) {
+    if (val != null && !val._typeImpl.getName().equals(CAS.TYPE_NAME_SOFA)) {
+      val.prettyPrint(indent, incr, buf, useShortNames, null, printRefs, isShortForm);
+    } else {
+      buf.append((val == null) ? "<null>" : "sofa id: " +((SofaFS) val).getSofaID()); 
+    }    
+  }
+  
+  /**
+   * For printing arrays except FSArrays; called after printing the type:nnn
+   *   prints the length
+   *   if the length = 0 that's all
+   *   otherwise:
+   *   uses Misc.addElementsToStringBuilder to output the elements.  This routine does
+   *       [ + array contents + ], unless the line is too long, in which case it switches to multi-line
+   * @param arrayLen the length
+   * @param f the feature structure
+   * @param indent the current indent
+   * @param incr the indent incr
+   * @param buf the stringbuilder where the result is added
+   */
+  private void printArrayElements(int arrayLen, IntConsumer f, int indent, int incr, StringBuilder buf) {
+    Misc.indent(buf, indent);
+    buf.append("Array length: " + arrayLen);
+    if (arrayLen == 0) {
+      return;
+    }
+
+    Misc.indent(buf, indent);
+    buf.append("Array elements: ");
+    if (IS_V2_PRETTY_PRINT) {
+      buf.append("[");
+      for (int i = 0; i < arrayLen; i++) {
+        if (i > 0) {
+            buf.append(", ");
+        }
+        f.accept(i); //this._casView.ll_getStringArrayValue(this.getAddress(), i);
+      }
+      buf.append("]");  // no extra new line
+    } else {
+      // no limit to size
+      Misc.addElementsToStringBuilder(buf, arrayLen, arrayLen, indent, incr, (sb, i) -> f.accept(i));
+    }
+  }
+  
+  /**
+   * For printing FSArrays; called after printing the type:nnn
+   * Only called if ! IS_V2_PRETTY_PRINT, since v2 didn't print the array contents
+   *   prints the length
+   *   if the length = 0 that's all
+   *   otherwise:
+   *   
+   * @param arrayLen the length
+   * @param f the feature structure
+   * @param indent the current indent
+   * @param incr the indent incr
+   * @param buf the stringbuilder where the result is added
+   */
+  private void printFSArrayElements(FSArray fsarray, int indent, int incr, StringBuilder buf, boolean useShortNames, PrintReferences printRefs, boolean isShortForm) {
+    Misc.indent(buf, indent);
+    int arraylen = fsarray.size();
+    buf.append("Array length: " + arraylen);
+    if (arraylen == 0) {
+      return;
+    }
+
+    Misc.indent(buf, indent);
+    buf.append("Array elements: [");
+    
+    indent += incr;
+    for (int i = 0; i < arraylen; i++) {
+      Misc.indent(buf, indent);
+      ppval(fsarray.get(i), indent, incr, buf, useShortNames, printRefs, isShortForm);
+    }
+    Misc.indent(buf, indent - incr);
+    buf.append(']');
+  }
+ 
+  private void appendOrNull(StringBuilder sb, String v) {
+    sb.append( (v == null) ? "null" : v);
   }
   
   public int getTypeIndexID() {
@@ -1308,7 +1555,11 @@
         return Long.toString(getLongValue(feat));
       case TypeSystemConstants.doubleTypeCode :
         return Double.toString(getDoubleValue(feat));
-      default: // byte, short, int, 
+      case TypeSystemConstants.byteTypeCode:
+        return Byte.toString(getByteValue(feat));
+      case TypeSystemConstants.shortTypeCode:
+        return Short.toString(getShortValue(feat));
+      default: // int, 
         return Integer.toString(getIntValue(feat));
       }
     }
@@ -1555,16 +1806,25 @@
 //    _flags = (_flags & ~bitMaskRefOffset) | v << shiftRefOffset;
 //  }
 
-  public TypeImpl _getTypeImpl() {
+  public final TypeImpl _getTypeImpl() {
     return _typeImpl;
   }
   
-  protected void _setTypeImpl(TypeImpl ti) {
+  protected final void _setTypeImpl(TypeImpl ti) {
     _typeImpl = ti;
   }
   
   public static int compare(FeatureStructureImplC a, FeatureStructureImplC b) {
     return Integer.compare(a._id, b._id);
   }
+  
+  protected final static int wrapGetIntCatchException(MethodHandle mh) {
+    try {
+      return (int) mh.invokeExact();
+    } catch(Throwable t) {
+      throw new UIMA_IllegalStateException(UIMA_IllegalStateException.JCAS_NO_TYPE, null, t);
+    }
+  }
+
 
 }
\ No newline at end of file
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FilteredIterator.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FilteredIterator.java
index 9916fbb..0e648ae 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FilteredIterator.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FilteredIterator.java
@@ -19,19 +19,21 @@
 
 package org.apache.uima.cas.impl;
 
+import java.util.Comparator;
 import java.util.NoSuchElementException;
 
 import org.apache.uima.cas.FSIterator;
 import org.apache.uima.cas.FSMatchConstraint;
 import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.jcas.cas.TOP;
 
 /**
  * Implements a filtered iterator.
  */
-class FilteredIterator<T extends FeatureStructure> implements FSIterator<T> {
+class FilteredIterator<T extends FeatureStructure> implements LowLevelIterator<T> {
 
   // The base iterator.
-  private FSIterator<T> it;
+  private LowLevelIterator<T> it;
 
   // The filter constraint.
   private FSMatchConstraint cons;
@@ -46,7 +48,7 @@
    */
   FilteredIterator(FSIterator<T> it, FSMatchConstraint cons) {
     this();
-    this.it = it;
+    this.it = (LowLevelIterator<T>) it;
     this.cons = cons;
     moveToFirst();
   }
@@ -74,41 +76,26 @@
   }
   
 
-  public void moveToFirst() {
-    this.it.moveToFirst();
+  public void moveToFirstNoReinit() {
+    this.it.moveToFirstNoReinit();
     adjustForConstraintForward();
   }
 
-  public void moveToLast() {
+  public void moveToLastNoReinit() {
     this.it.moveToLast();
     adjustForConstraintBackward();
   }
 
-  public void moveToNext() {
-    this.it.moveToNext();
-    adjustForConstraintForward();
-  }
-
   public void moveToNextNvc() {
     this.it.moveToNextNvc();
     adjustForConstraintForward();
   }
 
-  public void moveToPrevious() {
-    this.it.moveToPrevious();
-    adjustForConstraintBackward();
-  }
-
   public void moveToPreviousNvc() {
     this.it.moveToPreviousNvc();
     adjustForConstraintBackward();
   }
 
-  public T get() throws NoSuchElementException {
-    // This may throw an exception.
-    return this.it.get();
-  }
-
   public T getNvc() {
     return this.it.getNvc();
   }
@@ -123,10 +110,47 @@
   /**
    * @see org.apache.uima.cas.FSIterator#moveTo(FeatureStructure)
    */
-  public void moveTo(FeatureStructure fs) {
-    this.it.moveTo(fs);
+  public void moveToNoReinit(FeatureStructure fs) {
+    this.it.moveToNoReinit(fs);
     adjustForConstraintForward();
   }
+  
+//  @Override
+//  public void moveToExactNoReinit(FeatureStructure fs) {
+//    this.it.moveToExactNoReinit(fs);
+//    adjustForConstraintForward();
+//  }
+
+
+  @Override
+  public int ll_indexSizeMaybeNotCurrent() {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public LowLevelIndex<T> ll_getIndex() {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public int ll_maxAnnotSpan() {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public boolean isIndexesHaveBeenUpdated() {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public boolean maybeReinitIterator() {
+    return this.it.maybeReinitIterator();
+  }
+
+  @Override
+  public Comparator<TOP> getComparator() {
+    return it.getComparator();
+  }
 
 //  /* (non-Javadoc)
 //   * @see org.apache.uima.cas.impl.FSIteratorImplBase#moveTo(java.util.Comparator)
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FloatConstraint.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FloatConstraint.java
index ee79f87..7d92fc7 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FloatConstraint.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FloatConstraint.java
@@ -43,6 +43,7 @@
     this.floatConstraint = cons;
   }
 
+  @Override
   public boolean match(FeatureStructure fs) {
     // compile(((FeatureStructureImpl) fs).getCAS().getTypeSystem());
     final int max = this.featNames.size() - 1; // The last position in the
@@ -67,6 +68,7 @@
     return this.floatConstraint.match(fs.getFloatValue(feat));
   }
 
+  @Override
   public String toString() {
     return super.toString() + " " + this.floatConstraint.toString();
   }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_annotation.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_annotation.java
index e69d0f8..198b1f3 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_annotation.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_annotation.java
@@ -21,8 +21,6 @@
 

 import org.apache.uima.cas.FSIndex;

 import org.apache.uima.cas.FSIterator;

-import org.apache.uima.cas.FeatureStructure;

-import org.apache.uima.cas.SelectFSs;

 import org.apache.uima.cas.impl.Subiterator.BoundsUse;

 import org.apache.uima.cas.text.AnnotationFS;

 import org.apache.uima.cas.text.AnnotationIndex;

@@ -48,23 +46,41 @@
    * @see org.apache.uima.cas.text.AnnotationIndex#iterator(boolean)

    */

   @Override

-  public FSIterator<T> iterator(boolean ambiguous) {

+  public LowLevelIterator<T> iterator(boolean ambiguous) {

     if (ambiguous) {

       return iterator();

     }

     // return non-constrained, non-strict, unambiguous iterator

     boolean strict = false;  // https://issues.apache.org/jira/browse/UIMA-5063

-    boolean isBounded = false;

     return new Subiterator<T>(iterator(), 

                               null, 

                               ambiguous, 

                               strict, 

                               null, // no BoundsUse

                               true, // type priority used

-                              true, // ignored

-                              true, // ignored

-                              

-                              this.getFsRepositoryImpl().getAnnotationFsComparator()

+                              true // ignored

+                             ); 

+  }

+  

+  /**

+   * @param ambiguous false for unambiguous

+   * @param strict true for strict

+   * @param orderNotNeeded true for unordered

+   * @param ignoreType -

+   * @return - 

+   */

+  public LowLevelIterator<T> iterator(boolean ambiguous, boolean strict, boolean orderNotNeeded, boolean ignoreType) {

+    if (ambiguous) {

+      return iterator(orderNotNeeded, ignoreType);

+    }

+    // return non-constrained, non-strict, unambiguous iterator

+    return new Subiterator<T>(iterator(orderNotNeeded, ignoreType), 

+                              null,   // no bounding fs

+                              ambiguous, 

+                              strict, 

+                              null, // no BoundsUse

+                              ! ignoreType, // type priority used

+                              true // ignored - only for coveredBy or covering

                              ); 

   }

 

@@ -92,9 +108,7 @@
         strict, 

         BoundsUse.coveredBy,  // isBounded 

         true,  // uses type priority

-        true,  // position uses type - ignored

-        true,  // skip returning results equal to annot

-        this.getFsRepositoryImpl().getAnnotationFsComparator()

+        true  // skip returning results equal to annot

         );

   }

 

@@ -127,7 +141,9 @@
 

   @Override

   public FSIndex<T> withSnapshotIterators() {

-    return new FsIndex_snapshot<>(this);

+    FsIndex_singletype<T> idx = getFsIndex_singleType();

+    return new FsIndex_snapshot<>(this, idx.comparatorWithoutID, 

+                                        idx.comparatorNoTypeWithoutID);

   }

   

  }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_bag.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_bag.java
index f3c8c9a..69ce294 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_bag.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_bag.java
@@ -22,7 +22,6 @@
 import java.util.Collection;
 import java.util.List;
 
-import org.apache.uima.cas.FSIterator;
 import org.apache.uima.cas.FeatureStructure;
 import org.apache.uima.cas.Type;
 import org.apache.uima.cas.admin.FSIndexComparator;
@@ -198,19 +197,20 @@
   @Override
   protected void bulkAddTo(List<T> fss) {
     fss.addAll((Collection<? extends T>) this.index);
-  }
+  }  
   
   /* (non-Javadoc)
-   * @see org.apache.uima.cas.FSIndex#iterator()
+   * @see org.apache.uima.cas.impl.FsIndex_singletype#iterator(boolean, boolean)
+   *   both orderNotNeeded and ignoreType are ignored for bag indexes.
    */
   @Override
-  public FSIterator<T> iterator() {
-    setupIteratorCopyOnWrite();
+  public LowLevelIterator<T> iterator(boolean orderNotNeeded, boolean ignoreType) {
+    CopyOnWriteIndexPart cow_index_wrapper = getNonNullCow();
     return casImpl.inPearContext()
-             ? new FsIterator_bag_pear<>(this, type)
-             : new FsIterator_bag     <>(this, type);
+             ? new FsIterator_bag_pear<>(this, type, cow_index_wrapper)
+             : new FsIterator_bag     <>(this, type, cow_index_wrapper);
   }
-  
+
   @Override
   protected CopyOnWriteIndexPart createCopyOnWriteIndexPart() {
     if (CASImpl.traceCow) {
@@ -224,6 +224,11 @@
     return Integer.MAX_VALUE;
   }
   
+  @Override
+  public LowLevelIterator<T> iterator() {
+    return iterator(!IS_ORDERED, !IS_TYPE_ORDER);
+  }
+
 //  ObjHashSet<TOP> getObjHashSet() {
 //    return index;
 //  } 
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_flat.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_flat.java
index d498c74..cfacab8 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_flat.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_flat.java
@@ -30,30 +30,35 @@
 import org.apache.uima.cas.FeatureStructure;

 import org.apache.uima.internal.util.IntVector;

 import org.apache.uima.internal.util.Misc;

+import org.apache.uima.jcas.cas.TOP;

 

 /**

  * Common part of flattened indexes, used for both snapshot iterators and 

  * flattened sorted indexes

+ * 

+ * built from passed in instance of FsIndex_iicp

  *  

  * @param <T> the Java class type for this index

  */

 public class FsIndex_flat<T extends FeatureStructure> extends FsIndex_singletype<T> {

-

+  

   // The index, an array.

-  final private FeatureStructure[] indexedFSs;

+  final private TOP[] indexedFSs;

   

   final private FsIndex_iicp<T> iicp;

   

-  final private Comparator<FeatureStructure> comparator;

+  final private Comparator<TOP> comparatorWithoutId;

   

   final private int maxAnnotSpan;

     

   FsIndex_flat(FsIndex_iicp<T> iicp) {

-    super(iicp.getCasImpl(), iicp.fsIndex_singletype.getType(), iicp.fsIndex_singletype.getIndexingStrategy(),

-        iicp.fsIndex_singletype.getComparatorImplForIndexSpecs());

+    super(iicp.getCasImpl(), 

+          iicp.fsIndex_singletype.getType(), 

+          iicp.fsIndex_singletype.getIndexingStrategy(),

+          iicp.fsIndex_singletype.getComparatorImplForIndexSpecs());

     this.iicp = iicp;

     indexedFSs = fillFlatArray();

-    comparator = iicp.fsIndex_singletype;

+    comparatorWithoutId = iicp.fsIndex_singletype.comparatorWithoutID;

     maxAnnotSpan = iicp.ll_maxAnnotSpan();

   }  

   

@@ -61,14 +66,14 @@
    * Flat array filled, ordered

    * @param flatArray the array to fill

    */

-  private FeatureStructure[] fillFlatArray() {

+  private TOP[] fillFlatArray() {

     

-    FeatureStructure[] a =  (FeatureStructure[]) Array.newInstance(FeatureStructure.class, iicp.size());

+    TOP[] a =  (TOP[]) Array.newInstance(TOP.class, iicp.size());

     

     FSIterator<T> it = iicp.iterator();

     int i = 0;

     while (it.hasNext()) {

-      a[i++] = it.nextNvc();

+      a[i++] = (TOP) it.nextNvc();

     }

     

     if (i != a.length) {

@@ -86,8 +91,22 @@
    * @see org.apache.uima.cas.FSIndex#iterator()

    */

   @Override

-  public FSIterator<T> iterator() {

-    return new FsIterator_subtypes_snapshot<T>(this);

+  public LowLevelIterator<T> iterator() {

+    return iterator(IS_ORDERED, IS_TYPE_ORDER);

+  }

+  

+   /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.FsIndex_singletype#iterator(boolean, boolean)

+   */

+  @Override

+  public LowLevelIterator<T> iterator(boolean orderNotNeeded, boolean ignoreType) {

+    FsIndex_singletype<T> idx = iicp.getFsIndex_singleType();

+    Comparator<TOP> comp = orderNotNeeded 

+                             ? null

+                             : ignoreType

+                                ? idx.comparatorNoTypeWithoutID

+                                : idx.comparatorWithoutID;

+    return new FsIterator_subtypes_snapshot<T>(this, comp);

   }

 

   /* (non-Javadoc)

@@ -112,8 +131,8 @@
   @Override

   public T find(FeatureStructure fs) {

     if (isSorted()) {

-      for (FeatureStructure item : indexedFSs) {

-        if (comparator.compare(item, fs) == 0) {

+      for (TOP item : indexedFSs) {

+        if (comparatorWithoutId.compare(item, (TOP)fs) == 0) {

           return (T) item;

         }

       }

@@ -122,28 +141,32 @@
 

     // ordered case

     // r is index if found, otherwise, (-(insertion point) - 1). 

-    int r = Arrays.binarySearch(indexedFSs, fs, comparator);

+    int r = Arrays.binarySearch(indexedFSs, (TOP)fs, comparatorWithoutId);

     return (r >= 0) ? (T) indexedFSs[r] : null;

   }

 

-  public T findEq(T fs) {

-    

-    if (isSorted()) {

-      Arrays.binarySearch((T[]) indexedFSs, 0, indexedFSs.length, fs, (T fs1, T fs2) -> fs1 == fs2 ? 0 : -1);

-    } else {

-      for (FeatureStructure item : indexedFSs) {

-        if (fs == item) {

-          return (T) item;

-        }

-      }

-      return null;

-    }

-

-    // ordered case

-    // r is index if found, otherwise, (-(insertion point) - 1). 

-    int r = Arrays.binarySearch(indexedFSs, fs, (f1, f2) -> Integer.compare(f1._id(), f2._id()));

-    return (r == 0) ? fs : null;    

-  }

+//  public T findEq(T fs) {

+//    

+//    if (isSorted()) {

+//      Arrays.binarySearch((T[]) indexedFSs, 

+//                          0, 

+//                          indexedFSs.length, 

+//                          fs, 

+//                          comparator augmented by id;

+//    } else {

+//      for (FeatureStructure item : indexedFSs) {

+//        if (fs == item) {

+//          return (T) item;

+//        }

+//      }

+//      return null;

+//    }

+//

+//    // ordered case

+//    // r is index if found, otherwise, (-(insertion point) - 1). 

+//    int r = Arrays.binarySearch(indexedFSs, fs, (f1, f2) -> Integer.compare(f1._id(), f2._id()));

+//    return (r == 0) ? fs : null;    

+//  }

 

   /**

    * @see org.apache.uima.cas.FSIndex#size()

@@ -179,7 +202,7 @@
    */    

   @Override

   public int compare(FeatureStructure fs1, FeatureStructure fs2) {

-    return comparator.compare(fs1,  fs2);

+    return comparatorWithoutId.compare((TOP)fs1, (TOP)fs2);

   }

 

   @Override

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_iicp.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_iicp.java
index e127fac..5be627e 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_iicp.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_iicp.java
@@ -19,15 +19,17 @@
 

 package org.apache.uima.cas.impl;

 

+import java.util.AbstractCollection;

 import java.util.ArrayList;

 import java.util.Arrays;

 import java.util.Comparator;

+import java.util.stream.Stream;

 

 import org.apache.uima.cas.FSIndex;

-import org.apache.uima.cas.FSIterator;

 import org.apache.uima.cas.FeatureStructure;

 import org.apache.uima.cas.Type;

 import org.apache.uima.cas.admin.FSIndexComparator;

+import org.apache.uima.jcas.cas.TOP;

 

 /**

  * FsIndex_iicp (iicp)

@@ -47,9 +49,10 @@
  * For Internal Use

  */  

 class FsIndex_iicp<T extends FeatureStructure> 

+          extends AbstractCollection<T>

           implements Comparable<FsIndex_iicp<? extends FeatureStructure>>,

                      Comparator<FeatureStructure>,

-                     LowLevelIndex<T> {

+                     LowLevelIndex<T> {  

 

 //  private final static boolean DEBUG = false;

 

@@ -67,7 +70,7 @@
    * 

    * This is set up lazily on first need, to avoid extra work when won't be accessed

    */

-  FsIndex_singletype<FeatureStructure>[] cachedSubFsLeafIndexes = null;

+  FsIndex_singletype<TOP>[] cachedSubFsLeafIndexes = null;

   

   // VOLATILE to permit double-checked locking technique

   private volatile boolean isIteratorCacheSetup = false;

@@ -92,7 +95,7 @@
     } else {  

       int len = Math.min(3,  cachedSubFsLeafIndexes.length);

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

-        FsIndex_singletype<FeatureStructure> lii = cachedSubFsLeafIndexes[i]; 

+        FsIndex_singletype<TOP> lii = cachedSubFsLeafIndexes[i]; 

         sb.append("  cache ").append(i++);

         sb.append("  ").append(lii).append('\n');

       }

@@ -225,6 +228,8 @@
   /**

    * Maybe not used 3/2015

    * 

+   * Compares two instances of FsIndex_iicp, for ordering.

+   * 

    * Compares first using the type code of the main types

    *   If those are equal,

    *   Compares using the comparatorForIndexSpecs objects

@@ -253,18 +258,19 @@
   public int size() {

     createIndexIteratorCache();  // does nothing if already created

     int size = 0;

-    for (FsIndex_singletype<FeatureStructure> iicp : cachedSubFsLeafIndexes) {

+    for (FsIndex_singletype<TOP> iicp : cachedSubFsLeafIndexes) {

       size += iicp.size();

     }

     return size;

   }

   

+  @Override

   public int ll_maxAnnotSpan() {

     createIndexIteratorCache();  // does nothing if already created

     int span = -1;

     FsIndex_singletype<T> idx = getFsIndex_singleType();

     if (idx instanceof FsIndex_set_sorted && ((FsIndex_set_sorted)idx).isAnnotIdx) {

-      for (FsIndex_singletype<FeatureStructure> subIndex : cachedSubFsLeafIndexes) {

+      for (FsIndex_singletype<TOP> subIndex : cachedSubFsLeafIndexes) {

         int s = ((FsIndex_set_sorted)subIndex).ll_maxAnnotSpan(); 

         if (s > span) {

           span = s;

@@ -276,26 +282,14 @@
   

   public boolean isEmpty() {

     createIndexIteratorCache();  

-    for (FsIndex_singletype<FeatureStructure> index : cachedSubFsLeafIndexes) {

+    for (FsIndex_singletype<TOP> index : cachedSubFsLeafIndexes) {

       if (index.size() > 0) {

         return false;

       }

     }

     return true;

   }

-  

-  boolean has1OrMoreEntries() {

-    createIndexIteratorCache();  // does nothing if already created

-    final FsIndex_singletype<FeatureStructure>[] localIc = this.cachedSubFsLeafIndexes;

-    final int len = localIc.length;

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

-      if (localIc[i].size() > 0) {

-        return true;

-      };

-    }

-    return false;

-  }

-  

+    

   /**

    * A faster version of size() when there are lots of subtypes

    * The cache must be already set up

@@ -306,7 +300,7 @@
    * @return a guess at the size, done quickly

    */

   int guessedSize() {

-    final FsIndex_singletype<FeatureStructure>[] localIc = this.cachedSubFsLeafIndexes;

+    final FsIndex_singletype<TOP>[] localIc = this.cachedSubFsLeafIndexes;

     final int len = localIc.length;

     final int lim = Math.min(3, len);

     int size = 0;

@@ -351,9 +345,9 @@
 //          detectIllegalIndexUpdates[typeCode];

 //    }

     

-  boolean subsumes(int superType, int subType) {

-    return getCasImpl().getTypeSystemImpl().subsumes(superType,  subType);

-  }

+//  boolean subsumes(int superType, int subType) {

+//    return getCasImpl().getTypeSystemImpl().subsumes(superType,  subType);

+//  }

   

   // for flat index support

 //    void addToIteratedSortedIndexes() {

@@ -369,19 +363,19 @@
 //      }

 //    }

   

-  <T2 extends FeatureStructure> FsIndex_singletype<T2> getNoSubtypeIndexForType(Type type) {

-    createIndexIteratorCache();

-    for (FsIndex_singletype<FeatureStructure> noSubtypeIndex : cachedSubFsLeafIndexes) {

-      if (noSubtypeIndex.getType() == type) {

-        return (FsIndex_singletype<T2>) noSubtypeIndex;

-      }

-    }

-    return null;

-  }

+//  <T2 extends FeatureStructure> FsIndex_singletype<T2> getNoSubtypeIndexForType(Type type) {

+//    createIndexIteratorCache();

+//    for (FsIndex_singletype<FeatureStructure> noSubtypeIndex : cachedSubFsLeafIndexes) {

+//      if (noSubtypeIndex.getType() == type) {

+//        return (FsIndex_singletype<T2>) noSubtypeIndex;

+//      }

+//    }

+//    return null;

+//  }

   

-  FSIndexRepositoryImpl getFSIndexRepositoryImpl() {

-    return fsIndexRepositoryImpl;

-  }

+//  FSIndexRepositoryImpl getFSIndexRepositoryImpl() {

+//    return fsIndexRepositoryImpl;

+//  }

 

   FsIndex_singletype<T> getFsIndex_singleType() {

     return fsIndex_singletype;

@@ -405,6 +399,14 @@
     return fsIndex_singletype.getIndexingStrategy();

   }

 

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.LowLevelIndex#getComparator()

+   */

+  @Override

+  public Comparator<TOP> getComparator() {

+    return fsIndex_singletype.comparatorWithoutID;

+  }

+

   @Override

   public FSIndexComparator getComparatorForIndexSpecs() {

     return fsIndex_singletype.getComparatorForIndexSpecs();

@@ -416,8 +418,14 @@
 

   @Override

   public int compare(FeatureStructure fs1, FeatureStructure fs2) {

-    return fsIndex_singletype.compare(fs1,  fs2);

+    return fsIndex_singletype.comparatorWithoutID.compare((TOP)fs1, (TOP)fs2);

   }

+  

+//  @Override

+//  public int compare(FeatureStructure fs1, FeatureStructure fs2, boolean ignoreType) {

+//    return fsIndex_singletype.compare(fs1,  fs2, ignoreType);

+//  }

+  

     

   @Override

   public boolean contains(FeatureStructure fs) {

@@ -428,7 +436,7 @@
   public T find(FeatureStructure fs) {

     createIndexIteratorCache();  // does nothing if already created

     

-    for (FsIndex_singletype<FeatureStructure> idx : cachedSubFsLeafIndexes) {

+    for (FsIndex_singletype<TOP> idx : cachedSubFsLeafIndexes) {

      FeatureStructure result = idx.find(fs);

       if (result != null) {

         return (T) result;

@@ -452,22 +460,54 @@
   }

   

   @Override

-  public FSIterator<T> iterator() {

-    createIndexIteratorCache();  

-   

-    return (cachedSubFsLeafIndexes.length == 1)

-           ? (FSIterator<T>) fsIndex_singletype.iterator()

-           : fsIndex_singletype.isSorted()

-             ? new FsIterator_subtypes_ordered<T>(this)

-             : new FsIterator_aggregation_common<T>(new FsIterator_subtypes_unordered<T>(this).allIterators, fsIndex_singletype);

+  public boolean isSorted() {

+    return fsIndex_singletype.isSorted();

+  }

+  

+  /**

+   *  Iterator varieties

+   *  

+   *  All iterators are over a Type + subtypes (because that's the purpose of this class)

+   *    - ambiguous / unambiguous  (for AnnotationIndex)

+   *    - not strict / strict      (for AnnotationIndex)

+   *    - ignoring type priorities or not  (for any index)

+   *    - "unordered" - no need to preserve order

+   *  

+   *  These may be combined.  

+   */

+  

+  

+  

+  @Override

+  public LowLevelIterator<T> iterator() {

+    return iterator(false, false);

   } 

   

-  public FSIterator<T> iteratorUnordered() {

-    createIndexIteratorCache();  

+//  public LowLevelIterator<T> iterator(boolean orderNotNeeded) {

+//    return iterator(orderNotNeeded, false);

+//  }

+//  

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.LowLevelIndex#iterator(boolean, boolean)

+   *   orderNotNeeded is ignored, because would never be here unless order was needed

+   */

+  @Override

+  public LowLevelIterator<T> iterator(boolean orderNotNeeded, boolean ignoreType) {

+    createIndexIteratorCache(); 

+

+    if (cachedSubFsLeafIndexes.length == 1) {

+      return fsIndex_singletype.iterator(IS_ORDERED, ignoreType);  

+    }

+

+    FsIndex_singletype<T> idx = getFsIndex_singleType();    

+    Comparator<TOP> comparatorMaybeNoTypeWithoutId = ignoreType ? idx.comparatorNoTypeWithoutID : idx.comparatorWithoutID;

     

-    return (cachedSubFsLeafIndexes.length == 1)

-           ? (FSIterator<T>) fsIndex_singletype.iterator()

-           : new FsIterator_aggregation_common<T>(new FsIterator_subtypes_unordered<T>(this).allIterators, fsIndex_singletype); 

+    if (! fsIndex_singletype.isSorted() ||  // is a set index, or 

+                         orderNotNeeded) {  // order is not needed 

+      return new FsIterator_aggregation_common<T>(getIterators(), this, comparatorMaybeNoTypeWithoutId); 

+    }

+    

+    return new FsIterator_subtypes_ordered<T>(this, comparatorMaybeNoTypeWithoutId);   

   }

 

   /**

@@ -481,11 +521,10 @@
    */

   @Override

   public LowLevelIterator<T> ll_iterator(boolean ambiguous) {

-    if (!ambiguous) {

-      return new LLUnambiguousIteratorImpl<T>((LowLevelIterator<FeatureStructure>) iterator());

-     } else {

-       return (LowLevelIterator<T>) iterator();

-     }

+    LowLevelIterator<T> it = iterator(IS_ORDERED, IS_TYPE_ORDER);

+    return ambiguous

+             ? it

+             : new LLUnambiguousIteratorImpl<T>(it);

   }

   

 //  /* ***********************************

@@ -510,13 +549,41 @@
     

   @Override

   public FSIndex<T> withSnapshotIterators() {

-    return new FsIndex_snapshot<>(this);

+    FsIndex_singletype<T> idx = getFsIndex_singleType();

+    return new FsIndex_snapshot<>(this, idx.comparatorWithoutID, idx.comparatorNoTypeWithoutID);

   }

 

   public FSIndexRepositoryImpl getFsRepositoryImpl() {

     return getCasImpl().indexRepository;

   }

 

+  /**

+   * @return a stream of FSIndex_singletype, for all non-empty indexes

+   */

+  public Stream<FsIndex_singletype<TOP>> streamNonEmptyIndexes() {

+    createIndexIteratorCache();

+    return Arrays.stream(cachedSubFsLeafIndexes).filter(idx -> idx.size() > 0);

+  }

+  

+  void collectCowIndexParts(ArrayList<CopyOnWriteIndexPart<T>> indexes) {

+    createIndexIteratorCache();

+    for (FsIndex_singletype idx : cachedSubFsLeafIndexes) {

+      if (idx.size() > 0) {

+        indexes.add(idx.getNonNullCow());

+      }

+    }

+  }

+  

+  LowLevelIterator<T>[] getIterators() {

+    createIndexIteratorCache();

+    LowLevelIterator<T>[] r = new LowLevelIterator[cachedSubFsLeafIndexes.length];

+    int i = 0;

+    for (FsIndex_singletype<TOP> idx : cachedSubFsLeafIndexes) {

+      r[i++] = (LowLevelIterator<T>) idx.iterator();

+    }

+    return r;    

+  }

+  

 //  /* (non-Javadoc)

 //   * @see org.apache.uima.cas.FSIndex#select()

 //   */

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_set_sorted.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_set_sorted.java
index f4f5c1e..74360c0 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_set_sorted.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_set_sorted.java
@@ -19,13 +19,12 @@
 

 package org.apache.uima.cas.impl;

 

+import java.util.AbstractCollection;

 import java.util.Collection;

 import java.util.Comparator;

 import java.util.Iterator;

 import java.util.List;

-import java.util.NavigableSet;

 

-import org.apache.uima.cas.FSIterator;

 import org.apache.uima.cas.FeatureStructure;

 import org.apache.uima.cas.Type;

 import org.apache.uima.cas.admin.FSIndexComparator;

@@ -43,52 +42,29 @@
  *   

  * This is an index over just one type (excluding subtypes)

  * 

- * Uses a NavigableSet as the index (of FSs).  

- *   For sorted, because this is a set, to allow multiple (different) FSs having

- *     the same key values to be in the index, the key used for the index is augmented by a least-significant

- *     key which is the _id field of the FS itself.

+ * Uses key augmented by a least-significant additional key: the _id field of the FS itself,

+ *   to allow multiple otherwise equal (but not ==) FSs to be in the index.

  * 

  * @param <T> the Java class type for this index

  */

-public class FsIndex_set_sorted<T extends FeatureStructure> extends FsIndex_singletype<T> {

+final public class FsIndex_set_sorted<T extends FeatureStructure> extends FsIndex_singletype<T> {

   

-//  /**

+//  /**h

 //   * This impl of sorted set interface allows using the bulk add operation implemented in Java's 

 //   * TreeSet - that tests if the argument being passed in is an instance of SortedSet and does a fast insert.

 //   */

 

 

-  // The index, a NavigableSet. 

-  final private OrderedFsSet_array indexedFSs;

-  

+  // The index, a custom high-performance array impl 

+  final private OrderedFsSet_array<T> indexedFSs;

     

-  final private Comparator<TOP> comparatorWithID;

-  final private Comparator<TOP> comparatorWithoutID;

-  

   // only an optimization used for select.covering for AnnotationIndexes

   private int maxAnnotSpan = -1;

-  public final boolean isAnnotIdx;

      

-  FsIndex_set_sorted(CASImpl cas, Type type, int indexType, FSIndexComparator comparatorForIndexSpecs, boolean useSorted) {

+  FsIndex_set_sorted(CASImpl cas, Type type, int indexType, FSIndexComparator comparatorForIndexSpecs) {

     super(cas, type, indexType, comparatorForIndexSpecs);

-    FSIndexRepositoryImpl ir = this.casImpl.indexRepository;

     

-    if (ir.isAnnotationIndex(comparatorForIndexSpecs, indexType)) {

-      comparatorWithID = ir.getAnnotationFsComparatorWithId(); 

-      comparatorWithoutID = ir.getAnnotationFsComparator();

-      isAnnotIdx = true;

-    } else {

-      isAnnotIdx = false;

-      comparatorWithoutID = (o1, o2) -> compare(o1,  o2);

-      comparatorWithID = useSorted   

-          ? (o1, o2) -> {

-              final int c = compare(o1,  o2); 

-              // augment normal comparator with one that compares IDs if everything else equal

-              return (c == 0) ? (Integer.compare(o1._id(), o2._id())) : c;} 

-          : comparatorWithoutID;

-    }          

-    

-    this.indexedFSs = new OrderedFsSet_array(comparatorWithID, comparatorWithoutID);

+    this.indexedFSs = new OrderedFsSet_array<T>(comparatorNoTypeWithID, comparatorNoTypeWithoutID);

   }

 

   @Override

@@ -122,7 +98,9 @@
         maxAnnotSpan = span;

       }

     }

-    indexedFSs.add((TOP)fs);

+    indexedFSs.add(fs, isSorted() 

+                              ? comparatorNoTypeWithID 

+                              : comparatorNoTypeWithoutID);

   }

 

   /**

@@ -145,57 +123,67 @@
    */

   @Override

   public T find(FeatureStructure templateKey) {

-    if (null == templateKey || this.indexedFSs.isEmpty()) {

-      return null;

-    }

-    TOP found;

-    TOP templateKeyTop = (TOP) templateKey;

-    TOP fs1GEfs = this.indexedFSs.ceiling(templateKeyTop);

-    

-    if (fs1GEfs == null) {  // then all elements are less-that the templateKey

-      found = indexedFSs.lower(templateKeyTop);  //highest of elements less-than the template key

-      return (found == null) 

-               ? null 

-               : (comparatorWithoutID.compare(found, templateKeyTop) == 0) 

-                   ? (T)found 

-                   : null;

-    }

-    

-    // fs1GEfs is the least element that is greater-than-or-equal to the template key, using the fine-grained comparator

-    if (0 == comparatorWithoutID.compare(fs1GEfs, templateKeyTop)) {

-      return (T) fs1GEfs; 

-    }

-    

-    // fs1GEfs not null, GreaterThan the templateKey using comparatorWithoutID

-    // Therefore, the ones preceding it are LE using comparatorWithoutID

-    found = indexedFSs.lower(templateKeyTop);  // the greatest element in this set strictly less than the templateKey

-    return (found == null) 

-              ? null 

-              : (comparatorWithoutID.compare(found, templateKeyTop) == 0) 

-                   ? (T)found 

-                   : null;

+    int pos = this.indexedFSs.findWithoutID((TOP)templateKey);

+    return (pos >= 0)

+             ? this.indexedFSs.getAtPos(pos)

+             : null;

   }

-

-  public T findLeftmost(TOP templateKey) {

-    // descending iterator over elements LessThan templateKey

-    // iterator is over TOP, not T, to make compare easier

-    Iterator<TOP> it = indexedFSs.headSet(templateKey, false).descendingIterator();

   

-    TOP elementBefore = null;

-    TOP lastEqual = null;

-    // move to left until run out or have element not equal using compareWihtoutID to templateKey

-    while (it.hasNext()) {

-      if (0 != comparatorWithoutID.compare(elementBefore = it.next(), templateKey)) {

-        break;

-      }

-      lastEqual = elementBefore;

-    }

   

-    if (!it.hasNext()) { // moved past beginning

-      return (T) elementBefore;  // might return null to indicate not found

-    }

-    return (T) lastEqual;

-  }

+  

+//  @Override

+//  public T find(FeatureStructure templateKey) {

+//    if (null == templateKey || this.indexedFSs.isEmpty()) {

+//      return null;

+//    }

+//    TOP found;

+//    TOP templateKeyTop = (TOP) templateKey;

+//    TOP fs1GEfs = this.indexedFSs.ceiling(templateKeyTop);

+//    

+//    if (fs1GEfs == null) {  // then all elements are less-that the templateKey

+//      found = indexedFSs.lower(templateKeyTop);  //highest of elements less-than the template key

+//      return (found == null) 

+//               ? null 

+//               : (comparatorWithoutID.compare(found, templateKeyTop) == 0) 

+//                   ? (T)found 

+//                   : null;

+//    }

+//    

+//    // fs1GEfs is the least element that is greater-than-or-equal to the template key, using the fine-grained comparator

+//    if (0 == comparatorWithoutID.compare(fs1GEfs, templateKeyTop)) {

+//      return (T) fs1GEfs; 

+//    }

+//    

+//    // fs1GEfs not null, GreaterThan the templateKey using comparatorWithoutID

+//    // Therefore, the ones preceding it are LE using comparatorWithoutID

+//    found = indexedFSs.lower(templateKeyTop);  // the greatest element in this set strictly less than the templateKey

+//    return (found == null) 

+//              ? null 

+//              : (comparatorWithoutID.compare(found, templateKeyTop) == 0) 

+//                   ? (T)found 

+//                   : null;

+//  }

+//

+//  public T findLeftmost(TOP templateKey) {

+//    // descending iterator over elements LessThan templateKey

+//    // iterator is over TOP, not T, to make compare easier

+//    Iterator<TOP> it = indexedFSs.headSet(templateKey, false).descendingIterator();

+//  

+//    TOP elementBefore = null;

+//    TOP lastEqual = null;

+//    // move to left until run out or have element not equal using compareWihtoutID to templateKey

+//    while (it.hasNext()) {

+//      if (0 != comparatorWithoutID.compare(elementBefore = it.next(), templateKey)) {

+//        break;

+//      }

+//      lastEqual = elementBefore;

+//    }

+//  

+//    if (!it.hasNext()) { // moved past beginning

+//      return (T) elementBefore;  // might return null to indicate not found

+//    }

+//    return (T) lastEqual;

+//  }

 

   /**

    * @see org.apache.uima.cas.FSIndex#size()

@@ -218,6 +206,11 @@
    */

   @Override

   public boolean deleteFS(T fs) {

+    if (((TOP)fs)._getTypeImpl() != this.type) {

+      throw new IllegalArgumentException(

+          String.format("Wrong type %s passed to deleteFS of index over type %s", 

+            ((TOP)fs)._getTypeImpl().getName(), this.type.getName()));

+    }

 //    maybeProcessBulkAdds(); // moved to OrderedFsSet_array class

     maybeCopy();

     return this.indexedFSs.remove(fs);

@@ -225,22 +218,44 @@
   

   @Override

   protected void bulkAddTo(List<T> v) {

-    v.addAll((Collection<? extends T>) indexedFSs);

+    Collection<T> coll = new AbstractCollection<T>() {

+

+      @Override

+      public Iterator<T> iterator() { return null; }

+

+      @Override

+      public int size() { return FsIndex_set_sorted.this.size(); }

+

+      /* (non-Javadoc)

+       * @see java.util.AbstractCollection#toArray()

+       */

+      @Override

+      public T[] toArray() {

+        return (T[]) indexedFSs.toArray();

+      }

+    };

+    v.addAll(coll);

   }

-  

-  

-  NavigableSet<T> getNavigableSet() { //used by FsIterator_set_sorted to compute various derivitive nav sets

-    return (NavigableSet<T>) indexedFSs;

-  }

-   

+     

   @Override

-  public FSIterator<T> iterator() {

-    setupIteratorCopyOnWrite();

-    return casImpl.inPearContext()

-             ? new FsIterator_set_sorted_pear<>(this, type, this)

-             : new FsIterator_set_sorted     <>(this, type, this);

+  public LowLevelIterator<T> iterator() {

+    return iterator(IS_ORDERED, IS_TYPE_ORDER);

   }

   

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.FsIndex_singletype#iterator(boolean, boolean)

+   *   orderNotNeeded - ignored, because for a single index type, order always used

+   */

+  @Override

+  public LowLevelIterator<T> iterator(boolean orderNotNeeded, boolean ignoreType) {

+    CopyOnWriteIndexPart cow_wrapper = getNonNullCow();

+    // if index is empty, return never-the-less a real iterator,

+    //   not an empty one, because it may become non-empty

+    Comparator<TOP> comparatorMaybeNoTypeWithoutID = ignoreType ? comparatorNoTypeWithoutID : comparatorWithoutID;

+    return casImpl.inPearContext()

+             ? new FsIterator_set_sorted_pear<T>(this, cow_wrapper, comparatorMaybeNoTypeWithoutID)

+             : new FsIterator_set_sorted2<T>(this, cow_wrapper, comparatorMaybeNoTypeWithoutID);  }

+

   @Override

   protected CopyOnWriteIndexPart createCopyOnWriteIndexPart() {

     if (CASImpl.traceCow) {

@@ -249,7 +264,18 @@
     return new CopyOnWriteOrderedFsSet_array(indexedFSs);

   }

   

+  @Override

   public int ll_maxAnnotSpan() {

     return maxAnnotSpan;

   }

+

+  /* (non-Javadoc)

+   * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)

+   */

+  @Override

+  public int compare(FeatureStructure o1, FeatureStructure o2) {

+    return comparatorWithoutID.compare((TOP)o1, (TOP)o2);

+  }

+  

+  

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_singletype.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_singletype.java
index 669c873..e026da8 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_singletype.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_singletype.java
@@ -20,10 +20,12 @@
 package org.apache.uima.cas.impl;
 
 import java.lang.ref.WeakReference;
+import java.util.AbstractCollection;
 import java.util.Comparator;
 import java.util.List;
 import java.util.WeakHashMap;
 
+import org.apache.uima.cas.FSComparators;
 import org.apache.uima.cas.FSIndex;
 import org.apache.uima.cas.FSIterator;
 import org.apache.uima.cas.FeatureStructure;
@@ -34,171 +36,267 @@
 import org.apache.uima.jcas.cas.TOP;
 
 /**
- * The common (among all index kinds - set, sorted, bag) info for an index over 1 type (excluding subtypes)
- *   The name "Leaf" is a misnomer - it's just over one type excluding any subtypes if they exist
- * SubClasses define the actual index repository for each kind.
+ * The common (among all index kinds - set, sorted, bag) info for an index over
+ * 1 type (excluding subtypes)
  * 
- * @param <T> the Java cover class type for this index, passed along to (wrapped) iterators producing Java cover classes
+ * SubClasses FsIndex_bag, FsIndex_flat, FsIndex_set_sorted, define the actual
+ * index repository for each kind.
+ * 
+ * @param <T>
+ *          the Java cover class type for this index, passed along to (wrapped)
+ *          iterators producing Java cover classes
  */
-public abstract class FsIndex_singletype<T extends FeatureStructure> implements Comparator<FeatureStructure>, LowLevelIndex<T> {
+public abstract class FsIndex_singletype<T extends FeatureStructure> 
+    extends AbstractCollection<T>
+    implements Comparator<FeatureStructure>, LowLevelIndex<T> {
 
-  private final static String[] indexTypes = new String[] {"Sorted", "Set", "Bag", "DefaultBag"};
-  
+  private final static String[] indexTypes = new String[] {
+      "Sorted", "Set", "Bag", "DefaultBag" };
+
   /**
-   * shares equal FSIndexComparatorImpl comparatorForIndexSpecs objects
-   * updates and accesses are synchronized
+   * shares equal FSIndexComparatorImpl comparatorForIndexSpecs objects updates
+   * and accesses are synchronized
    */
-  private final static WeakHashMap<FSIndexComparatorImpl, WeakReference<FSIndexComparatorImpl>> comparatorCache = 
-      new WeakHashMap<>();
+  private final static WeakHashMap<FSIndexComparatorImpl, WeakReference<FSIndexComparatorImpl>> comparatorCache = new WeakHashMap<>();
 
-  private final int indexType;  // Sorted, Set, Bag, Default-bag, etc.
+  private final int indexType; // Sorted,
+                               // Set,
+                               // Bag,
+                               // Default-bag,
+                               // etc.
 
   // A reference to the low-level CAS.
   final protected CASImpl casImpl;
-  
   /**
    * comparator for an index, passed in as an argument to the constructor
    */
-  final private FSIndexComparatorImpl comparatorForIndexSpecs;
+  final protected FSIndexComparatorImpl comparatorForIndexSpecs;
 
-  /***********  Info about Index Comparator (not used for bag ***********
-   * Index into these arrays is the key number (indexes can have multiple keys)
+  final protected Comparator<TOP> comparatorWithID;
+  final protected Comparator<TOP> comparatorWithoutID;
+
+  /**
+   * comparator (with id) (ignoring typeorder) - used within one type
+   */
+  final protected Comparator<TOP> comparatorNoTypeWithID;
+
+  /**
+   * comparator (without id) (ignoring typeorder) - used within one type - used
+   * for iterator operations where the type is requested to be ignored
+   */
+  final protected Comparator<TOP> comparatorNoTypeWithoutID;
+
+  public final boolean isAnnotIdx;
+
+  /***********
+   * Info about Index Comparator (not used for bag *********** Index into these
+   * arrays is the key number (indexes can have multiple keys)
    **********************************************************************/
   // For each key, the int code of the type of that key.
-  final private Object[] keys;   // either a FeatImpl or a LinearTypeOrder;
+  final private Object[] keys; // either a FeatImpl or a LinearTypeOrder;
 
   final private int[] keyTypeCodes;
-  // For each key, the comparison to use.
-  final private boolean[] isReverse;    // true = reverse, false = standard
+  // For each key, the comparison to use. 
+  final private boolean[] isReverse; // true = reverse, false = standard
+
+  // /** true if one of the keys is the linear type order key */
+  // private boolean hasLinearTypeOrderKey = false;
+  // /** true if there is an linear type order key, but no type priorities are
+  // specified */
+  // private boolean hasEmptyLinearTypeOrderKey = false;
 
   protected final TypeImpl type; // The type of this
-  
   final private int typeCode;
-  
+
   /**
-   * common copy on write instance or null; starts out as null
-   * Iterator creation initializes (if null).
-   * A subsequent Modification to index, if this is not null:
-   *    call cow.makeCopy();
-   *    set wr_cow = null
-   *    do the modification
-   * index clear/flush - set to null;
+   * common copy on write instance or null; starts out as null Iterator creation
+   * initializes (if null). A subsequent Modification to index, if this is not
+   * null: call cow.makeCopy(); set wr_cow = null do the modification index
+   * clear/flush - set to null;
    * 
-   * Weak ref so that after iterator is GC'd, and no ref's exist, this becomes null, so that
-   * future mods no longer need to do extra work.
+   * Weak ref so that after iterator is GC'd, and no ref's exist, this becomes
+   * null, so that future mods no longer need to do extra work.
    */
-  protected WeakReference<CopyOnWriteIndexPart> wr_cow = null;  
-  
-  
+  protected WeakReference<CopyOnWriteIndexPart<T>> wr_cow = null;
+
   @Override
   public String toString() {
-    String kind = (indexType >= 0 && indexType < 4) ? indexTypes[indexType] : "Invalid";     
-    return this.getClass().getSimpleName() + 
-             "(" + kind + ")[" + type.getShortName() + "]";
+    String kind = (indexType >= 0 && indexType < 4) ? indexTypes[indexType] : "Invalid";
+    return this.getClass().getSimpleName() + "(" + kind + ")[" + type.getShortName() + "]";
   }
-  
-  // never called
-  // declared private to block external calls
-  @SuppressWarnings("unused")
-  private FsIndex_singletype() {
-    this.indexType = 0; // must do because it's final
-    this.casImpl = null;
-    this.type = null;
-    this.typeCode = 0;
-    comparatorForIndexSpecs = null;
-    keys = null;
-    keyTypeCodes = null;
-    isReverse = null;
-  }
+
+  // // never called
+  // // declared private to block external calls
+  // @SuppressWarnings("unused")
+  // private FsIndex_singletype() {
+  // this.indexType = 0; // must do because it's final
+  // this.casImpl = null;
+  // this.type = null;
+  // this.typeCode = 0;
+  // comparatorForIndexSpecs = null;
+  // keys = null;
+  // keyTypeCodes = null;
+  // isReverse = null;
+  // }
 
   /**
    * Constructor for FsIndex_singletype.
-   * @param cas -
-   * @param type -
-   * @param indexType -
-   * @param comparatorForIndexSpecs -
+   * 
+   * @param cas
+   *          -
+   * @param type
+   *          -
+   * @param indexType
+   *          -
+   * @param comparatorForIndexSpecs
+   *          -
    */
-  protected FsIndex_singletype(CASImpl cas, Type type, int indexType, FSIndexComparator comparatorForIndexSpecs) {
+  protected FsIndex_singletype(CASImpl cas, Type type, int indexType,
+      FSIndexComparator comparatorForIndexSpecs) {
     super();
     this.indexType = indexType;
     this.casImpl = cas;
     this.type = (TypeImpl) type;
-    this.typeCode = ((TypeImpl)type).getCode();
+    this.typeCode = ((TypeImpl) type).getCode();
     FSIndexComparatorImpl compForIndexSpecs = (FSIndexComparatorImpl) comparatorForIndexSpecs;
     this.comparatorForIndexSpecs = Misc.shareExisting(compForIndexSpecs, comparatorCache);
-//    this.comparatorForIndexSpecs = compForIndexSpecs/*.copy()*/;
-    
+    // this.comparatorForIndexSpecs = compForIndexSpecs/*.copy()*/;
+
     // Initialize the comparator info.
     final int nKeys = this.comparatorForIndexSpecs.getNumberOfKeys();
     this.keys = new Object[nKeys];
     this.keyTypeCodes = new int[nKeys];
     this.isReverse = new boolean[nKeys];
-    
+
     if (!this.comparatorForIndexSpecs.isValid()) {
+      isAnnotIdx = false;
+      comparatorWithID = null;
+      comparatorWithoutID = null;
+      comparatorNoTypeWithID = null;
+      comparatorNoTypeWithoutID = null;
       return;
     }
 
     for (int i = 0; i < nKeys; i++) {
-      
-      final Object k =  (comparatorForIndexSpecs.getKeyType(i) == FSIndexComparator.FEATURE_KEY)
-                     ? (FeatureImpl) this.comparatorForIndexSpecs.getKeyFeature(i)
-                     : this.comparatorForIndexSpecs.getKeyTypeOrder(i);
-      keys[i] = k; 
+      int keyType = comparatorForIndexSpecs.getKeyType(i);
+      final Object k = (keyType == FSIndexComparator.FEATURE_KEY)
+          ? (FeatureImpl) this.comparatorForIndexSpecs.getKeyFeature(i)
+          : this.comparatorForIndexSpecs.getKeyTypeOrder(i);
+      keys[i] = k;
       if (k instanceof FeatureImpl) {
-        keyTypeCodes[i] = ((TypeImpl)((FeatureImpl)k).getRange()).getCode();
+        keyTypeCodes[i] = ((TypeImpl) ((FeatureImpl) k).getRange()).getCode();
+      } else {
+        // key is linear type order
+        // hasLinearTypeOrderKey = true;
+        // hasEmptyLinearTypeOrderKey = ((LinearTypeOrder)k).isEmptyTypeOrder();
       }
-      isReverse[i] = this.comparatorForIndexSpecs.getKeyComparator(i) == FSIndexComparator.REVERSE_STANDARD_COMPARE;
+      isReverse[i] = this.comparatorForIndexSpecs
+          .getKeyComparator(i) == FSIndexComparator.REVERSE_STANDARD_COMPARE;
     }
-  }
-  
-  /**
-   * Adding FS to an index.
-   *   not in upper interfaces because it's internal use only - called via addToIndexes etc.
-   * @param fs the fs to be added
-   */
-  abstract void insert(T fs);  // not in upper interfaces because it's internal use only
 
-//  /**
-//   * @param fs - the Feature Structure to be removed.
-//   *             Only this exact Feature Structure is removed (this is a stronger test than, for example,
-//   *             what moveTo(fs) does, where the fs in that case is used as a template).  
-//   *             It is not an error if this exact Feature Structure is not in an index.
-//   * @return true if something was removed, false if not found
-//   */
-//  boolean remove(int fs) {
-//    return deleteFS((T) getCasImpl().getFsFromId_checked(fs));
-//  }
-   
+    FSIndexRepositoryImpl ir = this.casImpl.indexRepository;
+
+    if (ir.isAnnotationIndex(comparatorForIndexSpecs, indexType)) {
+      comparatorWithID = ir.getAnnotationFsComparator(FSComparators.WITH_ID,
+          FSComparators.WITH_TYPE_ORDER);
+      comparatorWithoutID = ir.getAnnotationFsComparator(FSComparators.WITHOUT_ID,
+          FSComparators.WITH_TYPE_ORDER);
+      comparatorNoTypeWithID = ir.getAnnotationFsComparator(FSComparators.WITH_ID,
+          FSComparators.WITHOUT_TYPE_ORDER);
+      comparatorNoTypeWithoutID = ir.getAnnotationFsComparator(FSComparators.WITHOUT_ID,
+          FSComparators.WITHOUT_TYPE_ORDER);
+      isAnnotIdx = true;
+    } else {
+      // NOT ANNOTATION INDEX      
+      isAnnotIdx = false;
+
+      if (indexType == BAG_INDEX) {
+        comparatorNoTypeWithID = comparatorNoTypeWithoutID = comparatorWithID = comparatorWithoutID = 
+            (o1, o2) -> ((FsIndex_bag)this).compare(o1, o2);
+      } else {
+        comparatorWithoutID = (o1, o2) -> compare(o1, o2, IS_TYPE_ORDER);
+  
+        comparatorWithID = (indexType == FSIndex.SORTED_INDEX) ? (o1, o2) -> {
+  
+          final int c = compare(o1, o2, IS_TYPE_ORDER);
+          // augment normal comparator with one that compares IDs if everything
+          // else equal
+          return (c == 0) ? (Integer.compare(o1._id(), o2._id())) : c;
+        }
+  
+            : comparatorWithoutID;
+  
+        comparatorNoTypeWithoutID = (o1, o2) -> compare(o1, o2, !IS_TYPE_ORDER);
+  
+        comparatorNoTypeWithID = (indexType == FSIndex.SORTED_INDEX) ? (o1, o2) -> {
+  
+          final int c = compare(o1, o2, !IS_TYPE_ORDER);
+          // augment normal comparator with one that compares IDs if everything
+          // else equal
+          return (c == 0) ? (Integer.compare(o1._id(), o2._id())) : c;
+        }
+  
+            : comparatorWithID;
+      }
+    }
+
+  }
+
   /**
-   * @param fs - the Feature Structure to be removed.
-   *             Only this exact Feature Structure is removed (this is a stronger test than, for example,
-   *             what moveTo(fs) does, where the fs in that case is used as a template).  
-   *             It is not an error if this exact Feature Structure is not in an index.
+   * Adding FS to an index. not in upper interfaces because it's internal use
+   * only - called via addToIndexes etc.
+   * 
+   * @param fs
+   *          the fs to be added
+   */
+  abstract void insert(T fs); // not in upper interfaces because it's internal
+                              // use only
+
+  // /**
+  // * @param fs - the Feature Structure to be removed.
+  // * Only this exact Feature Structure is removed (this is a stronger test
+  // than, for example,
+  // * what moveTo(fs) does, where the fs in that case is used as a template).
+  // * It is not an error if this exact Feature Structure is not in an index.
+  // * @return true if something was removed, false if not found
+  // */
+  // boolean remove(int fs) {
+  // return deleteFS((T) getCasImpl().getFsFromId_checked(fs));
+  // }
+
+  /**
+   * @param fs
+   *          - the Feature Structure to be removed. Only this exact Feature
+   *          Structure is removed (this is a stronger test than, for example,
+   *          what moveTo(fs) does, where the fs in that case is used as a
+   *          template). It is not an error if this exact Feature Structure is
+   *          not in an index.
    * @return true if something was removed, false if not found
    */
   abstract boolean deleteFS(T fs);
-  
-  /**
-   * Common part of iterator creation
-   */
-  protected void setupIteratorCopyOnWrite() {
-    if (null == wr_cow || null == wr_cow.get()) {
-      wr_cow = new WeakReference<>(createCopyOnWriteIndexPart());
-    }
-  }
-  
+
   @Override
-  public FSIterator<T> iterator(FeatureStructure initialPositionFs) {
-    FSIterator<T> fsIt = iterator();
+  public LowLevelIterator<T> iterator(FeatureStructure initialPositionFs) {
+    LowLevelIterator<T> fsIt = iterator();
     fsIt.moveTo(initialPositionFs);
     return fsIt;
   }
-    
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.uima.cas.impl.LowLevelIndex#getComparator()
+   */
+  @Override
+  public Comparator<TOP> getComparator() {
+    return comparatorWithoutID;
+  }
+
   @Override
   public FSIndexComparator getComparatorForIndexSpecs() {
     return this.comparatorForIndexSpecs;
   }
-  
+
   public FSIndexComparatorImpl getComparatorImplForIndexSpecs() {
     return this.comparatorForIndexSpecs;
   }
@@ -209,8 +307,10 @@
   }
 
   /**
-   * @param fs1 -
-   * @param fs2 -
+   * @param fs1
+   *          -
+   * @param fs2
+   *          -
    * @return 0 if equal, &lt; 0 if fs1 &lt; fs2, &gt; 0 if fs1 &gt; fs2
    */
   @Override
@@ -219,32 +319,43 @@
   }
 
   /**
-   * @param fs1 -
-   * @param fs2 -
+   * @param fs1
+   *          -
+   * @param fs2
+   *          -
    * @return 0 if equal, &lt; 0 if fs1 &lt; fs2, &gt; 0 if fs1 &gt; fs2
    */
   public int compare(int fs1, int fs2) {
     return compare(casImpl.getFsFromId_checked(fs1), casImpl.getFsFromId_checked(fs2));
   }
-    
-  /**
-   * @see org.apache.uima.cas.FSIndex#compare(FeatureStructure, FeatureStructure)
-   */    
-  @Override
-  public int compare(FeatureStructure afs1, FeatureStructure afs2) {
-  
+
+  // /**
+  // * @see org.apache.uima.cas.FSIndex#compare(FeatureStructure,
+  // FeatureStructure)
+  // *
+  // * Note: this is the "general" compare, based on
+  // * runtime interpreting the index's definition of its Keys, and the type
+  // ordering.
+  // *
+  // * Annotation Index instances should use the custom comparators
+  // */
+  // @Override
+  // public int compare(FeatureStructure afs1, FeatureStructure afs2) {
+  // return compare(afs1, afs2, false); // don't ignore type
+  // }
+
+  int compare(FeatureStructure afs1, FeatureStructure afs2, boolean ignoreType) {
+
     if (afs1 == afs2) {
       return 0;
     }
-    
+
     FeatureStructureImplC fs1 = (FeatureStructureImplC) afs1;
     FeatureStructureImplC fs2 = (FeatureStructureImplC) afs2;
 
     /**
-     * for each key:
-     *   if Feature:
-     *     Switch by type:  float, 
-     *       get the value:  fs1.getXXX, compare
+     * for each key defined by this index: if Feature: Switch by type: float,
+     * get the value: fs1.getXXX, compare
      */
     int i = -1;
     for (Object key : keys) {
@@ -252,13 +363,14 @@
       i++;
       if (key instanceof FeatureImpl) {
         FeatureImpl fi = (FeatureImpl) key;
-        if (fi.getRange().isStringOrStringSubtype()) { // string and string subtypes
+        if (fi.getRange().isStringOrStringSubtype()) { // string and string
+                                                       // subtypes
           result = Misc.compareStrings(fs1._getStringValueNc(fi), fs2._getStringValueNc(fi));
         } else {
           switch (keyTypeCodes[i]) {
           case TypeSystemConstants.booleanTypeCode:
             result = Integer.compare(fs1._getBooleanValueNc(fi) ? 1 : 0,
-                                     fs2._getBooleanValueNc(fi) ? 1 : 0);
+                fs2._getBooleanValueNc(fi) ? 1 : 0);
             break;
           case TypeSystemConstants.byteTypeCode:
             result = Integer.compare(fs1._getByteValueNc(fi), fs2._getByteValueNc(fi));
@@ -278,31 +390,36 @@
           case TypeSystemConstants.doubleTypeCode:
             result = Double.compare(fs1._getDoubleValueNc(fi), fs2._getDoubleValueNc(fi));
             break;
-            // next is compared above before the switch
-//          case TypeSystemConstants.stringTypeCode:
-//            result = Misc.compareStrings(fs1.getStringValueNc(fi), fs2.getStringValueNc(fi));
-//            break;         
+          // next is compared above before the switch
+          // case TypeSystemConstants.stringTypeCode:
+          // result = Misc.compareStrings(fs1.getStringValueNc(fi),
+          // fs2.getStringValueNc(fi));
+          // break;
           } // end of switch
         }
-      } else { // is type order compare    
-        result = ((LinearTypeOrder) key).compare(fs1, fs2);
+      } else { // is type order compare
+        if (ignoreType) {
+          result = 0;
+        } else {
+          result = ((LinearTypeOrder) key).compare(fs1, fs2);
+        }
       }
-        
+
       if (result == 0) {
-        continue;  
+        continue;
       }
-      
-      return (isReverse[i]) ? ( (result < 0) ? 1 : -1) 
-                            : ( (result > 0) ? 1 : -1);
-    } // of for loop iterating over all compare keys    
-    return 0;  // all keys compare equal      
+
+      return (isReverse[i]) ? ((result < 0) ? 1 : -1) : ((result > 0) ? 1 : -1);
+    } // of for loop iterating over all compare keys
+    return 0; // all keys compare equal
   }
 
   @Override
   public int hashCode() {
     final int prime = 31;
     int result = 1;
-    result = prime * result + ((comparatorForIndexSpecs == null) ? 0 : comparatorForIndexSpecs.hashCode());
+    result = prime * result
+        + ((comparatorForIndexSpecs == null) ? 0 : comparatorForIndexSpecs.hashCode());
     return result;
   }
 
@@ -331,21 +448,30 @@
   public Type getType() {
     return this.type;
   }
-  
+
   public TypeImpl getTypeImpl() {
     return this.type;
   }
-  
+
   int getTypeCode() {
     return this.typeCode;
   }
 
+  // /** true if there is a type order key, and no type priorities are defined
+  // */
+  // public boolean hasEmptyLinearTypeOrderKey() {
+  // return hasEmptyLinearTypeOrderKey;
+  // }
+
   /**
-   * For serialization: get all the items in this index and bulk add to an List&lt;T&gt;
-   * @param v the set of items to add
+   * For serialization: get all the items in this index and bulk add to an
+   * List&lt;T&gt;
+   * 
+   * @param v
+   *          the set of items to add
    */
   protected abstract void bulkAddTo(List<T> v);
-  
+
   @Override
   public LowLevelIterator<T> ll_iterator(boolean ambiguous) {
     if (ambiguous) {
@@ -354,30 +480,36 @@
 
     return null;
   }
-  
+
   @Override
   public CASImpl getCasImpl() {
     return this.casImpl;
   }
-  
+
   @Override
   public FSIndex<T> withSnapshotIterators() {
     // Is a no-op because this is a single type index.
     // should never be called
-    // this is an artifact of the fact that FsIndex_singletype implements FSIndex interface
+    // this is an artifact of the fact that FsIndex_singletype implements
+    // FSIndex interface
     return this;
   }
-  
+
   boolean isSetOrSorted() {
     return indexType == FSIndex.SET_INDEX || indexType == FSIndex.SORTED_INDEX;
   }
-  
-  boolean isSorted() {
+
+  public boolean isSorted() {
     return indexType == FSIndex.SORTED_INDEX;
   }
-  
+
   /**
-   * Differs from flush in that it manipulates flags in the FSs to indicate removed.
+   * Differs from flush in that it manipulates flags in the FSs to indicate
+   * removed.
+   * This can only be done if we can guarantee the FS is not indexed **in any view**.
+   * We do that by only resetting if it is a subtype of annotation base, which is guaranteed
+   *   to be indexed only in 1 view.
+   * 
    */
   void removeAll() {
     FSIterator<T> it = iterator();
@@ -398,34 +530,31 @@
       }
       return n;
     }
-    
+
     if (CASImpl.traceCow) {
       this.casImpl.traceCowReinit("getNew", this);
     }
 
-    // null means index updated since iterator was created, need to make new cow and use it
-    n = createCopyOnWriteIndexPart();  //new CopyOnWriteObjHashSet<TOP>(index);
+    // null means index updated since iterator was created, need to make new cow
+    // and use it
+    n = createCopyOnWriteIndexPart(); // new CopyOnWriteObjHashSet<TOP>(index);
     wr_cow = new WeakReference<>(n);
     return n;
   }
-  
-  protected CopyOnWriteIndexPart getCopyOnWriteIndexPart() {
-    if (wr_cow != null) {
-      CopyOnWriteIndexPart n = wr_cow.get();
-      if (n != null) {
-        return n;
-      }
-    }
-    return null;
-  }
-  
-  protected abstract CopyOnWriteIndexPart createCopyOnWriteIndexPart();
-  
+
   /**
-   * Called just before modifying an index
-   * if wr_cow has a value, 
-   *   tell that value to create a preserving copy of the index part, and
-   *   set wr_cow to null
+   * @return the copy-on-write wrapper for an index part if it exists for this
+   *         index, or null
+   */
+  public CopyOnWriteIndexPart<T> getCopyOnWriteIndexPart() {
+    return (wr_cow == null) ? null : wr_cow.get();
+  }
+
+  protected abstract CopyOnWriteIndexPart createCopyOnWriteIndexPart();
+
+  /**
+   * Called just before modifying an index if wr_cow has a value, tell that
+   * value to create a preserving copy of the index part, and set wr_cow to null
    */
   protected void maybeCopy() {
     if (wr_cow != null) {
@@ -436,13 +565,36 @@
       wr_cow = null;
     }
   }
-  
+
   @Override
   public void flush() {
-    maybeCopy();
+//   maybeCopy(); // https://issues.apache.org/jira/browse/UIMA-5687
     wr_cow = null;
-//    casImpl.indexRepository.isUsedChanged = true;
+    // casImpl.indexRepository.isUsedChanged = true;
   }
 
+  /* (non-Javadoc)
+   * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+   */
+  /**
+   * This is required to avoid compilation error (but not in Eclipse) due to 
+   * ambiguous interface inheritance from both FeatureStructure and Comparator
+   */
+  @Override
+  public abstract int compare(FeatureStructure o1, FeatureStructure o2);
+  
+  
+
+  /// **
+  // * Common part of iterator creation
+  // */
+  // protected CopyOnWriteIndexPart setupIteratorCopyOnWrite() {
+  // CopyOnWriteIndexPart cow_index_part = getCopyOnWriteIndexPart();
+  // if (null == wr_cow || null == wr_cow.get()) {
+  // cow_index_part = createCopyOnWriteIndexPart();
+  // wr_cow = new WeakReference<>(cow_index_part);
+  // }
+  // return cow_index_part;
+  // }
 
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_snapshot.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_snapshot.java
index 9d2ef04..a4dc8b6 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_snapshot.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIndex_snapshot.java
@@ -19,12 +19,11 @@
 

 package org.apache.uima.cas.impl;

 

+import java.util.AbstractCollection;

 import java.util.Comparator;

 

 import org.apache.uima.cas.FSIndex;

-import org.apache.uima.cas.FSIterator;

 import org.apache.uima.cas.FeatureStructure;

-import org.apache.uima.cas.SelectFSs;

 import org.apache.uima.cas.Type;

 import org.apache.uima.cas.admin.FSIndexComparator;

 import org.apache.uima.jcas.cas.TOP;

@@ -33,15 +32,23 @@
  * Implementation of light-weight wrapper of normal indexes, which support special kinds of iterators

  *   base on the setting of IteratorExtraFunction

  */

-public class FsIndex_snapshot <T extends FeatureStructure> implements LowLevelIndex<T>, Comparator<FeatureStructure> {

+public class FsIndex_snapshot <T extends FeatureStructure>

+                extends AbstractCollection<T>

+                implements LowLevelIndex<T>, Comparator<FeatureStructure> {

     

   /**

    * wrapped index 

    */

   private final FsIndex_iicp<T> wrapped;

+  private final Comparator<TOP> comparatorWithoutId;

+  private final Comparator<TOP> comparatorNoTypeWithoutId;

   

-  public FsIndex_snapshot(FsIndex_iicp<T> wrapped) {

+  public FsIndex_snapshot(FsIndex_iicp<T> wrapped, 

+                         Comparator<TOP> comparatorWithoutId,

+                         Comparator<TOP> comparatorTypeWithoutId) {

     this.wrapped = wrapped;

+    this.comparatorWithoutId = comparatorWithoutId;

+    this.comparatorNoTypeWithoutId = comparatorTypeWithoutId;

   }

 

   /* (non-Javadoc)

@@ -66,11 +73,20 @@
    * @see org.apache.uima.cas.FSIndex#iterator()

    */

   @Override

-  public FSIterator<T> iterator() {

-    return new FsIterator_subtypes_snapshot<T>(new FsIndex_flat<T>(wrapped));

+  public LowLevelIterator<T> iterator() {

+    return iterator(IS_ORDERED, IS_TYPE_ORDER);

   }

 

   /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.LowLevelIndex#iterator(boolean, boolean)

+   */

+  @Override

+  public LowLevelIterator<T> iterator(boolean orderNotNeeded, boolean ignoreType) {

+    Comparator<TOP> comparatorMaybeNoTypeWithoutID = ignoreType ? comparatorNoTypeWithoutId : comparatorWithoutId;

+    return new FsIterator_subtypes_snapshot<T>(new FsIndex_flat<T>(wrapped), comparatorMaybeNoTypeWithoutID);

+  }

+  

+  /* (non-Javadoc)

    * @see org.apache.uima.cas.FSIndex#getIndexingStrategy()

    */

   @Override

@@ -78,10 +94,11 @@
   

   /* (non-Javadoc)

    * @see org.apache.uima.cas.FSIndex#withSnapshotIterators()

+   * acts like a copy

    */

   @Override

   public FSIndex<T> withSnapshotIterators() {

-    return new FsIndex_snapshot<T>(wrapped);

+    return new FsIndex_snapshot<T>(wrapped, comparatorWithoutId, comparatorNoTypeWithoutId);

   }

 

   /* (non-Javadoc)

@@ -96,14 +113,13 @@
    */

   @Override

   public int compare(FeatureStructure o1, FeatureStructure o2) { return wrapped.compare(o1,  o2); }

-

+  

   @Override

   public LowLevelIterator<T> ll_iterator(boolean ambiguous) {

-    if (!ambiguous) {

-      return new LLUnambiguousIteratorImpl<T>((LowLevelIterator<FeatureStructure>) iterator());

-    } else {

-      return (LowLevelIterator<T>) iterator();

-    }

+    LowLevelIterator<T> it = iterator(IS_ORDERED, IS_TYPE_ORDER);

+    return ambiguous 

+            ? it

+            : new LLUnambiguousIteratorImpl<T>(it);

   }

 

   @Override

@@ -116,6 +132,14 @@
     return wrapped.getCasImpl();

   }

 

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.LowLevelIndex#getComparator()

+   */

+  @Override

+  public Comparator<TOP> getComparator() {

+    return wrapped.getComparator();

+  }

+

   @Override

   public FSIndexComparator getComparatorForIndexSpecs() {

     return wrapped.getComparatorForIndexSpecs();

@@ -125,4 +149,10 @@
   public int ll_maxAnnotSpan() {

     return wrapped.ll_maxAnnotSpan();

   }

+  

+  @Override 

+  public boolean isSorted() {

+    return wrapped.isSorted();

+  }  

+  

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_aggregation_common.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_aggregation_common.java
index 29b1433..c446f24 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_aggregation_common.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_aggregation_common.java
@@ -19,171 +19,167 @@
 

 package org.apache.uima.cas.impl;

 

-import java.lang.reflect.Array;

-import java.util.ArrayList;

-import java.util.List;

+import java.util.Comparator;

 import java.util.NoSuchElementException;

+import java.util.concurrent.atomic.AtomicInteger;

 

+import org.apache.uima.UIMAFramework;

 import org.apache.uima.cas.FSIndex;

 import org.apache.uima.cas.FSIterator;

 import org.apache.uima.cas.FeatureStructure;

 import org.apache.uima.cas.Type;

+import org.apache.uima.internal.util.Misc;

+import org.apache.uima.jcas.cas.TOP;

 

 /**

  * Aggregate several FS iterators.  Simply iterates over one after the other

  * without any sorting or merging.

- * Used by getAllIndexedFS and FsIterator_subtypes_unordered

+ * Used by getAllIndexedFS and FsIterator_subtypes when unordered

+ *   underlying iterators could be any (bag, set, or ordered

+ *   underlying iterators could be complex (unambiguous annotation, filtered,...)

  * 

  * The iterators can be for single types or for types with subtypes.

  *   Exception: if the ll_index is accessed, it is presumed to be of type FsIndex_subtypes.

- * 

- * Doesn't do concurrent mod checking - that's done if wanted by the individual iterators

- * being aggregated over.  

- * This results in allowing a few concurrent modifications, when crossing from one iterator to another

- * in moveToNext/Previous (because those get translated to move to first/last, which reset concurrent modification)

  */

-class FsIterator_aggregation_common<T extends FeatureStructure> 

-          implements LowLevelIterator<T> {

+class FsIterator_aggregation_common<T extends FeatureStructure> extends FsIterator_multiple_indexes<T> {

   

-  final private FSIterator<T>[] allIterators; // not just for single-type iterators

-  private FSIterator<T>[] nonEmptyIterators; 

-  private FSIterator<T>[] emptyIterators; 

+  private final static AtomicInteger moveToCount = new AtomicInteger(0);

   

-  private int lastValidIndex;

+//  /** only used for moveTo */

+//  final private boolean ignoreTypePriority;

   

-  final private FSIndex<T> index; // not used here, but returned via the ll_getIndex api.

+  /** the index of the current iterator */

+  private int current_it_idx = -1;

   

-  FsIterator_aggregation_common(FSIterator<T>[] iterators, FSIndex<T> index) {

-    this.allIterators = iterators;

-      // can't see the reason for needing to copy the iterators

-      // There's a separate call copy() to do that if needed

-//    for (int i = iterators.length - 1; i >=0; i--) {

-//      this.allIterators[i] = iterators[i].copy();

-//    }

+  FsIterator_aggregation_common(LowLevelIterator<T>[] iterators, 

+                                FSIndex<T> index, 

+                                Comparator<TOP> comparatorMaybeNoTypeWithoutId) {

+    super((LowLevelIndex<T>)index, iterators, comparatorMaybeNoTypeWithoutId);

+    moveToFirstNoReinit();

+  }

+  

+  /** copy constructor */

+  FsIterator_aggregation_common(FsIterator_aggregation_common<T> v) {

+    super(v);

+    current_it_idx = v.current_it_idx;

+  }

     

-    separateIntoEmptyAndNonEmptyIterators();

-    

-    this.index = index;

-    moveToStart();

-  }

   

-  private void separateIntoEmptyAndNonEmptyIterators() {

-    List<FSIterator<T>> nonEmptyOnes = new ArrayList<>();

-    List<FSIterator<T>> emptyOnes = new ArrayList<>();

-    for (FSIterator<T> it : allIterators) {

-      if (((LowLevelIterator<T>)it).ll_indexSize() == 0) {

-        emptyOnes.add(it);

-      } else {

-        nonEmptyOnes.add(it);

-      }

-    }

-    nonEmptyIterators = nonEmptyOnes.toArray(new FSIterator[nonEmptyOnes.size()]);

-    emptyIterators = emptyOnes.toArray(new FSIterator[emptyOnes.size()]);

-  }

-  

-  public T get() throws NoSuchElementException {

-    if (!isValid()) {

-      throw new NoSuchElementException();

-    }

-    return nonEmptyIterators[lastValidIndex].get();

-  }

-  

-  public T getNvc() {

-    return nonEmptyIterators[lastValidIndex].getNvc();

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.LowLevelIterator#moveToSupported()

+   */

+  @Override

+  public boolean isMoveToSupported() {

+    return false;

   }

 

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.FSIterator#isValid()

+   */

+  @Override

   public boolean isValid() {

-    return lastValidIndex >= 0 &&

-           lastValidIndex < nonEmptyIterators.length &&

-           nonEmptyIterators[lastValidIndex].isValid();

+    return current_it_idx >= 0;

   }

 

-  public void moveTo(FeatureStructure fs) {

-    if (firstChangedEmptyIterator() >= 0) {

-      separateIntoEmptyAndNonEmptyIterators();

-    } 

-    // don't need to check isIndexesHaveBeenUpdated because

-    // individual aggregated iterators will do that

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.FSIterator#getNvc()

+   */

+  @Override

+  public T getNvc() throws NoSuchElementException {

+    return nonEmptyIterators[current_it_idx].getNvc();

+  }

+

+  /**

+   * MoveTo for this kind of iterator

+   * Happens for set or sorted indexes being operated without rattling, or for other kinds of aggregation.

+   * 

+   * The meaning for set is to go to the position if it exists of the 1 element equal (using the index's comparator) the arg.

+   * But since the set is unordered, there's no point in doing this.  

+   * 

+   * The meaning for unordered other kinds:  They're not really unordered, just the aggregate is unordered.

+   * A use would be to partially restart iteration from some point.  

+   * But since this is unordered, there's not much point in doing this 

+   *   

+   */

+  public void moveToNoReinit(FeatureStructure fs) {

+    Misc.decreasingWithTrace(moveToCount, "MoveTo operations on unsorted iterators are likely mistakes." , UIMAFramework.getLogger());

     

-    for (int i = 0, nbrIt = nonEmptyIterators.length; i < nbrIt; i++) {

-      FSIterator<T> it = nonEmptyIterators[i];

-      if (((LowLevelIterator<T>)it).ll_getIndex().contains(fs)) {

-        lastValidIndex = i;

-        it.moveTo(fs);

-        return;

+//    Type typeCompare = fs.getType();

+    

+    int i = -1;

+    int validNonMatch = -1;

+    for (LowLevelIterator<T> it : nonEmptyIterators) {

+      

+      i++;

+      

+//      Type itType = (TypeImpl) it.getType();

+//      if ( ! typeCompare.subsumes(itType) ) {

+//        continue;

+//      }

+      

+      it.moveToNoReinit(fs);

+      if (it.isValid() && 0 == it.ll_getIndex().compare(fs, it.getNvc())) {

+        current_it_idx = i;

+        return;  // perfect match

+      }

+      if (validNonMatch == -1 && it.isValid()) {

+        validNonMatch = i; // capture first valid non-Match

       }

     }

-    moveToStart();  // default if not found

-  }

-

-  public void moveToFirst() {

-    if (firstChangedEmptyIterator() >= 0) {

-      separateIntoEmptyAndNonEmptyIterators();

+    

+    // nothing matched using iterator compare

+    if (validNonMatch >= 0) {

+      current_it_idx = validNonMatch;

+      return;  

     }

-    // don't need to check isIndexesHaveBeenUpdated because

-    // individual aggregated iterators will do that

-

-    moveToStart();

+    // mark iterator invalid otherwise

+    current_it_idx = -1;

   }

   

-  private void moveToStart() {

-    for (int i = 0, nbrIt = nonEmptyIterators.length; i < nbrIt; i++) {

-      FSIterator<T> it = nonEmptyIterators[i];

-      it.moveToFirst();

+//  /**

+//   * MoveToExact for this kind of iterator

+//   */

+//  public void moveToExactNoReinit(FeatureStructure fs) {

+//    Type typeCompare = fs.getType();

+//    int i = 0;

+//    for (LowLevelIterator<T> it : nonEmptyIterators) {

+//      if (it.getType() == typeCompare) {

+//        it.moveToExactNoReinit(fs);

+//        current_it_idx = it.isValid() ? i : -1;

+//        return;

+//      }

+//      i++;

+//    }

+//    current_it_idx = -1;

+//  }

+

+  

+  /** moves to the first non-empty iterator at its start position */

+  public void moveToFirstNoReinit() {

+    current_it_idx = -1; // no valid index

+    for (LowLevelIterator<T> it : nonEmptyIterators) {

+      current_it_idx++;

+      it.moveToFirstNoReinit();

       if (it.isValid()) {

-        lastValidIndex = i;

         return;

       }

-    }

-    lastValidIndex = -1; // no valid index

-    

+    }        

   }

 

-  public void moveToLast() {

-    if (firstChangedEmptyIterator() >= 0) {

-      separateIntoEmptyAndNonEmptyIterators();

-    }

-    // don't need to check isIndexesHaveBeenUpdated because

-    // individual aggregated iterators will do that

-

+  public void moveToLastNoReinit() {

     for (int i = nonEmptyIterators.length -1; i >= 0; i--) {

-      FSIterator<T> it = nonEmptyIterators[i];

-      it.moveToLast();

+      LowLevelIterator<T> it = nonEmptyIterators[i];

+      it.moveToLastNoReinit();

       if (it.isValid()) {

-        lastValidIndex = i;

+        current_it_idx = i;

         return;

       }

     }

-    lastValidIndex = -1; // no valid index

+    current_it_idx = -1; // no valid index

   }

 

-  public void moveToNext() {

-    // No point in going anywhere if iterator is not valid.

-    if (!isValid()) {

-      return;

-    }

-    

-    FSIterator<T> it = nonEmptyIterators[lastValidIndex];

-    it.moveToNextNvc();

-

-    if (it.isValid()) {

-      return;

-    }

-    

-    final int nbrIt = nonEmptyIterators.length;

-    for (int i = lastValidIndex + 1; i < nbrIt; i++) {

-      it = nonEmptyIterators[i];

-      it.moveToFirst();

-      if (it.isValid()) {

-        lastValidIndex = i;

-        return;

-      }

-    }

-    lastValidIndex = nonEmptyIterators.length;  // invalid position

-  }

-    

   public void moveToNextNvc() {

-    FSIterator<T> it = nonEmptyIterators[lastValidIndex];

+    FSIterator<T> it = nonEmptyIterators[current_it_idx];

     it.moveToNextNvc();

 

     if (it.isValid()) {

@@ -191,130 +187,109 @@
     }

     

     final int nbrIt = nonEmptyIterators.length;

-    for (int i = lastValidIndex + 1; i < nbrIt; i++) {

+    for (int i = current_it_idx + 1; i < nbrIt; i++) {

       it = nonEmptyIterators[i];

       it.moveToFirst();

       if (it.isValid()) {

-        lastValidIndex = i;

+        current_it_idx = i;

         return;

       }

     }

-    lastValidIndex = nonEmptyIterators.length;  // invalid position

-  }

-

-  public void moveToPrevious() {

-    // No point in going anywhere if iterator is not valid.

-    if (!isValid()) {

-      return;

-    }

-    

-    moveToPreviousNvc();

+    current_it_idx = -1;  // invalid position

   }

   

   @Override

   public void moveToPreviousNvc() {

     

-    FSIterator<T> it = nonEmptyIterators[lastValidIndex];

+    LowLevelIterator<T> it = nonEmptyIterators[current_it_idx];

     it.moveToPreviousNvc();

 

     if (it.isValid()) {

       return;

     }

     

-    for (int i = lastValidIndex - 1; i >=  0; i--) {

+    for (int i = current_it_idx - 1; i >=  0; i--) {

       it = nonEmptyIterators[i];

-      it.moveToLast();

+      it.moveToLastNoReinit();

       if (it.isValid()) {

-        lastValidIndex = i;

+        current_it_idx = i;

         return;

       }

     }

-    lastValidIndex = -1;  // invalid position

+    current_it_idx = -1;  // invalid position

   }

 

-  public int ll_indexSize() {

+  public int ll_indexSizeMaybeNotCurrent() {

     int sum = 0;

     for (int i = nonEmptyIterators.length - 1; i >=  0; i--) {

       FSIterator<T> it = nonEmptyIterators[i];

-      sum += ((LowLevelIterator<T>)it).ll_indexSize();

+      sum += ((LowLevelIterator<T>)it).ll_indexSizeMaybeNotCurrent();

     }

     return sum;

   }

   

   

   public int ll_maxAnnotSpan() {

-    int span = -1;

-    for (int i = nonEmptyIterators.length - 1; i >=  0; i--) {

-      FSIterator<T> it = nonEmptyIterators[i];

-      int x = ((LowLevelIterator<T>)it).ll_maxAnnotSpan();

-      if (x > span) {

-        span = x;

-      }

-    }

-    return (span == -1) ? Integer.MAX_VALUE : span;

+    throw Misc.internalError();  // should never be called, because this operation isn't useful

+                                 // in unordered indexes

+//    int span = -1;

+//    for (int i = nonEmptyIterators.length - 1; i >=  0; i--) {

+//      FSIterator<T> it = nonEmptyIterators[i];

+//      int x = ((LowLevelIterator<T>)it).ll_maxAnnotSpan();

+//      if (x > span) {

+//        span = x;

+//      }

+//    }

+//    return (span == -1) ? Integer.MAX_VALUE : span;

   };

-

+  

   /* (non-Javadoc)

    * @see org.apache.uima.cas.FSIterator#copy()

    */

   @Override

-  public FSIterator<T> copy() {

-    final FSIterator<T>[] ai = allIterators.clone();

-    for (int i = 0; i < ai.length; i++) {

-      ai[i] = ai[i].copy();

-    }

-    

-    FsIterator_aggregation_common<T> it = new FsIterator_aggregation_common<T>(ai, index);

-    

-    if (!isValid()) {

-      it.moveToFirst();

-      it.moveToPrevious();  // make it also invalid

-    } else {

-      T targetFs = get();

-      it.moveTo(targetFs);  // moves to left-most match

-      while (targetFs != it.get()) {

-        it.moveToNext();

-      }

-    }

-    return it;

+  public FsIterator_aggregation_common<T> copy() {

+    return new FsIterator_aggregation_common<T>(this);

   }

 

-

-  @Override

-  public LowLevelIndex<T> ll_getIndex() {

-    return (LowLevelIndex<T>) index;

-  }  

-  

   @Override

   public String toString() {

-    Type type = this.ll_getIndex().getType();

+//    Type type = this.ll_getIndex().getType();

     StringBuilder sb = new StringBuilder(this.getClass().getSimpleName()).append(":").append(System.identityHashCode(this));

-    sb.append(" over Type: ").append(type.getName()).append(":").append(((TypeImpl)type).getCode());

-    sb.append(", size: ").append(this.ll_indexSize());

+    

+    if (nonEmptyIterators.length == 0) {

+      sb.append(" empty iterator");

+      return sb.toString();

+    }

+    

+    sb.append( (main_idx == null && nonEmptyIterators.length > 1) 

+                 ? " over multiple Types: "

+                 : " over type: ");

+ 

+    if (main_idx == null) {

+      if (nonEmptyIterators.length > 1) {

+        sb.append('[');

+        for (FSIterator<T> it : nonEmptyIterators) {

+          Type type = ((LowLevelIterator<T>)it).ll_getIndex().getType(); 

+          sb.append(type.getName()).append(':').append(((TypeImpl)type).getCode()).append(' ');

+        }

+        sb.append(']');

+      } else {

+        Type type = ((LowLevelIterator<T>)nonEmptyIterators[0]).ll_getIndex().getType(); 

+        sb.append(type.getName()).append(':').append(((TypeImpl)type).getCode()).append(' ');

+      }

+    } else {

+      Type type = main_idx.getType(); 

+      sb.append(type.getName()).append(':').append(((TypeImpl)type).getCode()).append(' ');

+    }

+    

+    sb.append(", iterator size (may not match current index size): ").append(this.ll_indexSizeMaybeNotCurrent());

     return sb.toString();

   }

-  

-  /* (non-Javadoc)

-   * @see org.apache.uima.cas.impl.LowLevelIterator#isIndexesHaveBeenUpdated()

-   */

-  @Override

-  public boolean isIndexesHaveBeenUpdated() {

-    for (FSIterator<T> it : allIterators) {

-      if (((LowLevelIterator)it).isIndexesHaveBeenUpdated()) {

-        return true;

-      }

-    }

-    return false;

-  }

- 

-  private int firstChangedEmptyIterator() {

-    for (int i = 0; i < emptyIterators.length; i++) {

-      FSIterator<T> it = emptyIterators[i];

-      if (((LowLevelIterator<?>)it).isIndexesHaveBeenUpdated()) {

-        return i;

-      }

-    }

-    return -1;

-  }

 

+  @Override

+  public Comparator<TOP> getComparator() {

+    return null; // This style is unordered

+  }

+  

+  

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_backwards.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_backwards.java
index 4411d9b..da57932 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_backwards.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_backwards.java
@@ -19,10 +19,12 @@
 

 package org.apache.uima.cas.impl;

 

+import java.util.Comparator;

 import java.util.NoSuchElementException;

 

 import org.apache.uima.cas.FSIterator;

 import org.apache.uima.cas.FeatureStructure;

+import org.apache.uima.jcas.cas.TOP;

 

 /**

  * Wraps FSIterator<T>, runs it backwards

@@ -38,8 +40,8 @@
   }

 

   @Override

-  public int ll_indexSize() {

-    return it.ll_indexSize();

+  public int ll_indexSizeMaybeNotCurrent() {

+    return it.ll_indexSizeMaybeNotCurrent();

   }

 

   @Override

@@ -58,48 +60,33 @@
   }

 

   @Override

-  public T get() throws NoSuchElementException {

-    return it.get();

-  }

-

-  @Override

   public T getNvc() {

     return it.getNvc();

   }

 

   @Override

-  public void moveToNext() {

-    it.moveToPrevious();

-  }

-

-  @Override

   public void moveToNextNvc() {

     it.moveToPreviousNvc();

   }

 

   @Override

-  public void moveToPrevious() {

-    it.moveToNext();

-  }

-

-  @Override

   public void moveToPreviousNvc() {

     it.moveToNextNvc();

   }

 

   @Override

-  public void moveToFirst() {

-    it.moveToLast();

+  public void moveToFirstNoReinit() {

+    it.moveToLastNoReinit();

   }

 

   @Override

-  public void moveToLast() {

-    it.moveToFirst();

+  public void moveToLastNoReinit() {

+    it.moveToFirstNoReinit();

   }

 

   @Override

-  public void moveTo(FeatureStructure fs) {

-    it.moveTo(fs);  // moves to left most of equal, or one greater

+  public void moveToNoReinit(FeatureStructure fs) {

+    it.moveToNoReinit(fs);  // moves to left most of equal, or one greater

     LowLevelIndex<T> lli = ll_getIndex();

     if (isValid()) {

       if (lli.compare(get(), fs) == 0) {

@@ -113,7 +100,7 @@
         if (isValid()) {

           it.moveToPreviousNvc();

         } else {

-          it.moveToLast();

+          it.moveToLastNoReinit();

         }

       } else {

         // is valid, but not equal - went to wrong side

@@ -121,10 +108,15 @@
       }

     } else {

       // moved to one past the end.  Backwards: would be at the (backwards) first position

-      it.moveToLast();

+      it.moveToLastNoReinit();

     }

   }

 

+//  @Override

+//  public void moveToExactNoReinit(FeatureStructure fs) {

+//    it.moveToExactNoReinit(fs); 

+//  }

+

   @Override

   public FSIterator<T> copy() {

     return new FsIterator_backwards<T>(it.copy());

@@ -138,4 +130,14 @@
     return it.isIndexesHaveBeenUpdated();

   }

 

+  @Override

+  public boolean maybeReinitIterator() {

+    return it.maybeReinitIterator();

+  }

+

+  @Override

+  public Comparator<TOP> getComparator() {

+    return it.getComparator();

+  }

+

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_bag.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_bag.java
index de4f016..fed2513 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_bag.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_bag.java
@@ -19,27 +19,44 @@
 

 package org.apache.uima.cas.impl;

 

+import java.util.Comparator;

 import java.util.NoSuchElementException;

+import java.util.concurrent.atomic.AtomicInteger;

 

+import org.apache.uima.UIMAFramework;

 import org.apache.uima.cas.FeatureStructure;

 import org.apache.uima.internal.util.CopyOnWriteObjHashSet;

+import org.apache.uima.internal.util.Misc;

 import org.apache.uima.jcas.cas.TOP;

 

 class FsIterator_bag<T extends FeatureStructure> extends FsIterator_singletype<T> {

 

-  private CopyOnWriteObjHashSet<TOP> bag;

+  private static final AtomicInteger moveToCount = new AtomicInteger(0);

+  

+  protected CopyOnWriteObjHashSet<TOP> bag;

+  final protected FsIndex_bag<T> fsBagIndex; // just an optimization, is == to fsLeafIndexImpl from super class, allows dispatch w/o casting

   

   private int position = -1;  

   

   private boolean isGoingForward = true;

+  

 

-  final protected FsIndex_bag<T> fsBagIndex; // just an optimization, is == to fsLeafIndexImpl from super class, allows dispatch w/o casting

 

-  FsIterator_bag(FsIndex_bag<T> fsBagIndex, TypeImpl ti) {

-    super(ti, null);  // null: null comparator for bags

+  FsIterator_bag(FsIndex_bag<T> fsBagIndex, TypeImpl ti, CopyOnWriteIndexPart cow_wrapper) {

+    super(ti);

     this.fsBagIndex = fsBagIndex;  // need for copy()

+    bag = (CopyOnWriteObjHashSet<TOP>) cow_wrapper;

     moveToFirst();

   }

+  

+  public boolean maybeReinitIterator() {

+    if (!bag.isOriginal()) {

+      bag = (CopyOnWriteObjHashSet<TOP>) fsBagIndex.getNonNullCow();

+      return true;

+    }

+    return false;

+  }

+

 

   /* (non-Javadoc)

    * @see org.apache.uima.cas.FSIterator#isValid()

@@ -49,18 +66,6 @@
     return (position >= 0) && (position < bag.getCapacity());

   }

 

-  /* (non-Javadoc)

-   * @see org.apache.uima.cas.FSIterator#get()

-   */

-  @Override

-  public T get() {

-//    checkConcurrentModification();

-    if (isValid()) {

-      return (T) bag.get(position);

-    }

-    throw new NoSuchElementException();

-  }

-

   @Override

   public T getNvc() {

 //    checkConcurrentModification();

@@ -71,36 +76,22 @@
    * @see org.apache.uima.cas.FSIterator#moveToFirst()

    */

   @Override

-  public void moveToFirst() {

-    bag = (CopyOnWriteObjHashSet<TOP>) fsBagIndex.getNonNullCow();

-    resetConcurrentModification();

+  public void moveToFirstNoReinit() {

+//    resetConcurrentModification();

     isGoingForward = true;

     position = (bag.size() == 0) ? -1 : bag.moveToNextFilled(0);

   }

-

+  

   /* (non-Javadoc)

    * @see org.apache.uima.cas.FSIterator#moveToLast()

    *  If empty, make position -1 (invalid)

    */

   @Override

-  public void moveToLast() {

-    bag = (CopyOnWriteObjHashSet<TOP>) fsBagIndex.getNonNullCow();

-    resetConcurrentModification();

+  public void moveToLastNoReinit() {

+//    resetConcurrentModification();

     isGoingForward = false;

     position =  (bag.size() == 0) ? -1 : bag.moveToPreviousFilled(bag.getCapacity() -1);

   }

-

-  /* (non-Javadoc)

-   * @see org.apache.uima.cas.FSIterator#moveToNext()

-   */

-  @Override

-  public void moveToNext() {

-//    checkConcurrentModification(); 

-    if (isValid()) {

-      isGoingForward = true;

-      position = bag.moveToNextFilled(++position);

-    }

-  }

   

   @Override

   public void moveToNextNvc() {

@@ -109,19 +100,6 @@
     position = bag.moveToNextFilled(++position);

   }

 

-

-  /* (non-Javadoc)

-   * @see org.apache.uima.cas.FSIterator#moveToPrevious()

-   */

-  @Override

-  public void moveToPrevious() {

-//    checkConcurrentModification();

-    if (isValid()) {

-      isGoingForward = false;

-      position = bag.moveToPreviousFilled(--position);

-    }

-  }

-

   @Override

   public void moveToPreviousNvc() {

 //    checkConcurrentModification();

@@ -133,18 +111,29 @@
    * @see org.apache.uima.cas.FSIterator#moveTo(org.apache.uima.cas.FeatureStructure)

    */

   @Override

-  public void moveTo(FeatureStructure fs) {

-    bag = (CopyOnWriteObjHashSet<TOP>) fsBagIndex.getNonNullCow();

-    resetConcurrentModification();

+  public void moveToNoReinit(FeatureStructure fs) {

+//    throw new UnsupportedOperationException("MoveTo operations for unordered iterators is not supported");

+    Misc.decreasingWithTrace(moveToCount, "MoveTo operations on iterators over Bag indexes are likely mistakes." , UIMAFramework.getLogger());

+//    resetConcurrentModification();

+    // for backwards compatibility

     position = bag.moveTo(fs);

+    if (position >= 0) {

+      if (getNvc() == null) {

+        position = -1; // mark invalid

+      }

+    }

   }

-  

+

+//  public void moveToExactNoReinit(FeatureStructure fs) {

+//    position = bag.moveTo(fs);

+//  }

+

   /* (non-Javadoc)

    * @see org.apache.uima.cas.FSIterator#copy()

    */

   @Override

   public FsIterator_bag<T> copy() {

-    FsIterator_bag<T> copy = new FsIterator_bag<T>(this.fsBagIndex, this.ti);

+    FsIterator_bag<T> copy = new FsIterator_bag<T>(this.fsBagIndex, this.ti, bag);

     copyCommonSetup(copy);

     return copy;

   }

@@ -158,7 +147,7 @@
    * @see org.apache.uima.cas.impl.LowLevelIterator#ll_indexSize()

    */  

   @Override

-  public int ll_indexSize() {

+  public int ll_indexSizeMaybeNotCurrent() {

     return bag.size();

   }

 

@@ -175,13 +164,13 @@
     return fsBagIndex;

   }

 

-  /* (non-Javadoc)

-   * @see org.apache.uima.cas.impl.FsIterator_singletype#getModificationCountFromIndex()

-   */

-  @Override

-  protected int getModificationCountFromIndex() {

-    return bag.getModificationCount();

-  }

+//  /* (non-Javadoc)

+//   * @see org.apache.uima.cas.impl.FsIterator_singletype#getModificationCountFromIndex()

+//   */

+//  @Override

+//  protected int getModificationCountFromIndex() {

+//    return bag.getModificationCount();

+//  }

 

   /* (non-Javadoc)

    * @see org.apache.uima.cas.impl.LowLevelIterator#isIndexesHaveBeenUpdated()

@@ -191,5 +180,10 @@
     return bag != fsBagIndex.getCopyOnWriteIndexPart();

   }

 

+  @Override

+  public Comparator<TOP> getComparator() {

+    return null;  // not used for bag

+  }

+  

 }

 

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_bag_pear.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_bag_pear.java
index d40490f..27cba09 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_bag_pear.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_bag_pear.java
@@ -31,23 +31,18 @@
  */

 class FsIterator_bag_pear<T extends FeatureStructure> extends FsIterator_bag<T> {

 

-  FsIterator_bag_pear(FsIndex_bag<T> fsBagIndex, TypeImpl ti) {

-    super(fsBagIndex, ti);

+  FsIterator_bag_pear(FsIndex_bag<T> fsBagIndex, TypeImpl ti, CopyOnWriteIndexPart cow_wrapper) {

+    super(fsBagIndex, ti, cow_wrapper);

   }    

 

   @Override

-  public T get() {

-    return CASImpl.pearConvert(super.get());

-  }

-

-  @Override

   public T getNvc() {

     return CASImpl.pearConvert(super.getNvc());

   }

   

   @Override

   public FsIterator_bag_pear<T> copy() {

-    FsIterator_bag_pear<T> copy = new FsIterator_bag_pear<T>(this.fsBagIndex, this.ti);

+    FsIterator_bag_pear<T> copy = new FsIterator_bag_pear<T>(this.fsBagIndex, this.ti, this.bag );

     copyCommonSetup(copy);

     return copy;

   }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_limited.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_limited.java
index 80af58c..f3e74eb 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_limited.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_limited.java
@@ -19,10 +19,10 @@
 

 package org.apache.uima.cas.impl;

 

-import java.util.NoSuchElementException;

-

+import java.util.Comparator;

 import org.apache.uima.cas.FSIterator;

 import org.apache.uima.cas.FeatureStructure;

+import org.apache.uima.jcas.cas.TOP;

 

 /**

  * Wraps FSIterator<T>, limits results to n gets

@@ -41,72 +41,70 @@
 

   private void maybeMakeInvalid() {

     if (count == limit) {

-      iterator.moveToFirst();

+      iterator.moveToFirstNoReinit();

       iterator.moveToPrevious();

     }

   }

   

-  public T get() throws NoSuchElementException {

-    maybeMakeInvalid();

-    T r = iterator.get();

-    count++;  

-    return r;

-  }

-

+  @Override

   public T getNvc() {

     maybeMakeInvalid();

-    T r = iterator.getNvc();

+    T r = iterator.get();  // not getNvc because of above line

     count++;

     return r;

   }

 

-  public void moveToNext() {

-    maybeMakeInvalid();

-    iterator.moveToNext();

-  }

-

+  @Override

   public void moveToNextNvc() {

     maybeMakeInvalid();

-    iterator.moveToNextNvc();

+    iterator.moveToNext();   // not getNvc because of above line

   }

 

-  public void moveToPrevious() {

-    maybeMakeInvalid();

-    iterator.moveToPrevious();

-  }

-

+  @Override

   public void moveToPreviousNvc() {

     maybeMakeInvalid();

-    iterator.moveToPreviousNvc();

+    iterator.moveToPrevious();  // not getNvc because of above line

   }

 

-  public void moveToFirst() {

-    iterator.moveToFirst();

+  @Override

+  public void moveToFirstNoReinit() {

+    iterator.moveToFirstNoReinit();

     maybeMakeInvalid();

   }

 

-  public void moveToLast() {

-    iterator.moveToLast();

+  @Override

+  public void moveToLastNoReinit() {

+    iterator.moveToLastNoReinit();

     maybeMakeInvalid();

   }

 

-  public void moveTo(FeatureStructure fs) {

-    iterator.moveTo(fs);

+  @Override

+  public void moveToNoReinit(FeatureStructure fs) {

+    iterator.moveToNoReinit(fs);

     maybeMakeInvalid();

   }

 

+//  @Override

+//  public void moveToExactNoReinit(FeatureStructure fs) {

+//    iterator.moveToExactNoReinit(fs);

+//    maybeMakeInvalid();

+//  }

+

+

+  @Override

   public FSIterator<T> copy() {

     return new FsIterator_limited<T>(iterator.copy(), limit);

   }

 

+  @Override

   public boolean isValid() {

     maybeMakeInvalid();

     return iterator.isValid();

   }

 

   @Override

-  public int ll_indexSize() {

-    return iterator.ll_indexSize();

+  public int ll_indexSizeMaybeNotCurrent() {

+    return iterator.ll_indexSizeMaybeNotCurrent();

   }

 

   @Override

@@ -127,4 +125,14 @@
     return iterator.isIndexesHaveBeenUpdated();

   }

 

+  @Override

+  public boolean maybeReinitIterator() {

+    return iterator.maybeReinitIterator();

+  }

+

+  @Override

+  public Comparator<TOP> getComparator() {

+    return iterator.getComparator();

+  }

+

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_multiple_indexes.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_multiple_indexes.java
new file mode 100644
index 0000000..bc7e5e5
--- /dev/null
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_multiple_indexes.java
@@ -0,0 +1,196 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.cas.impl;

+

+import java.util.ArrayList;

+import java.util.Comparator;

+

+import org.apache.uima.cas.FeatureStructure;

+import org.apache.uima.jcas.cas.TOP;

+

+/**

+ * Common code for both

+ *   aggregation of indexes (e.g. select, iterating over multiple views)

+ *   aggregation of indexes in type/subtype hierarchy

+ *

+ * Supports creating corresponding iterators just for the non-empty ones

+ * Supports reinit - evaluating when one or more formerly empty indexes is no longer empty, and recalculating the 

+ *                   iterator set

+ *                   

+ * Supports move-to-leftmost when typeOrdering is to be ignored

+ *   -- when no typeorder key

+ *   -- when typeorder key, but select framework requests no typeordering for move to leftmost

+ *   

+ * @param <T> the highest type returned by these iterators

+ */

+public abstract class FsIterator_multiple_indexes <T extends FeatureStructure>  implements LowLevelIterator<T> {

+

+  // An array of iterators, one for each in the collection (e.g. subtypes, or views or ...)

+  // split among empty and non-empty.

+  final protected LowLevelIterator<T>[] allIterators;

+  private LowLevelIterator<T>[] emptyIterators;

+  protected LowLevelIterator<T> [] nonEmptyIterators;

+  

+  /** 

+   * for set and sorted, both ignore id 

+   *   because this comparator is not used for comparing within the index, only for

+   *   compares between index items and outside args.

+   * if ignoring type, uses that style 

+   */

+  final protected Comparator<TOP> comparatorMaybeNoTypeWithoutId; 

+//  final protected boolean ignoreType_moveToLeftmost;

+

+  final protected LowLevelIndex<T> main_idx;

+  

+//  /** true if sorted index, with typepriority as a key, but ignoring it because

+//   *    either there are no type priorities defined, or

+//   *    using a select-API-created iterator configured without typePriority

+//   *    

+//   *  Not final for the use case where there's a type-order key, type priorities are specified,

+//   *  but a select-API-created iterator wants to ignore type priorities.

+//   */

+//  final protected boolean isSortedTypeOrder_but_IgnoringTypeOrder; 

+   

+  public FsIterator_multiple_indexes(LowLevelIndex<T> main_idx, 

+                                     LowLevelIterator<T>[] iterators,

+//                                     boolean ignoreType_moveToLeftmost) {

+                                     Comparator<TOP> comparatorMaybeNoTypeWithoutId) {

+    this.allIterators = iterators;

+    this.main_idx = main_idx;

+    this.comparatorMaybeNoTypeWithoutId = comparatorMaybeNoTypeWithoutId;

+    separate_into_empty_indexes_and_non_empty_iterators();

+  }

+  

+  /**

+  /**

+   *  copy constructor 

+   * @param v the original to copy

+   */

+  public FsIterator_multiple_indexes(FsIterator_multiple_indexes<T> v) {

+    allIterators = v.allIterators.clone();

+    this.main_idx = v.main_idx;

+    this.comparatorMaybeNoTypeWithoutId = v.comparatorMaybeNoTypeWithoutId;

+    int i = 0;

+    for (LowLevelIterator<T> it : allIterators) {

+      allIterators[i++] = (LowLevelIterator<T>) it.copy();

+    }   

+    separate_into_empty_indexes_and_non_empty_iterators();

+  }

+  

+  /**

+   * Also resets all non-empty iterators to current values

+   */

+  protected void separate_into_empty_indexes_and_non_empty_iterators() {

+        

+    ArrayList<LowLevelIterator<T>> emptyIteratorsAl = new ArrayList<>();

+    ArrayList<LowLevelIterator<T>> nonEmptyIteratorsAl = new ArrayList<>();

+    for (LowLevelIterator<T> it : allIterators) {

+      LowLevelIndex<T> idx = it.ll_getIndex();

+      if (idx == null || idx.size() == 0) {

+        emptyIteratorsAl.add(it);  

+      } else {

+        nonEmptyIteratorsAl.add(it); 

+      }

+    }

+    

+    emptyIterators    = emptyIteratorsAl   .toArray(new LowLevelIterator[emptyIteratorsAl   .size()]);

+    nonEmptyIterators = nonEmptyIteratorsAl.toArray(new LowLevelIterator[nonEmptyIteratorsAl.size()]);

+  }

+    

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.LowLevelIterator#ll_indexSize()

+   */

+  @Override

+  public int ll_indexSizeMaybeNotCurrent() {

+    int sz = 0;

+    for (LowLevelIterator<T> it : nonEmptyIterators) {

+      sz += it.ll_indexSizeMaybeNotCurrent();      

+    }

+    return sz;

+  }

+  

+  @Override

+  public int ll_maxAnnotSpan() {

+    int span = -1;

+    for (LowLevelIterator<T> it : nonEmptyIterators) {

+      int s = it.ll_maxAnnotSpan();

+      if (s == Integer.MAX_VALUE) {

+        return s;

+      }

+      if (s > span) {

+        span = s;

+      }

+    }

+    return (span == -1) ? Integer.MAX_VALUE : span;

+  }

+

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.LowLevelIterator#isIndexesHaveBeenUpdated()

+   */

+  @Override

+  public boolean isIndexesHaveBeenUpdated() {

+    for (LowLevelIterator<T> it : nonEmptyIterators) {

+      if (it.isIndexesHaveBeenUpdated()) {

+        return true;

+      }

+    } 

+    

+    return empty_became_nonEmpty();  // slightly better than testing isIndexesHaveBeenUpdated

+                                     // because if it went from empty -> not empty -> empty, 

+                                     // is not counted as having been updated for this purpose

+  }

+  

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.LowLevelIterator#maybeReinitIterator()

+   */

+  @Override

+  public boolean maybeReinitIterator() {

+    boolean empty_became_nonEmpty = empty_became_nonEmpty();

+    if (empty_became_nonEmpty) {

+      separate_into_empty_indexes_and_non_empty_iterators();

+    }

+    

+    boolean any = false;

+    for (LowLevelIterator<T> it : nonEmptyIterators) {

+      any |= it.maybeReinitIterator();  // need to call on all, in order to reinit them if needed

+    }

+    return any;

+  }

+

+  

+  private boolean empty_became_nonEmpty() {

+    for (LowLevelIterator<T> it : emptyIterators) {

+      if (it.ll_getIndex().size() > 0) {  // don't test changed  might have had insert then delete...

+        return true;

+      }

+    }

+    return false;

+  }

+  

+  @Override

+  public LowLevelIndex<T> ll_getIndex() {

+    return (LowLevelIndex<T>)

+             ((main_idx != null)

+                ? main_idx 

+                : ((LowLevelIterator<T>)allIterators[0]).ll_getIndex());

+  }  

+

+  

+}

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_set_sorted2.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_set_sorted2.java
new file mode 100644
index 0000000..cb5f074
--- /dev/null
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_set_sorted2.java
@@ -0,0 +1,321 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.cas.impl;

+

+import java.util.Comparator;

+

+import org.apache.uima.cas.FeatureStructure;

+import org.apache.uima.internal.util.CopyOnWriteOrderedFsSet_array;

+import org.apache.uima.internal.util.Misc;

+import org.apache.uima.jcas.cas.TOP;

+

+/**

+ * An interator for 1 type for a set or sorted index

+ * 

+ * NOTE: This is the version used for set/sorted iterators

+ *   It is built directly on top of a CopyOnWrite wrapper for OrderedFsSet_array

+ *   It uses the version of OrdereFsSet_array that has no embedded nulls

+ * @param <T> the type of FSs being returned from the iterator, supplied by the calling context

+ */

+class FsIterator_set_sorted2<T extends FeatureStructure> extends FsIterator_singletype<T> {

+

+  // not final, because on moveToFirst/Last/FS, the semantics dictate that 

+  // if the underlying index was updated, this should iterate over that.

+  protected CopyOnWriteOrderedFsSet_array ofsa;  // orderedFsSet_array;

+  

+  private int pos;

+

+  protected final FsIndex_set_sorted<T> ll_index;

+   

+  /**

+   * if the iterator is configured to ignore TypeOrdering, then

+   * the comparator omits the type (if the index has a type order key)

+   */

+  protected final Comparator<TOP> comparatorMaybeNoTypeWithoutID;  

+  

+  public FsIterator_set_sorted2(FsIndex_set_sorted<T> ll_index, CopyOnWriteIndexPart cow_wrapper, Comparator<TOP> comparatorMaybeNoTypeWithoutID) {

+    super((TypeImpl)ll_index.getType());

+    this.comparatorMaybeNoTypeWithoutID = comparatorMaybeNoTypeWithoutID;

+    

+    this.ll_index = ll_index;

+    ofsa = (CopyOnWriteOrderedFsSet_array) cow_wrapper;

+    pos = ofsa.a_firstUsedslot;

+//    incrToSkipOverNulls(); 

+//    if (MEASURE) {

+//      int s = ofsa.a_nextFreeslot - ofsa.a_firstUsedslot;

+//      iterPctEmptySkip[(s - ofsa.size()) * 10 / s] ++;

+//    }   

+  }

+  

+  @Override

+  public boolean maybeReinitIterator() {

+    if (!ofsa.isOriginal()) {

+      // can't share this copy with other iterators - they may have not done a moveToFirst, etc.

+      //   and need to continue with the previous view

+      ofsa = (CopyOnWriteOrderedFsSet_array) ll_index.getNonNullCow();

+      return true;

+    }

+    return false;

+  }

+

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.FSIterator#isValid()

+   */

+  @Override

+  public boolean isValid() {

+    return pos >= ofsa.a_firstUsedslot && pos < ofsa.a_nextFreeslot;

+  }

+

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.FSIterator#getNvc()

+   */

+  @Override

+  public T getNvc() {

+    return (T) ofsa.a[pos];

+  }

+

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.FSIterator#moveToNextNvc()

+   */

+  @Override

+  public void moveToNextNvc() {

+    pos++;

+//    incrToSkipOverNulls();

+  }

+

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.FSIterator#moveToPreviousNvc()

+   */

+  @Override

+  public void moveToPreviousNvc() {

+    pos--;

+//    decrToSkipOverNulls();

+  }

+  

+  // Internal use

+  @Override

+  public void moveToFirstNoReinit() {

+    pos = ofsa.a_firstUsedslot;

+  }

+  

+  // Internal use

+  @Override

+  public void moveToLastNoReinit() {

+    pos = ofsa.a_nextFreeslot - 1;       

+  }

+  

+  // Internal use

+  @Override

+  public void moveToNoReinit(FeatureStructure fs) {

+    pos = ofsa.getOfsa().find((TOP) fs, comparatorMaybeNoTypeWithoutID); 

+

+    if (pos < 0) {

+      pos = (-pos) -1;  // insertion point, one above

+      return;

+    }

+    

+    int savedPos = pos;

+    

+    // pos is the equal-with-id item

+

+    moveToPreviousNvc();

+    if (isValid()) {

+      if (0 == comparatorMaybeNoTypeWithoutID.compare((TOP)get(), (TOP) fs)) {

+        moveToLeftMost(fs);

+      } else {

+        // did not compare equal, so previous was the right position

+        pos = savedPos;

+      }

+    } else {

+      // went one before start, restore to start

+      pos = savedPos;

+    }

+    return;   

+  }

+

+//  // Internal use

+//  public void moveToExactNoReinit(FeatureStructure fs) {

+//    pos = ofsa.getOfsa().find((TOP) fs);  // find == find with ID 

+//    // if not found, this will be negative marking iterator invalid

+//  }

+

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.FSIterator#copy()

+   */

+  @Override

+  public FsIterator_singletype<T> copy() {

+    FsIterator_set_sorted2<T> r = new FsIterator_set_sorted2<>(ll_index, ofsa, comparatorMaybeNoTypeWithoutID);

+    r.pos = pos;

+    return r;

+  }

+

+//  /* (non-Javadoc)

+//   * @see org.apache.uima.cas.FSIterator#getType()

+//   */

+//  @Override

+//  public Type getType() {

+//    // TODO Auto-generated method stub

+//    return LowLevelIterator.super.getType();

+//  }

+

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.LowLevelIterator#ll_indexSize()

+   */

+  @Override

+  public int ll_indexSizeMaybeNotCurrent() {

+    return ofsa.size();

+  }

+

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.LowLevelIterator#ll_getIndex()

+   */

+  @Override

+  public LowLevelIndex<T> ll_getIndex() {

+    return ll_index;

+  }

+

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.LowLevelIterator#ll_maxAnnotSpan()

+   */

+  @Override

+  public int ll_maxAnnotSpan() {

+    FsIndex_set_sorted<T> ss_idx = ll_index;

+    return ss_idx.isAnnotIdx 

+        ? ss_idx.ll_maxAnnotSpan()

+        : Integer.MAX_VALUE;

+  }

+

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.LowLevelIterator#isIndexesHaveBeenUpdated()

+   * This is local to this class because it references the ofsa

+   */

+  @Override

+  public boolean isIndexesHaveBeenUpdated() {

+    return ofsa != ll_index.getCopyOnWriteIndexPart();

+  }

+      

+//  private void incrToSkipOverNulls() {

+//    while (pos < ofsa.a_nextFreeslot) {

+//      if (ofsa.a[pos] != null) {

+//        break;

+//      }

+//      pos ++;

+//    }

+//  }

+//

+//  private void decrToSkipOverNulls() {

+//    while (pos >= ofsa.a_firstUsedslot) {

+//      if (ofsa.a[pos] != null) {

+//        break;

+//      }

+//      pos --;

+//    }

+//  }

+  

+  /**

+   * Starting at a position where the item is equal to fs

+   * using the compare without id, 

+   * move to the leftmost one

+   * 

+   * search opportunistically, starting at 1 before, 2, 4, 8, 16, etc.

+   * then doing binary search in the opposite dir

+   * 

+   * These methods are in this class because they manipulate "pos"

+   * @param fs -

+   */

+  private void moveToLeftMost(FeatureStructure fs) {

+    

+    // adjust to move to left-most equal item

+    boolean comparedEqual = false;

+    int origPos = pos;

+    int span = 1;

+    while (isValid()) {

+      int upperValidPos = pos;

+      pos = origPos - span;

+      pos = Math.max(-1,  pos);

+//      decrToSkipOverNulls();

+      if (!isValid()) {

+        moveToLeftMostUp(fs, upperValidPos);

+        return;

+      }

+      comparedEqual = (0 == comparatorMaybeNoTypeWithoutID.compare((TOP)get(), (TOP) fs));

+      if (!comparedEqual) {

+        moveToLeftMostUp(fs, upperValidPos);

+        return;

+      }

+      span = span << 1;

+    }

+  }

+  

+  /**

+   * Must be possible to leave the pos == to upperValidPos.

+   * Starts searching from next above current pos

+   * @param fs

+   * @param upperValidPos

+   */

+  private void moveToLeftMostUp(FeatureStructure fs, int upperValidPos) {

+    if (pos < ofsa.a_firstUsedslot) {

+      moveToFirst();

+    } else {

+      moveToNext();

+    }

+    // binary search between pos (inclusive) and upperValidPos (exclusive)

+    if (!isValid()) {

+      Misc.internalError();

+    }

+    if (pos == upperValidPos) {

+      return;

+    }

+    pos = ofsa.getOfsa().binarySearchLeftMostEqual((TOP) fs, pos, upperValidPos, comparatorMaybeNoTypeWithoutID);

+  }

+  

+  @Override

+  public Comparator<TOP> getComparator() {

+    return comparatorMaybeNoTypeWithoutID;

+  }

+

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.LowLevelIterator#moveToSupported()

+   */

+  @Override

+  public boolean isMoveToSupported() {

+    return this.ll_getIndex().isSorted();

+  }

+

+//  @Override

+//  protected int getModificationCountFromIndex() {

+//    return ofsa.getModificationCount();

+//  }

+  

+//  /**

+//   * Never returns an index to a "null" (deleted) item.

+//   * If all items are LT key, returns - size - 1 

+//   * @param fs the key

+//   * @return the lowest position whose item is equal to or greater than fs;

+//   *         if not equal, the item's position is returned as -insertionPoint - 1. 

+//   *         If the key is greater than all elements, return -size - 1). 

+//   */

+//  private int find(TOP fs) {

+//    return ofsa.getOfsa().find(fs);

+//  }

+  

+

+}

+

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_set_sorted_pear.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_set_sorted_pear.java
index 452de52..44d3a00 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_set_sorted_pear.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_set_sorted_pear.java
@@ -20,27 +20,22 @@
 package org.apache.uima.cas.impl;

 

 import java.util.Comparator;

-import java.util.Iterator;

-import java.util.NavigableSet;

-import java.util.NoSuchElementException;

 

 import org.apache.uima.cas.FeatureStructure;

-import org.apache.uima.internal.util.OrderedFsSet_array;

 import org.apache.uima.jcas.cas.TOP;

 

 /**

  * @param <T> the type of FSs being returned from the iterator, supplied by the calling context

  */

-class FsIterator_set_sorted_pear<T extends FeatureStructure> extends FsIterator_set_sorted<T> {

-

-  FsIterator_set_sorted_pear(FsIndex_set_sorted<T> fsSetSortIndex, TypeImpl ti, Comparator<FeatureStructure> comp) {

-    super(fsSetSortIndex, ti, comp);

-  }    

-

-  @Override

-  public T get() {

-    return CASImpl.pearConvert(super.get());

+class FsIterator_set_sorted_pear<T extends FeatureStructure> extends FsIterator_set_sorted2<T> {

+  

+  FsIterator_set_sorted_pear(FsIndex_set_sorted<T> ll_index, CopyOnWriteIndexPart cow_wrapper, Comparator<TOP> comparatorMaybeNoTypeWithoutID) {

+    super(ll_index, cow_wrapper, comparatorMaybeNoTypeWithoutID);

   }

+  

+//  FsIterator_set_sorted_pear createInstance(OrderedFsSet_array orderedFsSet_array, LowLevelIndex ll_index) {

+//    orderedFsSet_array.new LL_Iterator(ll_index);

+//  }    

 

   @Override

   public T getNvc() {

@@ -49,6 +44,6 @@
 

   @Override

   public FsIterator_set_sorted_pear<T> copy() {

-    return new FsIterator_set_sorted_pear<T>(this.fsSetSortIndex, ti, this.comparator);

+    return new FsIterator_set_sorted_pear<T>(ll_index, ofsa, this.comparatorMaybeNoTypeWithoutID);

   }

 }
\ No newline at end of file
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_singletype.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_singletype.java
index 3f9112d..537a941 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_singletype.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_singletype.java
@@ -19,18 +19,13 @@
 

 package org.apache.uima.cas.impl;

 

-import java.util.Comparator;

-import java.util.ConcurrentModificationException;

-

-import org.apache.uima.cas.FSIterator;

 import org.apache.uima.cas.FeatureStructure;

 import org.apache.uima.cas.Type;

 

 public abstract class FsIterator_singletype<T extends FeatureStructure>

-                    implements LowLevelIterator<T>, 

-                               Comparable<FsIterator_singletype<T>> {

+                    implements LowLevelIterator<T> {

 

-  private int modificationSnapshot; // to catch illegal modifications

+//  private int modificationSnapshot; // to catch illegal modifications

 

 //  /**

 //   * This is a ref to the shared value in the FSIndexRepositoryImpl

@@ -41,22 +36,23 @@
 

   protected final TypeImpl ti;  

   

-  /**

-   * The generic type is FeatureStructure to allow comparing between

-   * an instance of T and some other template type which can be a supertype of T, as long as

-   * the keys are defined in both.

-   */

-  final protected Comparator<FeatureStructure> comparator;

+//  /**

+//   * The generic type is FeatureStructure to allow comparing between

+//   * an instance of T and some other template type which can be a supertype of T, as long as

+//   * the keys are defined in both.

+//   */

+//  final protected Comparator<TOP> comparatorWithoutID;

 

-  public FsIterator_singletype(TypeImpl ti, Comparator<FeatureStructure> comparator){

-    this.comparator = comparator;

+  public FsIterator_singletype(TypeImpl ti){

+//    this.comparatorWithoutID = comparatorWithoutID;

 //    this.detectIllegalIndexUpdates = detectConcurrentMods;

     this.ti = ti;

 //    resetConcurrentModification();  // can't do here, each subtype must finish it's initialization first

     // subtypes do moveToFirst after they finish initialization

   }

 

-  protected abstract int getModificationCountFromIndex();

+  

+//  protected abstract int getModificationCountFromIndex();

   

 //  final protected <I extends FSIterator<T>> I checkConcurrentModification() {

 //    if (modificationSnapshot != getModificationCountFromIndex()) {

@@ -74,18 +70,18 @@
     }

   }

   

-  protected void resetConcurrentModification() {  

-    this.modificationSnapshot = // (null == this.detectIllegalIndexUpdates) ? 0 : this.detectIllegalIndexUpdates[typeCode];

-                              getModificationCountFromIndex();

-  }

+//  protected void resetConcurrentModification() {  

+//    this.modificationSnapshot = // (null == this.detectIllegalIndexUpdates) ? 0 : this.detectIllegalIndexUpdates[typeCode];

+//                              getModificationCountFromIndex();

+//  }

 

-  @Override

-  public int compareTo(FsIterator_singletype<T> o) {

-    if (comparator != null) {

-      return comparator.compare(this.get(), o.get());

-    } 

-    return Integer.compare(this.get()._id(), o.get()._id());

-  }

+//  @Override

+//  public int compareTo(FsIterator_singletype<T> o) {

+//    if (comparatorWithoutID != null) {

+//      return comparatorWithoutID.compare((TOP)this.get(), (TOP)o.get());

+//    } 

+//    return Integer.compare(this.get()._id(), o.get()._id());

+//  }

    

   @Override

   public abstract FsIterator_singletype<T> copy();

@@ -95,8 +91,8 @@
     Type type = ti;

     StringBuilder sb = new StringBuilder(this.getClass().getSimpleName()).append(":").append(System.identityHashCode(this));

     sb.append(" over Type: ").append(type.getName()).append(":").append(ti.getCode());

-    sb.append(", size: ").append(this.ll_indexSize());

+    sb.append(", index size (may not match current index size): ").append(this.ll_indexSizeMaybeNotCurrent());

     return sb.toString();

-  }

-  

+  } 

+    

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_subtypes_list.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_subtypes_list.java
deleted file mode 100644
index a0616dd..0000000
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_subtypes_list.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*

- * Licensed to the Apache Software Foundation (ASF) under one

- * or more contributor license agreements.  See the NOTICE file

- * distributed with this work for additional information

- * regarding copyright ownership.  The ASF licenses this file

- * to you under the Apache License, Version 2.0 (the

- * "License"); you may not use this file except in compliance

- * with the License.  You may obtain a copy of the License at

- * 

- *   http://www.apache.org/licenses/LICENSE-2.0

- * 

- * Unless required by applicable law or agreed to in writing,

- * software distributed under the License is distributed on an

- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

- * KIND, either express or implied.  See the License for the

- * specific language governing permissions and limitations

- * under the License.

- */

-

-package org.apache.uima.cas.impl;

-

-import java.util.ArrayList;

-

-import org.apache.uima.cas.FSIterator;

-import org.apache.uima.cas.FeatureStructure;

-

-public abstract class FsIterator_subtypes_list <T extends FeatureStructure>  extends FsIterator_subtypes<T> {

-

-  // An array of iterators, one for each subtype.

-  //   This array has the indexes for all the subtypes that were non-empty at the time of iterator creation

-  protected FsIterator_singletype<T>[] nonEmptyIterators;

-  private FsIterator_singletype<T>[] emptyIterators;

-  protected FsIterator_singletype<T>[] allIterators;

-

-  protected int lastValidIndex = 0;

-   

-  public FsIterator_subtypes_list(FsIndex_iicp<T> iicp) {

-    super(iicp);

-    this.nonEmptyIterators = initIterators();

-//    can't do moveToFirst, subtypes haven't yet set up enough things (like comparator)

-    // subtypes must do this call after setup complete

-//    moveToFirst();  // needed in order to set up lastvalid index, etc.

-  }

-  

-  // skip including iterators for empty indexes

-  //   The concurrent modification exception notification doesn't occur when subsequent "adds" are done, but

-  //   that is the same as current: 

-  //   where the move to first would mark the iterator "invalid" (because it was initially empty) and it would be

-  //     subsequently ignored - same effect

-  protected FsIterator_singletype<T>[] initIterators() {

-    iicp.createIndexIteratorCache();

-    final FsIndex_singletype<FeatureStructure>[] cachedSubIndexes = iicp.cachedSubFsLeafIndexes;

-        

-//    FsIterator_singletype<T>[] r = cachedSubIndexes.stream()

-//        .filter(leafIndex -> leafIndex.size() > 0)  // filter out empty ones     

-//        .map( index -> index.iterator())  // map fsIndex_singletype to an iterator over that

-//        .toArray(FsIterator_singletype[]::new);

-

-    ArrayList<FsIterator_singletype<T>> nonEmptyItr = new ArrayList<>();

-    ArrayList<FsIterator_singletype<T>> emptyItr = new ArrayList<>();

-    

-    for (FsIndex_singletype<FeatureStructure> leafIndex : iicp.cachedSubFsLeafIndexes) {

-      if (leafIndex.size() == 0) {

-        emptyItr.add((FsIterator_singletype<T>) leafIndex.iterator());

-      } else {

-        nonEmptyItr.add((FsIterator_singletype<T>) leafIndex.iterator());

-      }

-    }

-    

-    emptyIterators = emptyItr.toArray(new FsIterator_singletype[emptyItr.size()]);

-

-    FsIterator_singletype[] localNonEmptyIterators 

-                   = nonEmptyItr.toArray(new FsIterator_singletype[nonEmptyItr.size()]);

-    

-    allIterators = new FsIterator_singletype[emptyItr.size() + nonEmptyItr.size()];

-    System.arraycopy(localNonEmptyIterators, 0, allIterators, 0, localNonEmptyIterators.length);

-    System.arraycopy(emptyIterators, 0, allIterators, localNonEmptyIterators.length, emptyIterators.length);

-    

-    // if all are empty, put the first one in (to avoid handling 0 as a special case)

-    return (localNonEmptyIterators.length != 0) 

-        ? localNonEmptyIterators

-        : new FsIterator_singletype[] {emptyIterators[0]};  // use one empty one  

-

-  }

-

-  /* (non-Javadoc)

-   * @see org.apache.uima.cas.impl.LowLevelIterator#ll_indexSize()

-   */

-  @Override

-  public int ll_indexSize() {

-    int sz = 0;

-    for (FsIterator_singletype<T> it : nonEmptyIterators) {

-      sz += ((LowLevelIterator<T>)it).ll_indexSize();      

-    }

-    return sz;

-  }

-  

-  @Override

-  public int ll_maxAnnotSpan() {

-    int span = -1;

-    for (FsIterator_singletype<T> it : nonEmptyIterators) {

-      int s = ((LowLevelIterator)it).ll_maxAnnotSpan();

-      if (s == Integer.MAX_VALUE) {

-        return s;

-      }

-      if (s > span) {

-        span = s;

-      }

-    }

-    return (span == -1) ? Integer.MAX_VALUE : span;

-  }

-

-  /* (non-Javadoc)

-   * @see org.apache.uima.cas.impl.LowLevelIterator#isIndexesHaveBeenUpdated()

-   */

-  @Override

-  public boolean isIndexesHaveBeenUpdated() {

-    for (FsIterator_singletype<T> it : allIterators) {

-      if (it.isIndexesHaveBeenUpdated()) {

-        return true;

-      }

-    }

-    return false;

-  }

-  

-  protected int firstChangedEmptyIterator() {

-    for (int i = 0; i < emptyIterators.length; i++) {

-      FSIterator<T> it = emptyIterators[i];

-      if (((LowLevelIterator<?>)it).isIndexesHaveBeenUpdated()) {

-        return i;

-      }

-    }

-    return -1;

-  }

-  

-}

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_subtypes_ordered.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_subtypes_ordered.java
index 331047f..3304f2d 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_subtypes_ordered.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_subtypes_ordered.java
@@ -24,34 +24,53 @@
 

 import org.apache.uima.cas.FSIterator;

 import org.apache.uima.cas.FeatureStructure;

+import org.apache.uima.cas.Type;

+import org.apache.uima.jcas.cas.TOP;

 

 /**

  * Performs an ordered iteration among a set of iterators, each one corresponding to

  *   the type or subtype of the uppermost type.

  *   

  * The set of iterators is maintained in an array, with the 0th element being the current valid iterator.

- * 

- * This class doesn't do concurrent mod checking - that's done by the individual iterators.

  *

  * @param <T> result type

  */

 public class FsIterator_subtypes_ordered<T extends FeatureStructure> 

-                    extends FsIterator_subtypes_list<T> {

+                    extends FsIterator_multiple_indexes<T> {

  

   /**

    * The number of elements to keep in order before the binary heap starts. This section helps the

    * performance in cases where a couple of types dominate the index.

+   * 

+   * The sorted section is searched sequentially.

+   * Above the sorted section, the search is done using binary search

    */

   private static final int SORTED_SECTION = 3;

   

+  /** index into nonEmptyIterators, shows last valid one */

+  protected int lastValidIteratorIndex = -1;

+  

   private boolean wentForward = true;

   

-  final private Comparator<FeatureStructure> comparator; 

-

-  public FsIterator_subtypes_ordered(FsIndex_iicp<T> iicp) {

-    super(iicp);

-    this.comparator = iicp.fsIndex_singletype;

-    moveToStart();

+  

+  // The IICP

+  final private FsIndex_iicp<T> iicp;

+  

+//  /** true if sorted index, with typepriority as a key, but ignoring it because

+//   *    either there are no type priorities defined, or

+//   *    using a select-API-created iterator configured without typePriority

+//   *    

+//   *  Not final for the use case where there's a type-order key, type priorities are specified,

+//   *  but a select-API-created iterator wants to ignore type priorities.

+//   */

+//  final private boolean isSortedAndIgnoringTypeOrderKey; 

+  

+  // call used by select framework to specify ignoring type priority

+  public FsIterator_subtypes_ordered(FsIndex_iicp<T> iicp, Comparator<TOP> comparatorMaybeNoTypeWithoutId) {

+    super(iicp, iicp.getIterators(), comparatorMaybeNoTypeWithoutId);

+    this.iicp = iicp;

+    FsIndex_set_sorted<T> idx2 = (FsIndex_set_sorted<T>)iicp.fsIndex_singletype;

+    moveToFirstNoReinit();

   } 

   

   /**

@@ -59,24 +78,14 @@
    */

   

   @Override

-  public void moveToFirst() {

-    if (firstChangedEmptyIterator() >= 0) {

-      this.nonEmptyIterators = initIterators();

-    }

-    // no need to call isIndexesHaveBeenUpdated because

-    // there's no state in this iterator that needs updating.

-    moveToStart();

-  }

-  

-  private void moveToStart() {

-    

+  public void moveToFirstNoReinit() {   

     int lvi = this.nonEmptyIterators.length - 1;

     // Need to consider all iterators.

     // Set all iterators to insertion point.

     int i = 0;

     while (i <= lvi) {

-      final FsIterator_singletype<T> it = this.nonEmptyIterators[i];

-      it.moveToFirst();

+      final LowLevelIterator<T> it = this.nonEmptyIterators[i];

+      it.moveToFirstNoReinit();

       if (it.isValid()) {

         heapify_up(it, i, 1);

         ++i;

@@ -90,14 +99,11 @@
     }

     // configured to continue with forward iterations

     this.wentForward = true;

-    this.lastValidIndex = lvi;

+    this.lastValidIteratorIndex = lvi;

   }

   

   @Override

-  public void moveToLast() {

-    if (firstChangedEmptyIterator() >= 0) {

-      this.nonEmptyIterators = initIterators();

-    }

+  public void moveToLastNoReinit() {

     // no need to call isIndexesHaveBeenUpdated because

     // there's no state in this iterator that needs updating.

     

@@ -106,9 +112,9 @@
     // Set all iterators to insertion point.

     int i = 0;

     while (i <= lvi) {

-      final FsIterator_singletype<T> it = this.nonEmptyIterators[i];

-      it.resetConcurrentModification();

-      it.moveToLast();

+      final LowLevelIterator<T> it = this.nonEmptyIterators[i];

+//      it.resetConcurrentModification();

+      it.moveToLastNoReinit();

       if (it.isValid()) {

         heapify_up(it, i, -1);

         ++i;

@@ -122,28 +128,12 @@
     }

     // configured to continue with backward iterations

     this.wentForward = false;

-    this.lastValidIndex = lvi;

-  }

-

-  @Override

-  public void moveToNext() {

-    if (!isValid()) {

-      return;

-    }

-

-    final FsIterator_singletype<T> it0 = nonEmptyIterators[0]/*.checkConcurrentModification()*/;

-

-    if (this.wentForward) {

-      it0.moveToNextNvc();

-      heapify_down(it0, 1);

-    } else {

-      moveToNextCmn(it0);

-    }

+    this.lastValidIteratorIndex = lvi;

   }

 

   @Override

   public void moveToNextNvc() {

-    final FsIterator_singletype<T> it0 = nonEmptyIterators[0]/*.checkConcurrentModification()*/;

+    final LowLevelIterator<T> it0 = nonEmptyIterators[0]/*.checkConcurrentModification()*/;

 

     if (this.wentForward) {

       it0.moveToNextNvc();

@@ -153,7 +143,11 @@
     }

   }

 

-  private void moveToNextCmn(final FsIterator_singletype<T> it0) {

+  /**

+   * 

+   * @param it0 guaranteed to be a valid iterator by callers

+   */

+  private void moveToNextCmn(final LowLevelIterator<T> it0) {

     // We need to increment everything.

     int lvi = this.nonEmptyIterators.length - 1;

     int i = 1;

@@ -161,16 +155,16 @@
       // Any iterator other than the current one needs to be

       // incremented until it's pointing at something that's

       // greater than the current element.

-      final FsIterator_singletype<T> it = nonEmptyIterators[i]/*.checkConcurrentModification()*/;

+      final LowLevelIterator<T> it = nonEmptyIterators[i]/*.checkConcurrentModification()*/;

       // If the iterator we're considering is not valid, we

       // set it to the first element. This should be it for this iterator...

       if (!it.isValid()) {

-        it.moveToFirst();

+        it.moveToFirstNoReinit();

       }

       // Increment the iterator while it is valid and pointing

       // at something smaller than the current element.

       while (it.isValid() && is_before(it, it0, 1)) {

-        it.moveToNext();

+        it.moveToNextNvc();

       }

 

       // find placement

@@ -186,7 +180,7 @@
       }

     }

 

-    this.lastValidIndex = lvi;

+    this.lastValidIteratorIndex = lvi;

     this.wentForward = true;

 

     it0.moveToNext();

@@ -195,17 +189,8 @@
   }

   

   @Override

-  public void moveToPrevious() {

-    if (!isValid()) {

-      return;

-    }

-

-    moveToPreviousNvc();

-  }

-  

-  @Override

   public void moveToPreviousNvc() {

-    final FsIterator_singletype<T> it0 = nonEmptyIterators[0]/*.checkConcurrentModification()*/;

+    final LowLevelIterator<T> it0 = nonEmptyIterators[0]/*.checkConcurrentModification()*/;

     if (!this.wentForward) {

       it0.moveToPreviousNvc();

       // this also takes care of invalid iterators

@@ -218,11 +203,11 @@
         // Any iterator other than the current one needs to be

         // decremented until it's pointing at something that's

         // smaller than the current element.

-        final FsIterator_singletype<T> it = nonEmptyIterators[i]/*.checkConcurrentModification()*/;

+        final LowLevelIterator<T> it = nonEmptyIterators[i]/*.checkConcurrentModification()*/;

         // If the iterator we're considering is not valid, we

         // set it to the last element. This should be it for this iterator...

         if (!it.isValid()) {

-          it.moveToLast();

+          it.moveToLastNoReinit();

         }

         // Decrement the iterator while it is valid and pointing

         // at something greater than the current element.

@@ -243,7 +228,7 @@
         }

       }

 

-      this.lastValidIndex = lvi;

+      this.lastValidIteratorIndex = lvi;

       this.wentForward = false;

 

       it0.moveToPrevious();

@@ -256,43 +241,63 @@
    * Test the order with which the two iterators should be used. Introduces arbitrary ordering for

    * equivalent FSs. Only called with valid iterators.

    * 

-   * @param l

-   * @param r

-   * @param dir

+   * @param l - guaranteed to ba a valid iterator by callers

+   * @param r - guaranteed to be a valid iterator by callers

+   * @param dir 

    *          Direction of movement, 1 for forward, -1 for backward

    * @return true if the left iterator needs to be used before the right one.

    */

-  private boolean is_before(FsIterator_singletype<T> l, FsIterator_singletype<T> r,

+  private boolean is_before(LowLevelIterator<T> l, LowLevelIterator<T> r,

       int dir) {

 

-    final T fsLeft = l.get();

-    final T fsRight = r.get();

-    

-    int d = comparator.compare(fsLeft, fsRight);

+//    // debug

+//    if (!l.isValid()) {

+//      throw new RuntimeException("1st arg invalid");

+//    }

+//

+//    if (!r.isValid()) {

+//      throw new RuntimeException("2nd arg invalid");

+//    }

+        

+    int d = compare(l.getNvc(), r.getNvc());

+    return d * dir < 0;

+  }

+  

+  /**

+   * Only used to compare two iterator's with different types position

+   * @param fsLeft the left iterator's element

+   * @param fsRight the right iterator's element

+   * @return  1 if left > right,   (compare maybe ignores type)

+   *         -1 if left < right,   (compare maybe ignores type)

+   *          1 if left == right and left.id > right.id

+   *         -1 if left == right and left.id < right.id

+   */

+  private int compare(FeatureStructure fsLeft, FeatureStructure fsRight) {

+    int d = comparatorMaybeNoTypeWithoutId.compare((TOP)fsLeft, (TOP)fsRight);

 

     // If two FSs are identical wrt the comparator of the index,

     // we still need to be able to distinguish them to be able to have a

     // well-defined sequence. In that case, we arbitrarily order FSs by

-    // their

-    // addresses. We need to do this in order to be able to ensure that a

+    // their ids. We need to do this in order to be able to ensure that a

     // reverse iterator produces the reverse order of the forward iterator.

     if (d == 0) {

       d = fsLeft._id() - fsRight._id();

     }

-    return d * dir < 0;

+    return d;

   }

 

   /**

-   * Move the idx'th element up in the heap until it finds its proper position.

+   * Move the idx'th iterator element up in the heap until it finds its proper position.

+   * Up means previous iterators are before it

    * 

    * @param it

-   *          indexes[idx]

+   *          indexes[idx], guaranteed to be "valid"

    * @param idx

-   *          Element to move

+   *          Element to move, nonEmptyIterators[i] == it

    * @param dir

    *          Direction of iterator movement, 1 for forward, -1 for backward

    */

-  private void heapify_up(FsIterator_singletype<T> it, int idx, int dir) {

+  private void heapify_up(LowLevelIterator<T> it, int idx, int dir) {

 //    FSIndexFlat<? extends FeatureStructure> flatIndexInfo = iicp.flatIndex;

 //    if (null != flatIndexInfo) {

 //      flatIndexInfo.incrementReorderingCount();

@@ -326,25 +331,27 @@
    * Move the top element down in the heap until it finds its proper position.

    * 

    * @param it

-   *          indexes[0]

+   *          indexes[0], may be invalid

    * @param dir

    *          Direction of iterator movement, 1 for forward, -1 for backward

    */

-  private void heapify_down(FsIterator_singletype<T> it, int dir) {

+  private void heapify_down(LowLevelIterator<T> it, int dir) {

 //    FSIndexFlat<? extends FeatureStructure> flatIndexInfo = iicp.flatIndex;

 //    if (null != flatIndexInfo) {

 //      flatIndexInfo.incrementReorderingCount();

 //    }

 

     if (!it.isValid()) {

-      final FsIterator_singletype<T> itl = this.nonEmptyIterators[this.lastValidIndex]/*.checkConcurrentModification()*/;

-      this.nonEmptyIterators[this.lastValidIndex] = it;

+      // if at the end of the iteration, the lastValidIteratorIndex is this one (e.g., is 0)

+      // and this operation is a noop, but sets the lastValidIteratorIndex to -1, indicating the iterator is invalid

+      final LowLevelIterator<T> itl = this.nonEmptyIterators[this.lastValidIteratorIndex]/*.checkConcurrentModification()*/;

+      this.nonEmptyIterators[this.lastValidIteratorIndex] = it;

       this.nonEmptyIterators[0] = itl;

-      --this.lastValidIndex;

+      --this.lastValidIteratorIndex;

       it = itl;

     }

 

-    final int num = this.lastValidIndex;

+    final int num = this.lastValidIteratorIndex;

     if ((num < 1) || !is_before(this.nonEmptyIterators[1]/*.checkConcurrentModification()*/, it, dir)) {

       return;

     }

@@ -394,18 +401,7 @@
    */

   @Override

   public boolean isValid() {

-    return lastValidIndex >= 0;

-  }

-

-  /* (non-Javadoc)

-   * @see org.apache.uima.cas.FSIterator#get()

-   */

-  @Override

-  public T get() throws NoSuchElementException {

-    if (!isValid()) {

-      throw new NoSuchElementException();

-    }

-    return getNvc();

+    return lastValidIteratorIndex >= 0;

   }

 

   /* (non-Javadoc)

@@ -413,54 +409,89 @@
    */

   @Override

   public T getNvc() throws NoSuchElementException {

-    return nonEmptyIterators[0]/*.checkConcurrentModification()*/.get();

+    return nonEmptyIterators[0].get();

   }

 

   /* (non-Javadoc)

    * @see org.apache.uima.cas.FSIterator#moveTo(org.apache.uima.cas.FeatureStructure)

+   * 

+   * set all iterators to insertion point

+   * 

+   * While rattling the iterators for sort order:

+   *   if ignoreType_moveTo

+   *     use compare without type

    */

   @Override

-  public void moveTo(FeatureStructure fs) {

-    if (firstChangedEmptyIterator() >= 0) {

-      this.nonEmptyIterators = initIterators();

-    }

+  public void moveToNoReinit(FeatureStructure fs) {

     // no need to call isIndexesHaveBeenUpdated because

     // there's no state in this iterator that needs updating.

-

-    int lvi = this.nonEmptyIterators.length - 1;

+    

+    // set null unless need special extra type compare

+//    Type typeCompare = (isSortedAndIgnoringTypeOrderKey) ? fs.getType() : null;

+ 

+    int lastValidIterator_local = this.nonEmptyIterators.length - 1;

     // Need to consider all iterators.

     // Set all iterators to insertion point.

     int i = 0;

-    while (i <= lvi) {

-      final FsIterator_singletype<T> it = this.nonEmptyIterators[i];

-      it.moveTo(fs);

+    while (i <= lastValidIterator_local) {

+      final LowLevelIterator<T> it = this.nonEmptyIterators[i];

+      it.moveToNoReinit(fs);  

       if (it.isValid()) {

         heapify_up(it, i, 1);

         ++i;

       } else {

         // swap this iterator with the last possibly valid one

         // lvi might be equal to i, this will not be a problem

-        this.nonEmptyIterators[i] = this.nonEmptyIterators[lvi];

-        this.nonEmptyIterators[lvi] = it;

-        --lvi;

+        this.nonEmptyIterators[i] = this.nonEmptyIterators[lastValidIterator_local];

+        this.nonEmptyIterators[lastValidIterator_local] = it;

+        --lastValidIterator_local;

       }

     }

     // configured to continue with forward iterations

     this.wentForward = true;

-    this.lastValidIndex = lvi;

+    this.lastValidIteratorIndex = lastValidIterator_local;

   }

 

+//  /* (non-Javadoc)

+//   * @see org.apache.uima.cas.FSIterator#moveTo(org.apache.uima.cas.FeatureStructure)

+//   */

+//  @Override

+//  public void moveToExactNoReinit(FeatureStructure fs) {

+//

+//    int lvi = this.nonEmptyIterators.length - 1;

+//    // Need to consider all iterators.

+//    // Set all iterators to insertion point.

+//    int i = 0;

+//    while (i <= lvi) {

+//      final LowLevelIterator<T> it = this.nonEmptyIterators[i];

+//      it.moveToExactNoReinit(fs);  

+//      if (it.isValid()) {

+//        heapify_up(it, i, 1);

+//        ++i;

+//      } else {

+//        // swap this iterator with the last possibly valid one

+//        // lvi might be equal to i, this will not be a problem

+//        this.nonEmptyIterators[i] = this.nonEmptyIterators[lvi];

+//        this.nonEmptyIterators[lvi] = it;

+//        --lvi;

+//      }

+//    }

+//    // configured to continue with forward iterations

+//    this.wentForward = true;

+//    this.lastValidIteratorIndex = lvi;

+//  }

+

   /* (non-Javadoc)

    * @see org.apache.uima.cas.FSIterator#copy()

    */

   @Override

   public FSIterator<T> copy() {

-    FsIterator_subtypes_ordered<T> it = new FsIterator_subtypes_ordered<T>(iicp);

+    FsIterator_subtypes_ordered<T> it = new FsIterator_subtypes_ordered<T>(iicp, comparatorMaybeNoTypeWithoutId);

     if (!isValid()) {

       it.moveToPrevious();  // mark new one also invalid

     } else {

-      T posFs = get();

-      it.moveTo(posFs);  // moves to left-most position

+      T posFs = getNvc();

+      it.moveToNoReinit(posFs);  // moves to left-most position

       while(it.get() != posFs) {

         it.moveToNext();

       }

@@ -468,7 +499,17 @@
     return it;

   }

 

-  

+  @Override

+  public Comparator<TOP> getComparator() {

+    return comparatorMaybeNoTypeWithoutId;    

+  }

 

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.LowLevelIterator#moveToSupported()

+   */

+  @Override

+  public boolean isMoveToSupported() {

+    return true;

+  }

   

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_subtypes_snapshot.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_subtypes_snapshot.java
index 198c3ec..770262e 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_subtypes_snapshot.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_subtypes_snapshot.java
@@ -26,27 +26,57 @@
 import org.apache.uima.cas.FSIndex;

 import org.apache.uima.cas.FSIterator;

 import org.apache.uima.cas.FeatureStructure;

+import org.apache.uima.jcas.cas.TOP;

 

 public class FsIterator_subtypes_snapshot<T extends FeatureStructure> implements LowLevelIterator<T>, Comparator<FeatureStructure> {

-  

+

 //  final private FsIndex_flat<T> flatIndex;  // a newly created one, just for this iterator

   final private T[] snapshot;  // local for ref speed

   private int pos = 0; 

+  /** support for alternative source iterating, where there is no order */

   final private boolean is_unordered;

   final private LowLevelIndex<T> indexForComparator;

+  

+  final private boolean isNotUimaIndexSource;

+  

+  final private Comparator<TOP> comparatorMaybeNoTypeWithoutId;

     

-  public FsIterator_subtypes_snapshot(FsIndex_flat<T> flatIndex) {

+//  public FsIterator_subtypes_snapshot(FsIndex_flat<T> flatIndex) {

+//    this(flatIndex, false);

+//  }

+  

+  public FsIterator_subtypes_snapshot(FsIndex_flat<T> flatIndex, 

+                                      Comparator<TOP> comparatorMaybeNoTypeWithoutId) {

     this.indexForComparator = flatIndex;

     this.snapshot = (T[]) flatIndex.getFlatArray();

     this.is_unordered = flatIndex.getIndexingStrategy() != FSIndex.SORTED_INDEX;

+    this.comparatorMaybeNoTypeWithoutId = comparatorMaybeNoTypeWithoutId;

+    this.isNotUimaIndexSource = false;

   }

+

   

-  public FsIterator_subtypes_snapshot(T[] snapshot, LowLevelIndex<T> index, boolean is_unordered) {

-    this.indexForComparator = (LowLevelIndex<T>) index;

+  /**

+   * Alternative source iterator, 1st arg is different (not an "index", just an array)  

+   *   - altSources are unordered, and NoType is ignored

+   *   - also supports backwards iterators, these are ordered  (Maybe fix this in the future - this is not necessarily required)

+   *      

+   * 

+   * @param snapshot -

+   * @param index -

+   * @param is_unordered - mark as unordered

+   * @param comparatorMaybeNoTypeWithoutId -

+   */

+  public FsIterator_subtypes_snapshot(T[] snapshot, 

+                                      LowLevelIndex<T> index, 

+                                      boolean is_unordered,

+                                      Comparator<TOP> comparatorMaybeNoTypeWithoutId) {

+    this.indexForComparator = index;

     this.snapshot = snapshot;

     this.is_unordered = is_unordered;

+    this.comparatorMaybeNoTypeWithoutId = comparatorMaybeNoTypeWithoutId;

+    this.isNotUimaIndexSource = true;

   }

-  

+    

   /* (non-Javadoc)

    * @see org.apache.uima.cas.FSIterator#isValid()

    */

@@ -108,7 +138,7 @@
    * @see org.apache.uima.cas.FSIterator#moveToFirst()

    */

   @Override

-  public void moveToFirst() {

+  public void moveToFirstNoReinit() {

     pos = 0;

   }

 

@@ -116,7 +146,7 @@
    * @see org.apache.uima.cas.FSIterator#moveToLast()

    */

   @Override

-  public void moveToLast() {

+  public void moveToLastNoReinit() {

     pos = snapshot.length - 1;

   }

 

@@ -124,10 +154,10 @@
    * @see org.apache.uima.cas.FSIterator#moveTo(org.apache.uima.cas.FeatureStructure)

    */

   @Override

-  public void moveTo(FeatureStructure fs) {

+  public void moveToNoReinit(FeatureStructure fs) {

     if (is_unordered) {

       int i = 0;

-      while ((i < snapshot.length) && compare(snapshot[i],  fs) < 0) {

+      while ((i < snapshot.length) && compare(snapshot[i],  fs) != 0) {

         i++;

       }

       pos = i;

@@ -152,13 +182,34 @@
     }

   }

 

+//  /* (non-Javadoc)

+//   * @see org.apache.uima.cas.FSIterator#moveTo(org.apache.uima.cas.FeatureStructure)

+//   */

+//  @Override

+//  public void moveToExactNoReinit(FeatureStructure fs) {

+////    if (is_unordered) {

+//      int i = 0;

+//      while ((i < snapshot.length) && snapshot[i] != fs) {

+//        i++;

+//      }

+//      pos = i;

+////    } else {

+////      // next doesn't work, the snapshot is not sorted by the comparator

+//////      pos = Arrays.binarySearch(snapshot, fs);

+////      if ()

+////    }

+//  }

+

   /* (non-Javadoc)

    * @see org.apache.uima.cas.FSIterator#copy()

    */

   @Override

   public FSIterator<T> copy() {

     FsIterator_subtypes_snapshot<T> it = new FsIterator_subtypes_snapshot<T>(

-        this.snapshot, (LowLevelIndex<T>) this.indexForComparator, this.is_unordered);

+        this.snapshot, 

+        this.indexForComparator, 

+        this.is_unordered,

+        this.comparatorMaybeNoTypeWithoutId);

     it.pos = pos;

     return it;

   }

@@ -167,7 +218,7 @@
    * @see org.apache.uima.cas.impl.LowLevelIterator#ll_indexSize()

    */

   @Override

-  public int ll_indexSize() {

+  public int ll_indexSizeMaybeNotCurrent() {

     return snapshot.length;

   }

   

@@ -184,10 +235,11 @@
     return indexForComparator;

   }

   

+  @Override

   public int compare(FeatureStructure fs1, FeatureStructure fs2) {

-    return (null == this.indexForComparator) 

-        ? (fs1.equals(fs2) ? 0 : -1)

-        : this.indexForComparator.compare(fs1, fs2);

+    return (null == comparatorMaybeNoTypeWithoutId) 

+        ? Integer.compare(fs1._id(), fs2._id())

+        : comparatorMaybeNoTypeWithoutId.compare((TOP)fs1, (TOP)fs2);

   }

   

   /* (non-Javadoc)

@@ -198,4 +250,15 @@
     return false;

   }

 

+  @Override

+  public boolean maybeReinitIterator() {

+    return false;

+  }

+

+

+  @Override

+  public Comparator<TOP> getComparator() {

+    return comparatorMaybeNoTypeWithoutId;

+  }  

+  

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_subtypes_unordered.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_subtypes_unordered.java
deleted file mode 100644
index fc6f1f3..0000000
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_subtypes_unordered.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*

- * Licensed to the Apache Software Foundation (ASF) under one

- * or more contributor license agreements.  See the NOTICE file

- * distributed with this work for additional information

- * regarding copyright ownership.  The ASF licenses this file

- * to you under the Apache License, Version 2.0 (the

- * "License"); you may not use this file except in compliance

- * with the License.  You may obtain a copy of the License at

- * 

- *   http://www.apache.org/licenses/LICENSE-2.0

- * 

- * Unless required by applicable law or agreed to in writing,

- * software distributed under the License is distributed on an

- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

- * KIND, either express or implied.  See the License for the

- * specific language governing permissions and limitations

- * under the License.

- */

-

-package org.apache.uima.cas.impl;

-

-import java.util.NoSuchElementException;

-

-import org.apache.uima.cas.FSIterator;

-import org.apache.uima.cas.FeatureStructure;

-

-/**

- * This class has an instance created temporarily to reuse the 

- * computation of the iterator array, for use by the FsIterator_aggregation_common.

- * @param <T> the type of the iterator

- */

-public class FsIterator_subtypes_unordered<T extends FeatureStructure> extends FsIterator_subtypes_list<T> {

- 

-  public FsIterator_subtypes_unordered(FsIndex_iicp<T> iicp) {

-    super(iicp);

-  } 

-  

-  // these methods are never called but are needed to allow creation of the temporary instance of this.

-  

-  @Override

-  public boolean isValid() {throw new UnsupportedOperationException();}

-  @Override

-  public T get() throws NoSuchElementException {throw new UnsupportedOperationException();}

-  @Override

-  public T getNvc() {throw new UnsupportedOperationException();}

-  @Override

-  public void moveToNext() {throw new UnsupportedOperationException();}

-  @Override

-  public void moveToNextNvc() {throw new UnsupportedOperationException();}

-  @Override

-  public void moveToPrevious() {throw new UnsupportedOperationException();}

-  @Override

-  public void moveToPreviousNvc() {throw new UnsupportedOperationException();}

-  @Override

-  public void moveToFirst() {}  // can't throw, should be a no-op.

-  @Override

-  public void moveToLast() {throw new UnsupportedOperationException();}

-  @Override

-  public void moveTo(FeatureStructure fs) {throw new UnsupportedOperationException();}

-  @Override

-  public FSIterator<T> copy() {throw new UnsupportedOperationException();}

-  @Override

-  public boolean hasNext() {throw new UnsupportedOperationException();}

-  @Override

-  public T next() {throw new UnsupportedOperationException();}

-}

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/Id2FS.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/Id2FS.java
index c6cb5e5..f8d7525 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/Id2FS.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/Id2FS.java
@@ -26,6 +26,7 @@
 import org.apache.uima.internal.util.Misc;

 import org.apache.uima.jcas.cas.TOP;

 import org.apache.uima.jcas.impl.JCasHashMap;

+import org.apache.uima.util.IteratorNvc;

 

 /**

  * A map from ints representing FS id's (or "addresses") to those FSs

@@ -41,7 +42,7 @@
  * 

  * Threading: to support read-only views, concurrent with updates, needs to be thread safe

  */

-public class Id2FS {

+public class Id2FS implements Iterable<TOP> {

   static final boolean MEASURE = false;

   private static final int MEASURE_STACK_SIZE = 10;

   private static Map<MeasureCaller, MeasureCaller> callers = MEASURE ? new HashMap<>() : null;

@@ -64,6 +65,7 @@
     id2fs = new JCasHashMap(initialSize); 

   }

 

+  /** put but assert wasn't there before */

   void put(int id, TOP fs) {

     TOP prev = id2fs.put(id, fs);

     assert prev == null;

@@ -304,4 +306,9 @@
     }

   }

 

+  @Override

+  public IteratorNvc<TOP> iterator() {

+    return id2fs.iterator();

+  }

+

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/LLUnambiguousIteratorImpl.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/LLUnambiguousIteratorImpl.java
index 68f5834..bd85d35 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/LLUnambiguousIteratorImpl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/LLUnambiguousIteratorImpl.java
@@ -33,10 +33,15 @@
  */
 public class LLUnambiguousIteratorImpl<T extends FeatureStructure> extends FsIterator_subtypes_snapshot<T> {
 
-  public LLUnambiguousIteratorImpl(LowLevelIterator<FeatureStructure> it) {
-    super((T[]) createItemsArray(it), (LowLevelIndex<T>) it.ll_getIndex(), false);
+  public LLUnambiguousIteratorImpl(LowLevelIterator<T> it) {
+    super((T[]) createItemsArray(
+        (LowLevelIterator<FeatureStructure>) it), 
+        (LowLevelIndex<T>) it.ll_getIndex(), 
+        IS_ORDERED, 
+        it.getComparator());
   }
   
+  // this is static because can't have instance method call before super call in constructor
   private static Annotation[] createItemsArray(LowLevelIterator<FeatureStructure> it) {
     ArrayList<Annotation> items = new ArrayList<Annotation>();
     int lastSeenEnd = 0;
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/LinearTypeOrderBuilderImpl.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/LinearTypeOrderBuilderImpl.java
index 6ba882c..c1f8b46 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/LinearTypeOrderBuilderImpl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/LinearTypeOrderBuilderImpl.java
@@ -64,9 +64,11 @@
     private boolean hashCodeComputed = false;
 
     private int computedHashCode;
+    
+    private final boolean isEmptyTypeOrder;
 
-    private TotalTypeOrder(String[] typeList, TypeSystem ts) throws CASException {
-      this(encodeTypeList(typeList, ts), ts);
+    private TotalTypeOrder(String[] typeList, TypeSystem ts, boolean isEmpty) throws CASException {
+      this(encodeTypeList(typeList, ts), ts, isEmpty);
     }
 
     private static int[] encodeTypeList(String[] typeList, TypeSystem ts) throws CASException {
@@ -89,7 +91,7 @@
      * @param typeList the list of ordered types
      * @param ts the type system
      */
-    private TotalTypeOrder(int[] typeList, TypeSystem ts) {
+    private TotalTypeOrder(int[] typeList, TypeSystem ts, boolean isEmpty) {
       super();
       TypeSystemImpl tsi = (TypeSystemImpl) ts;
       this.order = typeList;
@@ -102,6 +104,7 @@
       for (int i = 0; i < this.order.length; i++) {
         this.typeCodeToOrder[this.order[i]] = (short)i;
       }
+      this.isEmptyTypeOrder = isEmpty;
     }
 
     
@@ -121,7 +124,7 @@
     // Look-up.
     @Override
     public boolean lessThan(Type t1, Type t2) {
-      return lessThan(((TypeImpl) t1).getCode(), ((TypeImpl) t2).getCode());
+      return lessThan(((TypeImpl) t1).getCode(), ((TypeImpl) t2).getCode());       
       // return this.lt[((TypeImpl) t1).getCode()].get(((TypeImpl) t2)
       // .getCode());
     }
@@ -129,7 +132,6 @@
     @Override
     public boolean lessThan(int t1, int t2) {
       return this.typeCodeToOrder[t1] < this.typeCodeToOrder[t2];
-
       // return this.lt[t1].get(t2);
     }
 
@@ -161,15 +163,21 @@
       TotalTypeOrder other = (TotalTypeOrder) obj;
       if (hashCode() != other.hashCode()) {
         return false;
-      }
+      }      
       if (!Arrays.equals(order, other.order)) {
         return false;
       }
       return true;
     }
 
+    @Override
+    public boolean isEmptyTypeOrder() {
+      return isEmptyTypeOrder;
+    }
+
   }
 
+    
   private class Node extends GraphNode {
 
     private Node(Object o) {
@@ -347,7 +355,7 @@
    * @return -
    */
   public static LinearTypeOrder createTypeOrder(int[] typeList, TypeSystem ts) {
-    return new TotalTypeOrder(typeList, ts);
+    return new TotalTypeOrder(typeList, ts, false);
   }
 
   @Override
@@ -407,30 +415,31 @@
       boolean doIn = true;
       boolean doOut = true;
       for (Iterator<Type> ni = typesToModify.iterator(); ni.hasNext();) {
-	type = ni.next();
-	String typeName = type.getName();
-	final Node n = this.order.getNode(typeName);
-	if (doIn && (nIn != null)) {
-	  if (n.inRank() == 0) {
-	    n.addAllPredecessors(nIn.getAllPredecessors());
-	  } else {
-	    doIn = false; // when going up the tree, when you find one
-                                // filled in, stop
-	  }
-	}
-	if (doOut && (nOut != null)) {
-	  if (n.outRank() == 0) {
-	    n.addAllSuccessors(nOut.getAllSuccessors());
-	  } else {
-	    doOut = false;
-	  }
-	}
+      	type = ni.next();
+      	String typeName = type.getName();
+      	final Node n = this.order.getNode(typeName);
+      	if (doIn && (nIn != null)) {
+      	  if (n.inRank() == 0) {
+      	    n.addAllPredecessors(nIn.getAllPredecessors());
+      	  } else {
+      	    doIn = false; // when going up the tree, when you find one
+                                      // filled in, stop
+      	  }
+      	}
+      	if (doOut && (nOut != null)) {
+      	  if (n.outRank() == 0) {
+      	    n.addAllSuccessors(nOut.getAllSuccessors());
+      	  } else {
+      	    doOut = false;
+      	  }
+      	}
       }
     } // for all types
   }
 
   @Override
   public LinearTypeOrder getOrder() throws CASException {
+    int origOrderSize = order.size();
     addInheritanceTypes();
     Node inRank0Nodes = new Node("");
     Graph g = this.order.copy(inRank0Nodes);
@@ -451,7 +460,7 @@
     // for (int i = 0; i < totalOrder.length; i++) {
     // System.out.println(" " + totalOrder[i]);
     // }
-    return new TotalTypeOrder(totalOrder, this.ts);
+    return new TotalTypeOrder(totalOrder, this.ts, origOrderSize == 0);
   }
 
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelCAS.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelCAS.java
index 720d045..a52c7ed 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelCAS.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelCAS.java
@@ -21,6 +21,7 @@
 
 import org.apache.uima.cas.FeatureStructure;
 import org.apache.uima.jcas.cas.TOP;
+import org.apache.uima.util.AutoCloseableNoException;
 
 /**
  * Defines the low-level CAS APIs. The low-level CAS APIs provide no access to feature structure
@@ -75,6 +76,7 @@
  * 
  */
 public interface LowLevelCAS {
+  
   /**
    * Not a valid type. Type class constant returned by
    * {@link #ll_getTypeClass(int) ll_getTypeClass()}.
@@ -144,10 +146,6 @@
 
   public static final int TYPE_CLASS_DOUBLEARRAY = 18;
   
-  public static final int TYPE_CLASS_JAVAOBJECT = 19;
-  
-  public static final int TYPE_CLASS_JAVAOBJECTARRAY = 20;
-
   static final int NULL_FS_REF = 0;
 
   /**
@@ -835,5 +833,49 @@
   CASImpl ll_getSofaCasView(int addr);
   
   int ll_getSofa();
+    
+  /**
+   * Enables the id_to_fs_map mode. 
+   * @return an AutoClosable whose close method doesn't throw an exception
+   *   that will reset the mode to what it was when it was changed
+   */
+  default AutoCloseableNoException ll_enableV2IdRefs() {
+    return ll_enableV2IdRefs(true);
+  }
+  
+  /**
+   * Enables or disables the id_to_fs_map mode. 
+   * @param enable true to enable, false to disable
+   * @return an AutoClosable whose close method doesn't throw an exception
+   *   that will reset the mode to what it was when it was changed
+   */
+  AutoCloseableNoException ll_enableV2IdRefs(boolean enable);
+  
+  /**
+   * @return true if the id_to_fs_map mode is enabled
+   */
+  boolean is_ll_enableV2IdRefs();
+  
+  /**
+   * Defaults new CASs to have the id_to_fs_map enabled
+   * @return an AutoCloseable which restores the previous setting
+   */
+  static AutoCloseableNoException ll_defaultV2IdRefs() {
+    return ll_defaultV2IdRefs(true);
+  }
+  
+  /**
+   * Sets the defaults for new CASs to have the id_to_fs_map enabled.
+   * @param enable true to enable, false to disable
+   * @return an AutoCloseable which restores the previous setting
+   */
+  static AutoCloseableNoException ll_defaultV2IdRefs(boolean enable) {
+    final ThreadLocal<Boolean> tl = CASImpl.getDefaultV2IdRefs(); 
+    final Boolean prev = tl.get();  // could be null, true or false
+    AutoCloseableNoException r = () -> tl.set(prev);     
+    tl.set(enable);
+    return r;
+  }
+
 }
 
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelException.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelException.java
index b70c817..e9cf4ac 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelException.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelException.java
@@ -103,10 +103,11 @@
 
 
   public LowLevelException(String aMessageKey, Object[] aArguments, Throwable aCause) {
-    super(aMessageKey, aArguments, aCause);
+    super(aCause, aMessageKey, aArguments);
   }
 
   /** @return The same as getMessage(), but prefixed with <code>"LowLevelException: "</code>. */
+  @Override
   public String toString() {
     return "LowLevelException: " + this.getMessage();
   }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelIndex.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelIndex.java
index 62b784a..5a91761 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelIndex.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelIndex.java
@@ -19,12 +19,16 @@
 
 package org.apache.uima.cas.impl;
 
+import java.util.Comparator;
+
 import org.apache.uima.cas.FSIndex;
+import org.apache.uima.cas.FSIterator;
 import org.apache.uima.cas.FeatureStructure;
 import org.apache.uima.cas.SelectFSs;
 import org.apache.uima.cas.Type;
 import org.apache.uima.cas.admin.FSIndexComparator;
 import org.apache.uima.internal.util.IntPointerIterator;
+import org.apache.uima.jcas.cas.TOP;
 
 /**
  * Low-level FS index object. Use to obtain low-level iterators.
@@ -33,7 +37,7 @@
 public interface LowLevelIndex<T extends FeatureStructure> extends FSIndex<T> {
 
   /**
-   * Get a low-level, FS reference iterator.
+   * Get a low-level FS iterator.
    * 
    * @return An iterator for this index.
    */
@@ -60,14 +64,41 @@
 //   */
 //  LowLevelIterator<T> ll_rootIterator();
 
-  int ll_compare(int ref1, int ref2);
+  /**
+   * Compare two Feature structures, referred to by IDs
+   * @param ref1 -
+   * @param ref2 -
+   * @return -
+   */
+  default int ll_compare(int ref1, int ref2) {
+    CASImpl cas = getCasImpl();
+    return compare(cas.getFsFromId_checked(ref1), cas.getFsFromId_checked(ref2));
+  };
   
+  /**
+   * @return a CAS View associated with this iterator
+   */
   CASImpl getCasImpl();
   
   // incorporated from FSIndexImpl
-  
+  /**
+   * This is **NOT** a comparator for Feature Structures, but rather 
+   * something that compares two comparator specifications
+   * @return -
+   */
   FSIndexComparator getComparatorForIndexSpecs();
 
+  /**
+   * 
+   * @return a comparator used by this index to compare Feature Structures
+   *   For sets, the equal is used to determine set membership
+   *   For sorted, the comparator is the sort order (this comparator is without the ID)
+   */
+  Comparator<TOP> getComparator(); 
+  
+  static final Comparator<TOP> FS_ID_COMPARATOR = 
+      (TOP fs1, TOP fs2) -> Integer.compare(fs1._id, fs2._id); 
+  
   default void flush() {   // probably not needed, but left for backwards compatibility  4/2015
     throw new UnsupportedOperationException();
   }
@@ -106,13 +137,18 @@
   }
   
   /**
-   * @param ti type which is a subtype of this index's type
+   * @param type which is a subtype of this index's type
    * @param <U> the type the subindex is over
    * @return the index but just over this subtype
    */
-  default <U extends T> LowLevelIndex<U> getSubIndex(TypeImpl ti) {
+  default <U extends T> LowLevelIndex<U> getSubIndex(Type type) {
+    TypeImpl ti = (TypeImpl) type;
     return getCasImpl().indexRepository.getIndexBySpec(ti.getCode(), getIndexingStrategy(), (FSIndexComparatorImpl) getComparatorForIndexSpecs());
   }
+  
+  default <U extends T> LowLevelIndex<U> getSubIndex(Class<? extends TOP> clazz) {
+    return getSubIndex(this.getCasImpl().getCasType(clazz));
+  }
 
   /**
    * @return for annotation indexes, an conservative estimate the maximum span between begin and end
@@ -120,30 +156,66 @@
    */
   int ll_maxAnnotSpan();  
   
+  /**
+   * @return true if the index is sorted
+   */
+  boolean isSorted();
   
   @Override
-  default <N extends FeatureStructure> SelectFSs<N> select() {
-    return ((SelectFSs_impl)getCasImpl().select()).index(this);
+  default SelectFSs<T> select() {
+    return ((SelectFSs_impl<T>)getCasImpl().select()).index(this);
   }
 
   @Override
-  default <N extends FeatureStructure> SelectFSs<N> select(Type type) {
-    return ((SelectFSs_impl)select()).type(type);
+  default <N extends T> SelectFSs<N> select(Type type) {
+    return ((SelectFSs_impl)select()).type(type); // need cast to impl because type() not in interface
   }
 
   @Override
-  default <N extends FeatureStructure> SelectFSs<N> select(Class<N> clazz) {
+  default <N extends T> SelectFSs<N> select(Class<N> clazz) {
     return ((SelectFSs_impl)select()).type(clazz);
   }
 
   @Override
-  default <N extends FeatureStructure> SelectFSs<N> select(int jcasType) {
+  default <N extends T> SelectFSs<N> select(int jcasType) {
     return ((SelectFSs_impl)select()).type(jcasType);
   }
 
   @Override
-  default <N extends FeatureStructure> SelectFSs<N> select(String fullyQualifiedTypeName) {
+  default <N extends T> SelectFSs<N> select(String fullyQualifiedTypeName) {
     return ((SelectFSs_impl)select()).type(fullyQualifiedTypeName);
   }
   
+  /**
+   * Return an iterator over the index. The position of the iterator will be set to 
+   * return the first item in the index.
+   * If the index is empty, the iterator position will be marked as invalid.
+   * 
+   * @return An FSIterator positioned at the beginning, or an invalid iterator.
+   */
+  default LowLevelIterator<T> iterator() {
+    return iterator(IS_ORDERED, IS_TYPE_ORDER);
+  }
+  
+  /**
+   * Internal use, used by select framework.
+   * 
+   * Return an iterator over the index. The position of the iterator will be set to 
+   * return the first item in the index.
+   * If the index is empty, the iterator position will be marked as invalid.
+   * 
+   * @param orderNotNeeded if true, skips work while iterating to keep iterators over multiple types in sync.
+   * @param ignoreType if true, the comparator used for moveTo leftmost operations 
+   *        will ignore typeOrder keys, if the index happens to define these
+   * 
+   * @return An FSIterator positioned at the beginning, or an invalid iterator.
+   */
+  LowLevelIterator<T> iterator(boolean orderNotNeeded, boolean ignoreType);
+
+  /**
+   * Internal use constants
+   */
+  static final boolean IS_ORDERED = false;
+  static final boolean IS_TYPE_ORDER = false;
+
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelIterator.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelIterator.java
index c79e056..76e6828 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelIterator.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelIterator.java
@@ -19,10 +19,14 @@
 
 package org.apache.uima.cas.impl;
 
+import java.util.Comparator;
 import java.util.NoSuchElementException;
 
+import org.apache.uima.UIMAFramework;
 import org.apache.uima.cas.FSIterator;
 import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.internal.util.Misc;
+import org.apache.uima.jcas.cas.TOP;
 
 /**
  * Low-level FS iterator. Returns FS references, instead of FS objects.
@@ -59,11 +63,11 @@
   
 
   /**
-   * Return the size of the underlying index.
-   * 
-   * @return The size of the index.
+   * @return The size of the index.  In case of copy-on-write, this returns the size of the
+   *         index at the time the iterator was created, or at the last moveTo, moveToFirst, or moveToLast.
+   *         To get the current index size, use ll_getIndex().getSize()
    */
-  int ll_indexSize();
+  int ll_indexSizeMaybeNotCurrent();
 
   /**
    * Get the index for just the top most type of this iterator (excludes subtypes).
@@ -83,42 +87,89 @@
    *   This includes empty iterators becoming non-empty.
    */
   boolean isIndexesHaveBeenUpdated();
+ 
+  /**
+   * Internal use
+   * @return true if the iterator was refreshed to match the current index
+   */
+  boolean maybeReinitIterator();
+ 
   
+  /* (non-Javadoc)
+   * @see org.apache.uima.cas.FSIterator#moveToFirst()
+   */
+  @Override
+  default void moveToFirst() {
+    maybeReinitIterator();
+    moveToFirstNoReinit();
+  }
+
+  /* (non-Javadoc)
+   * @see org.apache.uima.cas.FSIterator#moveToLast()
+   */
+  @Override
+  default void moveToLast() {
+    maybeReinitIterator();
+    moveToLastNoReinit();
+  }
+
+  /* (non-Javadoc)
+   * @see org.apache.uima.cas.FSIterator#moveTo(org.apache.uima.cas.FeatureStructure)
+   */
+  @Override
+  default void moveTo(FeatureStructure fs) {
+    maybeReinitIterator();
+    moveToNoReinit(fs);
+  }
+    
+
+  /**
+   * Internal use
+   * same as moveToFirst, but won't reset to use current contents of index if index has changed
+   */
+  void moveToFirstNoReinit();
+  
+  /**
+   * Internal use
+   * same as moveToLast, but won't reset to use current contents of index if index has changed
+   */
+  void moveToLastNoReinit();
+
+  /**
+   * Internal use
+   * same as moveTo(fs), but won't reset to use current contents of index if index has changed
+   * @param fs the fs to use as the template identifying the place to move to
+   */
+  void moveToNoReinit(FeatureStructure fs);
+  
+  /**
+   * @return the comparator used by this iterator.  It is always a withoutID style, and may be
+   *         either a withType or NoType style.  
+   */
+  Comparator<TOP> getComparator();
+    
+  default void ll_remove() {
+    LowLevelIndex<T> idx = ll_getIndex();
+    if (null == idx) {
+      UIMAFramework.getLogger().warn("remove called on UIMA iterator but iterator not over any index");
+    } else {
+      idx.getCasImpl().removeFsFromIndexes(get());
+    }
+  }
+
+
   /**
    * an empty iterator
    */
-  static final LowLevelIterator<FeatureStructure> FS_ITERATOR_LOW_LEVEL_EMPTY = new LowLevelIterator<FeatureStructure> () {
-    @Override
-    public boolean isValid() { return false; }
-    @Override
-    public FeatureStructure get() throws NoSuchElementException { throw new NoSuchElementException(); }
-    @Override
-    public FeatureStructure getNvc() { throw new NoSuchElementException(); }
-    @Override
-    public void moveTo(int i) {}
-    @Override
-    public void moveToFirst() {}
-    @Override
-    public void moveToLast() {}
-    @Override
-    public LowLevelIterator<FeatureStructure> copy() { return this; }
-    @Override
-    public void moveToNext() {}
-    @Override
-    public void moveToNextNvc() {}
-    @Override
-    public void moveToPrevious() {}
-    @Override
-    public void moveToPreviousNvc() {}
-    @Override
-    public void moveTo(FeatureStructure fs) {}
-    @Override
-    public int ll_indexSize() { return 0; }
-    @Override
-    public int ll_maxAnnotSpan() { return Integer.MAX_VALUE; }
-    @Override
-    public LowLevelIndex<FeatureStructure> ll_getIndex() { return null; }
-    @Override
-    public boolean isIndexesHaveBeenUpdated() { return false; }    
-  };
+  static final LowLevelIterator<FeatureStructure> FS_ITERATOR_LOW_LEVEL_EMPTY = new LowLevelIterator_empty();
+  
+  /**
+   * Internal use constants
+   */
+  static final boolean IS_ORDERED = false;
+  
+  /**
+   * @return false if this iterator is over an unordered collection or set or bag
+   */
+  default boolean isMoveToSupported() { return false; }
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelIterator_empty.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelIterator_empty.java
new file mode 100644
index 0000000..5bd7526
--- /dev/null
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/LowLevelIterator_empty.java
@@ -0,0 +1,62 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.cas.impl;

+

+import java.util.Comparator;

+import java.util.NoSuchElementException;

+

+import org.apache.uima.cas.FeatureStructure;

+import org.apache.uima.jcas.cas.TOP;

+

+/**

+ * An empty Low-level FS iterator

+ */

+public class LowLevelIterator_empty<T extends FeatureStructure> implements LowLevelIterator<T> {

+

+  @Override

+  public boolean isValid() { return false; }

+  @Override

+  public T getNvc() { throw new NoSuchElementException(); }

+  @Override

+  public void moveToFirstNoReinit() {}

+  @Override

+  public void moveToLastNoReinit() {}

+  @Override

+  public void moveToNoReinit(FeatureStructure fs) {}

+

+  @Override

+  public LowLevelIterator_empty<T> copy() { return this; }

+  @Override

+  public void moveToNextNvc() {}

+  @Override

+  public void moveToPreviousNvc() {}

+  @Override

+  public int ll_indexSizeMaybeNotCurrent() { return 0; }

+  @Override

+  public int ll_maxAnnotSpan() { return Integer.MAX_VALUE; }

+  @Override

+  public LowLevelIndex<T> ll_getIndex() { return null; }

+  @Override

+  public boolean isIndexesHaveBeenUpdated() { return false; }

+  @Override

+  public boolean maybeReinitIterator() { return false; }

+  @Override

+  public Comparator<TOP> getComparator() { return null; }

+}

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/PathConstraint.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/PathConstraint.java
index b84c29c..554df26 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/PathConstraint.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/PathConstraint.java
@@ -39,6 +39,7 @@
     this.featNames = featNames;
   }
 
+  @Override
   public String toString() {
     if (this.featNames == null) {
       return "";
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/SelectFSs_impl.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/SelectFSs_impl.java
index 0c7b2fd..92f9f56 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/SelectFSs_impl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/SelectFSs_impl.java
@@ -69,12 +69,41 @@
  * shift handled in this routine

  * Comment codes:

  *   AI = implies AnnotationIndex

+ *   

+ * Iterator varieties and impl

+ * 

+ *   bounded?  type      order not unambig? strict? skipEq    

+ *             Priority? Needed? 

+ *     no

+ *   coveredBy

+ *   covering

+ *   sameas

+ *   

+ *   for not-bounded, 

+ *     - ignore strict and skipEq

+ *     - order-not-needed only applies if iicp size &gt; 1

+ *     - unambig ==&gt; use Subiterator

+ *         -- subiterator wraps: according to typePriority and order-not-needed

+ *     - no Type Priority - need to pass in as arg to fsIterator_multiple_indexes

+ *        == if no type priority, need to prevent rattling off the == type while comparate is equal

+ *        == affects both FsIterator_aggregation_common and FsIterator_subtypes_ordered

+ *   for 3 other boundings:

+ *     - use subiterator, pass in strict and skipeq

+ *     

+   finish this javadoc comment edit

+ *   extends FeatureStructure, not TOP, because of ref from FSIndex 

+ *      which uses FeatureStructure for backwards compatibility                  

  */

 public class SelectFSs_impl <T extends FeatureStructure> implements SelectFSs<T> {

   

+  private final static boolean IS_UNORDERED = true;

+  private final static boolean IS_ORDERED = false;

+  private final static boolean IS_UNAMBIGUOUS = false;

+  private final static boolean IS_NOT_STRICT = false;

+  

   private CASImpl view;

   private JCasImpl jcas;

-  private FSIndex<T> index; 

+  private LowLevelIndex<T> index; 

   private TypeImpl ti;

   private int shift; 

   private int limit = -1;

@@ -83,9 +112,9 @@
   private FSList  sourceFSList  = null;  // alternate source

   

   private boolean isTypePriority = false;

-  private boolean isPositionUsesType = false;

-  private boolean isUseAnnotationEquals = false; // for boundsUse only

-  private boolean isNonOverlapping = false;

+//  private boolean isPositionUsesType = false;

+  private boolean isSkipSameBeginEndType = false; // for boundsUse only

+  private boolean isNonOverlapping = IS_UNAMBIGUOUS;

   private boolean isIncludeAnnotBeyondBounds = false;

   private boolean isAllViews = false;

   private boolean isNullOK = false;

@@ -99,7 +128,7 @@
   

   private BoundsUse boundsUse = null; 

   

-  private TOP startingFs = null;

+  private TOP startingFs = null; // this is used for non-annotation positioning too

   private AnnotationFS boundingFs = null;

   

   

@@ -141,17 +170,16 @@
    * INDEX

    * If not specified, defaults to all FSs (orderNotNeeded) unless AnnotationIndex implied

    * @param indexName -

-   * @param <N> type of returned Feature Structures

    * @return -

    */

-  public <N extends FeatureStructure> SelectFSs_impl<N> index(String indexName) {

+  public SelectFSs_impl<T> index(String indexName) {

     this.index = view.indexRepository.getIndex(indexName);

-    return (SelectFSs_impl<N>) this;

+    return this;

   }

   

-  public <N extends FeatureStructure> SelectFSs_impl<N> index(FSIndex<N> aIndex) {

-    this.index = (FSIndex<T>) aIndex;

-    return (SelectFSs_impl<N>) this;

+  public SelectFSs_impl<T> index(FSIndex<T> aIndex) {

+    this.index =  (LowLevelIndex<T>) aIndex;

+    return this;

   }

 

   /*

@@ -159,22 +187,22 @@
    * if not specified defaults to the index's uppermost type.  

    */

   

-  public <N extends FeatureStructure> SelectFSs_impl<N> type(Type uimaType) {

+  public <N extends T> SelectFSs_impl<N> type(Type uimaType) {

     this.ti = (TypeImpl) uimaType;

     return (SelectFSs_impl<N>) this;

   }

   

-  public <N extends FeatureStructure> SelectFSs_impl<N> type(String fullyQualifiedTypeName) {

+  public <N extends T> SelectFSs_impl<N> type(String fullyQualifiedTypeName) {

     this.ti = view.getTypeSystemImpl().getType(fullyQualifiedTypeName);

     return (SelectFSs_impl<N>) this;

   }

 

-  public <N extends FeatureStructure> SelectFSs_impl<N> type(int jcasClass_dot_type) {

+  public <N extends T> SelectFSs_impl<N> type(int jcasClass_dot_type) {

     this.ti = (TypeImpl) view.getJCas().getCasType(jcasClass_dot_type);

     return (SelectFSs_impl<N>) this;

   }

 

-  public <N extends FeatureStructure> SelectFSs_impl<N> type(Class<N> jcasClass_dot_class) {

+  public <N extends T> SelectFSs_impl<N> type(Class<N> jcasClass_dot_class) {

     this.ti = (TypeImpl) view.getJCasImpl().getCasType(jcasClass_dot_class);

     return (SelectFSs_impl<N>) this;

   }  

@@ -201,30 +229,30 @@
    * boolean operations

    *********************************/

   

-  /* (non-Javadoc)

-   * @see org.apache.uima.cas.SelectFSs#positionUsesType()

-   */

-  @Override

-  public SelectFSs<T> positionUsesType() {

-    this.isPositionUsesType = true;

-    return this;

-  }

-

-  /* (non-Javadoc)

-   * @see org.apache.uima.cas.SelectFSs#positionUsesType(boolean)

-   */

-  @Override

-  public SelectFSs<T> positionUsesType(boolean aPositionUsesType) {

-    this.isPositionUsesType = aPositionUsesType;

-    return this;

-  }

+//  /* (non-Javadoc)

+//   * @see org.apache.uima.cas.SelectFSs#positionUsesType()

+//   */

+//  @Override

+//  public SelectFSs<T> positionUsesType() {

+//    this.isPositionUsesType = true;

+//    return this;

+//  }

+//

+//  /* (non-Javadoc)

+//   * @see org.apache.uima.cas.SelectFSs#positionUsesType(boolean)

+//   */

+//  @Override

+//  public SelectFSs<T> positionUsesType(boolean aPositionUsesType) {

+//    this.isPositionUsesType = aPositionUsesType;

+//    return this;

+//  }

 

   /* (non-Javadoc)

    * @see org.apache.uima.cas.SelectFSs#skipEquals()

    */

   @Override

-  public SelectFSs<T> useAnnotationEquals() {

-    this.isUseAnnotationEquals = true;

+  public SelectFSs<T> skipWhenSameBeginEndType() {

+    this.isSkipSameBeginEndType = true;

     return this;

   }

 

@@ -233,7 +261,7 @@
    */

   @Override

   public SelectFSs<T> useAnnotationEquals(boolean useAnnotationEquals) {

-    this.isUseAnnotationEquals = useAnnotationEquals;

+    this.isSkipSameBeginEndType = useAnnotationEquals;

     return this;

   }

 

@@ -342,6 +370,7 @@
     this.startingFs = fs;

     return this;

   } 

+  

   @Override

   public SelectFSs_impl<T> startAt(int begin, int end) {  // AI

     this.startingFs = makePosAnnot(begin, end);

@@ -362,8 +391,8 @@
   }  

   

   @Override

-  public SelectFSs_impl<T> limit(int limit) {

-    this.limit = limit;

+  public SelectFSs_impl<T> limit(int alimit) {

+    this.limit = alimit;

     return this;

   }

     

@@ -449,14 +478,6 @@
     return sb.toString();

   }

   

-  /**

-   * prepare terminal operations

-   */

-  

-  /**

-   * Default type Annotation if not specified and annotation index is implied.

-   * 

-   */

   private void prepareTerminalOp() {

     if (boundsUse == null) {

       boundsUse = BoundsUse.notBounded;

@@ -467,7 +488,7 @@
     final boolean isUseAnnotationIndex = 

         ((index != null) && (index instanceof AnnotationIndex)) ||

         isNonOverlapping ||

-        isPositionUsesType ||

+//        isPositionUsesType ||

         isTypePriority ||

         isIncludeAnnotBeyondBounds || 

         boundsUse != BoundsUse.notBounded ||

@@ -477,9 +498,9 @@
       forceAnnotationIndex();  // throws if non-null index not an annotation index

     }

     

-    if (isTypePriority) {

-      isPositionUsesType = true;

-    }

+//    if (isTypePriority) {

+//      isPositionUsesType = true;

+//    }

         

     if (ti == null) {

       if (index != null) {

@@ -499,6 +520,10 @@
       ti = view.getTypeSystemImpl().getTopType();

     }

     

+    if (boundsUse == BoundsUse.covering) {

+      isIncludeAnnotBeyondBounds = true;  

+    }

+    

   }

   

   private void maybeValidateAltSource() {

@@ -523,14 +548,14 @@
     }

   }

   

-  private void decr(FSIterator<T> it) {

-    if (isBackwards) {

-      it.moveToNext();

-    } else {

-      it.moveToPrevious();

-    }

-  }

-  

+//  private void decr(FSIterator<T> it) {

+//    if (isBackwards) {

+//      it.moveToNext();

+//    } else {

+//      it.moveToPrevious();

+//    }

+//  }

+//  

   /*********************************

    * terminal operations

    * returning other than SelectFSs

@@ -553,8 +578,14 @@
   public FSIterator<T> fsIterator() {

     if (isFollowing && isBackwards) {

       isBackwards = false;

-      T[] a = (T[]) asArray(fsIterator1());

-      FSIterator<T> it = new FsIterator_backwards<>(new FsIterator_subtypes_snapshot<T>(a, (LowLevelIndex<T>) index, false));

+      LowLevelIterator<T> baseIterator = fsIterator1();

+      T[] a = (T[]) asArray(baseIterator);

+      FSIterator<T> it = new FsIterator_backwards<>(

+                           new FsIterator_subtypes_snapshot<T>(

+                               a, 

+                               (LowLevelIndex<T>) index, 

+                               IS_ORDERED,

+                               baseIterator.getComparator()));

       return (limit == 0)

           ? it

             // rewrap with limit - needs to be outer shell to get right invalid behavior

@@ -564,8 +595,13 @@
     if (isPreceding) {

       boolean bkwd = isBackwards;

       isBackwards = true;

-      T[] a = (T[]) asArray(fsIterator1());

-      FSIterator<T> it = new FsIterator_subtypes_snapshot<T>(a, (LowLevelIndex<T>) index, false);

+      LowLevelIterator<T> baseIterator = fsIterator1();

+      T[] a = (T[]) asArray(baseIterator);

+      FSIterator<T> it = new FsIterator_subtypes_snapshot<T>(

+                               a,

+                               (LowLevelIndex<T>) index,

+                               IS_ORDERED,

+                               baseIterator.getComparator());

       if (!bkwd) {

         it = new FsIterator_backwards<>(it); // because array is backwards

       }

@@ -575,13 +611,15 @@
           : new FsIterator_limited<>(it, limit); 

     }

     

+    // all others, including isFollowing but not backwards

     return fsIterator1();

   }

   

-  private FSIterator<T> fsIterator1() {

+  private LowLevelIterator<T> fsIterator1() {

     prepareTerminalOp();

-    FSIterator<T> it = isAllViews 

-                      ? new FsIterator_aggregation_common<T>(getPlainIteratorsForAllViews(), null)

+    LowLevelIterator<T> it = isAllViews 

+                      ? //new FsIterator_aggregation_common<T>(getPlainIteratorsForAllViews(), )

+                        createFsIterator_for_all_views()

                       : plainFsIterator(index, view);

 

     maybePosition(it);

@@ -589,26 +627,44 @@
     return (limit == -1) ? it : new FsIterator_limited<>(it, limit);    

   }

   

-  

-  

-  private FSIterator<T>[] getPlainIteratorsForAllViews() {

+  /**

+   * for a selected index, return an iterator over all the views for that index

+   * @return iterator over all views for that index, unordered

+   */

+  private FsIterator_aggregation_common<T> createFsIterator_for_all_views() {

     final int nbrViews = view.getNumberOfViews();

-    FSIterator<T>[] ita = new FSIterator[nbrViews];

+    LowLevelIterator<T>[] ita = new LowLevelIterator[nbrViews];

+//    LowLevelIndex<T>[] indexes = new LowLevelIndex[nbrViews];

     

     for (int i = 1; i <= nbrViews; i++) {

       CASImpl v = (i == 1) ? view.getInitialView() : (CASImpl) view.getView(i);

-      ita[i - 1] = plainFsIterator(getIndexForView(v), v);

+      LowLevelIndex<T> index_local = (LowLevelIndex<T>) getIndexForView(v);

+      ita[i - 1] = plainFsIterator(index_local, v);

+//      indexes[i - 1] = index;

     }

-    return ita;

+//    return new FsIterator_aggregation_common<T>(ita, new FsIndex_aggr<>(indexes));

+    return new FsIterator_aggregation_common<T>(ita, null, null);

+

   }

   

+//  private LowLevelIterator<T>[] getPlainIteratorsForAllViews() {

+//    final int nbrViews = view.getNumberOfViews();

+//    LowLevelIterator<T>[] ita = new LowLevelIterator[nbrViews];

+//    

+//    for (int i = 1; i <= nbrViews; i++) {

+//      CASImpl v = (i == 1) ? view.getInitialView() : (CASImpl) view.getView(i);

+//      ita[i - 1] = plainFsIterator(getIndexForView(v), v);

+//    }

+//    return ita;

+//  }

+  

   /** 

    * gets the index for a view that corresponds to the specified index

    *   by matching the index specs and type code

    * @param v -

    * @return -

    */

-  private FSIndex<T> getIndexForView(CASImpl v) {

+  private LowLevelIndex<T> getIndexForView(CASImpl v) {

     if (index == null) {

       return null;

     }

@@ -622,8 +678,14 @@
     return ir.getIndexBySpec(idx.getTypeCode(), idx.getIndexingStrategy(), idx.getComparatorImplForIndexSpecs());

   }

   

-  

-  private FSIterator<T> plainFsIterator(FSIndex<T> idx, CASImpl v) {

+  /**

+   * 

+   * @param idx the index selected, corresponds to a type + its subtypes, 

+   *        or if null, either an alternate source or means all types

+   * @param v the cas

+   * @return an iterator

+   */

+  private LowLevelIterator<T> plainFsIterator(LowLevelIndex<T> idx, CASImpl v) {

     if (null == idx) { 

       // no bounds, not ordered

       // type could be null

@@ -638,35 +700,39 @@
       }

     }

     

-    final boolean isIndexOrdered = idx.getIndexingStrategy() == FSIndex.SORTED_INDEX;

+    final boolean isSortedIndex = idx.getIndexingStrategy() == FSIndex.SORTED_INDEX;

     final boolean isAnnotationIndex = idx instanceof AnnotationIndex;

-    final AnnotationIndex ai = isAnnotationIndex ? (AnnotationIndex)idx: null;

-    FSIterator<T> it;

+    final FsIndex_annotation<Annotation> ai = isAnnotationIndex ? (FsIndex_annotation)idx: null;

+    LowLevelIterator<T> it;

     if (boundsUse == BoundsUse.notBounded) {

-      if (!isIndexOrdered) {

-        it = idx.iterator();       

+      if (!isSortedIndex) {

+        // set index

+        it = (LowLevelIterator<T>) idx.iterator();       

       } else {

-        // index is ordered but no bounds are being used - return plain fsIterator or maybe nonOverlapping version

-        it = (isAnnotationIndex && isNonOverlapping)

-               ? ai.iterator(false)

-               : (isUnordered && idx instanceof FsIndex_iicp) 

-                   ? ((FsIndex_iicp<T>)idx).iteratorUnordered()

-                   : idx.iterator();

+        // index is sorted but no bounds are being used.  Varieties:

+        //   - AnnotationIndex:

+        //     - overlapping / non-overlapping  (ambiguous, unambiguous)

+        //   - any sorted index including AnnotationIndex:

+        //     - typePriority / ignore typePriority

+        //     - orderNotNecessary / 

+

+        it = (isAnnotationIndex) 

+               ? (LowLevelIterator<T>) ai.iterator( ! isNonOverlapping, IS_NOT_STRICT /* because unbounded */, isUnordered, ! isTypePriority)

+               : idx.iterator(isUnordered, ! isTypePriority);

       }

     } else {

-    // bounds in use, index must be annotation index, is ordered

-    it = (FSIterator<T>) new Subiterator<>(

-        (FSIterator<AnnotationFS>)idx.iterator(), 

-        boundingFs, 

-        !isNonOverlapping,  // ambiguous

-        !isIncludeAnnotBeyondBounds,  // strict 

-        boundsUse,

-        isTypePriority, 

-        isPositionUsesType, 

-        isUseAnnotationEquals,              

-        v.indexRepository.getAnnotationFsComparator());

+      // bounds in use, index must be annotation index, is ordered

+      it = (LowLevelIterator<T>) new Subiterator<Annotation>(

+          (FSIterator<Annotation>) idx.iterator(isUnordered, ! isTypePriority), 

+          boundingFs, 

+          !isNonOverlapping,  // ambiguous

+          !isIncludeAnnotBeyondBounds,  // strict 

+          boundsUse,

+          isTypePriority,  

+          isSkipSameBeginEndType);

     }

     

+    

     it = isBackwards ? new FsIterator_backwards<>(it) : it;

     if (isBackwards) {

       it.moveToFirst();  

@@ -674,7 +740,7 @@
     return it;

   }

     

-  private FSIterator<T> altSourceIterator() {

+  private LowLevelIterator<T> altSourceIterator() {

     T[] filtered;

     if (sourceFSList != null) {

       List<T> filteredItems = new ArrayList<T>();

@@ -694,7 +760,7 @@
       // skip filtering if nullOK and no subsumption test needed because type = TOP or higher

       boolean noTypeFilter = ti == view.getTypeSystemImpl().topType;

       if (!isNullOK && noTypeFilter) {

-        return new FsIterator_subtypes_snapshot<T>((T[]) sourceFSArray, null, true); 

+        return new FsIterator_subtypes_snapshot<T>((T[]) sourceFSArray, null, IS_UNORDERED, null); 

       }

       

       List<T> filteredItems = new ArrayList<T>();

@@ -711,12 +777,20 @@
       }

       

       if (noTypeFilter && !noNullsWereFiltered) {

-        return new FsIterator_subtypes_snapshot<T>((T[]) sourceFSArray, null, true);         

+        return new FsIterator_subtypes_snapshot<T>(

+            (T[]) sourceFSArray, 

+            null, 

+            IS_UNORDERED,

+            null);         

       }

       

       filtered = filteredItems.toArray((T[]) Array.newInstance(FeatureStructure.class, filteredItems.size()));                    

     }        

-    return new FsIterator_subtypes_snapshot<T>(filtered, null, true);  // items not sorted 

+    return new FsIterator_subtypes_snapshot<T>(

+        filtered, 

+        null, 

+        IS_UNORDERED,

+        null);  // items not sorted 

   }

   

   @Override

@@ -731,8 +805,12 @@
     return new AbstractSequentialList<N>() {

       

       @Override

-      public ListIterator<N> listIterator(int index) {

-        return (ListIterator<N>) fsIterator();

+      public ListIterator<N> listIterator(int startingIndex) {

+        ListIterator<N> it = (ListIterator<N>) fsIterator();

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

+          it.next();

+        }

+        return it;

       }

 

       @Override

@@ -846,7 +924,7 @@
 

       @Override

       public long estimateSize() {

-        return ((characteristics & Spliterator.SIZED) == Spliterator.SIZED) ? localIndex.size() : Long.MAX_VALUE;

+        return ((characteristics & Spliterator.SIZED) == Spliterator.SIZED && localIndex != null) ? localIndex.size() : Long.MAX_VALUE;

       }

 

       @Override

@@ -914,7 +992,11 @@
     FSIterator<T> it = fsIterator();

     if (it.isValid()) {

       T v = it.getNvc();

-      it.moveToNext();

+      if (shift >= 0) {

+        it.moveToNext();

+      } else {

+        it.moveToPrevious();

+      }

       if (it.isValid()) {

         throw new CASRuntimeException(CASRuntimeException.SELECT_GET_TOO_MANY_INSTANCES, ti.getName(), maybeMsgPosition());

       }

@@ -1029,31 +1111,33 @@
    * @param it iterator to position

    * @return it positioned if needed

    */

-  public FSIterator<T> maybePosition(FSIterator<T> it) {

+  private FSIterator<T> maybePosition(FSIterator<T> it) {

     if (!it.isValid() || startingFs == null || boundsUse != BoundsUse.notBounded) {

       return it;

     }

     

     it.moveTo(startingFs);

     

-    if (index != null && index instanceof AnnotationIndex && !isFollowing && !isPreceding) {

-      if (!isTypePriority) {

-        int begin = ((Annotation)startingFs).getBegin();

-        int end = ((Annotation)startingFs).getEnd();

-        Type type = startingFs.getType();

-        Annotation fs = (Annotation) it.get();

-        while (begin == fs.getBegin() && end == fs.getEnd() 

-               && (!isPositionUsesType || type == fs.getType())) {

-          it.moveToPreviousNvc();

-          if (!it.isValid()) {

-            it.moveToFirst();

-            return it;

-          }

-          fs = (Annotation) it.get();

-        }

-        it.moveToNext();

-      }

-    }

+    // next commented out because the underlying iterator already does this

+//    if (index != null && index instanceof AnnotationIndex && !isFollowing && !isPreceding) {

+//      if (!isTypePriority) {

+//        int begin = ((Annotation)startingFs).getBegin();

+//        int end = ((Annotation)startingFs).getEnd();

+//        Type type = startingFs.getType();

+//        Annotation fs = (Annotation) it.get();

+//        while (begin == fs.getBegin() && end == fs.getEnd() 

+////               && (!isPositionUsesType || type == fs.getType())

+//               ) {

+//          it.moveToPreviousNvc();

+//          if (!it.isValid()) {

+//            it.moveToFirst();

+//            return it;

+//          }

+//          fs = (Annotation) it.get();

+//        }

+//        it.moveToNext();

+//      }

+//    }

     

     if (isFollowing) {

       final int end = ((Annotation)startingFs).getEnd();

@@ -1096,23 +1180,26 @@
    * @see org.apache.uima.cas.SelectFSs#following(org.apache.uima.jcas.cas.TOP)

    */

   @Override

-  public SelectFSs<T> following(TOP fs) {

-    return commonFollowing(fs, 0);

+  public SelectFSs<T> following(Annotation fs) {

+    return following(fs, 0);

   }

 

   /* (non-Javadoc)

    * @see org.apache.uima.cas.SelectFSs#following(int, int)

    */

   @Override

-  public SelectFSs<T> following(int begin, int end) {

-    return commonFollowing(makePosAnnot(begin, end), 0);

+  public SelectFSs<T> following(int position) {

+    return following(position, 0);

   }

 

   /* (non-Javadoc)

    * @see org.apache.uima.cas.SelectFSs#following(org.apache.uima.jcas.cas.TOP, int)

    */

   @Override

-  public SelectFSs<T> following(TOP fs, int offset) {

+  public SelectFSs<T> following(Annotation fs, int offset) {

+    if (fs.getBegin() < fs.getEnd()) {

+      fs = makePosAnnot(fs.getEnd(), fs.getEnd());

+    }

     return commonFollowing(fs, offset);

   }

 

@@ -1120,40 +1207,43 @@
    * @see org.apache.uima.cas.SelectFSs#following(int, int, int)

    */

   @Override

-  public SelectFSs<T> following(int begin, int end, int offset) {

-    return commonFollowing(makePosAnnot(begin, end), offset);

+  public SelectFSs<T> following(int position, int offset) {

+    return commonFollowing(makePosAnnot(position, position), offset);

   }

 

   /* (non-Javadoc)

    * @see org.apache.uima.cas.SelectFSs#preceding(org.apache.uima.jcas.cas.TOP)

    */

   @Override

-  public SelectFSs<T> preceding(TOP fs) {

-    return commonPreceding(fs, 0);

+  public SelectFSs<T> preceding(Annotation fs) {

+    return preceding(fs, 0);

   }

 

   /* (non-Javadoc)

    * @see org.apache.uima.cas.SelectFSs#preceding(int, int)

    */

   @Override

-  public SelectFSs<T> preceding(int begin, int end) {

-    return commonPreceding(makePosAnnot(begin, end), 0);

+  public SelectFSs<T> preceding(int position) {

+    return preceding(position, 0);

   }

 

   /* (non-Javadoc)

    * @see org.apache.uima.cas.SelectFSs#preceding(org.apache.uima.jcas.cas.TOP, int)

    */

   @Override

-  public SelectFSs<T> preceding(TOP fs, int offset) {

-    return commonPreceding(fs, offset);

+  public SelectFSs<T> preceding(Annotation annotation, int offset) {

+    if (annotation.getEnd() < Integer.MAX_VALUE) {

+      annotation = makePosAnnot(annotation.getBegin(), Integer.MAX_VALUE);

+    }

+    return commonPreceding(annotation, offset);

   }

 

   /* (non-Javadoc)

    * @see org.apache.uima.cas.SelectFSs#preceding(int, int, int)

    */

   @Override

-  public SelectFSs<T> preceding(int begin, int end, int offset) {

-    return commonPreceding(makePosAnnot(begin, end), offset);

+  public SelectFSs<T> preceding(int position, int offset) {

+    return commonPreceding(makePosAnnot(position, Integer.MAX_VALUE), offset);

   }

 

    

@@ -1190,16 +1280,16 @@
 //    }

 //  }

   

-  private SelectFSs<T> commonFollowing(TOP fs, int offset) {

-    this.startingFs = fs;

+  private SelectFSs<T> commonFollowing(Annotation annotation, int offset) {

+    this.startingFs = annotation;

     this.shift = offset;

     isFollowing = true;

     return this;

   }

 

-  private SelectFSs<T> commonPreceding(TOP fs, int offset) {

+  private SelectFSs<T> commonPreceding(Annotation annotation, int offset) {

 //    validateSinglePosition(fs, offset);

-    this.startingFs = fs;

+    this.startingFs = annotation;

     this.shift = offset;

     isPreceding = true;

     isBackwards = true; // always iterate backwards

@@ -1208,7 +1298,7 @@
   

   private void forceAnnotationIndex() {

     if (index == null) {

-      index = (FSIndex<T>) view.getAnnotationIndex();

+      index = (LowLevelIndex<T>) view.getAnnotationIndex();

     } else {

       if (!(index instanceof AnnotationIndex)) {

         /** Index "{0}" must be an AnnotationIndex. */ 

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/ShortHeap.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/ShortHeap.java
index 387af2c..17ecf71 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/ShortHeap.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/ShortHeap.java
@@ -36,18 +36,22 @@
     super(heapBaseSize, heapMultLimit);

   }

 

+  @Override

   final void initMemory() {

     this.heap = new short[this.heapBaseSize];

   }

   

+  @Override

   final void initMemory(int size) {

     this.heap = new short[size];

   }

 

+  @Override

   final int getCapacity() {

     return this.heap.length;

   }

 

+  @Override

   void growHeapIfNeeded() {

     if (heap.length >= heapPos)

       return;

@@ -58,6 +62,7 @@
     heap = new_array;

   }

 

+  @Override

   void resetToZeros() {

     Arrays.fill(this.heap, 0, this.heapPos, (short) NULL);

   }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/StringHeap.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/StringHeap.java
index 6b1e6a0..7b8edd8 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/StringHeap.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/StringHeap.java
@@ -192,7 +192,7 @@
   
   public String[] toArray() {
     String[] r = new String[stringList.size()];
-    return (String[]) stringList.toArray(r);
+    return stringList.toArray(r);
   }
 
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/Subiterator.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/Subiterator.java
index 06f4a56..3a25ce9 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/Subiterator.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/Subiterator.java
@@ -22,13 +22,13 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.NoSuchElementException;
 import java.util.function.Predicate;
 
-import org.apache.uima.cas.CASRuntimeException;
+import org.apache.uima.cas.FSComparators;
 import org.apache.uima.cas.FSIterator;
 import org.apache.uima.cas.FeatureStructure;
 import org.apache.uima.cas.Type;
+import org.apache.uima.cas.admin.LinearTypeOrder;
 import org.apache.uima.cas.text.AnnotationFS;
 import org.apache.uima.internal.util.Misc;
 import org.apache.uima.jcas.cas.TOP;
@@ -36,13 +36,72 @@
 import org.apache.uima.jcas.tcas.Annotation;
 
 /**
+ * Internal implementation of Subiterators.
+ * External APIs are
+ *   - methods on AnnotationIndex
+ *   - the SelectFSs Interface
+ *   
+ * This implementation extends the V2 implementation to support the 
+ * variations allowed by SelectFSs and AnnotationIndex
+ * 
+ * Several of the variations arise around how to handle FSs that are comparator-equal.
+ * 
+ * The variations are in three broad categories - bounds, skipping over FSs, and positioning using type ordering or not
+ *   - bounds:
+ *      -- no bounds
+ *      -- same begin / end 
+ *      -- coveredBy   
+ *      -- covering  
+ *   - skipping over FSs
+ *     - skip over the bounding annotation(s)
+ *        -- if it is the == one (uimaFIT style)
+ *        -- if it is comparator == (the UIMA v2 style)
+ *          --- with or without typePriority
+ *            ----  if without typePriority, with or without type ==
+ *          *****************************************
+ *          * redesigned 8/2017
+ *          *   for skipping, the type is always used, that is
+ *          *   items are skipped over only if having the same type
+ *          *****************************************
+ *     - unambiguous (for no-bounds or coveredBy, only: skip over FSs whose begin is < previous one's end) 
+ *     - strict (for coveredBy only: skip if end is > bounding Annotation's end)
+ *   - positioning (for moveTo)
+ *          *****************************************
+ *          * redesigned 8/2017
+ *          *   TypeOrderKey is always used
+ *          *****************************************
+ *     - NO maybe ignore type priorities while positioning to left-most equal item
+ *       -- NO if ignoring type priorities, maybe still compare types for equal when adjusting
+ *          NO to left-most equal item.
+ *          
+ * Positioning variations affect only the moveTo(fs) method.
+ *
+ * This class is not used for select sources which are ordered, but non-sorted collections / arrays.
+ * This class is used only with an AnnotationIndex.
+ * 
+ * Interaction among bounds, skipping, and positioning:
+ *   while moveTo(fs), items are skipped over.
+ *     - unambiguous
+ *     - skip over bounding annotation
+ *     - strict
+ *   moveTo(fs): uses isUseTypePriority and isPositionUsesType and isSkipEquals
+ *   while moveTo(fs), bounds limit position
+ *   
+ *   while moving to First/Last:
+ *     bounds provide edge
+ *     skipping done if skipped element at edge
+ *     (moveToLast & unambiguous - special calculation from start)
+ *     
+ */
+
+/**
  * Subiterator implementation.
  * 
- * There are two bounding styles and 2 underlying forms.
+ * There are 2 underlying forms.
  * 
  * The 2nd form is produced lazily when needed, and 
  * is made by a one-time forward traversal to compute unambiguous subsets and store them into a list.
- *   - The 2nd form is needed only for unambiguous style if backwards or moveto(fs) operation.
+ *   - The 2nd form is needed only for unambiguous style if backwards or moveTo(fs), or moveToLast operations.
  * 
  * The 1st form uses the underlying iterator directly, and does skipping as needed, while iterating  
  *   - going forward: 
@@ -80,11 +139,13 @@
  */
 public class Subiterator<T extends AnnotationFS> implements LowLevelIterator<T> {
 
-
+  private static final boolean IS_GOING_FORWARDS = true; 
+  private static final boolean IS_GOING_BACKWARDS = false;
+  
   public static enum BoundsUse {
-    coveredBy,
-    covering,
-    sameBeginEnd,
+    coveredBy,  // iterate within bounds specified by controlling Feature Structure
+    covering,   // iterate over FSs which cover the bounds specified by controlling Feature Structure
+    sameBeginEnd,  // iterate over FSs having the same begin and end 
     notBounded,
   }
     
@@ -96,23 +157,29 @@
 
   private int pos = 0;  // used for form 2
   
-  private final FSIterator<Annotation> it;
+  private final LowLevelIterator<Annotation> it;
   
   private final Annotation boundingAnnot;  // the bounding annotation need not be a subtype of T
   
   private final Annotation coveringStartPos;
   private final Annotation coveringEndPos;  // an approx end position
   
-  private final boolean isAmbiguous;  // true means ordinary, false means to skip until start is past prev end
-  private final boolean isStrict;
+  private final boolean isUnambiguous;  // true means need to skip until start is past prev end (going forward)
+  private final boolean isStrict;     // only true for coveredby; means skip things while iterating where the end is outside the bounds
+  /** true if bounds is one of sameBeginEnd, coveredBy, covering */
   private final boolean isBounded;
-  private final boolean isTypePriority;
-  private final boolean isPositionUsesType;
-  private final boolean isSkipEquals;
-  private final BoundsUse boundsUse;
+  /** for moveTo-leftmost, and bounds skipping if isSkipEquals */
+  private final boolean isUseTypePriority;
+//  private final boolean underlying_iterator_using_typepriorities;
+//  /** two uses: bounds skip if isSkipEqual, move-to-leftmost if !isUseTypePriority */
+//  private final boolean isPositionUsesType;
+  /** for bounds skipping alternative */
+  private final boolean isSkipSameBeginEndType;
+  /** one of notBounded, sameBeginEnd, coveredBy, covering */
+  private final BoundsUse boundsUse; 
   
   /**
-   * isEmpty is an expensive calculation, involving potentially traversing all the iterators in a particular type hierarchy
+   * isEmpty is a potentially expensive calculation, involving potentially traversing all the iterators in a particular type hierarchy
    * It is only done:
    *   - at init time
    *   - at moveToFirst/last/FS - these can cause regenerating the copy-on-write objects via the getNonNullCow call
@@ -136,7 +203,15 @@
   private final int boundEnd;
   private final TypeImpl boundType;
   
-  private final Comparator<TOP> annotationComparator;  // implements compare(fs1, fs2) for begin/end/type priority
+  /** null if ! isTypePriority */
+  private final LinearTypeOrder lto; 
+  
+  // only used in moveTo, in listform
+  // if ignoreTypeOrdering, use that form of comparator
+  private final Comparator<TOP> comparatorMaybeNoTypeWithoutId;  // implements compare(fs1, fs2) for begin/end/type priority
+
+  // only used when locating existing item after converting to list form
+  private final Comparator<TOP> annotationComparator_withId;
   private final JCasImpl jcas;
   
   /**
@@ -150,32 +225,33 @@
    * @param boundingAnnot null or the bounding annotation
    * @param ambiguous false means to skip annotations whose begin lies between previously returned begin (inclusive) and end (exclusive)
    * @param strict true means to skip annotations whose end is greater than the bounding end position (ignoring type priorities)
-   * @param isBounded false means it's an unambiguous iterator with no bounds narrowing
-   * @param isTypePriority false to ignore type priorities, and just use begin/end and maybe type
-   * @param isPositionUsesType only used if isTypePriority is false, and says to still compare types for eq
-   * @param isSkipEquals used only for bounded case, 
+   * @param boundsUse null if no bounds, boundingAnnot used for start position if non-null
+   * @param isUseTypePriority false to ignore type priorities, and just use begin/end and maybe type
+   * @param isSkipSameBeginEndType used only for coveredBy or covering case, 
    *                     false means to only skip returning an FS if it has the same id() as the bounding fs
-   * @param annotationComparator indexRepository.getAnnotationComparator() value
    */
   Subiterator(
       FSIterator<T> it, 
       AnnotationFS boundingAnnot, 
       boolean ambiguous, 
-      boolean strict,    // omit FSs whose end > bounds
+      boolean strict,    // omit FSs whose end > bounds, requires boundsUse == boundedby
       BoundsUse boundsUse, // null if no bounds; boundingAnnot used for start position if non-null
-      boolean isTypePriority,
-      boolean isPositionUsesType, 
-      boolean isSkipEquals,
-      Comparator<TOP> annotationComparator
+      boolean isUseTypePriority,
+      boolean isSkipSameBeginEndType  // useAnnotationEquals
       ) {
-    this.it = (FSIterator<Annotation>) it;
-    this.boundingAnnot = (Annotation) boundingAnnot;
+    
+    this.it = (LowLevelIterator<Annotation>) it;
+    this.boundingAnnot = (Annotation) boundingAnnot;  // could be same begin/end, coveredby, or covering
     this.isBounded = boundsUse != null && boundsUse != BoundsUse.notBounded;
     this.boundsUse = (boundsUse == null) ? BoundsUse.notBounded : boundsUse;
-    this.isAmbiguous = ambiguous;
+    this.isUnambiguous = !ambiguous;
+    if (strict) {
+      if (BoundsUse.coveredBy != boundsUse) {
+        throw new IllegalArgumentException("Strict requires BoundsUse.coveredBy");
+      }
+    }
     this.isStrict = strict;
-    this.isPositionUsesType = isPositionUsesType;
-    this.isSkipEquals = isSkipEquals;
+    this.isSkipSameBeginEndType = isSkipSameBeginEndType;
  
     if (isBounded && (null == boundingAnnot || !(boundingAnnot instanceof Annotation))) {
       Misc.internalError(new IllegalArgumentException("Bounded Subiterators require a bounding annotation"));
@@ -184,11 +260,23 @@
     this.boundEnd = isBounded ? boundingAnnot.getEnd(): -1;
     this.boundType = isBounded ? (TypeImpl) boundingAnnot.getType() : null;
 
-    this.isTypePriority = (boundsUse == BoundsUse.covering) ? false : isTypePriority;
+    FSIndexRepositoryImpl ir = this.it.ll_getIndex().getCasImpl().indexRepository;
+//    underlying_iterator_using_typepriorities =  ir.isAnnotationComparator_usesTypeOrder();
 
-    this.annotationComparator = annotationComparator;
-    this.jcas = (JCasImpl) ll_getIndex().getCasImpl().getJCas();
+    if (boundsUse == BoundsUse.covering && isUseTypePriority) {
+      throw new IllegalArgumentException("Cannot specify isUseTypePriority with BoundsUse.covering");
+    }
+
+    this.isUseTypePriority = isUseTypePriority;
+    lto = isUseTypePriority ? ir.getDefaultTypeOrder() : null;
     
+    this.comparatorMaybeNoTypeWithoutId = ir.getAnnotationFsComparator(
+        FSComparators.WITHOUT_ID, 
+        isUseTypePriority ?  FSComparators.WITH_TYPE_ORDER : FSComparators.WITHOUT_TYPE_ORDER);
+    this.annotationComparator_withId = ir.getAnnotationFsComparatorWithId();
+        
+    this.jcas = (JCasImpl) ll_getIndex().getCasImpl().getJCas();
+            
     if (boundsUse == BoundsUse.covering) {
       // compute start position and isEmpty setting
       int span = ((LowLevelIterator<?>)it).ll_maxAnnotSpan();  // an optimization, the largest end-begin annotation
@@ -215,7 +303,7 @@
   private void moveToStartSetEmptyAndId() {
     moveToStart();
     isEmpty = !isValid();
-    startId = isValid() ? get()._id() : 0;    
+    startId = isValid() ? getNvc()._id() : 0;    
   }
    
   /** 
@@ -224,11 +312,13 @@
    * @param boundingAnnot -
    * @param ambiguous -
    * @param strict -
-   * @param isBounded -
-   * @param isTypePriority -
-   * @param isPositionUsesType -
-   * @param isSkipEquals -
-   * @param annotationComparator -
+   * @param boundsUse -
+   * @param isUseTypePriority -
+   * @param isSkipSameBeginEndType -
+   * @param startId -
+   * @param isEmpty -
+   * @param converingStartPos -
+   * @param converingEndPos -
    */
   Subiterator(
       FSIterator<Annotation> it, 
@@ -236,283 +326,115 @@
       boolean ambiguous, 
       boolean strict,    // omit FSs whose end > bounds
       BoundsUse boundsUse, // null if boundingAnnot being used for starting position in unambiguous iterator
-      boolean isTypePriority,
-      boolean isPositionUsesType, 
-      boolean isSkipEquals,
-      Comparator<TOP> annotationComparator,
+      boolean isUseTypePriority,
+      boolean isSkipSameBeginEndType,
       int startId,
       boolean isEmpty,
       Annotation coveringStartPos,
       Annotation coveringEndPos
       ) {
-    this.it = it;
-    this.boundingAnnot = boundingAnnot;
-    this.isBounded = boundsUse != null;
-    this.boundsUse = boundsUse;
-    this.isAmbiguous = ambiguous;
+    
+    this.it = (LowLevelIterator<Annotation>) it;
+    this.boundingAnnot = (Annotation) boundingAnnot;  // could be same begin/end, coveredby, or covering
+    this.isBounded = boundsUse != null && boundsUse != BoundsUse.notBounded;
+    this.boundsUse = (boundsUse == null) ? BoundsUse.notBounded : boundsUse;
+    this.isUnambiguous = !ambiguous;
+    if (strict) {
+      if (BoundsUse.coveredBy != boundsUse) {
+        throw new IllegalArgumentException("Strict requires BoundsUse.coveredBy");
+      }
+    }
     this.isStrict = strict;
-    this.isTypePriority = isTypePriority;
-    this.isPositionUsesType = isPositionUsesType;
-    this.isSkipEquals = isSkipEquals;
-    this.startId = startId;
+    this.isSkipSameBeginEndType = isSkipSameBeginEndType;
 
     this.boundBegin = isBounded ? boundingAnnot.getBegin() : -1;
     this.boundEnd = isBounded ? boundingAnnot.getEnd(): -1;
     this.boundType = isBounded ? (TypeImpl) boundingAnnot.getType() : null;
+
+    FSIndexRepositoryImpl ir = this.it.ll_getIndex().getCasImpl().indexRepository;
+//    underlying_iterator_using_typepriorities =  ir.isAnnotationComparator_usesTypeOrder();
+
+    this.isUseTypePriority = isUseTypePriority;
+    lto = isUseTypePriority ? ir.getDefaultTypeOrder() : null;
+
+    this.comparatorMaybeNoTypeWithoutId = ir.getAnnotationFsComparator(
+        FSComparators.WITHOUT_ID, 
+        isUseTypePriority ?  FSComparators.WITH_TYPE_ORDER : FSComparators.WITHOUT_TYPE_ORDER);
+    this.annotationComparator_withId = ir.getAnnotationFsComparatorWithId();
     
-    this.annotationComparator = annotationComparator;
-    this.isEmpty = isEmpty;
     this.jcas = (JCasImpl) ll_getIndex().getCasImpl().getJCas();
+    
     this.coveringStartPos = coveringStartPos;
     this.coveringEndPos = coveringEndPos;
+    this.startId = startId;
+    this.isEmpty = isEmpty;
+    if (isEmpty) {
+      makeInvalid();
+    }    
   }
 
   /**
    * Converting to list form - called for 
    *   unambiguous iterator going backwards, 
    *   unambiguous iterator doing a moveTo(fs) operation
-   *   iterator doing a moveToLast() operation
-   * 
+   *   unambiguous iterator doing a moveToLast() operation 
    */
+  
   private void convertToListForm() {
-    moveToStart();  // moves to the start annotation, including moving past equals for annot style, and accommodating strict
+    moveToStart();  // moves to the start annotation, including moving past equals for annot style, 
+                    // and accommodating strict
     this.list = new ArrayList<Annotation>();
     while (isValid()) {
       list.add((Annotation) it.getNvc());
-      moveToNext();
+      moveToNext();  // does all the adjustments, so list has only appropriate elements
     }
     this.pos = 0;
     isListForm = true;  // do at end, so up to this point, iterator is not the list form style
   }
   
-  private void moveToExact(Annotation targetAnnotation) {
-    it.moveTo(targetAnnotation);  // move to left-most equal one
-    boolean found = adjustForTypePriorityBoundingBegin(targetAnnotation._id);
-    if (!found)
-    while (it.isValid()) {         // advance to the exact equal one
-      if (targetAnnotation._id() == it.getNvc()._id()) {
-        break;
-      }
-      it.moveToNext();
-    }
-  }
+  
   /**
-   * Move to the starting position of the sub iterator
-   * isEmpty may not yet be set
+   * Move to the starting position of the sub iterator.
+   * isEmpty may not yet be set.
+   * Never list form when called.
    */
   private void moveToStart() {
+    
     switch (boundsUse) {
+    
     case notBounded:
-      it.moveToFirst();
+      it.moveToFirstNoReinit();
       break;
+      
     case sameBeginEnd:
-      it.moveTo(boundingAnnot);
-      adjustForTypePriorityBoundingBegin(0);
-      skipOverBoundingAnnot(true);
-      maybeMakeItInvalidSameBeginEnd(); 
-    case coveredBy:
-      it.moveTo(boundingAnnot);
-      adjustForTypePriorityBoundingBegin(0);
-      adjustForStrictOrCoveringAndBoundSkip(true); // forward
+      it.moveToNoReinit(boundingAnnot);
+      if (it.isValid()) {
+        skipOverBoundingAnnot(IS_GOING_FORWARDS);
+      }
       break;
+    
+    case coveredBy:
+      it.moveToNoReinit(boundingAnnot);
+      if (it.isValid()) {
+        adjustForStrictOrCoveringAndBoundSkipNvc(IS_GOING_FORWARDS);
+      }
+      break;
+    
     case covering:
-      it.moveTo(coveringStartPos); // sufficiently before the bounds
-      adjustForTypePriorityBoundingBegin(0);
-      adjustForCoveringAndBoundSkip(true);  // forward
+      it.moveToNoReinit(coveringStartPos); // sufficiently before the bounds
+      if (it.isValid()) {
+        adjustForCoveringAndBoundSkip(IS_GOING_FORWARDS); 
+      }
       break;
     }
+    
+    if (! isBoundOk()) {
+      return;
+    }
+    
     maybeSetPrevEnd();  // used for unambiguous
   }
   
-  private void adjustForStrictOrCoveringAndBoundSkip(boolean forward) {
-    if (boundsUse == BoundsUse.covering) {
-      adjustForCoveringAndBoundSkip(forward);
-      return;
-    }
-    // this used for both coveredBy and sameBeginEnd
-    adjustForStrict(forward);
-    if (skipOverBoundingAnnot(forward)) {
-      adjustForStrict(forward);
-    }
-  }
-  
-  private void adjustForCoveringAndBoundSkip(boolean forward) {
-    adjustForCovering(forward);
-    if (skipOverBoundingAnnot(forward)) {
-      adjustForCovering(forward);
-    }    
-  }
-  
-  /**
-   * advance over FSs that are equal (2 choices) to the bounding annotation.
-   * May leave the iterator in invalid state.
-   * @param forward - true means move forward, false means move backwards
-   * @return true if some move happened, false if nothing happened
-   */
-  private boolean skipOverBoundingAnnot(boolean forward) {
-    boolean moved = false;
-    if (isBounded && it.isValid()) { // skip if not bounded or iterator is invalid
-      while (equalToBounds(it.getNvc())) {
-        moved = true;
-        if (forward) {
-          it.moveToNextNvc();
-        } else {
-          maybeMoveToPrevBounded();
-        }
-        if (!it.isValid()) {
-          break;
-        }
-      }
-    }
-    return moved;
-  }
-  
-  /**
-   * Special equalToBounds used only for having bounded iterators 
-   * skip returning the bounding annotation
-   * 
-   * Two styles: uimaFIT style: only skip the exact one (id's the same)
-   *             uima style: skip all that compare equal using the AnnotationIndex comparator
-   * @param fs -
-   * @return true if should be skipped
-   */
-  private boolean equalToBounds(Annotation fs) {
-    return fs._id == boundingAnnot._id ||
-           (isSkipEquals && annotationComparator.compare(fs,  boundingAnnot) == 0);
-  }
-    
-  private void maybeSetPrevEnd() {
-    if (!isAmbiguous && it.isValid()) {
-      this.prevEnd = it.getNvc().getEnd();
-    }    
-  }
-  
-  
-  /**
-   * For strict mode, advance iterator until the end is within the bounding end 
-   */
-  private void adjustForStrict(boolean forward) {
-    if (isStrict && boundsUse == BoundsUse.coveredBy) {
-      while (it.isValid() && (it.getNvc().getEnd() > this.boundEnd)) {
-        if (forward) {
-          it.moveToNextNvc();
-        } else {
-          maybeMoveToPrevBounded();
-        }
-      }
-    }
-  }
-  
-  /**
-   * when covering (which is different from coveredBy and sameBeginEnd,
-   *  means get all annotations which span the bounds), 
-   *  skip items where the end < bounds end,
-   *    because those items don't span the bounding FS
-   * 
-   * Edge case: item with same begin and end is considered "covering"
-   *              but subject to exclusion based on equalToBounds skipping
-   * Cases:
-   *   position of begin is after span begin - mark "invalid"
-   *   position of begin is before or == span begin:
-   *     position of end is == or > span end: OK
-   *     position of end is < span end:
-   *     if backward: moveToPrev until get valid position or run out.  if run out, mark invalid
-   *     if forward: move to next until position of begin advances but is <= span begin.
-   *      
-   * @param forward
-   */
-  private void adjustForCovering(boolean forward) {
-    if (!it.isValid()) {
-      return;
-    }
-    // moveTo may move to invalid position
-    // if the cur pos item has a begin beyond the bound, it cannot be a covering annotation
-    if (it.getNvc().getBegin() > this.boundBegin) {
-      makeInvalid();
-      return;
-    }
-    
-    // skip until get an FS whose end >= boundEnd, it is a candidate.
-    //   stop if begin gets too large (going forwards)
-    while (it.isValid() && (it.getNvc().getEnd() < this.boundEnd)) {
-      if (forward) {
-        it.moveToNextNvc();
-        if (it.isValid() && it.getNvc().getBegin() > this.boundBegin) {
-          makeInvalid();
-          return;
-        }
-      } else {
-        maybeMoveToPrevBounded();
-      }
-    }
-  }
-  
-  /**
-   * Assume: iterator is valid
-   */
-  private void maybeMoveToPrevBounded() {
-    if (it.get()._id == startId) {
-      it.moveToFirst();  // so next is invalid
-    }
-    it.moveToPreviousNvc();
-  }
-  
-  /**
-   * moves the iterator backwards if not using type priorities
-   * to the left most position with the same begin /end (and maybe type) as the fs at the current position.
-   * @param exactId 0 or the id to stop the traversal on
-   * @return false unless stopped on the matching exactId
-   */
-  private boolean adjustForTypePriorityBoundingBegin(int exactId) {
-    if (isTypePriority || !it.isValid()) {
-      return false;
-    }
-    Annotation a = it.get();
-    int begin = a.getBegin();
-    int end = a.getEnd();
-    Type type = a.getType();
-    do {
-      int id = it.get()._id;
-      if (id == exactId) {
-        return true;
-      }
-      if (id == startId) { // start id may not be set yet; if so it is set to 0 so this test is always false
-        return false;  // iterator is at the start, can't move more
-      }
-      it.moveToPrevious();
-      if (!it.isValid()) {
-        it.moveToFirst();  // not moveToStart - called by moveToStart
-//        Annotation f = it.getNvc();
-//        if (!isBeginEndTypeEqualToBound(it.getNvc())) {
-//          it.moveToPrevious();  // make invalid
-//        }      
-        return false;  
-      }
-    } while (isBeginEndTypeEqual(it.get(), begin, end, type));
-    it.moveToNext();  // went back one to far
-    return false;
-  }
-    
-//  private boolean isBeginEndTypeEqualToBound(Annotation fs) {
-//    return fs.getBegin() == boundBegin && fs.getEnd() == boundEnd &&
-//            (!isPositionUsesType || fs.getType() == boundType);
-//  }
-  
-  private boolean isBeginEndTypeEqual(Annotation fs, int begin, int end, Type type) {
-    return fs.getBegin() == begin && fs.getEnd() == end &&
-        (!isPositionUsesType || fs.getType() == type);
-  }
-  
-  /**
-   * For unambiguous, going forwards
-   */
-  private void movePastPrevAnnotation() {
-    if (!isAmbiguous) {
-      while (it.isValid() && (it.get().getBegin() < this.prevEnd)) {
-        it.moveToNext();
-      }
-    }
-  }
   
   
   /*
@@ -522,47 +444,40 @@
    */
   @Override
   public boolean isValid() {
-    if (isEmpty) return false;
     if (isListForm) {
       return (this.pos >= 0) && (this.pos < this.list.size());
     }
-    
-    if (!it.isValid()) {
-      return false;
-    }
-    
-    switch (boundsUse) {
-    case notBounded:
-      return true;
-    case coveredBy:
-      return it.get().getBegin() <= boundEnd;
-    case covering:
-      return it.isValid();
-    case sameBeginEnd:
-      Annotation a = it.get();
-      return a.getBegin() == boundBegin &&
-             a.getEnd() == boundEnd;
-    }
-    return false; // ignored, just hear to get rid of invalid compiler error report
-  }
 
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.cas.FSIterator#get()
-   */
-  @Override
-  public T get() throws NoSuchElementException {
-    if (isListForm) {
-      if ((this.pos >= 0) && (this.pos < this.list.size())) {
-        return (T) this.list.get(this.pos);
-      }
-    } else {
-      if (isValid()) {
-        return (T)it.get();
-      }
-    }
-    throw new NoSuchElementException();
+    // assume all non-list form movements leave the underlying iterator
+    //   positioned either as invalid, or at the valid spot including the bounds, for 
+    //   a get();
+    
+    return it.isValid();
+//    if (!it.isValid()) {
+//      return false;
+//    }
+//        
+//    // if iterator is valid, may still be invalid due to bounds
+//    switch (boundsUse) {
+//    case notBounded:
+//      return true;
+//      
+//    case coveredBy: {
+//      Annotation item = it.getNvc();
+//      if (item.getBegin() > boundEnd) return false;
+//      if 
+//    }
+//      if (t.get().getBegin() <= boundEnd;
+//      
+//      
+//    case covering:
+//      return it.isValid();
+//    case sameBeginEnd:
+//      Annotation a = it.get();
+//      return a.getBegin() == boundBegin &&
+//             a.getEnd() == boundEnd;
+//    }
+//    return false; // ignored, just hear to get rid of invalid compiler error report
   }
 
   /*
@@ -577,106 +492,70 @@
       return (T)it.getNvc();
     }
   }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.cas.FSIterator#moveToNext()
-   */
-  @Override
-  public void moveToNext() {
-    if (!isValid()) return;
-    moveToNextNvc();
-  }
   
   @Override
-  public void moveToNextNvc() {
+  public void moveToNextNvc() {  
+    // no isValid check because caller checked: "Nvc"
     if (isListForm) {
       ++this.pos;
       // maybeSetPrevEnd not needed because list form already accounted for unambiguous
       return;
     }
-   
-    if (isEmpty) {
-      return;
-    }
-    
+      
     it.moveToNextNvc();
-    if (!isAmbiguous) {               // skip until start > prev end
+    if (isUnambiguous) {               // skip until start > prev end
       movePastPrevAnnotation();
     }
 
-    adjustForStrictOrCoveringAndBoundSkip(true);
+    adjustForStrictOrCoveringAndBoundSkip(IS_GOING_FORWARDS);
     
     // stop logic going forwards for various bounding cases
     if (it.isValid()) {
       // stop in bounded case if out of bounds going forwards UIMA-5063
-      switch(boundsUse) {
-      case notBounded: 
-        break;
-      case coveredBy:
-        maybeMakeItInvalid_bounds(it.getNvc(), a -> a.getBegin() > boundEnd);
-        break;
-      case covering:
-        maybeMakeItInvalid_bounds(it.getNvc(), a -> a.getBegin() > boundBegin);
-        break;
-      case sameBeginEnd:
-        maybeMakeItInvalidSameBeginEnd();
-        break;
+      if ( ! isBoundOkNvc()) {
+        return;
       }
+//      switch(boundsUse) {
+//      case notBounded: 
+//        break;
+//      case coveredBy:
+//        maybeMakeItInvalid_bounds(it.getNvc(), a -> a.getBegin() > boundEnd);
+//        break;
+//      case covering:
+//        maybeMakeItInvalid_bounds(it.getNvc(), a -> a.getBegin() > boundBegin);
+//        break;
+//      case sameBeginEnd:
+//        maybeMakeItInvalidSameBeginEnd();
+//        break;
+//      }
     } 
     maybeSetPrevEnd();
   }
-  
-  private void maybeMakeItInvalidSameBeginEnd() {
-    maybeMakeItInvalid_bounds(it.getNvc(), a -> a.getBegin() != boundBegin || a.getEnd() != boundEnd);
-  }
-  
-  private void maybeMakeItInvalid_bounds(Annotation a, Predicate<Annotation> outOfBounds) {
-    if (outOfBounds.test(a)) {
-      makeInvalid();
-    }
-  }
-  
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.cas.FSIterator#moveToPrevious()
-   */
-  public void moveToPrevious() {
-    if (!isValid()) {
-      return;
-    }
-    moveToPreviousNvc();
-  }
-  
+    
   @Override  
-  public void moveToPreviousNvc() {
+  public void moveToPreviousNvc() {    
+    // no isValid check because caller checked: "Nvc"
     if (isListForm) {
       --this.pos;
       return;
     }
     
-    if (isEmpty) {
-      return;
-    }
-
-    if (!isAmbiguous) {
+    if (isUnambiguous) {
       // Convert to list form
-      Annotation currentAnnotation = it.get();  // save to restore position
+      Annotation currentAnnotation = it.getNvc();  // save to restore position
       convertToListForm();
-      moveToExact(currentAnnotation);
+      pos = Collections.binarySearch(this.list, currentAnnotation, annotationComparator_withId);
       --this.pos;
       return;
     }
 
-    if (it.isValid()) {
-      maybeMoveToPrevBounded();
-    }
+    // is ambiguous, not list form
+    maybeMoveToPrevBounded();  // makes iterator invalid if moving before startId 
 
-    adjustForStrictOrCoveringAndBoundSkip(false); // moving backwards
-    // stop logic going backwards for various bounding cases
-    // this is done by the maybeMoveToPrev call, where it compares to the saved startId
+    adjustForStrictOrCoveringAndBoundSkip(IS_GOING_BACKWARDS); 
+    
+  // stop logic going backwards for various bounding cases
+  // this is done by the maybeMoveToPrev call, where it compares to the saved startId
 //    if (it.isValid()) {
 //      // stop in bounded case if out of bounds going forwards UIMA-5063
 //      switch(boundsUse) {
@@ -698,15 +577,10 @@
   /*
    * (non-Javadoc)
    * 
-   * @see org.apache.uima.cas.FSIterator#moveToFirst()
+   * @see org.apache.uima.cas.FSIterator#moveToFirstNoReinit()
    */
   @Override
-  public void moveToFirst() {
-    if (isIndexesHaveBeenUpdated()) {
-      resetList();
-      moveToStartSetEmptyAndId();
-      return;
-    }    
+  public void moveToFirstNoReinit() {
   
     if (isEmpty) {
       return;
@@ -731,19 +605,19 @@
   /*
    * This operation is relatively expensive one time for unambiguous
    * 
-   * @see org.apache.uima.cas.FSIterator#moveToLast()
+   * @see org.apache.uima.cas.FSIterator#moveToLastNoReinit()
    */
   @Override
-  public void moveToLast() {
-    if (isIndexesHaveBeenUpdated()) {
-      moveToFirst(); // done to recompute is empty, reset list, recompute bounds, etc.
-    }
+  public void moveToLastNoReinit() {
+//    if (isIndexesHaveBeenUpdated()) {
+//      moveToFirst(); // done to recompute is empty, reset list, recompute bounds, etc.
+//    }
     
     if (isEmpty) {
       return;
     }
     
-    if (!isAmbiguous && !isListForm) {
+    if (isUnambiguous && !isListForm) {
       convertToListForm();
     }
     
@@ -785,7 +659,7 @@
    * @param goBackwards when true, continue to backup
    */
   private void moveToJustPastBoundsAndBackup(int begin, int end, Predicate<Annotation> goBackwards) {
-    it.moveTo(new Annotation(jcas, begin, end));
+    it.moveToNoReinit(new Annotation(jcas, begin, end));
     if (it.isValid()) {
       Annotation a = it.getNvc();
       while (goBackwards.test(a)) {
@@ -802,7 +676,7 @@
         a = it.getNvc();
       }
     } else {
-      it.moveToLast();
+      it.moveToLastNoReinit();
       adjustForStrictOrCoveringAndBoundSkip(false);
     }
   }
@@ -837,18 +711,18 @@
   /*
    * (non-Javadoc)
    * 
-   * @see org.apache.uima.cas.FSIterator#moveTo(org.apache.uima.cas.FeatureStructure)
+   * @see org.apache.uima.cas.FSIterator#moveToNoReinit(org.apache.uima.cas.FeatureStructure)
    */
   @Override
-  public void moveTo(FeatureStructure fs) {
-    if (isIndexesHaveBeenUpdated()) {
-      moveToFirst(); // done to recompute is empty, reset list, recompute bounds, etc.
+  public void moveToNoReinit(FeatureStructure fs) {
+    if (! (fs instanceof Annotation)) {
+      throw new IllegalArgumentException("Argument must be a subtype of Annotation");
     }
     
     if (isEmpty) return;
     
     Annotation fsa = (Annotation) fs;
-    if (!isAmbiguous && !isListForm) {  // unambiguous must be in list form
+    if (isUnambiguous && !isListForm) {  // unambiguous must be in list form
       convertToListForm();
     }
     
@@ -858,97 +732,447 @@
       // W A R N I N G - don't use it.xxx forms here, they don't work for list form
       // Don't need strict, skip-over-boundary, or type priority adjustments, 
       //   because these were done when the list form was created
-      pos = Collections.binarySearch(this.list, fsa, annotationComparator);
+      //   Want to move to leftmost
+      pos = Collections.binarySearch(this.list, fsa, comparatorMaybeNoTypeWithoutId);
       int begin = fsa.getBegin();
       int end   = fsa.getEnd();
       Type type = fsa.getType();
 
+      // Go back until we find a FS that is really smaller
+
       if (pos >= 0) {
+        moveToPrevious();
+      } else {
+        // no exact match
+        pos = (-pos) - 1;
+        
         if (!isValid()) {
+          // means the position is one beyond the end - where the insert should be.
           return;
         }
+      }
+      
+      // next compare is without type if isUseTypePriority is false
+      while (isValid() && 0 == comparatorMaybeNoTypeWithoutId.compare((Annotation)getNvc(), fsa)) {
+        moveToPreviousNvc();
+      }
         
-        // Go back until we find a FS that is really smaller
-        moveToPrevious();
-        
-        while (isValid() && isBeginEndTypeEqual((Annotation) get(), begin, end, type)) {
-          moveToPrevious();
-        }
-        
-        if (isValid()) {
-          moveToNext();  // backed up one to much          
-        } else {
-          moveToFirst();
-        }
-          
+      if (isValid()) {
+        moveToNextNvc();  // backed up one to much          
       } else {
-        // element wasn't found, 
-        //set the position to the next (greater) element in the list or to an invalid position 
-        //   if no element is greater
-        pos = (-pos) - 1;
-        if (!isValid()) {
-          moveToLast();
+        moveToFirstNoReinit();
+      }          
+
+      return;
+    } 
+    
+    
+    // not list form
+    // is ambiguous (because if unambiguous, would have been converted to list), may be strict.
+    // Always bounded (if unbounded, that's only when subiterator is being used to 
+    // implement "unambiguous", and that mode requires the "list" form above.)
+    // can be one of 3 bounds: coveredBy, covering, and sameBeginEnd.
+    
+    it.moveToNoReinit(fs);  // may move before, within, or after bounds
+    if (!it.isValid()) {
+      makeInvalid();
+      return;
+    }
+    
+    if ((boundsUse == BoundsUse.coveredBy ||
+         boundsUse == BoundsUse.sameBeginEnd) &&
+        it.getNvc().getBegin() < boundBegin) {
+      moveToFirstNoReinit();  
+    } else if (isAboveBound()) {
+      makeInvalid();
+      return;
+    }
+
+    // next call will mark iterator invalid if goes out of bounds while adjusting
+    adjustForStrictOrCoveringAndBoundSkip(IS_GOING_FORWARDS); // "covering" case adjustments
+      
+//      if (it.isValid()) {
+//        // if beyond bound, mark invalid 
+//        // if before bound, move to first
+//        Annotation a = it.get();
+//        
+//        switch (boundsUse) {
+//        case coveredBy:
+//        case sameBeginEnd:
+//          if (a.getBegin() > boundEnd) {
+//            makeInvalid();
+//          } else if (isUseTypePriority && annotationComparator.compare(a,  boundingAnnot) < 0) {
+//            // with type priority, position is before bound.
+//            moveToFirstNoReinit();
+//          } else { // is not type priority case - see if too low
+//            final int b = a.getBegin();
+//            final int e = a.getEnd();
+//            if (b < boundBegin ||  
+//                ( b == boundBegin && e > boundEnd)) {
+//              moveToFirstNoReinit();
+//            } else if (isPositionUsesType && 
+//                       b == boundBegin && 
+//                       e == boundEnd &&
+//                       a.getType() != boundType) {
+//              /** Subiterator {0} has bound type: {1}, begin: {2}, end: {3}, for coveredBy, not using type priorities, matching FS with same begin end and different type {4}, cannot order these*/
+//                     throw new CASRuntimeException(CASRuntimeException.SUBITERATOR_AMBIGUOUS_POSITION_DIFFERENT_TYPES, 
+//                         this, boundType.getName(), b, e, a.getType().getName()); 
+//                   }
+//          }
+//          break;
+//        case covering:
+//          break;
+//        default:
+//          Misc.internalError();
+//        }
+//      }
+    
+  }
+  
+  private boolean isBoundOk() {
+    if ( ! it.isValid()) {
+      return false;
+    }
+    return isBoundOkNvc();
+  }
+ 
+  private boolean isBoundOkNvc() {
+    if ( ! it.isValid()) {
+      return false;
+    }
+    if (boundsUse == BoundsUse.notBounded) {
+      return true;
+    }
+    
+    Annotation a = it.getNvc();
+    int begin = a.getBegin();
+    int end = a.getEnd();
+    boolean ok;
+    
+    switch (boundsUse) {
+    
+    case covering:
+      if (begin == boundBegin && end == boundEnd) {
+        ok = (lto == null) || lto.lessThan(a._getTypeImpl(), boundType);
+      } else {
+        ok = begin <= boundBegin &&
+             end    >= boundEnd;
+      }
+      break;
+      
+    case coveredBy:
+      if (begin == boundBegin && end == boundEnd) {
+        ok = (lto == null) || lto.lessThan(boundType, a._getTypeImpl());
+      } else {
+        ok = begin >= boundBegin && 
+             begin <= boundEnd;
+      }
+      break;
+             // getEnd not tested, doesn't play a role unless strict, which is tested elsewhere
+//    case sameBeginEnd:  // equivalent to default
+    case sameBeginEnd:
+    default:       // the default case is sameBeginEnd 
+      if (begin == boundBegin && end == boundEnd) {
+        ok = (lto == null) || boundType == a._getTypeImpl();
+      } else {
+        ok = false;
+      }
+      break;
+    }
+    
+    
+    if (! ok) {
+      makeInvalid();
+    }
+    return ok;
+  }
+  
+  private boolean isAboveBound() {
+    Annotation a = it.getNvc();
+    switch (boundsUse) {
+    case notBounded:
+      return false;
+    case covering:
+      return a.getBegin() > boundBegin;
+    case coveredBy:
+      return a.getBegin() > boundEnd;
+//    case sameBeginEnd:  // equivalent to default
+    default:
+      return a.getBegin() != boundBegin || a.getEnd() < boundEnd;
+    }
+  }
+  
+  /**
+   * While adjusting, check for going out of bounds, and mark iterater invalid if so.
+   * 
+   * @param forward_or_backward - true for forward
+   */
+  private void adjustForStrictOrCoveringAndBoundSkip(boolean forward_or_backward) {
+    if ( ! isValid() ) {
+      return;
+    }
+    adjustForStrictOrCoveringAndBoundSkipNvc(forward_or_backward);
+  }
+  
+  private void adjustForStrictOrCoveringAndBoundSkipNvc(boolean forward_or_backward) {
+    if (boundsUse == BoundsUse.covering) {
+      adjustForCoveringAndBoundSkip(forward_or_backward);
+      return;
+    }
+
+    // this used for both coveredBy and sameBeginEnd
+    adjustForStrict(forward_or_backward);  // skips if needed because end is out of range
+    if (skipOverBoundingAnnot(forward_or_backward)) { // skips if match the bound
+      adjustForStrict(forward_or_backward);  // re-do strict skip if above moved
+    }
+  }
+  
+  /**
+   * Marks iterator invalid if out of bounds
+   * @param forward_or_backwards true for forwards
+   */ 
+  private void adjustForCoveringAndBoundSkip(boolean forward_or_backwards) {
+    adjustForCovering(forward_or_backwards);
+    if (skipOverBoundingAnnot(forward_or_backwards)) {
+      // may not be invalid, incase there are multiple FSs with same begin/end
+      adjustForCovering(forward_or_backwards);
+    }    
+  }
+  
+  /**
+   * Marks iterator invalid if move makes it beyond bounds
+   * 
+   * advance over FSs that are equal (2 choices) to the bounding annotation.
+   * May leave the iterator in invalid state.
+   * @param forward - true means move forward, false means move backwards
+   * @return true if some move happened, false if nothing happened
+   */
+  private boolean skipOverBoundingAnnot(boolean forward) {
+    boolean moved = false;
+    if (isBounded && it.isValid()) { // skip if not bounded or iterator is invalid
+      while (equalToBounds(it.getNvc())) {
+        moved = true;
+        if (forward) {
+          it.moveToNextNvc();
+        } else {
+          maybeMoveToPrevBounded();
+        }
+        if (!it.isValid()) {
+          break;
+        }
+        if ( ! isBoundOkNvc()) {
+          return true;
+        }        
+      }
+    }
+    return moved;
+  }
+  
+  /**
+   * Special equalToBounds used only for having bounded iterators 
+   * skip returning the bounding annotation
+   * 
+   * Two styles: uimaFIT style: only skip the exact one (id's the same)
+   *             uima style: skip all that compare equal using the AnnotationIndex comparator
+   * @param fs -
+   * @return true if should be skipped
+   */
+  private boolean equalToBounds(Annotation fs) {
+    if (fs._id == boundingAnnot._id) return true;
+    
+    if (isSkipSameBeginEndType) {
+      return isBeginEndTypeEqual(fs, boundBegin, boundEnd, boundType);
+    }
+    return false;
+  }
+    
+  private void maybeSetPrevEnd() {
+    if (isUnambiguous && it.isValid()) {
+      this.prevEnd = it.getNvc().getEnd();
+    }    
+  }
+  
+  
+  /**
+   * For strict mode (implies coveredby), move iterator until the end is within the bounding end
+   * Check after any move if out-of-bounds, and mark invalid if so. 
+   * 
+   * While moving forwards,  mark iterator invalid if its begin > boundEnd.
+   * While moving backwards, mark iterator invalid if begin < boundBegin.
+   * While moving, skip over FSs that are equal (2 choices) to the bounding annotation. 
+   */
+  private void adjustForStrict(boolean forward) {
+    if (!isValid()) {
+      return;
+    }
+    
+    if (isStrict) {
+      Annotation item = it.getNvc();
+      while (item.getEnd() > this.boundEnd) {
+        if (forward) {
+          it.moveToNextNvc();
           if (!isValid()) {
             return;
           }
-        }
-        while (isValid() && isBeginEndTypeEqual((Annotation) get(), begin, end, type)) {
-          moveToPrevious();
-        }
-        if (!isValid()) {
-          moveToFirst();
-          return;
-        }
-        moveToNext();  // back up one
-      }
-    } else {
-      // not list form
-      // is ambiguous, may be strict.
-      // Always bounded (if unbounded, that's only when subiterator is being used to 
-      // implement "unambiguous", and that mode requires the "list" form above.)
-      // can be one of 3 bounds: coveredBy, covering, and sameBeginEnd.
-      it.moveTo(fs);  // may move before, within, or after bounds
-      adjustForTypePriorityBoundingBegin(0);  // does nothing if using type priorities
-      adjustForStrictOrCoveringAndBoundSkip(true); // "covering" case adjustments
-      
-      if (it.isValid()) {
-        // if beyond bound, mark invalid 
-        // if before bound, move to first
-        Annotation a = it.get();
-        
-        switch (boundsUse) {
-        case coveredBy:
-        case sameBeginEnd:
-          if (a.getBegin() > boundEnd) {
+          item = it.getNvc();
+          if (item.getBegin() > this.boundEnd) {
             makeInvalid();
-          } else if (isTypePriority && annotationComparator.compare(a,  boundingAnnot) < 0) {
-            // with type priority, position is before bound.
-            moveToFirst();
-          } else { // is not type priority case - see if too low
-            final int b = a.getBegin();
-            final int e = a.getEnd();
-            if (b < boundBegin ||  
-                ( b == boundBegin && e > boundEnd)) {
-              moveToFirst();
-            } else if (isPositionUsesType && 
-                       b == boundBegin && 
-                       e == boundEnd &&
-                       a.getType() != boundType) {
-              /** Subiterator {0} has bound type: {1}, begin: {2}, end: {3}, for coveredBy, not using type priorities, matching FS with same begin end and different type {4}, cannot order these*/
-                     throw new CASRuntimeException(CASRuntimeException.SUBITERATOR_AMBIGUOUS_POSITION_DIFFERENT_TYPES, 
-                         this, boundType.getName(), b, e, a.getType().getName()); 
-                   }
+            return;
           }
-          break;
-        case covering:
-          break;
-        default:
-          Misc.internalError();
+        } else {
+          maybeMoveToPrevBounded(); // makes iterator invalid if moving before startId
+          if (!isValid()) {
+            return;
+          }
+          item = it.getNvc();
         }
       }
     }
   }
   
+  /**
+   * Marks iterator invalid if moves beyond bound
+   * 
+   * when covering (which is different from coveredBy and sameBeginEnd,
+   *  means get all annotations which span the bounds), 
+   *  skip items where the end < bounds end,
+   *    because those items don't span the bounding FS
+   * 
+   * Edge case: item with same begin and end is considered "covering"
+   *              but subject to exclusion based on equalToBounds skipping
+   * Cases:
+   *   position of begin is after span begin - mark "invalid"
+   *   position of begin is before or == span begin:
+   *     position of end is == or > span end: OK
+   *     position of end is < span end:
+   *     if backward: moveToPrev until get valid position or run out.  if run out, mark invalid
+   *     if forward: move to next until position of begin advances but is <= span begin.
+   *      
+   * @param forward
+   */
+  private void adjustForCovering(boolean forward) {
+    if (!it.isValid()) {
+      return;
+    }
+    // moveTo may move to invalid position
+    // if the cur pos item has a begin beyond the bound, it cannot be a covering annotation
+    if (it.getNvc().getBegin() > this.boundBegin) {
+      makeInvalid();
+      return;
+    }
+    
+    // skip until get an FS whose end >= boundEnd, it is a candidate.
+    //   stop if begin gets too large (going forwards)
+    while (it.isValid() && (it.getNvc().getEnd() < this.boundEnd)) {
+      if (forward) {
+        it.moveToNextNvc();
+        if (it.isValid() && it.getNvc().getBegin() > this.boundBegin) {
+          makeInvalid();
+          return;
+        }
+      } else {
+        maybeMoveToPrevBounded();  // move to prev, if hit bound, makes invalid
+      }
+    }
+  }
+  
+  /**
+   * Assume: iterator is valid
+   */
+  private void maybeMoveToPrevBounded() {
+    if (it.getNvc()._id == startId) {
+      it.moveToFirstNoReinit();  // so next is invalid
+    }
+    it.moveToPreviousNvc();
+  }
+  
+//  /**
+//   * Adjust in case the underlying iterator is using type priorities, but we want to ignore them.
+//   *   For the case where there's a moveTo(fs) operation, that didn't go to the left-most due to 
+//   *   type priorities.
+//   * if not using type priorities (but comparator has type priorities),
+//   *   move backwards among equal begin/end/(maybe type) as current element,
+//   *     stop if get to exact equal id, or hit iterator boundary
+//   * @param exactId 0 or the id to stop the traversal on
+//   * @return true if stopped on equal exactId
+//   */
+//  private boolean maybe_adjustToLeftmost_IgnoringTypePriority_boundingBegin(int exactId) {
+//        
+//    if (this.isUseTypePriority) {
+//      return false; // skip if this subiterator is using type priorities
+//    }
+//    
+//    // not using type priorities.
+////    if (isPositionUsesType) {
+//      // even though type priorities are not being used, need to go to leftmost of the same type
+//      // as the bounding annotation.  No way to do this...  So not implementing this for now.
+////    }
+//
+//    if (!this.underlying_iterator_using_typepriorities) {  // not using type priorities, but underlying iterator isn't either
+//      return false;
+//    }
+//
+//    // not using type priorities, but underlying iterator is.  
+//    Annotation a = it.getNvc();
+//    int begin = a.getBegin();
+//    int end = a.getEnd();
+////    Type type = a.getType();  // not using type priorities implies want to ignore type match
+//    do {
+//      int id = a._id;
+//      if (id == exactId) {
+//        return true;         // early stop for one caller
+//      }
+//      if (id == startId) { // start id may not be set yet; if so it is set to 0 so this test is always false
+//        return false;  // iterator is at the start, can't move more
+//      }
+//      it.moveToPrevious();
+//      if (!it.isValid()) {
+//        it.moveToFirstNoReinit();  // not moveToStart - called by moveToStart
+//        return false;  
+//      }
+//      a = it.getNvc();
+//    } while (isBeginEndEqual(a, begin, end));
+//    it.moveToNext();  // went back one to far
+//    return false;
+//  }
+      
+  private boolean isBeginEndTypeEqual(Annotation fs, int begin, int end, Type type) {
+    if (fs.getBegin() != begin || fs.getEnd() != end) {
+      return false;  
+    }
+    
+    // begin and end compare
+    
+//    if (!isUseTypePriority) {
+//      return true;  // if not using type priority, no compare with type
+//    }
+    
+    // using type priority
+//    if (!underlying_iterator_using_typepriorities) {
+//      return true; // can't compare types if underlying iterator doesn't use type priorities
+//                   // because that would require searching in both directions among == begin/end
+//                   // values
+//                   // TODO maybe implement a general search, among begin/end equal things?
+//    }
+//    // using type priorities, and the comparator has type priorities
+    return fs.getType() == type;
+  }
+  
+//  private boolean isBeginEndEqual(Annotation fs, int begin, int end) {
+//    return fs.getBegin() == begin && fs.getEnd() == end;
+//  }
+  
+  /**
+   * For unambiguous, going forwards
+   */
+  private void movePastPrevAnnotation() {
+    if (isUnambiguous) {
+      while (it.isValid() && (it.get().getBegin() < this.prevEnd)) {
+        it.moveToNext();
+      }
+    }
+  }
+
   /*
    * (non-Javadoc)
    * 
@@ -959,13 +1183,12 @@
     Subiterator<T> copy = new Subiterator<T>(
         this.it.copy(), 
         this.boundingAnnot, 
-        this.isAmbiguous,
+        ! this.isUnambiguous,
         this.isStrict,
         this.boundsUse,
-        this.isTypePriority, 
-        this.isPositionUsesType, 
-        this.isSkipEquals,
-        this.annotationComparator,
+        this.isUseTypePriority, 
+        this.isSkipSameBeginEndType,
+        
         this.startId,
         this.isEmpty,
         this.coveringStartPos,
@@ -982,7 +1205,7 @@
    * in many cases, and may not be needed.
    */
   @Override
-  public int ll_indexSize() {
+  public int ll_indexSizeMaybeNotCurrent() {
     throw new UnsupportedOperationException();
   }
 
@@ -1000,7 +1223,7 @@
   }
 
   private void makeInvalid() {
-    it.moveToFirst();
+    it.moveToFirstNoReinit();
     it.moveToPrevious();
   }
 
@@ -1013,6 +1236,42 @@
     return ((LowLevelIterator<?>)it).isIndexesHaveBeenUpdated();
   }
 
+  @Override
+  public boolean maybeReinitIterator() {
+    if (it.maybeReinitIterator()) {
+      resetList();
+      moveToStartSetEmptyAndId();
+      return true;
+    }   
+    return false;
+  }
+
+  @Override
+  public Comparator<TOP> getComparator() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+//  /**
+//   * Simple implementation:
+//   *   move to leftmost, then
+//   *   advance until == or invalid
+//   */
+//  @Override
+//  public void moveToExactNoReinit(FeatureStructure fs) {
+//    moveToNoReinit(fs);
+//    while (isValid()) {
+//      T f = getNvc();
+//      if (f == fs) {
+//        return;
+//      }
+//      if (comparatorMaybeNoTypeWithoutId.compare((TOP)f, (TOP)fs) != 0) {
+//        makeInvalid();
+//        return;
+//      }
+//      moveToNextNvc();
+//    }
+//  }
 
 //  // makes an extra copy of the items
 //  private void initAmbiguousSubiterator(AnnotationFS annot, final boolean strict) {
@@ -1021,7 +1280,7 @@
 //    if (annot == null) {
 //      it.moveToFirst();
 //    } else {
-//      it.moveTo(annot);  // to "earliest" equal, or if none are equal, to the one just later than annot
+//      it.moveToNoReinit(annot);  // to "earliest" equal, or if none are equal, to the one just later than annot
 //    }
 //    
 //    // This is a little silly, it skips 1 of possibly many indexed annotations if the earliest one is "equal"
@@ -1053,7 +1312,7 @@
 //  private void initUnambiguousSubiterator(AnnotationFS annot, final boolean strict) {
 //    final int start = annot.getBegin();
 //    final int boundingEnd = annot.getEnd();
-//    it.moveTo(annot);
+//    it.moveToNoReinit(annot);
 //    
 //    if (it.isValid() && it.get().equals(annot)) {
 //      it.moveToNext();
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 7d7e238..eb4aba5 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
@@ -25,11 +25,11 @@
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Vector;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
 import java.util.stream.Stream;
 
-import org.apache.uima.cas.BuiltinTypeKinds;
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CommonArrayFS;
 import org.apache.uima.cas.Feature;
@@ -57,6 +57,7 @@
         
   private final String name;                // x.y.Foo
   private final String shortName;           //     Foo
+  private final String jcasClassName;       // chande prefix, maybe
   
   private final short typeCode;               // subtypes always have typecodes > this one and < typeCodeNextSibling
   private       short depthFirstCode;         // assigned at commit time
@@ -83,6 +84,13 @@
   
   protected final boolean isLongOrDouble;  // for code generation
   
+  /**
+   * when set, processing skipped for
+   *   - augment features from jcas
+   *   - conformance checking between jcas and type system
+   *   - validating the superclass chain upon load of jcas class
+   */
+  protected boolean isBuiltIn;  // for avoiding repetitive work
   
   int nbrOfLongOrDoubleFeatures = 0; 
   
@@ -156,12 +164,13 @@
    
   // 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() {
     this.name = null;
     this.shortName = null;
+    this.jcasClassName = null;
     this.superType = null;
     
     this.isInheritanceFinal = false;
@@ -178,6 +187,7 @@
     
     slotKind = TypeSystemImpl.getSlotKindFromType(this);
     this.allSuperTypes = null;
+    this.hashCodeNameLong = Misc.hashStringLong(name);
   }
   
   /**
@@ -195,6 +205,7 @@
     }
     
     this.name = name;
+    this.jcasClassName = Misc.typeName2ClassName(name);
     final int pos = this.name.lastIndexOf(TypeSystem.NAMESPACE_SEPARATOR);
     this.shortName = (pos >= 0) ? this.name.substring(pos + 1) : name;
     this.superType = supertype;
@@ -265,6 +276,7 @@
     slotKind = TypeSystemImpl.getSlotKindFromType(this);
     
     hasRefFeature = name.equals(CAS.TYPE_NAME_FS_ARRAY);  // initialization of other cases done at commit time
+    this.hashCodeNameLong = Misc.hashStringLong(name);
   }
 
   /**
@@ -277,6 +289,11 @@
     return this.name;
   }
   
+  public String getJCasClassName() {
+    return this.jcasClassName;
+  }
+  
+  
   /**
    * Get the super type.
    * 
@@ -306,22 +323,19 @@
   public String toString(int indent) {
     StringBuilder sb = new StringBuilder();
     sb.append(this.getClass().getSimpleName() + " [name: ").append(name).append(", superType: ").append((superType == null) ? "<null>" :superType.getName()).append(", ");
-    prettyPrintList(sb, "directSubtypes", directSubtypes, ti -> sb.append(ti.getName()));
+    prettyPrintList(sb, "directSubtypes", directSubtypes, (sbx, ti) -> sbx.append(ti.getName()));
     sb.append(", ");
     appendIntroFeats(sb, indent);
     return sb.toString();
   }
   
-  private <T> void prettyPrintList(StringBuilder sb, String title, List<T> items, Consumer<T> appender) {
+  private <T> void prettyPrintList(StringBuilder sb, String title, List<T> items, BiConsumer<StringBuilder, T> appender) {
     sb.append(title).append(": ");
     Misc.addElementsToStringBuilder(sb, items, appender);
   }
   
-  private static final char[] blanks = new char[80];
-  static {Arrays.fill(blanks,  ' ');}
-
   public void prettyPrint(StringBuilder sb, int indent) {
-    indent(sb, indent).append(name).append(": super: ").append((null == superType) ? "<null>" : superType.getName());
+    Misc.indent(sb, indent).append(name).append(": super: ").append((null == superType) ? "<null>" : superType.getName());
     
     if (staticMergedFeaturesIntroducedByThisType.size() > 0) {
       sb.append(", ");
@@ -329,11 +343,7 @@
     }
     sb.append('\n');
   }
-  
-  private StringBuilder indent(StringBuilder sb, int indent) {
-    return sb.append(blanks, 0, Math.min(indent,  blanks.length));
-  }
-  
+    
   public void prettyPrintWithSubTypes(StringBuilder sb, int indent) {
     prettyPrint(sb, indent);
     int nextIndent = indent + 2;
@@ -342,7 +352,7 @@
 
   private void appendIntroFeats(StringBuilder sb, int indent) {
     prettyPrintList(sb, "FeaturesIntroduced/Range/multiRef", staticMergedFeaturesIntroducedByThisType,
-        fi -> indent(sb.append('\n'), indent + 2).append(fi.getShortName()).append('/')
+        (sbx, fi) -> Misc.indent(sbx.append('\n'), indent + 2).append(fi.getShortName()).append('/')
                 .append(fi.getRange().getName()).append('/')
                 .append(fi.isMultipleReferencesAllowed() ? 'T' : 'F') );
   }
@@ -413,7 +423,7 @@
   public FeatureImpl getFeatureByBaseName(String featureShortName) {
     return staticMergedFeatures.get(featureShortName);
   }
-
+  
   /**
    * @see org.apache.uima.cas.Type#getShortName()
    */
@@ -447,6 +457,10 @@
     this.isInheritanceFinal = true;
   }
   
+  void setBuiltIn() {
+    this.isBuiltIn = true;
+  }
+  
   public boolean isLongOrDouble() {
     return this.isLongOrDouble;
   }
@@ -503,6 +517,9 @@
     }    
   }
   
+  /**
+   * Sets hasRefFeature and nbrOfLongOrDoubleFeatures
+   */
   private void computeHasXxx() {
     nbrOfLongOrDoubleFeatures = superType.getNbrOfLongOrDoubleFeatures();
     if (superType.hasRefFeature) {
@@ -531,7 +548,8 @@
    * @param fi feature to be added
    */
   void addFeature(FeatureImpl fi) {
-    checkExistingFeatureCompatible(staticMergedFeatures.get(fi.getShortName()), fi.getRange());
+    // next already checked by caller "addFeature" in TypeSystemImpl
+//    checkExistingFeatureCompatible(staticMergedFeatures.get(fi.getShortName()), fi.getRange());
     checkAndAdjustFeatureInSubtypes(this, fi);
 
     staticMergedFeatures.put(fi.getShortName(), fi);
@@ -896,31 +914,7 @@
                           ? ((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));
@@ -944,38 +938,48 @@
    */
   public final static TypeImpl singleton = new TypeImpl();
 
-  private int hashCode = 0;
-  private boolean hasHashCode = false;
+  private long hashCodeLong = 0;
+  private final long hashCodeNameLong;
+  private boolean hasHashCodeLong = false;
   
   @Override
   public int hashCode() {
-    if (hasHashCode) return hashCode;
-    synchronized (this) {
-      int h = computeHashCode();
-      if (tsi.isCommitted()) {
-        hashCode = h;
-        hasHashCode = true;
+    return (int) hashCodeLong();
+  }
+    
+  private long hashCodeLong() {
+    if (!hasHashCodeLong) {
+      synchronized (this) {
+        this.hashCodeLong = computeHashCodeLong();
+        if (this.getTypeSystem().isCommitted()) {
+          hasHashCodeLong = true; // no need to recompute
+        }
       }
-      return h;
     }
+    return hashCodeLong;
   }
   
+  public long hashCodeNameLong() {
+    return hashCodeNameLong;
+  }
+    
   /**
    * works across type systems
+   * a long so the hash code can be reliably used for quick equal compare.
+   * 
+   * Hash code is not a function of subtypes; otherwise two Type Systems
+   * with different types would have unequal TOP types, for example
    * @return -
    */
-  private int computeHashCode() {
-    final int prime = 31;
-    int result = 1;
-    result = prime * result + name.hashCode();
-    result = prime * result + ((superType == null) ? 0 : superType.name.hashCode());
-    for (TypeImpl ti : directSubtypes) {
-      result = prime * result + ti.name.hashCode();
-    }
+  private long computeHashCodeLong() {
+    final long prime = 31;
+    long result;
+    result = 31 + hashCodeNameLong;
+    result = prime * result + ((superType == null) ? 0 : superType.hashCodeLong());
     result = prime * result + (isFeatureFinal ? 1231 : 1237);
     result = prime * result + (isInheritanceFinal ? 1231 : 1237);
     for (FeatureImpl fi : getFeatureImpls()) {
-      result = prime * result + fi.hashCode();
+      result = prime * result + fi.hashCodeLong();
     }
     return result;
   }
@@ -990,68 +994,63 @@
     if (obj == null || !(obj instanceof TypeImpl)) return false;
 
     TypeImpl other = (TypeImpl) obj;
-    if (hashCode() != other.hashCode()) return false;
-    
-    if (!name.equals(other.name)) return false;
-    
-    if (superType == null) {
-      if (other.superType != null) return false;
-    } else {
-      if (other.superType == null) return false;
-      if (!superType.name.equals(other.superType.name)) return false;
-    }
-    
-    if (directSubtypes.size() != other.directSubtypes.size()) return false;
-    
-    if (isFeatureFinal != other.isFeatureFinal) return false;
-    if (isInheritanceFinal != other.isInheritanceFinal) return false;
-    
-    if (this.getNumberOfFeatures() != other.getNumberOfFeatures()) return false;
-    
-    final FeatureImpl[] fis1 = getFeatureImpls();
-    final FeatureImpl[] fis2 = other.getFeatureImpls();
-    if (!Arrays.equals(fis1,  fis2)) return false;
-    
-    for (int i = 0; i < directSubtypes.size(); i++) {
-      if (!directSubtypes.get(i).name.equals(other.directSubtypes.get(i).name)) return false;
-    }
-    
-    return true;
+    return hashCodeLong() == other.hashCodeLong();
+//    if (hashCode() != other.hashCode()) return false;
+//    
+//    if (!name.equals(other.name)) return false;
+//    
+//    if (superType == null) {
+//      if (other.superType != null) return false;
+//    } else {
+//      if (other.superType == null) return false;
+//      if (!superType.name.equals(other.superType.name)) return false;
+//    }
+//    
+//    if (directSubtypes.size() != other.directSubtypes.size()) return false;
+//    
+//    if (isFeatureFinal != other.isFeatureFinal) return false;
+//    if (isInheritanceFinal != other.isInheritanceFinal) return false;
+//    
+//    if (this.getNumberOfFeatures() != other.getNumberOfFeatures()) return false;
+//    
+//    final FeatureImpl[] fis1 = getFeatureImpls();
+//    final FeatureImpl[] fis2 = other.getFeatureImpls();
+//    if (!Arrays.equals(fis1,  fis2)) return false;
+//    
+//    for (int i = 0; i < directSubtypes.size(); i++) {
+//      if (!directSubtypes.get(i).name.equals(other.directSubtypes.get(i).name)) return false;
+//    }
+//    
+//    return true;
   }
   
   /**
    * compareTo must return 0 for "equal" types
+   *    equal means same name, same flags, same supertype chain, same subtypes, and same features
+   * Makes use of hashcodelong to probablistically shortcut computation for equal case
    * 
-   * use the fully qualified names as the comparison
-   * Note: you can only compare types from the same type system. If you compare types from different
-   * type systems, the result is undefined.
+   * for not equal types, do by parts
    */
   @Override
   public int compareTo(TypeImpl t) {
-    if (this == t) {
-      return 0;
-    }
     
-    int c = this.name.compareTo(t.name);
-    if (c != 0) return c;
-        
-    c = Integer.compare(this.hashCode(), t.hashCode());
-    if (c != 0) return c;
+    if (this == t) return 0;
+    long hcl = this.hashCodeLong();
+    long thcl = t.hashCodeLong();
+    if (hcl == thcl) return 0;
     
-    // if get here, we have two types of the same name, and same hashcode
-    //   may or may not be equal
-    //   check the parts.
+    // can't use hashcode for non equal compare -violates compare contract
 
+    int c = Long.compare(hashCodeNameLong, t.hashCodeNameLong);
+    if (c != 0) return c;
+            
     if (this.superType == null || t.superType == null) {
-      Misc.internalError();
+      throw Misc.internalError();
     };
     
-    c = this.superType.name.compareTo(t.superType.name);
+    c = Long.compare(this.superType.hashCodeNameLong, t.superType.hashCodeNameLong);
     if (c != 0) return c;
-    
-    c = Integer.compare(this.directSubtypes.size(), t.directSubtypes.size());
-    if (c != 0) return c;
-    
+        
     c = Integer.compare(this.getNumberOfFeatures(),  t.getNumberOfFeatures());
     if (c != 0) return c;
     
@@ -1063,17 +1062,16 @@
     final FeatureImpl[] fis1 = getFeatureImpls();
     final FeatureImpl[] fis2 = t.getFeatureImpls();
     
+    c = Integer.compare(fis1.length, fis2.length);
+    if (c != 0) return c;
+    
     for (int i = 0; i < fis1.length; i++) {
       c = fis1[i].compareTo(fis2[i]);
       if (c != 0) return c;      
     }
     
-    for (int i = 0; i < directSubtypes.size(); i++) {
-      c = this.directSubtypes.get(i).compareTo(t.directSubtypes.get(i));
-      if (c != 0) return c;      
-    }
-
-    return 0;
+    // never get here, because would imply equal, and hashcodelongs would have been equal above.
+    throw Misc.internalError();
   }
 
   boolean isPrimitiveArrayType() {
@@ -1140,6 +1138,31 @@
 //    return generator;
 //  }
 
+  @Override
+  public Iterator<Feature> iterator() {
+    final FeatureImpl[] fia = getFeatureImpls();
+    final int l = fia.length;
+    
+    return new Iterator<Feature>() {
+      int i = 0;
+      
+      @Override
+      public boolean hasNext() {
+        return i < l;
+      }
+
+      @Override
+      public Feature next() {
+        if (hasNext()) {
+          return fia[i++];
+        } else {
+          throw new NoSuchElementException();
+        }
+      }
+      
+    };
+  }
+
 //  /**
 //   * @return the jcasClassInfo
 //   */
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemConstants.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemConstants.java
index 26522f7..90295da 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemConstants.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemConstants.java
@@ -100,15 +100,14 @@
   /**

    * adjOffsets for builtin Features

    */

-  static final TypeSystemImpl staticTsi = TypeSystemImpl.staticTsi;

-  static final int sofaNumFeatAdjOffset = staticTsi.sofaType.getAdjOffset(CAS.FEATURE_BASE_NAME_SOFANUM);  

-  static final int sofaIdFeatAdjOffset = staticTsi.sofaType.getAdjOffset(CAS.FEATURE_BASE_NAME_SOFAID);

-  static final int sofaStringFeatAdjOffset = staticTsi.sofaType.getAdjOffset(CAS.FEATURE_BASE_NAME_SOFASTRING);

-  static final int sofaMimeFeatAdjOffset = staticTsi.sofaType.getAdjOffset(CAS.FEATURE_BASE_NAME_SOFAMIME);

-  static final int sofaUriFeatAdjOffset = staticTsi.sofaType.getAdjOffset(CAS.FEATURE_BASE_NAME_SOFAURI);

-  static final int sofaArrayFeatAdjOffset = staticTsi.sofaType.getAdjOffset(CAS.FEATURE_BASE_NAME_SOFAARRAY);

-  static final int annotBaseSofaFeatAdjOffset = staticTsi.annotBaseType.getAdjOffset(CAS.FEATURE_BASE_NAME_SOFA);

-  static final int beginFeatAdjOffset = staticTsi.annotType.getAdjOffset(CAS.FEATURE_BASE_NAME_BEGIN);

-  static final int endFeatAdjOffset = staticTsi.annotType.getAdjOffset(CAS.FEATURE_BASE_NAME_END);

-  static final int langFeatAdjOffset = staticTsi.docType.getAdjOffset(CAS.FEATURE_BASE_NAME_LANGUAGE);

+  static final int sofaNumFeatAdjOffset = TypeSystemImpl.staticTsi.sofaType.getAdjOffset(CAS.FEATURE_BASE_NAME_SOFANUM);  

+  static final int sofaIdFeatAdjOffset = TypeSystemImpl.staticTsi.sofaType.getAdjOffset(CAS.FEATURE_BASE_NAME_SOFAID);

+  static final int sofaStringFeatAdjOffset = TypeSystemImpl.staticTsi.sofaType.getAdjOffset(CAS.FEATURE_BASE_NAME_SOFASTRING);

+  static final int sofaMimeFeatAdjOffset = TypeSystemImpl.staticTsi.sofaType.getAdjOffset(CAS.FEATURE_BASE_NAME_SOFAMIME);

+  static final int sofaUriFeatAdjOffset = TypeSystemImpl.staticTsi.sofaType.getAdjOffset(CAS.FEATURE_BASE_NAME_SOFAURI);

+  static final int sofaArrayFeatAdjOffset = TypeSystemImpl.staticTsi.sofaType.getAdjOffset(CAS.FEATURE_BASE_NAME_SOFAARRAY);

+  static final int annotBaseSofaFeatAdjOffset = TypeSystemImpl.staticTsi.annotBaseType.getAdjOffset(CAS.FEATURE_BASE_NAME_SOFA);

+  static final int beginFeatAdjOffset = TypeSystemImpl.staticTsi.annotType.getAdjOffset(CAS.FEATURE_BASE_NAME_BEGIN);

+  static final int endFeatAdjOffset = TypeSystemImpl.staticTsi.annotType.getAdjOffset(CAS.FEATURE_BASE_NAME_END);

+  static final int langFeatAdjOffset = TypeSystemImpl.staticTsi.docType.getAdjOffset(CAS.FEATURE_BASE_NAME_LANGUAGE);

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java
index 7458ce3..95c595e 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java
@@ -33,6 +33,11 @@
 import static org.apache.uima.cas.impl.SlotKinds.SlotKind.Slot_ShortRef;
 import static org.apache.uima.cas.impl.SlotKinds.SlotKind.Slot_StrRef;
 
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.MutableCallSite;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -48,6 +53,7 @@
 import java.util.WeakHashMap;
 import java.util.stream.Collectors;
 
+import org.apache.uima.UIMAFramework;
 import org.apache.uima.UIMARuntimeException;
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASRuntimeException;
@@ -57,12 +63,14 @@
 import org.apache.uima.cas.TypeSystem;
 import org.apache.uima.cas.admin.CASAdminException;
 import org.apache.uima.cas.admin.TypeSystemMgr;
+import org.apache.uima.cas.impl.FSClassRegistry.JCasClassInfo;
 import org.apache.uima.cas.impl.SlotKinds.SlotKind;
 import org.apache.uima.internal.util.Misc;
 import org.apache.uima.jcas.JCasRegistry;
 import org.apache.uima.jcas.cas.AnnotationBase;
 import org.apache.uima.jcas.cas.BooleanArray;
 import org.apache.uima.jcas.cas.ByteArray;
+import org.apache.uima.jcas.cas.CommonList;
 import org.apache.uima.jcas.cas.DoubleArray;
 import org.apache.uima.jcas.cas.EmptyFSList;
 import org.apache.uima.jcas.cas.EmptyFloatList;
@@ -85,6 +93,7 @@
 import org.apache.uima.jcas.cas.StringList;
 import org.apache.uima.jcas.cas.TOP;
 import org.apache.uima.jcas.tcas.Annotation;
+import org.apache.uima.util.Logger;
 import org.apache.uima.util.impl.Constants;
 
 /**
@@ -117,6 +126,8 @@
  */
 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
@@ -142,6 +153,8 @@
 //  private final static boolean IS_DECOMPILE_JCAS = Misc.getNoValueSystemProperty(DECOMPILE_JCAS);
 //  private final static Set<String> decompiled = (IS_DECOMPILE_JCAS) ? new HashSet<String>(256) : null;
     
+  static private final MethodHandle MHC_MINUS_1 = MethodHandles.constant(int.class, -1);
+  
   /**
    * Type code that is returned on unknown type names.
    */
@@ -240,11 +253,11 @@
     
   final private static Map<TypeSystemImpl, WeakReference<TypeSystemImpl>> committedTypeSystems = Collections.synchronizedMap(new WeakHashMap<>());
   
-  /**
-   * used to pass the type being loaded reference to the JCas static initializer code,
-   *   referenced from the TypeSystemImpl.getAdjustedFeatureOffset([featurename]) method.
-   */
-  public final static ThreadLocal<TypeImpl> typeBeingLoadedThreadLocal = new ThreadLocal<TypeImpl>();
+//  /**  OBSOLETE with BETA and later levels
+//   * used to pass the type being loaded reference to the JCas static initializer code,
+//   *   referenced from the TypeSystemImpl.getAdjustedFeatureOffset([featurename]) method.
+//   */
+//  public final static ThreadLocal<TypeImpl> typeBeingLoadedThreadLocal = new ThreadLocal<TypeImpl>();
     
   /******************************************
    *   I N S T A N C E   V A R I A B L E S  *
@@ -419,10 +432,28 @@
   /**
    * Cache for implementing map from type code -> FsGenerator
    * Shared by all CASes using this type system
-   *   Excludes FsGeneratorArrays - those are built-in and constant 
+   *
+   *   maps from classloader to generator set for non-pears
+   *   
    */
   private final Map<ClassLoader, FsGenerator3[]> generatorsByClassLoader = new IdentityHashMap<>();
 
+  /**
+   * Cache for implementing map from type code -> FsGenerator
+   * Shared by all CASes using this type system
+   *
+   *   maps from classloader to generator set for pears
+   *   
+   */
+  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;
+  private boolean skip_loading_user_jcas = false;
+
   public TypeSystemImpl() {
 
     // set up meta info (TypeImpl) for built-in types
@@ -620,6 +651,24 @@
     setTypeFinal(stringNeListType);
     setTypeFinal(intNeListType);
     
+    topType.setBuiltIn();
+    listBaseType.setBuiltIn();
+    fsListType.setBuiltIn();
+    fsEListType.setBuiltIn();
+    fsNeListType.setBuiltIn();
+    floatListType.setBuiltIn();
+    floatEListType.setBuiltIn();
+    floatNeListType.setBuiltIn();
+    intListType.setBuiltIn();
+    intEListType.setBuiltIn();
+    intNeListType.setBuiltIn();
+    stringListType.setBuiltIn();
+    stringEListType.setBuiltIn();
+    stringNeListType.setBuiltIn();
+    annotType.setBuiltIn();
+    annotBaseType.setBuiltIn();
+    
+    
 //    setTypeFinal(fsArrayListType);
 //    setTypeFinal(intArrayListType);
 //    setTypeFinal(fsHashSetType);
@@ -640,6 +689,8 @@
     annotType.setFeatureFinal();
     annotBaseType.setFeatureFinal();
     
+    
+    
 //    fsArrayListType.setFeatureFinal();
 //    intListType.setFeatureFinal();
 //    fsHashSetType.setFeatureFinal();
@@ -870,7 +921,9 @@
 
 
   public boolean isInInt(Type rangeType) {
-    return rangeType.isPrimitive() && !subsumes(stringType, rangeType);
+    return (rangeType == null) 
+             ? false
+             : (rangeType.isPrimitive() && !subsumes(stringType, rangeType));
   }
   
   @Override
@@ -893,8 +946,16 @@
     FeatureImpl existingFeature = (FeatureImpl) getFeature(domainType, shortFeatName);
     if (existingFeature != null) {
       ((TypeImpl)domainType).checkExistingFeatureCompatible(existingFeature, rangeType);
-      if (subsumes(domainType, existingFeature.getHighestDefiningType())) {
-        existingFeature.setHighestDefiningType(domainType);
+      TypeImpl highestDefiningType = existingFeature.getHighestDefiningType();
+      if (highestDefiningType != domainType && subsumes(domainType, highestDefiningType)) {
+        // never happens in existing test cases  6/2017 schor
+        Misc.internalError();  // logically can never happen
+        // Note: The other case, where a type and subtype are defined, and then 
+        // features are added in any order, in particular, a 
+        //   supertype feature is added after a subtype feature of the same name/range has been added,
+        // causes the subtype's feature to be "deleted" and "inherited" instead.
+        //   code: checkAndAdjustFeatureInSubtypes in TypeImpl
+//        existingFeature.setHighestDefiningType(domainType);
       }
       return existingFeature;
     }
@@ -907,6 +968,9 @@
     if (!TypeSystemUtils.isIdentifier(shortFeatName)) {
       throw new CASAdminException(CASAdminException.BAD_FEATURE_SYNTAX, shortFeatName);
     }   
+    
+    // at end of FeatureImpl constructor, TypeImpl.addFeature is called
+    //   which does checks, calls checkAndAdjustFeatureInSubtypes, etc.
     return new FeatureImpl(
         (TypeImpl) domainType, 
         shortFeatName, 
@@ -1294,11 +1358,20 @@
     return commit(this.getClass().getClassLoader());  // default if not called with a CAS context 
   }
   
+  /**
+   * @see org.apache.uima.cas.admin.TypeSystemMgr#commit(ClassLoader)
+   */
+  @Override
   public TypeSystemImpl commit(ClassLoader cl) {
     synchronized(this) {
       if (this.locked) {
+        // is a no-op if already loaded for this Class Loader
+        // otherwise, need to load and set up generators for this class loader
+        getGeneratorsForClassLoader(cl, false);  // false - is not pear     
         return this; // might be called multiple times, but only need to do once
       }
+      
+      
       // because subsumes depends on it
       // and generator initialization uses subsumes
   //    this.numCommittedTypes = this.getNumberOfTypes(); // do before
@@ -1309,12 +1382,14 @@
       // because it will call the type system iterator
   //    this.casMetadata.setupFeaturesAndCreatableTypes();
 
-
       if (!IS_DISABLE_TYPESYSTEM_CONSOLIDATION) {
         WeakReference<TypeSystemImpl> prevWr = committedTypeSystems.get(this);
         if (null != prevWr) {
           TypeSystemImpl prev = prevWr.get();
-          if (null != prev) {
+          if (null != prev) {            
+            // the following is a no-op if the generators already set up for this class loader
+            prev.getGeneratorsForClassLoader(cl, false);  // false - is not pear
+
             return prev;
           }
         }      
@@ -1331,8 +1406,12 @@
 //          }
 //        }
 //      }
-      
-      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
@@ -1350,33 +1429,80 @@
         committedTypeSystems.put(this, new WeakReference<>(this));
       }
 
+      // this call is here for the case where a commit happens, but no subsequent
+      //   new CAS or switch classloader call is done.  For example, a "reinit" in an existing CAS
+      // This call internally calls the code to load JCas classes for this class loader.
+      getGeneratorsForClassLoader(cl, false);  // false - is not pear    
+//      FSClassRegistry.loadJCasForTSandClassLoader(this, true, cl);
       return this;
     } // of sync block 
-  }
+  }  
   
   /**
    * 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
     
+    if (! skip_loading_user_jcas) {
+      JCasClassInfo jcci = getJcci(ti);
+      
+      if (jcci != null) {
+        addJCasOffsetsWithSupers(jcci.jcasClass, tempIntFis, tempRefFis, tempNsr);
+      }
+    }
+        
     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;
     
@@ -1395,15 +1521,166 @@
 //    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) {
     
@@ -1604,6 +1881,7 @@
     TypeImpl t = (TypeImpl) type;
     t.setFeatureFinal();
     t.setInheritanceFinal();
+    t.setBuiltIn();
   }
   
   private FeatureImpl getFeature(String typeName, String featureShortName) {
@@ -2545,8 +2823,8 @@
 //  Class<?> getJCasClass(int typecode) {
 //    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)
@@ -2555,18 +2833,29 @@
    * @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) {
-      /*A JCas class field "{0}" is being initialized by non-framework (user) code before Type System Commit 
-       * for a type system with a corresponding type. 
-       * Either change the user load code to not do initialize, or to defer it until after the type system commit.*/
-      throw new CASRuntimeException(CASRuntimeException.JCAS_CLASS_INITIALIZED_BEFORE_TYPE_SYSTEM_COMMIT, featName);
-    }
-    FeatureImpl fi = type.getFeatureByBaseName(featName);
-    return (fi == null) ? -1 : fi.getAdjustedOffset();
+    /* The JCas class being loaded was generated for the "alpha" level of UIMA v3,
+     * and is not supported for Beta and later levels.
+     * 
+     * This can be fixed by regenerating this using the current v3 version of UIMA tooling
+     * (JCasgen, or the migration tooling to migrate from v2).
+     */
+    Logger logger = UIMAFramework.getLogger(TypeSystemImpl.class);
+    logger.warn(() -> logger.rb_ue(CASRuntimeException.JCAS_ALPHA_LEVEL_NOT_SUPPORTED)); 
+    return -1;
   }
   
+  static int getAdjustedFeatureOffset(TypeImpl type, String featName) {
+    FeatureImpl fi = type.getFeatureByBaseName(featName);
+    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();    
+  }
+    
   /**
    * When deserializing Xmi and XCAS, Arrays of Feature Structures are encoded as FSArray types, but they
    * may have a more restrictive typing, e.g. arrays of Annotation, with the type code of Annotation[].
@@ -2577,13 +2866,13 @@
    * from FSArray to the most restrictive (in case there are multiple refs) array type.
    */
   void fixupFSArrayTypes(TypeImpl featRange, TOP arrayFs) {
-    if (featRange.isTypedFsArray()) {
+    if (arrayFs != null && featRange.isTypedFsArray() ) { // https://issues.apache.org/jira/browse/UIMA-5446
       if (arrayFs._getTypeImpl().getComponentType().subsumesStrictly(featRange.getComponentType())) {
         arrayFs._setTypeImpl(featRange);  // replace more general type with more specific type
       }
     }
   }
-  
+    
   /**
    * Called when switching or initializing CAS's shared-view-data instance of FsGenerator[]
    * @param cl the class loader
@@ -2591,16 +2880,53 @@
    * @return the generators
    */
   public FsGenerator3[] getGeneratorsForClassLoader(ClassLoader cl, boolean isPear) {
-    synchronized (generatorsByClassLoader) {
-      FsGenerator3[] g = generatorsByClassLoader.get(cl);
-      if (g == null) {
+    Map<ClassLoader, FsGenerator3[]> gByC = isPear ? generators4pearsByClassLoader : generatorsByClassLoader;
+    synchronized (gByC) {
+      
+      FsGenerator3[] g = gByC.get(cl); // a separate map per type system instance
+      if (g == null && ! skip_loading_user_jcas) {
         g = FSClassRegistry.getGeneratorsForClassLoader(cl, isPear, this);
-        generatorsByClassLoader.put(cl, g);
+        gByC.put(cl, g);
       }
       return g;
     }
   }
+    
+  /**
+   * Creates and returns a new MutableCallSite, 
+//   * recording it in list of all callsites for this type, in a map by typename
+//   * 
+//   * Done this way because 
+//   *   - can't be a classloader-wide list of call sites - some might not be associated with this type system
+//   *   - can't be a typesystem-wide list of call sites - the JCas class might be used by multiple type systems
+//   *     and the first one to load it would set this value.
+//   *   - has to be pairs of feature name, call-site, in order to get the value to set, later
+//   *   --  doesn't need to be a hashmap, can be an arraylist of entry
+//   *   Type being loaded may not be known at this point.
+   * @param clazz the JCas class
+   * @param featName the short name of the feature
+   * @return the created callsite
+   */
+  public final static MutableCallSite createCallSite(Class<? extends TOP> clazz, String featName) {
+    MutableCallSite callSite = new MutableCallSite(MethodType.methodType(int.class));
+    callSite.setTarget(MHC_MINUS_1);  // for error checking
+//    ArrayList<Entry<String, MutableCallSite>> callSitesForType = FSClassRegistry.callSites_all_JCasClasses.computeIfAbsent(clazz, k -> new ArrayList<>());
+//    callSitesForType.add(new AbstractMap.SimpleEntry<String, MutableCallSite>(featName, callSite));
+    return callSite;
+  }
+
+  @Override
+  public Iterator<Type> iterator() {
+    return getTypeIterator();
+  }
+
+  public void set_skip_loading_user_jcas(boolean v) {
+    this.skip_loading_user_jcas = v;
+  }
   
+//  private static boolean isBuiltIn(Class<? extends TOP> clazz) {
+//    return BuiltinTypeKinds.creatableBuiltinJCasClassNames.contains(clazz.getName());
+//  }
 //  /**
 //   * Get a list of types which have OID feature, filtered down to being just the top-most
 //   * (in the type hierarchy)
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemUtils.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemUtils.java
index 6211cf4..e47777d 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemUtils.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemUtils.java
@@ -414,4 +414,17 @@
     return PathValid.NEVER;
   }
 
+  /**
+   * Classify types into FS type, array type etc. For the full list of return types, see the
+   * <code>LowLevelCAS.TYPE_CLASS*</code> constants, as well as the documentation for
+   * {@link LowLevelCAS#ll_getTypeClass(int) LowLevelCAS.ll_getTypeClass(int)}.
+   * 
+   * @param type
+   *                The type to classify.
+   * @return An integer encoding the the type class. See above.
+   */
+  public static final int classifyType(Type type) {
+    return TypeSystemImpl.getTypeClass((TypeImpl) type);
+  }
+
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/UimaDecompiler.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/UimaDecompiler.java
index 520c06d..8cb69c6 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/UimaDecompiler.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/UimaDecompiler.java
@@ -26,7 +26,6 @@
 import java.io.InputStream;

 import java.io.OutputStreamWriter;

 import java.io.UnsupportedEncodingException;

-import java.nio.file.Path;

 import java.util.Arrays;

 import java.util.regex.Matcher;

 import java.util.regex.Pattern;

@@ -99,16 +98,16 @@
     }

   }

     

-  /**

-   * decompile className, and use the byte array passed in instead of getting it from the classpath

-   * @param className the dotted name of the class

-   * @param byteArray the compiled definition for this class to decompile

-   * @return the decompilation

-   */

-  public ByteArrayOutputStream decompile(String className, byte[] byteArray) {

-    setDecompilerSettingsForByteArray(className.replace('.', '/'), byteArray);

-    return decompileCommon(className);

-  }

+//  /**

+//   * decompile className, and use the byte array passed in instead of getting it from the classpath

+//   * @param className the dotted name of the class

+//   * @param byteArray the compiled definition for this class to decompile

+//   * @return the decompilation

+//   */

+//  public ByteArrayOutputStream decompile(String className, byte[] byteArray) {

+//    setDecompilerSettingsForByteArray(className.replace('.', '/'), byteArray);

+//    return decompileCommon(className);

+//  }

   

   /**

    * decompile className, getting the compiled version from the classpath

@@ -180,7 +179,7 @@
   public String decompile(byte[] b) {

 //    PlainTextOutput pto = new PlainTextOutput();

     

-    String classNameSlashes = extractClassNameSlashes(b);

+    String classNameSlashes = Misc.classNameFromByteCode(b);

 //    setDecompilerSettingsForByteArray(classNameSlashes, b);

 //    Decompiler.decompile(classNameSlashes, pto, decompilerSettings);

 //    String s = pto.toString();

@@ -212,63 +211,66 @@
 //    Decompiler.decompile(classNameSlashes, pto, decompilerSettings);

 //    return pto.toString(); 

   }

-    

-  /**

-   * get the slashified form of the fully qualified class name, (minus the trailing .class)

-   * @param b the compiled form of the class

-   * @return fully qualified class name with slashes

-   */

-  public String extractClassNameSlashes(byte[] b) {

-    if (b[10] != 7 || b[13] != 1) { 

-      // class name not immediately findable in the compiled code, so decompile it (without knowing the class name)

-      PlainTextOutput pto = new PlainTextOutput();

-      setDecompilerSettingsForByteArray("", b);

-      //      decompilerSettings.setTypeLoader(getClasspathTypeLoader());

-      Decompiler.decompile("", pto, decompilerSettings);

-      String s = pto.toString();

-      

-      String packageName = "";

-      String className = "";

-      int ip = s.indexOf("package ");

-      if (ip >= 0) {

-        ip = ip + "package ".length();  // start of package name;

-        int ipe = s.indexOf(";", ip);  

-        packageName = s.substring(ip, ipe).replace('.', '/') + "/";

-      }

-      

-      Matcher m = cie_name.matcher(s);

-      boolean ok = m.find();

-      className = ok 

-                     ? m.group(2) 

-                     : "";    

-      

-      String classNameSlashes = packageName + className;

-//      if (classNameSlashes.equals("")) {

-//        throw new RuntimeException("Couldn't find class name");

+   

+  // use Misc.classNameFromByteCode

+//  /**

+//   * get the slashified form of the fully qualified class name, (minus the trailing .class)

+//   * @param b the compiled form of the class

+//   * @return fully qualified class name with slashes

+//   */

+//  public String extractClassNameSlashes(byte[] b) {

+//    if (b[10] == 7 && b[13] == 1) { // a well known compiled form

+//      int length = b[14] * 16 + b[15];

+//      try {

+//        String s = new String(b, 16, length, "UTF-8");

+//        if (s.endsWith(".class")) {

+//          s = s.substring(0, s.length() - ".class".length());

+//        }

+//        return s;      

+//      } catch (UnsupportedEncodingException e) {

+//        throw new RuntimeException(e);

 //      }

-      return classNameSlashes;

-    }

-    int length = b[14] * 16 + b[15];

-    try {

-      String s = new String(b, 16, length, "UTF-8");

-      if (s.endsWith(".class")) {

-        s = s.substring(0, s.length() - ".class".length());

-      }

-      return s;      

-    } catch (UnsupportedEncodingException e) {

-      throw new RuntimeException(e);

-    }

-  }

+//    } else {

+//      // class name not immediately findable in the compiled code, so decompile it (without knowing the class name)

+//      // this path is slow - has 2 decompiles per class (one just to find the package/class name).

+//      PlainTextOutput pto = new PlainTextOutput();

+//      setDecompilerSettingsForByteArray("", b);

+//      //      decompilerSettings.setTypeLoader(getClasspathTypeLoader());

+//      Decompiler.decompile("", pto, decompilerSettings);

+//      String s = pto.toString();

+//      

+//      String packageName = "";

+//      String className = "";

+//      int ip = s.indexOf("package ");

+//      if (ip >= 0) {

+//        ip = ip + "package ".length();  // start of package name;

+//        int ipe = s.indexOf(";", ip);  

+//        packageName = s.substring(ip, ipe).replace('.', '/') + "/";

+//      }

+//      

+//      Matcher m = cie_name.matcher(s);

+//      boolean ok = m.find();

+//      className = ok 

+//                     ? m.group(2) 

+//                     : "";    

+//      

+//      String classNameSlashes = packageName + className;

+////      if (classNameSlashes.equals("")) {

+////        throw new RuntimeException("Couldn't find class name");

+////      }

+//      return classNameSlashes;

+//    }

+//  }

   

   public boolean decompileToOutputDirectory(String className) {

     ByteArrayOutputStream baos = decompile(className);

     return writeIfOk(baos, className);

   }

 

-  public boolean decompileToOutputDirectory(String className, byte[] byteArray) {

-    ByteArrayOutputStream baos = decompile(className, byteArray);

-    return writeIfOk(baos, className);

-  }

+//  public boolean decompileToOutputDirectory(String className, byte[] byteArray) {

+//    ByteArrayOutputStream baos = decompile(className, byteArray);

+//    return writeIfOk(baos, className);

+//  }

 

   public boolean writeIfOk(ByteArrayOutputStream baos, String className) {

     if (!decompiledFailed(baos)) {

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/XCASDeserializer.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/XCASDeserializer.java
index c9db4a2..f24c115 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/XCASDeserializer.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/XCASDeserializer.java
@@ -21,10 +21,13 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.Reader;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Supplier;
 
+import org.apache.uima.UIMARuntimeException;
 import org.apache.uima.UimaContext;
 import org.apache.uima.UimaSerializable;
 import org.apache.uima.cas.CAS;
@@ -36,6 +39,7 @@
 import org.apache.uima.internal.util.Misc;
 import org.apache.uima.internal.util.Pair;
 import org.apache.uima.internal.util.StringUtils;
+import org.apache.uima.internal.util.XMLUtils;
 import org.apache.uima.internal.util.rb_trees.RedBlackTree;
 import org.apache.uima.jcas.cas.CommonPrimitiveArray;
 import org.apache.uima.jcas.cas.FSArray;
@@ -50,7 +54,6 @@
 import org.xml.sax.SAXParseException;
 import org.xml.sax.XMLReader;
 import org.xml.sax.helpers.DefaultHandler;
-import org.xml.sax.helpers.XMLReaderFactory;
 
 /**
  * XCAS Deserializer. Takes an XCAS and reads it into a CAS.
@@ -191,6 +194,11 @@
 
     // working with initial view
     private int nextIndex;
+    
+    private TOP highestIdFs = null;
+
+    /** the fsId read from the _id attribute */
+    private int fsId;
 
     private XCASDeserializerHandler(CASImpl aCAS, OutOfTypeSystemData ootsData) {
       super();
@@ -225,6 +233,7 @@
      * 
      * @see org.xml.sax.ContentHandler#startDocument()
      */
+    @Override
     public void startDocument() throws SAXException {
       // Do setup work in the constructor.
       this.state = DOC_STATE;
@@ -238,6 +247,7 @@
      * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String,
      *      java.lang.String, org.xml.sax.Attributes)
      */
+    @Override
     public void startElement(String nameSpaceURI, String localName, String qualifiedName,
             Attributes attrs) throws SAXException {
       // org.apache.vinci.debug.Debug.p("startElement: " + qualifiedName);
@@ -294,12 +304,15 @@
 
     // Create a new FS.
     private void readFS(String qualifiedName, Attributes attrs) throws SAXParseException {
+      // get the FeatureStructure id
+      fsId = Integer.parseInt(attrs.getValue(XCASSerializer.ID_ATTR_NAME));
+      
       if (qualifiedName.equals("uima.cas.SofA")) {
         qualifiedName = "uima.cas.Sofa";  // fix for XCAS written with pre-public version of Sofas
       }
       
       String typeName = getCasTypeName(qualifiedName);
-      TypeImpl type = (TypeImpl) ts.getType(typeName);
+      TypeImpl type = ts.getType(typeName);
       
       if (type == null) {
         if (this.outOfTypeSystemData == null) {
@@ -345,7 +358,7 @@
         final int extSofaNum = Integer.parseInt(sofaNum);
         
         // get the sofa's FeatureStructure id
-        final int sofaExtId = Integer.parseInt(attrs.getValue(XCASSerializer.ID_ATTR_NAME));
+//        final int sofaExtId = Integer.parseInt(attrs.getValue(XCASSerializer.ID_ATTR_NAME));
         
 
         // create some maps to handle v1 format XCAS ...
@@ -402,20 +415,20 @@
         // Now update the mapping from annotation int to ref values
         if (this.sofaRefMap.size() == extSofaNum) {
           // Sofa received in sofaNum order, add new one
-          this.sofaRefMap.add(sofaExtId);
+          this.sofaRefMap.add(fsId);
         } else if (this.sofaRefMap.size() > extSofaNum) {
           // new Sofa has lower sofaNum than last one
-          this.sofaRefMap.set(extSofaNum, sofaExtId);
+          this.sofaRefMap.set(extSofaNum, fsId);
         } else {
           // new Sofa has skipped ahead more than 1
           this.sofaRefMap.setSize(extSofaNum + 1);
-          this.sofaRefMap.set(extSofaNum, sofaExtId);
+          this.sofaRefMap.set(extSofaNum, fsId);
         }
 
         // get the sofa's mimeType
         String sofaMimeType = attrs.getValue(CAS.FEATURE_BASE_NAME_SOFAMIME);
-
-        fs = cas.createSofa(this.indexMap.get(extSofaNum), sofaID, sofaMimeType);
+        String finalSofaId = sofaID;
+        fs = maybeCreateWithV2Id(fsId, () -> cas.createSofa(this.indexMap.get(extSofaNum), finalSofaId, sofaMimeType));        
       } else {  // not a Sofa
         if (type.isAnnotationBaseType()) {
           
@@ -437,18 +450,19 @@
             }
             casView = cas.getView((Sofa) (fsTree.get(Integer.parseInt(extSofaRefString)).fs));
           }
-          if (ts.docType.subsumes(type)) {
-            fs = casView.getDocumentAnnotation();
+          if (type.getCode() == TypeSystemConstants.docTypeCode) {
+            fs = maybeCreateWithV2Id(fsId, () -> casView.getDocumentAnnotation());
+//            fs = casView.getDocumentAnnotation();
             cas.removeFromCorruptableIndexAnyView(fs, cas.getAddbackSingle());
           } else {
-            fs = casView.createFS(type);
+            fs = maybeCreateWithV2Id(fsId, () -> casView.createFS(type));
             if (currentFs instanceof UimaSerializable) {
               UimaSerializable ufs = (UimaSerializable) currentFs;
               uimaSerializableFixups.add(() -> ufs._init_from_cas_data());
             }
           }
         } else {  // not an annotation base
-          fs = cas.createFS(type);
+          fs = maybeCreateWithV2Id(fsId, () -> cas.createFS(type));
           if (currentFs instanceof UimaSerializable) {
             UimaSerializable ufs = (UimaSerializable) currentFs;
             uimaSerializableFixups.add(() -> ufs._init_from_cas_data());
@@ -506,7 +520,7 @@
         }
       }
 
-      if (ts.docType.subsumes(type)) {
+      if (type.getCode() == TypeSystemConstants.docTypeCode) {
         cas.addbackSingle(fs);
       }
       
@@ -576,7 +590,9 @@
           throw createException(XCASParsingException.ILLEGAL_ARRAY_ATTR, attrName);
         }
       }
-      TOP fs = (TOP) cas.createArray(type, size);
+      final int finalSize = size;
+      TOP fs = maybeCreateWithV2Id(fsId, () -> cas.createArray(type, finalSize));
+//      TOP fs = cas.createArray(type, size);
       
       FSInfo fsInfo = new FSInfo(fs, indexRep);
       if (id >= 0) {
@@ -654,7 +670,7 @@
          
           fixupToDos.add( () -> finalizeRefValue(Integer.parseInt(featVal), fs, feat));
         } else {  // is not a ref type.
-          cas.setFeatureValueFromString(fs, feat, featVal);
+          CASImpl.setFeatureValueFromStringNoDocAnnotUpdate(fs, feat, featVal);
         }
 
       }
@@ -670,6 +686,7 @@
      * 
      * @see org.xml.sax.ContentHandler#characters(char[], int, int)
      */
+    @Override
     public void characters(char[] chars, int start, int length) throws SAXException {
       switch (this.state) {
         case DOC_TEXT_STATE:
@@ -699,6 +716,7 @@
      * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String,
      *      java.lang.String)
      */
+    @Override
     public void endElement(String nsURI, String localName, String qualifiedName)
             throws SAXException {
       switch (this.state) {
@@ -744,8 +762,9 @@
         }
         case DOC_TEXT_STATE: {
           // Assume old style CAS with one text Sofa
-          Sofa newSofa = cas.createInitialSofa("text");
-          CASImpl initialView = (CASImpl) cas.getInitialView();
+          Sofa newSofa = (Sofa) maybeCreateWithV2Id(1, () -> cas.createInitialSofa("text"));
+//          Sofa newSofa = cas.createInitialSofa("text");
+          CASImpl initialView = cas.getInitialView();
           initialView.registerView(newSofa);
           // Set the document text without creating a documentAnnotation
           initialView.setDocTextFromDeserializtion(buffer.toString());
@@ -808,6 +827,7 @@
      * 
      * @see org.xml.sax.ContentHandler#endDocument()
      */
+    @Override
     public void endDocument() throws SAXException {
       // time = System.currentTimeMillis() - time;
       // System.out.println("Done reading xml data in " + new TimeSpan(time));
@@ -888,7 +908,7 @@
           String featName = "_ref_" + featFullName.substring(separatorOffset + 1);
           ootsAttrs.add(new Pair(featName, Integer.toString(extId)));
         }
-        fs.setFeatureValue(fi, null);
+        CASImpl.setFeatureValueMaybeSofa(fs, fi, null);
       } else {
         // the sofa ref in annotationBase is set when the fs is created, not here
         if (fi.getCode() != TypeSystemConstants.annotBaseSofaFeatCode) { 
@@ -897,14 +917,14 @@
             Sofa sofa = (Sofa) fs;
             switch (fi.getRangeImpl().getCode()) {
             case TypeSystemConstants.sofaArrayFeatCode: sofa.setLocalSofaData(fsInfo.fs); break;
-            default: throw new CASRuntimeException(CASRuntimeException.INTERNAL_ERROR);
+            default: throw new CASRuntimeException(UIMARuntimeException.INTERNAL_ERROR);
             }
             return;
           }
           
           // handle case where feature is xyz[] (an array ref, not primitive) but the value of fs is FSArray
           ts.fixupFSArrayTypes(fi.getRangeImpl(), fsInfo.fs);
-          fs.setFeatureValue(fi, fsInfo.fs);
+          CASImpl.setFeatureValueMaybeSofa(fs, fi, fsInfo.fs);
         }
       }
     }
@@ -1045,6 +1065,7 @@
      * 
      * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
      */
+    @Override
     public void error(SAXParseException e) throws SAXException {
       throw e;
     }
@@ -1054,6 +1075,7 @@
      * 
      * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException)
      */
+    @Override
     public void fatalError(SAXParseException e) throws SAXException {
       throw e;
     }
@@ -1063,6 +1085,7 @@
      * 
      * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
      */
+    @Override
     public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {
       // Since we're not validating, we don't need to do anything; this won't
       // be called.
@@ -1073,6 +1096,7 @@
      * 
      * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
      */
+    @Override
     public void setDocumentLocator(Locator loc) {
       // System.out.println("Setting document locator.");
       this.locator = loc;
@@ -1083,6 +1107,7 @@
      * 
      * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException)
      */
+    @Override
     public void warning(SAXParseException e) throws SAXException {
       throw e;
     }
@@ -1159,6 +1184,25 @@
                 "_dash_");
       }
     }
+    
+    TOP maybeCreateWithV2Id(int id, Supplier<TOP> create) {
+      if (cas.is_ll_enableV2IdRefs()) {
+        cas.set_reuseId(id);
+        try {
+          TOP fs = create.get();
+          if (highestIdFs == null) {
+            highestIdFs = fs;
+          } else if (highestIdFs._id < fs._id) {
+            highestIdFs = fs;  // for setting up getNextId at end
+          } 
+          return fs;
+        } finally {           
+          cas.set_reuseId(0); // in case of error throw
+        }
+      } else {
+        return create.get();          
+      }
+    }
   }
 
   final private TypeSystemImpl ts;
@@ -1266,6 +1310,28 @@
   /**
    * Deserializes an XCAS from a stream.
    * 
+   * @param aReader
+   *          Reader from which to read the XCAS XML document
+   * @param aCAS
+   *          CAS into which to deserialize. This CAS must be set up with a type system that is
+   *          compatible with that in the XCAS.
+   * @param aLenient
+   *          if true, unknown Types will be ignored. If false, unknown Types will cause an
+   *          exception. The default is false.
+   * 
+   * @throws SAXException
+   *           if an XML Parsing error occurs
+   * @throws IOException
+   *           if an I/O failure occurs
+   */
+  public static void deserialize(Reader aReader, CAS aCAS, boolean aLenient)
+          throws SAXException, IOException {
+    deserialize(new InputSource(aReader), aCAS, aLenient);
+  }
+
+  /**
+   * Deserializes an XCAS from a stream.
+   * 
    * @param aStream
    *          input stream from which to read the XCAS XML document
    * @param aCAS
@@ -1282,7 +1348,13 @@
    */
   public static void deserialize(InputStream aStream, CAS aCAS, boolean aLenient)
           throws SAXException, IOException {
-    XMLReader xmlReader = XMLReaderFactory.createXMLReader();
+    deserialize(new InputSource(aStream), aCAS, aLenient);
+  }
+  
+  public static void deserialize(InputSource aSource, CAS aCAS, boolean aLenient)
+      throws SAXException, IOException {
+
+    XMLReader xmlReader = XMLUtils.createXMLReader();
     XCASDeserializer deser = new XCASDeserializer(aCAS.getTypeSystem());
     ContentHandler handler;
     if (aLenient) {
@@ -1291,7 +1363,16 @@
       handler = deser.getXCASHandler(aCAS);
     }
     xmlReader.setContentHandler(handler);
-    xmlReader.parse(new InputSource(aStream));
+    xmlReader.parse(aSource);
+
+    CASImpl casImpl = ((CASImpl) aCAS.getLowLevelCAS());
+    if (casImpl.is_ll_enableV2IdRefs()) {
+      TOP highest_fs = ((XCASDeserializerHandler) handler).highestIdFs;
+
+      casImpl.setLastUsedFsId(highest_fs._id);
+      casImpl.setLastFsV2Size(highest_fs._getTypeImpl().getFsSpaceReq(highest_fs));
+    }
   }
+  
 
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/XCASSerializer.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/XCASSerializer.java
index 2163e0b..f671cb3 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/XCASSerializer.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/XCASSerializer.java
@@ -23,7 +23,8 @@
 import java.io.OutputStream;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Deque;
 import java.util.IdentityHashMap;
 import java.util.Iterator;
@@ -47,6 +48,7 @@
 import org.apache.uima.jcas.cas.IntegerArray;
 import org.apache.uima.jcas.cas.LongArray;
 import org.apache.uima.jcas.cas.ShortArray;
+import org.apache.uima.jcas.cas.Sofa;
 import org.apache.uima.jcas.cas.StringArray;
 import org.apache.uima.jcas.cas.TOP;
 import org.apache.uima.util.XMLSerializer;
@@ -347,27 +349,39 @@
      * Push the indexed FSs onto the queue.
      */
     private void enqueueIndexed() {
-      List<TOP> allSofas = cas.getBaseIndexRepositoryImpl().getIndexedFSs();
-      
-      // XCAS requires sofas in order of id
-      Collections.sort(allSofas, (fs1, fs2) -> Integer.compare(fs1._id, fs2._id) );
-      enqueueList(allSofas, 0);
-      
+      Collection<Sofa> sofaCollection = cas.getBaseIndexRepositoryImpl().<Sofa>getIndexedFSs(Sofa.class);
+      int sofaCount = sofaCollection.size();
+      if (sofaCount > 0) {
+        Sofa[] allSofas = sofaCollection.toArray(new Sofa[sofaCount]);
+        
+        // XCAS requires sofas in order of id
+        Arrays.sort(allSofas, (fs1, fs2) -> Integer.compare(fs1._id, fs2._id) );
+        enqueueArray(allSofas, 0);
+      }
 
       // Get indexes for each SofaFS in the CAS
       for (int sofaNum = 1, numViews = cas.getViewCount(); sofaNum <= numViews; sofaNum++) {
         FSIndexRepositoryImpl viewIR = (FSIndexRepositoryImpl) cas.getBaseCAS().getSofaIndexRepository(sofaNum);
         if (viewIR != null) {
-          enqueueList(viewIR.getIndexedFSs(), sofaNum);
+          Collection<TOP> fssInView = viewIR.getIndexedFSs();
+          if (! fssInView.isEmpty()) {
+            enqueueCollection(fssInView, sofaNum);
+          }
         }
       }
     }
     
-    private void enqueueList(List<TOP> fss, int sofaNum) {
+    private void enqueueArray(TOP[] fss, int sofaNum) {
       for (TOP fs : fss) {   // enqueues the fss for one view (incl view 0 - the base view
         enqueueIndexed(fs, sofaNum);
       }
     }
+    
+    private void enqueueCollection(Collection<TOP> fss, int sofaNum) {
+      for (TOP fs : fss) {
+        enqueueIndexed(fs, sofaNum);
+      }
+    }
 
     private void enqueueFeaturesOfIndexed() {
       final int max = indexedFSs.size();
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiCasDeserializer.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiCasDeserializer.java
index 6a52e24..4a063d6 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiCasDeserializer.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiCasDeserializer.java
@@ -51,6 +51,7 @@
 import org.apache.uima.internal.util.I18nUtil;
 import org.apache.uima.internal.util.IntVector;
 import org.apache.uima.internal.util.Misc;
+import org.apache.uima.internal.util.XMLUtils;
 import org.apache.uima.internal.util.XmlAttribute;
 import org.apache.uima.internal.util.XmlElementName;
 import org.apache.uima.internal.util.XmlElementNameAndContents;
@@ -81,7 +82,6 @@
 import org.xml.sax.SAXParseException;
 import org.xml.sax.XMLReader;
 import org.xml.sax.helpers.DefaultHandler;
-import org.xml.sax.helpers.XMLReaderFactory;
 
 /**
  * XMI CAS deserializer. Used to read in a CAS from XML Metadata Interchange (XMI) format.
@@ -187,7 +187,7 @@
 
     // true if unknown types should be ignored; false if they should cause an error
     boolean lenient;
-
+    
     // number of oustanding startElement events that we are ignoring
     // we add 1 when an ignored element starts and subtract 1 when an ignored
     // element ends
@@ -290,7 +290,7 @@
      *   xmi:id is strictly greater than the mergePoint value will be
      *   deserialized. 
      */
-    private XmiCasDeserializerHandler(CASImpl aCAS, boolean lenient,
+    private XmiCasDeserializerHandler(CASImpl aCAS, boolean lenient, 
             XmiSerializationSharedData sharedData, int mergePoint, AllowPreexistingFS allowPreexistingFS) {
       super();
       this.casBeingFilled = aCAS.getBaseCAS();
@@ -701,6 +701,7 @@
             todo.add(fs);   // https://issues.apache.org/jira/browse/UIMA-4099
           } else {
             if (!lenient) {
+              if (xmiId == 0) report0xmiId();  //debug
               throw createException(XCASParsingException.UNKNOWN_ID, Integer.toString(xmiId));
             }
             else {
@@ -726,7 +727,8 @@
       }
       // translate sofa's xmi:id into its sofanum
       Sofa sofa = (Sofa) maybeGetFsForXmiId(sofaXmiId);
-      if (null == sofa) {        
+      if (null == sofa) {
+        if (sofaXmiId == 0) report0xmiId();  //debug
         throw createException(XCASParsingException.UNKNOWN_ID, Integer.toString(sofaXmiId));
       }
       return (FSIndexRepositoryImpl) indexRepositories.get(sofa.getSofaNum());
@@ -791,6 +793,7 @@
         	  localRemoves.add(fs);     // https://issues.apache.org/jira/browse/UIMA-4099
         	} else {
         	  if (!lenient) {
+        	    if (xmiId == 0) report0xmiId();  //debug
               throw createException(XCASParsingException.UNKNOWN_ID, Integer.toString(xmiId));
             } else {
         		//unknown view member may be an OutOfTypeSystem FS
@@ -883,7 +886,7 @@
         }
         
         
-        // before looping over features, set the xmi to fs correspondence for this FS, incase a 
+        // before looping over features, set the xmi to fs correspondence for this FS, in case a 
         //   feature does a self reference
         String idStr = attrs.getValue(ID_ATTR_NAME);
         final int extId;
@@ -948,7 +951,7 @@
      * called from readFS 751
      * called from processDeferred, to handle features specified as child elements
      * @param type -
-     * @param fsAddr the address of the FS
+     * @param fs the FS
      * @param featName the feature name
      * @param featVal the value of the feature
      * @param isNewFS  true if this is a new FS
@@ -1045,8 +1048,8 @@
         case LowLevelCAS.TYPE_CLASS_FLOAT:
         case LowLevelCAS.TYPE_CLASS_DOUBLE:
         case LowLevelCAS.TYPE_CLASS_STRING:
-        case LowLevelCAS.TYPE_CLASS_JAVAOBJECT: {
-          casBeingFilled.setFeatureValueFromString(fs, fi, featVal);  
+            {
+          CASImpl.setFeatureValueFromStringNoDocAnnotUpdate(fs, fi, featVal);  
           break;
         }
         case LowLevelCAS.TYPE_CLASS_FS: deserializeFsRef(featVal, fi, fs); break;
@@ -1077,7 +1080,7 @@
           
             ByteArray byteArray = createOrUpdateByteArray(featVal, -1, existingByteArray);
             if (byteArray != existingByteArray) {
-              fs.setFeatureValue(fi,  byteArray);
+              CASImpl.setFeatureValueMaybeSofa(fs, fi, byteArray);
             }
           } else {  // not ByteArray, but encoded locally
             String[] arrayVals = parseArray(featVal);
@@ -1108,14 +1111,14 @@
 
     private void deserializeFsRef(String featVal, FeatureImpl fi, TOP fs) {
       if (featVal == null || featVal.length() == 0) {
-        fs.setFeatureValue(fi, null);  
+        CASImpl.setFeatureValueMaybeSofa(fs, fi, null);  
       } else {
         int xmiId = Integer.parseInt(featVal); 
         TOP tgtFs = maybeGetFsForXmiId(xmiId);
         if (null == tgtFs) {
           fixupToDos.add( () -> finalizeRefValue(xmiId, fs, fi));
         } else {
-          fs.setFeatureValue(fi,  tgtFs);
+          CASImpl.setFeatureValueMaybeSofa(fs, fi, tgtFs);
           ts.fixupFSArrayTypes(fi.getRangeImpl(), tgtFs);
         }
       }
@@ -1188,7 +1191,7 @@
           CommonArrayFS existingArray = (CommonArrayFS) fs.getFeatureValue(fi);
           CommonArrayFS casArray = createOrUpdateArray(fi.getRangeImpl(), featVals, -1, existingArray);
           if (existingArray != casArray) {
-            fs.setFeatureValue(fi, casArray);
+            CASImpl.setFeatureValueMaybeSofa(fs, fi, (TOP)casArray);
           }
           //add to nonshared fs to encompassing FS map
           if (!fi.isMultipleReferencesAllowed()) {  // ! multiple refs => value is not shared
@@ -1205,7 +1208,7 @@
           if (featVals == null) {
             fs.setFeatureValue(fi,  null);
           } else if (featVals.size() == 0) {
-            fs.setFeatureValue(fi, casBeingFilled.getEmptyList(rangeCode));
+            fs.setFeatureValue(fi, casBeingFilled.emptyList(rangeCode));
           } else {
             CommonList existingList = (CommonList) fs.getFeatureValue(fi);
             CommonList theList = createOrUpdateList(fi.getRangeImpl(), featVals, -1, existingList);
@@ -1240,7 +1243,7 @@
         updateExistingList(values, existingList);
         return existingList;
       } else {
-        return createListFromStringValues(values, casBeingFilled.getEmptyListFromTypeCode(listType.getCode()));
+        return createListFromStringValues(values, casBeingFilled.emptyListFromTypeCode(listType.getCode()));
       }
     }
     
@@ -1309,7 +1312,9 @@
      */
     private CommonArrayFS createNewArray(TypeImpl type, List<String> values) {
       final int sz = values.size();
-      CommonArrayFS fs = (CommonArrayFS) casBeingFilled.createArray(type, sz);
+      CommonArrayFS fs = (sz == 0) 
+                           ? casBeingFilled.emptyArray(type)
+                           : (CommonArrayFS) casBeingFilled.createArray(type, sz);
       if (fs instanceof FSArray) {
         final FSArray fsArray = (FSArray) fs;
         for (int i = 0; i < sz; i++) {
@@ -1374,7 +1379,7 @@
         if (existingList instanceof EmptyList) {
           return existingList;
         } else {
-          return existingList.getEmptyList();
+          return existingList.emptyList();
         }
       }
           
@@ -1406,7 +1411,7 @@
       
         // got to the end of the values, but the existing list has more elements
         //   truncate the existing list
-        prevNode.setTail(existingList.getEmptyList());
+        prevNode.setTail(existingList.emptyList());
         return existingList;
       }
 
@@ -1428,7 +1433,7 @@
     
       // got to the end of the values, but the existing list has more elements
       //   truncate the existing list
-      prevNode.setTail(existingList.getEmptyList());
+      prevNode.setTail(existingList.emptyList());
       return existingList;
     }
 
@@ -1629,8 +1634,8 @@
         return (byte) (c - '0');
       else if ('A' <= c && c <= 'F')
         return (byte) (c - 'A' + 10);
-      else if ('1' <= c && c <= 'f')
-        return (byte) (c - '1' + 10);
+      else if ('a' <= c && c <= 'f')
+        return (byte) (c - 'a' + 10);
       else
         throw new NumberFormatException("Invalid hex char: " + c);
     }
@@ -1736,7 +1741,7 @@
               for(FeatureImpl fi : currentType.getFeatureImpls()) {
                 if (!(fi.getName().equals(CAS.FEATURE_FULL_NAME_SOFA))) {
                   if ( ! this.featsSeen.contains(fi.getCode())) {
-                    casBeingFilled.setFeatureValueFromString(currentFs,  fi, null);
+                    CASImpl.setFeatureValueFromStringNoDocAnnotUpdate(currentFs,  fi, null);
                   }
                 }
               }              
@@ -1816,24 +1821,24 @@
     
     private void finalizeRefValue(int xmiId, TOP fs, FeatureImpl fi) throws XCASParsingException {
       TOP tgtFs = maybeGetFsForXmiId(xmiId);
-      if (null == tgtFs) {
+      if (null == tgtFs && xmiId != 0) { // https://issues.apache.org/jira/browse/UIMA-5446
         if (!lenient) {
           throw createException(XCASParsingException.UNKNOWN_ID, Integer.toString(xmiId));
         } else {
           // the element may be out of typesystem.  In that case set it
           // to null, but record the id so we can add it back on next serialization.
           this.sharedData.addOutOfTypeSystemAttribute(fs, fi.getShortName(), Integer.toString(xmiId));
-          fs.setFeatureValue(fi,  null);
+          CASImpl.setFeatureValueMaybeSofa(fs, fi, null);
         }
       } else {
-        fs.setFeatureValue(fi,  tgtFs);
+        CASImpl.setFeatureValueMaybeSofa(fs, fi, tgtFs);
         ts.fixupFSArrayTypes(fi.getRangeImpl(), tgtFs);
       }
     }
    
     private void finalizeFSListRefValue(int xmiId, NonEmptyFSList neNode) throws XCASParsingException {
       TOP tgtFs = maybeGetFsForXmiId(xmiId);
-      if (null == tgtFs) {
+      if (null == tgtFs && xmiId != 0) { // https://issues.apache.org/jira/browse/UIMA-5446
         if (!lenient) {
           throw createException(XCASParsingException.UNKNOWN_ID, Integer.toString(xmiId));
         } else {
@@ -1850,7 +1855,7 @@
     
     private void finalizeFSArrayRefValue(int xmiId, FSArray fsArray, int index) throws XCASParsingException {
       TOP tgtFs = maybeGetFsForXmiId(xmiId);
-      if (null == tgtFs) {
+      if (null == tgtFs && xmiId != 0) {  // https://issues.apache.org/jira/browse/UIMA-5446
         if (!lenient) {
           throw createException(XCASParsingException.UNKNOWN_ID, Integer.toString(xmiId));
         } else {
@@ -2084,6 +2089,24 @@
   public XmiCasDeserializer(TypeSystem ts) {
     this(ts, null);
   }
+  
+  /* ========================================================= */
+  /*      getters for Xmi Cas Handler                          */
+  /*   Arguments:                                              */
+  /*     cas                                                   */
+  /*     lenient                                               */
+  /*     sharedData                                            */
+  /*     mergePoint (or -1)                                    */
+  /*     allow preexisting                                     */
+  /*                                                           */
+  /* existing variants:                                        */
+  /*     cas                                                   */
+  /*     cas, lenient                                          */
+  /*     cas, lenient, sharedData                              */
+  /*     cas, lenient, sharedData, mergePoint                  */
+  /*     cas, lenient, sharedData, mergePoint, allow           */
+  /* ========================================================= */
+ 
 
   /**
    * Create a default handler for deserializing a CAS from XMI.
@@ -2112,14 +2135,13 @@
    * @return The <code>DefaultHandler</code> to pass to the SAX parser.
    */
   public DefaultHandler getXmiCasHandler(CAS cas, boolean lenient) {
-    return new XmiCasDeserializerHandler((CASImpl) cas, lenient, null, -1, AllowPreexistingFS.ignore);
+    return getXmiCasHandler(cas, lenient, null); 
   }
+  
+  
 
   /**
-   * Create a default handler for deserializing a CAS from XMI. By default this is not lenient,
-   * meaning that if the XMI references Types that are not in the Type System, an Exception will be
-   * thrown. Use {@link XmiCasDeserializer#getXmiCasHandler(CAS,boolean)} to turn on lenient mode
-   * and ignore any unknown types.
+   * Create a default handler for deserializing a CAS from XMI. 
    * 
    * @param cas
    *          This CAS will be used to hold the data deserialized from the XMI
@@ -2134,14 +2156,11 @@
    */
   public DefaultHandler getXmiCasHandler(CAS cas, boolean lenient,
           XmiSerializationSharedData sharedData) {
-    return new XmiCasDeserializerHandler((CASImpl) cas, lenient, sharedData, -1, AllowPreexistingFS.ignore);
+    return getXmiCasHandler(cas, lenient, sharedData, -1);
   }
   
   /**
-   * Create a default handler for deserializing a CAS from XMI. By default this is not lenient,
-   * meaning that if the XMI references Types that are not in the Type System, an Exception will be
-   * thrown. Use {@link XmiCasDeserializer#getXmiCasHandler(CAS,boolean)} to turn on lenient mode
-   * and ignore any unknown types.
+   * Create a default handler for deserializing a CAS from XMI. 
    * 
    * @param cas
    *          This CAS will be used to hold the data deserialized from the XMI
@@ -2161,7 +2180,7 @@
    */
   public DefaultHandler getXmiCasHandler(CAS cas, boolean lenient,
           XmiSerializationSharedData sharedData, int mergePoint) {
-    return new XmiCasDeserializerHandler((CASImpl) cas, lenient, sharedData, mergePoint, AllowPreexistingFS.ignore);
+    return getXmiCasHandler(cas, lenient, sharedData, mergePoint, AllowPreexistingFS.ignore);
   }  
   
   /**
@@ -2192,6 +2211,7 @@
     return new XmiCasDeserializerHandler((CASImpl) cas, lenient, sharedData, mergePoint, allow);
   }  
 
+
   /**
    * Deserializes a CAS from XMI.
    * 
@@ -2286,7 +2306,7 @@
   public static void deserialize(InputStream aStream, CAS aCAS, boolean aLenient,
           XmiSerializationSharedData aSharedData, int aMergePoint)
           throws SAXException, IOException {
-    XMLReader xmlReader = XMLReaderFactory.createXMLReader();
+    XMLReader xmlReader = XMLUtils.createXMLReader();
     XmiCasDeserializer deser = new XmiCasDeserializer(aCAS.getTypeSystem());
     ContentHandler handler = deser.getXmiCasHandler(aCAS, aLenient, aSharedData, aMergePoint);
     xmlReader.setContentHandler(handler);
@@ -2360,7 +2380,7 @@
   public static void deserialize(InputStream aStream, CAS aCAS, boolean aLenient,
 		  XmiSerializationSharedData aSharedData, int aMergePoint, AllowPreexistingFS allowPreexistingFS)
   throws SAXException, IOException {
-	  XMLReader xmlReader = XMLReaderFactory.createXMLReader();
+	  XMLReader xmlReader = XMLUtils.createXMLReader();
 	  XmiCasDeserializer deser = new XmiCasDeserializer(aCAS.getTypeSystem());
 	  ContentHandler handler = deser.getXmiCasHandler(aCAS, aLenient, aSharedData, aMergePoint, allowPreexistingFS);
 	  xmlReader.setContentHandler(handler);
@@ -2424,5 +2444,9 @@
     }
   }    
 
-
+  private void report0xmiId() {
+    Throwable t = new Throwable();
+    System.err.println("Debug 0 xmiId encountered where not expected");
+    t.printStackTrace();
+  }
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiCasSerializer.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiCasSerializer.java
index 70b6a62..719ab67 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiCasSerializer.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiCasSerializer.java
@@ -44,6 +44,7 @@
 import org.apache.uima.internal.util.XmlElementNameAndContents;
 import org.apache.uima.jcas.cas.ByteArray;
 import org.apache.uima.jcas.cas.CommonList;
+import org.apache.uima.jcas.cas.EmptyStringList;
 import org.apache.uima.jcas.cas.FSArray;
 import org.apache.uima.jcas.cas.Sofa;
 import org.apache.uima.jcas.cas.StringArray;
@@ -727,7 +728,7 @@
     protected void writeArrays(TOP fsArray, int typeCode, int typeClass) throws SAXException {
       XmlElementName xmlElementName = cds.typeCode2namespaceNames[typeCode];
       
-      if (fsArray instanceof StringArray) {
+      if (fsArray instanceof StringArray && ((StringArray)fsArray).size() != 0) {
 
         // string arrays are encoded as elements, in case they contain whitespace
         List<XmlElementNameAndContents> childElements = new ArrayList<XmlElementNameAndContents>();
@@ -926,8 +927,11 @@
           // special case for StringArrays, which stored values as child elements rather
           // than attributes.
         case LowLevelCAS.TYPE_CLASS_STRINGARRAY: 
+          StringArray stringArray = (StringArray) fs.getFeatureValue(fi);
           if (cds.isStaticMultiRef(fi)) {
-            attrValue = cds.getXmiId(fs.getFeatureValue(fi));
+            attrValue = cds.getXmiId(stringArray);
+          } else if (stringArray != null && stringArray.size() == 0) {
+            attrValue = "";  //https://issues.apache.org/jira/browse/UIMA-5558
           } else {
             stringArrayToElementList(featName, (StringArray) fs.getFeatureValue(fi), childElements);
             attrValue = null;
@@ -962,17 +966,23 @@
             // it is not safe to use a space-separated attribute, which would
             // break for strings containing spaces. So use child elements instead.
             StringList stringList = (StringList) fs.getFeatureValue(fi);
-            if (stringList != null) {
-              List<String> listOfStrings = stringList.anyListToStringList(null, cds);
+            if (stringList == null) {
+              attrValue = null;
+            } else {
+              if (stringList instanceof EmptyStringList) {
+                attrValue = "";
+              } else {
+                List<String> listOfStrings = stringList.anyListToStringList(null, cds);
 //              if (array.length > 0 && !arrayAndListFSs.put(featVal, featVal)) {
 //                reportWarning("Warning: multiple references to a ListFS.  Reference identity will not be preserved.");
 //              }
-              for (String string : listOfStrings) {
-                childElements.add(new XmlElementNameAndContents(new XmlElementName("", featName,
-                        featName), string));
+                for (String string : listOfStrings) {
+                  childElements.add(new XmlElementNameAndContents(new XmlElementName("", featName,
+                          featName), string));
+                }
+                attrValue = null;
               }
             }
-            attrValue = null;
           }
           break;
         
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiSerializationSharedData.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiSerializationSharedData.java
index d09e338..0c6c3e1 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiSerializationSharedData.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiSerializationSharedData.java
@@ -78,7 +78,7 @@
    * getFsAddrForXmiId() method, necessary to support merging multiple XMI
    * CASes into the same CAS object.
    **/
-  private Int2ObjHashMap<TOP> xmiIdToFs = new Int2ObjHashMap<>(TOP.class);
+  private Int2ObjHashMap<TOP, TOP> xmiIdToFs = new Int2ObjHashMap<>(TOP.class);
   
   /**
    * List of OotsElementData objects, each of which captures information about
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/text/AnnotationIndex.java b/uimaj-core/src/main/java/org/apache/uima/cas/text/AnnotationIndex.java
index c9ba76e..ac159da 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/text/AnnotationIndex.java
+++ b/uimaj-core/src/main/java/org/apache/uima/cas/text/AnnotationIndex.java
@@ -40,8 +40,10 @@
  * annotations with smaller spans, which produces an iteration order similar to a preorder tree
  * traversal.</li>
  * <li>Annotations whose start offsets are equal and whose end offsets are equal are sorted based
- * on {@link org.apache.uima.resource.metadata.TypePriorities} (which is an element of the component
- * descriptor). That is, if <code>a.start = b.start</code>, <code>a.end = b.end</code>, and
+ * on {@link org.apache.uima.resource.metadata.TypePriorities} if type priorities are specified.
+ * Type Priorities specification is an optional element of the component
+ * descriptor). When type priorities are in use, if <code>a.start = b.start</code>, 
+ * <code>a.end = b.end</code>, and
  * the type of <code>a</code> is defined before the type of <code>b</code> in the type
  * priorities, then <code>a &lt; b</code>.
  * <li>
@@ -76,7 +78,7 @@
    * @return A annotation iterator.
    */
   FSIterator<T> iterator(boolean ambiguous);
-
+                              
   /**
    * Return a subiterator whose bounds are defined by the input annotation.
    * 
diff --git a/uimaj-core/src/main/java/org/apache/uima/examples/SourceDocumentInformation.java b/uimaj-core/src/main/java/org/apache/uima/examples/SourceDocumentInformation.java
index 200a799..9c7e335 100644
--- a/uimaj-core/src/main/java/org/apache/uima/examples/SourceDocumentInformation.java
+++ b/uimaj-core/src/main/java/org/apache/uima/examples/SourceDocumentInformation.java
@@ -21,6 +21,9 @@
 
 package org.apache.uima.examples;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -31,14 +34,9 @@
 import org.apache.uima.jcas.tcas.Annotation;
 
 
-/** 
- * Stores detailed information about the original source document from which the current CAS was initialized. 
- * All information (like size) refers to the source document and not to the document in the CAS 
- *  which may be converted and filtered by a CAS Initializer. 
- * For example this information will be written to the Semantic Search index so that 
- *  the original document contents can be retrieved by queries.
- * Updated by JCasGen Wed Dec 21 14:40:40 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-examples/src/main/resources/org/apache/uima/examples/SourceDocumentInformation.xml
+/** Stores detailed information about the original source document from which the current CAS was initialized. All information (like size) refers to the source document and not to the document in the CAS which may be converted and filtered by a CAS Initializer. For example this information will be written to the Semantic Search index so that the original document contents can be retrieved by queries.
+ * Updated by JCasGen Sun Oct 08 19:24:05 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-examples/src/main/resources/org/apache/uima/examples/SourceDocumentInformation.xml
  * @generated */
 public class SourceDocumentInformation extends Annotation {
   /** @generated
@@ -65,7 +63,7 @@
  
  
   /* *******************
-   *   Feature Offsets *
+   *   Feature Names   *
    * *******************/ 
    
   public final static String _FeatName_uri = "uri";
@@ -74,15 +72,15 @@
   public final static String _FeatName_lastSegment = "lastSegment";
 
 
-  /* *******************
-   *   Feature Offsets *
-   * *******************/ 
-   
   /* Feature Adjusted Offsets */
-  public final static int _FI_uri = TypeSystemImpl.getAdjustedFeatureOffset("uri");
-  public final static int _FI_offsetInSource = TypeSystemImpl.getAdjustedFeatureOffset("offsetInSource");
-  public final static int _FI_documentSize = TypeSystemImpl.getAdjustedFeatureOffset("documentSize");
-  public final static int _FI_lastSegment = TypeSystemImpl.getAdjustedFeatureOffset("lastSegment");
+  private final static CallSite _FC_uri = TypeSystemImpl.createCallSite(SourceDocumentInformation.class, "uri");
+  private final static MethodHandle _FH_uri = _FC_uri.dynamicInvoker();
+  private final static CallSite _FC_offsetInSource = TypeSystemImpl.createCallSite(SourceDocumentInformation.class, "offsetInSource");
+  private final static MethodHandle _FH_offsetInSource = _FC_offsetInSource.dynamicInvoker();
+  private final static CallSite _FC_documentSize = TypeSystemImpl.createCallSite(SourceDocumentInformation.class, "documentSize");
+  private final static MethodHandle _FH_documentSize = _FC_documentSize.dynamicInvoker();
+  private final static CallSite _FC_lastSegment = TypeSystemImpl.createCallSite(SourceDocumentInformation.class, "lastSegment");
+  private final static MethodHandle _FH_lastSegment = _FC_lastSegment.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -138,14 +136,14 @@
    * @generated
    * @return value of the feature 
    */
-  public String getUri() { return _getStringValueNc(_FI_uri);}
+  public String getUri() { return _getStringValueNc(wrapGetIntCatchException(_FH_uri));}
     
   /** setter for uri - sets URI of document. (For example, file:///MyDirectory/myFile.txt for a simple file or http://incubator.apache.org/uima/index.html for content from a web source.) 
    * @generated
    * @param v value to set into the feature 
    */
   public void setUri(String v) {
-    _setStringValueNfc(_FI_uri, v);
+    _setStringValueNfc(wrapGetIntCatchException(_FH_uri), v);
   }    
     
    
@@ -157,14 +155,14 @@
    * @generated
    * @return value of the feature 
    */
-  public int getOffsetInSource() { return _getIntValueNc(_FI_offsetInSource);}
+  public int getOffsetInSource() { return _getIntValueNc(wrapGetIntCatchException(_FH_offsetInSource));}
     
   /** setter for offsetInSource - sets Byte offset of the start of document content within original source file or other input source. Only used if the CAS document was retrieved from an source where one physical source file contained several conceptual documents. Zero otherwise. 
    * @generated
    * @param v value to set into the feature 
    */
   public void setOffsetInSource(int v) {
-    _setIntValueNfc(_FI_offsetInSource, v);
+    _setIntValueNfc(wrapGetIntCatchException(_FH_offsetInSource), v);
   }    
     
    
@@ -176,14 +174,14 @@
    * @generated
    * @return value of the feature 
    */
-  public int getDocumentSize() { return _getIntValueNc(_FI_documentSize);}
+  public int getDocumentSize() { return _getIntValueNc(wrapGetIntCatchException(_FH_documentSize));}
     
   /** setter for documentSize - sets Size of original document in bytes before processing by CAS Initializer. Either absolute file size of size within file or other source. 
    * @generated
    * @param v value to set into the feature 
    */
   public void setDocumentSize(int v) {
-    _setIntValueNfc(_FI_documentSize, v);
+    _setIntValueNfc(wrapGetIntCatchException(_FH_documentSize), v);
   }    
     
    
@@ -195,14 +193,14 @@
    * @generated
    * @return value of the feature 
    */
-  public boolean getLastSegment() { return _getBooleanValueNc(_FI_lastSegment);}
+  public boolean getLastSegment() { return _getBooleanValueNc(wrapGetIntCatchException(_FH_lastSegment));}
     
   /** setter for lastSegment - sets For a CAS that represents a segment of a larger source document, this flag indicates whether this CAS is the final segment of the source document.  This is useful for downstream components that want to take some action after having seen all of the segments of a particular source document. 
    * @generated
    * @param v value to set into the feature 
    */
   public void setLastSegment(boolean v) {
-    _setBooleanValueNfc(_FI_lastSegment, v);
+    _setBooleanValueNfc(wrapGetIntCatchException(_FH_lastSegment), v);
   }    
     
   }
diff --git a/uimaj-core/src/main/java/org/apache/uima/flow/FlowController_ImplBase.java b/uimaj-core/src/main/java/org/apache/uima/flow/FlowController_ImplBase.java
index 326716c..56e4bce 100644
--- a/uimaj-core/src/main/java/org/apache/uima/flow/FlowController_ImplBase.java
+++ b/uimaj-core/src/main/java/org/apache/uima/flow/FlowController_ImplBase.java
@@ -24,6 +24,7 @@
 import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
 import org.apache.uima.resource.ResourceConfigurationException;
 import org.apache.uima.resource.ResourceInitializationException;
+import org.apache.uima.util.Logger;
 
 /**
  * Implementation base class for FlowControllers. Normally developers do not extend this class
@@ -117,4 +118,12 @@
   protected FlowControllerContext getContext() {
     return mContext;
   }
+  
+  /**
+   * Gets the logger for this FlowController
+   * @return the logger for this FlowController
+   */
+  protected Logger getLogger() {  // https://issues.apache.org/jira/projects/UIMA/issues/UIMA-5565
+    return getContext().getLogger();
+  }
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/impl/ChildUimaContext_impl.java b/uimaj-core/src/main/java/org/apache/uima/impl/ChildUimaContext_impl.java
index 7242f4a..9d34e12 100644
--- a/uimaj-core/src/main/java/org/apache/uima/impl/ChildUimaContext_impl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/impl/ChildUimaContext_impl.java
@@ -88,6 +88,7 @@
    *      org.apache.uima.util.Logger, org.apache.uima.resource.ResourceManager,
    *      ConfigurationManager)
    */
+  @Override
   public void initializeRoot(Logger aLogger, ResourceManager aResourceManager,
           ConfigurationManager aConfigurationManager) {
     throw new UIMA_UnsupportedOperationException();
@@ -98,6 +99,7 @@
    * 
    * @return the InstrumentationFacility to be used within this AnalysisEngine
    */
+  @Override
   public InstrumentationFacility getInstrumentationFacility() {
     return getRootContext().getInstrumentationFacility();
   }
@@ -107,8 +109,9 @@
    * 
    * @see org.apache.uima.UimaContextAdmin#setLogger(org.apache.uima.util.Logger)
    */
+  @Override
   public void setLogger(Logger aLogger) {
-    mLogger = aLogger;
+    mLogger = maybeThrottleLogger(aLogger);
   }
 
   /**
@@ -116,6 +119,7 @@
    * 
    * @return the ResourceManager
    */
+  @Override
   public ResourceManager getResourceManager() {
     if (null == mPearResourceManager) {
       return parentContext.getResourceManager();
@@ -137,6 +141,7 @@
    * 
    * @see org.apache.uima.UimaContextAdmin#getConfigurationManager()
    */
+  @Override
   public ConfigurationManager getConfigurationManager() {
     return getRootContext().getConfigurationManager();
   }
@@ -148,6 +153,7 @@
    * This method is to be called from the Analysis Engine, not the Annotator, so it is not part of
    * the AnnotatorContext interface.
    */
+  @Override
   public void setProcessTrace(ProcessTrace aProcessTrace) {
     getRootContext().setProcessTrace(aProcessTrace);
   }
@@ -157,6 +163,7 @@
    * 
    * @return root context
    */
+  @Override
   public UimaContextAdmin getRootContext() {
     return mRootContext;
   }
@@ -164,6 +171,7 @@
   /**
    * @see org.apache.uima.analysis_engine.annotator.AnnotatorContext#getLogger()
    */
+  @Override
   public Logger getLogger() {
     return mLogger;
   }
@@ -173,6 +181,7 @@
    * 
    * @see org.apache.uima.UimaContext#getSession()
    */
+  @Override
   public Session getSession() {
     // must update root session first, in case it has been changed, for example by the deployment
     // wrapper
@@ -185,6 +194,7 @@
    * 
    * @see org.apache.uima.UimaContextAdmin#setSession(org.apache.uima.resource.Session)
    */
+  @Override
   public void setSession(Session aSession) {
     throw new UIMA_UnsupportedOperationException();
 
diff --git a/uimaj-core/src/main/java/org/apache/uima/impl/RootUimaContext_impl.java b/uimaj-core/src/main/java/org/apache/uima/impl/RootUimaContext_impl.java
index 450a74c..bef3ea3 100644
--- a/uimaj-core/src/main/java/org/apache/uima/impl/RootUimaContext_impl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/impl/RootUimaContext_impl.java
@@ -77,10 +77,12 @@
    */
   protected volatile Settings mExternalOverrides;
   
+  @Override
   public Settings getExternalOverrides() {
     return mExternalOverrides;
   }
   
+  @Override
   public void setExternalOverrides(Settings externalOverrides) {
     mExternalOverrides = externalOverrides;
   }
@@ -101,6 +103,7 @@
    *      org.apache.uima.util.Logger, org.apache.uima.resource.ResourceManager,
    *      ConfigurationManager)
    */
+  @Override
   public void initializeRoot(Logger aLogger, ResourceManager aResourceManager,
           ConfigurationManager aConfigurationManager) {
     mLogger = aLogger;
@@ -112,6 +115,7 @@
   /**
    * @see org.apache.uima.analysis_engine.annotator.AnnotatorContext#getLogger()
    */
+  @Override
   public Logger getLogger() {
     return mLogger;
   }
@@ -121,8 +125,9 @@
    * 
    * @see org.apache.uima.UimaContextAdmin#setLogger(org.apache.uima.util.Logger)
    */
+  @Override
   public void setLogger(Logger aLogger) {
-    mLogger = aLogger;
+    mLogger = maybeThrottleLogger(aLogger);
   }
 
   /**
@@ -130,6 +135,7 @@
    * 
    * @return the ResourceManager
    */
+  @Override
   public ResourceManager getResourceManager() {
     return mResourceManager;
   }
@@ -139,6 +145,7 @@
    * 
    * @see org.apache.uima.UimaContextAdmin#getConfigurationManager()
    */
+  @Override
   public ConfigurationManager getConfigurationManager() {
     return mConfigurationManager;
   }
@@ -148,6 +155,7 @@
    * 
    * @return the InstrumentationFacility to be used within this AnalysisEngine
    */
+  @Override
   public InstrumentationFacility getInstrumentationFacility() {
     return mInstrumentationFacility;
   }
@@ -159,6 +167,7 @@
    * This method is to be called from the Analysis Engine, not the Annotator, so it is not part of
    * the AnnotatorContext interface.
    */
+  @Override
   public void setProcessTrace(ProcessTrace aProcessTrace) {
     mInstrumentationFacility.setProcessTrace(aProcessTrace);
   }
@@ -168,6 +177,7 @@
    * 
    * @see org.apache.uima.UimaContextAdmin#setSession(org.apache.uima.resource.Session)
    */
+  @Override
   public void setSession(Session aSession) {
     mSession = aSession;
     mConfigurationManager.setSession(mSession);
@@ -179,6 +189,7 @@
    * 
    * @see org.apache.uima.UimaContext#getSession()
    */
+  @Override
   public Session getSession() {
     return mSession;
   }
@@ -188,6 +199,7 @@
    * 
    * @return root context
    */
+  @Override
   public UimaContextAdmin getRootContext() {
     return this;
   }
diff --git a/uimaj-core/src/main/java/org/apache/uima/impl/UIMAFramework_impl.java b/uimaj-core/src/main/java/org/apache/uima/impl/UIMAFramework_impl.java
index d167f29..127312c 100644
--- a/uimaj-core/src/main/java/org/apache/uima/impl/UIMAFramework_impl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/impl/UIMAFramework_impl.java
@@ -24,10 +24,10 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParser;
@@ -40,10 +40,12 @@
 import org.apache.uima.UIMAFramework;
 import org.apache.uima.UIMARuntimeException;
 import org.apache.uima.UimaContextAdmin;
+import org.apache.uima.analysis_component.AnalysisComponent_ImplBase;
 import org.apache.uima.collection.CollectionProcessingEngine;
 import org.apache.uima.collection.CollectionProcessingManager;
 import org.apache.uima.collection.metadata.CpeDescription;
 import org.apache.uima.internal.util.I18nUtil;
+import org.apache.uima.internal.util.XMLUtils;
 import org.apache.uima.resource.ConfigurationManager;
 import org.apache.uima.resource.ResourceInitializationException;
 import org.apache.uima.resource.ResourceManager;
@@ -53,6 +55,7 @@
 import org.apache.uima.util.UimaTimer;
 import org.apache.uima.util.XMLParser;
 import org.apache.uima.util.impl.Constants;
+import org.apache.uima.util.impl.Logger_common_impl;
 import org.apache.uima.util.impl.XMLParser_impl;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
@@ -158,8 +161,8 @@
   /**
    * HashMap includes all log wrapper classes
    */
-  private HashMap mLoggers;
-
+  private ConcurrentHashMap<String, Logger> mLoggers;
+  
   /**
    * Creates a new UIMAFramework_impl.
    */
@@ -169,6 +172,7 @@
   /**
    * @see org.apache.uima.UIMAFramework#_initialize()
    */
+  @Override
   protected void _initialize() throws Exception {
     // attempt to improve initialization performance
     Introspector.setBeanInfoSearchPath(Constants.EMPTY_STRING_ARRAY);
@@ -185,12 +189,13 @@
             .getResourceAsStream("performanceTuning.properties"));
 
     // create new HashMap for the LogWrappers
-    mLoggers = new HashMap(200, 1.0f);
+    mLoggers = new ConcurrentHashMap<>(200, 1.0f);
   }
 
   /**
    * @see org.apache.uima.UIMAFramework#_getMajorVersion()
    */
+  @Override
   public short _getMajorVersion() {
     return UimaVersion.getMajorVersion(); // major version
   }
@@ -198,6 +203,7 @@
   /**
    * @see org.apache.uima.UIMAFramework#_getMinorVersion()
    */
+  @Override
   public short _getMinorVersion() {
     return UimaVersion.getMinorVersion(); // minor version
   }
@@ -205,6 +211,7 @@
   /**
    * @see org.apache.uima.UIMAFramework#_getBuildRevision()
    */
+  @Override
   public short _getBuildRevision() {
     return UimaVersion.getBuildRevision(); // build revision
   }
@@ -215,6 +222,7 @@
    * 
    * @return the <code>ResourceFactory</code> to be used by the application
    */
+  @Override
   protected CompositeResourceFactory _getResourceFactory() {
     return mResourceFactory;
   }
@@ -225,6 +233,7 @@
    * 
    * @return the <code>ResourceSpecifierFactory</code> to be used by the application.
    */
+  @Override
   protected ResourceSpecifierFactory _getResourceSpecifierFactory() {
     return mResourceSpecifierFactory;
   }
@@ -235,6 +244,7 @@
    * 
    * @return the <code>XMLParser</code> to be used by the application.
    */
+  @Override
   protected XMLParser _getXMLParser() {
     return mXMLParser;
   }
@@ -242,6 +252,7 @@
   /**
    * @see org.apache.uima.UIMAFramework#newCollectionProcessingManager()
    */
+  @Override
   protected CollectionProcessingManager _newCollectionProcessingManager(
           ResourceManager aResourceManager) {
     try {
@@ -263,6 +274,7 @@
    * 
    * @return the <code>Logger</code> to be used by the application.
    */
+  @Override
   protected Logger _getLogger() {
     return mDefaultLogger;
   }
@@ -273,40 +285,56 @@
    * 
    * @return the <code>Logger</code> of the specified source class
    */
+  @Override
   protected Logger _getLogger(Class component) {
+    
+    
     // search for the source class logger in the HashMap
-    Object o = mLoggers.get(component.getName());
+    Logger o = mLoggers.get(component.getName());
 
     if (o == null) // source class logger not available
     {
-      // create new Logger for the source class
-      // set method argument type
-      Class[] argumentTypes = { Class.class };
-      // set argument value
-      Object[] arguments = { component };
-      try {
-        // get static method getInstance(Class component)
-        Method instanceMethod = mLoggerClass.getMethod("getInstance", argumentTypes);
-        // invoke getInstance(Class component) method and retrieve logger object
-        o = instanceMethod.invoke(null, arguments);
-      } catch (NoSuchMethodException e) {
-        throw new UIMARuntimeException(e);
-      } catch (InvocationTargetException e) {
-        throw new UIMARuntimeException(e);
-      } catch (IllegalAccessException e) {
-        throw new UIMARuntimeException(e);
-      }
+      synchronized (this) {
+        o = mLoggers.get(component.getName());
 
-      // put created logger to the HashMap
-      mLoggers.put(component.getName(), o);
+        if (o == null) { // source class logger not available
+      
+          // create new Logger for the source class
+          // set method argument type
+          Class[] argumentTypes = { Class.class };
+          // set argument value
+          Object[] arguments = { component };
+          try {
+            // get static method getInstance(Class component)
+            Method instanceMethod = mLoggerClass.getMethod("getInstance", argumentTypes);
+            // invoke getInstance(Class component) method and retrieve logger object
+            o = (Logger) instanceMethod.invoke(null, arguments);
+            if (AnalysisComponent_ImplBase.class.isAssignableFrom(component) || 
+                // Watch out: next Annotat_ImplBase class exists in 2 packages, this one is old one, needed for backwards compat.
+                org.apache.uima.analysis_engine.annotator.Annotator_ImplBase.class.isAssignableFrom(component)) {  
+              ((Logger_common_impl)o).setAnnotatorLogger(true); 
+            } 
+          } catch (NoSuchMethodException e) {
+            throw new UIMARuntimeException(e);
+          } catch (InvocationTargetException e) {
+            throw new UIMARuntimeException(e);
+          } catch (IllegalAccessException e) {
+            throw new UIMARuntimeException(e);
+          }
+    
+          // put created logger to the HashMap
+          mLoggers.put(component.getName(), o);
+        }
+      }
     }
 
-    return (Logger) o;
+    return o;
   }
 
   /**
    * @see org.apache.uima.UIMAFramework#_newLogger()
    */
+  @Override
   protected Logger _newLogger() {
     try {
       // get static method getInstance()
@@ -328,6 +356,7 @@
    * 
    * @return a new <code>ResourceManager</code> to be used by the application.
    */
+  @Override
   protected ResourceManager _newDefaultResourceManager() {
     try {
       return (ResourceManager) Class.forName(mResourceManagerImplClassName).newInstance();
@@ -346,6 +375,7 @@
    * 
    * @return a new <code>ResourceManager</code> to be used by the application.
    */
+  @Override
   protected ResourceManager _newDefaultResourceManagerPearWrapper() {
     try {
       return (ResourceManager) Class.forName(mResourceManagerPearWrapperImplClassName).newInstance();
@@ -364,6 +394,7 @@
    * 
    * @return a new <code>ConfigurationManager</code> to be used by the application.
    */
+  @Override
   protected ConfigurationManager _newConfigurationManager() {
     try {
       return (ConfigurationManager) Class.forName(mConfigurationManagerImplClassName).newInstance();
@@ -379,6 +410,7 @@
   /**
    * @see org.apache.uima.UIMAFramework#_newUimaContext()
    */
+  @Override
   protected UimaContextAdmin _newUimaContext() {
     try {
       return (UimaContextAdmin) Class.forName(mUimaContextImplClassName).newInstance();
@@ -394,6 +426,7 @@
   /**
    * @see org.apache.uima.UIMAFramework#_newTimer()
    */
+  @Override
   protected UimaTimer _newTimer() {
     try {
       return (UimaTimer) Class.forName(mTimerClassName).newInstance();
@@ -412,6 +445,7 @@
    * @see org.apache.uima.UIMAFramework#_produceCollectionProcessingEngine(org.apache.uima.collection.metadata.cpeDescription,
    *      java.util.Map)
    */
+  @Override
   protected CollectionProcessingEngine _produceCollectionProcessingEngine(
           CpeDescription aCpeDescription, Map<String, Object> aAdditionalParams)
           throws ResourceInitializationException {
@@ -434,6 +468,7 @@
    * 
    * @see org.apache.uima.UIMAFramework#_getDefaultPerformanceTuningProperties()
    */
+  @Override
   protected Properties _getDefaultPerformanceTuningProperties() {
     return (Properties) mDefaultPerformanceTuningProperties.clone();
   }
@@ -457,7 +492,8 @@
     // TOOD: Need UtilityClassLoader here? I don't think we do; this works
     // with XML4J v3. This is a good thing, since the UtilityClassLoader writes
     // to the logger, which isn't created yet!
-    SAXParserFactory factory = SAXParserFactory.newInstance();
+
+    SAXParserFactory factory = XMLUtils.createSAXParserFactory();
     SAXParser parser = factory.newSAXParser();
     XMLReader reader = parser.getXMLReader();
 
@@ -493,6 +529,7 @@
     /**
      * @see org.xml.sax.ContentHandler#startDocument()
      */
+    @Override
     public void startDocument() throws SAXException {
       context = CONTEXT_NONE;
     }
@@ -501,6 +538,7 @@
      * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String,
      *      java.lang.String, org.xml.sax.Attributes)
      */
+    @Override
     public void startElement(String uri, String localName, String qName, Attributes attributes)
             throws SAXException {
       if ("logger".equals(qName)) {
@@ -663,6 +701,7 @@
      * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String,
      *      java.lang.String)
      */
+    @Override
     public void endElement(String uri, String localName, String qName) throws SAXException {
       if ("factoryConfig".equals(qName)) {
         context = CONTEXT_NONE;
@@ -684,6 +723,7 @@
     /**
      * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException)
      */
+    @Override
     public void warning(SAXParseException e) throws SAXException {
       if (_getLogger() != null) {
         UIMAFramework.getLogger(CLASS_NAME).logrb(Level.WARNING, CLASS_NAME.getName(), "warning",
@@ -694,6 +734,7 @@
     /**
      * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
      */
+    @Override
     public void error(SAXParseException e) throws SAXException {
       throw new UIMARuntimeException(e);
     }
diff --git a/uimaj-core/src/main/java/org/apache/uima/impl/UimaContext_ImplBase.java b/uimaj-core/src/main/java/org/apache/uima/impl/UimaContext_ImplBase.java
index a385f66..4e990b3 100644
--- a/uimaj-core/src/main/java/org/apache/uima/impl/UimaContext_ImplBase.java
+++ b/uimaj-core/src/main/java/org/apache/uima/impl/UimaContext_ImplBase.java
@@ -37,6 +37,7 @@
 import java.util.TreeMap;
 import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.uima.UIMAFramework;
 import org.apache.uima.UIMARuntimeException;
@@ -56,6 +57,7 @@
 import org.apache.uima.resource.metadata.ConfigurationGroup;
 import org.apache.uima.resource.metadata.ConfigurationParameter;
 import org.apache.uima.util.Level;
+import org.apache.uima.util.Logger;
 import org.apache.uima.util.Settings;
 import org.apache.uima.util.UriUtils;
 import org.apache.uima.util.impl.Constants;
@@ -70,6 +72,8 @@
    */
   private static final String LOG_RESOURCE_BUNDLE = "org.apache.uima.impl.log_messages";
     
+  private static AtomicInteger MDC_NEXT_ID = new AtomicInteger(0);
+  
   /**
    * The ComponentInfoImpl class (an inner non-static class) has no fields and 
    *   just one method that refers to fields in
@@ -167,6 +171,19 @@
 
   final private String uniqueIdentifier;
   
+  final private String mdcUniqueId;
+  
+  /**
+   * A number to throttle logging from Annotators
+   * If not the max value, it wraps loggers obtained with getLogger() that are 
+   * for Annotator classes, with the ThrottlingLogger.
+   * 
+   * This value is set from an Additional Parameters key 
+   *   AnalysisEngine.PARAM_SUPPRESS_EXCESSIVE_ANNOTATOR_LOGGING
+   * passed in as part of the additional parameters 
+   */
+  protected int loggingThrottleLimit = Integer.MAX_VALUE;
+  
   /**
    * Default constructor. 
    * Only Called for creating a "Root" instance.
@@ -174,6 +191,7 @@
   public UimaContext_ImplBase() { 
     mQualifiedContextName = "/";  // This constructor for root call only
     uniqueIdentifier = constructUniqueName();
+    mdcUniqueId = String.valueOf(MDC_NEXT_ID.getAndIncrement());
     mSofaMappings = new TreeMap<String, String>();
 
   }
@@ -186,6 +204,7 @@
   public UimaContext_ImplBase(String contextName, Map<String, String> sofaMappings) {
     mQualifiedContextName = contextName;
     uniqueIdentifier = constructUniqueName();
+    mdcUniqueId = "invalid";  // never referenced
     mSofaMappings = sofaMappings;
   }
   
@@ -208,6 +227,7 @@
   /* Returns a unique name of this component
    * 
    */
+  @Override
   public String getUniqueName() {
     // return a unique name of this component
     return getQualifiedContextName()+"_"+uniqueIdentifier;
@@ -218,6 +238,7 @@
    * 
    * @see org.apache.uima.UimaContextAdmin#createChild(java.lang.String)
    */
+  @Override
   public UimaContextAdmin createChild(String aContextName, Map<String, String> aSofaMappings) {
 
     // create child context with the absolute mappings
@@ -263,6 +284,7 @@
   /**
    * @see org.apache.uima.analysis_engine.annotator.AnnotatorContext#getConfigParameterValue(java.lang.String)
    */
+  @Override
   public Object getConfigParameterValue(String aName) {
     return getConfigurationManager().getConfigParameterValue(makeQualifiedName(aName));
   }
@@ -271,6 +293,7 @@
    * @see org.apache.uima.analysis_engine.annotator.AnnotatorContext#getConfigParameterValue(java.lang.String,
    *      java.lang.String)
    */
+  @Override
   public Object getConfigParameterValue(String aGroupName, String aParamName) {
     return getConfigurationManager().getConfigParameterValue(makeQualifiedName(aParamName),
             aGroupName);
@@ -303,6 +326,7 @@
    * 
    * @see org.apache.uima.analysis_engine.annotator.AnnotatorContext#getResourceURL(java.lang.String)
    */
+  @Override
   public URL getResourceURL(String aKey) throws ResourceAccessException {
     URL result = getResourceManager().getResourceURL(makeQualifiedName(aKey));
     if (result != null) {
@@ -327,6 +351,7 @@
   /* (non-Javadoc)
    * @see org.apache.uima.UimaContext#getResourceURI(java.lang.String)
    */
+  @Override
   public URI getResourceURI(String aKey) throws ResourceAccessException {
     return getResourceURIfromURL( getResourceURL(aKey));
   }
@@ -348,6 +373,7 @@
   /* (non-Javadoc)
    * @see org.apache.uima.UimaContext#getResourceFilePath(java.lang.String)
    */
+  @Override
   public String getResourceFilePath(String aKey) throws ResourceAccessException {
     URI resourceUri = getResourceURI(aKey);
     if (resourceUri != null) {
@@ -369,6 +395,7 @@
    * 
    * @see org.apache.uima.analysis_engine.annotator.AnnotatorContext#getResourceAsStream(java.lang.String)
    */
+  @Override
   public InputStream getResourceAsStream(String aKey) throws ResourceAccessException {
     InputStream result = getResourceManager().getResourceAsStream(makeQualifiedName(aKey));
     if (result != null) {
@@ -400,6 +427,7 @@
    * 
    * @see org.apache.uima.analysis_engine.annotator.AnnotatorContext#getResourceObject(java.lang.String)
    */
+  @Override
   public Object getResourceObject(String aKey) throws ResourceAccessException {
     return getResourceManager().getResource(makeQualifiedName(aKey));
   }
@@ -408,6 +436,7 @@
    * @see org.apache.uima.analysis_engine.annotator.AnnotatorContext#getResourceAsStream(java.lang.String,
    *      java.lang.String[])
    */
+  @Override
   public InputStream getResourceAsStream(String aKey, String[] aParams)
           throws ResourceAccessException {
     InputStream result = getResourceManager().getResourceAsStream(makeQualifiedName(aKey), aParams);
@@ -439,6 +468,7 @@
    * @see org.apache.uima.analysis_engine.annotator.AnnotatorContext#getResourceObject(java.lang.String,
    *      java.lang.String[])
    */
+  @Override
   public Object getResourceObject(String aKey, String[] aParams) throws ResourceAccessException {
     return getResourceManager().getResource(makeQualifiedName(aKey), aParams);
   }
@@ -447,6 +477,7 @@
    * @see org.apache.uima.analysis_engine.annotator.AnnotatorContext#getResourceURL(java.lang.String,
    *      java.lang.String[])
    */
+  @Override
   public URL getResourceURL(String aKey, String[] aParams) throws ResourceAccessException {
     URL result = getResourceManager().getResourceURL(makeQualifiedName(aKey), aParams);
     if (result != null) {
@@ -471,6 +502,7 @@
   /* (non-Javadoc)
    * @see org.apache.uima.UimaContext#getResourceURI(java.lang.String, java.lang.String[])
    */
+  @Override
   public URI getResourceURI(String aKey, String[] aParams) throws ResourceAccessException {
     return getResourceURIfromURL(getResourceURL(aKey, aParams));
   } 
@@ -478,6 +510,7 @@
   /* (non-Javadoc)
    * @see org.apache.uima.UimaContext#getResourceFilePath(java.lang.String, java.lang.String[])
    */
+  @Override
   public String getResourceFilePath(String aKey, String[] aParams) throws ResourceAccessException {
     URI resourceUri = getResourceURI(aKey, aParams);
     if (resourceUri != null) {
@@ -496,6 +529,7 @@
   /**
    * @see org.apache.uima.analysis_engine.annotator.AnnotatorContext#getDataPath()
    */
+  @Override
   public String getDataPath() {
     return getResourceManager().getDataPath();
   }
@@ -504,6 +538,7 @@
     return mQualifiedContextName + name;
   }
 
+  @Override
   public String getQualifiedContextName() {
     return mQualifiedContextName;
   }
@@ -513,6 +548,7 @@
    * 
    * @see org.apache.uima.UimaContext#getConfigurationGroupNames()
    */
+  @Override
   public String[] getConfigurationGroupNames() {
     ConfigurationGroup[] groups = getConfigurationManager().getConfigParameterDeclarations(
             getQualifiedContextName()).getConfigurationGroups();
@@ -534,6 +570,7 @@
    * 
    * @see org.apache.uima.UimaContext#getConfigurationParameterNames()
    */
+  @Override
   public String[] getConfigParameterNames() {
     ConfigurationParameter[] params = getConfigurationManager().getConfigParameterDeclarations(
             getQualifiedContextName()).getConfigurationParameters();
@@ -553,6 +590,7 @@
    * 
    * @see org.apache.uima.UimaContext#getConfigurationParameterNames(java.lang.String)
    */
+  @Override
   public String[] getConfigParameterNames(String aGroup) {
     ConfigurationGroup[] groups = getConfigurationManager().getConfigParameterDeclarations(
             getQualifiedContextName()).getConfigurationGroupDeclarations(aGroup);
@@ -584,6 +622,7 @@
    * 
    * @see org.apache.uima.UimaContextAdmin#getExternalOverrides()
    */
+  @Override
   public Settings getExternalOverrides() {
     return getRootContext().getExternalOverrides();
   }
@@ -593,6 +632,7 @@
    * 
    * @see org.apache.uima.UimaContextAdmin#setExternalOverrides(org.apache.uima.util.Settings)
    */
+  @Override
   public void setExternalOverrides(Settings externalOverrides) {
     getRootContext().setExternalOverrides(externalOverrides);
   }
@@ -602,6 +642,7 @@
    * 
    * @see org.apache.uima.UimaContext#mapToSofaID(java.lang.String)
    */
+  @Override
   public SofaID mapToSofaID(String aSofaName) {
 
     int index = aSofaName.indexOf(".");
@@ -630,6 +671,7 @@
    * 
    * @see org.apache.uima.UimaContext#mapSofaIDToComponentSofaName(java.lang.String)
    */
+  @Override
   public String mapSofaIDToComponentSofaName(String aSofaID) {
     String componentSofaName = aSofaID;
     SofaID[] sofaArr = getSofaMappings();
@@ -645,6 +687,7 @@
    * 
    * @see org.apache.uima.UimaContext#getSofaMappings()
    */
+  @Override
   public SofaID[] getSofaMappings() {
     Set<Map.Entry<String, String>> sofamap = mSofaMappings.entrySet();
     Iterator<Map.Entry<String, String>> iter = sofamap.iterator();
@@ -664,10 +707,12 @@
   /* (non-Javadoc)
    * @see org.apache.uima.UimaContextAdmin#getSofaMap()
    */
+  @Override
   public Map<String, String> getSofaMap() {
     return Collections.unmodifiableMap(mSofaMappings);
   }
 
+  @Override
   public void defineCasPool(int aSize, Properties aPerformanceTuningSettings, boolean aSofaAware)
           throws ResourceInitializationException {
     mCasPoolSize = aSize;
@@ -680,6 +725,7 @@
   /**
    * @see UimaContextAdmin#returnedCAS(AbstractCas)
    */
+  @Override
   public void returnedCAS(AbstractCas aCAS) {
     //remove Base CAS from outstanding CASes set
     CAS baseCas = null;
@@ -757,6 +803,7 @@
   /**
    * @return the component info
    */
+  @Override
   public ComponentInfo getComponentInfo() {
     return mComponentInfo;
   }
@@ -766,9 +813,19 @@
    * 
    * @see org.apache.uima.UimaContextAdmin#getManagementInterface()
    */
+  @Override
   public AnalysisEngineManagement getManagementInterface() {
     return mMBean;
   }
+  
+  protected Logger maybeThrottleLogger(Logger logger) {
+    final int limit = ((UimaContext_ImplBase)getRootContext()).loggingThrottleLimit; 
+    if (limit == Integer.MAX_VALUE ||
+        !logger.isAnnotatorLogger()) {
+      return logger;
+    }
+    return logger.getLimitedLogger(limit);
+  }
 
   /**
    * Implementation of the ComponentInfo interface that allows the CAS to access information from
@@ -784,6 +841,7 @@
      * @see org.apache.uima.cas.ComponentInfo#mapToSofaID(java.lang.String)
      * 
      */
+    @Override
     public String mapToSofaID(String aSofaName) {
       int index = aSofaName.indexOf(".");
       String nameToMap = aSofaName;
@@ -804,4 +862,12 @@
     }
 
   }
+  
+  public void setLoggingThrottleLimit(Integer v) {
+    loggingThrottleLimit = v;
+  }
+
+  public String getMdcId() {
+    return mdcUniqueId;
+  }
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/impl/Util.java b/uimaj-core/src/main/java/org/apache/uima/impl/Util.java
index 0814f9d..9f5b753 100644
--- a/uimaj-core/src/main/java/org/apache/uima/impl/Util.java
+++ b/uimaj-core/src/main/java/org/apache/uima/impl/Util.java
@@ -18,10 +18,13 @@
  */
 package org.apache.uima.impl;
 
+import org.apache.uima.UimaContext;
+import org.apache.uima.UimaContextHolder;
 import org.apache.uima.cas.AbstractCas;
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.ComponentInfo;
 import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.internal.util.function.Runnable_withException;
 import org.apache.uima.resource.ResourceManager;
 import org.apache.uima.resource.impl.CasManager_impl;
 
@@ -89,5 +92,46 @@
     return r;
   }
   
+  /**
+   * Calls userCode and then restores the context holder
+   * @param userCode run this code within the current context
+   */
+  public static void preserveContextHolder(Runnable userCode) {
+    UimaContext prevContext = UimaContextHolder.getContext();
+    try {
+      userCode.run();
+    } finally {
+      UimaContextHolder.setContext(prevContext);
+    }
+  }
+
+  /**
+   * Calls userCode with specified context, then restores the context holder
+   * @param context to use while running the userCode
+   * @param userCode the code to run.
+   */
+  public static void withContextHolder(UimaContext context, Runnable userCode) {
+    UimaContext prevContext = UimaContextHolder.setContext(context);
+    try {
+      userCode.run();
+    } finally {
+      UimaContextHolder.setContext(prevContext);
+    }
+  }
+  
+  /**
+   * Calls userCode with specified context, then restores the context holder
+   * @param context to use while running the userCode
+   * @param userCode the code to run.
+   * @throws Exception -
+   */
+  public static void withContextHolderX(UimaContext context, Runnable_withException userCode) throws Exception {
+    UimaContext prevContext = UimaContextHolder.setContext(context);
+    try {
+      userCode.run();
+    } finally {
+      UimaContextHolder.setContext(prevContext);
+    }
+  }  
 
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/Common_hash_support.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/Common_hash_support.java
new file mode 100644
index 0000000..38ddd75
--- /dev/null
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/Common_hash_support.java
@@ -0,0 +1,535 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+package org.apache.uima.internal.util;

+

+import java.util.Arrays;

+import java.util.function.IntConsumer;

+import java.util.function.IntPredicate;

+import java.util.function.IntSupplier;

+

+/**

+ * A common superclass for hash maps and hash sets

+ *

+ */

+public abstract class Common_hash_support {

+

+  // set to true to collect statistics for tuning

+  // you have to also put a call to showHistogram() at the end of the run

+  protected static final boolean TUNE = false;

+  

+  protected static final int MIN_SIZE = 10;   // 10 / .66 =15.15

+  protected static final int MIN_CAPACITY = 16;

+  protected static final int MIN_CAPACITY_SHRINK = 64;  // don't shrink below this - thrashing

+  

+  protected final float loadFactor;  

+  

+  protected final int initialCapacity; 

+

+  protected int histogram [];

+  protected int maxProbe = 0;

+

+  protected int sizeWhichTriggersExpansion;

+  private int size = 0; // number of elements in the table  

+

+  protected int removed = 0;  // for rebalancing  

+

+  /** set to the first found_removed when searching */

+  protected int found_removed;

+

+  protected boolean secondTimeShrinkable = false;

+

+  /**

+   * @param initialSizeBeforeExpanding the number of elements the table should hold before expanding

+   */

+  public Common_hash_support(int initialSizeBeforeExpanding) {

+    this(initialSizeBeforeExpanding, 0.66F);

+  }

+    

+  public Common_hash_support(int initialSizeBeforeExpanding, float factor) {

+    this.loadFactor = factor;

+    this.initialCapacity = tableSpace(initialSizeBeforeExpanding, factor);

+    if (TUNE) {

+      histogram = new int[200];

+      Arrays.fill(histogram, 0);

+      maxProbe = 0;

+    }

+  }

+

+  public Common_hash_support(Common_hash_support orig) {

+    this(orig.initialCapacity);

+    this.sizeWhichTriggersExpansion = orig.sizeWhichTriggersExpansion;

+    this.size = orig.size;

+    this.removed = orig.removed; 

+    this.secondTimeShrinkable = orig.secondTimeShrinkable;

+

+    // copy doesn't do tuning measurements

+    this.histogram = null;

+  }

+  

+  public void clear() {

+    // see if size is less than the 1/2 size that triggers expansion

+    if (size + removed <  (sizeWhichTriggersExpansion >>> 1)) {

+      // if 2nd time then shrink by 50%

+      //   this is done to avoid thrashing around the threshold

+      if (secondTimeShrinkable) {

+        secondTimeShrinkable = false;

+        final int newCapacity = Math.max(initialCapacity, keys_length() >>> 1);

+        if (newCapacity < keys_length()) { 

+          newTable(newCapacity);  // shrink table by 50%

+          size = 0;

+          removed = 0;

+          resetHistogram();

+          if (PositiveIntSet.IS_TRACE_MODE_SWITCH) {

+            System.out.println("TRAcE_MODE Common_hash clear 2nd time shrinkable, newCapacity=" + newCapacity + ", keys_length: " + keys_length());

+          }

+          return;

+        } else { // don't shrink below minimum

+          clearExisting();

+          if (PositiveIntSet.IS_TRACE_MODE_SWITCH) {

+            System.out.println("TRAcE_MODE Common_hash clear 2nd time shrinkable but nothing done, below minimum: newCapacity=" + newCapacity + ", keys_length: " + keys_length());

+          }

+          return;

+        }

+      } else {

+        if (PositiveIntSet.IS_TRACE_MODE_SWITCH) System.out.println("TRACE_MODE Common_hash clear setting 2nd time shrinkable");

+        secondTimeShrinkable = true;

+      }

+    } else {

+      secondTimeShrinkable = false; // reset this to require 2 triggers in a row

+    }

+    clearExisting();

+  }

+  

+  private void clearExisting() {

+    clearKeysAndValues();

+    size = 0;

+    removed = 0;

+    resetHistogram();    

+  }

+  

+  /** It gets a ref to the current value of table, and then searches that array.

+   * Side effect: found_removed is set to the position of the first REMOVED_KEY (if any) encountered

+   * during the search.

+   * 

+   * @param hash     the hash code of the key

+   * @param is_eq_or_not_present   true if the key at the int position is == to the key, or is 0

+   * @param is_removed_key true if the key at the int position is "removed"

+   * @return the probeAddr in keys array.  The value is the not-present-value if not found

+   */

+  protected int findPosition(

+                   int hash,

+                   IntPredicate is_eq_or_not_present,

+                   IntPredicate is_removed_key) {

+    

+    found_removed = -1;  

+//    final int hash = key_hash.getAsInt();

+

+//    final int[] localKeys = keys;

+    final int bitMask = keys_length() - 1;

+    

+    int nbrProbes = 1;

+    int probeDelta = 0;

+    int probeAddr = hash & bitMask;

+    

+    for (;;) {

+

+      if (is_eq_or_not_present.test(probeAddr)) {

+        if (TUNE) {

+          updateHistogram(nbrProbes);

+        }

+        return probeAddr;

+      }

+

+      if (found_removed == -1 && is_removed_key.test(probeAddr)) {

+        found_removed = probeAddr;

+      }

+

+      if (TUNE) nbrProbes++;

+      

+      if (probeDelta < 13) {

+        probeDelta ++; // stop at a prime

+                       // which guarantees all slots eventually traversed.

+      }

+      probeAddr = bitMask & (probeAddr + probeDelta);

+    }

+    

+//    

+//    // fast paths

+//    if (is_eq_or_not_present.test(probeAddr)) {

+////    final int testKey = localKeys[probeAddr];

+////    if (testKey == 0 || testKey == key) {

+//      if (TUNE) {

+//        updateHistogram(1);

+//      }

+//      return probeAddr;

+//    }

+//    if (is_removed_key.test(probeAddr)) {

+////        testKey == REMOVED_KEY) {

+//      found_removed = probeAddr;

+//    }

+//    return findPosition2(is_eq_or_not_present, is_removed_key, probeAddr);

+  } 

+ 

+//  private int findPosition2(IntPredicate is_eq_or_not_present,

+//                    IntPredicate is_removed_key, 

+//                    int probeAddr) {

+//    final int bitMask = keys_length() - 1;

+//    int nbrProbes = 2;

+//    int probeDelta = 1;

+//    probeAddr = bitMask & (probeAddr + (probeDelta++));

+//

+//    while (true) {

+//      if (is_eq_or_not_present.test(probeAddr)) {

+////      final int testKey = localKeys[probeAddr];

+////      if (testKey == 0 || testKey == key) {

+//        break;

+//      }

+//      

+//      if (found_removed == -1 && is_removed_key.test(probeAddr)) {

+//        found_removed = probeAddr;

+//      }

+//      nbrProbes++;

+//      if (probeDelta < 13) {

+//        probeDelta ++; // stop at a prime

+//                       // which guarantees all slots eventually traversed.

+//      }

+//      probeAddr = bitMask & (probeAddr + (probeDelta++));

+//    }

+//

+//    if (TUNE) {

+//      final int pv = histogram[nbrProbes];

+//

+//      histogram[nbrProbes] = 1 + pv;

+//      if (maxProbe < nbrProbes) {

+//        maxProbe = nbrProbes;

+//      }

+//    }

+//    return probeAddr;

+//  }

+   

+  /**

+   * As REMOVED tokens populate,

+   * the number of 0's (representing free cells and

+   *   also the end of bucket chain searches) drops.

+   *   

+   *   If this drops a lot, then searches take much longer.

+   *   If there are no 0's left, searches never terminate!

+   *   

+   * Keep the number of 0's at about 1 - load factor 

+   * 

+   */

+  private void maybeRebalanceRemoves() {

+    final int old_capacity = keys_length();

+    if (old_capacity <= MIN_CAPACITY_SHRINK) {

+      return;  

+    }

+    int new_capacity = old_capacity >> 1;

+            

+//    //debug

+//      int sz = size;

+      

+    /******************************************************

+     * Logic for clearing out the removed markers in bulk

+     * 

+     * 3 cases:  resize up (never happens), down, or the same

+     * 

+     * Don't clear out if there's room left unless

+     *   there's too much room left and should downsize

+     * 

+     * Don't over do - avoid thrashing, avoid work for small sizes

+     * 

+     * Case for upsizing: none.  It's guaranteed there are always enough

+     *   0's for the load factor, by put/add implementation.  

+     *  

+     * Case for downsizing: if the size < 1/3 of the new capacity or,

+     *   number being removed would be > 1/3 of the new capacity  

+     ******************************************************/

+      

+    if (removed + size >= sizeWhichTriggersExpansion) {

+      Misc.internalError();  // put or add always keeps this false. remove always reduces or keeps this value the same

+    }

+    

+    // REMOVED tags if there are enough of them to make it worthwhile

+    // or if just should shrink because removed + size is smaller than 1/3 the new capacity

+    int one_third_new_capacity = sizeWhichTriggersExpansion >> 2;

+    int one_half_new_capacity = new_capacity >> 1;

+    if (removed > one_half_new_capacity || (size < one_third_new_capacity)) {

+      if (size >= one_third_new_capacity) {

+        new_capacity = old_capacity;

+      }

+      if (TUNE) {

+        System.out.println("Capacity (maybe) decreasing from " + old_capacity + " to " + new_capacity + " removed= " + removed + " size= " + size);

+      }      

+      copyOld2New(new_capacity, old_capacity);

+    }

+//    //debug

+//    if (sz != size) 

+//      System.out.println("debug");

+  }

+  

+  /**

+   * This method calls the subclass's copy_to_new_table method, 

+   *   passing an inner lambda containing common code for copying old to new.

+   *   

+   *   That inner lambda, when invoked by the copy_to_new_table method, 

+   *     is passed another lambda of one argument (the old index) 

+   *     which is called to copy each element.  

+   * @param new_capacity

+   * @param old_capacity

+   */

+  private void copyOld2New(int new_capacity, int old_capacity) {

+    copy_to_new_table( 

+      new_capacity,

+      old_capacity,

+      

+        // this code assigned to "commonCopy" arg

+        (IntConsumer copyToNew, IntPredicate is_valid_old_key) -> {  

+      newTable(new_capacity);

+      removed = 0; // reset before put, otherwise, causes premature expansion

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

+        if (is_valid_old_key.test(i)) {

+          copyToNew.accept(i);

+        }

+      }

+    });    

+  }

+

+  /**

+   * advance pos until it points to a non 0 or is 1 past end

+   * If pos is negative, start at 0.

+   * Don't move if pos already has valid key

+   * @param pos -

+   * @return updated pos

+   */

+  protected int moveToNextFilled(int pos) {

+    final int max = keys_length();

+    if (pos < 0) {

+      pos = 0;

+    }

+    while (true) {

+      if (pos >= max) {

+        return pos;

+      }

+      if (is_valid_key(pos)) {

+        return pos;

+      }

+      pos ++;

+    }

+  }

+

+  /**

+   * decrement pos until it points to a non 0 or is -1

+   * If pos is beyond end start at end.

+   * Don't move if pos already has valid key

+   * @param pos -

+   * @return updated pos

+   */

+  protected int moveToPreviousFilled(int pos) {

+    final int max = keys_length();

+    if (pos > max) {

+      pos = max - 1;

+    }

+    

+    while (true) {

+      if (pos < 0) {

+        return pos;

+      }

+      if (is_valid_key(pos)) {

+        return pos;

+      }

+      pos --;

+    }

+  }

+  

+  // called by clear, increase table size, decrease table size

+  protected void newTable(int capacity) {

+    capacity = Math.max(MIN_SIZE, Misc.nextHigherPowerOf2(capacity));

+    newKeysAndValues(capacity);

+    sizeWhichTriggersExpansion = (int)(capacity * loadFactor);

+  }

+  

+  protected void incrementSize() {

+    size++;

+    if (size + removed >= sizeWhichTriggersExpansion) {

+      maybeIncreaseTableCapacity();

+    }

+  }

+

+  private void maybeIncreaseTableCapacity() {

+    int old_capacity = keys_length();

+    int new_capacity = (removed >= size) 

+                         ? old_capacity 

+                         : 2 * old_capacity;

+    

+    if (TUNE) {

+      System.out.println("Capacity (maybe) increasing from " + old_capacity + " to " + new_capacity + ", removes= " + removed + " size=" + size);

+    }

+    

+    copyOld2New(new_capacity, old_capacity);

+  }

+  

+  protected void commonPutOrAddNotFound() {

+    

+    if (found_removed != -1) {

+      removed --; // used up a removed slot

+    }

+    incrementSize();

+//    debugValidate();

+  }

+  

+  /**

+   * only called if actually found and removed an entry

+   */

+  protected void commonRemove() {

+    removed ++;

+    size --;

+    maybeRebalanceRemoves();

+//    debugValidate();

+  }

+  

+  public int size() {

+    return size;

+  }

+

+  @FunctionalInterface

+  public interface CommonCopyOld2New {

+    void apply(IntConsumer copyToNew, IntPredicate is_valid_old_key);

+  }

+  protected abstract boolean is_valid_key(int pos);

+  protected abstract int keys_length();

+  protected abstract void newKeysAndValues(int capacity);

+  protected abstract void clearKeysAndValues();

+  protected abstract void copy_to_new_table(int new_capacity, int old_capacity, CommonCopyOld2New r);

+  

+  protected void resetHistogram() {

+    if (TUNE) {

+      histogram = new int[200];

+      Arrays.fill(histogram, 0);

+      maxProbe = 0;

+    }    

+  }

+

+  private void updateHistogram(int nbrProbes) {

+    histogram[nbrProbes] = 1 + histogram[nbrProbes];

+    if (maxProbe < nbrProbes) {

+      maxProbe = nbrProbes;

+    }

+  }

+

+  public void showHistogram() {

+    if (TUNE) {

+      int sumI = 0;

+      for (int i : histogram) {

+        sumI += i;

+      }

+      

+      System.out.format(

+          "Histogram of number of probes, loadfactor = %.1f, maxProbe=%,d nbr of find operations at last table size=%,d%n",

+          loadFactor, maxProbe, sumI);

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

+        if (i == maxProbe && histogram[i] == 0) {

+          System.out.println("huh?");

+        }

+        System.out.println(i + ": " + histogram[i]);

+      }     

+      

+      System.out.println("bytes / entry = " + (float) (keys_length()) * 8 / size());

+      System.out.format("size = %,d, prevExpansionTriggerSize = %,d, next = %,d%n",

+          size(),

+          (int) ((keys_length() >>> 1) * loadFactor),

+          (int) (keys_length() * loadFactor));

+    }

+  }

+

+  // test case use

+  int getCapacity() {

+    return keys_length();

+  }

+  

+  protected abstract class CommonKeyIterator implements IntListIterator {

+

+    protected int curPosition;

+    

+    protected final int firstPosition;

+    

+    protected CommonKeyIterator() {

+        this.curPosition = moveToNextFilled(0);

+        firstPosition = curPosition;

+    }

+    

+    @Override

+    public boolean hasNext() {

+      return curPosition < keys_length() && curPosition >= 0;

+    }

+

+    @Override

+    public boolean hasPrevious() {

+      if (curPosition > keys_length() || curPosition <= 0) {

+        return false;

+      }

+      

+      int test = moveToPreviousFilled(curPosition - 1);

+      return test >= 0;

+    }

+

+    @Override

+    /**

+     * @see org.apache.uima.internal.util.IntListIterator#moveToStart()

+     */

+    public void moveToStart() {

+      curPosition = moveToNextFilled(0);

+    }

+

+    @Override

+    /**

+     * @see org.apache.uima.internal.util.IntListIterator#moveToEnd()

+     */

+    public void moveToEnd() {

+      curPosition = moveToPreviousFilled(keys_length() - 1);

+    }

+    

+  }

+  

+  /**

+   * 

+   * @param numberOfElements -

+   * @param factor -

+   * @return capacity of the main table (either 2 byte or 4 byte entries)

+   */

+  public static int tableSpace(int numberOfElements, Float factor) {

+    if (numberOfElements < 0) {

+      throw new IllegalArgumentException("must be > 0");

+    }

+    final int capacity = Math.round(numberOfElements / factor);

+    return  Math.max(16, Misc.nextHigherPowerOf2(capacity));

+  }

+

+  protected void debugValidate() {

+    // count non-0, non-removed, compare to size

+    int sum = 0;

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

+      if (is_valid_key(i)) {

+        sum ++;

+        if (sum > size) {

+          System.out.println("debug");

+        }

+      }

+    }

+  }

+}

diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/CopyOnWriteObjHashSet.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/CopyOnWriteObjHashSet.java
index 11e2d88..85f7477 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/CopyOnWriteObjHashSet.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/CopyOnWriteObjHashSet.java
@@ -24,6 +24,7 @@
 import org.apache.uima.cas.FeatureStructure;

 import org.apache.uima.cas.impl.CopyOnWriteIndexPart;

 import org.apache.uima.internal.util.ObjHashSet;

+import org.apache.uima.jcas.cas.TOP;

 

 /**

  * implements ObjHashSet partially, for iterator use

@@ -33,9 +34,15 @@
   

   private ObjHashSet<T> ohs;

   

+  private ObjHashSet<T> original;

+  

+  private final int original_size;

+  

   

   public CopyOnWriteObjHashSet(ObjHashSet<T> original) {

     this.ohs = original;    

+    this.original = original;

+    this.original_size = original.size();

   }

 

   /**

@@ -58,12 +65,7 @@
   public int find(T obj) {

     return ohs.find(obj);

   }

-  

-//  @Override

-//  public int size() {

-//    

-//  }

-  

+    

   /**

    * For iterator use

    * @param index a magic number returned by the internal find

@@ -148,13 +150,13 @@
     return ohs.toString();

   }

 

-  /**

-   * @see ObjHashSet#getModificationCount()

-   * @return the modification count

-   */

-  public int getModificationCount() {

-    return ohs.getModificationCount();

-  }

+//  /**

+//   * @see ObjHashSet#getModificationCount()

+//   * @return the modification count

+//   */

+//  public int getModificationCount() {

+//    return ohs.getModificationCount();

+//  }

 

   /**

    * @see ObjHashSet#getCapacity()

@@ -168,8 +170,30 @@
    * @see ObjHashSet#size()

    * @return the size

    */

-  public int size() {

-    return ohs.size();

+  final public int size() {

+    return original_size;

   }

 

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.CopyOnWriteIndexPart#isOriginal(java.lang.Object)

+   */

+  @Override

+  public boolean isOriginal() {

+    return ohs == original;

+  }

+

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.CopyOnWriteIndexPart#copyToArray(org.apache.uima.jcas.cas.TOP[], int)

+   */

+  @Override

+  public int copyToArray(TOP[] target, int startingIndexInTarget) {

+    Iterator<T> it = iterator();

+    int i = startingIndexInTarget;

+    while (it.hasNext()) {

+      target[i++] = (TOP) it.next();

+    }

+    return i;

+  }

+

+  

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/CopyOnWriteOrderedFsSet_array.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/CopyOnWriteOrderedFsSet_array.java
index 9437c94..a38bb15 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/CopyOnWriteOrderedFsSet_array.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/CopyOnWriteOrderedFsSet_array.java
@@ -18,57 +18,56 @@
  */

 package org.apache.uima.internal.util;

 

-import java.util.Collection;

-import java.util.Collections;

-import java.util.Comparator;

 import java.util.Iterator;

-import java.util.NavigableSet;

 import java.util.NoSuchElementException;

-import java.util.SortedSet;

-import java.util.Spliterator;

-import java.util.function.Consumer;

-import java.util.function.Predicate;

-import java.util.function.Supplier;

-import java.util.stream.Stream;

 

 import org.apache.uima.cas.impl.CopyOnWriteIndexPart;

-import org.apache.uima.internal.util.OrderedFsSet_array.SubSet;

 import org.apache.uima.jcas.cas.TOP;

 

 /**

  * implements OrderedFsSet_array partially, for iterator use

  */

 

-public class CopyOnWriteOrderedFsSet_array implements NavigableSet<TOP>, CopyOnWriteIndexPart {

+public class CopyOnWriteOrderedFsSet_array implements CopyOnWriteIndexPart {

   

-  private OrderedFsSet_array set;

+  private OrderedFsSet_array<TOP> set;

+    

+  final public int a_firstUsedslot;

+  final public int a_nextFreeslot;

+  final public OrderedFsSet_array<TOP> original;

+  final private int original_size;

   

-  final public Comparator<TOP> comparatorWithoutID;

-  

-  final Supplier<OrderedFsSet_array> sosa = () -> set;

-  

+  public TOP[] a;  // derived from "set" above

+   

   public CopyOnWriteOrderedFsSet_array(OrderedFsSet_array original) {

     this.set = original;    

-    this.comparatorWithoutID = original.comparatorWithoutID;

+    this.original = original;

+//    this.comparatorNoTypeWithoutID = original.comparatorNoTypeWithoutID;

+//    this.comparatorNoTypeWithID = original.comparatorNoTypeWithID;

+    this.a_firstUsedslot = original.a_firstUsedslot;

+    this.a_nextFreeslot = original.a_nextFreeslot;

+    this.a = original.a;

+    this.original_size = original.size();

   }

-

+  

   /**

    * Called by index when about to make an update

    * This copy captures the state of things before the update happens

    */

   @Override

   public void makeReadOnlyCopy() {

-    set = new OrderedFsSet_array(set, true); // true = make read only copy

+    this.set = new OrderedFsSet_array<TOP>(set, true); // true = make read only copy

+    this.a = set.a;

   }

 

-  /**

-   * @see java.lang.Iterable#forEach(java.util.function.Consumer)

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.CopyOnWriteIndexPart#isOriginal(java.lang.Object)

    */

   @Override

-  public void forEach(Consumer<? super TOP> action) {

-    set.forEach(action);

+  public boolean isOriginal() {

+    return set == original;

   }

-

+  

   /**

    * @see java.lang.Object#hashCode()

    */

@@ -82,413 +81,26 @@
    */

   @Override

   public boolean equals(Object obj) {

-    return set.equals(obj);

-  }

-

-  /**

-   * @see OrderedFsSet_array#comparator()

-   */

-  @Override

-  public Comparator<? super TOP> comparator() {

-    return set.comparator();

-  }

-

-  /**

-   * @see OrderedFsSet_array#first()

-   */

-  @Override

-  public TOP first() {

-    return set.first();

-  }

-

-  /**

-   * @see OrderedFsSet_array#last()

-   */

-  @Override

-  public TOP last() {

-    return set.last();

+    if (obj instanceof CopyOnWriteOrderedFsSet_array) {

+      return set.equals(((CopyOnWriteOrderedFsSet_array)obj).set);  // set object equals

+    }

+    return false;

   }

 

   /**

    * @see OrderedFsSet_array#size()

+   * @return the size of this version of the index (maybe not the current index size)

    */

-  @Override

-  public int size() {

-    return set.size();

+  final public int size() {

+    return original_size;

   }

 

-  /**

-   * @see OrderedFsSet_array#isEmpty()

-   */

-  @Override

-  public boolean isEmpty() {

-    return set.isEmpty();

-  }

-

-  /**

-   * @see OrderedFsSet_array#contains(java.lang.Object)

-   */

-  @Override

-  public boolean contains(Object o) {

-    return set.contains(o);

-  }

-

-  /**

-   * @see OrderedFsSet_array#toArray()

-   */

-  @Override

-  public Object[] toArray() {

-    return set.toArray();

-  }

-

-  /**

-   * @see OrderedFsSet_array#toArray(java.lang.Object[])

-   */

-  @Override

-  public <T> T[] toArray(T[] a1) {

-    return set.toArray(a1);

-  }

-

-  /**

-   * @see OrderedFsSet_array#add(TOP)

-   */

-  @Override

-  public boolean add(TOP fs) {

-    return set.add(fs);

-  }

-

-  /**

-   * @see java.util.SortedSet#spliterator()

-   */

-  @Override

-  public Spliterator<TOP> spliterator() {

-    return set.spliterator();

-  }

-

-  /**

-   * @see java.util.Collection#removeIf(java.util.function.Predicate)

-   */

-  @Override

-  public boolean removeIf(Predicate<? super TOP> filter) {

-    return set.removeIf(filter);

-  }

-

-  /**

-   * @see java.util.Collection#stream()

-   */

-  @Override

-  public Stream<TOP> stream() {

-    return set.stream();

-  }

-

-  /**

-   * @see java.util.Collection#parallelStream()

-   */

-  @Override

-  public Stream<TOP> parallelStream() {

-    return set.parallelStream();

-  }

-

-  /**

-   * @see OrderedFsSet_array#remove(java.lang.Object)

-   */

-  @Override

-  public boolean remove(Object o) {

-    return set.remove(o);

-  }

-

-  /**

-   * @see OrderedFsSet_array#containsAll(java.util.Collection)

-   */

-  @Override

-  public boolean containsAll(Collection<?> c) {

-    return set.containsAll(c);

-  }

-

-  /**

-   * @see OrderedFsSet_array#addAll(java.util.Collection)

-   */

-  @Override

-  public boolean addAll(Collection<? extends TOP> c) {

-    return set.addAll(c);

-  }

-

-  /**

-   * @see OrderedFsSet_array#retainAll(java.util.Collection)

-   */

-  @Override

-  public boolean retainAll(Collection<?> c) {

-    return set.retainAll(c);

-  }

-

-  /**

-   * @see OrderedFsSet_array#removeAll(java.util.Collection)

-   */

-  @Override

-  public boolean removeAll(Collection<?> c) {

-    return set.removeAll(c);

-  }

-

-  /**

-   * 

-   * @see OrderedFsSet_array#clear()

-   */

-  @Override

-  public void clear() {

-    set.clear();

-  }

-

-  /**

-   * @see OrderedFsSet_array#lower(TOP)

-   */

-  @Override

-  public TOP lower(TOP fs) {

-    return set.lower(fs);

-  }

-

-  /**

-   * @see OrderedFsSet_array#lowerPos(TOP)

-   * @param fs the Feature Structure to use for positioning

-   * @return -

-   */

-  public int lowerPos(TOP fs) {

-    return set.lowerPos(fs);

-  }

-

-  /**

-   * @see OrderedFsSet_array#floor(TOP)

-   */

-  @Override

-  public TOP floor(TOP fs) {

-    return set.floor(fs);

-  }

-

-  /**

-   * @see OrderedFsSet_array#floorPos(TOP)

-   * @param fs the Feature Structure to use for positioning

-   * @return -

-   */

-  public int floorPos(TOP fs) {

-    return set.floorPos(fs);

-  }

-

-  /**

-   * @see OrderedFsSet_array#ceiling(TOP)

-   */

-  @Override

-  public TOP ceiling(TOP fs) {

-    return set.ceiling(fs);

-  }

-

-  /**

-   * @see OrderedFsSet_array#ceilingPos(TOP)

-   * @param fs the Feature Structure to use for positioning

-   * @return -

-   */

-  public int ceilingPos(TOP fs) {

-    return set.ceilingPos(fs);

-  }

-

-  /**

-   * @see OrderedFsSet_array#higher(TOP)

-   */

-  @Override

-  public TOP higher(TOP fs) {

-    return set.higher(fs);

-  }

-

-  /**

-   * @see OrderedFsSet_array#higherPos(TOP)  

-   * @param fs the Feature Structure to use for positioning

-   * @return -

-   */

-  public int higherPos(TOP fs) {

-    return set.higherPos(fs);

-  }

-

-  /**

-   * @see OrderedFsSet_array#pollFirst()

-   */

-  @Override

-  public TOP pollFirst() {

-    return set.pollFirst();

-  }

-

-  /**

-   * @see OrderedFsSet_array#pollLast()

-   */

-  @Override

-  public TOP pollLast() {

-    return set.pollLast();

-  }

-

-  /**

-   * @see OrderedFsSet_array#iterator()

-   */

-//  @Override

-//  public Iterator<TOP> iterator() {

-//    return set.iterator();

+//  /**

+//   * @return the modification count

+//   */

+//  public int getModificationCount() {

+//    return set.getModificationCount();

 //  }

-  /**

-   * @see Iterable#iterator()

-   */

-  @Override

-  public Iterator<TOP> iterator() {

-    if (set.isEmpty()) {

-      return Collections.emptyIterator();

-    }

-    

-    return new Iterator<TOP>() {

-      private int pos = set.a_firstUsedslot;

-      { incrToNext(); }  // non-static initializer code

-      

-      @Override

-      public boolean hasNext() {

-        set.processBatch();

-        return pos < set.a_nextFreeslot;

-      }

-      

-      @Override

-      public TOP next() {

-        if (!hasNext()) {

-          throw new NoSuchElementException();

-        }

-

-        TOP r = set.a[pos++];

-        incrToNext();

-        return r;        

-      }

-      

-      private void incrToNext() {

-        while (pos < set.a_nextFreeslot) {

-          if (set.a[pos] != null) {

-            break;

-          }

-          pos ++;

-        }

-      }

-

-    };

-  }

-  

-  /**

-   * @see OrderedFsSet_array#descendingSet()

-   */

-  @Override

-  public NavigableSet<TOP> descendingSet() {

-    throw new UnsupportedOperationException(); // unused

-  }

-

-  /**

-   * @see OrderedFsSet_array#descendingIterator()

-   */

-//  @Override

-//  public Iterator<TOP> descendingIterator() {

-//    return set.descendingIterator();

-//  }

-  /**

-   * @see NavigableSet#descendingIterator()

-   */

-  @Override

-  public Iterator<TOP> descendingIterator() {

-    set.processBatch();

-    return new Iterator<TOP>() {

-      private int pos = set.a_nextFreeslot - 1;    // 2 slots:  next free = 2, first slot = 0

-                                               // 1 slot:   next free = 1, first slot = 0

-                                               // 0 slots:  next free = 0; first slot = 0 (not -1)

-      { if (pos >= 0) {  // pos is -1 if set is empty

-        decrToNext(); 

-        }

-      }

-       

-      @Override

-      public boolean hasNext() {

-        return pos >= set.a_firstUsedslot;

-      }

-      

-      @Override

-      public TOP next() {

-        if (!hasNext()) {

-          throw new NoSuchElementException();

-        }

-

-        TOP r = set.a[pos--];

-        decrToNext();

-        return r;        

-      }

-      

-      private void decrToNext() {

-        while (pos >= set.a_firstUsedslot) {

-          if (set.a[pos] != null) {

-            break;

-          }

-          pos --;

-        }

-      }

-    };

-  }

-

-  /**

-   * @see OrderedFsSet_array#subSet(TOP, boolean, TOP, boolean)

-   */

-  @Override

-  public NavigableSet<TOP> subSet(TOP fromElement, boolean fromInclusive, TOP toElement,

-      boolean toInclusive) {

-    return new SubSet(sosa, fromElement, fromInclusive, toElement, toInclusive, false, null); 

-  }

-

-  /**

-   * @see OrderedFsSet_array#headSet(TOP, boolean)

-   */

-  @Override

-  public NavigableSet<TOP> headSet(TOP toElement, boolean inclusive) {

-    if (isEmpty()) {

-      return this; 

-    }

-    return new SubSet(sosa, first(), true, toElement, inclusive, false, null);

-  }

-

-  /**

-   * @see OrderedFsSet_array#tailSet(TOP, boolean)

-   */

-  @Override

-  public NavigableSet<TOP> tailSet(TOP fromElement, boolean inclusive) {

-    if (isEmpty()) {

-      return this;

-    }

-    return new SubSet(sosa, fromElement, inclusive, last(), true, false, null);

-  }

-

-  /**

-   * @see OrderedFsSet_array#subSet(TOP, TOP)

-   */

-  @Override

-  public SortedSet<TOP> subSet(TOP fromElement, TOP toElement) {

-    return new SubSet(sosa, fromElement, true, toElement, false, false, null);

-  }

-

-  /**

-   * @see OrderedFsSet_array#headSet(TOP)

-   */

-  @Override

-  public SortedSet<TOP> headSet(TOP toElement) {

-    return headSet(toElement, false);

-  }

-

-  /**

-   * @see OrderedFsSet_array#tailSet(TOP)

-   */

-  @Override

-  public SortedSet<TOP> tailSet(TOP fromElement) {

-    return tailSet(fromElement, true);

-  }

-

-  /**

-   * @return the modification count

-   */

-  public int getModificationCount() {

-    return set.getModificationCount();

-  }

 

   /**

    * @see OrderedFsSet_array#toString()

@@ -497,6 +109,42 @@
   public String toString() {

     return set.toString();

   }

+    

+  public OrderedFsSet_array<TOP> getOfsa() {

+    return set;

+  }

+  

+  /* (non-Javadoc)

+   * @see java.lang.Iterable#iterator()

+   */

+  @Override

+  public Iterator<TOP> iterator() {

+    return new Iterator<TOP>() {

 

+      int pos = a_firstUsedslot;

+      

+      @Override

+      public boolean hasNext() {

+        return pos >= 0 && pos < a_nextFreeslot;

+      }

+

+      @Override

+      public TOP next() {

+        if (!hasNext()) {

+          throw new NoSuchElementException();

+        }

+        return a[pos++];

+      }      

+    };

+  }

+

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.CopyOnWriteIndexPart#copyToArray(org.apache.uima.jcas.cas.TOP[], int)

+   */

+  @Override

+  public int copyToArray(TOP[] target, int startingIndexInTarget) {

+    System.arraycopy(a, a_firstUsedslot, target, startingIndexInTarget, size());

+    return startingIndexInTarget + size();

+  }

 

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/I18nUtil.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/I18nUtil.java
index 031c224..867267b 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/I18nUtil.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/I18nUtil.java
@@ -20,7 +20,11 @@
 package org.apache.uima.internal.util;
 
 import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
 import java.util.Locale;
+import java.util.Map;
 import java.util.ResourceBundle;
 
 /**
@@ -28,6 +32,74 @@
  * 
  */
 public class I18nUtil {
+  
+  /**
+   * Cache for bundle lookup
+   *   otherwise, there are multiple lookups in a call-stack-climbing class loader
+   *   
+   */
+  
+  static class Bid {
+    final String bundleName;
+    final Locale locale;
+    final ClassLoader loader;
+    final ClassLoader [] loaders;
+    public Bid(String bundleName, Locale locale, ClassLoader loader, ClassLoader[] loaders) {
+      super();
+      this.bundleName = bundleName;
+      this.locale = locale;
+      this.loader = (loaders != null) ? null : loader;
+      this.loaders = loaders;
+    }
+    
+    @Override
+    public int hashCode() {
+      final int prime = 31;
+      int result = 1;
+      result = prime * result + ((bundleName == null) ? 0 : bundleName.hashCode());
+      result = prime * result + ((loader == null) ? 0 : loader.hashCode());
+      result = prime * result +  ((loaders == null) ? 0 : Arrays.hashCode(loaders));
+      result = prime * result + ((locale == null) ? 0 : locale.hashCode());
+      return result;
+    }
+    @Override
+    public boolean equals(Object obj) {
+      if (this == obj)
+        return true;
+      if (obj == null)
+        return false;
+      if (getClass() != obj.getClass())
+        return false;
+      Bid other = (Bid) obj;
+      if (bundleName == null) {
+        if (other.bundleName != null)
+          return false;
+      } else if (!bundleName.equals(other.bundleName))
+        return false;
+      if (loader == null) {
+        if (other.loader != null)
+          return false;
+      } else if (!loader.equals(other.loader))
+        return false;
+      if (locale == null) {
+        if (other.locale != null)
+          return false;
+      } else if ( locale != other.locale)
+        return false;
+      if (loaders == null) {
+        if (other.loaders != null)
+          return false;
+      } else if (!Arrays.equals(loaders, other.loaders))
+        return false;
+      return true;
+    }
+    
+  }
+  
+  private static final ThreadLocal<Map<Bid, ResourceBundle>> b_cache = 
+      ThreadLocal.withInitial(() -> new HashMap<>());
+  
+  
   /**
    * Localize a message to the default Locale.
    * 
@@ -110,11 +182,25 @@
           String aMessageKey, Object[] aArguments, ClassLoader aLoader) {
     try {
       if (aLoader == null) {
+        // get the constant, thread-safe, stack-climbing class loader
         aLoader = MsgLocalizationClassLoader.getMsgLocalizationClassLoader();        
       }
+      
+      final boolean is_stack_climbing_loader = aLoader == MsgLocalizationClassLoader.getMsgLocalizationClassLoader();
+
       // locate the resource bundle for this exception's messages
-      ResourceBundle bundle =  ResourceBundle.getBundle(aResourceBundleName, aLocale, aLoader);
-      String message = bundle.getString(aMessageKey);
+      String message;
+      if (aResourceBundleName == null) {
+        message = "Null ResourceBundle, key = \"" + aMessageKey + "\"";
+      } else {
+        ClassLoader[] cls = is_stack_climbing_loader ? Misc.getCallingClass_classLoaders() : null;
+        final ClassLoader final_aLoader = aLoader;
+        Bid cache_key = new Bid(aResourceBundleName, aLocale, aLoader, cls);        
+        ResourceBundle bundle =  b_cache.get().computeIfAbsent(cache_key,
+            (bid) -> 
+              ResourceBundle.getBundle(aResourceBundleName, aLocale, final_aLoader));
+        message = bundle.getString(aMessageKey);
+      }
       // if arguments exist, use MessageFormat to include them
       if (aArguments != null && aArguments.length > 0) {
         MessageFormat fmt = new MessageFormat(message);
@@ -128,11 +214,11 @@
   }
 
   public static void setTccl(ClassLoader tccl) {
-    MsgLocalizationClassLoader.CallClimbingClassLoader.originalTccl.set(tccl);
+    MsgLocalizationClassLoader.CallClimbingClassLoader.original_thread_context_class_loader.set(tccl);
   }
   
   public static void removeTccl() {
-    MsgLocalizationClassLoader.CallClimbingClassLoader.originalTccl.remove();
+    MsgLocalizationClassLoader.CallClimbingClassLoader.original_thread_context_class_loader.remove();
   }
     
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/Int2ObjHashMap.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/Int2ObjHashMap.java
index 56c5e5c..5792316 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/Int2ObjHashMap.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/Int2ObjHashMap.java
@@ -20,10 +20,13 @@
 package org.apache.uima.internal.util;

 

 import java.lang.reflect.Array;

+import java.util.ArrayList;

 import java.util.Arrays;

 import java.util.Iterator;

 import java.util.NoSuchElementException;

+import java.util.function.IntFunction;

 

+import org.apache.uima.util.IntEntry;

 import org.apache.uima.util.impl.Constants;

 

 /**

@@ -39,132 +42,38 @@
  *   keys are non-0 ints

  *     - 0 is reserved for the empty key slot

  *     - Integer.MIN_VALUE is reserved for removed slot 

- *   Entry set not (yet) impl

  *   

  * values can be anything, but null is the value returned by get if not found so 

  *   values probably should not be null

  *   

- * remove not currently supported

+ * remove supported by replacing the value slot with null, and replacing the key slot with a "removed" token.

+ * A cleanout of removed items occurs when necessary.

+ * 

+ * @param <T> the type of the component type, must match the clazz in the constructor call

+ * @param <E> the type of the elements

  *   

  */

-public class Int2ObjHashMap<T> {

+public class Int2ObjHashMap<T, E extends T> extends Common_hash_support implements Iterable<IntEntry<E>>{

+  

+  private static final int REMOVED_KEY = Integer.MIN_VALUE;

 

-  private class KeyIterator implements IntListIterator {

-

-    /**

-     * Keep this always pointing to a non-0 entry, or

-     * if not valid, outside the range

-     */

-    private int curPosition;

+  private class KeyIterator extends CommonKeyIterator implements IntListIterator {   

     

-    private final int firstPosition;

-

-    private KeyIterator() {

-      this.curPosition = 0;

-      moveToNextFilled();

-      firstPosition = curPosition;

+    @Override

+    public final int nextNvc()  {   

+      final int r = keys[curPosition];

+      curPosition = moveToNextFilled(curPosition + 1);

+      return r;     

     }

     

-    public final boolean hasNext() {

-      return curPosition < keys.length;

+    @Override

+    public int previousNvc() {

+      curPosition = moveToPreviousFilled(curPosition - 1);

+      return keys[curPosition];      

     }

 

-    public final int next() {

-      

-//      if (!hasNext()) {

-//        throw new NoSuchElementException();

-//      }

-      try {

-        final int r = keys[curPosition++];

-        moveToNextFilled();

-        return r;

-      } catch (IndexOutOfBoundsException e) {

-        throw new NoSuchElementException();

-      }

-    }

-

-    /**

-     * @see org.apache.uima.internal.util.IntListIterator#hasPrevious()

-     */

-    public boolean hasPrevious() {

-      return (curPosition > firstPosition);

-    }

-

-    /**

-     * @see org.apache.uima.internal.util.IntListIterator#previous()

-     */

-    public int previous() {

-      if (!hasPrevious()) {

-        throw new NoSuchElementException();

-      }

-      curPosition --;

-      moveToPreviousFilled();

-      return keys[curPosition];

-    }

-

-    /**

-     * @see org.apache.uima.internal.util.IntListIterator#moveToEnd()

-     */

-    public void moveToEnd() {

-      curPosition = keys.length - 1;

-      moveToPreviousFilled();

-    }

-

-    /**

-     * @see org.apache.uima.internal.util.IntListIterator#moveToStart()

-     */

-    public void moveToStart() {

-      curPosition = 0;

-      moveToNextFilled();

-    }

-    

-    /**

-     * advance pos until it points to a non 0 or is 1 past end

-     * @param pos

-     * @return updated pos

-     */

-    private void moveToNextFilled() {      

-      final int max = keys.length;

-      while (true) {

-        if (curPosition >= max) {

-          return;

-        }

-        if (keys[curPosition] != 0) {

-          return;

-        }

-        curPosition ++;

-      }

-    }

-     

-    /**

-     * decrement pos until it points to a non 0 or is -1

-     * @param pos

-     * @return updated pos

-     */

-    private void moveToPreviousFilled() {

-      final int max = keys.length;

-      if (curPosition > max) {

-        curPosition = max - 1;

-      }

-      

-      while (true) {

-        if (curPosition < 0) {

-          return;

-        }

-        if (keys[curPosition] != 0) {

-          return;

-        }

-        curPosition --;

-      }

-    }

   }

-  

-

-  

-  // set to true to collect statistics for tuning

-  // you have to also put a call to showHistogram() at the end of the run

-  private static final boolean TUNE = false;

-   

+    

   // this load factor gives, for array doubling strategy:

   //   between 1.5 * 8 bytes (2 words, one for key, one for value) = 12 and

   //           3   * 8                                               24 bytes per entry

@@ -178,38 +87,36 @@
   

   // See corresponding Int2IntPerfTest which is disabled normally

  

-  private final float loadFactor = (float)0.66;  

-  

-  private final int initialCapacity; 

-

-  private int histogram [];

-  private int maxProbe = 0;

-

-  private int sizeWhichTriggersExpansion;

-  private int size; // number of elements in the table  

+//  private final float loadFactor = (float)0.66;  

+//  

+//  private final int initialCapacity; 

+//

+//  private int histogram [];

+//  private int maxProbe = 0;

+//

+//  private int sizeWhichTriggersExpansion;

+//  private int size; // number of elements in the table  

  

   private int [] keys;

-  private T [] values;

+  private T [] values;  // this array constructed using the componentType

   

-  private boolean secondTimeShrinkable = false;

+//  private boolean secondTimeShrinkable = false;

   

-  final private Class<T> componentType;

-

+  final private Class<T> componentType;  // needed to make new instances of the value array

+  

+//  /** set to the first found_removed when searching */

+//  private int found_removed;

+  

+//  private int removed = 0;  // for rebalancing  

+    

   public Int2ObjHashMap(Class<T> clazz) {

-    this(clazz, 16);

+    this(clazz, MIN_SIZE);

   }

   

-  public Int2ObjHashMap(Class<T> clazz, int initialCapacity) {

+  public Int2ObjHashMap(Class<T> clazz, int initialSizeBeforeExpanding) {

+    super(initialSizeBeforeExpanding);

     this.componentType = clazz;

-    initialCapacity = Misc.nextHigherPowerOf2(initialCapacity);

-    this.initialCapacity = initialCapacity;

-    newTableKeepSize(initialCapacity);

-    size = 0;

-    if (TUNE) {

-      histogram = new int[200];

-      Arrays.fill(histogram, 0);

-      maxProbe = 0;

-    }

+    newTable(this.initialCapacity);

   }

   

   /** 

@@ -217,197 +124,352 @@
    * @param clazz

    * @param initialCapacity

    */

-  private Int2ObjHashMap(

-      Class<T> clazz, 

-      int initialCapacity,

-      int sizeWhichTriggersExpansion, 

-      int size, 

-      int[] keys, 

-      T[] values) {

-    this.componentType = clazz;

-    this.initialCapacity = Misc.nextHigherPowerOf2(initialCapacity);

-    this.sizeWhichTriggersExpansion = sizeWhichTriggersExpansion;

-    this.histogram = null;

-    this.size = size;

-    this.keys = Arrays.copyOf(keys, keys.length);

-    this.values = Arrays.copyOf(values, values.length);

+  private Int2ObjHashMap(Int2ObjHashMap orig) {

+    super(orig);

+    this.componentType = orig.componentType;

+    this.keys = Arrays.copyOf(orig.keys, keys.length);

+    this.values = (T[]) Arrays.copyOf(orig.values, values.length);

   }

         

-  private void newTableKeepSize(int capacity) {

-    // minimum size is 16

-    capacity = Math.max(16, Misc.nextHigherPowerOf2(capacity));

-    keys = new int[capacity];

-    values = (T[]) Array.newInstance(componentType, capacity);

-    sizeWhichTriggersExpansion = (int)(capacity * loadFactor);

-  }

+//  private void newTableKeepSize(int capacity) {

+//    capacity = Math.max(MIN_SIZE, Misc.nextHigherPowerOf2(capacity));

+//    keys = new int[capacity];

+//    values = (T[]) Array.newInstance(componentType, capacity);

+//    sizeWhichTriggersExpansion = (int)(capacity * loadFactor);

+//  }

 

-  private void incrementSize() {

-    if (size >= sizeWhichTriggersExpansion) {

-      increaseTableCapacity();

-    }

-    size++;

-  }

+//  protected void incrementSize() {

+//    if (size + removed >= sizeWhichTriggersExpansion) {

+//      increaseTableCapacity();

+//    }

+//    size++;

+//  }

 

-  private void increaseTableCapacity() {

-    final int [] oldKeys = keys;

-    final T [] oldValues = values;

-    final int oldCapacity = oldKeys.length;

-    int newCapacity = 2 * oldCapacity;

+//  private void increaseTableCapacity() {

+//    final int [] oldKeys = keys;

+//    final T [] oldValues = values;

+//    final int oldCapacity = oldKeys.length;

+//    int newCapacity = 2 * oldCapacity;

+//    

+//    if (TUNE) {

+//      System.out.println("Capacity increasing from " + oldCapacity + " to " + newCapacity);

+//    }

+//    removed = 0;

+//    newTableKeepSize(newCapacity);

+//    int vi = 0;

+//    for (int key : oldKeys) {

+//      if (key != 0 && key != REMOVED_KEY) {

+//        putInner(key, oldValues[vi]);

+//      }

+//      vi++;

+//    }

+//  }

     

-    if (TUNE) {

-      System.out.println("Capacity increasing from " + oldCapacity + " to " + newCapacity);

-    }

-    newTableKeepSize(newCapacity);

-    int vi = 0;

-    for (int key : oldKeys) {

-      if (key != 0) {

-        putInner(key, oldValues[vi]);

-      }

-      vi++;

-    }

-  }

+//  // called by clear

+//  private void newTable(int capacity) {

+//    newTableKeepSize(capacity);

+//    size = 0;

+//    resetHistogram();

+//  }

   

-  // called by clear

-  private void newTable(int capacity) {

-    newTableKeepSize(capacity);

-    size = 0;

-    resetHistogram();

-  }

+//  private void resetHistogram() {

+//    if (TUNE) {

+//      histogram = new int[200];

+//      Arrays.fill(histogram, 0);

+//      maxProbe = 0;

+//    }    

+//  }

+

+//  public void clear() {

+//    // see if size is less than the 1/2 size that triggers expansion

+//    if (size <  (sizeWhichTriggersExpansion >>> 1)) {

+//      // if 2nd time then shrink by 50%

+//      //   this is done to avoid thrashing around the threshold

+//      if (secondTimeShrinkable) {

+//        secondTimeShrinkable = false;

+//        final int newCapacity = Math.max(initialCapacity, keys.length >>> 1);

+//        if (newCapacity < keys.length) { 

+//          newTable(newCapacity);  // shrink table by 50%

+//        } else { // don't shrink below minimum

+//          Arrays.fill(keys, 0);

+//          Arrays.fill(values,  null);

+//        }

+//        size = 0;

+//        resetHistogram();

+//        return;

+//      } else {

+//        secondTimeShrinkable = true;

+//      }

+//    } else {

+//      secondTimeShrinkable = false; // reset this to require 2 triggers in a row

+//    }

+//    size = 0;

+//    Arrays.fill(keys, 0);

+//    Arrays.fill(values, null);

+//    resetHistogram();

+//  }

+

+

+

+  /** 

+   * Searches the keys for a match

+   * @param key -

+   * @return the probeAddr in keys array - The value[probeAddr] is 0 value if not found

+   */

   

-  private void resetHistogram() {

-    if (TUNE) {

-      histogram = new int[200];

-      Arrays.fill(histogram, 0);

-      maxProbe = 0;

-    }    

-  }

-

-  public void clear() {

-    // see if size is less than the 1/2 size that triggers expansion

-    if (size <  (sizeWhichTriggersExpansion >>> 1)) {

-      // if 2nd time then shrink by 50%

-      //   this is done to avoid thrashing around the threshold

-      if (secondTimeShrinkable) {

-        secondTimeShrinkable = false;

-        final int newCapacity = Math.max(initialCapacity, keys.length >>> 1);

-        if (newCapacity < keys.length) { 

-          newTable(newCapacity);  // shrink table by 50%

-        } else { // don't shrink below minimum

-          Arrays.fill(keys, 0);

-          Arrays.fill(values,  null);

-        }

-        size = 0;

-        resetHistogram();

-        return;

-      } else {

-        secondTimeShrinkable = true;

-      }

-    } else {

-      secondTimeShrinkable = false; // reset this to require 2 triggers in a row

-    }

-    size = 0;

-    Arrays.fill(keys, 0);

-    Arrays.fill(values, null);

-    resetHistogram();

-  }

-

-  /** It gets a ref to the current value of table, and then searches that int array.

-  * 

-  * @param key -

-  * @return the probeAddr in keys array - might have a 0 value, or the key value if found

-  */

-  private int find(final int key) {

-    if (key == 0) {

+  private int findPosition(final int key) {

+    

+    if (key == 0) {  

       throw new IllegalArgumentException("0 is an invalid key");

     }

-

-    final int hash = Misc.hashInt(key);

-

-    final int[] localKeys = keys;

-    final int bitMask = localKeys.length - 1;

-    int probeAddr = hash & bitMask;

-

-    // fast paths

-    final int testKey = localKeys[probeAddr];

-    if (testKey == 0 || testKey == key) {

-      if (TUNE) {

-        updateHistogram(1);

-      }

-      return probeAddr;

+    if (key == REMOVED_KEY) {

+      throw new IllegalArgumentException("Integer.MIN_VALUE is an invalid key");

     }

-

-    return find2(localKeys, key, probeAddr);

-  } 

+    

+    

+    return findPosition(

+    

+        // key hash

+        Misc.hashInt(key),

+        

+        //is_eq_or_is_not_present

+        i -> keys[i] == 0 || keys[i] == key,

+        

+        // is_removed_key

+        i -> keys[i] == REMOVED_KEY

+        

+        );

+        

+  }

+//  private int find(final int key) {

+//    if (key == 0) {

+//      throw new IllegalArgumentException("0 is an invalid key");

+//    }

+//    if (key == REMOVED_KEY) {

+//      throw new IllegalArgumentException("Integer.MIN_VALUE is an invalid key");

+//    }

+//    found_removed = 0;  

+//    final int hash = Misc.hashInt(key);

+//

+//    final int[] localKeys = keys;

+//    final int bitMask = localKeys.length - 1;

+//    int probeAddr = hash & bitMask;

+//

+//    // fast paths

+//    final int testKey = localKeys[probeAddr];

+//    if (testKey == 0 || testKey == key) {

+//      if (TUNE) {

+//        updateHistogram(1);

+//      }

+//      return probeAddr;

+//    }

+//    if (testKey == REMOVED_KEY) {

+//      found_removed = probeAddr;

+//    }

+//    return find2(localKeys, key, probeAddr);

+//  } 

  

-  private int find2(final int[] localKeys, final int key, int probeAddr) {

-    final int bitMask = localKeys.length - 1;

-    int nbrProbes = 2;

-    int probeDelta = 1;

-    probeAddr = bitMask & (probeAddr + (probeDelta++));

+//  private int find2(final int[] localKeys, final int key, int probeAddr) {

+//    final int bitMask = localKeys.length - 1;

+//    int nbrProbes = 2;

+//    int probeDelta = 1;

+//    probeAddr = bitMask & (probeAddr + (probeDelta++));

+//

+//    while (true) {

+//      final int testKey = localKeys[probeAddr];

+//      if (testKey == 0 || testKey == key) {

+//        break;

+//      }

+//      if (found_removed == 0 && testKey == REMOVED_KEY) {

+//        found_removed = probeAddr;

+//      }

+//      nbrProbes++;

+//      probeAddr = bitMask & (probeAddr + (probeDelta++));

+//    }

+//

+//    if (TUNE) {

+//      final int pv = histogram[nbrProbes];

+//

+//      histogram[nbrProbes] = 1 + pv;

+//      if (maxProbe < nbrProbes) {

+//        maxProbe = nbrProbes;

+//      }

+//    }

+//    return probeAddr;

+//  }

 

-    while (true) {

-      final int testKey = localKeys[probeAddr];

-      if (testKey == 0 || testKey == key) {

-        break;

-      }

-      nbrProbes++;

-      probeAddr = bitMask & (probeAddr + (probeDelta++));

-    }

+//  private void updateHistogram(int nbrProbes) {

+//    histogram[nbrProbes] = 1 + histogram[nbrProbes];

+//    if (maxProbe < nbrProbes) {

+//      maxProbe = nbrProbes;

+//    }

+//  }

 

-    if (TUNE) {

-      final int pv = histogram[nbrProbes];

-

-      histogram[nbrProbes] = 1 + pv;

-      if (maxProbe < nbrProbes) {

-        maxProbe = nbrProbes;

-      }

-    }

-    return probeAddr;

+  public E get(int key) {

+    return (key == 0) ? null : (E) values[findPosition(key)];

   }

 

-  private void updateHistogram(int nbrProbes) {

-    histogram[nbrProbes] = 1 + histogram[nbrProbes];

-    if (maxProbe < nbrProbes) {

-      maxProbe = nbrProbes;

-    }

+  public E remove(int key) {

+  int pos = findPosition(key);

+  T v = values[pos];

+  int k = keys[pos];                      

+  if (k != 0) {

+    values[pos] = null;

+    keys[pos] = REMOVED_KEY;

+    commonRemove();

   }

-

-  public T get(int key) {

-    return (key == 0) ? null : values[find(key)];

+  return (E) v;  

   }

-

+  

+//  private void maybeRebalanceRemoves() {

+//    final int new_capacity = keys.length >> 1;

+//    if (removed > REBALANCE_MIN_REMOVED &&

+//        removed > new_capacity) {

+//      // cleanup will remove more than 1/2 the items

+//      

+//      int [] oldKeys = keys;

+//      T [] oldValues = values;

+//      newTable(new_capacity);

+//      removed = 0; // reset before put, otherwise, causes premature expansion

+//      

+//      for (int i = 0; i < oldKeys.length; i++) {

+//        int k = oldKeys[i];

+//        if (k != 0 && k != REMOVED_KEY) {

+//          put(k, oldValues[i]);

+//        }

+//      }

+//    }

+//  }

+  

+  protected void copy_to_new_table(

+      /* ignored */int newCapacity,

+      /* ignored */int oldCapacity,

+      CommonCopyOld2New commonCopy) {

+    int [] oldKeys = keys;

+    T [] oldValues = values;

+    commonCopy.apply(

+        

+        // copyToNew 

+        i -> 

+          putInner(oldKeys[i], oldValues[i]),

+        

+        // is_valid_old_key 

+        i ->  

+          oldKeys[i] != 0 && oldKeys[i] != REMOVED_KEY);

+  }

+ 

+  // debug

+//  private void dump(int[] ks) {

+//    HashSet<Integer> found = new HashSet<>();

+//    int nbr0 = 0;

+//    int nbrRmv = 0;

+//    for (int k : ks) {

+//      if (k == 0) {

+//        nbr0++;

+//      } else if (k == REMOVED_KEY) {

+//        nbrRmv ++;

+//      } else {

+//        boolean wasAdded = found.add(k);

+//        if (! wasAdded) {

+//          System.out.println("dups");

+//        }

+//      }

+//    }

+//  }

+//    

+//  private boolean checkKeyExists(int key) {

+//    int c = 0;

+//    for (int i = 0; i < keys.length; i++) {

+//      int k = keys[i];

+//      if (k == key) {

+//        c++;

+//        if (c > 1) {

+//          System.out.println("found key " + key + " in position " + i);

+//          return true;

+//        }

+//      }

+//    }

+//    return false;

+//  }

+  

+  

   public boolean containsKey(int key) {

-    int probeAddr = find(key);

-    return probeAddr != 0 && keys[probeAddr] != 0;

+    int probeAddr = findPosition(key);

+    return keys[probeAddr] != 0 ;

   }

  

-  public boolean isKeyValid(int position) {

-    return (position != 0) && (keys[position] != 0);

-  }

-

   public T put(int key, T value) {

-    final int i = find(key);

+    int i = findPosition(key);

     final boolean keyNotFound = keys[i] == 0;

     final T prevValue = values[i];

+    

+    if (! keyNotFound) { // key found

+      values[i] = value;

+      return prevValue;

+    }

+

+    if (found_removed != -1) {

+      i = found_removed;  // use the removed slot for the new value

+    } 

+//    //debug 

+//    if (checkKeyExists(key)) {

+//      find(key);

+//      System.out.println("stop");

+//    }

+//    // debug

+//    if (key == 322 && (i == 618 || i == 617)) {

+//      find(key);

+//      System.out.println("stop");

+//    }

+

     keys[i] = key;

     values[i] = value;

-    if (keyNotFound) {

-      incrementSize();

-    }

+    

+    commonPutOrAddNotFound();

     return prevValue;

   }

+  

+  public T computeIfAbsent(int key, IntFunction<T> mappingFunction) {

+    int i = findPosition(key);

+    if (keys[i] == 0) {

+      // key not found

+      if (found_removed != -1) {

+        i = found_removed; // use the removed slot for the new value

+      }

+      keys[i] = key;

+      values[i] = mappingFunction.apply(key);

+      commonPutOrAddNotFound();

+      return values[i];

+    }

+    

+    // key found

+    return values[i];

+  }

+

+  public T putIfAbsent(int key, T value) {

+    int i = findPosition(key);

+    if (keys[i] == 0) {

+      // key not found

+      if (found_removed != -1) {

+        i = found_removed; // use the removed slot for the new value

+      }

+      keys[i] = key;

+      values[i] = value;

+      commonPutOrAddNotFound();

+      return value;

+    }

+    

+    // key found

+    return values[i];

+  }

 

   public void putInner(int key, T value) {

-    final int i = find(key);

+    final int i = findPosition(key);

     assert (keys[i] == 0);

     keys[i] = key;

     values[i] = value;

   }

-

-  public int size() {

-    return size;

-  }

-  

+ 

   public int[] getSortedKeys() {

     final int size = size();

     if (size == 0) {

@@ -416,7 +478,7 @@
     final int[] r = new int[size];

     int i = 0;

     for (int k : keys) {

-      if (k != 0) {

+      if (k != 0 && k != REMOVED_KEY) {

         r[i++] = k;

       }

     }

@@ -437,75 +499,112 @@
     throw new UnsupportedOperationException();// only makes sense for sorted things

   }

   

-  public Iterator<T> values() {

-    return new Iterator<T>() {

+  /**

+   * @return an iterator&lt;T&gt; over the values in random order

+   */

+  public Iterator<E> values() {

+    return new Iterator<E>() {

       

       /**

        * Keep this always pointing to a non-0 entry, or

        * if not valid, outside the range

        */

-      private int curPosition = 0;

-      { moveToNextFilled(); }  // non-static initializer

+      private int curPosition = moveToNextFilled(0);

       

-

       @Override

       public boolean hasNext() {

         return curPosition < keys.length;

       }

 

       @Override

-      public T next() {

-        try {

-          final T r = values[curPosition++];

-          moveToNextFilled();

-          return r;

-        } catch (IndexOutOfBoundsException e) {

+      public E next() {

+        if (!hasNext()) {

           throw new NoSuchElementException();

         }

+        E r = (E) values[curPosition];

+        curPosition = moveToNextFilled(curPosition + 1);

+        return r;

       }

       

-      private void moveToNextFilled() {      

-        final int max = keys.length;

-        while (true) {

-          if (curPosition >= max) {

-            return;

-          }

-          if (keys[curPosition] != 0) {

-            return;

-          }

-          curPosition ++;

-        }

-      }

+//      private void moveToNextFilled() {      

+//        final int max = keys.length;

+//        while (true) {

+//          if (curPosition >= max) {

+//            return;

+//          }

+//          int k = keys[curPosition];

+//          if (k != 0 && k != REMOVED_KEY) {  

+//            return;

+//          }

+//          curPosition ++;

+//        }

+//      }

     };

   }

 

-  public void showHistogram() {

-    if (TUNE) {

-      int sumI = 0;

-      for (int i : histogram) {

-        sumI += i;

-      }

-      

-      System.out.format(

-          "Histogram of number of probes, loadfactor = %.1f, maxProbe=%,d nbr of find operations at last table size=%,d%n",

-          loadFactor, maxProbe, sumI);

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

-        if (i == maxProbe && histogram[i] == 0) {

-          System.out.println("huh?");

-        }

-        System.out.println(i + ": " + histogram[i]);

-      }     

-      

-      System.out.println("bytes / entry = " + (float) (keys.length) * 8 / size());

-      System.out.format("size = %,d, prevExpansionTriggerSize = %,d, next = %,d%n",

-          size(),

-          (int) ((keys.length >>> 1) * loadFactor),

-          (int) (keys.length * loadFactor));

+  public T[] valuesArray() {

+    Iterator<E> it = values();

+    int size = size();

+    T[] r = (T[]) Array.newInstance(componentType, size);

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

+      r[i] = it.next();

     }

+    return r;

+  }

+  

+  public Int2ObjHashMap<T, E> copy() {

+    return new Int2ObjHashMap<>(this);

   }

 

-  public Int2ObjHashMap<T> copy() {

-    return new Int2ObjHashMap<>(componentType, initialCapacity, sizeWhichTriggersExpansion, size, keys, values);

+  @Override

+  public Iterator<IntEntry<E>> iterator() {

+    

+    return new Iterator<IntEntry<E>>() {

+      

+      /**

+       * Keep this always pointing to a non-0 entry, or

+       * if not valid, outside the range

+       */

+      private int curPosition = moveToNextFilled(0);

+      

+      @Override

+      public boolean hasNext() {

+        return curPosition < keys.length;

+      }

+

+      @Override

+      public IntEntry<E> next() {

+        if (!hasNext()) {

+          throw new NoSuchElementException();

+        }

+        final IntEntry<E> r = new IntEntry<>(keys[curPosition], (E) values[curPosition]);

+        curPosition = moveToNextFilled(curPosition + 1);

+        return r;        

+      }

+      

+    };

+

+  }

+

+  protected int keys_length() {

+    return keys.length;

+  }

+

+  @Override

+  protected boolean is_valid_key(int pos) {

+    return keys[pos] != 0 && keys[pos] != REMOVED_KEY;

+  }

+

+  @Override

+  protected void newKeysAndValues(int size) {

+    keys = new int[size];

+    values = (T[]) Array.newInstance(componentType, size);    

+  }

+

+  @Override

+  protected void clearKeysAndValues() {

+    Arrays.fill(keys, 0);

+    Arrays.fill(values, null);

   }

 

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/IntBitSet.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/IntBitSet.java
index 41eeb30..322c930 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/IntBitSet.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/IntBitSet.java
@@ -88,6 +88,9 @@
   public IntBitSet(int maxAdjKey, int offset) {

     set = new BitSet(Math.max(1, maxAdjKey));

     this.offset = offset;

+    if (IS_TRACE_MODE_SWITCH) {

+      System.out.println("TRACE_MODE new IntBitSet, maxAdjKey = " + maxAdjKey + ", offset= " + offset);

+    }

   }

   

   /**

@@ -209,14 +212,12 @@
     public final boolean hasNext() {

       return (curKey >= 0);

     }

-

-    public final int next() {

-      if (!hasNext()) {

-        throw new NoSuchElementException();

-      }

+    

+    @Override

+    public final int nextNvc() {

       final int r = curKey;

       curKey = set.nextSetBit(curKey + 1);

-      return r + offset;

+      return r + offset;      

     }

 

     /**

@@ -225,14 +226,12 @@
     public boolean hasPrevious() {

       throw new UnsupportedOperationException();

     }

-

-    /**

-     * @see org.apache.uima.internal.util.IntListIterator#previous()

-     */

-    public int previous() {

+ 

+    @Override

+    public int previousNvc() {

       throw new UnsupportedOperationException();

     }

-

+    

     /**

      * @see org.apache.uima.internal.util.IntListIterator#moveToEnd()

      */

diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/IntHashSet.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/IntHashSet.java
index a9f4b2e..06bd854 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/IntHashSet.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/IntHashSet.java
@@ -21,11 +21,14 @@
 

 import java.util.Arrays;

 import java.util.NoSuchElementException;

+import java.util.function.IntPredicate;

 

 import org.apache.uima.util.impl.Constants;

 

 /**

  * A set of non-zero ints. 

+ *   Can be negative.

+ *   

  *   0 reserved internally to indicate "not in the map";

  *   you will get an exception if you try to store 0 as a value.

  *   

@@ -51,40 +54,18 @@
  *   

  *   Automatically switches to full int representation if needed  

  */

-public class IntHashSet implements PositiveIntSet {

+public class IntHashSet extends Common_hash_support implements PositiveIntSet {

   

-  public static final int SIZE_NEEDING_4_BYTES = 256 * 256 - 2;  

-  public static final float DEFAULT_LOAD_FACTOR = 0.66F;

+  public static final int SIZE_NEEDING_4_BYTES = 256 * 256 - 2; 

   

   private static final int REMOVED4 = Integer.MIN_VALUE;

   private static final int REMOVED2 = Short.MIN_VALUE;

   

-  // set to true to collect statistics for tuning

-  // you have to also put a call to showHistogram() at the end of the run

-  private static final boolean TUNE = false;

-

-  static int nextHigherPowerOf2(int i) {

-    return (i < 1) ? 1 : Integer.highestOneBit(i) << ( (Integer.bitCount(i) == 1 ? 0 : 1));

-  }

- 

   // this load factor gives, for array doubling strategy:

   //   between 1.5 * 4 bytes (1 word for key) = 6 and

   //           3   * 4                          12 bytes per entry

   // This compares with 160 bytes/entry for the IntArrayRBT impl

-  

-  private final float loadFactor = DEFAULT_LOAD_FACTOR;  

-  

-  private final int initialCapacity; 

-

-  private int histogram [];

-  private int maxProbe = 0;

-

-  private int sizeWhichTriggersExpansion;

-  private int size; // number of elements in the table

-  private int nbrRemoved; // number of removed elements (coded as removed)

-  

-  private int removedPositionToUse = -1;

-  

+      

   // offset only used with keys2.  values stored are key - offset

   //   intent is to have them fit into short data type.

   //   If the offset is 100,000, then the keys range from 100000 - 32766 to 100000 + 32767, includes "0"

@@ -97,15 +78,15 @@
  

   private int [] keys4;

   private short[] keys2;

-

-  private boolean secondTimeShrinkable = false;

+  

+  private boolean isMake4;

   

   // these are true values (before any offset adjustment)

   private int mostPositive = Integer.MIN_VALUE;

   private int mostNegative = Integer.MAX_VALUE;

 

   public IntHashSet() {

-    this(12, 0);

+    this(10, 0);

   }

   

   public IntHashSet(int initialCapacity) {

@@ -114,87 +95,95 @@
   

   /**

    * 

-   * @param initialCapacity - you can add this many before expansion

+   * @param initialSizeBeforeExpanding - you can add this many before expansion

    * @param offset - for values in the short range, the amount to subtract

    *                 before storing.

    *                 If == MIN_VALUE, then force 4 byte ints

    */

-  public IntHashSet(int initialCapacity, int offset) {

-    this.initialCapacity = initialCapacity;

-    boolean force4 = offset == Integer.MIN_VALUE;

-    this.offset = force4 ? 0 : offset;

-    newTableKeepSize(tableSpace(initialCapacity), force4);

-    size = 0;

-    if (TUNE) {

-      histogram = new int[200];

-      Arrays.fill(histogram, 0);

-      maxProbe = 0;

+  public IntHashSet(int initialSizeBeforeExpanding, int offset) {

+    super(initialSizeBeforeExpanding);

+    isMake4 = offset == Integer.MIN_VALUE;

+    this.offset = isMake4 ? 0 : offset;

+    newTable(this.initialCapacity);

+    resetTable();

+    if (IS_TRACE_MODE_SWITCH) {

+      System.out.println("TRACE_MODE new IntHashSet, sizeBeforeExpanding = " + initialSizeBeforeExpanding + ", offset= " + offset);

     }

   }

   

+//  /**

+//   * The number of 32 bit words that are reserved when 

+//   * creating a table to hold the specified number of elements

+//   * 

+//   * The number is a power of 2.

+//   * 

+//   * The number is at least 16.

+//   * 

+//   * The number is such that you could add this many elements without

+//   *   triggering the capacity expansion.

+//   *   

+//   * @param numberOfElements -

+//   * @return -

+//   */

+//  public int tableSpace(int numberOfElements) {

+//    return tableSpace(numberOfElements, loadFactor);

+//  }

+//  

+  

+  public static int tableSpace(int numberOfElements) {

+    return Common_hash_support.tableSpace(numberOfElements, 0.66f);

+  }

+  

+//  /**

+//   * 

+//   * @param numberOfElements -

+//   * @param factor -

+//   * @return capacity of the main table (either 2 byte or 4 byte entries)

+//   */

+//  public static int tableSpace(int numberOfElements, Float factor) {

+//    if (numberOfElements < 0) {

+//      throw new IllegalArgumentException("must be > 0");

+//    }

+//    final int capacity = Math.round(numberOfElements / factor);

+//    return  Math.max(16, Misc.nextHigherPowerOf2(capacity));

+//  }

+//  

+//  private void newTableKeepSize(int capacity, boolean make4) {

+//    if (!make4) {

+//      capacity = Math.max(4, nextHigherPowerOf2(capacity));

+//      // don't use short values unless 

+//      //    the number of items is < 65536

+//      make4 = (capacity >= SIZE_NEEDING_4_BYTES);

+//    }

+//    

+//    if (make4) {

+//      keys4 = new int[capacity];

+//      keys2 = null;

+//    } else {

+//      keys2 = new short[capacity];

+//      keys4 = null;

+//    }

+//    sizeWhichTriggersExpansion = (int)(capacity * loadFactor);

+//    nbrRemoved = 0;

+//  }

+  

   /**

-   * The number of 32 bit words that are reserved when 

-   * creating a table to hold the specified number of elements

-   * 

-   * The number is a power of 2.

-   * 

-   * The number is at least 16.

-   * 

-   * The number is such that you could add this many elements without

-   *   triggering the capacity expansion.

-   *   

-   * @param numberOfElements -

-   * @return -

+   * Method called by handleHashSet in PositiveIntSet

+   * to indicate if adding this many items would cause an expansion

+   * @return true if would not expand

    */

-  public int tableSpace(int numberOfElements) {

-    return tableSpace(numberOfElements, loadFactor);

-  }

-  

-  /**

-   * 

-   * @param numberOfElements -

-   * @param factor -

-   * @return capacity of the main table (either 2 byte or 4 byte entries)

-   */

-  public static int tableSpace(int numberOfElements, Float factor) {

-    if (numberOfElements < 0) {

-      throw new IllegalArgumentException("must be > 0");

-    }

-    final int capacity = Math.round(numberOfElements / factor);

-    return  Math.max(16, nextHigherPowerOf2(capacity));

-  }

-  

-  private void newTableKeepSize(int capacity, boolean make4) {

-    if (!make4) {

-      capacity = Math.max(4, nextHigherPowerOf2(capacity));

-      make4 = (capacity >= SIZE_NEEDING_4_BYTES);

-    }

-    // don't use short values unless 

-    //    the number of items is < 65536

-    if (make4) {

-      keys4 = new int[capacity];

-      keys2 = null;

-    } else {

-      keys2 = new short[capacity];

-      keys4 = null;

-    }

-    sizeWhichTriggersExpansion = (int)(capacity * loadFactor);

-    nbrRemoved = 0;

-  }

-

-  private void incrementSize() {

-    if ((size + nbrRemoved) >= sizeWhichTriggersExpansion) {

-      increaseTableCapacity();

-    }

-    size++;

-  }

-  

   public boolean wontExpand() {

     return wontExpand(1);

   }

   

+  /**

+   * Method called by handleHashSet in PositiveIntSet

+   * to indicate if adding this many items would cause an expansion

+   * @param n the number of items added

+   * @return true if would not expand

+   */

   public boolean wontExpand(int n) {

-    return (size + nbrRemoved + n) < sizeWhichTriggersExpansion;  

+    return (size() + removed + n) < sizeWhichTriggersExpansion;  

   }

   

   public int getSpaceUsedInWords() {

@@ -204,11 +193,7 @@
   public static int getSpaceOverheadInWords() {

     return 11;

   }

-  

-  private int getCapacity() {

-    return (null == keys4) ? keys2.length : keys4.length;

-  }

-  

+    

   /**

    * Only call this if using short values with offset

    * @param adjKey

@@ -219,174 +204,176 @@
     return adjKey + offset + ((adjKey < 0) ? 1 : 0); 

   }

   

-  private void increaseTableCapacity() {

-    final int oldCapacity = getCapacity();

-    // keep same capacity if just removing the "removed" markers would 

-    // shrink the used slots to the same they would have been had there been no removed, and 

-    // the capacity was doubled.

-    final int newCapacity = (nbrRemoved > size) ? oldCapacity : oldCapacity << 1;

-    

-    if (keys2 != null) {

-      final short[] oldKeys = keys2;

-      newTableKeepSize(newCapacity, false);

-      if (newCapacity >= 256 * 256) {  // = 65536

-        // switch to 4

-        if (TUNE) {System.out.println("Switching to 4 byte keys, Capacity increasing from " + oldCapacity + " to " + newCapacity);}

-        for (short adjKey : oldKeys) {

-          if (adjKey != 0 && adjKey != REMOVED2) {

-            addInner4(getRawFromAdjKey(adjKey));

-          }

-        }

-        

-      } else {

-        if (TUNE) {System.out.println("Keeping 2 byte keys, Capacity increasing from " + oldCapacity + " to " + newCapacity);}

-        for (short adjKey : oldKeys) {

-          if (adjKey != 0 && adjKey != REMOVED2) {

-            addInner2(adjKey);

-          }

-        }

-      }

-      

-    } else {

-      final int [] oldKeys = keys4;      

-      if (TUNE) {System.out.println("Capacity increasing from " + oldCapacity + " to " + newCapacity);}

-      newTableKeepSize(newCapacity, true);

-      for (int key : oldKeys) {

-        if (key != 0 && key != REMOVED4) {

-          addInner4(key);

-        }

-      }

-    }

-  }

+//  private void increaseTableCapacity() {

+//    final int oldCapacity = getCapacity();

+//    // keep same capacity if just removing the "removed" markers would 

+//    // shrink the used slots to the same they would have been had there been no removed, and 

+//    // the capacity was doubled.

+//    final int newCapacity = (nbrRemoved > size) ? oldCapacity : oldCapacity << 1;

+//    

+//    if (keys2 != null) {

+//      final short[] oldKeys = keys2;

+//      newTableKeepSize(newCapacity, false);

+//      if (newCapacity >= 256 * 256) {  // = 65536

+//        // switch to 4

+//        if (TUNE) {System.out.println("Switching to 4 byte keys, Capacity increasing from " + oldCapacity + " to " + newCapacity);}

+//        for (short adjKey : oldKeys) {

+//          if (adjKey != 0 && adjKey != REMOVED2) {

+//            addInner4(getRawFromAdjKey(adjKey));

+//          }

+//        }

+//        

+//      } else {

+//        if (TUNE) {System.out.println("Keeping 2 byte keys, Capacity increasing from " + oldCapacity + " to " + newCapacity);}

+//        for (short adjKey : oldKeys) {

+//          if (adjKey != 0 && adjKey != REMOVED2) {

+//            addInner2(adjKey);

+//          }

+//        }

+//      }

+//      

+//    } else {

+//      final int [] oldKeys = keys4;      

+//      if (TUNE) {System.out.println("Capacity increasing from " + oldCapacity + " to " + newCapacity);}

+//      newTableKeepSize(newCapacity, true);

+//      for (int key : oldKeys) {

+//        if (key != 0 && key != REMOVED4) {

+//          addInner4(key);

+//        }

+//      }

+//    }

+//  }

   

-  // called by clear

-  private void newTable(int capacity) {

-    newTableKeepSize(capacity, false);

-    resetTable();

-  }

-

-  private void resetHistogram() {

-    if (TUNE) {

-      histogram = new int[200];

-      Arrays.fill(histogram, 0);

-      maxProbe = 0;

-    }

-  }

+//  // called by clear

+//  private void newTable(int capacity) {

+//    newTableKeepSize(capacity, false);

+//    resetTable();

+//  }

+//

+//  private void resetHistogram() {

+//    if (TUNE) {

+//      histogram = new int[200];

+//      Arrays.fill(histogram, 0);

+//      maxProbe = 0;

+//    }

+//  }

   

-  private void resetArray() {

-    if (keys4 == null) {

-      Arrays.fill(keys2,  (short)0);

-    } else {

-      Arrays.fill(keys4, 0);

-    }

-    resetTable();

-  }

+//  private void resetArray() {

+//    if (keys4 == null) {

+//      Arrays.fill(keys2,  (short)0);

+//    } else {

+//      Arrays.fill(keys4, 0);

+//    }

+//    resetTable();

+//  }

   

   private void resetTable() {

     mostPositive = Integer.MIN_VALUE;

     mostNegative = Integer.MAX_VALUE;

-    resetHistogram();

-    size = 0;

-    nbrRemoved = 0;    

+//    resetHistogram();

+//    size = 0;

+//    nbrRemoved = 0;    

   }

   

   @Override

   public void clear() {

-    // see if size is less than the 1/2 size that triggers expansion

-    if (size <  (sizeWhichTriggersExpansion >>> 1)) {

-      // if 2nd time then shrink by 50%

-      //   this is done to avoid thrashing around the threshold

-      if (secondTimeShrinkable) {

-        secondTimeShrinkable = false;

-        final int currentCapacity = getCapacity();

-        final int newCapacity = Math.max(initialCapacity, currentCapacity >>> 1);

-        if (newCapacity < currentCapacity) { 

-          newTable(newCapacity);  // shrink table by 50%

-        } else { // don't shrink below minimum

-          resetArray();

-        }

-        return;

-        

-      } else {

-        secondTimeShrinkable = true;

-      }

-    } else {

-      secondTimeShrinkable = false; // reset this to require 2 triggers in a row

-    }

-   resetArray();

+    super.clear();

+    resetTable();

+//    // see if size is less than the 1/2 size that triggers expansion

+//    if (size <  (sizeWhichTriggersExpansion >>> 1)) {

+//      // if 2nd time then shrink by 50%

+//      //   this is done to avoid thrashing around the threshold

+//      if (secondTimeShrinkable) {

+//        secondTimeShrinkable = false;

+//        final int currentCapacity = getCapacity();

+//        final int newCapacity = Math.max(initialCapacity, currentCapacity >>> 1);

+//        if (newCapacity < currentCapacity) { 

+//          newTable(newCapacity);  // shrink table by 50%

+//        } else { // don't shrink below minimum

+//          resetArray();

+//        }

+//        return;

+//        

+//      } else {

+//        secondTimeShrinkable = true;

+//      }

+//    } else {

+//      secondTimeShrinkable = false; // reset this to require 2 triggers in a row

+//    }

+//   resetArray();

   }

 

-  /** 

-  * returns a position in the key/value table

-  *   if the key is not found, then the position will be to the

-  *   place where the key would be put upon adding, and the 

-  *   current internal value of keys[position] would be 0.

-  *   

-  *   if the key is found, then keys[position] == key

-  * @param adjKey - raw key - offset (-1 if this value is 0 or negative, to skip 0, if shorts)

-  * @return the probeAddr in keys array - might have a 0 value, or the key value if found

-  */

-  private int findPosition(final int adjKey) {

-    return findPosition(adjKey, false);

-  } 

-  

-  private int findPosition(final int adjKey, final boolean includeRemoved) {

-    if (adjKey == 0) {

-      throw new IllegalArgumentException("0 is an invalid key");

-    }

-

-    final int hash = Misc.hashInt(adjKey);

-    int nbrProbes = 1;

-    int probeDelta = 1;

-    int probeAddr;

-    removedPositionToUse = -1;

-    

-    if (keys4 == null) {

-      final short[] localKeys2 = keys2;

-      final int bitMask = localKeys2.length - 1;

-      probeAddr = hash & bitMask;

-

-       while (true) {

-        final int testKey = localKeys2[probeAddr];

-        if (includeRemoved && (removedPositionToUse == -1) && (testKey == REMOVED2)) {

-          nbrRemoved --;  // because caller will use this as a slot for adding

-          removedPositionToUse = probeAddr;

-        }

-        if (testKey == 0 || testKey == adjKey) {

-           break;

-        }

-        nbrProbes++; 

-        probeAddr = bitMask & (probeAddr + (probeDelta++));

-      }

-    } else {

-      final int[] localKeys4 = keys4;

-      final int bitMask = localKeys4.length - 1;

-      probeAddr = hash & bitMask;

-      while (true) {

-        final int testKey = localKeys4[probeAddr];

-        if (includeRemoved && (removedPositionToUse == -1) && (testKey == REMOVED4)) {

-          nbrRemoved --;  // because caller will use this as a slot for adding

-          removedPositionToUse = probeAddr;

-        }

-        if (testKey == 0 || testKey == adjKey) {

-          break;

-        }

-        nbrProbes++;

-        probeAddr = bitMask & (probeAddr + (probeDelta++));

-      }

-    }

-

-    if (TUNE) {

-      final int pv = histogram[nbrProbes];

-

-      histogram[nbrProbes] = 1 + pv;

-      if (maxProbe < nbrProbes) {

-        maxProbe = nbrProbes;

-      }

-    }

-

-    return probeAddr;

-  }

+//  /** 

+//  * returns a position in the key/value table

+//  *   if the key is not found, then the position will be to the

+//  *   place where the key would be put upon adding, and the 

+//  *   current internal value of keys[position] would be 0.

+//  *   

+//  *   if the key is found, then keys[position] == key

+//  * @param adjKey - raw key - offset (-1 if this value is 0 or negative, to skip 0, if shorts)

+//  * @return the probeAddr in keys array - might have a 0 value, or the key value if found

+//  */

+//  private int findPosition(final int adjKey) {

+//    return findPosition(adjKey, false);

+//  } 

+//  

+//  private int findPosition(final int adjKey, final boolean includeRemoved) {

+//    if (adjKey == 0) {

+//      throw new IllegalArgumentException("0 is an invalid key");

+//    }

+//

+//    final int hash = Misc.hashInt(adjKey);

+//    int nbrProbes = 1;

+//    int probeDelta = 1;

+//    int probeAddr;

+//    removedPositionToUse = -1;

+//    

+//    if (keys4 == null) {

+//      final short[] localKeys2 = keys2;

+//      final int bitMask = localKeys2.length - 1;

+//      probeAddr = hash & bitMask;

+//

+//       while (true) {

+//        final int testKey = localKeys2[probeAddr];

+//        if (includeRemoved && (removedPositionToUse == -1) && (testKey == REMOVED2)) {

+//          nbrRemoved --;  // because caller will use this as a slot for adding

+//          removedPositionToUse = probeAddr;

+//        }

+//        if (testKey == 0 || testKey == adjKey) {

+//           break;

+//        }

+//        nbrProbes++; 

+//        probeAddr = bitMask & (probeAddr + (probeDelta++));

+//      }

+//    } else {

+//      final int[] localKeys4 = keys4;

+//      final int bitMask = localKeys4.length - 1;

+//      probeAddr = hash & bitMask;

+//      while (true) {

+//        final int testKey = localKeys4[probeAddr];

+//        if (includeRemoved && (removedPositionToUse == -1) && (testKey == REMOVED4)) {

+//          nbrRemoved --;  // because caller will use this as a slot for adding

+//          removedPositionToUse = probeAddr;

+//        }

+//        if (testKey == 0 || testKey == adjKey) {

+//          break;

+//        }

+//        nbrProbes++;

+//        probeAddr = bitMask & (probeAddr + (probeDelta++));

+//      }

+//    }

+//

+//    if (TUNE) {

+//      final int pv = histogram[nbrProbes];

+//

+//      histogram[nbrProbes] = 1 + pv;

+//      if (maxProbe < nbrProbes) {

+//        maxProbe = nbrProbes;

+//      }

+//    }

+//

+//    return probeAddr;

+//  }

    

   // only called when keys are shorts

   private boolean isAdjKeyOutOfRange(int adjKey) {

@@ -398,41 +385,112 @@
   

   @Override

   public boolean contains(int rawKey) {

-    return find(rawKey) != -1;

+    int pos = findPosition(rawKey);

+    if (pos == -1) {

+      return false;

+    }

+    if (keys4 == null) {

+      return keys2[pos] != 0;

+    } else {

+      return keys4[pos] != 0;

+    }

   }

   

+  /** 

+   * This method is part of the PositiveSet API, and

+   * is defined to return an int that could be used with

+   *   iterators to position them.  

+   *   

+   * For this case, it is not used, because 

+   *   the iterators don't support positioning this way

+   *   because they are not sorted.

+   */

   @Override

   public int find(int rawKey) {

-    if (rawKey == 0) {

-      return -1;

-    }

+    throw new UnsupportedOperationException();

+  }

+  

 

+  /**

+   * @param rawKey the key value to find

+   * @return the position in the table if present, otherwise the position of the slot where the 

+   *         key value would be added, unless the new value is at a position which would require

+   *         the key2 form to be switched to the key4 form, in which case,

+   *         -1 is returned (means not found, and requires conversion to 4 byte keys)

+   */

+  private int findPosition(int rawKey) {

+    

+    if (rawKey == 0) {  

+      throw new IllegalArgumentException("0 is an invalid key");

+    }

+    

     if (keys4 == null) {

+      // special handling for 2 byte keys with offsets

       // check for keys never stored in short table 

       //   adjKey of Short.MIN_VALUE which is the removed flag

       final int adjKey = getAdjKey(rawKey);

       if (isAdjKeyOutOfRange(adjKey)) {

         return -1;

       }

-      final int pos = findPosition(adjKey);   

-      return (keys2[pos] == adjKey) ? pos : -1;

+      

+      if (rawKey == REMOVED2) {

+        throw new IllegalArgumentException(String.valueOf(REMOVED2) + " is an invalid key");

+      }

+      

+      return findPositionAdjKey(adjKey);

+      

+    } else {

+      

+      if (rawKey == REMOVED4) {

+        throw new IllegalArgumentException(String.valueOf(REMOVED4) + " is an invalid key");

+      }

+      

+      return findPosition4(rawKey);

     }

     

-    // using 4 byte keys, no offset

-    if (rawKey == Integer.MIN_VALUE) {

-      return -1;  // not stored in table (reserved value for removed items)

-    }

-    final int pos = findPosition(rawKey);

-    return (keys4[pos] == rawKey) ? pos : -1;

   }

    

+  private int findPosition4(int rawKey) {

+    

+    return super.findPosition(

+        

+        // key hash

+        Misc.hashInt(rawKey),

+        

+        // is_eq_or_is_not_present

+        i -> keys4[i] == 0 || keys4[i] == rawKey,

+        

+        // is_removed_key

+        i -> keys4[i] == REMOVED4

+      );    

+  }

+  

+  private int findPositionAdjKey(int adjKey) {

+    // special handling for 2 byte keys with offsets

+    // check for keys never stored in short table 

+    //   adjKey of Short.MIN_VALUE which is the removed flag

+        

+    return super.findPosition(

+          

+          // key hash

+          Misc.hashInt(adjKey),

+          

+          // is_eq_or_is_not_present

+          i -> keys2[i] == 0 || keys2[i] == adjKey,

+          

+          // is_removed_key

+          i -> keys2[i] == REMOVED2

+        );    

+  }

+  

+  

   /**

    * return the adjusted key.

    *   never called for 4 byte form

    *   for 2 byte key mode, subtract the offset, and adjust by -1 if 0 or less

    *     Note: returned value can be less than Short.MIN_VALUE 

    * @param rawKey

-   * @return adjusted key

+   * @return adjusted key, a range from negative to positive, but never 0

    */

   private int getAdjKey(int rawKey) {

 //    if (rawKey == 0 || (rawKey == Integer.MIN_VALUE)) {

@@ -448,7 +506,9 @@
   private void switchTo4byte() {

     // convert to 4 byte because values can't be offset and fit in a short

     final short[] oldKeys = keys2;

-    newTableKeepSize(getCapacity(), true);  // make a 4 table. same size

+    isMake4 = true;

+    newTable(getCapacity());  // make a 4 table. same size

+    removed = 0; 

     for (short adjKey : oldKeys) {

       if (adjKey != 0 && adjKey != REMOVED2) {

         addInner4(getRawFromAdjKey(adjKey));

@@ -467,7 +527,7 @@
       throw new IllegalArgumentException("argument must be non-zero");

     }

        

-    if (size == 0) {

+    if (size() == 0) {

       mostPositive = mostNegative = rawKey;

     } else {

       if (rawKey > mostPositive) {

@@ -479,6 +539,9 @@
     }

     

     if (keys4 != null) {

+      if (rawKey == REMOVED4) {

+        throw new IllegalArgumentException(String.valueOf(REMOVED4) + " is an invalid key");

+      }

       return find4AndAddIfMissing(rawKey);

       

       // short keys

@@ -490,26 +553,42 @@
         

         // key in range

       } else {

-        final int i = findPosition(adjKey, true);  // reuse removed slots

+        final int i = findPositionAdjKey(adjKey);  

         if (keys2[i] == adjKey) {

           return false;

         }

         

-        keys2[ (removedPositionToUse != -1) ? removedPositionToUse : i ] = (short) adjKey;

-        incrementSize();

+        keys2[ (found_removed != -1) ? found_removed : i ] = (short) adjKey;

+        commonPutOrAddNotFound();

         return true;

       }

     }

   }

   

   private boolean find4AndAddIfMissing(int rawKey) {

-    removedPositionToUse = -1;

-    final int i = findPosition(rawKey, true);

+    int i = findPosition4(rawKey);

     if (keys4[i] == rawKey) {

-      return false;

+      return false;  // already in table

     }

-    keys4[ (removedPositionToUse == -1) ? i : removedPositionToUse] = rawKey;

-    incrementSize();

+    

+    if (found_removed == -1) {

+      keys4[i] = rawKey;

+      incrementSize();

+    } else {

+      keys4[found_removed] = rawKey;

+      commonPutOrAddNotFound();

+    }

+//    keys4[ (found_removed == -1) ? i : found_removed] = rawKey;

+//    commonPutOrAddNotFound();

+//    

+//    

+//    removedPositionToUse = -1;

+//    final int i = findPosition(rawKey, true);

+//    if (keys4[i] == rawKey) {

+//      return false;

+//    }

+//    keys4[ (found_removed == -1) ? i : found_removed] = rawKey;

+//    incrementSize();

     return true;

   }

   

@@ -542,13 +621,13 @@
    * @param rawKey

    */

   private void addInner4(int rawKey) {

-    final int i = findPosition(rawKey);

+    final int i = findPosition4(rawKey);

     assert(keys4[i] == 0);

     keys4[i] = rawKey;

   }

   

   private void addInner2(short adjKey) {

-    final int i = findPosition(adjKey);

+    final int i = findPositionAdjKey(adjKey);

     assert(keys2[i] == 0);    

     keys2[i] = adjKey;

   }

@@ -568,33 +647,35 @@
    */

   @Override

   public boolean remove(int rawKey) {

-    final int pos = find(rawKey);

-    if (pos < 0) {

+//    debugValidate();

+    final int pos = findPosition(rawKey);

+    if (pos == -1 || ((keys4 == null) 

+                        ? (keys2[pos] == 0) 

+                        : (keys4[pos] == 0)) ) {

       return false;

     }

     

+//    //debug

+//    if (size() <= 0) 

+//      System.out.println("debug");

+//    assert size() > 0;

     if (keys4 == null) {

       keys2[pos] = REMOVED2;

     } else {

       keys4[pos] = REMOVED4;

     }

-    

-    size--;

-    nbrRemoved ++;

+

     if (rawKey == mostPositive) {

       mostPositive --;  // a weak adjustment

     }

     if (rawKey == mostNegative) {

       mostNegative ++;  // a weak adjustment

     }

+

+    commonRemove();    

     return true;

   }    

-  

-  @Override

-  public int size() {

-    return size;

-  }

-  

+    

   /**

    * 

    * @return a value that is &gt;= the actual most positive value in the table.

@@ -651,16 +732,16 @@
    * For short keys, the value stored for adjKey == 0 is -1, adjKey == -1 is -2, etc.

    */

   @Override

-  public int get(int index) {

+  public int get(int pos) {

     final int adjKey;

     if (keys4 == null) {

-      adjKey = keys2[index];

+      adjKey = keys2[pos];

       if (adjKey == 0 || adjKey == REMOVED2) {

         return 0;  // null, not present

       }

       return getRawFromAdjKey(adjKey);

     } else {

-      adjKey = keys4[index];

+      adjKey = keys4[pos];

       if (adjKey == 0 || adjKey == REMOVED4) {

         return 0;  // null, not present

       }

@@ -668,65 +749,66 @@
     }

   }

   

-  /**

-   * advance pos until it points to a non 0 or is 1 past end

-   * @param pos

-   * @return updated pos

-   */

-  private int moveToNextFilled(int pos) {

-    if (pos < 0) {

-      pos = 0;

-    }

-    

-    final int max = getCapacity();

-    if (null == keys4) {

-      while (true) {

-        if (pos >= max) {

-          return pos;

-        }

-        int v = get(pos);

-        if (v != 0 && v != REMOVED2) {

-          return pos;

-        }

-        pos++;

-      }

-    } else {

-      // keys4 case

-      while (true) {

-        if (pos >= max) {

-          return pos;

-        }

-        int v = get(pos);

-        if (v != 0 && v != REMOVED4) {

-          return pos;

-        }

-        pos ++;

-      }

-    }

-  }

+//  /**

+//   * advance pos until it points to a non 0 or is 1 past end

+//   * @param pos

+//   * @return updated pos

+//   */

+//  private int moveToNextFilled(int pos) {

+//    if (pos < 0) {

+//      pos = 0;

+//    }

+//    

+//    final int max = getCapacity();

+//    if (null == keys4) {

+//      while (true) {

+//        if (pos >= max) {

+//          return pos;

+//        }

+//        int v = get(pos);

+//        if (v != 0 && v != REMOVED2) {

+//          return pos;

+//        }

+//        pos++;

+//      }

+//    } else {

+//      // keys4 case

+//      while (true) {

+//        if (pos >= max) {

+//          return pos;

+//        }

+//        int v = get(pos);

+//        if (v != 0 && v != REMOVED4) {

+//          return pos;

+//        }

+//        pos ++;

+//      }

+//    }

+//  }

    

-  /**

-   * decrement pos until it points to a non 0 or is -1

-   * @param pos

-   * @return updated pos

-   */

-  private int moveToPreviousFilled(int pos) {

-    final int max = getCapacity();

-    if (pos > max) {

-      pos = max - 1;

-    }

-    

-    while (true) {

-      if (pos < 0) {

-        return pos;

-      }

-      int v = get(pos);

-      if (v != 0 && v != ( (keys4 == null) ? REMOVED2 : REMOVED4)) {

-        return pos;

-      }

-      pos --;

-    }

-  }

+//  /**

+//   * see if there's a value a pos

+//   *   if not, decrement pos until it points to a non 0 or is -1

+//   * @param pos to start looking for a value

+//   * @return a pos with a value, or -1. if there's a value at the original pos, then that pos is returned.

+//   */

+//  private int moveToPreviousFilled(int pos) {

+//    final int max = getCapacity();

+//    if (pos > max) {

+//      pos = max - 1;

+//    }

+//    

+//    while (true) {

+//      if (pos < 0) {

+//        return pos;

+//      }

+//      int v = get(pos);  // bug - adjust key!

+//      if (v != 0 && v != ( (keys4 == null) ? REMOVED2 : REMOVED4)) {

+//        return pos;

+//      }

+//      pos --;

+//    }

+//  }

 

   private class IntHashSetIterator implements IntListIterator {

 

@@ -741,29 +823,34 @@
       return curPosition < getCapacity();

     }

 

-    public final int next() {

-      if (!hasNext()) {

-        throw new NoSuchElementException();

-      }

-      return get(curPosition++);

+    public final int nextNvc() {

+      curPosition = moveToNextFilled(curPosition);

+      int r = get(curPosition);

+      curPosition = moveToNextFilled(curPosition + 1);

+      return r;

     }

-

+    

     /**

      * @see org.apache.uima.internal.util.IntListIterator#hasPrevious()

      */

     public boolean hasPrevious() {

-      curPosition = moveToPreviousFilled(curPosition);

-      return (curPosition >= 0);

+      int prev = moveToPreviousFilled(curPosition - 1);

+      return (prev >= 0);

     }

-

-    /**

-     * @see org.apache.uima.internal.util.IntListIterator#previous()

-     */

+    

+    @Override

     public int previous() {

-      if (!hasPrevious()) {

+      curPosition = moveToPreviousFilled(curPosition - 1);

+      if (curPosition < 0) {

         throw new NoSuchElementException();

       }

-      return get(curPosition--);

+      return get(curPosition);

+    }

+    

+    @Override

+    public int previousNvc() {

+      curPosition = moveToPreviousFilled(curPosition - 1);

+      return get(curPosition);

     }

 

     /**

@@ -859,7 +946,7 @@
     return String

         .format(

             "IntHashSet [loadFactor=%s, initialCapacity=%s, sizeWhichTriggersExpansion=%s, size=%s, offset=%s%n keys4=%s%n keys2=%s%n secondTimeShrinkable=%s, mostPositive=%s, mostNegative=%s]",

-            loadFactor, initialCapacity, sizeWhichTriggersExpansion, size, offset,

+            loadFactor, initialCapacity, sizeWhichTriggersExpansion, size(), offset,

             Arrays.toString(keys4), Arrays.toString(keys2), secondTimeShrinkable, mostPositive,

             mostNegative);

   }

@@ -872,6 +959,82 @@
   int getOffset() {

     return offset;

   }

+

+  @Override

+  protected boolean is_valid_key(int pos) {

+    if (keys4 == null) {

+      return keys2[pos] != 0 && keys2[pos] != REMOVED2;

+    }

+    return keys4[pos] != 0 && keys4[pos] != REMOVED4;

+  }

+

+  @Override

+  protected int keys_length() {

+    return (keys4 == null) ? keys2.length : keys4.length;

+  }

+

+  @Override

+  protected void newKeysAndValues(int capacity) {

+    if (isMake4) {

+      keys4 = new int[capacity];

+      keys2 = null;

+    } else {

+      keys2 = new short[capacity];

+      keys4 = null;

+    }

+  }

+

+  @Override

+  protected void clearKeysAndValues() {

+    if (keys4 == null) {

+      Arrays.fill(keys2,  (short)0);

+    } else {

+      Arrays.fill(keys4, 0);

+    }  

+    resetTable();

+  }

+

+  @Override

+  protected void copy_to_new_table(

+      int new_capacity,

+      int old_capacity,

+      CommonCopyOld2New commonCopy) {

+    // logic covers

+    //   2 sizes of copying old 2 new

+    //   logic to switch to 4 byte key size

+    

+    if (keys2 != null) {

+      final short[] oldKeys = keys2;

+      IntPredicate oldKeyValid = i -> oldKeys[i] != 0 && oldKeys[i] != REMOVED2;

+      

+      if (new_capacity >= 256 * 256)  { // == 65536

+        // switch to 4

+        if (TUNE) {System.out.println("Switching to 4 byte keys");}

+        isMake4 = true;  

+        commonCopy.apply( 

+            // copyToNew

+            i -> addInner4(getRawFromAdjKey(oldKeys[i])),

+            

+            oldKeyValid); // is_valid_old_key

+      } else {              

+        commonCopy.apply(

+            

+            // copyToNew

+            i -> addInner2(oldKeys[i]),

+            

+            oldKeyValid); // is_valid_old_key

+      }

+    } else {

+      final int[] oldKeys = keys4;

+//      if (TUNE) {System.out.println("Capacity increasing from " + old_capacity + " to " + new_capacity);}

+      commonCopy.apply(

+          // copyToNew

+          i -> addInner4(oldKeys[i]),

+      

+          i -> oldKeys[i] != 0 && oldKeys[i] != REMOVED4);

+    }

+    

+  }

   

   

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/IntListIterator.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/IntListIterator.java
index 107215d..a7748e4 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/IntListIterator.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/IntListIterator.java
@@ -35,16 +35,28 @@
   boolean hasNext();
 
   /**
-   * Return the next feature structure and increment the iterator.
+   * Return the next int in the list and increment the iterator.
    * 
-   * @return The next feature structure.
+   * @return The next int.
    * @exception NoSuchElementException
    *              If no next element exists, i.e., when the iterator points at the last position in
    *              the index.
    */
-  int next() throws NoSuchElementException;
+  default int next() throws NoSuchElementException {
+    if (!hasNext()) {
+      throw new NoSuchElementException();
+    }
+    return nextNvc();
+  }
 
   /**
+   * version of next() which bypasses the validity check.
+   * Only use this if you've already done this check yourself.
+   * @return the next int in the list and increment the iterator.
+   */
+  int nextNvc();
+  
+  /**
    * Check if there is a previous element. Does not move the iterator.
    * 
    * @return <code>true</code> iff there is a previous element.
@@ -52,14 +64,26 @@
   boolean hasPrevious();
 
   /**
-   * Return the previous feature structure and decrement the iterator.
+   * Return the previous int and decrement the iterator.
    * 
-   * @return The previous feature structure.
+   * @return the previous int (found by first moving the iterator one backwards).
    * @exception NoSuchElementException
    *              If no previous element exists, i.e., when the iterator points at the first
    *              position in the index.
    */
-  int previous();
+  default int previous() throws NoSuchElementException {
+    if (!hasPrevious()) {
+      throw new NoSuchElementException();
+    }
+    return previousNvc();
+  }
+  
+  /**
+   * version of previous that bypasses the validity check.
+   * Only use this if you've already done this check yourself.
+   * @return the previous int (found by first moving the iterator one backwards).
+   */
+  int previousNvc();
 
   /**
    * Move the iterator to the start of the underlying index.
diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/IntSet.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/IntSet.java
index 4bae80f..98780e0 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/IntSet.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/IntSet.java
@@ -46,6 +46,9 @@
    */
   public IntSet(int capacity) {
     this.iVec = new IntVector(capacity);
+    if (IS_TRACE_MODE_SWITCH) {
+      System.out.println("TRACE_MODE new IntSet with capacity: " + capacity);
+    }
   }
 
   /**
@@ -189,12 +192,9 @@
     public final boolean hasNext() {
       return (pos >= 0 && pos < size());
     }
-
+   
     @Override
-    public final int next() {
-      if (!hasNext()) {
-        throw new NoSuchElementException();
-      }
+    public final int nextNvc() {
       return iVec.get(pos++);
     }
 
@@ -206,16 +206,10 @@
       final int posm1 = pos - 1;
       return (posm1 >= 0 && posm1 < size());
     }
-
-    /**
-     * @see org.apache.uima.internal.util.IntListIterator#previous()
-     */
+    
     @Override
-    public int previous() {
-      if (!hasPrevious()) {
-        throw new NoSuchElementException();
-      }
-      return iVec.get(pos--);      
+    public int previousNvc() {
+      return iVec.get(--pos);
     }
 
     /**
diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/IntStack.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/IntStack.java
index 8ecb1ac..7650b76 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/IntStack.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/IntStack.java
@@ -69,7 +69,7 @@
    */
   public int pop() {
     --this.pos;
-    return this.array[this.pos];
+    return get(this.pos); // this.array[this.pos];
   }
 
   /**
@@ -78,7 +78,7 @@
    * @return The top element.
    */
   public int peek() {
-    return this.array[this.pos - 1];
+    return get(this.pos - 1); // this.array[this.pos - 1];
   }
 
   /**
diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/IntVector.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/IntVector.java
index cd46148..1c7747f 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/IntVector.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/IntVector.java
@@ -51,7 +51,7 @@
   // Points to the next free cell in the array.
   protected int pos;
 
-  protected int[] array = null;
+  private int[] array = null;
 
   /**
    * Default constructor.
@@ -610,24 +610,18 @@
       }
 
       @Override
-      public int next() throws NoSuchElementException {
-        if (!hasNext()) {
-          throw new NoSuchElementException();
-        }
-        return get(pos++);
+      public int nextNvc() {
+        return get(pos++);        
       }
-
+      
       @Override
       public boolean hasPrevious() {
-        return pos >= 0 && pos < size();  // same as has next
+        return pos > 0 && pos < size();  
       }
-
+      
       @Override
-      public int previous() {
-        if (!hasPrevious()) {
-          throw new NoSuchElementException();
-        }
-        return get(pos--);
+      public int previousNvc() {
+        return get(--pos);
       }
 
       @Override
diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/Misc.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/Misc.java
index ee578ef..54902a3 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/Misc.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/Misc.java
@@ -22,7 +22,10 @@
 import java.io.ByteArrayOutputStream;

 import java.io.File;

 import java.io.FileOutputStream;

+import java.io.FilenameFilter;

 import java.io.IOException;

+import java.io.PrintStream;

+import java.io.UnsupportedEncodingException;

 import java.lang.invoke.MethodHandle;

 import java.lang.invoke.MethodHandles;

 import java.lang.invoke.MethodHandles.Lookup;

@@ -30,23 +33,41 @@
 import java.lang.reflect.Field;

 import java.lang.reflect.Method;

 import java.net.MalformedURLException;

+import java.net.URISyntaxException;

 import java.net.URL;

+import java.nio.ByteBuffer;

+import java.util.AbstractSequentialList;

+import java.util.ArrayList;

 import java.util.Collection;

 import java.util.Iterator;

 import java.util.List;

+import java.util.ListIterator;

+import java.util.Set;

 import java.util.WeakHashMap;

+import java.util.concurrent.atomic.AtomicInteger;

+import java.util.function.BiConsumer;

 import java.util.function.Consumer;

 import java.util.function.IntConsumer;

+import java.util.function.Supplier;

 import java.util.regex.Pattern;

 

+import org.apache.uima.UIMAFramework;

 import org.apache.uima.UIMARuntimeException;

 import org.apache.uima.cas.CAS;

+import org.apache.uima.cas.impl.BuiltinTypeKinds;

+import org.apache.uima.internal.util.MsgLocalizationClassLoader.CallStack;

 import org.apache.uima.internal.util.function.Runnable_withException;

+import org.apache.uima.util.Level;

+import org.apache.uima.util.Logger;

 

 public class Misc {

+  

+  public static final boolean isJava9ea = System.getProperty("java.version").startsWith("9-ea");

 

-  public static final String blanks = "                                                     ";

+  public static final String blanks = new String(new char[1000]).replace('\0', ' ');

   public static final String dots = "...";

+//  public static final String ls = System.lineSeparator(); // n or r n

+  public static final int[] INT0 = new int[] {0};

   

   private static final Pattern whitespace = Pattern.compile("\\s");

 

@@ -54,6 +75,34 @@
     return whitespace.matcher(s).replaceAll(replacement);

   }

   

+  public static String null2str(String s) {

+    return (s == null) ? "" : s;

+  }

+  

+  public static String dumpByteArray(byte[] b, int limit) {

+    if (b == null) {

+      return "null";

+    }

+    if (b.length == 0) {

+      return "0-length";

+    }

+    StringBuilder sb = new StringBuilder(b.length * 3);

+    for (int i = 0; i < b.length; i++) {

+      if ((i % 100) == 0) {

+        sb.append('\n');

+      }

+      sb.append(String.format("%02X", b[i]));  // 0 means 0 padding, 2 means width

+      if ((i % 2) == 1) {

+        sb.append(' ');

+      }

+      if (i > limit) {

+        sb.append("\n Hit the limit: ").append(limit);

+        break;

+      }

+    }

+    return sb.toString();

+  }

+  

   /**

    * @param s starting frames above invoker

    * @param n max number of callers to return

@@ -91,11 +140,45 @@
   public static String formatcaller(String className, String methodName, int lineNumber) {

     return className.substring(1 + className.lastIndexOf('.')) + "." + methodName + "[" + lineNumber + "]";

   }

+  

+  public static ClassLoader [] getCallingClass_classLoaders() {

+    

+   // get the call stack; "new" is needed to get the current context call stack

+    

+    final Class<?>[] cs = new CallStack().getCallStack();

+    // start at the caller of the caller's class loader

+    // cs[0] is getClassContext

+    // cs[1] is getCallStack

+    // cs[2] is this method, getCallingClass_classLoaders

+    ArrayList<ClassLoader> cls = new ArrayList<>();

+    for (int i = 3; i < cs.length; i++) {

+      Class<?> callingClass = cs[i];

+      ClassLoader cl = callingClass.getClassLoader();

+      if (null == cl) { // means system class loader

+        cl = ClassLoader.getSystemClassLoader();

+      }

+      if (! cls.contains(cl)) {

+        cls.add(cl);          

+      }

+    }

+    return cls.toArray(new ClassLoader[cls.size()]);

+  }

 

+  /**

+   * @param s the string to possibly elide

+   * @param n the length, after which, elision happens

+   * @return the elided string, padded on the left to length n

+   */

   public static String elide(String s, int n) {

     return elide(s, n, true);

   }

   

+  /**

+   * @param s the string to possibly elide

+   * @param n the length, after which, elision happens

+   * @param pad true to include left padding to length n

+   * @return the elided string, padded on the left to length n

+   */

   public static String elide(String s, int n, boolean pad) {

     if (s == null) {

       s = "null";

@@ -110,21 +193,142 @@
     return s.substring(0, ss) + dots.substring(0, dl) + s.substring(sl - ss2);

   }

   

-  public final static MethodHandles.Lookup UIMAlookup = MethodHandles.lookup();

+  /**

+   * @param sb the stringBuilder to indent

+   * @param indent the indent amount (passed as array of 1 item, to allow it to be final for lambdas

+   * @return the stringBuilder, with nl if needed, and indention

+   */

+  public static StringBuilder indent(StringBuilder sb, int[] indent) {

+    return indent(sb, indent[0]);

+  }

   

+  /**

+   * @param sb the stringBuilder to indent

+   * @param indent the indent amount 

+   * @return the stringBuilder, with nl if needed, and indention

+   */

+  public static StringBuilder indent(StringBuilder sb, int indent) {

+    // if the current sb doesn't end with a new line and indent > 0, add a new line

+    if (!endsWithNl(sb) && indent > 0) {

+      sb.append('\n');

+    }

+    return sb.append(blanks, 0, Math.min(blanks.length(), indent));    

+  }

+  

+  public static void addNlIfMissing(StringBuilder sb) {

+    if (!endsWithNl(sb)) {

+      sb.append('\n');

+    }

+  }

+  

+  public static void addNlIfMissing(StringBuffer sb) {

+    if (!endsWithNl(sb)) {

+      sb.append('\n');

+    }

+  }

+  

+  private static boolean endsWithNl(StringBuilder sb) {

+    int l = sb.length();

+    return (l >= 1) && sb.charAt(l-1) == '\n';

+  }

+    

+  private static boolean endsWithNl(StringBuffer sb) {

+    int l = sb.length();

+    return (l >= 1) && sb.charAt(l-1) == '\n';

+  }

+

+  public final static MethodHandles.Lookup UIMAlookup = MethodHandles.lookup();

+ 

+  

+  private static FilenameFilter jarFilter = new FilenameFilter() {

+    public boolean accept(File dir, String name) {

+      name = name.toLowerCase();

+      return (name.endsWith(".jar"));

+    }

+  };

+

+  public static URL[] getURLs(String s) throws MalformedURLException, IOException, URISyntaxException {

+    List<URL> urls = new ArrayList<URL>();

+    String[] spaths = s.split(File.pathSeparator);

+    for (String p : spaths) {

+      addUrlsFromPath(p, urls);

+    }

+    return urls.toArray(new URL[urls.size()]);

+  }

+  

+  /**

+   * Given a String corresponding to one file path, which may be a directory, or may end in *,

+   * add the URLS it represents to the urls argument.

+   * 

+   * @param p a Jar path, or a Directory, or a directory ending with a directory-separator and a single *

+   *        p may be relative or absolute, following the definition of same in the Java File class.

+   * @param urls the list to add the URLs to

+   * @throws MalformedURLException -

+   * @throws IOException -

+   * @throws URISyntaxException -

+   */

+  public static void addUrlsFromPath(String p, List<URL> urls) throws MalformedURLException, IOException, URISyntaxException {

+    boolean mustBeDirectory = false;

+    if (p.endsWith("*")) {

+      if (p.length() < 2 || p.charAt(p.length() - 2) != File.separatorChar) {

+        UIMAFramework.getLogger().error("Path Specification \"{}\" invalid.", p);

+        throw new MalformedURLException();

+      }

+      p = p.substring(0, p.length() - 2);

+      mustBeDirectory = true;

+    }

+    

+    File pf = new File(p);

+    if (pf.isDirectory()) {

+      File[] jars = pf.listFiles(jarFilter);

+      if (jars == null || jars.length == 0) {

+        // this is the case where the user wants to include

+        // a directory containing non-jar'd .class files

+        addPathToURLs(urls, pf); 

+      } else {

+        for (File f : jars) {

+          addPathToURLs(urls, f);

+        }

+      }

+    } else if (mustBeDirectory) {

+      UIMAFramework.getLogger().error("Path Specification \"{}\" must be a directory.", p);

+      throw new MalformedURLException();

+    } else if (p.toLowerCase().endsWith(".jar")) {

+      addPathToURLs(urls, pf);

+    } else {

+      // have a segment which does not denote a jar - skip it but note that 

+      UIMAFramework.getLogger().warn("Skipping adding \"{}\" to URLs because it is not a directory or a JAR", p);

+    }

+  }

+  

+  private static void addPathToURLs(List<URL> urls, File cp) throws MalformedURLException {

+    URL url = cp.toURI().toURL();

+    urls.add(url);

+  }

+  

+  /**

+   * Convert a classpath having multiple parts separated by the pathSeparator,

+   * expanding paths that end with "*" as needed.

+   * @param classpath - to scan and convert to list of URLs

+   * @return the urls

+   */

   public static URL[] classpath2urls (String classpath) {

     try {

-      String [] sa = classpath.split(File.pathSeparator);

-      URL[] r = new URL[sa.length];

-      for (int i = 0; i < sa.length; i++) {

-        r[i] = new File(sa[i]).toURI().toURL();

-      }

-      return r;

-    } catch (MalformedURLException e) {

+      return getURLs(classpath);

+    } catch (IOException | URISyntaxException e) {

       throw new RuntimeException(e);

     }

   }

   

+  public static String expandClasspath(String classpath) {

+    StringBuilder sb = new StringBuilder();

+    for (URL url : classpath2urls(classpath)) {

+      sb.append(url.getPath());  // returns as a string just the path part of the url

+      sb.append(File.pathSeparatorChar);

+    }

+    return sb.substring(0, sb.length() - 1);  // drop trailing ":"

+  }

+  

   /**

    * 

    * @param name of property

@@ -143,39 +347,180 @@
    * @param <T> the kind of elements in the collection

    * @return the StringBuilder for chaining

    */

-  public static <T> StringBuilder addElementsToStringBuilder(StringBuilder sb, Collection<T> c){

+  public static <T> StringBuilder addElementsToStringBuilder(StringBuilder sb, Collection<T> c) {

+    return addElementsToStringBuilder(sb, c, 1000);

+  }

+  

+  public static <T> StringBuilder addElementsToStringBuilder(StringBuilder sb, Collection<T> c, int limit) {

+    return addElementsToStringBuilder(sb, c, limit, StringBuilder::append);

+  }

+

+  public static <T> StringBuilder addElementsToStringBuilder(StringBuilder sb, Collection<T> c, BiConsumer<StringBuilder, T> appender) {

+    return addElementsToStringBuilder(sb, c, 1000, appender);

+  }

+  

+  public static <T> StringBuilder addElementsToStringBuilder(List<T> c, int limit) {

+    return addElementsToStringBuilder(c, limit, StringBuilder::append);

+  }

+  

+  public static <T> StringBuilder addElementsToStringBuilder(List<T> c, int limit, BiConsumer<StringBuilder, T> appender) {

+    return addElementsToStringBuilder(INT0, c, limit, appender);

+  }

+

+  public static <T> StringBuilder addElementsToStringBuilder(int[] indent, List<T> c, int limit, BiConsumer<StringBuilder, T> appender) {

+    if (c == null) {

+      return indent(new StringBuilder(), indent).append("null");

+    }

+    

+    int sz = Math.min(limit, c.size());

+    StringBuilder sb = indent(new StringBuilder(sz * 5 + 2), indent);

+    return addElementsToStringBuilder(indent, sb, c, limit, appender);

+  }

+    

+  /**

+   * Does two styles of list formatting:

+   *   Style 1:  [ item1, item 2, item3]

+   *   Style 2:  [ 

+   *               item1,

+   *               item2,

+   *               item3

+   *             ]

+   * Starts as style 1, switches to style 2 when length &gt; 60             

+   * @param sb where the string is assembled

+   * @param c the collection to process

+   * @param limit the maximum number of items, if negative, no limit

+   * @param appender the appender

+   * @param <T> the type of the collection

+   * @return argument sb, appeneded

+   */

+  public static <T> StringBuilder addElementsToStringBuilder(StringBuilder sb, Collection<T> c, int limit, BiConsumer<StringBuilder, T> appender) {

+    return addElementsToStringBuilder(INT0, sb, c, limit, appender);

+  }

+  

+  public static <T> StringBuilder addElementsToStringBuilder(int[] indent, StringBuilder sb, Collection<T> c, int limit, BiConsumer<StringBuilder, T> appender) {

+    

+  

+    int origLength = sb.length();

+    

+    if (c.size() == 0) {       // empty case

+      return sb.append("[]");

+    }

+    

     sb.append('[');

-    String[] prefix = new String[] {""};

-    c.stream().forEachOrdered(item -> {

-       sb.append(prefix[0]);

-       sb.append(item.toString());

-       prefix[0] = ", ";

-    });

+    int i = 0;

+    boolean overLimit = false;

+    for (T item : c) {

+      if ((i++) >= limit && limit >= 0) {

+        overLimit = true;

+        break;

+      } else {

+//        sb.append(item.toString());

+        appender.accept(sb, item);

+        sb.append(", ");

+        if (sb.length() - origLength > 60) {

+          sb.setLength(origLength);  // is too long to present on one line, change to multi-line format

+          return style2(indent, sb, c, limit, appender);

+        }

+      }

+    }

+    

+    if (overLimit) {

+      sb.append("...");

+    } else {

+      sb.setLength(sb.length() - 2);  // drop the final ", "

+    }

+    

     sb.append(']');

     return sb;

   }

   

-  /**

-   * For standardized prettyprinting, to string

-   * Adds a collection of things (running an appender to append the result to the same sb) separated by , and surrounded by [  ], to a StringBuilder

-   * @param sb where the formatted collection results are appended to 

-   * @param c the collection

-   * @param appender the function for getting the value to append

-   * @param <T> the kind of elements in the collection

-   * @return the StringBuilder for chaining

-   */

-  public static<T> StringBuilder addElementsToStringBuilder(StringBuilder sb, Collection<T> c, Consumer<T> appender){

+  public static StringBuilder addElementsToStringBuilder(StringBuilder sb, int size, int limit, int indent, int incr, BiConsumer<StringBuilder, Integer> appender) {

+    int origLength = sb.length();

+    

+    if (size == 0) {       // empty case

+      return sb.append("[]");

+    }

+    

+    // first try to put on one line

     sb.append('[');

-    String[] prefix = new String[] {""};

-    c.stream().forEachOrdered(item -> {

-       sb.append(prefix[0]);

-       appender.accept(item);

-       prefix[0] = ", ";

-    });

+

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

+      if (i != 0) {

+        sb.append(", ");

+      }

+      appender.accept(sb, i);

+      

+      if (sb.length() - origLength > 60) {

+        sb.setLength(origLength);  // is too long to present on one line, change to multi-line format

+        return style2(sb, size, limit, indent, incr, appender);

+      }

+    }

+    

+    if (size > limit) {

+      sb.append("...");

+    } 

+    

     sb.append(']');

     return sb;

-  }  

+  }

   

+  private static <T> StringBuilder style2(int[] indent, StringBuilder sb, Collection<T> c, int limit, BiConsumer<StringBuilder, T> appender) {

+    sb.append("[");

+    indent[0] += 2;

+    indent(sb, indent);

+    try {

+      int i = 0;

+      int cl = -1; // for dropping trailing end punctuation

+      boolean overLimit = false;

+      for (T item : c) {

+        if ((i++) >= limit && limit >= 0) {

+          overLimit = true;

+          break;

+        } else {

+          appender.accept(sb, item);

+          cl = sb.length();

+          sb.append(",");

+          indent(sb, indent);

+        }

+      }

+      

+      if (overLimit) {

+        sb.append("...");

+      } else {

+        sb.setLength(cl);  // drop the final ",etc "

+      }      

+    } finally {

+      indent[0] -= 2;

+      indent(sb, indent).append(']');

+    }

+    return sb;

+  }

+

+  private static <T> StringBuilder style2(StringBuilder sb, int size, int limit, int indent, int incr, BiConsumer<StringBuilder, Integer> appender) {

+    sb.append("[");

+    indent += incr;

+

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

+      if (i != 0) {

+        sb.append(',');

+      }

+      sb.append('\n');

+      indent(sb, indent);

+      appender.accept(sb, i);

+    }

+    

+    if (size > limit) {

+      sb.append(",\n");

+      indent(sb, indent);

+      sb.append("...");

+    }

+

+    sb.append('\n');

+    indent(sb, indent - incr);

+    sb.append(']');

+    return sb;

+  }

+

   /**

    * Writes a byte array output stream to a file

    * @param baos the array to write

@@ -306,6 +651,23 @@
     } 

   }

   

+  static public int getPrivateStaticIntFieldNoInherit(Class<?> clazz, String fieldName) {

+    try {

+      Field f = clazz.getDeclaredField(fieldName);

+      f.setAccessible(true);

+      return f.getInt(null);

+    } catch (NoSuchFieldException e) {

+      return Integer.MIN_VALUE;

+    } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {

+        throw new RuntimeException(e);

+    } 

+  }

+  

+  /**

+   * Takes trailing arguments of strings and adds them all the first

+   * @param c the collection to add the strings to

+   * @param v 0 or more strings as arguments

+   */

   static public void addAll(Collection<String> c, String ... v) {

     for (String s : v) {

       c.add(s);

@@ -327,11 +689,12 @@
   

   public static void assertUie(boolean v, Throwable e) {

     if (!v) 

-      throw new UIMARuntimeException(e, UIMARuntimeException.INTERNAL_ERROR);

+      throw new UIMARuntimeException(e, UIMARuntimeException.INTERNAL_ERROR, e);

   }

   

-  public static void internalError() {

+  public static RuntimeException internalError() {

     assertUie(false);

+    return null;

   }

   

   public static void internalError(Throwable e) {

@@ -366,7 +729,31 @@
     h1 ^= h1 >>> 16;

     return h1;

   }

+  

+  /**

+   * a hash for strings as a long - less likely to be a collision

+   * @param s - the string

+   * @return a long hash

+   */

+  public static long hashStringLong(String s) {

+    if (s == null) return 0;

+    int l = s.length();

+    if (l == 0) return 0;

+    long c = 1; 

+    

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

+      c = 31 * c + s.charAt(i);

+    }

+    return c;

+  }

 

+  /**

+   * Get item from array list.  If index is &gt; length, expand the array, and return null

+   * @param a the list

+   * @param i the index

+   * @param <T> the type of the items in the list

+   * @return the item at the index or null

+   */

   public static <T> T getWithExpand(List<T> a, int i) {

     while (i >= a.size()) {

       a.add(null);

@@ -439,11 +826,66 @@
   /**

    * format a list of items for pretty printing as [item1, item2, ... ]

    * @param items to print

+   * @param <T> the type of elements in the list

    * @return  [item1, item2, ... ]

    */

-  public static String ppList(List<?> items) {

-    StringBuilder sb = new StringBuilder(items.size() * 5 + 2);

-    return addElementsToStringBuilder(sb, items).toString();

+  public static <T> String ppList(List<T> items) {

+    return ppList(items, 1000);

+  }

+  

+  /**

+   * @param items to print

+   * @param max - maximum number of items to print

+   * @param <T> the type of elements in the list

+   * @return  [item1, item2, ... ]

+   */

+  public static <T> String ppList(List<T> items, int max) {

+    return addElementsToStringBuilder(items, max).toString();   

+  }

+  

+  /**

+   * @param items to print

+   * @param max - maximum number of items to print

+   * @param appender - appender function

+   * @param <T> the type of elements in the list

+   * @return  [item1, item2, ... ]

+   */

+  public static <T> String ppList(List<T> items, int max, BiConsumer<StringBuilder, T> appender) {

+    return addElementsToStringBuilder(items, max, appender).toString();   

+  }

+  

+  /**

+   * format a list of items for pretty printing as [item1, item2, ... ]

+   * @param indent the amount to use as indentation

+   * @param items to print

+   * @param <T> the type of elements in the list

+   * @return  [item1, item2, ... ]

+   */

+  public static <T> String ppList(int[] indent, List<T> items) {

+    return ppList(indent, items, 1000);

+  }

+  

+  /**

+   * @param indent the amount to use as indentation

+   * @param items to print

+   * @param max - maximum number of items to print

+   * @param <T> the type of elements in the list

+   * @return  [item1, item2, ... ]

+   */

+  public static <T> String ppList(int[] indent, List<T> items, int max) {

+    return addElementsToStringBuilder(items, max).toString();   

+  }

+

+  /**

+   * @param indent the amount to use as indentation

+   * @param items to print

+   * @param max - maximum number of items to print

+   * @param appender - appender function

+   * @param <T> the type of elements in the list

+   * @return  [item1, item2, ... ]

+   */

+  public static <T> String ppList(int[] indent, List<T> items, int max, BiConsumer<StringBuilder, T> appender) {

+    return addElementsToStringBuilder(items, max, appender).toString();   

   }

 

   /**

@@ -465,19 +907,36 @@
   /**

    * Convert a JCas class name (fully qualified) to a UIMA type name 

    *   Normally this is the same, but for two prefixes, it's slightly different

+   *   Also, class names for primitives (int, byte, etc. ) converted to int, byte, etc.

    * @param className the Java JCas class name for a UIMA type, fully qualified

    * @return the fully qualified UIMA Type name 

    */

   public static String javaClassName2UimaTypeName(String className) {

-    if (className.startsWith("org.apache.uima.jcas.cas.")) { 

+    if (className.startsWith("org.apache.uima.jcas.cas.") && 

+        BuiltinTypeKinds.creatableBuiltinJCasClassNames.contains(className)) { 

       return CAS.UIMA_CAS_PREFIX + className.substring("org.apache.uima.jcas.cas.".length());

     }

-    if (className.startsWith("org.apache.uima.jcas.tcas.")) { 

+    if (className.startsWith("org.apache.uima.jcas.tcas.")&& 

+        BuiltinTypeKinds.creatableBuiltinJCasClassNames.contains(className)) { 

       return CAS.UIMA_TCAS_PREFIX + className.substring("org.apache.uima.jcas.tcas.".length());

     }

-    return className;

+    

+    switch (className) {

+    case "boolean": return "uima.cas.Boolean";

+    case "byte":    return "uima.cas.Byte";

+    case "short":   return "uima.cas.Short";

+    case "int":     return "uima.cas.Integer";

+    case "long":    return "uima.cas.Long";

+    case "float":   return "uima.cas.Float";

+    case "double":  return "uima.cas.Double";

+    case "java.lang.String": 

+                    return "uima.cas.String"; 

+    default: return className;

+    }

   }

   

+  

+  

   public static void timeLoops(String title, int iterations, Runnable_withException r) throws Exception {

     long shortest = Long.MAX_VALUE;

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

@@ -527,14 +986,193 @@
     }

   }

   

-  public static <T> Iterable<T> iterable(Iterator<T> iterator) {

-    return new Iterable<T>() {

-      @Override

-      public Iterator<T> iterator() {

-        return iterator;

+

+  // bad idea - the iterator would be tied to another one, not independent

+//  public static <T> Iterable<T> iterable(Iterator<T> iterator) {

+//    return new Iterable<T>() {

+//      @Override

+//      public Iterator<T> iterator() {

+//        return iterator;

+//      }

+//    };

+//  }

+  

+  public static boolean isJava9ea() {

+    return isJava9ea;

+  }

+  

+  /** 

+   * extract the slashified version of the fully qualified class name from

+   * the bytecode for a class

+   * @param bytes the bytecode to extract from

+   * @return the slashified class name eg. x/y/z/Myclass

+   */

+  public static String classNameFromByteCode(byte[] bytes) {

+    ByteBuffer bb = ByteBuffer.wrap(bytes);

+    int temp = (bb.getShort() & 0xffff);  // constant at the beginning

+    assert 0xCAFE == temp;

+    temp = (bb.getShort() & 0xffff);

+    assert 0xBABE == temp;

+    bb.getInt();  // skip major/minor version

+    

+    int constantPoolCount = (bb.getShort() & 0xffff) - 1;  // in bytecode "words"

+    int[] classes = new int[constantPoolCount];

+    String[] strings = new String[constantPoolCount];

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

+      int tagByte = bb.get();

+      switch (tagByte) {

+      case 7: classes[i] = bb.getShort() & 0xffff; break;

+      case 1: strings[i] = readModifiedUTF8(bb); break;

+      case 5: 

+      case 6: bb.getLong(); i++; /* skip next */ break;

+      case 8: bb.getShort(); break;

+      default: bb.getInt(); 

       }

+    }

+    bb.getShort(); // go past access flags

+    int indexIntoConstantPoolOfClassInfo = (bb.getShort() & 0xffff) - 1;

+    return strings[classes[indexIntoConstantPoolOfClassInfo] - 1];

+  }

+  

+  /** 

+   * read ByteBuffer modified UTF into String

+   * see http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4 

+   */

+  private static String readModifiedUTF8(ByteBuffer bb) {

+    int len = bb.getShort() & 0xffff;

+    StringBuilder sb = new StringBuilder();

+    

+    while (len > 0) {

+      int c = bb.get() & 0xff;

+      if ((c & 0x80) == 0 ) {

+        sb.append((char) c);

+        len --;

+      } else if ((c & 0x60) == 0x40) {

+        int r = (c & 0x1f) << 6;

+        c = bb.get() & 0xff;

+        assert 0x80 == (c & 0xc0);

+        r = r | (bb.get() & 0x3f);

+        sb.append((char) r);

+        len -= 2;

+      } else if ((c & 0xf0) == 0xe0)  {

+        int r = c & 0x0f << 6;

+        c = bb.get() & 0xff;

+        assert 0x80 == (c & 0xc0);

+        r = (r | (c & 0x3f)) << 6;

+        c = bb.get() & 0xff;

+        assert 0x80 == (c & 0xc0);

+        r = r | (c & 0x3f);

+        sb.append((char) r);

+        len -= 3;

+      } else {

+        internalError(new UnsupportedEncodingException());

+      }

+    }

+    

+    return sb.toString();

+  }

+  

+  public static <T> List<T> setAsList(Set<T> set) {

+    return new AbstractSequentialList<T>() {

+

+      @Override

+      public ListIterator<T> listIterator(int index) {

+        Iterator<T> it = set.iterator();

+        int[] i = {0};

+        return new ListIterator<T>() {

+

+          @Override

+          public boolean hasNext() {

+            return it.hasNext();

+          }

+

+          @Override

+          public T next() {

+            i[0]++;

+            return it.next();

+          }

+

+          @Override

+          public int nextIndex() {

+            return i[0];

+          }

+

+          @Override

+          public void remove() {

+            it.remove();

+          }

+          

+          @Override public boolean hasPrevious()   {throw new UnsupportedOperationException();}

+          @Override public T       previous()      {throw new UnsupportedOperationException();}

+          @Override public int     previousIndex() {throw new UnsupportedOperationException();}

+          @Override public void    set(T e)        {throw new UnsupportedOperationException();}

+          @Override public void    add(T e)        {throw new UnsupportedOperationException();}          

+        };

+      }

+

+      @Override

+      public int size() {

+        return set.size();

+      }

+      

     };

   }

+  

+  static public boolean contains(String[] strings, String item) {

+    for (String string: strings) {

+      if (Misc.equalStrings(string,  item)) {

+        return true;

+      }

+    }

+    return false;

+  }

+  

+  static public boolean contains(ClassLoader[] cls, ClassLoader cl) {

+    for (ClassLoader item : cls) {

+      if (item == cl) {

+        return true;

+      }

+    }

+    return false;

+  }

+  

+  /**

+   * Issues message at warning or fine level (fine if enabled, includes stack trace)

+   * @param errorCount the count of errors used to decrease the frequency

+   * @param message the message

+   * @param logger the logger to use

+   */

+  public static void decreasingWithTrace(AtomicInteger errorCount, String message, Logger logger) {

+    if (logger != null) {

+      final int c = errorCount.incrementAndGet();

+      final int cTruncated = Integer.highestOneBit(c); 

+      // log with decreasing frequency

+      if (cTruncated == c) {

+        if (logger.isLoggable(Level.FINE)) {

+          try { throw new Throwable();}

+          catch (Throwable e) {

+            ByteArrayOutputStream baos = new ByteArrayOutputStream();

+            PrintStream ps = new PrintStream(baos);

+            e.printStackTrace(ps);

+            message = "Message count: " + c + "; " + message + " Message count indicates messages skipped to avoid potential flooding.\n" + baos.toString();

+            logger.log(Level.FINE, message);

+          }

+        } else {

+          message = "Message count: " + c + "; " + message + " Message count indicates messages skipped to avoid potential flooding.";

+          logger.log(Level.WARNING, message);

+        }

+      }

+    }

+  }

+

+  public static void decreasingMessage(AtomicInteger errorCount, Supplier<String> messageSupplier, Consumer<String> publishMessage) {

+    final int c = errorCount.incrementAndGet();

+    final int cTruncated = Integer.highestOneBit(c);  // 1, 2, 4, 8, etc.

+    if (cTruncated == c) { // only happens for 1, 2, 4, etc

+      String message = "Message count: " + c + "; " + messageSupplier.get() + " Message count indicates messages skipped to avoid potential flooding.";

+      publishMessage.accept(message);

+    }

+  }

 //private static final Function<String, Class> uimaSystemFindLoadedClass;

 //static {

 //  try {

diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/MsgLocalizationClassLoader.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/MsgLocalizationClassLoader.java
index 6fc0df9..e027d79 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/MsgLocalizationClassLoader.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/MsgLocalizationClassLoader.java
@@ -20,8 +20,6 @@
 package org.apache.uima.internal.util;

 

 import java.net.URL;

-import java.util.IdentityHashMap;

-import java.util.Map;

 

 /**

  * Class Loader for loading localized messages

@@ -54,11 +52,25 @@
     }

   }

   

-  static final CallStack csi = new CallStack();

+//  static final CallStack csi = new CallStack();  // not used 2/2018

 

+  /**

+   * One instance of this class made

+   * Must be thread-safe

+   */

   static class CallClimbingClassLoader extends ClassLoader {

-  

-    static final ThreadLocal<ClassLoader> originalTccl = new ThreadLocal<>();

+    

+    /**

+     * This value is set / cleared in a try / finally block, from 

+     * the value of originalContextClassLoader in the 

+     *   two classes org.apache.uima.InternationalizedRuntimeException and

+     *               org.apache.uima.InternationalizedException

+     *               

+     * The purpose is to enable using the class loader from the context where the 

+     * exception was created.

+     */

+    static final ThreadLocal<ClassLoader> original_thread_context_class_loader = new ThreadLocal<>();

+       

     /*

      * Try to load the class itself before delegate the class loading to its parent

      */

@@ -83,78 +95,114 @@
      */

     @Override

     protected Class<?> findClass(String name) throws ClassNotFoundException {

-      Map<ClassLoader,ClassLoader> alreadySearched = new IdentityHashMap<>(7);

-      // get the call stack

-      Class<?>[] cs = new CallStack().getCallStack();

-      // start at the caller of the caller's class loader

-      // cs[0] is getClassContext

-      // cs[1] is getCallStack

-      // cs[2] is this method, find class     

-      for (int i = 3; i < cs.length; i++) {

-        Class<?> callingClass = cs[i];

-        ClassLoader cl = callingClass.getClassLoader();

-        if (null == cl) { // means system class loader

-          cl = ClassLoader.getSystemClassLoader();

-        }

-        if (null != alreadySearched.get(cl)) {

-          continue;

-        }

-        alreadySearched.put(cl, cl);

-        Class<?> c = null;

-        try {

-          c = cl.loadClass(name);  // include delegation

-          return c;

-        } catch (ClassNotFoundException e) {

-          // leave c == null

-        }      

-      }

+        

       // UIMA-3692, UIMA-4793 try the thread context class loader

       // if not found, will return class not found exception

-      try {

-        ClassLoader cl = originalTccl.get();

-        if (cl != null) {

+      

+      ClassLoader cl = original_thread_context_class_loader.get();

+      if (cl != null) {

+        try {

           return cl.loadClass(name);

+        } catch (ClassNotFoundException e) {}

+      }

+      

+      // 2nd try: the current thread context class loader

+      ClassLoader context_classLoader = Thread.currentThread().getContextClassLoader();

+      if (null != context_classLoader && cl != context_classLoader) {

+        try {

+          return context_classLoader.loadClass(name);

+        } catch (ClassNotFoundException e) {}

+      }

+      

+      // get the call stack; "new" is needed to get the current context call stack

+      ClassLoader[] cls = Misc.getCallingClass_classLoaders();

+      

+      for (ClassLoader ccl : cls) {

+        if (ccl == cl || ccl == context_classLoader) {

+          continue; // alread tried

         }

-      } catch (ClassNotFoundException e) {}

-      // last try: the current thread context class loader

-      return Thread.currentThread().getContextClassLoader().loadClass(name);

+        Class<?> c = null;

+        try {

+          c = ccl.loadClass(name);  // include delegation

+          return c;

+        } catch (ClassNotFoundException e) {}

+      }  // end of for loop, looking through all the super classes      

+      

+      throw new ClassNotFoundException(name);

     }

     

+    

     @Override

     public URL getResource(String name) {

-      Map<ClassLoader,ClassLoader> alreadySearched = new IdentityHashMap<>(7);

-      // get the call stack

-      Class<?>[] cs = new CallStack().getCallStack();

-      // start at the caller of the caller's class loader

-      // cs[0] is getClassContext

-      // cs[1] is getCallStack

-      // cs[2] is this method, find class

-      for (int i = 3; i < cs.length; i++) {

-        Class<?> callingClass = cs[i];

-        ClassLoader cl = callingClass.getClassLoader();

-        if (null == cl) { // means system class loader

-          cl = ClassLoader.getSystemClassLoader();

-        }

-        if (null != alreadySearched.get(cl)) {

-          continue;

-        }

-        alreadySearched.put(cl, cl);

 

-        URL c = cl.getResource(name);  // include delegation

-        if (null != c) {

-          return c;

-        }    

-      }

-      // UIMA-3692, UIMA-4793  try the thread context class loader

+      // UIMA-3692, UIMA-4793 try the thread context class loader

       // if not found, will return class not found exception

-      ClassLoader cl = originalTccl.get();

+      

+      ClassLoader cl = original_thread_context_class_loader.get();

       if (cl != null) {

         URL c = cl.getResource(name);

         if (null != c) {

           return c;

         }

       }

-      return Thread.currentThread().getContextClassLoader().getResource(name);

+      

+      // 2nd try: the current thread context class loader

+      ClassLoader context_classLoader = Thread.currentThread().getContextClassLoader();

+      if (null != context_classLoader && cl != context_classLoader) {

+        URL c = context_classLoader.getResource(name);

+        if (null != c) {

+          return c;

+        }

+      }

+      

+      ClassLoader[] cls = Misc.getCallingClass_classLoaders();

+      

+      for (ClassLoader ccl : cls) {

+        if (ccl == cl || ccl == context_classLoader) {

+          continue; // alread tried

+        }

+        URL c = ccl.getResource(name);

+        if (null != c) {

+          return c;

+        }

+      }  // end of for loop, looking through all the super classes      

+ 

+      return null;

+    

+//      Map<ClassLoader,ClassLoader> alreadySearched = new IdentityHashMap<>(7);

+//      // get the call stack

+//      Class<?>[] cs = new CallStack().getCallStack();

+//      // start at the caller of the caller's class loader

+//      // cs[0] is getClassContext

+//      // cs[1] is getCallStack

+//      // cs[2] is this method, find class

+//      for (int i = 3; i < cs.length; i++) {

+//        Class<?> callingClass = cs[i];

+//        ClassLoader cl = callingClass.getClassLoader();

+//        if (null == cl) { // means system class loader

+//          cl = ClassLoader.getSystemClassLoader();

+//        }

+//        if (null != alreadySearched.get(cl)) {

+//          continue;

+//        }

+//        alreadySearched.put(cl, cl);

+//

+//        URL c = cl.getResource(name);  // include delegation

+//        if (null != c) {

+//          return c;

+//        }    

+//      }

+//      // UIMA-3692, UIMA-4793  try the thread context class loader

+//      // if not found, will return class not found exception

+//      ClassLoader cl = original_thread_context_class_loader.get();

+//      if (cl != null) {

+//        URL c = cl.getResource(name);

+//        if (null != c) {

+//          return c;

+//        }

+//      }

+//      return Thread.currentThread().getContextClassLoader().getResource(name);

+//    }

     }

   }

   

diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/Obj2IntIdentityHashMap.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/Obj2IntIdentityHashMap.java
index 0e1648a..a97f3a0 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/Obj2IntIdentityHashMap.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/Obj2IntIdentityHashMap.java
@@ -23,8 +23,6 @@
 import java.util.Arrays;

 import java.util.NoSuchElementException;

 

-import org.apache.uima.cas.FeatureStructure;

-

 /**

  * A Map from non-null Objects of type T to ints

  *   int value 0 reserved to mean object is not in the table.

@@ -38,33 +36,26 @@
  * so find operations continue to work (they can't stop upon finding this object).

  *

  */

-public class Obj2IntIdentityHashMap<T> {

+public class Obj2IntIdentityHashMap<T> extends Common_hash_support {

   

-  public static final float DEFAULT_LOAD_FACTOR = 0.66F;

-  // set to true to collect statistics for tuning

-  // you have to also put a call to showHistogram() at the end of the run

-  private static final boolean TUNE = false;

-

   private final T removedMarker;

 

   private final Class<T> componentType;  // for rieifying the T type

    

-  private final float loadFactor = DEFAULT_LOAD_FACTOR;  

+//  private final float loadFactor = DEFAULT_LOAD_FACTOR;  

   

-  private final int initialCapacity; 

+//  private final int initialCapacity; 

 

-  private int histogram [];

-  private int maxProbe = 0;

 

-  private int sizeWhichTriggersExpansion;

-  private int size; // number of elements in the table

-  private int nbrRemoved; // number of removed elements (coded as removed)

+//  private int sizeWhichTriggersExpansion;

+//  private int size; // number of elements in the table

+//  private int nbrRemoved; // number of removed elements (coded as removed)

   

   // the actual Object table

   private T [] keys;

   private int [] values;

 

-  private boolean secondTimeShrinkable = false;

+//  private boolean secondTimeShrinkable = false;

   

   

   public Obj2IntIdentityHashMap(Class<T> clazz, T removedMarker) {

@@ -77,33 +68,26 @@
    * @param removedMarker - a unique value never stored in the table, used to mark removed items

    */

   public Obj2IntIdentityHashMap(int initialCapacity, Class<T> clazz, T removedMarker) {

+    super(initialCapacity);

     this.componentType = clazz;

-    initialCapacity = Misc.nextHigherPowerOf2(initialCapacity);

-    this.initialCapacity = initialCapacity;

-    newTableKeepSize(initialCapacity);

-    size = 0;

-    if (TUNE) {

-      histogram = new int[200];

-      Arrays.fill(histogram, 0);

-      maxProbe = 0;

-    }

     this.removedMarker = removedMarker;

+    newTable(this.initialCapacity);

   }

   

-  private void newTableKeepSize(int capacity) {

-    keys = (T[]) Array.newInstance(componentType, capacity);

-    values = new int[capacity];

-    sizeWhichTriggersExpansion = (int)(capacity * loadFactor);

-    nbrRemoved = 0;

-  }

-

-  private void incrementSize() {

-    if (size + nbrRemoved >= sizeWhichTriggersExpansion) {

-      increaseTableCapacity();

-    }

-    size++;

-  }

-        

+//  private void newTableKeepSize(int capacity) {

+//    keys = (T[]) Array.newInstance(componentType, capacity);

+//    values = new int[capacity];

+//    sizeWhichTriggersExpansion = (int)(capacity * loadFactor);

+//    nbrRemoved = 0;

+//  }

+//

+//  private void incrementSize() {

+//    if (size + nbrRemoved >= sizeWhichTriggersExpansion) {

+//      increaseTableCapacity();

+//    }

+//    size++;

+//  }

+//        

 //  public boolean wontExpand() {

 //    return wontExpand(1);

 //  }

@@ -111,65 +95,65 @@
 //  public boolean wontExpand(int n) {

 //    return (size + nbrRemoved + n) < sizeWhichTriggersExpansion;  

 //  }

-  

-  public int getCapacity() {

-    return keys.length;

-  }

-    

-  /**

-   * This may not increase the table capacity, but may just 

-   * clean out the REMOVED items

-   */

-  private void increaseTableCapacity() {

-    final int oldCapacity = getCapacity();

-    // keep same capacity if just removing the "removed" markers would 

-    // shrink the used slots to the same they would have been had there been no removed, and 

-    // the capacity was doubled.

-    final int newCapacity = (nbrRemoved > size) ? oldCapacity : oldCapacity << 1;

-    

-    final T [] oldKeys = keys;

-    final int [] oldValues = values;

-    if (TUNE) {System.out.println("Capacity increasing from " + oldCapacity + " to " + newCapacity);}

-    newTableKeepSize(newCapacity);

-    for (int i = 0; i < oldKeys.length; i++) {

-      T key = oldKeys[i];

-      if (key != null && key != removedMarker) {

-        addInner(key, oldValues[i]);

-      }

-    }

-  }

-  

-  // called by clear

-  private void newTable(int capacity) {

-    newTableKeepSize(capacity);

-    resetTable();

-  }

-

-  private void resetHistogram() {

-    if (TUNE) {

-      histogram = new int[200];

-      Arrays.fill(histogram, 0);

-      maxProbe = 0;

-    }

-  }

-  

-  private void resetArray() {

-    Arrays.fill(keys, null);

-    Arrays.fill(values,  0);

-    resetTable();

-  }

-  

-  private void resetTable() {

-    resetHistogram();

-    size = 0;

-  }

-  

-  public void clear() {

-    secondTimeShrinkable = Misc.maybeShrink(

-        secondTimeShrinkable, size, getCapacity(), 2, initialCapacity,

-        newCapacity -> newTable(newCapacity),

-        () -> resetArray());

-  }

+//  

+//  public int getCapacity() {

+//    return keys.length;

+//  }

+//    

+//  /**

+//   * This may not increase the table capacity, but may just 

+//   * clean out the REMOVED items

+//   */

+//  private void increaseTableCapacity() {

+//    final int oldCapacity = getCapacity();

+//    // keep same capacity if just removing the "removed" markers would 

+//    // shrink the used slots to the same they would have been had there been no removed, and 

+//    // the capacity was doubled.

+//    final int newCapacity = (nbrRemoved > size) ? oldCapacity : oldCapacity << 1;

+//    

+//    final T [] oldKeys = keys;

+//    final int [] oldValues = values;

+//    if (TUNE) {System.out.println("Capacity increasing from " + oldCapacity + " to " + newCapacity);}

+//    newTableKeepSize(newCapacity);

+//    for (int i = 0; i < oldKeys.length; i++) {

+//      T key = oldKeys[i];

+//      if (key != null && key != removedMarker) {

+//        putInner(key, oldValues[i]);

+//      }

+//    }

+//  }

+//  

+//  // called by clear

+//  private void newTable(int capacity) {

+//    newTableKeepSize(capacity);

+//    resetTable();

+//  }

+//

+//  private void resetHistogram() {

+//    if (TUNE) {

+//      histogram = new int[200];

+//      Arrays.fill(histogram, 0);

+//      maxProbe = 0;

+//    }

+//  }

+//  

+//  private void resetArray() {

+//    Arrays.fill(keys, null);

+//    Arrays.fill(values,  0);

+//    resetTable();

+//  }

+//  

+//  private void resetTable() {

+//    resetHistogram();

+//    size = 0;

+//  }

+//  

+//  public void clear() {

+//    secondTimeShrinkable = Misc.maybeShrink(

+//        secondTimeShrinkable, size, getCapacity(), 2, initialCapacity,

+//        newCapacity -> newTable(newCapacity),

+//        () -> resetArray());

+//  }

 

   /** 

   * returns a position in the key/value table

@@ -182,43 +166,57 @@
   * @return the probeAddr in keys array - might reference a slot holding null, or the key value if found

   */

   private int findPosition(final T obj) {

-    return findPosition(obj, false);

-  }

-  

-  private int findPosition(final T obj, final boolean includeRemoved) {

     if (obj == null) {

       throw new IllegalArgumentException("null is an invalid key");

     }

-

-    final int hash = Misc.hashInt(System.identityHashCode(obj));  // identity hash map

-    int nbrProbes = 1;

-    int probeDelta = 1;

-    int probeAddr;

     

-    final T[] localKeys = keys;

-    final int bitMask = localKeys.length - 1;

-    probeAddr = hash & bitMask;

-    while (true) {

-      final T testKey = localKeys[probeAddr];

-      if (testKey == null || testKey == obj || (includeRemoved && testKey == removedMarker)) { 

-        break;

-      }

-      

-      nbrProbes++;

-      probeAddr = bitMask & (probeAddr + (probeDelta++));

-    }

-

-    if (TUNE) {

-      final int pv = histogram[nbrProbes];

-

-      histogram[nbrProbes] = 1 + pv;

-      if (maxProbe < nbrProbes) {

-        maxProbe = nbrProbes;

-      }

-    }

-

-    return probeAddr;

+    return findPosition( 

+        

+        // key hash

+        Misc.hashInt(System.identityHashCode(obj)),

+        

+        // is_eq_or_is_not_present

+        i -> keys[i] == null || keys[i] == obj,

+        

+        // is_removed_key

+        i -> keys[i] == removedMarker);

+    

   }

+  

+//  private int findPosition(final T obj, final boolean includeRemoved) {

+//    if (obj == null) {

+//      throw new IllegalArgumentException("null is an invalid key");

+//    }

+//

+//    final int hash = Misc.hashInt(System.identityHashCode(obj));  // identity hash map

+//    int nbrProbes = 1;

+//    int probeDelta = 1;

+//    int probeAddr;

+//    

+//    final T[] localKeys = keys;

+//    final int bitMask = localKeys.length - 1;

+//    probeAddr = hash & bitMask;

+//    while (true) {

+//      final T testKey = localKeys[probeAddr];

+//      if (testKey == null || testKey == obj || (includeRemoved && testKey == removedMarker)) { 

+//        break;

+//      }

+//      

+//      nbrProbes++;

+//      probeAddr = bitMask & (probeAddr + (probeDelta++));

+//    }

+//

+//    if (TUNE) {

+//      final int pv = histogram[nbrProbes];

+//

+//      histogram[nbrProbes] = 1 + pv;

+//      if (maxProbe < nbrProbes) {

+//        maxProbe = nbrProbes;

+//      }

+//    }

+//

+//    return probeAddr;

+//  }

 

   public boolean contains(Object obj) {  // arg must be Object to fit Collection API

     return (componentType.isAssignableFrom(obj.getClass())) ? (find((T) obj) != -1) : false;

@@ -229,17 +227,20 @@
    * @return the position of obj in the table, or -1 if not in the table

    */

   public int find(T obj) {

-    if (obj == null || size == 0) {

+    if (obj == null || size() == 0) {

       return -1;

     }

     

     final int pos = findPosition(obj);

-    return (keys[pos] == obj) ? pos : -1;

+    return (obj == keys[pos]) ? pos : -1;  // == because identity hash map

   }

       

   public int get(T obj) {

-    int pos = find(obj);

-    return (pos >= 0) ? values[pos] : 0;

+    if (obj == null || size() == 0) {

+      return 0;

+    }

+    int pos = findPosition(obj);

+    return values[pos];

   }

   

   /**

@@ -249,33 +250,27 @@
    * @return the previous value, or 0 if this map did not already contain the specified key

    */

   public int put(T obj, int value) {

-    if (obj == null) {

-      throw new IllegalArgumentException("argument must be non-null");

-    }

-           

-    final int i = findPosition(obj, true);  // include REMOVED

+    int i = findPosition(obj); 

     if (keys[i] == obj) {  // identityHashMap

-      int r = values[i];

+      int prevValue = values[i];

       values[i] = value;

-      return r;  

+      return prevValue;  

     }

-    

-    if (keys[i] == removedMarker) {

-      nbrRemoved --;

-      assert (nbrRemoved >= 0);

+   

+    if (found_removed != -1) {

+      i = found_removed;

     }

     keys[i] = obj;

-    int r = values[i];

     values[i] = value;

-    incrementSize();

-    return r;

+    commonPutOrAddNotFound();

+    return 0;

   }

         

   /**

    * used for increasing table size

    * @param rawKey

    */

-  private void addInner(T obj, int value) {

+  private void putInner(T obj, int value) {

     final int i = findPosition(obj);

     assert(keys[i] == null);

     keys[i] = obj;

@@ -296,48 +291,56 @@
     }

     

     final int pos = findPosition((T) rawKey);  // null or equal obj

+    int r = values[pos];

     

-    return (rawKey == keys[pos]) ? removeAtPosition(pos) : 0;

+    if (rawKey == keys[pos]) {

+      values[pos] = 0;

+      keys[pos] = removedMarker;

+      commonRemove();

+    }

+    

+    return r;

+    

   } 

   

-  private int removeAtPosition(int pos) { 

-    // found, remove it

-    keys[pos] = (T) removedMarker;  // at runtime, this cast is a no-op

-    int r = values[pos];

-    values[pos] = 0;

-    size--;

-    nbrRemoved ++;

-    return r;

-  }

-  

-  public int size() {

-    return size;

-  }

-  

-  public void showHistogram() {

-    if (TUNE) {

-      int sumI = 0;

-      for (int i : histogram) {

-        sumI += i;

-      }

-      

-      System.out.format(

-          "Histogram of number of probes, loadfactor = %.1f, maxProbe=%,d nbr of find operations at last table size=%,d%n",

-          loadFactor, maxProbe, sumI);

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

-        if (i == maxProbe && histogram[i] == 0) {

-          System.out.println("huh?");

-        }

-        System.out.println(i + ": " + histogram[i]);

-      }     

-      

-      System.out.println("bytes / entry = " + (float) (keys.length) * 4 / size());

-      System.out.format("size = %,d, prevExpansionTriggerSize = %,d, next = %,d%n",

-        size(),

-        (int) ((keys.length >>> 1) * loadFactor),

-        (int) (keys.length * loadFactor));        

-    }

-  }

+//  private int removeAtPosition(int pos) { 

+//    // found, remove it

+//    keys[pos] = (T) removedMarker;  // at runtime, this cast is a no-op

+//    int r = values[pos];

+//    values[pos] = 0;

+//    size--;

+//    nbrRemoved ++;

+//    return r;

+//  }

+//  

+//  public int size() {

+//    return size;

+//  }

+//  

+//  public void showHistogram() {

+//    if (TUNE) {

+//      int sumI = 0;

+//      for (int i : histogram) {

+//        sumI += i;

+//      }

+//      

+//      System.out.format(

+//          "Histogram of number of probes, loadfactor = %.1f, maxProbe=%,d nbr of find operations at last table size=%,d%n",

+//          loadFactor, maxProbe, sumI);

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

+//        if (i == maxProbe && histogram[i] == 0) {

+//          System.out.println("huh?");

+//        }

+//        System.out.println(i + ": " + histogram[i]);

+//      }     

+//      

+//      System.out.println("bytes / entry = " + (float) (keys.length) * 4 / size());

+//      System.out.format("size = %,d, prevExpansionTriggerSize = %,d, next = %,d%n",

+//        size(),

+//        (int) ((keys.length >>> 1) * loadFactor),

+//        (int) (keys.length * loadFactor));        

+//    }

+//  }

   

 //  /**

 //   */

@@ -353,65 +356,67 @@
 //    }

 //    return values[index];

 //  }

-  

-  /**

-   * advance pos until it points to a non 0 or is 1 past end

-   * @param pos -

-   * @return updated pos

-   */

-  public int moveToNextFilled(int pos) {

-    if (pos < 0) {

-      pos = 0;

-    }

-    

-    final int max = getCapacity();

-    while (true) {

-      if (pos >= max) {

-        return pos;

-      }

-      Object v = keys[pos];

-      if (v != null && v != removedMarker) {

-        return pos;

-      }

-      pos ++;

-    }

-  }

-   

-  /**

-   * decrement pos until it points to a non 0 or is -1

-   * @param pos -

-   * @return updated pos

-   */

-  public int moveToPreviousFilled(int pos) {

-    final int max = getCapacity();

-    if (pos > max) {

-      pos = max - 1;

-    }

-    

-    while (true) {

-      if (pos < 0) {

-        return pos;

-      }

-      T v = keys[pos];

-      if (v != null && v != removedMarker) {

-        return pos;

-      }

-      pos --;

-    }

-  }

-

+//  

+//  /**

+//   * advance pos until it points to a non 0 or is 1 past end

+//   * @param pos -

+//   * @return updated pos

+//   */

+//  public int moveToNextFilled(int pos) {

+//    if (pos < 0) {

+//      pos = 0;

+//    }

+//    

+//    final int max = getCapacity();

+//    while (true) {

+//      if (pos >= max) {

+//        return pos;

+//      }

+//      Object v = keys[pos];

+//      if (v != null && v != removedMarker) {

+//        return pos;

+//      }

+//      pos ++;

+//    }

+//  }

+//   

+//  /**

+//   * decrement pos until it points to a non 0 or is -1

+//   * @param pos -

+//   * @return updated pos

+//   */

+//  public int moveToPreviousFilled(int pos) {

+//    final int max = getCapacity();

+//    if (pos > max) {

+//      pos = max - 1;

+//    }

+//    

+//    while (true) {

+//      if (pos < 0) {

+//        return pos;

+//      }

+//      T v = keys[pos];

+//      if (v != null && v != removedMarker) {

+//        return pos;

+//      }

+//      pos --;

+//    }

+//  }

+//

   private class Obj2IntIdentityHashMapIterator implements IntListIterator {

 

-    protected int curPosition;

+    /** always keep at valid position */

+    private int curPosition;

+    private final int firstPosition;

 

     private Obj2IntIdentityHashMapIterator() {

       this.curPosition = moveToNextFilled(0);

+      this.firstPosition = this.curPosition;

     }

 

     @Override

     public final boolean hasNext() {

-      curPosition = moveToNextFilled(curPosition);

-      return curPosition < getCapacity();

+      return curPosition < keys_length() && curPosition >= 0;

     }

 

     @Override

@@ -421,7 +426,7 @@
       }

       int r = values[curPosition];

       curPosition = moveToNextFilled(curPosition + 1);

-      return r;

+      return r; 

     }

 

     // if uncomment this, need to add it to the IntListIterator Interface

@@ -431,22 +436,32 @@
 //        removeAtPosition(pos);

 //      } 

 //    }

+    

+    @Override

+    public final int nextNvc() {

+      int r = values[curPosition];

+      curPosition = moveToNextFilled(curPosition + 1);

+      return r;      

+    }

 

     @Override

     public boolean hasPrevious() {

-      // TODO Auto-generated method stub

-      return false;

+      throw new UnsupportedOperationException();

     }

 

     @Override

     public int previous() {

-      // TODO Auto-generated method stub

-      return 0;

+      throw new UnsupportedOperationException();

+    }

+    

+    @Override

+    public int previousNvc() {

+      throw new UnsupportedOperationException();     

     }

 

     @Override

     public void moveToStart() {

-      this.curPosition = moveToNextFilled(0);

+      this.curPosition = firstPosition;

     }

 

     @Override

@@ -470,48 +485,48 @@
     return new Obj2IntIdentityHashMapIterator();

   }

   

-  public int moveToFirst() {

-    return (size() == 0) ? -1 : moveToNextFilled(0);

-  }

-

-  public int moveToLast() {

-    return (size() == 0) ? -1 : moveToPreviousFilled(getCapacity() -1);

-  }

-

-  public int moveToNext(int position) {

-    if (position < 0) {

-      return position;

-    }

-    final int n = moveToNextFilled(position + 1); 

-    return (n >= getCapacity()) ? -1 : n;

-  }

-

-  public int moveToPrevious(int position) {

-    if (position >= getCapacity()) {

-      return -1;

-    }

-    return moveToPreviousFilled(position - 1);

-  }

-

-  public boolean isValid(int position) {

-    return (position >= 0) && (position < getCapacity());

-  }

-  

-  /**

-   * if the fs is in the set, the iterator should return it.

-   * if not, move to the first - just to return something.

-   * @param fs position to this fs

-   * @return the index if present, otherwise moveToNextFileed(0);

-   */

-  public int moveTo(FeatureStructure fs) {

-    if (componentType.isAssignableFrom(fs.getClass())) {

-      int pos = find((T)fs);

-      if (pos >= 0) {

-        return pos;

-      }

-    }

-    return moveToFirst(); 

-  }

+//  public int moveToFirst() {

+//    return (size() == 0) ? -1 : moveToNextFilled(0);

+//  }

+//

+//  public int moveToLast() {

+//    return (size() == 0) ? -1 : moveToPreviousFilled(getCapacity() -1);

+//  }

+//

+//  public int moveToNext(int position) {

+//    if (position < 0) {

+//      return position;

+//    }

+//    final int n = moveToNextFilled(position + 1); 

+//    return (n >= getCapacity()) ? -1 : n;

+//  }

+//

+//  public int moveToPrevious(int position) {

+//    if (position >= getCapacity()) {

+//      return -1;

+//    }

+//    return moveToPreviousFilled(position - 1);

+//  }

+//

+//  public boolean isValid(int position) {

+//    return (position >= 0) && (position < getCapacity());

+//  }

+//  

+//  /**

+//   * if the fs is in the set, the iterator should return it.

+//   * if not, move to the first - just to return something.

+//   * @param fs position to this fs

+//   * @return the index if present, otherwise moveToNextFileed(0);

+//   */

+//  public int moveTo(FeatureStructure fs) {

+//    if (componentType.isAssignableFrom(fs.getClass())) {

+//      int pos = find((T)fs);

+//      if (pos >= 0) {

+//        return pos;

+//      }

+//    }

+//    return moveToFirst(); 

+//  }

 

   /* (non-Javadoc)

    * @see java.lang.Object#toString()

@@ -521,12 +536,53 @@
     return String

         .format(

             "%s [loadFactor=%s, initialCapacity=%s, sizeWhichTriggersExpansion=%s, size=%s, secondTimeShrinkable=%s%n keys=%s]",

-            this.getClass().getName(), loadFactor, initialCapacity, sizeWhichTriggersExpansion, size, secondTimeShrinkable, 

+            this.getClass().getName(), loadFactor, initialCapacity, sizeWhichTriggersExpansion, size(), secondTimeShrinkable, 

             Arrays.toString(keys));

   }

 

-  public boolean isEmpty() {

-    return size == 0;

-  }

+@Override

+protected boolean is_valid_key(int pos) {

+  return keys[pos] != null && keys[pos] != removedMarker;

+}

+

+@Override

+protected int keys_length() {

+  return keys.length;

+}

+

+@Override

+protected void newKeysAndValues(int capacity) {

+  keys = (T[]) Array.newInstance(componentType, capacity);

+  values = new int[capacity];

+  

+}

+

+@Override

+protected void clearKeysAndValues() {

+  Arrays.fill(keys, null);

+  Arrays.fill(values,  0);

+}

+

+@Override

+protected void copy_to_new_table(

+    /* ignored */int newCapacity,

+    /* ignored */int oldCapacity,

+    CommonCopyOld2New commonCopy) {

+  

+  final T[] oldKeys = keys;

+  final int[] oldValues = values;

+  commonCopy.apply(

+    

+    // copyToNew

+    i -> putInner(oldKeys[i], oldValues[i]),

+    

+    // is_valid_old_key

+    i -> oldKeys[i] != null && oldKeys[i] != removedMarker

+    );

+}

+

+//  public boolean isEmpty() {

+//    return size() == 0;

+//  }

 

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/ObjHashSet.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/ObjHashSet.java
index cc31f88..fb1952b 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/ObjHashSet.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/ObjHashSet.java
@@ -40,35 +40,33 @@
  * so find operations continue to work (they can't stop upon finding this object).

  *

  */

-public class ObjHashSet<T> implements Set<T> {

+public class ObjHashSet<T> extends Common_hash_support implements Set<T> {

   

-  public static final float DEFAULT_LOAD_FACTOR = 0.66F;

-  // set to true to collect statistics for tuning

-  // you have to also put a call to showHistogram() at the end of the run

-  private static final boolean TUNE = false;

+//  public static final float DEFAULT_LOAD_FACTOR = 0.66F;

 

+  /** the object of type T indicating key is removed */

   private final T removedMarker;

 

   private final Class<T> clazz;  // for reifying the T type

    

-  private final float loadFactor = DEFAULT_LOAD_FACTOR;  

+//  private final float loadFactor = DEFAULT_LOAD_FACTOR;  

   

-  private final int initialCapacity; 

-

-  private int histogram [];

-  private int maxProbe = 0;

-

-  private int sizeWhichTriggersExpansion;

-  private int size; // number of elements in the table

-  private int nbrRemoved; // number of removed elements (coded as removed)

+//  private final int initialCapacity; 

+//

+//  private int histogram [];

+//  private int maxProbe = 0;

+//

+//  private int sizeWhichTriggersExpansion;

+//  private int size; // number of elements in the table

+//  private int nbrRemoved; // number of removed elements (coded as removed)

   

   // the actual Object table, operated as a hashtable

   private T [] keys;

-  private T [] emptyKeyArray = null;  

+//  final private T [] emptyKeyArray;  

 

-  private boolean secondTimeShrinkable = false;

+//  private boolean secondTimeShrinkable = false;

   

-  private int modificationCount = 0;

+//  private int modificationCount = 0; // not currently used

   

   public ObjHashSet(Class<T> clazz, T removedMarker) {

     this(12, clazz, removedMarker);  // default initial size

@@ -80,15 +78,17 @@
    * @param removedMarker - a unique value never stored in the table, used to mark removed items

    */

   public ObjHashSet(int initialCapacity, Class<T> clazz, T removedMarker) {

+    super(initialCapacity);

     this.clazz = clazz;

-    this.initialCapacity = initialCapacity;

-    newTableKeepSize(initialCapacity);

-    size = 0;

-    if (TUNE) {

-      histogram = new int[200];

-      Arrays.fill(histogram, 0);

-      maxProbe = 0;

-    }

+//    this.emptyKeyArray = (T[]) Array.newInstance(clazz, 1);

+//    this.initialCapacity = initialCapacity;

+    newTable(initialCapacity);

+//    size = 0;

+//    if (TUNE) {

+//      histogram = new int[200];

+//      Arrays.fill(histogram, 0);

+//      maxProbe = 0;

+//    }

     this.removedMarker = removedMarker;

   }

   

@@ -97,55 +97,46 @@
    * @param ohs -

    */

   public ObjHashSet(ObjHashSet<T> ohs) {

+    super(ohs);

     this.removedMarker = ohs.removedMarker;

     this.clazz = ohs.clazz;

-    this.initialCapacity = ohs.initialCapacity;

-    this.histogram = ohs.histogram;

-    this.maxProbe = ohs.maxProbe;

-    this.sizeWhichTriggersExpansion = ohs.sizeWhichTriggersExpansion;

-    this.size = ohs.size;

-    this.nbrRemoved = ohs.nbrRemoved;

-    this.keys = ohs.keys.clone();

-    this.secondTimeShrinkable = ohs.secondTimeShrinkable;

-    this.modificationCount = ohs.modificationCount;

+//    this.initialCapacity = ohs.initialCapacity;

+//    this.histogram = ohs.histogram;

+//    this.maxProbe = ohs.maxProbe;

+//    this.sizeWhichTriggersExpansion = ohs.sizeWhichTriggersExpansion;

+//    this.size = ohs.size;

+//    this.nbrRemoved = ohs.nbrRemoved;

+    this.keys = Arrays.copyOf(ohs.keys, ohs.keys.length);

+//    this.secondTimeShrinkable = ohs.secondTimeShrinkable;

+//    this.modificationCount = ohs.modificationCount;

   }

   

 

   public ObjHashSet(ObjHashSet<T> ohs, boolean readOnly) {

+    this(ohs);

     if (!readOnly) Misc.internalError();

-    this.removedMarker = ohs.removedMarker;

-    this.clazz = ohs.clazz;

-    this.initialCapacity = ohs.initialCapacity;

-    this.histogram = ohs.histogram;

-    this.maxProbe = ohs.maxProbe;

-    this.sizeWhichTriggersExpansion = ohs.sizeWhichTriggersExpansion;

-    this.size = ohs.size;

-    this.nbrRemoved = ohs.nbrRemoved;

-    this.keys = (size == 0) ? emptyKeyArray() : ohs.keys.clone();

-    this.secondTimeShrinkable = ohs.secondTimeShrinkable;

-    this.modificationCount = ohs.modificationCount;

   }

 

-  private T[] emptyKeyArray() {

-    if (emptyKeyArray == null) {

-      emptyKeyArray = (T[]) Array.newInstance(clazz, 1);

-    }

-    return emptyKeyArray;

-  }

+//  private T[] emptyKeyArray() {

+//    if (emptyKeyArray == null) {

+//      emptyKeyArray = (T[]) Array.newInstance(clazz, 1);

+//    }

+//    return emptyKeyArray;

+//  }

   

-  private void newTableKeepSize(int capacity) {

-    capacity = Misc.nextHigherPowerOf2(capacity);

-    keys = (T[]) Array.newInstance(clazz, capacity);

-    sizeWhichTriggersExpansion = (int)(capacity * loadFactor);

-    nbrRemoved = 0;

-  }

+//  private void newTableKeepSize(int capacity) {

+//    capacity = Misc.nextHigherPowerOf2(capacity);

+//    keys = (T[]) Array.newInstance(clazz, capacity);

+//    sizeWhichTriggersExpansion = (int)(capacity * loadFactor);

+//    nbrRemoved = 0;

+//  }

 

-  private void incrementSize() {

-    if (size + nbrRemoved >= sizeWhichTriggersExpansion) {

-      increaseTableCapacity();

-    }

-    size++;

-  }

+//  private void incrementSize() {

+//    if (size + nbrRemoved >= sizeWhichTriggersExpansion) {

+//      maybeIncreaseTableCapacity();

+//    }

+//    size++;

+//  }

         

 //  public boolean wontExpand() {

 //    return wontExpand(1);

@@ -154,84 +145,84 @@
 //  public boolean wontExpand(int n) {

 //    return (size + nbrRemoved + n) < sizeWhichTriggersExpansion;  

 //  }

-  /**

-   * @return the current capacity, &gt;= size

-   */

-  public int getCapacity() {

-    return keys.length;

-  }

+//  /**

+//   * @return the current capacity, &gt;= size

+//   */

+//  public int getCapacity() {

+//    return keys.length;

+//  }

     

-  /**

-   * This may not increase the table capacity, but may just 

-   * clean out the REMOVED items

-   */

-  private void increaseTableCapacity() {

-    final int oldCapacity = getCapacity();

-    // keep same capacity if just removing the "removed" markers would 

-    // shrink the used slots to the same they would have been had there been no removed, and 

-    // the capacity was doubled.

-    final int newCapacity = (nbrRemoved > size) ? oldCapacity : oldCapacity << 1;

-    

-    final T [] oldKeys = keys;      

-    if (TUNE) {System.out.println("Capacity increasing from " + oldCapacity + " to " + newCapacity);}

-    newTableKeepSize(newCapacity);

-    for (T key : oldKeys) {

-      if (key != null && key != removedMarker) {

-        addInner(key);

-      }

-    }

-  }

+//  /**

+//   * This may not increase the table capacity, but may just 

+//   * clean out the REMOVED items

+//   */

+//  private void maybeIncreaseTableCapacity() {

+//    final int oldCapacity = getCapacity();

+//    // keep same capacity if just removing the "removed" markers would 

+//    // shrink the used slots to the same they would have been had there been no removed, and 

+//    // the capacity was doubled.

+//    final int newCapacity = (nbrRemoved > size) ? oldCapacity : oldCapacity << 1;

+//    

+//    final T [] oldKeys = keys;      

+//    if (TUNE) {System.out.println("Capacity increasing from " + oldCapacity + " to " + newCapacity);}

+//    newTableKeepSize(newCapacity);

+//    for (T key : oldKeys) {

+//      if (key != null && key != removedMarker) {

+//        addInner(key);

+//      }

+//    }

+//  }

   

-  // called by clear

-  private void newTable(int capacity) {

-    newTableKeepSize(capacity);

-    resetTable();

-  }

-

-  private void resetHistogram() {

-    if (TUNE) {

-      histogram = new int[200];

-      Arrays.fill(histogram, 0);

-      maxProbe = 0;

-    }

-  }

+//  // called by clear

+//  private void newTable(int capacity) {

+//    newTableKeepSize(capacity);

+//    resetTable();

+//  }

+//

+//  private void resetHistogram() {

+//    if (TUNE) {

+//      histogram = new int[200];

+//      Arrays.fill(histogram, 0);

+//      maxProbe = 0;

+//    }

+//  }

+//  

+//  private void resetArray() {

+//    Arrays.fill(keys, null);

+//    resetTable();

+//  }

+//  

+//  private void resetTable() {

+//    resetHistogram();

+//    size = 0;

+////    modificationCount ++;

+//  }

   

-  private void resetArray() {

-    Arrays.fill(keys, null);

-    resetTable();

-  }

-  

-  private void resetTable() {

-    resetHistogram();

-    size = 0;

-    modificationCount ++;

-  }

-  

-  @Override

-  public void clear() {

-    // see if size is less than the 1/4 size that triggers expansion

-    if (size <  (sizeWhichTriggersExpansion >>> 2)) { 

-      // if 2nd time then shrink by 50%

-      //   this is done to avoid thrashing around the threshold

-      if (secondTimeShrinkable) {

-        secondTimeShrinkable = false;

-        final int currentCapacity = getCapacity();

-        final int newCapacity = Math.max(initialCapacity, currentCapacity >>> 1);

-        if (newCapacity < currentCapacity) { 

-          newTable(newCapacity);  // shrink table by 50%

-        } else { // don't shrink below minimum

-          resetArray();

-        }

-        return;

-        

-      } else {

-        secondTimeShrinkable = true;

-      }

-    } else {

-      secondTimeShrinkable = false; // reset this to require 2 triggers in a row

-    }

-   resetArray();

-  }

+//  @Override

+//  public void clear() {

+//    // see if size is less than the 1/4 size that triggers expansion

+//    if (size <  (sizeWhichTriggersExpansion >>> 2)) { 

+//      // if 2nd time then shrink by 50%

+//      //   this is done to avoid thrashing around the threshold

+//      if (secondTimeShrinkable) {

+//        secondTimeShrinkable = false;

+//        final int currentCapacity = getCapacity();

+//        final int newCapacity = Math.max(initialCapacity, currentCapacity >>> 1);

+//        if (newCapacity < currentCapacity) { 

+//          newTable(newCapacity);  // shrink table by 50%

+//        } else { // don't shrink below minimum

+//          resetArray();

+//        }

+//        return;

+//        

+//      } else {

+//        secondTimeShrinkable = true;

+//      }

+//    } else {

+//      secondTimeShrinkable = false; // reset this to require 2 triggers in a row

+//    }

+//   resetArray();

+//  }

 

   /** 

   * returns a position in the key/value table

@@ -243,44 +234,62 @@
   * @param obj the object to find

   * @return the probeAddr in keys array - might reference a slot holding null, or the key value if found

   */

-  private int findPosition(final T obj) {

-    return findPosition(obj, false);

-  }

-  

-  private int findPosition(final T obj, final boolean includeRemoved) {

-    if (obj == null) {

+  private int findPosition(final T key) {

+    if (key == null) {

       throw new IllegalArgumentException("null is an invalid key");

     }

-

-    final int hash = Misc.hashInt(obj.hashCode());

-    int nbrProbes = 1;

-    int probeDelta = 1;

-    int probeAddr;

+    if (key == removedMarker) {

+      throw new IllegalArgumentException("A removed marker is an invalid key");

+    }

     

-    final T[] localKeys = keys;

-    final int bitMask = localKeys.length - 1;

-    probeAddr = hash & bitMask;

-    while (true) {

-      final T testKey = localKeys[probeAddr];

-      if (testKey == null || testKey.equals(obj) || (includeRemoved && testKey == removedMarker)) { 

-        break;

-      }

-      

-      nbrProbes++;

-      probeAddr = bitMask & (probeAddr + (probeDelta++));

-    }

-

-    if (TUNE) {

-      final int pv = histogram[nbrProbes];

-

-      histogram[nbrProbes] = 1 + pv;

-      if (maxProbe < nbrProbes) {

-        maxProbe = nbrProbes;

-      }

-    }

-

-    return probeAddr;

+    return findPosition(

+        

+        // key hash

+        Misc.hashInt(key.hashCode()),

+        

+        // is_eq_or_is_not_present

+        i -> keys[i] == null || keys[i].equals(key),

+        

+        // is removed key

+        i -> keys[i] == removedMarker);

+    

+//    return findPosition(obj, false);

   }

+  

+//  private int findPosition(final T obj, final boolean includeRemoved) {

+//    if (obj == null) {

+//      throw new IllegalArgumentException("null is an invalid key");

+//    }

+//

+//    final int hash = Misc.hashInt(obj.hashCode());

+//    int nbrProbes = 1;

+//    int probeDelta = 1;

+//    int probeAddr;

+//    

+//    final T[] localKeys = keys;

+//    final int bitMask = localKeys.length - 1;

+//    probeAddr = hash & bitMask;

+//    while (true) {

+//      final T testKey = localKeys[probeAddr];

+//      if (testKey == null || testKey.equals(obj) || (includeRemoved && testKey == removedMarker)) { 

+//        break;

+//      }

+//      

+//      nbrProbes++;

+//      probeAddr = bitMask & (probeAddr + (probeDelta++));

+//    }

+//

+//    if (TUNE) {

+//      final int pv = histogram[nbrProbes];

+//

+//      histogram[nbrProbes] = 1 + pv;

+//      if (maxProbe < nbrProbes) {

+//        maxProbe = nbrProbes;

+//      }

+//    }

+//

+//    return probeAddr;

+//  }

 

   @Override

   public boolean contains(Object obj) {  // arg must be Object to fit Collection API

@@ -292,7 +301,7 @@
    * @return the position of obj in the table, or -1 if not in the table

    */

   public int find(T obj) {

-    if (obj == null || size == 0) {

+    if (obj == null || size() == 0) {

       return -1;

     }

     

@@ -306,22 +315,19 @@
    * @return true if this set did not already contain the specified element

    */

   @Override

-  public boolean add(T obj) {

-    if (obj == null) {

-      throw new IllegalArgumentException("argument must be non-null");

-    }

-           

-    final int i = findPosition(obj, true);  // include REMOVED

-    if (obj.equals(keys[i])) {  // keys[i] may be null  

+  public boolean add(T obj) {           

+    final int i = findPosition(obj); 

+    if (obj.equals(keys[i])) { // keys[i] may be null

       return false;  // false if already present

     }

-    if (keys[i] == removedMarker) {

-      nbrRemoved --;

-      assert (nbrRemoved >= 0);

-    }

-    keys[i] = obj;

-    incrementSize();

-    modificationCount ++;

+//    if (keys[i] == removedMarker) {

+//      nbrRemoved --;

+//      assert (nbrRemoved >= 0);

+//    }

+    keys[ (found_removed != -1) ? found_removed : i ] = obj;

+    commonPutOrAddNotFound();

+//    modificationCount ++;

+//    val259();

     return true;

   }

         

@@ -331,8 +337,13 @@
    */

   private void addInner(T obj) {

     final int i = findPosition(obj);

+//    //debug

+//    if (keys[i] != null) {

+//      System.out.println("debug");

+//    }

     assert(keys[i] == null);

     keys[i] = obj;

+//    val259();

   }

   

   /**

@@ -350,51 +361,55 @@
     

     final int pos = findPosition((T) rawKey);  // null or equal obj

     

-    return (rawKey.equals(keys[pos])) ? removeAtPosition(pos) : false;

+    if (keys[pos] == null) {

+      return false;

+    }

+    

+    keys[pos] = removedMarker;

+    commonRemove();

+//    val259();

+    return true;

   } 

   

-  private boolean removeAtPosition(int pos) {

-    // found, remove it

-    keys[pos] = removedMarker;  // at runtime, this cast is a no-op    

-    size --;

-    modificationCount ++;

-    nbrRemoved ++;

-    return true;

+  private void removeAtPosition(int pos) {

+    keys[pos] = removedMarker;  // at runtime, this cast is a no-op

+    commonRemove();

+//    val259();

   }

   

 

-  /**

-   * @see Set#size()

-   */

-  @Override

-  public int size() {

-    return size;

-  }

+//  /**

+//   * @see Set#size()

+//   */

+//  @Override

+//  public int size() {

+//    return size;

+//  }

   

-  public void showHistogram() {

-    if (TUNE) {

-      int sumI = 0;

-      for (int i : histogram) {

-        sumI += i;

-      }

-      

-      System.out.format(

-          "Histogram of number of probes, loadfactor = %.1f, maxProbe=%,d nbr of find operations at last table size=%,d%n",

-          loadFactor, maxProbe, sumI);

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

-        if (i == maxProbe && histogram[i] == 0) {

-          System.out.println("huh?");

-        }

-        System.out.println(i + ": " + histogram[i]);

-      }     

-      

-      System.out.println("bytes / entry = " + (float) (keys.length) * 4 / size());

-      System.out.format("size = %,d, prevExpansionTriggerSize = %,d, next = %,d%n",

-        size(),

-        (int) ((keys.length >>> 1) * loadFactor),

-        (int) (keys.length * loadFactor));        

-    }

-  }

+//  public void showHistogram() {

+//    if (TUNE) {

+//      int sumI = 0;

+//      for (int i : histogram) {

+//        sumI += i;

+//      }

+//      

+//      System.out.format(

+//          "Histogram of number of probes, loadfactor = %.1f, maxProbe=%,d nbr of find operations at last table size=%,d%n",

+//          loadFactor, maxProbe, sumI);

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

+//        if (i == maxProbe && histogram[i] == 0) {

+//          System.out.println("huh?");

+//        }

+//        System.out.println(i + ": " + histogram[i]);

+//      }     

+//      

+//      System.out.println("bytes / entry = " + (float) (keys.length) * 4 / size());

+//      System.out.format("size = %,d, prevExpansionTriggerSize = %,d, next = %,d%n",

+//        size(),

+//        (int) ((keys.length >>> 1) * loadFactor),

+//        (int) (keys.length * loadFactor));        

+//    }

+//  }

   

   /**

    */

@@ -411,51 +426,51 @@
     return obj;

   }

   

-  /**

-   * advance pos until it points to a non 0 or is 1 past end

-   * @param pos -

-   * @return updated pos

-   */

-  public int moveToNextFilled(int pos) {

-//    if (pos < 0) {

-//      pos = 0;

+////  /**

+////   * advance pos until it points to a non 0 or is 1 past end

+////   * @param pos -

+////   * @return updated pos

+////   */

+////  public int moveToNextFilled(int pos) {

+//////    if (pos < 0) {

+//////      pos = 0;

+//////    }

+////    

+////    final int max = getCapacity();

+////    while (true) {

+////      if (pos >= max) {

+////        return pos;

+////      }

+////      T v = keys[pos];

+////      if (v != null && v != removedMarker) {

+////        return pos;

+////      }

+////      pos ++;

+////    }

+////  }

+//   

+//  /**

+//   * decrement pos until it points to a non 0 or is -1

+//   * @param pos -

+//   * @return updated pos

+//   */

+//  public int moveToPreviousFilled(int pos) {

+//    final int max = getCapacity();

+//    if (pos > max) {

+//      pos = max - 1;

 //    }

-    

-    final int max = getCapacity();

-    while (true) {

-      if (pos >= max) {

-        return pos;

-      }

-      T v = keys[pos];

-      if (v != null && v != removedMarker) {

-        return pos;

-      }

-      pos ++;

-    }

-  }

-   

-  /**

-   * decrement pos until it points to a non 0 or is -1

-   * @param pos -

-   * @return updated pos

-   */

-  public int moveToPreviousFilled(int pos) {

-    final int max = getCapacity();

-    if (pos > max) {

-      pos = max - 1;

-    }

-    

-    while (true) {

-      if (pos < 0) {

-        return pos;

-      }

-      T v = keys[pos];

-      if (v != null && v != removedMarker) {

-        return pos;

-      }

-      pos --;

-    }

-  }

+//    

+//    while (true) {

+//      if (pos < 0) {

+//        return pos;

+//      }

+//      T v = keys[pos];

+//      if (v != null && v != removedMarker) {

+//        return pos;

+//      }

+//      pos --;

+//    }

+//  }

 

   private class ObjHashSetIterator implements Iterator<T> {

 

@@ -476,21 +491,17 @@
 

     @Override

     public final T next() {

-      if (curPosition >= getCapacity()) {

+      if (!hasNext()) {

         throw new NoSuchElementException();

       }

-      try {

-        T r = get(curPosition);

-        curPosition = moveToNextFilled(curPosition + 1);

-        return r;

-      } catch (ArrayIndexOutOfBoundsException e) {

-        throw new NoSuchElementException();

-      }

+      T r = get(curPosition);

+      curPosition = moveToNextFilled(curPosition + 1);

+      return r;

     }

 

     @Override

     public void remove() {

-      int pos = moveToPrevious(curPosition - 1);

+      int pos = moveToPreviousFilled(curPosition - 1);

       if (pos >= 0) {

         removeAtPosition(pos);

       }

@@ -518,13 +529,13 @@
 //    final int n = moveToNextFilled(position + 1); 

 //    return (n >= getCapacity()) ? -1 : n;

 //  }

-

-  private int moveToPrevious(int position) {

-    if (position >= getCapacity()) {

-      return -1;

-    }

-    return moveToPreviousFilled(position - 1);

-  }

+//

+//  private int moveToPrevious(int position) {

+//    if (position >= getCapacity()) {

+//      return -1;

+//    }

+//    return moveToPreviousFilled(position - 1);

+//  }

 

 //  public boolean isValid(int position) {

 //    return (position >= 0) && (position < getCapacity());

@@ -558,7 +569,7 @@
     

     final T2[] r = (a.length >= s)? a : (T2[]) Array.newInstance(a.getClass(), s);

     int pos = moveToFirst();

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

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

       r[i] = (T2) get(pos);

       pos = moveToNextFilled(pos + 1);

     }

@@ -581,14 +592,14 @@
     return String

         .format(

             "%s [loadFactor=%s, initialCapacity=%s, sizeWhichTriggersExpansion=%s, size=%s, secondTimeShrinkable=%s%n keys=%s]",

-            this.getClass().getName(), loadFactor, initialCapacity, sizeWhichTriggersExpansion, size, secondTimeShrinkable, 

+            this.getClass().getName(), loadFactor, initialCapacity, sizeWhichTriggersExpansion, size(), secondTimeShrinkable, 

             Arrays.toString(keys));

   }

 

   // Collection methods

   @Override

   public boolean isEmpty() {

-    return size == 0;

+    return size() == 0;

   }

 

   @Override

@@ -625,11 +636,59 @@
     return anyChanged;

   }

 

-  /**

-   * @return the modificiation count

-   */

-  public int getModificationCount() {

-    return modificationCount;

+  @Override

+  protected boolean is_valid_key(int pos) {

+    return keys[pos] != null & keys[pos] != removedMarker;

   }

+

+  @Override

+  protected int keys_length() {

+    return keys.length;

+  }

+

+  @Override

+  protected void newKeysAndValues(int capacity) {

+    keys = (T[]) Array.newInstance(clazz, capacity);

+  }

+

+  @Override

+  protected void clearKeysAndValues() {

+    Arrays.fill(keys, null);   

+  }

+

+  @Override

+  protected void copy_to_new_table(int new_capacity, int old_capacity, CommonCopyOld2New commonCopy) {

+    

+    final T[] oldKeys = keys;

+    

+    commonCopy.apply(

+    

+        // copyToNew

+        i -> addInner(oldKeys[i]),

+        

+        i -> oldKeys[i] != null && oldKeys[i] != removedMarker);

+  }

+

+  // debug

+//  private static final Integer I259 = new Integer(259);

+//  private void val259() {

+//    int sum = 0;

+//    for (int i = 0; i < keys.length; i++) {

+//      T k = keys[i];

+//      if (I259.equals(k)) {

+//        sum++;

+//        System.out.println("debug 259 " + i);

+//      }

+//    }

+//    if (sum > 1) {

+//      System.out.println("debug");

+//    }

+//  }

+//  /**

+//   * @return the modificiation count

+//   */

+//  public int getModificationCount() {

+//    return modificationCount;

+//  }

   

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/OrderedFsSet_array.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/OrderedFsSet_array.java
index bc69043..fbac4be 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/OrderedFsSet_array.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/OrderedFsSet_array.java
@@ -20,986 +20,381 @@
 package org.apache.uima.internal.util;

 

 import java.lang.reflect.Array;

-import java.util.ArrayList;

 import java.util.Arrays;

-import java.util.Collection;

-import java.util.Collections;

 import java.util.Comparator;

 import java.util.Iterator;

-import java.util.NavigableSet;

 import java.util.NoSuchElementException;

 import java.util.Set;

-import java.util.SortedSet;

-import java.util.function.Supplier;

 

+import org.apache.uima.cas.FeatureStructure;

 import org.apache.uima.jcas.cas.TOP;

-import org.apache.uima.util.impl.Constants;

 

 /**

+ * This one is being used, the other one (ending in 2) may be put back into service

+ * for large sizes, later.  (7/2017)

+ * 

+ * 

  * A set of FSs, ordered using a comparator 

  * Not thread-safe, use on single thread only

  * 

  * Use: set-sorted indexes in UIMA

  * 

- * Entries kept in order in 1 big ArrayList

+ * Entries kept in order in 1 big TOP[]

+ *   have ensureCapacity - grows by doubling up to multiplication-limit point, then by addition

  * 

  * Adds optimized:

  *   - maintain high mark, if &gt;, add to end

- *   - batch adds other than above

- *     -- do when reference needed

- *     -- sort the to be added

- *   - to add to pos p, shift elements in p to higher, insert   

  * 

- * shifting optimization: 

- *   removes replace element with null

- *   shift until hit null 

- *   

- * bitset: 1 for avail slot

- *   used to compute move for array copy

- * 

- *   

+ * shifting optimization:

+ *   for removes: shift space to back or front, whichever is closer 

+ *   for adds: shift space from back or front, whichever is closer

+ *      

  */

-public class OrderedFsSet_array implements NavigableSet<TOP> {

+public class OrderedFsSet_array<T extends FeatureStructure> implements Iterable<T> {

 //  public boolean specialDebug = false;

   final private static boolean TRACE = false;

   final private static boolean MEASURE = false;

-  final private static int DEFAULT_MIN_SIZE = 8;  // power of 2 please

-  final private static int MAX_DOUBLE_SIZE = 1024 * 1024 * 4;  // 4 million, power of 2 please

-  final private static int MIN_SIZE = 8;

    

-//  final private static MethodHandle getActualArray;

-//  

-//  static {

-//    Field f;

-//    try {

-//      f = ArrayList.class.getDeclaredField("array");

-//    } catch (NoSuchFieldException e) {

-//      try {

-//        f = ArrayList.class.getDeclaredField("elementData");

-//      } catch (NoSuchFieldException e2) {

-//        throw new RuntimeException(e2);

-//      }

-//    }

-//    

-//    f.setAccessible(true);

-//    try {

-//      getActualArray = Misc.UIMAlookup.unreflectGetter(f);

-//    } catch (IllegalAccessException e) {

-//      throw new RuntimeException(e);

-//    }

-//  }

-  

-    

-  TOP[] a = new TOP[DEFAULT_MIN_SIZE];

+  private static final int DEFAULT_SIZE = 8;

+

+  private static final int DEFAULT_MULTIPLICATION_LIMIT = 1024 * 1024 * 16;

+

+  final private int multiplication_limit = DEFAULT_MULTIPLICATION_LIMIT;

+

+  TOP[] a;

   /**

    * index of slot at the end which is free, all following slots are free too

    */

   int a_nextFreeslot = 0;

   int a_firstUsedslot = 0;

-  

-  private final ArrayList<TOP> batch = new ArrayList<>();

-  

-  final private Comparator<TOP> comparatorWithID;

-  final public Comparator<TOP> comparatorWithoutID;

-  private int size = 0;

-  private int maxSize = 0;

-  

-  private TOP highest = null;

-  private int nullBlockStart = -1;  // inclusive

-  private int nullBlockEnd = -1 ;    // exclusive

-  

-  private boolean doingBatchAdds = false;

-  private int modificationCount = 0;

-  private int lastRemovedPos = -1;

     

+  final private Comparator<TOP> comparatorNoTypeWithID;

+  final private Comparator<TOP> comparatorNoTypeWithoutID;

+  private int maxSize = 0; // managing shrinking

+  

+//  private TOP highest = null;

+  

+  // maybe not needed due to cow - for tracking if any mods have been done

+//  private int modificationCount = 0;

+  

   private StringBuilder tr = TRACE ? new StringBuilder() : null;

   

-  public OrderedFsSet_array(Comparator<TOP> comparatorWithID, Comparator<TOP> comparatorWithoutID) {

-    this.comparatorWithID = comparatorWithID;

-    this.comparatorWithoutID = comparatorWithoutID;

+  public OrderedFsSet_array(Comparator<TOP> comparatorNoTypeWithID, Comparator<TOP> comparatorNoTypeWithoutID) {

+    this.comparatorNoTypeWithID = comparatorNoTypeWithID;

+    this.comparatorNoTypeWithoutID = comparatorNoTypeWithoutID;

+    a = new TOP[DEFAULT_SIZE];

   }

-  

+//  //debug

+//  private static int callnbr = 0;

   /**

-   * copy constructor

-   * @param set the original to be copied

+   * called to make a read-only copy

+   * @param set -

+   * @param isReadOnly -

    */

-  public OrderedFsSet_array(OrderedFsSet_array set) {

-    set.processBatch();

-    this.a = set.a.clone();

-    this.a_nextFreeslot = set.a_nextFreeslot;

-    this.a_firstUsedslot = set.a_firstUsedslot;

-    this.comparatorWithID = set.comparatorWithID;

-    this.comparatorWithoutID = set.comparatorWithoutID;

-    this.size = set.size;

-    this.maxSize = set.maxSize;

-    this.highest = set.highest;

-    this.nullBlockStart = set.nullBlockStart;

-    this.nullBlockEnd = set.nullBlockEnd;

-    this.modificationCount = set.modificationCount;

-    this.lastRemovedPos = set.lastRemovedPos;

-  }

-

-  public OrderedFsSet_array(OrderedFsSet_array set, boolean isReadOnly) {

+  public OrderedFsSet_array(OrderedFsSet_array<T> set, boolean isReadOnly) {

     if (!isReadOnly) Misc.internalError();

-    set.processBatch();

-    this.size = set.size;

-    this.a = (size == 0) ? Constants.EMPTY_TOP_ARRAY : set.a.clone();

-    this.a_nextFreeslot = set.a_nextFreeslot;

+    

+//    //debug

+//    if ((callnbr++)%1024 == 0) {

+//      System.out.format("debug shrink, a_firstUsedslot: %,4d set.a_nextFreeslot: %,4d, array length: %,4d size: %,d%n", set.a_firstUsedslot, set.a_nextFreeslot, set.a.length, size);

+//    }

+    

+    // Iterators have refs into this, so don't change the start offset

+    // No issue with truncating though - these are read-only

+    this.a = new TOP[set.a.length];

+    System.arraycopy(set.a, 0, this.a, 0, set.a_nextFreeslot);

     this.a_firstUsedslot = set.a_firstUsedslot;

-    this.comparatorWithID = set.comparatorWithID;

-    this.comparatorWithoutID = set.comparatorWithoutID;

+    this.a_nextFreeslot = set.a_nextFreeslot;

+    this.comparatorNoTypeWithID = set.comparatorNoTypeWithID;

+    this.comparatorNoTypeWithoutID = set.comparatorNoTypeWithoutID;

     

     this.maxSize = set.maxSize;

-    this.highest = set.highest;

-    this.nullBlockStart = set.nullBlockStart;

-    this.nullBlockEnd = set.nullBlockEnd;

-    this.modificationCount = set.modificationCount;

-    this.lastRemovedPos = set.lastRemovedPos;

+//    this.modificationCount = set.modificationCount;

   }

   

-  

-

-  /**

-   * @see SortedSet#comparator()

-   */

-  @Override

-  public Comparator<? super TOP> comparator() {

-    return comparatorWithID;

-  }

-

-  /**

-   * @see SortedSet#first()

-   */

-  @Override

-  public TOP first() {

-    processBatch();

-    if (size == 0) {

-      throw new NoSuchElementException();

-    }

-    for (int i = a_firstUsedslot; i < a_nextFreeslot; i++) {

-      TOP item = a[i];

-      if (null != item) {

-        if (i > a_firstUsedslot) {

-          a_firstUsedslot = i;

-        }

-        return item; 

-      }

-    }

-    Misc.internalError();

-    return null;

-  }

-

-  /**

-   * @see SortedSet#last()

-   */

-  @Override

-  public TOP last() {

-    processBatch();

-    if (size == 0) {

-      throw new NoSuchElementException();

-    }

-    for (int i = a_nextFreeslot - 1; i >= a_firstUsedslot; i--) {

-      TOP item = a[i];

-      if (item != null) {

-        if (i < a_nextFreeslot - 1) {

-          a_nextFreeslot = i + 1;

-        }

-        return item;

-      }

-    }

-    Misc.internalError();

-    return null;

-  }

-

-  /**

-   * @see Set#size()

-   */

-  @Override

   public int size() {

-    processBatch();

-    return size;

+    return a_nextFreeslot - a_firstUsedslot;

   }

 

-  /**

-   * @see Set#isEmpty()

-   */

-  @Override

   public boolean isEmpty() {

-    return size == 0 && batch.size() == 0;

+    return size() == 0;

   }

-

-  /**

-   * @see Set#contains(Object)

-   */

-  @Override

-  public boolean contains(Object o) {

-    if (o == null) {

-      throw new IllegalArgumentException();

-    }

-    if (isEmpty()) {

-      return false;

-    }

-    TOP fs = (TOP) o;

-    processBatch();

-    return find(fs) >= 0;

-  }

-

-  /**

-   * @see Set#toArray()

-   */

-  @Override

-  public Object[] toArray() {

-    Object [] r = new Object[size()];

-    int i = 0;

-    for (TOP item : a) {

-      if (item != null) {

-        r[i++] = item;

-      }

-    }

-//    try { // debug

-      assert r.length == i;

-//    } catch (AssertionError e) { // debug

-//      System.err.format("size: %,d, final index: %,d, array length: %,d%n", size(), i, a.length );

-//      for (int di = 0; di < a.length; di++) {

-//        System.err.format("a[%,d] = %s%n", di, a[di]);

-//      }

-//      System.err.format("first used slot: %,d, next free slot: %,d batch size: %,d,"

-//          + " nullblockstart: %,d nullBlockEnd: %d, lastRemovedPos: %,d",

-//          a_firstUsedslot, a_nextFreeslot, batch.size(), nullBlockStart, nullBlockEnd,

-//          lastRemovedPos);

-//      throw e;

-//    }

-    return r;

-  }

-

-  /**

-   * @see Set#toArray(Object[])

-   */

-  @SuppressWarnings("unchecked")

-  @Override

-  public <T> T[] toArray(T[] a1) {

-    if (a1.length < size()) {

-      a1 = (T[]) Array.newInstance(a.getClass(), size());

-    }

-    int i = 0;

-    for (TOP item : a) {

-      if (item != null) {

-        a1[i++] = (T) item;

-      }

-    }

-    if (i < a1.length) {

-      a1[i] = null;  // contract for toArray, when array bigger than items

-    }

-    return a1;

-  }

-

-  /**

-   * Note: doesn't implement the return value; always returns true;

-   * @see Set#add(Object)

-   */

   

-  @Override

-  public boolean add(TOP fs) {

-    if (highest == null) {

-      addNewHighest(fs);

-      return true;

+  public boolean add(T fs1) {

+    throw new UnsupportedOperationException(); 

+  }

+  

+  /**

+   * 

+   * @param fs1 item to add

+   * @param comparator either the comparator without type with ID for sorted indexes, or the comparator withoutType without ID for set indexes

+   * @return true if fs was added (not already present)

+   */

+  public boolean add(T fs1, Comparator<TOP> comparator) {

+    if (fs1 == null) {

+      throw new IllegalArgumentException("Null cannot be added to this set.");

     }

     

-    int c = comparatorWithID.compare(fs, highest);

-    if (c > 0) {

-      addNewHighest(fs);

-      return true;

+    TOP fs = (TOP) fs1;

+    

+    int c = 1;

+    

+    boolean highest = false;

+    

+    if (size() == 0 || (c = comparator.compare(fs, a[a_nextFreeslot - 1])) > 0 ) {

+      highest = true;

+//      addNewHighest(fs);

+////      modificationCount++;

+//      maxSize = Math.max(maxSize, size());

+//      return true;

     }

     

-    if (c == 0) {

+    if (c == 0) { // found as equal to last item, skip insert

       return false;

     }

+

+    /******************

+     * add a new item *

+     ******************/

+    int insertPosOfAddedSpace;

     

-    batch.add(fs);

-    if (MEASURE) {

-      addNotToEndCount ++;

+    if (highest) {

+      insertPosOfAddedSpace = a_nextFreeslot;

+    } else {

+

+      insertPosOfAddedSpace = find(fs, comparator);

+      if (insertPosOfAddedSpace >= 0) {

+        // was found

+        return false;

+      }

+      

+      insertPosOfAddedSpace = (- insertPosOfAddedSpace) - 1;

     }

+    

+    int indexOfNewItem = insertSpace(insertPosOfAddedSpace, highest) - 1;

+    

+    a[indexOfNewItem] = fs;

+//    modificationCount++;

+    maxSize = Math.max(maxSize, size());

     return true;

   }

-  

-  private void addNewHighest(TOP fs) {

-    highest = fs;

-    ensureCapacity(1);

-    a[a_nextFreeslot++] = fs;

-    incrSize();

-    if (MEASURE) {

-      addToEndCount++;

-    }

-    return;

-  }

-  

-  private void incrSize() {

-    size++;

-    maxSize = Math.max(maxSize, size);

-    modificationCount++;

-  }

-  

-//  /** validate array

-//   *    number of non-null elements == size

-//   */

-//  // debug

-//  private void validateA() {

-//    synchronized (batch) {

-//      try {

-//        if (nullBlockStart != -1) {

-//          assert a[nullBlockStart] == null;

-//          if (nullBlockStart > 0) {

-//            assert a[nullBlockStart - 1] != null;

-//          }

-//        }

-//        int sz = 0;

-//        for (TOP item : a) {

-//          if (item != null) {

-//            sz++;

-//          }

-//        }

-//    //    if (sz != size) {

-//    //      System.out.format("debug error OrderedFsSet_array size(): %,d array non-null element count: %,d%n",

-//    //          size, sz);

-//    //    }

-//        assert sz == size;

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

-//          assert a[i] == null;

-//        }

-//        for (int i = a_nextFreeslot; i < a.length; i++) {

-//          assert a[i] == null;

-//        }

-//        assert a_firstUsedslot < a_nextFreeslot;

-//        TOP prev = a[a_firstUsedslot];

-//        for (int i = a_firstUsedslot + 1; i < a_nextFreeslot; i++) {

-//          TOP fs = a[i];

-//          if (fs != null) {

-//            assert comparatorWithID.compare(fs, prev) > 0;

-//            prev = fs;

-//          }

-//        }

-//      } catch (AssertionError e) {

-//        e.printStackTrace();

-//      }

-//    }  

-//  }

-

-  private void ensureCapacity(int incr) {

-    int szNeeded = a_nextFreeslot + incr;

-    if (szNeeded <= a.length) {

+       

+  private void ensureCapacity() {

+    // if space at end or space at beginning

+    if (a_nextFreeslot < a.length || a_firstUsedslot > 0) {

       return;

     }

-    int sz = a.length;

-    do {

-      sz = (sz < MAX_DOUBLE_SIZE) ? (sz << 1) : (sz + MAX_DOUBLE_SIZE);

-    } while (sz < szNeeded);

-    

-    TOP[] aa = new TOP[sz];

-    System.arraycopy(a, 0, aa, 0, a_nextFreeslot);

+       

+    int newSize = (a.length > multiplication_limit)

+                    ? a.length + multiplication_limit

+                    : (a.length << 1);

+       

+    TOP[] aa = new TOP[newSize];

+    System.arraycopy(a, 0, aa, 0, a.length);

     a = aa;

   }

-  

-  private boolean shrinkCapacity() {

-    int nextSmallerSize = getNextSmallerSize(2);

-    if (nextSmallerSize == MIN_SIZE) {

-      return false;

-    }

-    if (maxSize < nextSmallerSize) {

-      a = new TOP[getNextSmallerSize(1)];

-      maxSize = 0;

-      return true;

-    }

-    maxSize = 0; 

-    return false;

-  }

-  

+      

   /**

-   * get next smaller size

-   * @param n number of increments

-   * @return the size

-   */

-  private int getNextSmallerSize(int n) {

-    int sz = a.length;

-    if (sz <= MIN_SIZE) {

-      return MIN_SIZE;

-    }

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

-      sz = (sz > MAX_DOUBLE_SIZE) ? (sz - MAX_DOUBLE_SIZE) : sz >> 1;

-    }

-    return sz;

-  }

-  

-  void processBatch() {

-    if (batch.size() != 0) {

-//      validateA();

-      doProcessBatch();

-//      validateA();

-    }

-  }

-  

-  /**

-   * Because multiple threads can be "reading" the CAS and using iterators,

-   * the sync must insure that the setting of batch.size() to 0 occurs after

-   * all the adding is done.

+   * This is called when inserting new items.

+   * May be called to insert at top

    * 

-   * This keeps other threads blocked until the batch is completely processed.

-   */

-  private void doProcessBatch() {

-    synchronized (batch) {

-      int batchSize = batch.size();

-

-      if (batchSize == 0) {

-        return;  // another thread did this

-      }

-      if (doingBatchAdds == true) {

-        return;  // bypass recursive calls from Eclipse IDE on same thread

-      }

-      try {

-//        validateA();

-        doingBatchAdds = true;

-        if (MEASURE) {

-          batchAddCount ++;

-          batchAddTotal += batchSize;

-          batchCountHistogram[31 - Integer.numberOfLeadingZeros(batchSize)] ++;

-        }

- 

-        /* the number of new empty slots created, 

-         *   may end up being larger than actually used because some of the items 

-         *   being inserted may already be in the array

-         *     - decreases as each item is actually inserted into the array

-         */

-        int nbrNewSlots = 1; // start at one, may increase

-        

-        if (batchSize > 1) {

-          // Sort the items to add 

-          Collections.sort(batch, comparatorWithID);

-          TOP prev = batch.get(batchSize - 1);

-        

-//          nbrNewSlots = batch.size();

-          // count dups (to reduce excess allocations)

-          //   deDups done using the comparatorWithID

-          final boolean useEq = comparatorWithID != comparatorWithoutID;  // true for Sorted, false for set

-          for (int i = batchSize - 2; i >= 0; i--) {

-            TOP item = batch.get(i);

-            if (useEq ? (item == prev) : (comparatorWithID.compare(item, prev) == 0)) {

-              batch.set(i + 1, null); // need to do this way so the order of adding is the same as v2

-              if (i + 1 == batchSize - 1) {

-                batchSize --;  // start with non-null when done

-              }

-            } else {

-              prev = item;

-              nbrNewSlots++;  // count of items that will actually be added; skips the duplicates

-            }

-          }

-        } 

-        

-        int i_batch = batchSize - 1;

-        int insertPosOfAddedSpace = 0;

-        TOP itemToAdd;

-        // skip entries already found

-        itemToAdd = batch.get(i_batch);

-        while (itemToAdd == null || (insertPosOfAddedSpace = find(itemToAdd)) >= 0) {

-          // skip any entries at end of list if they're already in the set

-          i_batch--;

-          nbrNewSlots --;

-          if (i_batch < 0) {

-            batch.clear();

-            return; // all were already in the index

-          }

-          itemToAdd = batch.get(i_batch);

-        }

-        

-        assert nbrNewSlots > 0; // otherwise batch would be empty and would have returned before

-        

-        // insertPosOfAddedSpace is index to non-null item that is > itemToAdd

-        //                       or points to 1 beyond current size

-        insertPosOfAddedSpace = (- insertPosOfAddedSpace) - 1;

-        // insertPos is insert point, i_batch is index of first batch element to insert

-        // there may be other elements in batch that duplicate; these won't be inserted, but 

-        //   there will be space lost in this case

-         

-        int indexOfNewItem = insertSpace(insertPosOfAddedSpace, nbrNewSlots) // returns index of a non-null item

-                                                                           // the new item goes one spot to the left of this

-            - 1;  // inserts nulls at the insert point, shifting other cells down

-    

-        int nbrNewSlotsRemaining = nbrNewSlots;  // will be decremented as slots are used

-        // process first item

-        insertItem(indexOfNewItem, itemToAdd);

-//        TOP prevItem = itemToAdd;

-        if (indexOfNewItem + 1 == a_nextFreeslot) {

-          highest = itemToAdd;

-        }

-        nbrNewSlotsRemaining --;

-        

-        int bPos = i_batch - 1; // next after first one from end

-        for (; bPos >= 0; bPos --) {

-          itemToAdd = batch.get(bPos);

-          if (null == itemToAdd) {

-            continue;  // skipping a duplicate

-          }

-          int pos = findRemaining(itemToAdd);

-    

-          if (pos >= 0) {

-            continue;  // already in the list

-          }

-          pos = (-pos) - 1;  // pos is the insert point, new item goes 1 to left of this

-              

-          indexOfNewItem = pos - 1;  // where the new item goes, 1 to left of insert point

-          if (nullBlockStart == 0) {

-            // this and all the rest of the elements are lower, insert in bulk

-            // because all are lower, none are in the array, so don't need the compare check

-            insertItem(indexOfNewItem--, itemToAdd);

-            nbrNewSlotsRemaining --;

-            bPos--;

-            

-            for (;bPos >= 0; bPos--) {          

-              itemToAdd = batch.get(bPos);

-              if (itemToAdd == null) {

-                continue;

-              }

-              insertItem(indexOfNewItem--, itemToAdd);

-              nbrNewSlotsRemaining --;  // do this way to respect skipped items due to == to prev        

-            }

-            break;

-          }

-//          validateA();

-          if (indexOfNewItem == -1 || null != a[indexOfNewItem]) {

-            indexOfNewItem = shiftFreespaceDown(pos, nbrNewSlotsRemaining) - 1;  // results in null being available at pos - 1

-          }

-          insertItem(indexOfNewItem, itemToAdd);

-          nbrNewSlotsRemaining --;

-        }

-        if (nbrNewSlotsRemaining > 0) {

-          // have extra space left over due to dups not being added

-          // If this space is not at beginning, move space to beginning or end (whichever is closer)

-//          if (indexOfNewItem - nbrNewSlotsRemaining > 0) { 

-          if (nullBlockEnd != a_firstUsedslot) {

-          // space is not at beginning

-          

-            int mid = (a_nextFreeslot + a_firstUsedslot) >>> 1;  // overflow aware 

-            if (indexOfNewItem < mid) {

-              shiftFreespaceDown(a_firstUsedslot, nbrNewSlotsRemaining);

-//              System.arraycopy(a, indexOfNewItem - nbrNewSlots, a, 0, nbrNewSlots);

-//              a_firstUsedslot += nbrNewSlots;

-//              validateA();

-            } else {

-              shiftFreespaceUp(a_nextFreeslot, nbrNewSlotsRemaining);

-              a_nextFreeslot -= nbrNewSlotsRemaining;

-//              // move to end

-//              System.arraycopy(a, indexOfNewItem, a, indexOfNewItem - nbrNewSlots, a_nextFreeslot - indexOfNewItem);

-//              Arrays.fill(a, a_nextFreeslot - nbrNewSlots, a_nextFreeslot, null);

-//              a_nextFreeslot -= nbrNewSlots;

-//              validateA();

-            }

-          }

-        }

-        nullBlockStart = nullBlockEnd = -1;

-//        validateA();

-        batch.clear();

-      } finally {

-        doingBatchAdds = false;

-      }

-    }

-  }

-  

-  /**

-   * side effects:

-   *   increment size

-   *   reset a_firstUsedslot if adding in front

-   *   ( a_nextFreeslot not updated, because this method only called to inserting before end )

-   *   nullBlockEnd reduced conditionally

-   * @param indexToUpdate - the index in the array to update with the item to add

-   * @param itemToAdd -

-   */

-  private void insertItem(int indexToUpdate, TOP itemToAdd) {

-//    validateA();

-    try {

-      assert indexToUpdate >= 0;

-      assert null == a[indexToUpdate];

-    } catch (AssertionError e) {

-      if (TRACE) {

-        System.err.println("OrderedFsSet_array caught assert.  array values around indexToUpdate: ");

-        for (int i = indexToUpdate - 2; i < indexToUpdate + 3; i++) {

-          if (i >= 0 && i < a.length) {

-            System.err.format("a[%,d]: %s%n", i, a[i].toString(2));

-          } else {

-            System.err.format("a[%,d}: out-of-range%n", i);

-          }

-        }

-        System.err.format("trace info: %n%s", tr);

-      }

-      throw e;

-    }

- 

-    a[indexToUpdate] = itemToAdd;

-    incrSize();

-    if (indexToUpdate < a_firstUsedslot) {

-      a_firstUsedslot = indexToUpdate;  

-    }

-    if (nullBlockEnd == indexToUpdate + 1) {

-      nullBlockEnd --;

-    }

-    if (nullBlockStart == indexToUpdate) {

-      nullBlockStart = -1;

-    }

-//    validateA();

-  }

-

-  /**

-   * Attempt to move a small amount; make use of both beginning and end free space.

+   * Side effects:  a_firstUsedslot adjusted if insert before first

+   *                a_nextFreeslot adjusted if after last

    * 

-   * @param positionToInsert position containing a value, to free up by moving the current free block

-   *                         so that the last free element is at that (adjusted up) position.          

-   * @param nbrNewSlots

-   * @return adjusted positionToInsert, the free spot is just to the left of this position

+   * Rebalancing: 

+   *   normally not done, instead just the smaller distance to front/back things are moved

+   *     by 1 position.

+   *     

+   *   for highest insert when out of space there 

+   *      rebalance by moving 1/2 the space from front to end.

+   *   

+   *   for lowest  insert when out of space there

+   *      rebalance by moving 1/2 the space from end to front.

+   *     

+   * @param insertPosOfAddedSpace position where new item goes 1 to the left

+   * @param highest true if inserting at end

+   * @return adjusted insertPosOfAddedSpace, the free spot is just to the left of this position

    */

-  private int insertSpace(final int positionToInsert, int nbrNewSlots) {

+  private int insertSpace(int insertPosOfAddedSpace, boolean highest) {

     if (TRACE) {

       tr.setLength(0);

       tr.append("Tracing OrderedFsSet_array\n");

-      tr.append(String.format("insertSpace called with positionToInsert: %,d nbrNewSlots: %,d%n", positionToInsert, nbrNewSlots));

+      tr.append(String.format("insertSpace called with insertPosOfAddedSpace: %,d %n", insertPosOfAddedSpace));

     }

+

+    ensureCapacity(); // add space at end if no space at front or end meaning capacity == size()

     

-    // while the positionToInsert (a ref to non-null or 1 past end) 

-    //   is > 0 && the pos to the left is null,

-    //     reduce the nbrNewSlots

-    int i = positionToInsert;

-    int nullsBelowInsertMin = -1;

-    while (i > 0 && a[i - 1] == null && nbrNewSlots > 0) {

-      i--;

-      nbrNewSlots--;

-      nullsBelowInsertMin = i;

-    }

+    final boolean useFront;

     

-    if (nbrNewSlots == 0) {

-      return positionToInsert;  // because previous exists and is empty

-    }

-    

-    // nbrNewSlots, if at front, reduced by 

-    if (nbrNewSlots == 1) {

-      int distanceFromLastRemoved = (lastRemovedPos == -1) 

-                                      ? Integer.MAX_VALUE 

-                                      : (positionToInsert - lastRemovedPos);

-      int distanceFromEnd = a_nextFreeslot - positionToInsert;

-      int distanceFromFront = (0 == a_firstUsedslot)

-                                ? Integer.MAX_VALUE

-                                : positionToInsert - a_firstUsedslot;

-      boolean useFront =

-          // make sure size of front free space is not included in previous nulls already counted

-          a_firstUsedslot > positionToInsert && 

-          distanceFromFront < distanceFromEnd;

-      boolean useLastRemoved =

-          // make sure lastRemovedPos is outside range already counted

-          (lastRemovedPos > positionToInsert &&

-           lastRemovedPos < nullsBelowInsertMin) 

-             ? (Math.abs(distanceFromLastRemoved) < (useFront 

-                 ? distanceFromFront 

-                 : distanceFromEnd))

-             : false;

+    if (highest) {

+

+      if (a_nextFreeslot >= a.length) {  // there's no room at end, only room in front.  

+        insertPosOfAddedSpace -= rebalanceMoveSpaceToEnd();  // updates a_nextFreeslot and a_firstUsedslot

+      }

+

+      a_nextFreeslot ++;

+      return insertPosOfAddedSpace + 1;

       

-      if (TRACE) 

-        tr.append(String.format("distances: %d %d %d, useFront: %s useLastRemoved: %s%n",

-            distanceFromLastRemoved, distanceFromEnd, distanceFromFront, useFront, useLastRemoved));

-      if (useLastRemoved) {  // due to find skipping over nulls, the distanceFromLastRemoved is never 0

-        if (distanceFromLastRemoved > 0) {

-          if (distanceFromLastRemoved != 1) { 

-            nullBlockStart = lastRemovedPos;

-            nullBlockEnd = lastRemovedPos + 1;

-            shiftFreespaceUp(lastRemovedPos, nbrNewSlots); // move one slot (since nullblockstart/end set above

-          }

-          lastRemovedPos = -1; 

-          return positionToInsert;

-        } else {

-          nullBlockStart = lastRemovedPos;

-          lastRemovedPos = -1;

-          int r = shiftFreespaceDown(positionToInsert, nbrNewSlots);

-          if (TRACE) 

-            tr.append(String.format("shiftFreespaceDown result was %,d%n", r));

-          return r;

-        }

+    } else if (insertPosOfAddedSpace == a_firstUsedslot) {

+      

+      // special case: add before first

+      if (a_firstUsedslot == 0) {  // there's no room at beginning, only room at end

+        insertPosOfAddedSpace += rebalanceMoveSpaceToFront();

       }

-      if (useFront) {

-        nullBlockStart = a_firstUsedslot - 1;

-//        if (null != a[nullBlockStart]) {

-        if (a_firstUsedslot != positionToInsert) {

-          // need to move the free slot if not already next to the insert position

-          nullBlockEnd = a_firstUsedslot;

-          shiftFreespaceUp(positionToInsert, nbrNewSlots);

-        }

-//        a_firstUsedslot --;  // not done here, done in insert routine

-        return positionToInsert;

+      a_firstUsedslot --;

+      return insertPosOfAddedSpace;

+    } 

+      

+    // not highest, not before first element

+    int distanceFromEnd   = a_nextFreeslot        - insertPosOfAddedSpace;

+    int distanceFromFront = insertPosOfAddedSpace - a_firstUsedslot;

+    useFront = distanceFromFront < distanceFromEnd;

+    

+    /*******************

+     * Use Front Space *

+     *******************/

+    if (useFront) {

+      if (a_firstUsedslot == 0) {

+        insertPosOfAddedSpace += rebalanceMoveSpaceToFront();

       }

+      System.arraycopy(a, a_firstUsedslot, a, a_firstUsedslot - 1, insertPosOfAddedSpace - a_firstUsedslot);

+      a_firstUsedslot --;

+      return insertPosOfAddedSpace;  

     }

     

-    // using space at end

-    ensureCapacity(nbrNewSlots);

-    nullBlockStart = a_nextFreeslot;

-    nullBlockEnd = nullBlockStart + nbrNewSlots; 

-    a_nextFreeslot += nbrNewSlots;

-    int r = shiftFreespaceDown(positionToInsert, nbrNewSlots);

-    if (TRACE) {

-      tr.append(String.format("shiftFreespaceDown2 result was %,d, nullBlockStart: %,d nullBlockEnd: %,d a_nextFreeslot: %,d%n", 

-          r, nullBlockStart, nullBlockEnd, a_nextFreeslot));

+    /*******************

+     * Use End   Space *

+     *******************/

+    if (a_nextFreeslot >= a.length) {

+      insertPosOfAddedSpace -= rebalanceMoveSpaceToEnd();

     }

-    return r;

+    System.arraycopy(a, insertPosOfAddedSpace, a, insertPosOfAddedSpace + 1, a_nextFreeslot - insertPosOfAddedSpace);

+    a_nextFreeslot ++;

+    return insertPosOfAddedSpace + 1;

   }

   

   /**

-   * Shift a block of free space lower in the array.

-   * This is done by shifting the space at the insert point

-   *   for length = start of free block - insert point 

-   *   to the right by the nbrNewSlots

-   *   and then resetting (filling) the freed up space with null

-   *   

-   * Example:  u = used, f = free space

-   * 

-   * before                      |--| 

-   * uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuffffffffuuuuuuu

-   *                             ^ insert point

-   * after                               |--|

-   * uuuuuuuuuuuuuuuuuuuuuuuuuuuuffffffffuuuuuuuuuuu

-   *                                     ^ insert point

-   *                                    

-   * before 

-   * |------------------------------|

-   * uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuffffffffuuuuuuu

-   * ^ insert point

-   * after   |------------------------------| 

-   * ffffffffuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

-   *         ^ insert point

-   * before 

-   *     |------------------------------|

-   * ffffuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuffffffffuuuuuuu

-   *     ^ insert point

-   * after       |------------------------------| 

-   * ffffffffffffuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

-   *             ^ insert point

-   *                                    

-   * move up by nbrNewSlots

-   * length to move = nullBlockStart - insert point

-   * new insert point is nbrOfFreeSlots higher (this points to a filled spot, prev spot is free)

-   * 

-   * fill goes from original newInsertPoint, for min(nbrNewSlots, length of move)

-   *   

-   * hidden param:  nullBlockStart

-   * @param insertPoint index of slot array, currently occupied, where an item is to be set into

-   * @param nbrNewSlots - the size of the inserted space

-   * @return the updated insert point, now moved up

+   * move 1/2 of space at front to end

+   * @return amount of space shifted to end, amount to decr insertPosOfAddedSpace

    */

-  private int shiftFreespaceDown(final int insertPoint, final int nbrNewSlots) {

-    assert insertPoint >= 0;

-    assert nbrNewSlots >= 0;

-    int lengthToMove = nullBlockStart - insertPoint;

-    System.arraycopy(a, insertPoint, a, insertPoint + nbrNewSlots, lengthToMove);

-    int lengthToClear = Math.min(nbrNewSlots, lengthToMove);

-    Arrays.fill(a, insertPoint, insertPoint + lengthToClear, null);

-    nullBlockStart = insertPoint;

-    nullBlockEnd = nullBlockStart + nbrNewSlots;

-    

-    // adjust nullBlockStart to account for nulls in front

-    int i = insertPoint - 1;

-    for (; i >= 0; i--) {

-      if (a[i] != null) {

-        break;

-      }

-    }

-    nullBlockStart = i + 1;

-    

-    if (MEASURE) {

-      moveSizeHistogram[32 - Integer.numberOfLeadingZeros(lengthToMove)] ++;

-      movePctHistogram[lengthToMove* 10 / (a_nextFreeslot - a_firstUsedslot)] ++;

-      fillHistogram[32 - Integer.numberOfLeadingZeros(lengthToClear)] ++;

-    }

-    if (insertPoint == a_firstUsedslot) {

-      a_firstUsedslot = insertPoint + nbrNewSlots;

-    }

-    return insertPoint + nbrNewSlots;

+  private int rebalanceMoveSpaceToEnd() {

+    int amtOfShift = (a_firstUsedslot + 1) >> 1;  // is a min of 1

+    assert amtOfShift > 0;

+    System.arraycopy(a, a_firstUsedslot, a, a_firstUsedslot - amtOfShift, size());

+    Arrays.fill(a, a_nextFreeslot-amtOfShift, a_nextFreeslot, null);

+    a_nextFreeslot -= amtOfShift;

+    a_firstUsedslot -= amtOfShift;

+    return amtOfShift;

   }

-  

+      

   /**

-   * Shift a block of free space higher in the array.

-   * This is done by shifting the space at the insert point

-   *   of length = insert point - (end+1) of free block 

-   *   to the left by the nbrNewSlots

-   *   and then resetting (filling) the freed up space with null

-   *   

-   * Example:  u = used, f = free space

-   * 

-   * before              |-|   << block shifted 

-   * uuuuuuuuuuuuuuufffffuuuuuuuuuuuuuuuuuuuuuuuuuuu

-   *                        ^ insert point

-   * after          |-|   << block shifted

-   * uuuuuuuuuuuuuuuuuufffffuuuuuuuuuuuuuuuuuuu

-   *                        ^ insert point

-   *                                    

-   * before                                  |----|

-   * uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuffffuuuuuuu

-   *                                               ^ insert point

-   *     note: insert point is never beyond last because

-   *     those are added immediately

-   * after                               |----|

-   * uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuffffu

-   *                                               ^ insert point

-   *                                    

-   * before       |--|   

-   * uuuuuuuuuuuufuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

-   *                  ^ insert point

-   * after       |--|

-   * uuuuuuuuuuuuuuuufuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

-   *                  ^ insert point

-   *                                    

-   *     |--------|  before 

-   * ffffuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

-   *               ^ insert point

-   * |--------|

-   * uuuuuuuuuuffffuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

-   *               ^ insert point

-   *                                    

-   *                                    

-   * move down by nbrNewSlots

-   * length to move = insert point - null block end (which is 1 plus index of last free)

-   * new insert point is the same as the old one (this points to a filled spot, prev spot is free)

-   * 

-   * fill goes from original null block end, for min(nbrNewSlots, length of move)

-   *   

-   * hidden param:  nullBlockEnd = 1 past end of last free slot

-   * @param newInsertPoint index of slot array, currently occupied, where an item is to be set into

-   * @param nbrNewSlots - the size of the inserted space

-   * @return the updated insert point, now moved up

+   * move 1/2 of space at end to front

+   * @return amount of space shifted to end, amount to incr insertPosOfAddedSpace

    */

-  

-  private int shiftFreespaceUp(int newInsertPoint, int nbrNewSlots) {

-    boolean need2setFirstUsedslot = nullBlockEnd == a_firstUsedslot;

-    int lengthToMove = newInsertPoint - nullBlockEnd;

-    System.arraycopy(a, nullBlockEnd, a, nullBlockStart, lengthToMove);

-    int lengthToClear = Math.min(nbrNewSlots, lengthToMove);

-    Arrays.fill(a, newInsertPoint - lengthToClear, newInsertPoint, null);

-    nullBlockStart = newInsertPoint - nbrNewSlots;

-    nullBlockEnd = newInsertPoint;

-    if (need2setFirstUsedslot) {

-      a_firstUsedslot = 0;

-    }

-    return newInsertPoint;

+  private int rebalanceMoveSpaceToFront() {

+    int amtOfShift = (1 + a.length - a_nextFreeslot) >> 1;  // is a min of 1

+    assert amtOfShift > 0;

+    System.arraycopy(a, a_firstUsedslot, a, a_firstUsedslot + amtOfShift, size());

+    Arrays.fill(a, a_firstUsedslot, a_firstUsedslot + amtOfShift , null);

+    a_nextFreeslot += amtOfShift;

+    a_firstUsedslot += amtOfShift;

+    return amtOfShift;

   }

-    

+

 //  /**

-//   * @param from start of items to shift, inclusive

-//   * @param to end of items to shift, exclusive

+//   * If all items are LT key, returns - size - 1 

+//   * @param fs the key

+//   * @return the lowest position whose item is equal to or greater than fs;

+//   *         if not equal, the item's position is returned as -insertionPoint - 1. 

+//   *         If the key is greater than all elements, return -size - 1). 

 //   */

-//  private void shiftBy2(int from, int to) {

-//    if (to == -1) {

-//      to = theArray.size();

-//      theArray.add(null);

-//      theArray.add(null);

-//    }

-//      try {

-//        Object[] aa = (Object[]) getActualArray.invokeExact(theArray);

-//        System.arraycopy(aa, from, aa, from + 2, to - from);

-//      } catch (Throwable e) {

-//        throw new RuntimeException(e);

-//      }

+//  private int find(TOP fs) {

+//    return binarySearch(a, a_firstUsedslot, a_nextFreeslot, fs, comparatorNoTypeWithID);

 //  }

+    

+  /**

+   *  using NoType because all callers of this have already used the type of fs to select

+   *  the right index.

+   * @param fs -

+   * @return -

+   */

+  public int findWithoutID(TOP fs) {

+    return binarySearch(a, a_firstUsedslot, a_nextFreeslot, fs, comparatorNoTypeWithoutID);

+  }

+  

+  public int find(TOP fs, Comparator<TOP> comparator) {

+    return binarySearch(a, a_firstUsedslot, a_nextFreeslot, fs, comparator);

+  }

+  

+  /**

+   * 

+   * @param _a the array

+   * @param start the index representing the lower bound (inclusive) to search for

+   * @param end the index representing the upper bound (exclusive) to search for

+   * @param fs - the fs to search for

+   * @param _comparatorWithID -

+   * @return - the index of the found item, or if not found, the (-index) -1 of the 

+   *           position one more than where the item would go

+   */

+  public static int binarySearch(

+      TOP[] _a, 

+      int start, 

+      int end,

+      final TOP fs,       

+      Comparator<TOP> _comparatorWithID) {

+    return Arrays.binarySearch(_a, start, end, fs, _comparatorWithID );

 

-  /**

-   * Never returns an index to a "null" (deleted) item.

-   * If all items are LT key, returns - size - 1 

-   * @param fs the key

-   * @param pos first position to compare

-   * @return the lowest position whose item is equal to or greater than fs;

-   *         if not equal, the item's position is returned as -insertionPoint - 1. 

-   *         If the key is greater than all elements, return -size - 1). 

-   */

-  private int find(TOP fs) {

-    if (size == 0) {

-      return -1;

-    }

-    return binarySearch(fs);

+//    if (start < 0 || end - start <= 0) {

+//      return (start < 0) ? -1 : ( (-start) - 1);  // means not found, insert at position start

+//    }

+//    int lower = start, upper = end;

+//    for (;;) {

+//    

+//      int mid = (lower + upper) >>> 1;  // overflow aware

+//      TOP item = _a[mid];

+//      int pos = mid;

+//        

+//      int c = _comparatorWithID .compare(fs, item);

+//      if (c == 0) {

+//        return pos;

+//      }

+//      

+//      if (c < 0) {  // fs is smaller than item at pos in array; search downwards

+//        upper = pos;  // upper is exclusive

+//        if (upper == lower) {

+//          return (-upper) - 1;

+//        }

+//      } else {  // fs is larger than item at pos in array; search upwards

+//        lower = pos + 1;             // lower is inclusive

+//        if (lower == upper) {

+//          return (-upper) - 1;

+//        }

+//      }

+//    }

   }

   

-  private int findRemaining(TOP fs) {

-    int pos = binarySearch(fs, a_firstUsedslot, nullBlockStart);

-    return pos < 0 && ((-pos) - 1 == nullBlockStart) 

-            ? ( -(nullBlockEnd) - 1) 

-            : pos;

-  }

-    

   /**

-   * Special version of binary search that ignores null values

-   * @param fs the value to look for

-   * @return the position whose non-null value is equal to fs, or is gt fs (in which case, return (-pos) - 1)

+   * Removes the exactly matching (including ID) FS if present

+   * 

+   * Only called when type of FS matches this index's type, so the NoType comparator is used.

+   * 

+   * @param o the object (must be a FS of the type of this index) to remove

+   * @return true if it was removed, false if it wasn't in the index

    */

-  private int binarySearch(final TOP fs) {

-    return binarySearch(fs, a_firstUsedslot, a_nextFreeslot);

-  }

-  

-  private int binarySearch(final TOP fs, int start, int end) {

 

-    if (start < 0 || end - start <= 0) {

-      return (start < 0) ? -1 : ( (-start) - 1);  // means not found, insert at position start

-    }

-    int lower = start, upper = end;

-    int prevUpperPos = -1;

-    for (;;) {

-    

-      int mid = (lower + upper) >>> 1;  // overflow aware

-      TOP item = a[mid];

-      int delta = 0;

-      int midup = mid;

-      int middwn = mid;

-      int pos = mid;

-    

-      while (null == item) {  // skip over nulls

-        if (nullBlockStart != -1 && 

-            middwn >= nullBlockStart && 

-            midup  < nullBlockEnd) {

-          // in the null block

-          // move to edges

-          midup  = nullBlockEnd;   // midup inclusive, nullBlockEnd exclusive

-          middwn = nullBlockStart - 1; // middwn and nullBlockStart inclusive

-        } else {

-          delta ++;

-        }

-        boolean belowUpper = (pos = midup + delta) < upper;

-        if (belowUpper && null != (item = a[pos])) {

-          break;

-        }

-        boolean belowLower = (pos = middwn - delta) < lower;

-        if (!belowLower && null != (item = a[pos])) {

-          break;

-        }

-        if (! belowUpper && belowLower) {

-          return (-prevUpperPos) - 1; // return previous

-        }

-      }

-     

-      int c = comparatorWithID.compare(fs, item);

-      if (c == 0) {

-        return pos;

-      }

-      

-      if (c < 0) {  // fs is smaller than item at pos in array; search downwards

-        upper = prevUpperPos = pos; 

-        if (upper == lower) {

-          return (-lower) - 1;

-        }

-      } else {  // fs is larger than item at pos in array; search upwards

-        lower = pos + 1;

-        if (lower == upper) {

-          return (-upper) - 1;

-        }

-      }

-    }

-  }

-  

-  /**

-   * @see Set#remove(Object)

-   */

-  @Override

   public boolean remove(Object o) {

-    processBatch();

+    if (o == null) {

+      throw new IllegalArgumentException("Null cannot be the argument to remove");

+    }

+    

+    if (!(o instanceof TOP)) {

+      return false;

+    }

+    

     TOP fs = (TOP) o;

     

-    int pos = find(fs);

+    int pos = binarySearch(a, a_firstUsedslot, a_nextFreeslot, fs, comparatorNoTypeWithID);

+//        find(fs); // using ID as part of comparator

     if (pos < 0) {

       return false;

     }

@@ -1007,772 +402,137 @@
     // at this point, pos points to a spot that compares "equal" using the comparator

     // for sets, this is the single item that is in the index

     // for sorted, because find uses the compareWithID comparator, this is the unique equal element

-    assert a[pos] != null;

-    a[pos] = null;

-    size --;

-    modificationCount ++;

-    if (size == 0) {

-      clearResets();  // also clears last removed pos

-    } else {

-      // size is > 0

-      if (pos == a_firstUsedslot) {

-        do {  // removed the first used slot

-          a_firstUsedslot ++;

-        } while (a[a_firstUsedslot] == null);

-      } else if (pos == a_nextFreeslot - 1) {

-        do {

-          a_nextFreeslot --;

-        } while (a[a_nextFreeslot - 1] == null);

-        highest = a[a_nextFreeslot - 1];

-      } 

-      

-      if (size < ((a_nextFreeslot - a_firstUsedslot) >> 1) &&

-          size > 8) {

-        compressOutRemoves();  // also clears lastRemovedPos

-      } else {

-        // update lastRemovedPos

-        lastRemovedPos = (pos > a_firstUsedslot && pos < (a_nextFreeslot - 1))

-                           ? pos  // is a valid position 

-                           : -1;  // is not a valid position

+    

+    // compute closest space 

+    

+    /******************************************

+     * remove by shifting using closest space *

+     ******************************************/

+    final int distanceFromEnd = a_nextFreeslot - pos;

+    final int distanceFromFront = pos - a_firstUsedslot;

+    

+    if (distanceFromFront < distanceFromEnd) {

+      if (distanceFromFront > 0) {  // skip when distance is 0 - no move needed

+        System.arraycopy(a, a_firstUsedslot,  a,  a_firstUsedslot + 1, distanceFromFront);

       }

+      a[a_firstUsedslot] = null;      

+      a_firstUsedslot ++;

+    } else {

+      if (distanceFromEnd > 1) { // skip when distance from end == 0, no move needed

+        System.arraycopy(a,  pos + 1, a,  pos,  distanceFromEnd - 1); // sub 1 because a_nextFreeslot is exclusive

+      }

+      a_nextFreeslot --;

+      a[a_nextFreeslot] = null;

     }

+//    modificationCount ++; 

     return true;

   }

   

-  /**

-   * When the main array between the first used slot and the next free slot has too many nulls 

-   * representing removed items, scan and gc them.

-   *   assumes: first used slot is not null, nextFreeslot - 1 is not null

-   */

-  private void compressOutRemoves() {

-    int j = a_firstUsedslot + 1;

-    for (int i = a_firstUsedslot + 1; i < a_nextFreeslot; i++, j++) {

-      while (a[i] == null) {

-        i ++;

-      }

-      if (i > j) {

-        a[j] = a[i];

-      }

-    }

-    

-    Arrays.fill(a, j, a_nextFreeslot, null);

-    a_nextFreeslot = j;

-    lastRemovedPos = -1;

-  }

-  

-  /**

-   * @see Set#containsAll(Collection)

-   */

-  @Override

-  public boolean containsAll(Collection<?> c) {

-    throw new UnsupportedOperationException();

-  }

-

-  /**

-   * @see Set#addAll(Collection)

-   */

-  @Override

-  public boolean addAll(Collection<? extends TOP> c) {

-    boolean changed = false;

-    for (TOP item : c) {

-      changed |= add(item);

-    }

-    return changed;

-  }

-  

-  /**

-   * @see Set#retainAll(Collection)

-   */

-  @Override

-  public boolean retainAll(Collection<?> c) {

-    throw new UnsupportedOperationException();

-  }

-

-  /**

-   * @see Set#removeAll(Collection)

-   */

-  @Override

-  public boolean removeAll(Collection<?> c) {

-    throw new UnsupportedOperationException();

-  }

   

   /**

    * @see Set#clear()

    */

-  @Override

   public void clear() {

     if (isEmpty()) {

       return;

     }

-    if (!shrinkCapacity()) {

-//      //debug 

-//      if (a_firstUsedslot == -1) {

-//        System.out.println("a_firstUsedslot was -1");

-//      }

-//      if (a_nextFreeslot == -1) {

-//        System.out.println("a_nextFreeslot was -1");

-//      }

-      Arrays.fill(a, a_firstUsedslot, a_nextFreeslot, null);      

+    

+    int len = a.length;

+    if (maxSize < (len >> 3) && len > 128) {  

+      int newSize =  len >> 1;

+      a = new TOP[newSize];

+    } else {

+      Arrays.fill(a, null);

     }

-    clearResets();

-  }

-  

-  private void clearResets() {

     a_firstUsedslot = 0;

     a_nextFreeslot = 0;

-    batch.clear();

-    size = 0;

+//    modificationCount ++;

     maxSize = 0;

-    nullBlockStart = -1;

-    nullBlockEnd = -1;

-    doingBatchAdds = false; // just for safety, not logically needed I think.

-    highest = null;    

-    modificationCount ++;

-    lastRemovedPos = -1;

-  }

-

-  /**

-   * @see NavigableSet#lower(Object)

-   */

-  @Override

-  public TOP lower(TOP fs) {

-    int pos = lowerPos(fs);

-    return (pos < 0) ? null : a[pos];

-  }

-  

-  /**

-   * @param fs element to test

-   * @return pos of greatest element less that fs or -1 if no such

-   */

-  public int lowerPos(TOP fs) {

-    processBatch();

-    int pos = find(fs); // position of lowest item GE fs  

-    pos = (pos < 0) ? ((-pos) - 2) : (pos - 1);

-    // above line subtracts 1 from LE pos; pos is now lt, may be -1

-    while (pos >= a_firstUsedslot) {

-      if (a[pos] != null) {

-        return pos;

-      }

-      pos --;

-    }

-    return -1; 

-  }

-

-

-  /**

-   * @see NavigableSet#floor(Object)

-   */

-  @Override

-  public TOP floor(TOP fs) {

-    int pos = floorPos(fs);

-    return (pos < 0) ? null : a[pos];

-  }

-  

-  /**

-   * @param fs -

-   * @return -

-   */

-  public int floorPos(TOP fs) {

-    processBatch();

-    int pos = find(fs);  // position of lowest item GE fs

-    if (pos < 0){

-      pos = (-pos) - 2;

-    }

-    // pos is = or lt, may be -1

-    while (pos >= a_firstUsedslot) {

-      if (a[pos] != null) {

-        return pos;

-      }

-      pos --;

-    }

-    return -1;

-  }

-

-  /**

-   * @see NavigableSet#ceiling(Object)

-   */

-  @Override

-  public TOP ceiling(TOP fs) {

-    int pos = ceilingPos(fs);

-    return (pos < a_nextFreeslot) ? a[pos] : null;

-  }

-  

-

-  /**

-   * @param fs -

-   * @return -

-   */

-  public int ceilingPos(TOP fs) {

-    processBatch();

-    int pos = find(fs); // position of lowest item GE fs

-    if (pos < 0){

-      pos = (-pos) -1;

-    } else {

-      return pos;

-    }

     

-    while (pos < a_nextFreeslot) {

-      if (a[pos] != null) {

-        return pos;

-      }

-      pos ++;

-    }

-    return pos;

   }

-

+  

   /**

-   * @see NavigableSet#higher(Object)

+   * Guaranteed by caller to have an equal (withoutID) item, but might be the "end" item

+   * searching up to find it.  

+   * @param fs - the fs to search for

+   * @param start the index representing the lower bound (inclusive) to search for

+   * @param end the index representing the upper bound (exclusive) to search for

+   *            Not called unless there's one equal item below this.

+   * @param comparator the comparator to use (with or without type)

+   * @return - the index of the leftmost equal (without id) item

    */

-  @Override

-  public TOP higher(TOP fs) {

-    int pos = higherPos(fs);

-    return (pos < a_nextFreeslot) ? a[pos] : null;

-  }

+  public int binarySearchLeftMostEqual(final TOP fs, int start, int end, Comparator<TOP> comparator) {

 

-  /**

-   * @param fs the Feature Structure to use for positioning

-   * @return the position that's higher

-   */

-  public int higherPos(TOP fs) {

-    processBatch();

-    int pos = find(fs); // position of lowest item GE fs

-    pos = (pos < 0) ? ((-pos) -1) : (pos + 1);

+//    assert start >= 0;    

+//    assert start < end;

     

-    while (pos < a_nextFreeslot) {

-      if (a[pos] != null) {

-        return pos;

-      }

-      pos ++;

-    }

-    return pos;

-  }

-

-  /**

-   * @see NavigableSet#pollFirst()

-   */

-  @Override

-  public TOP pollFirst() {

-    throw new UnsupportedOperationException();

-  }

-

-  /**

-   * @see NavigableSet#pollLast()

-   */

-  @Override

-  public TOP pollLast() {

-    throw new UnsupportedOperationException();

-  }

-

-  /**

-   * @see Iterable#iterator()

-   */

-  @Override

-  public Iterator<TOP> iterator() {

-    processBatch();

-    if (a_nextFreeslot == 0) {

-      return Collections.emptyIterator();

-    }

-    return new Iterator<TOP>() {

-      private int pos = a_firstUsedslot;

-      { incrToNext(); 

-        if (MEASURE) {

-          int s = a_nextFreeslot - a_firstUsedslot;

-          iterPctEmptySkip[(s - size()) * 10 / s] ++;

+    int lower = start, upper = end;

+    for (;;) {

+    

+      int mid = (lower + upper) >>> 1;  // overflow aware

+      TOP item = a[mid];

+      int pos = mid;

+         

+      int c = comparator.compare(item, fs);

+      if (c == 0) {

+        upper = pos;  // upper is exclusive

+        if (upper == lower) {

+          return upper;

+        }

+      } else {  // item is less than fs; search upwards

+        lower = pos + 1;             // lower is inclusive

+        if (lower == upper) {

+          return upper;

         }

       }

-       

-      @Override

-      public boolean hasNext() {

-        processBatch();

-        return pos < a_nextFreeslot;

-      }

+    }

+  }

+  

+

+  /* (non-Javadoc)

+   * @see java.lang.Iterable#iterator()

+   */

+  @Override

+  public Iterator<T> iterator() {

+    return new Iterator<T>() {

+

+      int pos = a_firstUsedslot;

       

       @Override

-      public TOP next() {

+      public boolean hasNext() {

+        return pos >= 0 && pos < a_nextFreeslot;

+      }

+

+      @Override

+      public T next() {

         if (!hasNext()) {

           throw new NoSuchElementException();

         }

-

-        TOP r = a[pos++];

-        incrToNext();

-        return r;        

-      }

-      

-      private void incrToNext() {

-        while (pos < a_nextFreeslot) {

-          if (a[pos] != null) {

-            break;

-          }

-          pos ++;

-        }

-      }

+        return (T)a[pos++];

+      }      

     };

   }

-

-  /**

-   * @see NavigableSet#descendingSet()

-   */

-  @Override

-  public NavigableSet<TOP> descendingSet() {

-    throw new UnsupportedOperationException();

+  

+  public TOP[] toArray() {

+    TOP[] r = new TOP[size()];

+    System.arraycopy(a, a_firstUsedslot, r, 0, size());

+    return r;    

   }

 

-  /**

-   * @see NavigableSet#descendingIterator()

-   */

-  @Override

-  public Iterator<TOP> descendingIterator() {

-    processBatch();

-    return new Iterator<TOP>() {

-      private int pos = a_nextFreeslot - 1;    // 2 slots:  next free = 2, first slot = 0

-                                               // 1 slot:   next free = 1, first slot = 0

-                                               // 0 slots:  next free = 0; first slot = 0 (not -1)

-      { if (pos >= 0) {  // pos is -1 if set is empty

-        decrToNext(); 

-        }

-      }

-       

-      @Override

-      public boolean hasNext() {

-        return pos >= a_firstUsedslot;

-      }

-      

-      @Override

-      public TOP next() {

-        if (!hasNext()) {

-          throw new NoSuchElementException();

-        }

-

-        TOP r = a[pos--];

-        decrToNext();

-        return r;        

-      }

-      

-      private void decrToNext() {

-        while (pos >= a_firstUsedslot) {

-          if (a[pos] != null) {

-            break;

-          }

-          pos --;

-        }

-      }

-    };

-  }

-

-  /**

-   * @see NavigableSet#subSet(Object, boolean, Object, boolean)

-   */

-  @Override

-  public NavigableSet<TOP> subSet(TOP fromElement, boolean fromInclusive, TOP toElement, boolean toInclusive) {

-    return new SubSet(() -> this, fromElement, fromInclusive, toElement, toInclusive, false, null);

-  }

-

-  /**

-   * @see NavigableSet#headSet(Object, boolean)

-   */

-  @Override

-  public NavigableSet<TOP> headSet(TOP toElement, boolean inclusive) {

-    if (isEmpty()) {

-      return this; 

+  public <U> U[] toArray(U[] a1) {

+    if (a1.length < size()) {

+      a1 = (U[]) Array.newInstance(a1.getClass(), size());

     }

-    return subSet(first(), true, toElement, inclusive);     

-  }

-

-  /**

-   * @see NavigableSet#tailSet(Object, boolean)

-   */  

-  @Override

-  public NavigableSet<TOP> tailSet(TOP fromElement, boolean inclusive) {

-    if (isEmpty()) {

-      return this;

-    }

-    return subSet(fromElement, inclusive, last(), true);

-  }

-

-  /**

-   * @see NavigableSet#subSet(Object, Object)

-   */

-  @Override

-  public SortedSet<TOP> subSet(TOP fromElement, TOP toElement) {

-    return subSet(fromElement, true, toElement, false);

-  }

-

-  /**

-   * @see NavigableSet#headSet(Object)

-   */

-  @Override

-  public SortedSet<TOP> headSet(TOP toElement) {

-    return headSet(toElement, false);

-  }

-

-  /**

-   * @see NavigableSet#tailSet(Object)

-   */

-  @Override

-  public SortedSet<TOP> tailSet(TOP fromElement) {

-    return tailSet(fromElement, true);

+    System.arraycopy(a1,  a_firstUsedslot, a1,  0, size());

+    return a1;

   }

   

+//  public int getModificationCount() {

+//    return modificationCount;

+//  }

   

-  /**

-   * This is used in a particular manner:

-   *   only used to create iterators over that subset

-   *     -- no insert/delete

-   */

-  public static class SubSet implements NavigableSet<TOP> {

-    final Supplier<OrderedFsSet_array> theSet;

-    final private TOP fromElement;

-    final private TOP toElement;

-    final private boolean fromInclusive;

-    final private boolean toInclusive;

-    

-    final private int firstPosInRange;

-    final private int lastPosInRange;  // inclusive

-    

-    final private TOP firstElementInRange;

-    final private TOP lastElementInRange;

-        

-    private int sizeSubSet = -1; // lazy - computed on first ref

-

-    private OrderedFsSet_array theSet() {

-      return theSet.get();

-    }

-    

-    SubSet(Supplier<OrderedFsSet_array> theSet, TOP fromElement, boolean fromInclusive, TOP toElement, boolean toInclusive) {

-      this(theSet, fromElement, fromInclusive, toElement, toInclusive, true, theSet.get().comparatorWithID);

-    }

-    

-    SubSet(Supplier<OrderedFsSet_array> theSet, TOP fromElement, boolean fromInclusive, TOP toElement, boolean toInclusive, boolean doTest, Comparator<TOP> comparator) {

-      this.theSet = theSet;

-      this.fromElement = fromElement;

-      this.toElement = toElement;

-      this.fromInclusive = fromInclusive;

-      this.toInclusive = toInclusive;

-      if (doTest && comparator.compare(fromElement, toElement) > 0) {

-        throw new IllegalArgumentException();

-      }

-      OrderedFsSet_array s = theSet();

-      theSet().processBatch();    

-      firstPosInRange = fromInclusive ? s.ceilingPos(fromElement) : s.higherPos(fromElement);

-      lastPosInRange  = toInclusive ? s.floorPos(toElement) : s.lowerPos(toElement);

-      // lastPosInRange can be LT firstPosition if fromInclusive is false

-      //   In this case, the subset is empty

-      if (lastPosInRange < firstPosInRange) {

-        firstElementInRange = null;

-        lastElementInRange = null;

-      } else {

-        firstElementInRange = s.a[firstPosInRange];

-        lastElementInRange = s.a[lastPosInRange];

-      }

-    }

-    

-    @Override

-    public Comparator<? super TOP> comparator() {

-      return theSet().comparatorWithID;

-    }

-

-    @Override

-    public TOP first() {

-      return firstElementInRange;

-    }

-

-    @Override

-    public TOP last() {

-      return lastElementInRange;

-    }

-

-    @Override

-    public int size() {

-      if (firstElementInRange == null) {

-        return 0;

-      }

-      if (sizeSubSet == -1) {

-        Iterator<TOP> it = iterator();

-        int i = 0;

-        while (it.hasNext()) {

-          it.next();

-          i++;

-        }

-        sizeSubSet = i;

-      }

-      return sizeSubSet;

-    }

-

-    @Override

-    public boolean isEmpty() {

-      return size() == 0;

-    }

-

-    @Override

-    public boolean contains(Object o) {

-      TOP fs = (TOP) o;

-      if (!isInRange(fs)) {

-        return false;

-      }

-      return theSet().contains(o);

-    }

-

-    @Override

-    public Object[] toArray() {

-      throw new UnsupportedOperationException();

-    }

-

-    @Override

-    public <T> T[] toArray(T[] a1) {

-      throw new UnsupportedOperationException();

-    }

-

-    @Override

-    public boolean add(TOP e) {

-      throw new UnsupportedOperationException();

-    }

-

-    @Override

-    public boolean remove(Object o) {

-      throw new UnsupportedOperationException();

-    }

-

-    @Override

-    public boolean containsAll(Collection<?> c) {

-      throw new UnsupportedOperationException();

-    }

-

-    @Override

-    public boolean addAll(Collection<? extends TOP> c) {

-      throw new UnsupportedOperationException();

-    }

-

-    @Override

-    public boolean retainAll(Collection<?> c) {

-      throw new UnsupportedOperationException();

-    }

-

-    @Override

-    public boolean removeAll(Collection<?> c) {

-      throw new UnsupportedOperationException();

-    }

-

-    @Override

-    public void clear() {

-      throw new UnsupportedOperationException();

-    }

-

-    @Override

-    public TOP lower(TOP fs) {

-      if (lastElementInRange == null || isLeFirst(fs)) {

-        return null;

-      }

-      // if the key is > lastElement, 

-      //   return last element

-      if (isGtLast(fs)) {

-        return lastElementInRange;

-      }

-      // in range

-      return theSet().lower(fs);

-    }

-

-    @Override

-    public TOP floor(TOP fs) {

-      

-      // if the key is < the first element in the range, return null

-      if (lastElementInRange == null || isLtFirst(fs)) {

-        return null;

-      }

-      

-      // if the key is >= lastElement, 

-      //   return last element

-      if (isGeLast(fs)) {

-        return lastElementInRange;

-      }

-      

-      return theSet().floor(fs);

-    }

-

-    @Override

-    public TOP ceiling(TOP fs) {

-      // if the key is > the last element in the range, return null

-      if (firstElementInRange == null || isGtLast(fs)) {

-        return null;

-      }

-      

-      if (isLeFirst(fs)) {

-        return firstElementInRange;

-      }

-      

-      return theSet().ceiling(fs);

-    }

-

-    @Override

-    public TOP higher(TOP fs) {

-      if (firstElementInRange == null || isGeLast(fs)) {

-        return null;

-      }

-      

-      if (isLtFirst(fs)) {

-        return firstElementInRange;

-      }

-      

-      return theSet().higher(fs);

-    }

-

-    @Override

-    public TOP pollFirst() {

-      throw new UnsupportedOperationException();

-    }

-

-    @Override

-    public TOP pollLast() {

-      throw new UnsupportedOperationException();

-    }

-

-    @Override

-    public Iterator<TOP> iterator() {

-      if (firstElementInRange == null) {

-        return Collections.emptyIterator();

-      }

-      return new Iterator<TOP>() {

-        private int pos = firstPosInRange;

-         

-        @Override

-        public boolean hasNext() {

-          return pos <= lastPosInRange;  // lastPos is inclusive

-        }

-        

-        @Override

-        public TOP next() {

-          if (!hasNext()) {

-            throw new NoSuchElementException();

-          }

-

-          TOP r = theSet().a[pos++];

-          incrToNext();

-          return r;        

-        }

-        

-        private void incrToNext() {

-          while (pos <= lastPosInRange) {

-            if (theSet().a[pos] != null) {

-              break;

-            }

-            pos ++;

-          }

-        }

-      };

-    }

-

-    @Override

-    public NavigableSet<TOP> descendingSet() {

-      throw new UnsupportedOperationException();

-    }

-

-    @Override

-    public Iterator<TOP> descendingIterator() {

-      if (firstElementInRange == null) {

-        return Collections.emptyIterator();

-      }

-      return new Iterator<TOP>() {

-        private int pos = lastPosInRange;

-         

-        @Override

-        public boolean hasNext() {

-          return pos >= firstPosInRange;  

-        }

-        

-        @Override

-        public TOP next() {

-          if (!hasNext()) {

-            throw new NoSuchElementException();

-          }

-

-          TOP r = theSet().a[pos--];

-          decrToNext();

-          return r;        

-        }

-        

-        private void decrToNext() {

-          while (pos >= firstPosInRange) {

-            if (theSet().a[pos] != null) {

-              break;

-            }

-            pos --;

-          }

-        }

-      };

-    }

-

-    @Override

-    public NavigableSet<TOP> subSet(TOP fromElement1, boolean fromInclusive1, TOP toElement1,

-        boolean toInclusive1) {

-      if (!isInRange(fromElement1) || !isInRange(toElement1)) {

-        throw new IllegalArgumentException();

-      }

-      return theSet().subSet(fromElement1, fromInclusive1, toElement1, toInclusive1);  

-    }

-

-    @Override

-    public NavigableSet<TOP> headSet(TOP toElement1, boolean inclusive) {

-      return subSet(fromElement, fromInclusive, toElement1, inclusive);

-    }

-

-    @Override

-    public NavigableSet<TOP> tailSet(TOP fromElement1, boolean inclusive) {

-      return subSet(fromElement1, inclusive, toElement, toInclusive);

-    }

-

-    @Override

-    public SortedSet<TOP> subSet(TOP fromElement1, TOP toElement1) {

-      return subSet(fromElement1, true, toElement1, false);

-    }

-

-    @Override

-    public SortedSet<TOP> headSet(TOP toElement1) {

-      return headSet(toElement1, true);

-    }

-

-    @Override

-    public SortedSet<TOP> tailSet(TOP fromElement1) {

-      return tailSet(fromElement1, false);

-    }

-  

-    private boolean isGtLast(TOP fs) {

-      return theSet().comparatorWithID.compare(fs, lastElementInRange) > 0;      

-    }

-    

-    private boolean isGeLast(TOP fs) {

-      return theSet().comparatorWithID.compare(fs,  lastElementInRange) >= 0;

-    }

-

-    private boolean isLtFirst(TOP fs) {

-      return theSet().comparatorWithID.compare(fs, firstElementInRange) < 0;

-    }

-

-    private boolean isLeFirst(TOP fs) {

-      return theSet().comparatorWithID.compare(fs, firstElementInRange) <= 0;

-    }

-    

-    private boolean isInRange(TOP fs) {

-      return isInRangeLower(fs) && isInRangeHigher(fs);

-    }

-      

-    private boolean isInRangeLower(TOP fs) {

-      if (firstElementInRange == null) {

-        return false;

-      }

-      int r = theSet().comparatorWithID.compare(fs, firstElementInRange);

-      return fromInclusive ? (r >= 0) : (r > 0);

-    }

-    

-    private boolean isInRangeHigher(TOP fs) {

-      if (lastElementInRange == null) {

-        return false;

-      }

-      int r = theSet().comparatorWithID.compare(fs, lastElementInRange);

-      return toInclusive ? (r <= 0) : (r < 0);

-    }

-  }

-

-  public int getModificationCount() {

-    return modificationCount;

+  public T getAtPos(int pos) {

+    return (T) a[pos];

   }

   

   @Override

@@ -1800,19 +560,15 @@
     }

     b   .append(", a_nextFreeslot=").append(a_nextFreeslot)

         .append(", a_firstUsedslot=").append(a_firstUsedslot)

-        .append(", batch=").append(batch)

-        .append(", origComparator=").append(comparatorWithID)

-        .append(", size=").append(size)

+        .append(", origComparator=").append(comparatorNoTypeWithID)

         .append(", maxSize=").append(maxSize)

-        .append(", highest=").append(highest)

-        .append(", nullBlockStart=").append(nullBlockStart)

-        .append(", nullBlockEnd=").append(nullBlockEnd).append("]");

+        .append("]");

     return b.toString();

   } 

  

   // these are approximate - don't take into account multi-thread access

   static private int addToEndCount = 0;

-  static private int addNotToEndCount = 0;

+//  static private int addNotToEndCount = 0;

   static private int batchCountHistogram[];

   static private int batchAddCount = 0; 

   static private int batchAddTotal = 0; // includes things not added because of dups

@@ -1870,5 +626,64 @@
     }

 

   }

-  

+

+//  /* (non-Javadoc)

+//   * @see java.util.Set#contains(java.lang.Object)

+//   */

+//  @Override

+//  public boolean contains(Object o) {

+//    if (o == null) {

+//      throw new IllegalArgumentException();

+//    }

+//    if (isEmpty()) {

+//      return false;

+//    }

+//    if (! (o instanceof TOP)) {

+//      return false;

+//    }

+//    TOP fs = (TOP) o;

+//    return findWithoutID(fs) >= 0;

+//  }

+

+

+//

+//

+//  /* (non-Javadoc)

+//   * @see java.util.Set#containsAll(java.util.Collection)

+//   */

+//  @Override

+//  public boolean containsAll(Collection<?> c) {

+//    throw new UnsupportedOperationException();

+//  }

+//

+//  /* (non-Javadoc)

+//   * @see java.util.Set#addAll(java.util.Collection)

+//   */

+//  @Override

+//  public boolean addAll(Collection<? extends T> c) {

+//    boolean changed = false;

+//    for (T item : c) {

+//      changed |= add(item);

+//    }

+//    return changed;

+//  }

+//

+//  /* (non-Javadoc)

+//   * @see java.util.Set#retainAll(java.util.Collection)

+//   */

+//  @Override

+//  public boolean retainAll(Collection<?> c) {

+//    throw new UnsupportedOperationException();

+//  }

+//

+//  /* (non-Javadoc)

+//   * @see java.util.Set#removeAll(java.util.Collection)

+//   */

+//  @Override

+//  public boolean removeAll(Collection<?> c) {

+//    throw new UnsupportedOperationException();

+//  }

+//

+//

+//  

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/OrderedFsSet_array2.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/OrderedFsSet_array2.java
new file mode 100644
index 0000000..c22ddc7
--- /dev/null
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/OrderedFsSet_array2.java
@@ -0,0 +1,2141 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.internal.util;

+

+import java.lang.reflect.Array;

+import java.util.ArrayList;

+import java.util.Arrays;

+import java.util.Collection;

+import java.util.Collections;

+import java.util.Comparator;

+import java.util.Iterator;

+import java.util.NavigableSet;

+import java.util.NoSuchElementException;

+import java.util.Set;

+import java.util.SortedSet;

+import java.util.function.Supplier;

+

+import org.apache.uima.jcas.cas.TOP;

+import org.apache.uima.util.impl.Constants;

+

+/**

+ * This one not in current use

+ * Maybe be put back into service when the array becomes large and it starts outperforming the other

+ * 

+ * A set of FSs, ordered using a comparator 

+ * Not thread-safe, use on single thread only

+ * 

+ * Use: set-sorted indexes in UIMA

+ * 

+ * Entries kept in order in 1 big ArrayList

+ * 

+ * Adds optimized:

+ *   - maintain high mark, if &gt;, add to end

+ *   - batch adds other than above

+ *     -- do when reference needed

+ *     -- sort the to be added

+ *   - to add to pos p, shift elements in p to higher, insert   

+ * 

+ * shifting optimization: 

+ *   removes replace element with null

+ *   shift until hit null 

+ *   

+ * nullBlock - a group of nulls (free space) together

+ *   - might be created by a batch add which 

+ *     adds a block of space all at once

+ *   - might arise from encountering 1 or more "nulls" created

+ *     by removes

+ *   - id by nullBlockStart (inclusive) and nullBlockEnd (exclusive)

+ *   

+ * bitset: 1 for avail slot

+ *   used to compute move for array copy

+ * 

+ *   

+ */

+public class OrderedFsSet_array2 implements NavigableSet<TOP> {

+//  public boolean specialDebug = false;

+  final private static boolean TRACE = false;

+  final private static boolean MEASURE = false;

+  final private static int DEFAULT_MIN_SIZE = 8;  // power of 2 please

+  final private static int MAX_DOUBLE_SIZE = 1024 * 1024 * 4;  // 4 million, power of 2 please

+  final private static int MIN_SIZE = 8;

+   

+//  final private static MethodHandle getActualArray;

+//  

+//  static {

+//    Field f;

+//    try {

+//      f = ArrayList.class.getDeclaredField("array");

+//    } catch (NoSuchFieldException e) {

+//      try {

+//        f = ArrayList.class.getDeclaredField("elementData");

+//      } catch (NoSuchFieldException e2) {

+//        throw new RuntimeException(e2);

+//      }

+//    }

+//    

+//    f.setAccessible(true);

+//    try {

+//      getActualArray = Misc.UIMAlookup.unreflectGetter(f);

+//    } catch (IllegalAccessException e) {

+//      throw new RuntimeException(e);

+//    }

+//  }

+  

+    

+  TOP[] a = new TOP[DEFAULT_MIN_SIZE];

+  /**

+   * index of slot at the end which is free, all following slots are free too

+   */

+  int a_nextFreeslot = 0;

+  int a_firstUsedslot = 0;

+  

+  private final ArrayList<TOP> batch = new ArrayList<>();

+  

+  final public Comparator<TOP> comparatorWithID;

+  final public Comparator<TOP> comparatorWithoutID;

+  private int size = 0;

+  private int maxSize = 0;

+  

+  private TOP highest = null;

+  private int nullBlockStart = -1;  // inclusive

+  private int nullBlockEnd = -1 ;    // exclusive

+  

+  private boolean doingBatchAdds = false;

+  private int modificationCount = 0;

+  /**

+   * Tricky to maintain.

+   * If holes are moved around, this value may need updating

+   */

+  private int lastRemovedPos = -1;

+  

+  private StringBuilder tr = TRACE ? new StringBuilder() : null;

+//  private int nbrNewSlots;  // this is a field so it can be read and set by insertSpace

+  

+  // debug

+//  private int itercount = 0;

+  

+  public OrderedFsSet_array2(Comparator<TOP> comparatorWithID, Comparator<TOP> comparatorWithoutID) {

+    this.comparatorWithID = comparatorWithID;

+    this.comparatorWithoutID = comparatorWithoutID;

+  }

+  

+  /**

+   * copy constructor - not currently used (06/2017)

+   * @param set the original to be copied

+   */

+  public OrderedFsSet_array2(OrderedFsSet_array2 set) {

+    set.processBatch();

+    this.a = Arrays.copyOf(set.a, set.a.length);

+    this.a_nextFreeslot = set.a_nextFreeslot;

+    this.a_firstUsedslot = set.a_firstUsedslot;

+    this.comparatorWithID = set.comparatorWithID;

+    this.comparatorWithoutID = set.comparatorWithoutID;

+    this.size = set.size;

+    this.maxSize = set.maxSize;

+    this.highest = set.highest;

+    this.nullBlockStart = set.nullBlockStart;

+    this.nullBlockEnd = set.nullBlockEnd;

+    this.modificationCount = set.modificationCount;

+    this.lastRemovedPos = set.lastRemovedPos;

+  }

+

+  /**

+   * called to make a read-only copy

+   * @param set -

+   * @param isReadOnly -

+   */

+  public OrderedFsSet_array2(OrderedFsSet_array2 set, boolean isReadOnly) {

+    if (!isReadOnly) Misc.internalError();

+    set.processBatch();

+    this.size = set.size;

+    this.a = (size == 0) ? Constants.EMPTY_TOP_ARRAY : Arrays.copyOf(set.a, set.a.length);

+    this.a_nextFreeslot = set.a_nextFreeslot;

+    this.a_firstUsedslot = set.a_firstUsedslot;

+    this.comparatorWithID = set.comparatorWithID;

+    this.comparatorWithoutID = set.comparatorWithoutID;

+    

+    this.maxSize = set.maxSize;

+    this.highest = set.highest;

+    this.nullBlockStart = set.nullBlockStart;

+    this.nullBlockEnd = set.nullBlockEnd;

+    this.modificationCount = set.modificationCount;

+    this.lastRemovedPos = set.lastRemovedPos;

+  }

+  

+  

+

+  /**

+   * @see SortedSet#comparator()

+   */

+  @Override

+  public Comparator<? super TOP> comparator() {

+    return comparatorWithID;

+  }

+

+  /**

+   * @see SortedSet#first()

+   */

+  @Override

+  public TOP first() {

+    processBatch();

+    if (size == 0) {

+      throw new NoSuchElementException();

+    }

+    for (int i = a_firstUsedslot; i < a_nextFreeslot; i++) {

+      TOP item = a[i];

+      if (null != item) {

+        if (i > a_firstUsedslot) {

+          a_firstUsedslot = i;

+        }

+        return item; 

+      }

+    }

+    Misc.internalError();

+    return null;

+  }

+

+  /**

+   * @see SortedSet#last()

+   */

+  @Override

+  public TOP last() {

+    processBatch();

+    if (size == 0) {

+      throw new NoSuchElementException();

+    }

+    for (int i = a_nextFreeslot - 1; i >= a_firstUsedslot; i--) {

+      TOP item = a[i];

+      if (item != null) {

+        if (i < a_nextFreeslot - 1) {

+          a_nextFreeslot = i + 1;

+        }

+        return item;

+      }

+    }

+    Misc.internalError();

+    return null;

+  }

+

+  /**

+   * @see Set#size()

+   */

+  @Override

+  public int size() {

+    processBatch();

+    return size;

+  }

+

+  /**

+   * @see Set#isEmpty()

+   */

+  @Override

+  public boolean isEmpty() {

+    return size == 0 && batch.size() == 0;

+  }

+

+  /**

+   * @see Set#contains(Object)

+   */

+  @Override

+  public boolean contains(Object o) {

+    if (o == null) {

+      throw new IllegalArgumentException();

+    }

+    if (isEmpty()) {

+      return false;

+    }

+    TOP fs = (TOP) o;

+    processBatch();

+    return find(fs) >= 0;

+  }

+

+  /**

+   * @see Set#toArray()

+   */

+  @Override

+  public Object[] toArray() {

+    Object [] r = new Object[size()];

+    int i = 0;

+    for (TOP item : a) {

+      if (item != null) {

+        r[i++] = item;

+      }

+    }

+//    try { // debug

+      assert r.length == i;

+//    } catch (AssertionError e) { // debug

+//      System.err.format("size: %,d, final index: %,d, array length: %,d%n", size(), i, a.length );

+//      for (int di = 0; di < a.length; di++) {

+//        System.err.format("a[%,d] = %s%n", di, a[di]);

+//      }

+//      System.err.format("first used slot: %,d, next free slot: %,d batch size: %,d,"

+//          + " nullblockstart: %,d nullBlockEnd: %d, lastRemovedPos: %,d",

+//          a_firstUsedslot, a_nextFreeslot, batch.size(), nullBlockStart, nullBlockEnd,

+//          lastRemovedPos);

+//      throw e;

+//    }

+    return r;

+  }

+

+  /**

+   * @see Set#toArray(Object[])

+   */

+  @SuppressWarnings("unchecked")

+  @Override

+  public <T> T[] toArray(T[] a1) {

+    if (a1.length < size()) {

+      a1 = (T[]) Array.newInstance(a.getClass(), size());

+    }

+    int i = 0;

+    for (TOP item : a) {

+      if (item != null) {

+        a1[i++] = (T) item;

+      }

+    }

+    if (i < a1.length) {

+      a1[i] = null;  // contract for toArray, when array bigger than items

+    }

+    return a1;

+  }

+

+  /**

+   * Note: doesn't implement the return value; always returns true;

+   * @see Set#add(Object)

+   */

+  

+  @Override

+  public boolean add(TOP fs) {

+    if (fs == null) {

+      throw new IllegalArgumentException("Null cannot be added to this set.");

+    }

+    if (highest == null) {

+      addNewHighest(fs);

+      return true;

+    }

+    

+    int c = comparatorWithID.compare(fs, highest);

+    if (c > 0) {

+      addNewHighest(fs);

+      return true;

+    }

+    

+    if (c == 0) {

+      return false;

+    }

+    

+    batch.add(fs);

+    if (MEASURE) {

+      addNotToEndCount ++;

+    }

+    return true;

+  }

+  

+  private void addNewHighest(TOP fs) {

+    highest = fs;

+    ensureCapacity(1);

+    a[a_nextFreeslot++] = fs;

+    incrSize();

+    if (MEASURE) {

+      addToEndCount++;

+    }

+    return;

+  }

+  

+  private void incrSize() {

+    size++;

+    maxSize = Math.max(maxSize, size);

+    modificationCount++;

+  }

+  

+//  /** validate array

+//   *    number of non-null elements == size

+//   */

+//  // debug

+//  private void validateA() {

+//    synchronized (batch) {

+//      try {

+//        if (nullBlockStart != -1) {

+//          assert a[nullBlockStart] == null;

+//          if (nullBlockStart > 0) {

+//            assert a[nullBlockStart - 1] != null;

+//          }

+//        }

+//        int sz = 0;

+//        for (TOP item : a) {

+//          if (item != null) {

+//            sz++;

+//          }

+//        }

+//    //    if (sz != size) {

+//    //      System.out.format("debug error OrderedFsSet_array size(): %,d array non-null element count: %,d%n",

+//    //          size, sz);

+//    //    }

+//        assert sz == size;

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

+//          assert a[i] == null;

+//        }

+//        for (int i = a_nextFreeslot; i < a.length; i++) {

+//          assert a[i] == null;

+//        }

+//        assert a_firstUsedslot < a_nextFreeslot;

+//        TOP prev = a[a_firstUsedslot];

+//        for (int i = a_firstUsedslot + 1; i < a_nextFreeslot; i++) {

+//          TOP fs = a[i];

+//          if (fs != null) {

+//            assert comparatorWithID.compare(fs, prev) > 0;

+//            prev = fs;

+//          }

+//        }

+//      } catch (AssertionError e) {

+//        e.printStackTrace();

+//      }

+//    }  

+//  }

+

+  private void ensureCapacity(int incr) {

+    int szNeeded = a_nextFreeslot + incr;

+    if (szNeeded <= a.length) {

+      return;

+    }

+    int sz = a.length;

+    do {

+      sz = (sz < MAX_DOUBLE_SIZE) ? (sz << 1) : (sz + MAX_DOUBLE_SIZE);

+    } while (sz < szNeeded);

+    

+    TOP[] aa = new TOP[sz];

+    System.arraycopy(a, 0, aa, 0, a_nextFreeslot);

+    a = aa;

+  }

+  

+  private boolean shrinkCapacity() {

+    int nextSmallerSize = getNextSmallerSize(2);

+    if (nextSmallerSize == MIN_SIZE) {

+      return false;

+    }

+    if (maxSize < nextSmallerSize) {

+      a = new TOP[getNextSmallerSize(1)];

+      maxSize = 0;

+      return true;

+    }

+    maxSize = 0; 

+    return false;

+  }

+  

+  /**

+   * get next smaller size

+   * @param n number of increments

+   * @return the size

+   */

+  private int getNextSmallerSize(int n) {

+    int sz = a.length;

+    if (sz <= MIN_SIZE) {

+      return MIN_SIZE;

+    }

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

+      sz = (sz > MAX_DOUBLE_SIZE) ? (sz - MAX_DOUBLE_SIZE) : sz >> 1;

+    }

+    return sz;

+  }

+  

+  public void processBatch() {

+    if (batch.size() != 0) {

+//      validateA();

+      doProcessBatch();

+//      validateA();

+    }

+  }

+  

+  /**

+   * Because multiple threads can be "reading" the CAS and using iterators,

+   * the sync must insure that the setting of batch.size() to 0 occurs after

+   * all the adding is done.

+   * 

+   * This keeps other threads blocked until the batch is completely processed.

+   */

+  private void doProcessBatch() {

+    synchronized (batch) {

+      int batchSize = batch.size();

+

+      if (batchSize == 0) {

+        return;  // another thread did this

+      }

+      if (doingBatchAdds == true) {

+        return;  // bypass recursive calls from Eclipse IDE on same thread, 

+                 // when its toString methods invoke this recursively to update the

+                 // debug UI for instance, while single stepping.

+      }

+      try {

+//        validateA();

+        // debug 

+//        assert (lastRemovedPos != -1) ? a[lastRemovedPos] == null : true;

+        doingBatchAdds = true;

+        if (MEASURE) {

+          batchAddCount ++;

+          batchAddTotal += batchSize;

+          batchCountHistogram[31 - Integer.numberOfLeadingZeros(batchSize)] ++;

+        }

+ 

+        /* the number of new empty slots created, 

+         *   may end up being larger than actually used because some of the items 

+         *   being inserted may already be in the array

+         *     - decreases as each item is actually inserted into the array

+         */

+        int nbrNewSlots = 1; // start at one, may increase

+        

+        if (batchSize > 1) {

+          // Sort the items to add 

+          Collections.sort(batch, comparatorWithID);

+          TOP prev = batch.get(batchSize - 1);

+        

+//          nbrNewSlots = batch.size();

+          // count dups (to reduce excess allocations)

+          //   deDups done using the comparatorWithID

+          final boolean useEq = comparatorWithID != comparatorWithoutID;  // true for Sorted, false for set

+          for (int i = batchSize - 2; i >= 0; i--) {

+            TOP item = batch.get(i);

+            if (useEq ? (item == prev) : (comparatorWithID.compare(item, prev) == 0)) {

+              batch.set(i + 1, null); // need to do this way so the order of adding is the same as v2

+              if (i + 1 == batchSize - 1) {

+                batchSize --;  // start with non-null when done

+              }

+            } else {

+              prev = item;

+              nbrNewSlots++;  // count of items that will actually be added; skips the duplicates

+            }

+          }

+        } 

+        

+        int i_batch = batchSize - 1;

+        int insertPosOfAddedSpace = 0;

+        TOP itemToAdd;

+        // skip entries already found

+        itemToAdd = batch.get(i_batch);

+        while (itemToAdd == null || (insertPosOfAddedSpace = find(itemToAdd)) >= 0) {

+          // skip any entries at end of list if they're already in the set

+          i_batch--;

+          nbrNewSlots --;

+          if (i_batch < 0) {

+            batch.clear();

+            return; // all were already in the index

+          }

+          itemToAdd = batch.get(i_batch);

+        }

+        

+//        assert nbrNewSlots > 0; // otherwise batch would be empty and would have returned before

+        

+        // insertPosOfAddedSpace is index to non-null item that is > itemToAdd

+        //                       or points to 1 beyond current size

+        insertPosOfAddedSpace = (- insertPosOfAddedSpace) - 1;

+        // insertPos is insert point, i_batch is index of first batch element to insert

+        // there may be other elements in batch that duplicate; these won't be inserted, but 

+        //   there will be space lost in this case

+         

+        int indexOfNewItem = insertSpace(insertPosOfAddedSpace, nbrNewSlots) // returns index of a non-null item

+                                                                           // the new item goes one spot to the left of this

+            - 1;  // inserts nulls at the insert point, shifting other cells down

+        assert nbrNewSlots == nullBlockEnd - nullBlockStart;

+

+        int nbrNewSlotsRemaining = nbrNewSlots;  // will be decremented as slots are used

+        // process first item

+        if (indexOfNewItem >= nullBlockStart) {

+          nbrNewSlotsRemaining --;

+        } // else, don't decr because we're using existing nulls

+        //debug

+//        assert (nbrNewSlotsRemaining > 0) ? indexOfNewItem != nullBlockStart : true;

+//        assert (nbrNewSlotsRemaining > 0) ? nullBlockEnd - 1 > nullBlockStart : true;

+        insertItem(indexOfNewItem, itemToAdd);

+//        TOP prevItem = itemToAdd;

+        if (indexOfNewItem + 1 == a_nextFreeslot) {

+          highest = itemToAdd;

+        }

+        

+        

+        //debug

+//        assert (nbrNewSlotsRemaining > 0) ? nullBlockStart != -1 : true;

+        

+        int bPos = i_batch - 1; // next after first one from end

+        for (; bPos >= 0; bPos --) {

+          itemToAdd = batch.get(bPos);

+          if (null == itemToAdd) {

+            continue;  // skipping a duplicate

+          }

+          int pos = findRemaining(itemToAdd); // search limited, ends at nullBlockstart

+    

+          if (pos >= 0) {

+            continue;  // already in the list

+          }

+          pos = (-pos) - 1;  // pos is the insert point 

+                             // new item goes 1 to left of this

+          assert a[pos] != null;

+          

+          indexOfNewItem = pos - 1;  // where the new item goes, 1 to left of insert point

+          if (nullBlockStart == 0) {

+            // this and all the rest of the elements are lower, insert in bulk

+            // because all are lower, none are in the array, so don't need the compare check

+            insertItem(indexOfNewItem--, itemToAdd);

+            nbrNewSlotsRemaining --;

+            bPos--;

+            

+            for (;bPos >= 0; bPos--) {          

+              itemToAdd = batch.get(bPos);

+              if (itemToAdd == null) {

+                continue;

+              }

+              insertItem(indexOfNewItem--, itemToAdd);

+              nbrNewSlotsRemaining --;  // do this way to respect skipped items due to == to prev        

+            }

+            break;

+          }

+//          validateA();

+//          boolean debugdidshift = false;

+          if (indexOfNewItem == -1 || null != a[indexOfNewItem]) {

+//            debugdidshift = true;

+            indexOfNewItem = shiftFreespaceDown(pos, nbrNewSlotsRemaining) - 1;  // results in null being available at pos - 1         

+            assert nbrNewSlotsRemaining == nullBlockEnd - nullBlockStart;

+            nbrNewSlotsRemaining --;  // only decr if using a new slot, skip if filling in a null

+          } else {

+            // there was a null in the spot to insert

+            // two cases: if the spot is within the nullBlock, need to decr nbrNewSlots

+            if (indexOfNewItem < nullBlockEnd && indexOfNewItem >= nullBlockStart) {

+              nbrNewSlotsRemaining --;  // the insertItem will adjust nullBlock start/end

+            }

+          }

+//          //debug

+//          assert (nbrNewSlotsRemaining > 0) ? nullBlockStart != -1 : true;

+          insertItem(indexOfNewItem, itemToAdd);

+//          //debug

+//          assert nbrNewSlotsRemaining == nullBlockEnd - nullBlockStart;

+//          assert (nbrNewSlotsRemaining > 0) ? nullBlockStart != -1 : true;

+

+        }

+        if (nbrNewSlotsRemaining > 0) {

+          // have extra space left over due to dups not being added

+          // If this space is not at beginning, move space to beginning or end (whichever is closer)

+//          if (indexOfNewItem - nbrNewSlotsRemaining > 0) { 

+          if (nullBlockEnd != a_firstUsedslot) {

+          // space is not at beginning

+          

+            assert nbrNewSlotsRemaining == nullBlockEnd - nullBlockStart;

+            int nullBlockEnd_end = a_nextFreeslot - nullBlockEnd;

+            int nullBlockStart_start = nullBlockStart - a_firstUsedslot;

+            assert nullBlockEnd_end > 0;

+            assert nullBlockStart_start > 0;

+

+            if (nullBlockStart_start <= nullBlockEnd_end) {

+              shiftFreespaceDown(a_firstUsedslot, nbrNewSlotsRemaining);

+//              System.arraycopy(a, indexOfNewItem - nbrNewSlots, a, 0, nbrNewSlots);

+//              a_firstUsedslot += nbrNewSlots;

+//              validateA();

+            } else {

+              shiftFreespaceUp(a_nextFreeslot, nbrNewSlotsRemaining);

+              a_nextFreeslot -= nbrNewSlotsRemaining;

+//              // move to end

+//              System.arraycopy(a, indexOfNewItem, a, indexOfNewItem - nbrNewSlots, a_nextFreeslot - indexOfNewItem);

+//              Arrays.fill(a, a_nextFreeslot - nbrNewSlots, a_nextFreeslot, null);

+//              a_nextFreeslot -= nbrNewSlots;

+//              validateA();

+            }

+          }

+        }

+        nullBlockStart = nullBlockEnd = -1;

+//        validateA();

+        batch.clear();

+      } finally {

+        doingBatchAdds = false;

+//        //debug

+//        assert (lastRemovedPos != -1) ? a[lastRemovedPos] == null : true;

+

+      }

+

+     }

+    

+    

+  }

+  

+  /**

+   * side effects:

+   *   increment size

+   *   reset a_firstUsedslot if adding in front

+   *   ( a_nextFreeslot not updated, because this method only called to inserting before end )

+   *   nullBlockEnd reduced conditionally

+   *   lastRemovedPos is reset if that position is used

+   * @param indexToUpdate - the index in the array to update with the item to add

+   * @param itemToAdd -

+   */

+  private void insertItem(int indexToUpdate, TOP itemToAdd) {

+//    validateA();

+    try {

+      assert indexToUpdate >= 0;

+      assert null == a[indexToUpdate];

+    } catch (AssertionError e) {

+      if (TRACE) {

+        System.err.println("OrderedFsSet_array caught assert.  array values around indexToUpdate: ");

+        for (int i = indexToUpdate - 2; i < indexToUpdate + 3; i++) {

+          if (i >= 0 && i < a.length) {

+            System.err.format("a[%,d]: %s%n", i, a[i].toString(2));

+          } else {

+            System.err.format("a[%,d}: out-of-range%n", i);

+          }

+        }

+        System.err.format("trace info: %n%s", tr);

+      }

+      throw e;

+    }

+ 

+    a[indexToUpdate] = itemToAdd;

+    if (indexToUpdate == lastRemovedPos) {

+      lastRemovedPos = -1;  // used up a last removed position

+    }

+    incrSize();

+    if (indexToUpdate < a_firstUsedslot) {

+      a_firstUsedslot = indexToUpdate;  

+    }

+    if (nullBlockEnd == indexToUpdate + 1) {

+      nullBlockEnd --;

+      if (nullBlockStart == nullBlockEnd) {

+        nullBlockStart = nullBlockEnd = -1;

+      }

+    }

+    if (nullBlockStart == indexToUpdate) {

+      nullBlockStart = nullBlockEnd = -1;

+    }

+//    validateA();

+  }

+

+  /**

+   * This is called when inserting new items from the batch.

+   * It does a bulk insert of space for all the items in the batch.

+   * 

+   * Attempts to move a small amount with a multi-part strategy:

+   *   - make use of existing "nulls" at the insert spot

+   *     -- if not enough,

+   *       --- if just need one more, compute distance from 3 possible source:

+   *            -- front, end, and lastRemovedPos (if not already included in existing "nulls")   

+   *     combine with a new additional block that is moved down from the top.

+   *   - make use of both beginning and end free space.

+   * 

+   * If there is already a "null" at the insert spot, use that space.

+   *   - if there are enough nulls, return 

+   *   

+   * Sets (as side effect) nullBlockStart and nullBlockEnd

+   *   The setting includes all of the nulls, both what might have been present at the 

+   *   insert spot and any added new ones.

+   *      nullBlockStart refs a null, 

+   *      nullBlockEnd refs a non-null (or null if things are being inserted at the end) position

+   *        - the insert position

+   * 

+   * @param positionToInsert position containing a value, to free up by moving the current free block

+   *                         so that the last free element is at that (adjusted up) position.          

+   * @param nbrNewSlots

+   * @return adjusted positionToInsert, the free spot is just to the left of this position

+   */

+  private int insertSpace(final int positionToInsert, final int origNbrNewSlots) {

+    if (TRACE) {

+      tr.setLength(0);

+      tr.append("Tracing OrderedFsSet_array\n");

+      tr.append(String.format("insertSpace called with positionToInsert: %,d nbrNewSlots: %,d%n", positionToInsert, origNbrNewSlots));

+    }

+         

+    // while the positionToInsert (a ref to non-null or 1 past end) 

+    //   is > 0 && the pos to the left is null,

+    //     reduce the nbrNewSlots

+    int i = positionToInsert;

+    int nullsBelowInsertMin = i;

+    int nbrNewSlotsNeeded = origNbrNewSlots;

+   

+    /***********************************

+     * count nulls already present     *

+     * reduce nbrNewSlotsNeeded        *

+     *   reset lastRemovedPos if using *

+     ***********************************/

+    while (i > 0 && a[i - 1] == null && nbrNewSlotsNeeded > 0) {

+      i--;

+      nbrNewSlotsNeeded--;

+      nullsBelowInsertMin = i;

+      if (i == lastRemovedPos) {

+        lastRemovedPos = -1;  // subsumed by this calc

+      }

+    }

+    

+    int r = positionToInsert;

+    

+    /***********************************

+     * Finish if nulls already found   *

+     * for all new slots               *

+     ***********************************/

+ 

+    if (nbrNewSlotsNeeded != 0) {

+      

+      /***********************************

+       * Compute closest space           *

+       ***********************************/

+      

+//      //debug

+//      itercount ++;

+    

+      int distanceFromLastRemoved = (lastRemovedPos == -1 || nbrNewSlotsNeeded != 1) 

+                                      ? Integer.MAX_VALUE // skip using this

+                                      : (positionToInsert - lastRemovedPos);

+      int distanceFromEnd = a_nextFreeslot - positionToInsert;

+      int distanceFromFront = (a_firstUsedslot < nbrNewSlotsNeeded)

+                                ? Integer.MAX_VALUE

+                                : positionToInsert - a_firstUsedslot;

+

+      boolean useFront =

+  //          // make sure size of front free space is not included in previous nulls already counted

+  //          a_firstUsedslot > positionToInsert && 

+          distanceFromFront < distanceFromEnd;

+      boolean useLastRemoved = (Math.abs(distanceFromLastRemoved) < (useFront 

+                                                                      ? distanceFromFront 

+                                                                      : distanceFromEnd));

+

+      if (!useLastRemoved && !useFront) {

+        // using back, but reevaluate if would need to expand

+        if (a.length < a_nextFreeslot + nbrNewSlotsNeeded) {

+          // if use back space, a will need to expand;

+          // use front space if available

+          useFront = nbrNewSlotsNeeded <= a_firstUsedslot;

+//          //debug

+//          System.out.format("debug insertSpace, maybe overriding use front, space needed = %4d, space avail = %d%n",

+//              nbrNewSlotsNeeded, a_firstUsedslot);

+        }

+      }

+      if (TRACE) 

+        tr.append(String.format("distances: %d %d %d, useFront: %s useLastRemoved: %s%n",

+            distanceFromLastRemoved, distanceFromEnd, distanceFromFront, useFront, useLastRemoved));

+

+//      // debug

+//      if (itercount % 128 == 0) {

+//        System.out.format("debug insertSpace: %4d distances: %10d %4d %10d, useFront: %5s useLastRemoved: %s%n",

+//            itercount, distanceFromLastRemoved, distanceFromEnd, distanceFromFront, useFront, useLastRemoved);

+//      }

+//      //debug

+//      if (itercount % 128 == 0 && itercount > 140000) {

+//        System.out.format("debug insertSpace: space in front: %,5d space at end: %d%n",

+//             a_firstUsedslot, a.length - a_nextFreeslot);

+//      }

+      

+      if (useLastRemoved) {  // due to find skipping over nulls, the distanceFromLastRemoved is never 0

+        nullBlockStart = lastRemovedPos;

+        nullBlockEnd = lastRemovedPos + 1;

+        

+        if (distanceFromLastRemoved > 0) {

+          assert distanceFromLastRemoved != 1; 

+          shiftFreespaceUp(nullsBelowInsertMin, nbrNewSlotsNeeded); // move one slot (since nullblockstart/end set above        

+        } else {

+          r = shiftFreespaceDown(positionToInsert, nbrNewSlotsNeeded);

+          if (TRACE) 

+            tr.append(String.format("shiftFreespaceDown result was %,d%n", r));

+        }

+        lastRemovedPos = -1;

+      } else if (useFront) {

+        nullBlockStart = a_firstUsedslot - nbrNewSlotsNeeded;

+        nullBlockEnd = a_firstUsedslot;

+  //        if (null != a[nullBlockStart]) {

+        if (a_firstUsedslot != positionToInsert) {

+          // need to move the free slot if not already next to the insert position

+          shiftFreespaceUp(positionToInsert, nbrNewSlotsNeeded);

+        }

+  //        a_firstUsedslot --;  // not done here, done in insert routine

+      } else {

+        // using space at end

+        ensureCapacity(nbrNewSlotsNeeded);

+        nullBlockStart = a_nextFreeslot;

+        nullBlockEnd = nullBlockStart + nbrNewSlotsNeeded; 

+        r = shiftFreespaceDown(positionToInsert, nbrNewSlotsNeeded);

+        a_nextFreeslot += nbrNewSlotsNeeded;  // due to shift just done in line above

+        if (TRACE) {

+          tr.append(String.format("shiftFreespaceDown2 result was %,d, nullBlockStart: %,d nullBlockEnd: %,d a_nextFreeslot: %,d%n", 

+              r, nullBlockStart, nullBlockEnd, a_nextFreeslot));

+        }

+        //reset null block to full size

+      }

+    } else {

+//      //debug

+//      System.out.format("debug insertSpace: using existing nulls, start: %,6d length: %,d%n", r - origNbrNewSlots, origNbrNewSlots);

+    }

+    nullBlockEnd = r;

+    nullBlockStart = r - origNbrNewSlots;

+//    // debug

+//    for (int ii = nullBlockStart; ii < nullBlockEnd; ii++) {

+//      assert a[ii] == null;

+//    }

+    return r;   

+  }

+  

+

+  /**

+   * Shift a block of free space lower in the array.

+   * This is done by shifting the space at the insert point

+   *   for length = start of free block - insert point 

+   *   to the right by the nbrNewSlots

+   *   and then resetting (filling) the freed up space with null

+   *   

+   * Example:  u = used, f = free space

+   * 

+   * before                      |--| 

+   * uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuffffffffuuuuuuu

+   *                             ^ insert point

+   * after                               |--|

+   * uuuuuuuuuuuuuuuuuuuuuuuuuuuuffffffffuuuuuuuuuuu

+   *                                     ^ insert point

+   *                                    

+   * before 

+   * |------------------------------|

+   * uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuffffffffuuuuuuu

+   * ^ insert point

+   * after   |------------------------------| 

+   * ffffffffuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

+   *         ^ insert point

+   * before 

+   *     |------------------------------|

+   * ffffuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuffffffffuuuuuuu

+   *     ^ insert point

+   * after       |------------------------------| 

+   * ffffffffffffuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

+   *             ^ insert point

+   *                                    

+   * move up by nbrNewSlots

+   * length to move = nullBlockStart - insert point

+   * new insert point is nbrOfFreeSlots higher (this points to a filled spot, prev spot is free)

+   * 

+   * fill goes from original newInsertPoint, for min(nbrNewSlots, length of move)

+   *   

+   * There may be nulls already at the insert point, or encountered along the way.

+   *   - nulls along the way are kept, unchanged

+   *   - nulls at the insert point are incorporated; the freespace added is combined (need to verify)

+   *   

+   * hidden param:  nullBlockStart

+   * side effect: lastRemovedPosition maybe updated

+   * @param insertPoint index of slot array, currently occupied, where an item is to be set into

+   * @param nbrNewSlots - the size of the inserted space

+   * @return the updated insert point, now moved up

+   */

+  private int shiftFreespaceDown(final int insertPoint, final int nbrNewSlots) {

+    assert insertPoint >= 0;

+    assert nbrNewSlots >= 0;

+    int lengthToMove = nullBlockStart - insertPoint;

+

+    try {

+      // adjust lastRemovedPos if in moving part

+      if (lastRemovedPos >= insertPoint && lastRemovedPos < (insertPoint + lengthToMove)) {

+        lastRemovedPos = lastRemovedPos + nbrNewSlots;

+      }

+      System.arraycopy(a, insertPoint, a, insertPoint + nbrNewSlots, lengthToMove);

+    } catch (ArrayIndexOutOfBoundsException e) {

+      System.err.println("Internal error: OrderedFsSet_sorted got array out of bounds in shiftFreeSpaceDown " + e.toString());

+      System.err.format("  array size: %,d insertPoint: %,d nbrNewSlots: %,d lengthToMove: %d%n",

+          a.length, insertPoint, nbrNewSlots, lengthToMove);  // 32, 0, 1, -1 implies: nullBlockStart = -1

+      throw e;

+    }

+    int lengthToClear = Math.min(nbrNewSlots, lengthToMove);

+    Arrays.fill(a, insertPoint, insertPoint + lengthToClear, null);

+    nullBlockStart = insertPoint;

+    nullBlockEnd = nullBlockStart + nbrNewSlots;

+    

+    // adjust nullBlockStart to account for nulls in front

+    int i = insertPoint - 1;

+    for (; i >= 0; i--) {

+      if (a[i] != null) {

+        break;

+      }

+    }

+    nullBlockStart = i + 1;

+    

+    if (MEASURE) {

+      moveSizeHistogram[32 - Integer.numberOfLeadingZeros(lengthToMove)] ++;

+      movePctHistogram[lengthToMove* 10 / (a_nextFreeslot - a_firstUsedslot)] ++;

+      fillHistogram[32 - Integer.numberOfLeadingZeros(lengthToClear)] ++;

+    }

+    if (insertPoint == a_firstUsedslot) {

+      a_firstUsedslot = insertPoint + nbrNewSlots;

+    }

+    return insertPoint + nbrNewSlots;

+  }

+  

+  /**

+   * Shift a block of free space higher in the array.

+   * This is done by shifting the space at the insert point

+   *   of length = insert point - (end+1) of free block 

+   *   to the left by the nbrNewSlots

+   *   and then resetting (filling) the freed up space with null

+   *   

+   * Example:  u = used, f = free space

+   * 

+   * before              |-|   << block shifted 

+   * uuuuuuuuuuuuuuufffffuuuuuuuuuuuuuuuuuuuuuuuuuuu

+   *                        ^ insert point

+   * after          |-|   << block shifted

+   * uuuuuuuuuuuuuuuuuufffffuuuuuuuuuuuuuuuuuuu

+   *                        ^ insert point

+   *                                    

+   * before                                  |----|

+   * uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuffffuuuuuuu

+   *                                               ^ insert point

+   *     note: insert point is never beyond last because

+   *     those are added immediately

+   * after                               |----|

+   * uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuffffu

+   *                                               ^ insert point

+   *                                    

+   * before       |--|   

+   * uuuuuuuuuuuufuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

+   *                  ^ insert point

+   * after       |--|

+   * uuuuuuuuuuuuuuuufuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

+   *                  ^ insert point

+   *                                    

+   *     |--------|  before 

+   * ffffuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

+   *               ^ insert point

+   * |--------|

+   * uuuuuuuuuuffffuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

+   *               ^ insert point

+   *                                    

+   *                                    

+   * move down by nbrNewSlots

+   * length to move = insert point - null block end (which is 1 plus index of last free)

+   * new insert point is the same as the old one (this points to a filled spot, prev spot is free)

+   * 

+   * fill goes from original null block end, for min(nbrNewSlots, length of move)

+   *   

+   * hidden param:  nullBlock Start, nullBlockEnd = 1 past end of last free slot

+   * @param newInsertPoint index of slot array, currently occupied, where an item is to be set into

+   * @param nbrNewSlots - the size of the inserted space

+   * @return the updated insert point, now moved up

+   */

+  

+  private int shiftFreespaceUp(int newInsertPoint, int nbrNewSlots) {

+    boolean need2setFirstUsedslot = nullBlockEnd == a_firstUsedslot;

+    int lengthToMove = newInsertPoint - nullBlockEnd;

+   

+    // adjust lastRemovedPos if in moving part

+    if (lastRemovedPos >= nullBlockEnd && lastRemovedPos < (nullBlockEnd + lengthToMove)) {

+      lastRemovedPos = lastRemovedPos - nbrNewSlots;

+    }

+    

+    System.arraycopy(a, nullBlockEnd, a, nullBlockStart, lengthToMove);

+    int lengthToClear = Math.min(nbrNewSlots, lengthToMove);

+    Arrays.fill(a, newInsertPoint - lengthToClear, newInsertPoint, null);

+    nullBlockStart = newInsertPoint - nbrNewSlots;

+    nullBlockEnd = newInsertPoint;

+    if (need2setFirstUsedslot) {

+      a_firstUsedslot = 0;

+    }

+    return newInsertPoint;

+  }

+    

+//  /**

+//   * @param from start of items to shift, inclusive

+//   * @param to end of items to shift, exclusive

+//   */

+//  private void shiftBy2(int from, int to) {

+//    if (to == -1) {

+//      to = theArray.size();

+//      theArray.add(null);

+//      theArray.add(null);

+//    }

+//      try {

+//        Object[] aa = (Object[]) getActualArray.invokeExact(theArray);

+//        System.arraycopy(aa, from, aa, from + 2, to - from);

+//      } catch (Throwable e) {

+//        throw new RuntimeException(e);

+//      }

+//  }

+

+  /**

+   * Never returns an index to a "null" (deleted) item.

+   * If all items are LT key, returns - size - 1 

+   * @param fs the key

+   * @return the lowest position whose item is equal to or greater than fs;

+   *         if not equal, the item's position is returned as -insertionPoint - 1. 

+   *         If the key is greater than all elements, return -size - 1). 

+   */

+  private int find(TOP fs) {

+    if (size == 0) {

+      return -1;

+    }

+    return binarySearch(fs);

+  }

+  

+  /**

+   * find, within constricted range: start: a_firstUsedslot, end = nullBlockStart

+   * @param fs -

+   * @return - the slot matching, or the one just above, if none match,

+   *           but limited to the nullBlockStart position.

+   *           If the answer is not found, and the insert position is

+   *           the nullBlockStart, then return the nullBlockEnd as the position

+   *           (using the not-found encoding).

+   */

+  private int findRemaining(TOP fs) {

+    int pos = binarySearch(fs, a_firstUsedslot, nullBlockStart, a, nullBlockStart, nullBlockEnd, comparatorWithID);

+    return pos < 0 && ((-pos) - 1 == nullBlockStart) 

+            ? ( -(nullBlockEnd) - 1) 

+            : pos;

+  }

+    

+  /**

+   * Special version of binary search that ignores null values

+   * @param fs the value to look for

+   * @return the position whose non-null value is equal to fs, or is gt fs (in which case, return (-pos) - 1)

+   */

+  private int binarySearch(final TOP fs) {

+    return binarySearch(fs, a_firstUsedslot, a_nextFreeslot, a, nullBlockStart, nullBlockEnd, comparatorWithID);

+  }

+  

+  /**

+   * At the start, the start and end positions are guaranteed to refer to non-null entries

+   * But during operation, lower may refer to "null" entries (upper always non-null)

+   * 

+   * @param fs - the fs to search for

+   * @param start the index representing the lower bound (inclusive) to search for

+   * @param end the index representing the upper bound (exclusive) to search for

+   * @param _a the array

+   * @param _nullBlockStart inclusive

+   * @param _nullBlockEnd exclusive

+   * @param _comparatorWithID -

+   * @return - the index of the found item, or if not found, the (-index) -1 of the 

+   *           poosition one more than where the item would go

+   */

+  public static int binarySearch(final TOP fs, int start, int end,

+      TOP[] _a, 

+      int _nullBlockStart,

+      int _nullBlockEnd,

+      Comparator<TOP> _comparatorWithID) {

+

+    if (start < 0 || end - start <= 0) {

+      return (start < 0) ? -1 : ( (-start) - 1);  // means not found, insert at position start

+    }

+    int lower = start, upper = end;

+    for (;;) {

+    

+      int mid = (lower + upper) >>> 1;  // overflow aware

+      TOP item = _a[mid];

+      int delta = 0;

+      int midup = mid;

+      int middwn = mid;

+      int pos = mid;

+    

+      while (null == item) {  // skip over nulls

+        

+        /**

+         * lower (inclusive) may point to null,

+         * upper (exclusive) guaranteed to not point to a null

+         * 

+         * the mid position is point to a null; 

+         *   We split the mid into two items: midup and middown.

+         *     - both may point to a non-null item eventually

+         *     - the one that gets to a non-null first is used, unless:

+         *       -- it is == to the upper, in which case we attempt to find the

+         *          middown non-null.

+         *       -- it is below the lower (only happens if the lower is ref-ing a null), in which case

+         *          we attempt to find the midup non-null

+         *       -- if both the midup == upper and middown < lower, then 

+         *            not found, return (-upper) -1;

+         *            

+         *   This may be inside a null block - in which case

+         *     shortcut: speed the midup and middown to the edges (1st non-null positions)

+         */

+        

+        

+        if (_nullBlockStart != -1 && 

+            middwn >= _nullBlockStart && 

+            midup  < _nullBlockEnd) {

+          // in the null block

+          // move to edges

+          midup  = _nullBlockEnd;   // midup exclusive, nullBlockEnd exclusive

+          middwn = _nullBlockStart - 1; // middwn and nullBlockStart inclusive

+        } else {

+          delta ++;

+        }

+        

+        // belowUpper == true means there's an item available to compare, at the midup + delta point, which is < upper.

+        //       is < because upper is exclusive

+        boolean belowUpper = (pos = midup + delta) < upper;

+        if (belowUpper && null != (item = _a[pos])) {

+          break;  // have a non-null candidate, below the upper, to compare

+        }

+        // belowLower == true means we've gone past the last place to compare with, below.

+        // if belowLower == false, then there's an item available to compare, at the middwn - delta point, which is >= lower

+        boolean belowLower = (pos = middwn - delta) < lower; 

+        if (!belowLower && null != (item = _a[pos])) { 

+          break;  // have a non-null candidate, = or above the lower, to compare

+        }

+        

+        if (! belowUpper && belowLower) {

+          return (-upper) - 1; // return previous

+        }

+      }

+     

+      int c = _comparatorWithID .compare(fs, item);

+      if (c == 0) {

+        return pos;

+      }

+      

+      if (c < 0) {  // fs is smaller than item at pos in array; search downwards

+        upper = pos;  // upper is exclusive

+        if (upper == lower) {

+          return (-upper) - 1;

+        }

+      } else {  // fs is larger than item at pos in array; search upwards

+        lower = pos + 1;             // lower is inclusive

+        if (lower == upper) {

+          return (-upper) - 1;

+        }

+      }

+    }

+  }

+  

+  /**

+   * @see Set#remove(Object)

+   */

+  @Override

+  public boolean remove(Object o) {

+    if (o == null) {

+      throw new IllegalArgumentException("Null cannot be the argument to remove");

+    }

+    processBatch();

+    TOP fs = (TOP) o;

+    

+    int pos = find(fs);

+    if (pos < 0) {

+      return false;

+    }

+    

+    // at this point, pos points to a spot that compares "equal" using the comparator

+    // for sets, this is the single item that is in the index

+    // for sorted, because find uses the compareWithID comparator, this is the unique equal element

+    assert a[pos] != null;

+    a[pos] = null;

+    size --;

+    modificationCount ++;

+    if (size == 0) {

+      clearResets();  // also clears last removed pos

+    } else {

+      // size is > 0

+      if (pos == a_firstUsedslot) {

+        do {  // removed the first used slot

+          a_firstUsedslot ++;

+        } while (a[a_firstUsedslot] == null);

+      } else if (pos == a_nextFreeslot - 1) {

+        do {

+          a_nextFreeslot --;

+        } while (a[a_nextFreeslot - 1] == null);

+        highest = a[a_nextFreeslot - 1];

+      } 

+      

+      if (size < ((a_nextFreeslot - a_firstUsedslot) >> 1) &&

+          size > 8) {

+        compressOutRemoves();  // also clears lastRemovedPos

+      } else {

+        // update lastRemovedPos

+        lastRemovedPos = (pos > a_firstUsedslot && pos < (a_nextFreeslot - 1))

+                           ? pos  // is a valid position 

+                           : -1;  // is not a valid position

+      }

+      

+      // non-empty case: capacity shrinking: do when

+      //   capacity > 64  (skip for 64 or less)

+      //   space from a_nextFreeSlot to (capacity >> 2) + a_firstUsedslot > 32  

+      //   time since last add > 5 seconds  not done - test might be too expensive

+      

+      //compute space + buffer (another power of 2) to save from both front and back.  Back part might be negative

+      int spaceToSave = a_firstUsedslot + (a.length >> 2) - a_nextFreeslot;

+      if (spaceToSave > 32 

+//          && System.currentTimeMillis() - lastAddTime > 5000 // avoid as test might be more expensive than copy

+          ) {

+        

+        // compute actual space available at each end to save, without extra buffer

+        // space to save at beginning is just a_firstUsedslot

+        // space in front is 0 or positive, space at end may be negative.

+        int spaceAtEnd = (a.length >> 1) - a_nextFreeslot;

+        

+        // divide space between front and back, 1/2 and 1/2

+        

+        int totalSpaceToSave = spaceAtEnd + a_firstUsedslot;

+

+        int spaceToHaveAtFront = totalSpaceToSave >> 1;

+        

+        int spaceToReclaimAtFront = Math.max(0,  a_firstUsedslot - spaceToHaveAtFront);

+        

+//        System.out.format("debug shrinking, a_firstUsedslot: %d, spaceToReclaimAtFront: %d,"

+//            + " spaceAtEnd: %d%n", a_firstUsedslot, spaceToReclaimAtFront, spaceAtEnd);

+        

+        a = Arrays.copyOfRange(a, spaceToReclaimAtFront, spaceToReclaimAtFront + (a.length >> 1));

+

+        a_firstUsedslot -= spaceToReclaimAtFront;

+        a_nextFreeslot -= spaceToReclaimAtFront;

+        if (lastRemovedPos != -1) {

+          assert lastRemovedPos > spaceToReclaimAtFront;

+          lastRemovedPos -= spaceToReclaimAtFront;

+        }

+        

+//        System.out.println("debug space in front: " + a_firstUsedslot);

+        

+      }

+

+    }

+    return true;

+  }

+  

+  /**

+   * When the main array between the first used slot and the next free slot has too many nulls 

+   * representing removed items, scan and gc them.

+   *   assumes: first used slot is not null, nextFreeslot - 1 is not null

+   */

+  private void compressOutRemoves() {

+    int j = a_firstUsedslot + 1; // outside of for loop because need value of j after loop ends

+    for (int i = a_firstUsedslot + 1; i < a_nextFreeslot; i++, j++) {

+      while (a[i] == null) {

+        i ++;

+      }

+      if (i > j) {

+        a[j] = a[i];

+      }

+    }

+    

+    Arrays.fill(a, j, a_nextFreeslot, null); // j is one past last filled slot

+    a_nextFreeslot = j;

+    lastRemovedPos = -1;

+  }

+  

+  /**

+   * @see Set#containsAll(Collection)

+   */

+  @Override

+  public boolean containsAll(Collection<?> c) {

+    throw new UnsupportedOperationException();

+  }

+

+  /**

+   * @see Set#addAll(Collection)

+   */

+  @Override

+  public boolean addAll(Collection<? extends TOP> c) {

+    boolean changed = false;

+    for (TOP item : c) {

+      changed |= add(item);

+    }

+    return changed;

+  }

+  

+  /**

+   * @see Set#retainAll(Collection)

+   */

+  @Override

+  public boolean retainAll(Collection<?> c) {

+    throw new UnsupportedOperationException();

+  }

+

+  /**

+   * @see Set#removeAll(Collection)

+   */

+  @Override

+  public boolean removeAll(Collection<?> c) {

+    throw new UnsupportedOperationException();

+  }

+  

+  /**

+   * @see Set#clear()

+   */

+  @Override

+  public void clear() {

+    if (isEmpty()) {

+      return;

+    }

+    if (!shrinkCapacity()) {

+//      //debug 

+//      if (a_firstUsedslot == -1) {

+//        System.out.println("a_firstUsedslot was -1");

+//      }

+//      if (a_nextFreeslot == -1) {

+//        System.out.println("a_nextFreeslot was -1");

+//      }

+      Arrays.fill(a, a_firstUsedslot, a_nextFreeslot, null);      

+    }

+    clearResets();

+  }

+  

+  private void clearResets() {

+    a_firstUsedslot = 0;

+    a_nextFreeslot = 0;

+    batch.clear();

+    size = 0;

+    maxSize = 0;

+    nullBlockStart = -1;

+    nullBlockEnd = -1;

+    doingBatchAdds = false; // just for safety, not logically needed I think.

+    highest = null;    

+    modificationCount ++;

+    lastRemovedPos = -1;

+  }

+

+  /**

+   * @see NavigableSet#lower(Object)

+   */

+  @Override

+  public TOP lower(TOP fs) {

+    int pos = lowerPos(fs);

+    return (pos < 0) ? null : a[pos];

+  }

+  

+  /**

+   * @param fs element to test

+   * @return pos of greatest element less that fs or -1 if no such

+   */

+  public int lowerPos(TOP fs) {

+    processBatch();

+    int pos = find(fs); // position of lowest item GE fs  

+    pos = (pos < 0) ? ((-pos) - 2) : (pos - 1);

+    // above line subtracts 1 from LE pos; pos is now lt, may be -1

+    while (pos >= a_firstUsedslot) {

+      if (a[pos] != null) {

+        return pos;

+      }

+      pos --;

+    }

+    return -1; 

+  }

+

+

+  /**

+   * @see NavigableSet#floor(Object)

+   */

+  @Override

+  public TOP floor(TOP fs) {

+    int pos = floorPos(fs);

+    return (pos < 0) ? null : a[pos];

+  }

+  

+  /**

+   * @param fs -

+   * @return -

+   */

+  public int floorPos(TOP fs) {

+    processBatch();

+    int pos = find(fs);  // position of lowest item GE fs

+    if (pos < 0){

+      pos = (-pos) - 2;

+    }

+    // pos is = or lt, may be -1

+    while (pos >= a_firstUsedslot) {

+      if (a[pos] != null) {

+        return pos;

+      }

+      pos --;

+    }

+    return -1;

+  }

+

+  /**

+   * @see NavigableSet#ceiling(Object)

+   */

+  @Override

+  public TOP ceiling(TOP fs) {

+    int pos = ceilingPos(fs);

+    return (pos < a_nextFreeslot) ? a[pos] : null;

+  }

+  

+

+  /**

+   * @param fs -

+   * @return -

+   */

+  public int ceilingPos(TOP fs) {

+    processBatch();

+    int pos = find(fs); // position of lowest item GE fs

+    if (pos < 0){

+      pos = (-pos) -1;

+    } else {

+      return pos;

+    }

+    

+    while (pos < a_nextFreeslot) {

+      if (a[pos] != null) {

+        return pos;

+      }

+      pos ++;

+    }

+    return pos;

+  }

+

+  /**

+   * @see NavigableSet#higher(Object)

+   */

+  @Override

+  public TOP higher(TOP fs) {

+    int pos = higherPos(fs);

+    return (pos < a_nextFreeslot) ? a[pos] : null;

+  }

+

+  /**

+   * @param fs the Feature Structure to use for positioning

+   * @return the position that's higher

+   */

+  public int higherPos(TOP fs) {

+    processBatch();

+    int pos = find(fs); // position of lowest item GE fs

+    pos = (pos < 0) ? ((-pos) -1) : (pos + 1);

+    

+    while (pos < a_nextFreeslot) {

+      if (a[pos] != null) {

+        return pos;

+      }

+      pos ++;

+    }

+    return pos;

+  }

+

+  /**

+   * @see NavigableSet#pollFirst()

+   */

+  @Override

+  public TOP pollFirst() {

+    throw new UnsupportedOperationException();

+  }

+

+  /**

+   * @see NavigableSet#pollLast()

+   */

+  @Override

+  public TOP pollLast() {

+    throw new UnsupportedOperationException();

+  }

+

+  /**

+   * @see Iterable#iterator()

+   */

+  @Override

+  public Iterator<TOP> iterator() {

+    processBatch();

+    if (a_nextFreeslot == 0) {

+      return Collections.emptyIterator();

+    }

+    return new Iterator<TOP>() {

+      private int pos = a_firstUsedslot;

+      { incrToSkipOverNulls(); 

+        if (MEASURE) {

+          int s = a_nextFreeslot - a_firstUsedslot;

+          iterPctEmptySkip[(s - size()) * 10 / s] ++;

+        }

+      }

+       

+      @Override

+      public boolean hasNext() {

+        processBatch();

+        return pos < a_nextFreeslot;

+      }

+      

+      @Override

+      public TOP next() {

+        if (!hasNext()) {

+          throw new NoSuchElementException();

+        }

+

+        TOP r = a[pos++];

+        incrToSkipOverNulls();

+        return r;        

+      }

+      

+      private void incrToSkipOverNulls() {

+        while (pos < a_nextFreeslot) {

+          if (a[pos] != null) {

+            break;

+          }

+          pos ++;

+        }

+      }

+    };

+  }

+

+//  /**

+//   * Directly implement FSIterator

+//   *   for GC efficiency

+//   * @return low level iterator

+//   */

+//  public <T extends FeatureStructure> LowLevelIterator<T> ll_Iterator(LowLevelIndex ll_index, CopyOnWriteIndexPart cow_wrapper) {

+//    processBatch();

+//    return new LL_Iterator<T>(ll_index, cow_wrapper);

+//  }

+

+  /**

+   * @see NavigableSet#descendingSet()

+   */

+  @Override

+  public NavigableSet<TOP> descendingSet() {

+    throw new UnsupportedOperationException();

+  }

+

+  /**

+   * @see NavigableSet#descendingIterator()

+   */

+  @Override

+  public Iterator<TOP> descendingIterator() {

+    processBatch();

+    return new Iterator<TOP>() {

+      private int pos = a_nextFreeslot - 1;    // 2 slots:  next free = 2, first slot = 0

+                                               // 1 slot:   next free = 1, first slot = 0

+                                               // 0 slots:  next free = 0; first slot = 0 (not -1)

+      { if (pos >= 0) {  // pos is -1 if set is empty

+        decrToNext(); 

+        }

+      }

+       

+      @Override

+      public boolean hasNext() {

+        return pos >= a_firstUsedslot;

+      }

+      

+      @Override

+      public TOP next() {

+        if (!hasNext()) {

+          throw new NoSuchElementException();

+        }

+

+        TOP r = a[pos--];

+        decrToNext();

+        return r;        

+      }

+      

+      private void decrToNext() {

+        while (pos >= a_firstUsedslot) {

+          if (a[pos] != null) {

+            break;

+          }

+          pos --;

+        }

+      }

+    };

+  }

+

+  /**

+   * @see NavigableSet#subSet(Object, boolean, Object, boolean)

+   */

+  @Override

+  public NavigableSet<TOP> subSet(TOP fromElement, boolean fromInclusive, TOP toElement, boolean toInclusive) {

+    return new SubSet(() -> this, fromElement, fromInclusive, toElement, toInclusive, false, null);

+  }

+

+  /**

+   * @see NavigableSet#headSet(Object, boolean)

+   */

+  @Override

+  public NavigableSet<TOP> headSet(TOP toElement, boolean inclusive) {

+    if (isEmpty()) {

+      return this; 

+    }

+    return subSet(first(), true, toElement, inclusive);     

+  }

+

+  /**

+   * @see NavigableSet#tailSet(Object, boolean)

+   */  

+  @Override

+  public NavigableSet<TOP> tailSet(TOP fromElement, boolean inclusive) {

+    if (isEmpty()) {

+      return this;

+    }

+    return subSet(fromElement, inclusive, last(), true);

+  }

+

+  /**

+   * @see NavigableSet#subSet(Object, Object)

+   */

+  @Override

+  public SortedSet<TOP> subSet(TOP fromElement, TOP toElement) {

+    return subSet(fromElement, true, toElement, false);

+  }

+

+  /**

+   * @see NavigableSet#headSet(Object)

+   */

+  @Override

+  public SortedSet<TOP> headSet(TOP toElement) {

+    return headSet(toElement, false);

+  }

+

+  /**

+   * @see NavigableSet#tailSet(Object)

+   */

+  @Override

+  public SortedSet<TOP> tailSet(TOP fromElement) {

+    return tailSet(fromElement, true);

+  }

+  

+  

+  /**

+   * This is used in a particular manner:

+   *   only used to create iterators over that subset

+   *     -- no insert/delete

+   */

+  public static class SubSet implements NavigableSet<TOP> {

+    final Supplier<OrderedFsSet_array2> theSet;

+    final private TOP fromElement;

+    final private TOP toElement;

+    final private boolean fromInclusive;

+    final private boolean toInclusive;

+    

+    final private int firstPosInRange;

+    final private int lastPosInRange;  // inclusive

+    

+    final private TOP firstElementInRange;

+    final private TOP lastElementInRange;

+        

+    private int sizeSubSet = -1; // lazy - computed on first ref

+

+    private OrderedFsSet_array2 theSet() {

+      return theSet.get();

+    }

+    

+    SubSet(Supplier<OrderedFsSet_array2> theSet, TOP fromElement, boolean fromInclusive, TOP toElement, boolean toInclusive) {

+      this(theSet, fromElement, fromInclusive, toElement, toInclusive, true, theSet.get().comparatorWithID);

+    }

+    

+    SubSet(Supplier<OrderedFsSet_array2> theSet, TOP fromElement, boolean fromInclusive, TOP toElement, boolean toInclusive, boolean doTest, Comparator<TOP> comparator) {

+      this.theSet = theSet;

+      this.fromElement = fromElement;

+      this.toElement = toElement;

+      this.fromInclusive = fromInclusive;

+      this.toInclusive = toInclusive;

+      if (doTest && comparator.compare(fromElement, toElement) > 0) {

+        throw new IllegalArgumentException();

+      }

+      OrderedFsSet_array2 s = theSet();

+      theSet().processBatch();    

+      firstPosInRange = fromInclusive ? s.ceilingPos(fromElement) : s.higherPos(fromElement);

+      lastPosInRange  = toInclusive ? s.floorPos(toElement) : s.lowerPos(toElement);

+      // lastPosInRange can be LT firstPosition if fromInclusive is false

+      //   In this case, the subset is empty

+      if (lastPosInRange < firstPosInRange) {

+        firstElementInRange = null;

+        lastElementInRange = null;

+      } else {

+        firstElementInRange = s.a[firstPosInRange];

+        lastElementInRange = s.a[lastPosInRange];

+      }

+    }

+    

+    @Override

+    public Comparator<? super TOP> comparator() {

+      return theSet().comparatorWithID;

+    }

+

+    @Override

+    public TOP first() {

+      return firstElementInRange;

+    }

+

+    @Override

+    public TOP last() {

+      return lastElementInRange;

+    }

+

+    @Override

+    public int size() {

+      if (firstElementInRange == null) {

+        return 0;

+      }

+      if (sizeSubSet == -1) {

+        Iterator<TOP> it = iterator();

+        int i = 0;

+        while (it.hasNext()) {

+          it.next();

+          i++;

+        }

+        sizeSubSet = i;

+      }

+      return sizeSubSet;

+    }

+

+    @Override

+    public boolean isEmpty() {

+      return size() == 0;

+    }

+

+    @Override

+    public boolean contains(Object o) {

+      TOP fs = (TOP) o;

+      if (!isInRange(fs)) {

+        return false;

+      }

+      return theSet().contains(o);

+    }

+

+    @Override

+    public Object[] toArray() {

+      throw new UnsupportedOperationException();

+    }

+

+    @Override

+    public <T> T[] toArray(T[] a1) {

+      throw new UnsupportedOperationException();

+    }

+

+    @Override

+    public boolean add(TOP e) {

+      throw new UnsupportedOperationException();

+    }

+

+    @Override

+    public boolean remove(Object o) {

+      throw new UnsupportedOperationException();

+    }

+

+    @Override

+    public boolean containsAll(Collection<?> c) {

+      throw new UnsupportedOperationException();

+    }

+

+    @Override

+    public boolean addAll(Collection<? extends TOP> c) {

+      throw new UnsupportedOperationException();

+    }

+

+    @Override

+    public boolean retainAll(Collection<?> c) {

+      throw new UnsupportedOperationException();

+    }

+

+    @Override

+    public boolean removeAll(Collection<?> c) {

+      throw new UnsupportedOperationException();

+    }

+

+    @Override

+    public void clear() {

+      throw new UnsupportedOperationException();

+    }

+

+    @Override

+    public TOP lower(TOP fs) {

+      if (lastElementInRange == null || isLeFirst(fs)) {

+        return null;

+      }

+      // if the key is > lastElement, 

+      //   return last element

+      if (isGtLast(fs)) {

+        return lastElementInRange;

+      }

+      // in range

+      return theSet().lower(fs);

+    }

+

+    @Override

+    public TOP floor(TOP fs) {

+      

+      // if the key is < the first element in the range, return null

+      if (lastElementInRange == null || isLtFirst(fs)) {

+        return null;

+      }

+      

+      // if the key is >= lastElement, 

+      //   return last element

+      if (isGeLast(fs)) {

+        return lastElementInRange;

+      }

+      

+      return theSet().floor(fs);

+    }

+

+    @Override

+    public TOP ceiling(TOP fs) {

+      // if the key is > the last element in the range, return null

+      if (firstElementInRange == null || isGtLast(fs)) {

+        return null;

+      }

+      

+      if (isLeFirst(fs)) {

+        return firstElementInRange;

+      }

+      

+      return theSet().ceiling(fs);

+    }

+

+    @Override

+    public TOP higher(TOP fs) {

+      if (firstElementInRange == null || isGeLast(fs)) {

+        return null;

+      }

+      

+      if (isLtFirst(fs)) {

+        return firstElementInRange;

+      }

+      

+      return theSet().higher(fs);

+    }

+

+    @Override

+    public TOP pollFirst() {

+      throw new UnsupportedOperationException();

+    }

+

+    @Override

+    public TOP pollLast() {

+      throw new UnsupportedOperationException();

+    }

+

+    @Override

+    public Iterator<TOP> iterator() {

+      if (firstElementInRange == null) {

+        return Collections.emptyIterator();

+      }

+      return new Iterator<TOP>() {

+        private int pos = firstPosInRange;

+         

+        @Override

+        public boolean hasNext() {

+          return pos <= lastPosInRange;  // lastPos is inclusive

+        }

+        

+        @Override

+        public TOP next() {

+          if (!hasNext()) {

+            throw new NoSuchElementException();

+          }

+

+          TOP r = theSet().a[pos++];

+          incrToSkipOverNulls();

+          return r;        

+        }

+        

+        private void incrToSkipOverNulls() {

+          while (pos <= lastPosInRange) {

+            if (theSet().a[pos] != null) {

+              break;

+            }

+            pos ++;

+          }

+        }

+      };

+    }

+

+    @Override

+    public NavigableSet<TOP> descendingSet() {

+      throw new UnsupportedOperationException();

+    }

+

+    @Override

+    public Iterator<TOP> descendingIterator() {

+      if (firstElementInRange == null) {

+        return Collections.emptyIterator();

+      }

+      return new Iterator<TOP>() {

+        private int pos = lastPosInRange;

+         

+        @Override

+        public boolean hasNext() {

+          return pos >= firstPosInRange;  

+        }

+        

+        @Override

+        public TOP next() {

+          if (!hasNext()) {

+            throw new NoSuchElementException();

+          }

+

+          TOP r = theSet().a[pos--];

+          decrToNext();

+          return r;        

+        }

+        

+        private void decrToNext() {

+          while (pos >= firstPosInRange) {

+            if (theSet().a[pos] != null) {

+              break;

+            }

+            pos --;

+          }

+        }

+      };

+    }

+

+    @Override

+    public NavigableSet<TOP> subSet(TOP fromElement1, boolean fromInclusive1, TOP toElement1,

+        boolean toInclusive1) {

+      if (!isInRange(fromElement1) || !isInRange(toElement1)) {

+        throw new IllegalArgumentException();

+      }

+      return theSet().subSet(fromElement1, fromInclusive1, toElement1, toInclusive1);  

+    }

+

+    @Override

+    public NavigableSet<TOP> headSet(TOP toElement1, boolean inclusive) {

+      return subSet(fromElement, fromInclusive, toElement1, inclusive);

+    }

+

+    @Override

+    public NavigableSet<TOP> tailSet(TOP fromElement1, boolean inclusive) {

+      return subSet(fromElement1, inclusive, toElement, toInclusive);

+    }

+

+    @Override

+    public SortedSet<TOP> subSet(TOP fromElement1, TOP toElement1) {

+      return subSet(fromElement1, true, toElement1, false);

+    }

+

+    @Override

+    public SortedSet<TOP> headSet(TOP toElement1) {

+      return headSet(toElement1, true);

+    }

+

+    @Override

+    public SortedSet<TOP> tailSet(TOP fromElement1) {

+      return tailSet(fromElement1, false);

+    }

+  

+    private boolean isGtLast(TOP fs) {

+      return theSet().comparatorWithID.compare(fs, lastElementInRange) > 0;      

+    }

+    

+    private boolean isGeLast(TOP fs) {

+      return theSet().comparatorWithID.compare(fs,  lastElementInRange) >= 0;

+    }

+

+    private boolean isLtFirst(TOP fs) {

+      return theSet().comparatorWithID.compare(fs, firstElementInRange) < 0;

+    }

+

+    private boolean isLeFirst(TOP fs) {

+      return theSet().comparatorWithID.compare(fs, firstElementInRange) <= 0;

+    }

+    

+    private boolean isInRange(TOP fs) {

+      return isInRangeLower(fs) && isInRangeHigher(fs);

+    }

+      

+    private boolean isInRangeLower(TOP fs) {

+      if (firstElementInRange == null) {

+        return false;

+      }

+      int r = theSet().comparatorWithID.compare(fs, firstElementInRange);

+      return fromInclusive ? (r >= 0) : (r > 0);

+    }

+    

+    private boolean isInRangeHigher(TOP fs) {

+      if (lastElementInRange == null) {

+        return false;

+      }

+      int r = theSet().comparatorWithID.compare(fs, lastElementInRange);

+      return toInclusive ? (r <= 0) : (r < 0);

+    }

+  }

+

+  public int getModificationCount() {

+    return modificationCount;

+  }

+  

+  @Override

+  public String toString() {

+//    processBatch();

+    StringBuilder b = new StringBuilder();

+    b.append("OrderedFsSet_array [a=");

+    if (a != null) {

+      boolean firstTime = true;

+      for (TOP i : a) {

+        if (firstTime) {

+          firstTime = false;

+        } else {

+          b.append(",\n");

+        }

+        if (i != null) {

+          b.append(i.toShortString());

+        } else {

+          b.append("null");

+        }

+  //      prettyPrint(0, 2, b, true); 

+      }

+    } else {

+      b.append("null");

+    }

+    b   .append(", a_nextFreeslot=").append(a_nextFreeslot)

+        .append(", a_firstUsedslot=").append(a_firstUsedslot)

+        .append(", batch=").append(batch)

+        .append(", origComparator=").append(comparatorWithID)

+        .append(", size=").append(size)

+        .append(", maxSize=").append(maxSize)

+        .append(", highest=").append(highest)

+        .append(", nullBlockStart=").append(nullBlockStart)

+        .append(", nullBlockEnd=").append(nullBlockEnd).append("]");

+    return b.toString();

+  } 

+ 

+  // these are approximate - don't take into account multi-thread access

+  static private int addToEndCount = 0;

+  static private int addNotToEndCount = 0;

+  static private int batchCountHistogram[];

+  static private int batchAddCount = 0; 

+  static private int batchAddTotal = 0; // includes things not added because of dups

+  static private int moveSizeHistogram[];

+  static private int movePctHistogram[];

+  static private int fillHistogram[];

+  static private int iterPctEmptySkip[];

+  

+  static {

+    if (MEASURE) {

+      batchCountHistogram = new int[24];  // slot x = 2^x to (2^(x+1) - 1) counts

+                                          // slot 0 = 1, slot 1 = 2-3, etc

+      Arrays.fill(batchCountHistogram,  0);

+      

+      moveSizeHistogram = new int[24];

+      movePctHistogram = new int[10];  // slot 0 = 0-9%  1 = 10-19% 9 = 90 - 100%

+      fillHistogram = new int[24];

+      

+      iterPctEmptySkip = new int[10];

+          

+      Runtime.getRuntime().addShutdownHook(new Thread(null, () -> {

+        System.out.println("Histogram measures of Ordered Set add / remove operations");

+        System.out.format(" - Add to end: %,d,  batch add count: %,d  batch add tot: %,d%n", 

+            addToEndCount, batchAddCount, batchAddTotal);

+        for (int i = 0; i < batchCountHistogram.length; i++) {

+          int v = batchCountHistogram[i];

+          if (v == 0) continue;

+          System.out.format(" batch size: %,d, count: %,d%n", 1 << i, v);

+        }

+        for (int i = 0; i < moveSizeHistogram.length; i++) {

+          int v = moveSizeHistogram[i];

+          if (v == 0) continue;

+          System.out.format(" move size: %,d, count: %,d%n", 

+              (i == 0) ? 0 : 1 << (i - 1), v);

+        }

+        for (int i = 0; i < movePctHistogram.length; i++) {

+          int v = movePctHistogram[i];

+          if (v == 0) continue;

+          System.out.format(" move Pct: %,d - %,d, count: %,d%n", i*10, (i+1)*10, v);

+        }

+        for (int i = 0; i < fillHistogram.length; i++) {

+          int v = fillHistogram[i];

+          if (v == 0) continue;

+          System.out.format(" fill size: %,d, count: %,d%n", 

+              (i == 0) ? 0 : 1 << (i - 1), v);

+        }

+        for (int i = 0; i < iterPctEmptySkip.length; i++) {

+          int v = iterPctEmptySkip[i];

+          if (v == 0) continue;

+          System.out.format(" iterator percent empty needing skip: %,d - %,d, count: %,d%n", i*10, (i+1)*10, v);

+        }

+

+

+      }, "dump measures OrderedFsSetSorted"));

+    }

+

+  }

+  

+}

diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/Pair.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/Pair.java
index 65c71c2..d83e110 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/Pair.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/Pair.java
@@ -67,5 +67,13 @@
     }

     return true;

   }

+

+  /* (non-Javadoc)

+   * @see java.lang.Object#toString()

+   */

+  @Override

+  public String toString() {

+    return "Pair [t=" + t + ", u=" + u + "]";

+  }

   

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/PositiveIntSet.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/PositiveIntSet.java
index 2b23f1d..6fb42f7 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/PositiveIntSet.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/PositiveIntSet.java
@@ -26,6 +26,8 @@
  */

 public interface PositiveIntSet {

 

+  static final boolean IS_TRACE_MODE_SWITCH = false;  // for debugging

+

   /**

    * remove all members of the set

    */

@@ -125,7 +127,7 @@
   default void forAllInts(IntConsumer v) {

     IntListIterator it = iterator();

     while (it.hasNext()) {

-      v.accept(it.next());

+      v.accept(it.nextNvc());

     }

   }

 }
\ No newline at end of file
diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/PositiveIntSet_impl.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/PositiveIntSet_impl.java
index ab5469f..0a062f1 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/PositiveIntSet_impl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/PositiveIntSet_impl.java
@@ -175,7 +175,7 @@
     IntListIterator it = intSet.iterator();

     int i = 0;

     while (it.hasNext()) {

-      allValues[i++] = it.next();

+      allValues[i++] = it.nextNvc();

     }

     Arrays.sort(allValues);

     return new IntListIteratorOverArray(allValues);

@@ -194,26 +194,20 @@
     public boolean hasNext() {

       return pos >= 0 && pos < a.length;

     }

-

+    

     @Override

-    public int next() throws NoSuchElementException {

-      if (hasNext()) {

-        return a[pos++];

-      }

-      throw new NoSuchElementException();

+    public int nextNvc() {

+      return a[pos++];

     }

 

     @Override

     public boolean hasPrevious() {

-      return pos >= 0 && pos < a.length;      

+      return pos > 0 && pos < a.length;      

     }

-

+    

     @Override

-    public int previous() {

-      if (hasPrevious()) {

-        return a[pos--];

-      }

-      throw new NoSuchElementException();

+    public int previousNvc() {

+      return a[--pos];    // decrement first!

     }

 

     @Override

@@ -321,7 +315,7 @@
       IntListIterator it = intSet.iterator();

       allocateIntBitSet(largestInt, key, 0);

       while (it.hasNext()) {

-        intSet.add(it.next());

+        intSet.add(it.nextNvc());

       }

     }

   }

@@ -342,7 +336,7 @@
     IntListIterator it = getUnorderedIterator();

     int i = 0;

     while (it.hasNext()) {

-      a[i++] = it.next();

+      a[i++] = it.nextNvc();

     }

     return a;

   }

@@ -413,7 +407,7 @@
     } else {

       isShort = (estMax - estMin) < HASH_SET_SHORT_MAX_SIZE;

     }

-    int numberOfTableElements =  IntHashSet.tableSpace(numberOfElements, IntHashSet.DEFAULT_LOAD_FACTOR);

+    int numberOfTableElements =  IntHashSet.tableSpace(numberOfElements);       

     return (numberOfTableElements >> ((isShort) ? 1 : 0)) 

         + IntHashSet.getSpaceOverheadInWords();

   }

@@ -645,7 +639,7 @@
     isBitSet = isHashSet = false;

     

     while (it.hasNext()) {

-      intSet.add(it.next());

+      intSet.add(it.nextNvc());

     }

     return;

   }

@@ -665,7 +659,7 @@
     isHashSet = true;

     

     while (it.hasNext()) {

-      intSet.add(it.next());

+      intSet.add(it.nextNvc());

     }

   }

   

@@ -675,7 +669,7 @@
     allocateIntBitSet(estMax, estMin, offset);

     

     while (it.hasNext()) {

-      intSet.add(it.next());

+      intSet.add(it.nextNvc());

     }

   }

 

diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/UIMAClassLoader.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/UIMAClassLoader.java
index 60eead5..8d85b45 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/UIMAClassLoader.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/UIMAClassLoader.java
@@ -35,6 +35,8 @@
  * delegated to the application class loader.
  * 
  * This loader supports loading a special class "MethodHandlesLookup" from org.apache.uima.cas.impl.MethodHandlesLookup
+ * This is loaded from a byte string in order to have the defaulting mechanism for
+ * MethodHandlesLookup default to this class loaders context.
  * 
  */
 public class UIMAClassLoader extends URLClassLoader {
@@ -44,6 +46,10 @@
           }
          }
 
+  /** 
+   * This is a trick to allow loading the same class multiple times in different UIMAClassLoaders
+   * https://issues.apache.org/jira/browse/UIMA-5030 
+   */
   public static final String MHLC = "org.apache.uima.cas.impl.MethodHandlesLookup";
   /**
    * This is the byte array that defines the class org.apache.uima.cas.impl.MethodHandlesLookup, obtained by
@@ -115,7 +121,7 @@
    *           if a malformed URL has occurred in the classpath string.
    */
   public UIMAClassLoader(String classpath) throws MalformedURLException {
-    super(transformClasspath(classpath));
+    super(Misc.classpath2urls(classpath));
     commonInit();
   }
 
@@ -157,7 +163,7 @@
    *           if a malformed URL has occurred in the classpath string.
    */
   public UIMAClassLoader(String classpath, ClassLoader parent) throws MalformedURLException {
-    super(transformClasspath(classpath), parent);
+    super(Misc.classpath2urls(classpath), parent);
     commonInit();
   }
   
@@ -223,5 +229,20 @@
   
     }
   }
+
+  /* 
+   * loads resource from this class loader first, if possible
+   * (non-Javadoc)
+   * @see java.lang.ClassLoader#getResource(java.lang.String)
+   */
+  @Override
+  public URL getResource(String name) {
+    URL url = findResource(name);
+    
+    if (null == url) {
+      url = super.getResource(name);
+    }
+    return url;
+  }
   
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/XMLUtils.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/XMLUtils.java
index b137378..1f75b37 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/XMLUtils.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/XMLUtils.java
@@ -23,10 +23,23 @@
 import java.io.Writer;
 import java.lang.reflect.Constructor;
 
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXTransformerFactory;
+
+import org.apache.uima.UIMAFramework;
+import org.apache.uima.util.Level;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 import org.w3c.dom.Text;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLReaderFactory;
 
 /**
  * Some utilities for working with XML.
@@ -34,7 +47,16 @@
  * 
  */
 public abstract class XMLUtils {
-
+  
+  // constants - not all Java versions define these
+  
+  private static final String ACCESS_EXTERNAL_STYLESHEET = "http://javax.xml.XMLConstants/property/accessExternalStylesheet";
+  private static final String ACCESS_EXTERNAL_DTD = "http://javax.xml.XMLConstants/property/accessExternalDTD";
+  
+  private static final String DISALLOW_DOCTYPE_DECL = "http://apache.org/xml/features/disallow-doctype-decl";
+  private static final String LOAD_EXTERNAL_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
+  private static final String EXTERNAL_GENERAL_ENTITIES = "http://xml.org/sax/features/external-general-entities";
+  private static final String EXTERNAL_PARAMETER_ENTITIES = "http://xml.org/sax/features/external-parameter-entities";
   /**
    * Normalizes the given string for output to XML. This converts all special characters, e.g. &lt;,
    * %gt;, &amp;, to their XML representations, e.g. &amp;lt;, &amp;gt;, &amp;amp;. The normalized
@@ -517,4 +539,131 @@
         (c >= 0xE000 && c <= 0xFFFD));
   }
 
+  public static SAXParserFactory createSAXParserFactory() {
+    SAXParserFactory factory = SAXParserFactory.newInstance();
+    try {
+      factory.setFeature(DISALLOW_DOCTYPE_DECL, true);
+    } catch (SAXNotRecognizedException e) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "SAXParserFactory didn't recognize feature " + DISALLOW_DOCTYPE_DECL);
+    } catch (SAXNotSupportedException e) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "SAXParserFactory doesn't support feature " + DISALLOW_DOCTYPE_DECL);
+    } catch (ParserConfigurationException e) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "SAXParserFactory doesn't support feature " + DISALLOW_DOCTYPE_DECL);
+    }
+    
+    try {
+      factory.setFeature(LOAD_EXTERNAL_DTD, false);
+    } catch (SAXNotRecognizedException e) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "SAXParserFactory didn't recognize feature " + LOAD_EXTERNAL_DTD);
+    } catch (SAXNotSupportedException e) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "SAXParserFactory doesn't support feature " + LOAD_EXTERNAL_DTD);
+    } catch (ParserConfigurationException e) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "SAXParserFactory doesn't support feature " + LOAD_EXTERNAL_DTD);
+    }
+    
+    factory.setXIncludeAware(false);
+    return factory;
+  }
+  
+  public static XMLReader createXMLReader() throws SAXException {
+    XMLReader xmlReader = XMLReaderFactory.createXMLReader();
+    try {
+      xmlReader.setFeature(EXTERNAL_GENERAL_ENTITIES, false);
+    } catch (SAXNotRecognizedException e) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "XMLReader didn't recognize feature " + EXTERNAL_GENERAL_ENTITIES);
+    } catch (SAXNotSupportedException e) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "XMLReader doesn't support feature " + EXTERNAL_GENERAL_ENTITIES);
+    }
+
+    try {
+      xmlReader.setFeature(EXTERNAL_PARAMETER_ENTITIES, false);
+    } catch (SAXNotRecognizedException e) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "XMLReader didn't recognize feature " + EXTERNAL_PARAMETER_ENTITIES);
+    } catch (SAXNotSupportedException e) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "XMLReader doesn't support feature " + EXTERNAL_PARAMETER_ENTITIES);
+    }
+
+    try {
+      xmlReader.setFeature(LOAD_EXTERNAL_DTD,false);
+    } catch (SAXNotRecognizedException e) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "XMLReader didn't recognized feature " + LOAD_EXTERNAL_DTD);
+    } catch (SAXNotSupportedException e) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "XMLReader doesn't support feature " + LOAD_EXTERNAL_DTD);
+    }
+
+    return xmlReader;
+  }
+  
+  public static SAXTransformerFactory createSaxTransformerFactory() {
+    SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();    
+    try {
+      saxTransformerFactory.setAttribute(ACCESS_EXTERNAL_DTD, "");
+    } catch (IllegalArgumentException e) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "SAXTransformerFactory didn't recognize setting attribute " + ACCESS_EXTERNAL_DTD);
+    }
+
+    try {
+      saxTransformerFactory.setAttribute(ACCESS_EXTERNAL_STYLESHEET, "");
+    } catch (IllegalArgumentException e) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "SAXTransformerFactory didn't recognize setting attribute " + ACCESS_EXTERNAL_STYLESHEET);
+    }
+
+    return saxTransformerFactory;
+  }
+
+  public static TransformerFactory createTransformerFactory() {
+    TransformerFactory transformerFactory = TransformerFactory.newInstance();
+    try {
+      transformerFactory.setAttribute(ACCESS_EXTERNAL_DTD, "");
+    } catch (IllegalArgumentException e) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "TransformerFactory didn't recognize setting attribute " + ACCESS_EXTERNAL_DTD);
+    }
+    
+    try {
+      transformerFactory.setAttribute(ACCESS_EXTERNAL_STYLESHEET, "");
+    } catch (IllegalArgumentException e) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "TransformerFactory didn't recognize setting attribute " + ACCESS_EXTERNAL_STYLESHEET);
+    }
+
+    return transformerFactory;
+  }
+  
+  public static DocumentBuilderFactory createDocumentBuilderFactory() { 
+    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+    try {
+      documentBuilderFactory.setFeature(DISALLOW_DOCTYPE_DECL, true);
+    } catch (ParserConfigurationException e1) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "DocumentBuilderFactory didn't recognize setting feature " + DISALLOW_DOCTYPE_DECL);
+    }
+    
+    try {
+      documentBuilderFactory.setFeature(LOAD_EXTERNAL_DTD, false);
+    } catch (ParserConfigurationException e) {
+      UIMAFramework.getLogger().log(Level.WARNING, 
+          "DocumentBuilderFactory doesn't support feature " + LOAD_EXTERNAL_DTD);
+    }
+    
+    documentBuilderFactory.setXIncludeAware(false);
+    documentBuilderFactory.setExpandEntityReferences(false);
+    
+    return documentBuilderFactory;
+  }
 }
+
diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/rb_trees/Int2IntRBT.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/rb_trees/Int2IntRBT.java
index 3ba42bc..d259bd2 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/rb_trees/Int2IntRBT.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/rb_trees/Int2IntRBT.java
@@ -125,42 +125,31 @@
 
     private KeyIterator() {
       super();
-      this.currentNode = NIL;
+      this.currentNode = getFirstNode();
     }
 
     public final boolean hasNext() {
-      return (this.currentNode != Int2IntRBT.this.greatestNode);
+      return this.currentNode != NIL;
     }
 
-    public final int next() {
-      if (!hasNext()) {
-        throw new NoSuchElementException();
-      }
-      this.currentNode = (this.currentNode == NIL) ? getFirstNode() : nextNode(this.currentNode);
-      return Int2IntRBT.this.getKeyForNode(this.currentNode);
+    @Override
+    public final int nextNvc() {
+      int v = Int2IntRBT.this.getKeyForNode(this.currentNode);
+      this.currentNode = nextNode(this.currentNode);
+      return v;      
     }
-
+    
     /**
      * @see org.apache.uima.internal.util.IntListIterator#hasPrevious()
      */
     public boolean hasPrevious() {
-      return (this.currentNode != NIL);
+      return this.currentNode != NIL && this.currentNode != getFirstNode();
     }
-
-    /**
-     * @see org.apache.uima.internal.util.IntListIterator#previous()
-     */
-    public int previous() {
-      if (!hasPrevious()) {
-        throw new NoSuchElementException();
-      }
-      final int currentKey = Int2IntRBT.this.getKeyForNode(this.currentNode);
-      if (this.currentNode == getFirstNode()) {
-        this.currentNode = NIL;
-      } else {
-        this.currentNode = previousNode(this.currentNode);
-      }
-      return currentKey;
+    
+    @Override
+    public int previousNvc() {
+      this.currentNode = previousNode(this.currentNode);
+      return Int2IntRBT.this.getKeyForNode(this.currentNode);
     }
 
     /**
diff --git a/uimaj-core/src/main/java/org/apache/uima/internal/util/rb_trees/IntArrayRBT.java b/uimaj-core/src/main/java/org/apache/uima/internal/util/rb_trees/IntArrayRBT.java
index e061eb1..2f8f278 100644
--- a/uimaj-core/src/main/java/org/apache/uima/internal/util/rb_trees/IntArrayRBT.java
+++ b/uimaj-core/src/main/java/org/apache/uima/internal/util/rb_trees/IntArrayRBT.java
@@ -193,15 +193,12 @@
     public final boolean hasNext() {
       return (this.currentNode != NIL);
     }
-
+    
     @Override
-    public final int next() {
-      if (!hasNext()) {
-        throw new NoSuchElementException();
-      }
+    public final int nextNvc() {
       int r = IntArrayRBT.this.getKeyForNode(this.currentNode);
       this.currentNode = nextNode(this.currentNode);
-      return r;
+      return r;      
     }
 
     /**
@@ -209,7 +206,7 @@
      */
     @Override
     public boolean hasPrevious() {
-      return (previousNode(this.currentNode) != NIL);
+      return previousNode(this.currentNode) != NIL;
     }
 
     /**
@@ -223,6 +220,12 @@
       }
       throw new NoSuchElementException();
     }
+    
+    @Override
+    public int previousNvc() {
+      this.currentNode = previousNode(this.currentNode);
+      return getKey(this.currentNode);
+    }
 
     /**
      * @see org.apache.uima.internal.util.IntListIterator#moveToEnd()
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/JCas.java b/uimaj-core/src/main/java/org/apache/uima/jcas/JCas.java
index 2bd0303..7e86139 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/JCas.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/JCas.java
@@ -20,6 +20,7 @@
 package org.apache.uima.jcas;
 
 import java.io.InputStream;
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.ListIterator;
 
@@ -27,6 +28,7 @@
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASException;
 import org.apache.uima.cas.CASRuntimeException;
+import org.apache.uima.cas.CommonArrayFS;
 import org.apache.uima.cas.ConstraintFactory;
 import org.apache.uima.cas.FSIndex;
 import org.apache.uima.cas.FSIndexRepository;
@@ -46,9 +48,21 @@
 import org.apache.uima.cas.impl.LowLevelCAS;
 import org.apache.uima.cas.impl.LowLevelIndexRepository;
 import org.apache.uima.cas.impl.SelectFSs_impl;
+import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.text.AnnotationIndex;
+import org.apache.uima.jcas.cas.BooleanArray;
+import org.apache.uima.jcas.cas.ByteArray;
+import org.apache.uima.jcas.cas.DoubleArray;
+import org.apache.uima.jcas.cas.EmptyFSList;
+import org.apache.uima.jcas.cas.EmptyFloatList;
+import org.apache.uima.jcas.cas.EmptyIntegerList;
+import org.apache.uima.jcas.cas.EmptyList;
+import org.apache.uima.jcas.cas.EmptyStringList;
 import org.apache.uima.jcas.cas.FSArray;
+import org.apache.uima.jcas.cas.FloatArray;
 import org.apache.uima.jcas.cas.IntegerArray;
+import org.apache.uima.jcas.cas.LongArray;
+import org.apache.uima.jcas.cas.ShortArray;
 import org.apache.uima.jcas.cas.Sofa;
 import org.apache.uima.jcas.cas.StringArray;
 import org.apache.uima.jcas.cas.TOP;
@@ -102,11 +116,11 @@
   /**
    * Backwards Compatibility only - throws unsupported operation exception
    * 
-   * get the JCas _Type instance for a particular CAS type constant
+   * In UIMA V2, this previously got the JCas _Type instance for a particular CAS type constant
+   * In UIMA V3, there is no _Type instance, so this throws an exception
    * 
-   * @param i
-   *          the CAS type constant, written as Foo.type
-   * @return the instance of the JCas xxx_Type object for the specified type
+   * @param i the CAS type constant, written as Foo.type
+   * @return none - throws an exception
    */
   public abstract TOP_Type getType(int i);
   
@@ -159,7 +173,7 @@
    */
   @Deprecated
   default void putJfsFromCaddr(int casAddr, FeatureStructure fs) {
-    throw new UnsupportedOperationException("not supported in UIMA v3");
+    throw new UnsupportedOperationException("not supported in UIMA v3; maybe caused by running with UIMA v2 JCas classes in UIMA v3");
   } 
 
   /*
@@ -167,7 +181,7 @@
    * @deprecated only for V2 compiling
    */
   default <T extends TOP> T getJfsFromCaddr(int casAddr) {
-    throw new UnsupportedOperationException("not supported in UIMA v3");
+    throw new UnsupportedOperationException("not supported in UIMA v3; maybe caused by running with UIMA v2 JCas classes in UIMA v3");
   } 
 
   /*
@@ -244,12 +258,11 @@
 
   /**
    * Gets the document annotation. The object returned from this method can be typecast to
-   * org.apache.uima.jcas.tcas.DocumentAnnotation
+   * org.apache.uima.jcas.tcas.DocumentAnnotation if that class is loaded (it may not be...)
    * <p>
-   * The reason that the return type of this method is not DocumentAnnotation is because of problems
-   * that arise when using the UIMA Extension ClassLoader to load annotator classes. The
-   * DocumentAnnotation type may be defined in the UIMA extension ClassLoader, differently than in
-   * the framework ClassLoader.
+   * The reason that the return type of this method is not DocumentAnnotation is because 
+   * that class may not be loaded, or it may be loaded under a different class loader
+   * when using the UIMA Extension ClassLoader to load annotator classes. 
    * 
    * @return The one instance of the DocumentAnnotation annotation.
    * @see org.apache.uima.cas.CAS#getDocumentAnnotation
@@ -262,35 +275,151 @@
    * updatable (it has no subfields). This is initialized lazily on first reference, and reset when
    * the CAS is reset.
    * @return 0-length instance of a StringArray
+   * @deprecated renamed emptyXXXArray
    */
-
-  StringArray getStringArray0L();
-
+  @Deprecated
+  default StringArray getStringArray0L() {
+    return this.getCas().emptyStringArray();
+  }
   /**
    * A constant for each cas which holds a 0-length instance. Since this can be a common value, we
    * avoid creating multiple copies of it. All uses can use the same valuee because it is not
    * updatable (it has no subfields). This is initialized lazily on first reference, and reset when
    * the CAS is reset.
+   * @return 0-length instance of a StringArray
+   */
+  default StringArray emptyStringArray() {
+    return this.getCas().emptyStringArray();
+  }
+
+  /**
+   * A constant for each cas which holds a 0-length instance. Since this can be a common value, we
+   * avoid creating multiple copies of it. All uses can use the same value because it is not
+   * updatable (it has no subfields). This is initialized lazily on first reference, and reset when
+   * the CAS is reset.
+   * @return 0-length instance of an IntegerArray
+   * @deprecated renamed emptyXXXArray
+   */
+  @Deprecated
+  default IntegerArray getIntegerArray0L() {
+    return this.getCas().emptyIntegerArray();
+  }
+  /**
+   * A constant for each cas which holds a 0-length instance. Since this can be a common value, we
+   * avoid creating multiple copies of it. All uses can use the same value because it is not
+   * updatable (it has no subfields). This is initialized lazily on first reference, and reset when
+   * the CAS is reset.
    * @return 0-length instance of an IntegerArray
    */
-  IntegerArray getIntegerArray0L();
+  default IntegerArray emptyIntegerArray() {
+    return this.getCas().emptyIntegerArray();
+  }
 
   /**
    * A constant for each cas which holds a 0-length instance. Since this can be a common value, we
-   * avoid creating multiple copies of it. All uses can use the same valuee because it is not
+   * avoid creating multiple copies of it. All uses can use the same value because it is not
    * updatable (it has no subfields). This is initialized lazily on first reference, and reset when
    * the CAS is reset.
    * @return 0-length instance of a FloatArray
-  FloatArray getFloatArray0L();
+   * @deprecated renamed emptyXXXArray
+   */
+  @Deprecated
+  default FloatArray getFloatArray0L() {
+    return this.getCas().emptyFloatArray();
+  }
+  /**
+   * A constant for each cas which holds a 0-length instance. Since this can be a common value, we
+   * avoid creating multiple copies of it. All uses can use the same value because it is not
+   * updatable (it has no subfields). This is initialized lazily on first reference, and reset when
+   * the CAS is reset.
+   * @return 0-length instance of a FloatArray
+   */
+  default FloatArray emptyFloatArray() {
+    return this.getCas().emptyFloatArray();
+  }
 
   /**
    * A constant for each cas which holds a 0-length instance. Since this can be a common value, we
-   * avoid creating multiple copies of it. All uses can use the same valuee because it is not
+   * avoid creating multiple copies of it. All uses can use the same value because it is not
    * updatable (it has no subfields). This is initialized lazily on first reference, and reset when
    * the CAS is reset.
+   * 
+   * See also the CAS API 
+   * @return 0-length instance of a FSArray
+   * @deprecated renamed emptyXXXArray
+   */
+  @Deprecated
+  default FSArray getFSArray0L() {
+    return this.getCas().emptyFSArray();
+  }
+  /**
+   * A constant for each cas which holds a 0-length instance. Since this can be a common value, we
+   * avoid creating multiple copies of it. All uses can use the same value because it is not
+   * updatable (it has no subfields). This is initialized lazily on first reference, and reset when
+   * the CAS is reset.
+   * 
+   * See also the CAS API 
    * @return 0-length instance of a FSArray
    */
-  FSArray getFSArray0L();
+  default FSArray emptyFSArray() {
+    return this.getCas().emptyFSArray();
+  }
+
+  /**
+   * A constant for each cas which holds a 0-length instance. Since this can be a common value, we
+   * avoid creating multiple copies of it. All uses can use the same value because it is not
+   * updatable (it has no subfields). This is initialized lazily on first reference, and reset when
+   * the CAS is reset.
+   * @return 0-length instance of a ByteArray
+   */
+  default ByteArray emptyByteArray() {
+    return this.getCas().emptyByteArray();
+  }
+
+  /**
+   * A constant for each cas which holds a 0-length instance. Since this can be a common value, we
+   * avoid creating multiple copies of it. All uses can use the same value because it is not
+   * updatable (it has no subfields). This is initialized lazily on first reference, and reset when
+   * the CAS is reset.
+   * @return 0-length instance of a ShortArray
+   */
+  default ShortArray emptyShortArray() {
+    return this.getCas().emptyShortArray();
+  }
+
+  /**
+   * A constant for each cas which holds a 0-length instance. Since this can be a common value, we
+   * avoid creating multiple copies of it. All uses can use the same value because it is not
+   * updatable (it has no subfields). This is initialized lazily on first reference, and reset when
+   * the CAS is reset.
+   * @return 0-length instance of a LongArray
+   */
+  default LongArray emptyLongArray() {
+    return this.getCas().emptyLongArray();
+  }
+  
+  /**
+   * A constant for each cas which holds a 0-length instance. Since this can be a common value, we
+   * avoid creating multiple copies of it. All uses can use the same value because it is not
+   * updatable (it has no subfields). This is initialized lazily on first reference, and reset when
+   * the CAS is reset.
+   * @return 0-length instance of a DoubleArray
+   */
+  default DoubleArray emptyDoubleArray() {
+    return this.getCas().emptyDoubleArray();
+  }
+  
+  /**
+   * A constant for each cas which holds a 0-length instance. Since this can be a common value, we
+   * avoid creating multiple copies of it. All uses can use the same value because it is not
+   * updatable (it has no subfields). This is initialized lazily on first reference, and reset when
+   * the CAS is reset.
+   * @return 0-length instance of a DoubleArray
+   */
+  default BooleanArray emptyBooleanArray() {
+    return this.getCas().emptyBooleanArray();
+  }
+
 
   /**
    * initialize the JCas for new Cas content. Not used, does nothing.
@@ -595,12 +724,40 @@
   void removeAllIncludingSubtypes(int i);
   
   /**
+   * Remove all instances of type, including all subtypes from all indexes in the repository view.
+   * @param clazz the JCas class of the type to remove.  To remove all use TOP.class
+   * @param <T> the type to remove
+   * @exception NullPointerException if the <code>clazz</code> parameter is <code>null</code>.
+  */
+  default <T extends TOP> void removeAllIncludingSubtypes(Class<T> clazz) {
+    getFSIndexRepository().removeAllIncludingSubtypes(getCasType(clazz));
+  }
+  
+  /**
    * Remove all feature structures of a given type (excluding subtypes) from all indexes in the repository associated with this CAS View.
    * @param i the CAS type constant, written as Foo.type (for a given JCas Type) or anInstanceOfFoo.getTypeIndexID(), for an instance
    */
   void removeAllExcludingSubtypes(int i);
 
   /**
+   * Remove all instances of just this type, excluding subtypes, from all indexes in the repository view.
+   * @param clazz the JCas Class of the type to remove
+   * @param <T> the type to remove
+   * @exception NullPointerException if the <code>type</code> parameter is <code>null</code>.
+  */
+  default <T extends TOP> void removeAllExcludingSubtypes(Class<T> clazz) {
+    getFSIndexRepository().removeAllExcludingSubtypes(getCasType(clazz));
+  }
+
+  /**
+   * Return the UIMA Type object corresponding to this JCas's JCas cover class
+   *   (Note: different JCas's, with different type systems, may share the same cover class impl)
+   * @param clazz a JCas cover class
+   * @return the corresponding UIMA Type object
+   */
+  public Type getCasType(Class<? extends FeatureStructure> clazz);
+  
+  /**
    * Get the standard annotation index.
    * 
    * @return The standard annotation index.
@@ -645,6 +802,22 @@
    * subtypes).  The elements are returned in arbitrary order, and duplicates (if they exist)
    * are not removed.
    *
+   * @param type - the type specifying which type and subtypes are included
+   * @param <T> the Java clazz of the returned types
+   *  
+   * @return An iterator that returns all indexed FeatureStructures of the JCas clazz 
+   *         and its subtypes, in no particular order.
+   */
+  default <T extends TOP> FSIterator<T> getAllIndexedFS(Type type) {
+    return getFSIndexRepository().getAllIndexedFS(type);
+  }
+
+  
+  /**
+   * Gets an iterator over all indexed FeatureStructures of the specified Type (and any of its
+   * subtypes).  The elements are returned in arbitrary order, and duplicates (if they exist)
+   * are not removed.
+   *
    * @param clazz - the JCas Java class specifing which type and subtypes are included
    * @param <T> the Java clazz
    *  
@@ -653,8 +826,43 @@
    */
   <T extends TOP> FSIterator<T> getAllIndexedFS(Class<T> clazz);
 
+  /**
+   * Returns an unmodifiable collection of all the FSs that are indexed in this view, in an arbitrary order.  
+   * Subsequent modifications to the indexes do not affect this collection.
+   * @param type the type of Feature Structures to include (including subtypes)
+   * @param <T> The Java class associated with type
+   * @return an unmodifiable, unordered collection of all indexed (in this view) Feature Structures
+   *         of the specified type (including subtypes)
+   */
+  default <T extends TOP> Collection<T> getIndexedFSs(Type type) {
+    return this.getIndexRepository().getIndexedFSs(type);
+  }
   
   /**
+   * Returns an unmodifiable collection of all the FSs that are indexed in this view, in an arbitrary order.  
+   * Subsequent modifications to the indexes do not affect this collection.
+   * @param clazz
+   *          The JCas class corresponding to the type
+   * @param <T> The Java class associated with type
+   * @return an unmodifiable, unordered collection of all indexed (in this view) Feature Structures
+   *         of the specified type (including subtypes)
+   */
+  default <T extends TOP> Collection<T> getIndexedFSs(Class<T> clazz) {
+    return this.getIndexRepository().getIndexedFSs(clazz);
+  }
+
+  /**
+   * Returns an unmodifiable collection of all of the FSs
+   * that are indexed in this view, in an arbitrary order.  
+   * Subsequent modifications to the indexes do not affect this collection.
+   * @return an unmodifiable, unordered collection of all indexed (in this view) Feature Structures
+   *         of the specified type (including subtypes)
+   */
+  default Collection<TOP> getIndexedFSs() { 
+    return this.getIndexRepository().getIndexedFSs();
+  }
+
+  /**
    * Get iterator over all views in this JCas.  Each view provides access to Sofa data
    * and the index repository that contains metadata (annotations and other feature 
    * structures) pertaining to that Sofa.
@@ -723,24 +931,94 @@
   <T extends TOP> FSIndex<T> getIndex(String label, Class<T> clazz);
   
   
-  default <T extends FeatureStructure> SelectFSs<T> select() {
+  /**
+   * @param <T> the Type of the elements being accessed
+   * @return a newly created selection object for accessing feature structures
+   */  
+  default <T extends TOP> SelectFSs<T> select() {
     return new SelectFSs_impl<>(getCas());
   }
 
-  default <N extends FeatureStructure> SelectFSs<N> select(Type type) {
+  /**
+   * @param type specifies the type (and subtypes of that type) to access
+   * @param <N> the Type of the elements being accessed
+   * @return a newly created selection object for accessing feature structures of that type and its subtypes
+   */
+  default <N extends TOP> SelectFSs<N> select(Type type) {
     return new SelectFSs_impl<>(getCasImpl()).type(type);
   }
 
-  default <N extends FeatureStructure> SelectFSs<N> select(Class<N> clazz) {
+  /**
+   * @param clazz a JCas class corresponding to the type (and subtypes of that type) to access
+   * @param <N> the Type of the elements being accessed
+   * @return a newly created selection object for accessing feature structures of that type and its subtypes
+   */
+ default <N extends TOP> SelectFSs<N> select(Class<N> clazz) {
     return new SelectFSs_impl<>(getCasImpl()).type(clazz);
   }
 
-  default <N extends FeatureStructure> SelectFSs<N> select(int jcasType) {
+ /**
+  * @param jcasType the "type" field from the JCas class corresponding to the type (and subtypes of that type) to access
+  * @param <N> the Type of the elements being accessed
+  * @return a newly created selection object for accessing feature structures of that type and its subtypes
+  */
+  default <N extends TOP> SelectFSs<N> select(int jcasType) {
     return new SelectFSs_impl<>(getCasImpl()).type(jcasType);
   }
 
-  default <N extends FeatureStructure> SelectFSs<N> select(String fullyQualifiedTypeName) {
+  /**
+   * @param fullyQualifiedTypeName the string name of the type to access
+   * @param <N> the Type of the elements being accessed
+   * @return a newly created selection object for accessing feature structures of that type and its subtypes
+   */
+  default <N extends TOP> SelectFSs<N> select(String fullyQualifiedTypeName) {
     return new SelectFSs_impl<>(getCasImpl()).type(fullyQualifiedTypeName);
   }
 
+  /**
+   * @param clazz the JCas class of the list, e.g. FloatList.class
+   * @param <T> the type of the list, e.g FloatList
+   * @return - the shared (in this CAS) instance of the empty list (immutable)
+   */
+  default <T extends TOP> EmptyList emptyList(Class<T> clazz) {
+    return this.getCasImpl().emptyListFromTypeCode(((TypeImpl)getCasType(clazz)).getCode());
+  }
+
+  /** 
+   * @return a lazily created shared (for this CAS) empty list
+   */
+  default EmptyFloatList emptyFloatList() {
+    return getCas().emptyFloatList();
+  };
+  
+  /** 
+   * @param <T> the type of the FeatureStructures in the FSList
+   * @return a lazily created shared (for this CAS) empty list
+   */
+  default <T extends TOP> EmptyFSList<T> emptyFSList() {
+    return getCas().emptyFSList();
+  };
+  
+  /** 
+   * @return a lazily created shared (for this CAS) empty list
+   */
+  default EmptyIntegerList emptyIntegerList() {
+    return getCas().emptyIntegerList();
+  };
+
+  /** 
+   * @return a lazily created shared (for this CAS) empty list
+   */
+  default EmptyStringList emptyStringList() {
+    return getCas().emptyStringList();
+  };
+  
+  /**
+   * @param clazz the JCas class of the Array, e.g. FloatArray.class
+   * @param <T> the type of the list, e.g FloatArray
+   * @return a shared (in this CAS) instance of the empty array (immutable)
+   */
+  default <T extends TOP> CommonArrayFS emptyArray(Class<T> clazz) {
+    return this.getCasImpl().emptyArray(getCasType(clazz));
+  }
 }
\ No newline at end of file
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/JCasRegistry.java b/uimaj-core/src/main/java/org/apache/uima/jcas/JCasRegistry.java
index 88a62da..838b39a 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/JCasRegistry.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/JCasRegistry.java
@@ -34,6 +34,9 @@
  * The internals maintain a weak reference to the loaded class in order to allow the 
  * index value to be reused if the associated JCas class is garbaged collected.
  * 
+ *   This could happen if the JCas classes are loaded under a class loader which is a child
+ *   of the class loader of this framework class, and that child classloader later gets GC'd.
+ * 
  * The register method is called from JCas cover class static initialization and
  * returns the unique index value for this class.
  * 
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/AnnotationBase.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/AnnotationBase.java
index cfc151b..ab30adf 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/AnnotationBase.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/AnnotationBase.java
@@ -19,6 +19,9 @@
 
 package org.apache.uima.jcas.cas;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASRuntimeException;
 import org.apache.uima.cas.Feature;
@@ -53,7 +56,7 @@
 public class AnnotationBase extends TOP implements AnnotationBaseImpl {
 
   /* public static strings for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.cas.jcas.AnnotationBase";
+  public final static String _TypeName = CAS.TYPE_NAME_ANNOTATION_BASE;
   public final static String _FeatName_sofa = "sofa";
 
   public final static int typeIndexID = JCasRegistry.register(AnnotationBase.class);
@@ -68,11 +71,14 @@
   // private final static int _FI_sofa = JCasRegistry.registerFeature();  // only for journal-able or corruptable feature slots
   
   /* local data */
-  public final static int _FI_sofa = TypeSystemImpl.getAdjustedFeatureOffset("sofa");
+//  public final static int _FI_sofa = TypeSystemImpl.getAdjustedFeatureOffset("sofa");
+  private final static CallSite _FC_sofa = TypeSystemImpl.createCallSite(AnnotationBase.class, "sofa");
+  private final static MethodHandle _FH_sofa = _FC_sofa.dynamicInvoker();
   
 //  private final Sofa _F_sofa;
   
   // Never called. Disable default constructor
+  @Deprecated
   protected AnnotationBase() {
   }
 
@@ -87,7 +93,7 @@
       throw new CASRuntimeException(CASRuntimeException.DISALLOW_CREATE_ANNOTATION_IN_BASE_CAS, this.getClass().getName());
     }
     // no journaling, no index corruption checking
-    _setRefValueCommon(_FI_sofa, _casView.getSofaRef());
+    _setRefValueCommon(wrapGetIntCatchException(_FH_sofa), _casView.getSofaRef());
   }
 
   /**
@@ -103,7 +109,7 @@
       throw new CASRuntimeException(CASRuntimeException.DISALLOW_CREATE_ANNOTATION_IN_BASE_CAS, this.getClass().getName());
     }
     // no journaling, no index corruption checking
-    _setRefValueCommon(_FI_sofa, _casView.getSofaRef());
+    _setRefValueCommon(wrapGetIntCatchException(_FH_sofa), _casView.getSofaRef());
   }
 
   // *------------------*
@@ -112,7 +118,7 @@
   /*
    * getter for sofa - gets Sofaref for annotation
    */
-  public Sofa getSofa() { return (Sofa) _getFeatureValueNc(_FI_sofa); }
+  public Sofa getSofa() { return (Sofa) _getFeatureValueNc(wrapGetIntCatchException(_FH_sofa)); }
   
   // There is no setter for this
   //   The value is set and is fixed when this is created
@@ -128,7 +134,7 @@
     if (fi.getCode() == TypeSystemConstants.annotBaseSofaFeatCode) {
       // trying to set the sofa - don't do this, but check if the value
       // is OK (note: may break backwards compatibility)  
-      if (v != _getFeatureValueNc(AnnotationBase._FI_sofa)) {
+      if (v != _getFeatureValueNc(wrapGetIntCatchException(_FH_sofa))) {
         throw new CASRuntimeException(CASRuntimeException.ILLEGAL_SOFAREF_MODIFICATION);
       }
     }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/ArrayFSImpl.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/ArrayFSImpl.java
index 4d29e5b..f1a5b04 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/ArrayFSImpl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/ArrayFSImpl.java
@@ -19,6 +19,7 @@
 package org.apache.uima.jcas.cas;

 

 import org.apache.uima.cas.ArrayFS;

+import org.apache.uima.cas.FeatureStructure;

 

 /**

  * For backwards compatibility with V2, only

@@ -26,6 +27,6 @@
  * @deprecated use FSArray instead

  */

 @Deprecated

-public interface ArrayFSImpl extends ArrayFS {

+public interface ArrayFSImpl<E extends FeatureStructure> extends ArrayFS<E> {

   

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/BooleanArray.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/BooleanArray.java
index 0f5666e..1c65194 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/BooleanArray.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/BooleanArray.java
@@ -19,10 +19,11 @@
 
 package org.apache.uima.jcas.cas;
 
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
-import org.apache.uima.cas.BooleanArrayFS;
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CommonArrayFS;
 import org.apache.uima.cas.impl.BooleanArrayFSImpl;
 import org.apache.uima.cas.impl.CASImpl;
@@ -31,10 +32,10 @@
 import org.apache.uima.jcas.JCasRegistry;
 
 /** JCas class model for BooleanArray */
-public final class BooleanArray extends TOP implements CommonPrimitiveArray, BooleanArrayFSImpl, Iterable<Boolean> {
+public final class BooleanArray extends TOP implements CommonPrimitiveArray<Boolean>, BooleanArrayFSImpl, Iterable<Boolean> {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.cas.jcas.BooleanArray";
+  public final static String _TypeName = CAS.TYPE_NAME_BOOLEAN_ARRAY;
 
   /**
    * Each cover class when loaded sets an index. Used in the JCas typeArray to go from the cover
@@ -76,8 +77,8 @@
     if (CASImpl.traceFSs) {  // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(2); // space for length and ref
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2size_nonHeapStoredArrays(); 
     }     
   }
   
@@ -93,8 +94,8 @@
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(2); // space for length and ref
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2size_nonHeapStoredArrays(); 
     }     
   }
 
@@ -132,7 +133,7 @@
    * @see org.apache.uima.cas.BooleanArrayFS#toArray()
    */
   public boolean[] toArray() {
-    return theArray.clone();
+    return Arrays.copyOf(theArray, theArray.length);
   }
 
   /** return the size of the array */
@@ -170,7 +171,7 @@
    * @see org.apache.uima.jcas.cas.CommonArray#copyValuesFrom(org.apache.uima.jcas.cas.CommonArray)
    */
   @Override
-  public void copyValuesFrom(CommonArrayFS v) {
+  public void copyValuesFrom(CommonArrayFS<Boolean> v) {
     BooleanArray bv = (BooleanArray) v;
     System.arraycopy(bv.theArray,  0,  theArray, 0, theArray.length);
     _casView.maybeLogArrayUpdates(this, 0, size());
@@ -209,9 +210,10 @@
    * @param a the source for the array's initial values
    * @return a newly created and populated array
    */
-  public static BooleanArray createFromArray(JCas jcas, boolean[] a) {
+  public static BooleanArray create(JCas jcas, boolean[] a) {
     BooleanArray booleanArray = new BooleanArray(jcas, a.length);
     booleanArray.copyFromArray(a, 0, 0, a.length);
     return booleanArray;
   }
+  
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/ByteArray.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/ByteArray.java
index d26011b..76a34a4 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/ByteArray.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/ByteArray.java
@@ -19,10 +19,11 @@
 
 package org.apache.uima.jcas.cas;
 
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
-import org.apache.uima.cas.ByteArrayFS;
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CommonArrayFS;
 import org.apache.uima.cas.impl.ByteArrayFSImpl;
 import org.apache.uima.cas.impl.CASImpl;
@@ -31,10 +32,10 @@
 import org.apache.uima.jcas.JCasRegistry;
 
 /** JCas class model for ByteArray */
-public final class ByteArray extends TOP implements CommonPrimitiveArray, ByteArrayFSImpl, Iterable<Byte> {
+public final class ByteArray extends TOP implements CommonPrimitiveArray<Byte>, ByteArrayFSImpl, Iterable<Byte> {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.cas.jcas.ByteArray";
+  public final static String _TypeName = CAS.TYPE_NAME_BYTE_ARRAY;
 
   /**
    * Each cover class when loaded sets an index. Used in the JCas typeArray to go from the cover
@@ -72,8 +73,8 @@
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(2); // space for length and ref
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2size_nonHeapStoredArrays(); 
     }     
   }
 
@@ -90,8 +91,8 @@
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(2); // space for length and ref
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2size_nonHeapStoredArrays(); 
     }     
   }
 
@@ -129,7 +130,7 @@
    * @see org.apache.uima.cas.ByteArrayFS#toArray()
    */
   public byte[] toArray() {
-    return theArray.clone();
+    return Arrays.copyOf(theArray, theArray.length);
   }
 
   /** return the size of the array */
@@ -167,7 +168,7 @@
    * @see org.apache.uima.jcas.cas.CommonArray#copyValuesFrom(org.apache.uima.jcas.cas.CommonArray)
    */
   @Override
-  public void copyValuesFrom(CommonArrayFS v) {
+  public void copyValuesFrom(CommonArrayFS<Byte> v) {
     ByteArray bv = (ByteArray) v;
     System.arraycopy(bv.theArray,  0,  theArray, 0, theArray.length);
     _casView.maybeLogArrayUpdates(this, 0, size());
@@ -205,10 +206,22 @@
    * @param a the source for the array's initial values
    * @return a newly created and populated array
    */
-  public static ByteArray createFromArray(JCas jcas, byte[] a) {
+  public static ByteArray create(JCas jcas, byte[] a) {
     ByteArray byteArray = new ByteArray(jcas, a.length);
     byteArray.copyFromArray(a, 0, 0, a.length);
     return byteArray;
   }
 
+  /**
+   * @param item the item to see if is in the array
+   * @return true if the item is in the array
+   */
+  public boolean contains(byte item) {
+    for (byte b : theArray) {
+      if (b == item) {
+        return true;
+      }
+    }
+    return false;
+  }
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/CommonList.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/CommonList.java
index ee7b1de..589dc71 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/CommonList.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/CommonList.java
@@ -30,7 +30,6 @@
 import org.apache.uima.cas.CASRuntimeException;

 import org.apache.uima.cas.FeatureStructure;

 import org.apache.uima.cas.impl.CasSerializerSupport;

-import org.apache.uima.cas.impl.FeatureStructureImplC;

 import org.apache.uima.cas.impl.XmiSerializationSharedData;

 import org.apache.uima.cas.impl.XmiSerializationSharedData.OotsElementData;

 import org.apache.uima.internal.util.XmlAttribute;

@@ -74,6 +73,11 @@
 		}

 	}

 	

+	/**

+	 * Like GetNthNode, but throws exception if empty

+	 * @param i - 

+	 * @return -

+	 */

 	default CommonList getNonEmptyNthNode(int i) {

 	  CommonList node = getNthNode(i);

     if (node instanceof EmptyList) {

@@ -89,34 +93,68 @@
 	 */

 	default int getLength() {

 	  final int[] length = {0};

-	  try {

-      walkList( n -> length[0]++, () -> {});

-    } catch (SAXException e) {

-      // never happen

-    }

+    walkList(n -> length[0]++, () -> {});

 	  return length[0];

 	}

 	

-	default void walkList(Consumer_withSaxException<NonEmptyList> consumer, Runnable foundLoop) throws SAXException {

-	  final Set<CommonList> visited = Collections.newSetFromMap(new IdentityHashMap<>());

-	  CommonList node = this;

-	  while (node instanceof NonEmptyList) {

-	    consumer.accept((NonEmptyList) node);

-	    node = node.getCommonTail();

-	    if (node == null) {

-	      break;

-	    }

-	    if (visited.contains(node) && foundLoop != null) {

-	      foundLoop.run();

-	    }

-	  }

-	}

-	

+	/**

+	 * Walks a list, executing the consumer on each element.

+	 * If a loop is found, the foundloop method is run.

+	 * @param consumer  a Consumer with Sax Exception 

+	 * @param foundLoop run if a loop happens

+	 * @throws SAXException -

+	 */

+  default void walkList_saxException(Consumer_withSaxException<NonEmptyList> consumer, Runnable foundLoop)

+      throws SAXException {

+    final Set<CommonList> visited = Collections.newSetFromMap(new IdentityHashMap<>());

+    CommonList node = this;

+    while (node instanceof NonEmptyList) {

+      consumer.accept((NonEmptyList) node);

+      node = node.getCommonTail();

+      if (node == null) {

+        break;

+      }

+      if (visited.contains(node) && foundLoop != null) {

+        foundLoop.run();

+      }

+    }

+  }

+

+  /**

+   * Walks a list, executing the consumer on each element.

+   * If a loop is found, the foundloop method is run.

+   * @param consumer  a Consumer (with no declared exceptions) 

+   * @param foundLoop run if a loop happens

+   */

+  default void walkList(Consumer<NonEmptyList> consumer, Runnable foundLoop) {

+    final Set<CommonList> visited = Collections.newSetFromMap(new IdentityHashMap<>());

+    CommonList node = this;

+    while (node instanceof NonEmptyList) {

+      consumer.accept((NonEmptyList) node);

+      node = node.getCommonTail();

+      if (node == null) {

+        break;

+      }

+      if (visited.contains(node) && foundLoop != null) {

+        foundLoop.run();

+      }

+    }

+  }

+

+  

+	/**

+	 * Creates a non empty node

+	 * @return a new non empty node

+	 */

 	CommonList createNonEmptyNode();

 	

-	CommonList getEmptyList();

+	/**

+	 * @return a shared instance of the empty node.

+	 */

+	CommonList emptyList();

 	

 	/**

+	 * Internal use

    * overridden in nonempty nodes

 	 * Return the head value of a list as a string suitable for serialization.

 	 * 

@@ -128,6 +166,7 @@
 	};

 	

 	/**

+	 * Internal use

    * overridden in nonempty nodes

    * used when deserializing

    * @param v value to set, as a string

@@ -188,14 +227,15 @@
   //   the default impl throws UnsupportedOperationException;

   //   each kind of non-empty list class has its own impl

   /**

-   * default 

-   * @param v -

+   * sets the tail of this node 

+   * @param v the tail

    */

   default void setTail(CommonList v) {

     throw new UnsupportedOperationException();

   }

 

   /**

+   * Internal Use.

    * List to String for XMI and JSON serialization, for the special format where

    *   all the list elements are in one serialized item

    * 

@@ -256,18 +296,23 @@
     } // end of while loop

   } 

   

+  /**

+   * Internal use

+   * @param sharedData -

+   * @param cds -

+   * @return -

+   */

   default List<String> anyListToStringList(XmiSerializationSharedData sharedData, CasSerializerSupport.CasDocSerializer cds) {

     final List<String> list = new ArrayList<String>();

     anyListToOutput(sharedData, cds, s -> list.add(s)); 

     return list;

   }

-    

-  /* (non-Javadoc)

-   * @see org.apache.uima.cas.FeatureStructure#id()

+  

+  /**

+   * @return true if this object represents an empty list

    */

-  @Override

-  default int _id() {

-    return ((FeatureStructureImplC)this)._id();

+  default boolean isEmpty() {

+    return this instanceof EmptyList;

   }

-

+    

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/CommonPrimitiveArray.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/CommonPrimitiveArray.java
index 8ea785c..63bfb3d 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/CommonPrimitiveArray.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/CommonPrimitiveArray.java
@@ -24,10 +24,12 @@
 /**

  * This interface is implemented by arrays of non-FeatureStructure components 

  *   boolean, byte, short, int, long, float, double, String, JavaObject

+ * Internal Use Only.

  */

-public interface CommonPrimitiveArray extends CommonArrayFS {

+public interface CommonPrimitiveArray<T> extends CommonArrayFS<T> {

   

   /**

+   * Internal Use Only.

    * Set an array value from a string representation

    * NOTE: does **not** log the change for delta cas; this should only be used by 

    *       internal deserializers

diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/DoubleArray.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/DoubleArray.java
index aac3ab3..50863a2 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/DoubleArray.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/DoubleArray.java
@@ -23,10 +23,11 @@
 import java.util.NoSuchElementException;
 import java.util.PrimitiveIterator.OfDouble;
 import java.util.Spliterator;
+import java.util.function.DoubleConsumer;
 import java.util.stream.DoubleStream;
 
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CommonArrayFS;
-import org.apache.uima.cas.DoubleArrayFS;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.DoubleArrayFSImpl;
 import org.apache.uima.cas.impl.TypeImpl;
@@ -34,10 +35,10 @@
 import org.apache.uima.jcas.JCasRegistry;
 
 /** JCas class model for DoubleArray */
-public final class DoubleArray extends TOP implements CommonPrimitiveArray, DoubleArrayFSImpl, Iterable<Double> {
+public final class DoubleArray extends TOP implements CommonPrimitiveArray<Double>, DoubleArrayFSImpl, Iterable<Double> {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.cas.jcas.DoubleArray";
+  public final static String _TypeName = CAS.TYPE_NAME_DOUBLE_ARRAY;
   
   /**
    * Each cover class when loaded sets an index. Used in the JCas typeArray to go from the cover
@@ -53,6 +54,7 @@
    * @return the type array index
    */
   // can't be factored - refs locally defined field
+  @Override
   public int getTypeIndexID() {
     return typeIndexID;
   }
@@ -76,8 +78,8 @@
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(2); // space for length and ref
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2size_nonHeapStoredArrays(); 
     }     
   }
   
@@ -94,14 +96,15 @@
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(2); // space for length and ref
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2size_nonHeapStoredArrays(); 
     }     
   }
 
   /**
    * @see org.apache.uima.cas.DoubleArrayFS#get(int)
    */
+  @Override
   public double get(int i) {
     return theArray[i];
   }
@@ -109,6 +112,7 @@
   /**
    * @see org.apache.uima.cas.DoubleArrayFS#set(int , double)
    */
+  @Override
   public void set(int i, double v) {
     theArray[i] = v;
     _casView.maybeLogArrayUpdate(this, null, i);
@@ -117,6 +121,7 @@
   /**
    * @see org.apache.uima.cas.DoubleArrayFS#copyFromArray(double[], int, int, int)
    */
+  @Override
   public void copyFromArray(double[] src, int srcPos, int destPos, int length) {
     System.arraycopy(src, srcPos, theArray, destPos, length);
   }
@@ -124,6 +129,7 @@
   /**
    * @see org.apache.uima.cas.DoubleArrayFS#copyToArray(int, double[], int, int)
    */
+  @Override
   public void copyToArray(int srcPos, double[] dest, int destPos, int length) {
     System.arraycopy(theArray, srcPos, dest, destPos, length);
   }
@@ -131,11 +137,13 @@
   /**
    * @see org.apache.uima.cas.DoubleArrayFS#toArray()
    */
+  @Override
   public double[] toArray() {
-    return theArray.clone();
+    return Arrays.copyOf(theArray, theArray.length);
   }
 
   /** return the size of the array */
+  @Override
   public int size() {
     return theArray.length;
   }
@@ -143,6 +151,7 @@
   /**
    * @see org.apache.uima.cas.DoubleArrayFS#copyToArray(int, String[], int, int)
    */
+  @Override
   public void copyToArray(int srcPos, String[] dest, int destPos, int length) {
     _casView.checkArrayBounds(theArray.length, srcPos, length);
     for (int i = 0; i < length; i++) {
@@ -153,6 +162,7 @@
   /**
    * @see org.apache.uima.cas.DoubleArrayFS#copyFromArray(String[], int, int, int)
    */
+  @Override
   public void copyFromArray(String[] src, int srcPos, int destPos, int length) {
     _casView.checkArrayBounds(theArray.length, destPos, length);
     for (int i = 0; i < length; i++) {
@@ -182,6 +192,7 @@
     set(i, Double.parseDouble(v));    
   }
   
+  @Override
   public Spliterator.OfDouble spliterator() {
     return Arrays.spliterator(theArray);
   }
@@ -224,10 +235,34 @@
    * @param a the source for the array's initial values
    * @return a newly created and populated array
    */
-  public static DoubleArray createFromArray(JCas jcas, double[] a) {
+  public static DoubleArray create(JCas jcas, double[] a) {
     DoubleArray doubleArray = new DoubleArray(jcas, a.length);
     doubleArray.copyFromArray(a, 0, 0, a.length);
     return doubleArray;
   }
 
+  /**
+   * non boxing version 
+   * @param action -
+   */
+  public void forEach(DoubleConsumer action) {
+    for (double d : theArray) {
+      action.accept(d);
+    }
+  }
+
+
+  /**
+   * @param item the item to see if is in the array
+   * @return true if the item is in the array
+   */
+  public boolean contains(double item) {
+    for (double b : theArray) {
+      if (b == item) {
+        return true;
+      }
+    }
+    return false;
+  }
+
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/EmptyFSList.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/EmptyFSList.java
index 6156ff1..5706567 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/EmptyFSList.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/EmptyFSList.java
@@ -19,16 +19,17 @@
 
 package org.apache.uima.jcas.cas;
 
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeImpl_list;
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 
-public class EmptyFSList extends FSList implements EmptyList {
+public class EmptyFSList<T extends TOP> extends FSList<T> implements EmptyList {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.jcas.cas.EmptyFSList";
+  public final static String _TypeName = CAS.TYPE_NAME_EMPTY_FS_LIST;
   
   public final static int typeIndexID = JCasRegistry.register(EmptyFSList.class);
 
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/EmptyFloatList.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/EmptyFloatList.java
index dd35763..dc62c7b 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/EmptyFloatList.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/EmptyFloatList.java
@@ -19,6 +19,7 @@
 
 package org.apache.uima.jcas.cas;
 
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeImpl_list;
@@ -28,7 +29,7 @@
 public class EmptyFloatList extends FloatList implements EmptyList {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.jcas.cas.EmptyFloatList";
+  public final static String _TypeName = CAS.TYPE_NAME_EMPTY_FLOAT_LIST;
 
   public final static int typeIndexID = JCasRegistry.register(EmptyFloatList.class);
 
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/EmptyIntegerList.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/EmptyIntegerList.java
index 78d6bd7..928b35a 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/EmptyIntegerList.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/EmptyIntegerList.java
@@ -19,6 +19,7 @@
 
 package org.apache.uima.jcas.cas;
 
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeImpl_list;
@@ -28,7 +29,7 @@
 public class EmptyIntegerList extends IntegerList implements EmptyList {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.jcas.cas.EmptyIntegerList";
+  public final static String _TypeName = CAS.TYPE_NAME_EMPTY_INTEGER_LIST;
 
   public final static int typeIndexID = JCasRegistry.register(EmptyIntegerList.class);
 
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/EmptyStringList.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/EmptyStringList.java
index c673b26..3f4206f 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/EmptyStringList.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/EmptyStringList.java
@@ -19,6 +19,7 @@
 
 package org.apache.uima.jcas.cas;
 
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeImpl_list;
@@ -28,7 +29,7 @@
 public class EmptyStringList extends StringList implements EmptyList {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.jcas.cas.EmptyStringList";
+  public final static String _TypeName = CAS.TYPE_NAME_EMPTY_STRING_LIST;
 
   public final static int typeIndexID = JCasRegistry.register(EmptyStringList.class);
 
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSArray.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSArray.java
index ad5b83c..9b810a5 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSArray.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSArray.java
@@ -26,6 +26,7 @@
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASRuntimeException;
 import org.apache.uima.cas.CommonArrayFS;
 import org.apache.uima.cas.FeatureStructure;
@@ -34,11 +35,17 @@
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 
-/** Java Class model for Cas FSArray type */
-public final class FSArray extends TOP implements Iterable<TOP>, ArrayFSImpl, SelectViaCopyToArray {
+/** Java Class model for Cas FSArray type
+ *  extends FeatureStructure for backwards compatibility 
+ *  when using FSArray with no typing. 
+ */
+public final class FSArray<T extends FeatureStructure> extends TOP 
+                           implements ArrayFSImpl<T>,
+                                      Iterable<T>,                                      
+                                      SelectViaCopyToArray<T> {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.cas.jcas.FSArray";
+  public final static String _TypeName = CAS.TYPE_NAME_FS_ARRAY;
 
   /**
    * each cover class when loaded sets an index. used in the JCas typeArray to go from the cover
@@ -54,6 +61,7 @@
    * @return the type array index
    */
   // can't be factored - refs locally defined field
+  @Override
   public int getTypeIndexID() {
     return typeIndexID;
   }
@@ -79,8 +87,8 @@
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(length);
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2Size_arrays(length);
     }    
   }
   
@@ -99,29 +107,43 @@
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(length);
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2Size_arrays(length);
     }    
   }
 
 
   /** return the indexed value from the corresponding Cas FSArray as a Java Model object. */
-  public TOP get(int i) {
-    return _maybeGetPearFs(theArray[i]);
+  @Override
+  public <U extends TOP> U get(int i) {
+    return (U) _maybeGetPearFs(theArray[i]);
+  }
+  
+  // internal use
+  TOP get_without_PEAR_conversion(int i) {
+    return theArray[i];
   }
 
   /** updates the Cas, setting the indexed value with the corresponding Cas FeatureStructure. */
-  public void set(int i, FeatureStructure v) {
-    TOP vt = (TOP) v;
-    if (vt != null && _casView.getBaseCAS() != vt._casView.getBaseCAS()) {
+  @Override
+  public void set(int i, T av) {
+    TOP v = (TOP) av;
+    if (v != null && _casView.getBaseCAS() != v._casView.getBaseCAS()) {
       /** Feature Structure {0} belongs to CAS {1}, may not be set as the value of an array or list element in a different CAS {2}.*/
-      throw new CASRuntimeException(CASRuntimeException.FS_NOT_MEMBER_OF_CAS, vt, vt._casView, _casView);
+      throw new CASRuntimeException(CASRuntimeException.FS_NOT_MEMBER_OF_CAS, v, v._casView, _casView);
     }
-    theArray[i] = _maybeGetBaseForPearFs(vt);
+    theArray[i] = _maybeGetBaseForPearFs(v);
+    _casView.maybeLogArrayUpdate(this, null, i);
+  }
+  
+  // internal use
+  void set_without_PEAR_conversion(int i, TOP v) {
+    theArray[i] = v;
     _casView.maybeLogArrayUpdate(this, null, i);
   }
 
   /** return the size of the array. */
+  @Override
   public int size() {
     return theArray.length;
   }
@@ -129,7 +151,8 @@
   /**
    * @see org.apache.uima.cas.ArrayFS#copyFromArray(FeatureStructure[], int, int, int)
    */
-  public void copyFromArray(FeatureStructure[] src, int srcPos, int destPos, int length) {
+  @Override
+  public <U extends FeatureStructure> void copyFromArray(U[] src, int srcPos, int destPos, int length) {
     int srcEnd = srcPos + length;
     int destEnd = destPos + length;
     if (srcPos < 0 ||
@@ -142,14 +165,15 @@
     // doing this element by element to get pear conversions done if needed, and 
     // to get journaling done
     for (;srcPos < srcEnd && destPos < destEnd;) {
-      set(destPos++, src[srcPos++]);
+      set(destPos++, (T) src[srcPos++]);
     }
   }
 
   /**
    * @see org.apache.uima.cas.ArrayFS#copyToArray(int, FeatureStructure[], int, int)
    */
-  public void copyToArray(int srcPos, FeatureStructure[] dest, int destPos, int length) {
+  @Override
+  public <U extends FeatureStructure> void copyToArray(int srcPos, U[] dest, int destPos, int length) {
     int srcEnd = srcPos + length;
     int destEnd = destPos + length;
     if (srcPos < 0 ||
@@ -159,24 +183,27 @@
           String.format("FSArray.copyToArray, srcPos: %,d destPos: %,d length: %,d",  srcPos, destPos, length));
     }
     for (;srcPos < srcEnd && destPos < destEnd;) {
-      dest[destPos++] = _maybeGetPearFs(get(srcPos++));
+      dest[destPos++] = (U) _maybeGetPearFs(get(srcPos++));
     }
   }
 
   /**
    * @see org.apache.uima.cas.ArrayFS#toArray()
    */
+  @Override
   public FeatureStructure[] toArray() {
     FeatureStructure[] r = new FeatureStructure[size()];
     copyToArray(0, r, 0, size());
     return r;
   }
   
+  @Override
   public FeatureStructure[] _toArrayForSelect() { return toArray(); }
 
   /**
    * Not supported, will throw UnsupportedOperationException
    */
+  @Override
   public void copyFromArray(String[] src, int srcPos, int destPos, int length) {
     throw new UnsupportedOperationException();
   }
@@ -198,6 +225,7 @@
    *                    <code>length &gt; size()</code> or
    *                    <code>destPos + length &gt; destArray.length</code>.
    */
+  @Override
   public void copyToArray(int srcPos, String[] dest, int destPos, int length) {
     _casView.checkArrayBounds(theArray.length, srcPos, length);
     for (int i = 0; i < length; i++) {
@@ -218,8 +246,8 @@
    * no conversion to Pear trampolines done
    */
   @Override
-  public void copyValuesFrom(CommonArrayFS v) {
-    FSArray bv = (FSArray) v;
+  public void copyValuesFrom(CommonArrayFS<T> v) {
+    FSArray<T> bv = (FSArray<T>) v;
     System.arraycopy(bv.theArray,  0,  theArray, 0, theArray.length);
     _casView.maybeLogArrayUpdates(this, 0, size());
   }
@@ -228,17 +256,18 @@
    * Convenience - create a FSArray from an existing FeatureStructure[]
    * @param jcas -
    * @param a -
+   * @param <U> the element type of the FSArray, subtype of FeatureStructure
    * @return -
    */
-  public static FSArray create(JCas jcas, FeatureStructure[] a) {
-    FSArray fsa = new FSArray(jcas, a.length);
+  public static <U extends FeatureStructure> FSArray<U> create(JCas jcas, FeatureStructure[] a) {
+    FSArray<U> fsa = new FSArray<U>(jcas, a.length);
     fsa.copyFromArray(a, 0, 0, a.length);
     return fsa;
   }
 
   @Override
-  public Iterator<TOP> iterator() {
-    return new Iterator<TOP>() {
+  public Iterator<T> iterator() {
+    return new Iterator<T>() {
       int i = 0;
       
       @Override
@@ -247,21 +276,54 @@
       }
 
       @Override
-      public TOP next() {
+      public T next() {
         if (!hasNext()) {
           throw new NoSuchElementException();
         }
-        return get(i++);  // does trampoline conversion
+        return (T) get(i++);  // does trampoline conversion
       }
     };
   }
   
   @Override
-  public Spliterator<TOP> spliterator() {
-    return Arrays.spliterator(theArray);
+  public Spliterator<T> spliterator() {
+    return (Spliterator<T>) Arrays.spliterator(theArray);
   }
   
-  public <T extends TOP> Stream<T> stream() {
-    return (Stream<T>) StreamSupport.stream(spliterator(), false);
+  public Stream<T> stream() {
+    return StreamSupport.stream(spliterator(), false);
   }
+
+  public boolean contains(Object o) {
+    if (null == o) {
+      for (TOP e : theArray) {
+        if (e == null) {
+          return true;
+        }
+      }
+      return false;
+    }
+    
+    if (!(o instanceof TOP)) {
+      return false;
+    }
+    TOP item = (TOP) o;
+    for (TOP e : theArray) {
+      if (item.equals(e)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public <U extends TOP> U[] toArray(U[] a) {
+    final int sz = size();
+    if (a.length < sz) {
+      return (U[]) Arrays.copyOf(theArray, sz, a.getClass());
+    }
+    System.arraycopy(theArray, 0, a, 0, size());
+    return a;
+  }
+
+ 
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSArrayList.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSArrayList.java
index 5150d07..b592656 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSArrayList.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSArrayList.java
@@ -21,6 +21,8 @@
 
 package org.apache.uima.jcas.cas;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
 import java.util.AbstractList;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -35,6 +37,7 @@
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.function.UnaryOperator;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import org.apache.uima.UimaSerializableFSs;
@@ -47,9 +50,6 @@
 import org.apache.uima.cas.impl.TypeSystemImpl;
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
-import org.apache.uima.jcas.cas.FSArray;
-import org.apache.uima.jcas.cas.SelectViaCopyToArray;
-import org.apache.uima.jcas.cas.TOP;
 import org.apache.uima.util.impl.Constants;
 
 
@@ -75,13 +75,16 @@
  *       
  *     <li>This enables operation without creating the Java Object in use cases of deserializing and
  *     referencing when updating is not being used.
+ *     
+ *     <li>The values stored internally are non-PEAR ones.
+ *     <li>The get/set/add operations convert to/from PEAR ones as needed
  *   </ul>
  *
  * @param <T> the generic type
  */
 
 public class FSArrayList <T extends TOP> extends TOP implements 
-                         UimaSerializableFSs, CommonArrayFS, SelectViaCopyToArray, 
+                         UimaSerializableFSs, CommonArrayFS<T>, SelectViaCopyToArray<T>, 
                          List<T>, RandomAccess, Cloneable {
  
   /** The Constant EMPTY_LIST. */
@@ -91,7 +94,7 @@
    * @ordered 
    */
   @SuppressWarnings ("hiding")
-  public final static String _TypeName = "org.apache.uima.jcas.type.FSArrayList";
+  public final static String _TypeName = "org.apache.uima.jcas.cas.FSArrayList";
   
   /** @generated
    * @ordered 
@@ -110,11 +113,11 @@
   public              int getTypeIndexID() {return typeIndexID;}
  
   /** lifecycle   - starts as empty array list   - becomes non-empty when updated (add)       -- used from that point on. */
-  private final List<T> fsArrayList;
+  private final ArrayList<T> fsArrayList;
   
   /** lifecycle   - starts as the empty list   - set when _init_from_cas_data()   - set to null when update (add/remove) happens. */
   @SuppressWarnings("unchecked")
-  private List<T> fsArrayAsList = (List<T>) EMPTY_LIST;
+  private List<T> fsArray_asList = (List<T>) EMPTY_LIST;
 
   /* *******************
    *   Feature Offsets *
@@ -124,7 +127,9 @@
 
 
   /* Feature Adjusted Offsets */
-  public final static int _FI_fsArray = TypeSystemImpl.getAdjustedFeatureOffset("fsArray");
+//  public final static int _FI_fsArray = TypeSystemImpl.getAdjustedFeatureOffset("fsArray");
+  private final static CallSite _FC_fsArray = TypeSystemImpl.createCallSite(FSArrayList.class, "fsArray");
+  private final static MethodHandle _FH_fsArray = _FC_fsArray.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -183,24 +188,24 @@
    * @generated
    * @return value of the feature 
    */
-  private FSArray getFsArray() { return (FSArray)(_getFeatureValueNc(_FI_fsArray));}
+  private FSArray getFsArray() { return (FSArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_fsArray)));}
     
   /** setter for fsArray - sets internal use - holds the contents 
    * @generated
    * @param v value to set into the feature 
    */
   private void setFsArray(FSArray v) {
-    _setFeatureValueNcWj(_FI_fsArray, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_fsArray), v);
   }    
     
   /**
    * Maybe start using array list.
    */
   private void maybeStartUsingArrayList() {
-    if (fsArrayAsList != null) {
+    if (fsArray_asList != null) {
       fsArrayList.clear();
-      fsArrayList.addAll(fsArrayAsList);
-      fsArrayAsList = null;  // stop using this one
+      fsArrayList.addAll(fsArray_asList);
+      fsArray_asList = null;  // stop using this one
     }
   }
     
@@ -212,20 +217,30 @@
     // special handling to have getter and setter honor pear trampolines
     final FSArray fsa = getFsArray();
     if (null == fsa) {
-      fsArrayAsList = Collections.emptyList();
+      fsArray_asList = Collections.emptyList();
     } else {
     
-      fsArrayAsList = new AbstractList<T>() {
+      fsArray_asList = new AbstractList<T>() {
         int i = 0;
         @Override
-        public T get(int index) {
-          return (T) fsa.get(i);
+        public T get(int index) {  
+          return (T) fsa.get_without_PEAR_conversion(i); 
         }
   
         @Override
         public int size() {
           return fsa.size();
-        }      
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.AbstractList#set(int, java.lang.Object)
+         */
+        @Override
+        public T set(int index, T element) {
+          T prev = get(index);
+          fsa.set_without_PEAR_conversion(index, element);
+          return prev;
+        } 
       };
     }
   }
@@ -236,7 +251,7 @@
   @Override
   public void _save_to_cas_data() {
     // if fsArraysAsList is not null, then the cas data form is still valid, do nothing
-    if (null != fsArrayAsList) {
+    if (null != fsArray_asList) {
       return;
     }
     
@@ -247,36 +262,382 @@
       setFsArray(fsa = new FSArray(_casView.getJCasImpl(), sz));
     }
     
-    // using element by element instead of bulk operations to
-    //   pick up any pear trampoline conversion and 
     //   in case fsa was preallocated and right size, may need journaling
     int i = 0;
-    for (TOP fs : fsArrayList) {
-      TOP currentValue = fsa.get(i);
+    for (TOP fs : fsArrayList) {  // getting non-PEAR values
+      TOP currentValue = fsa.get_without_PEAR_conversion(i);  
       if (currentValue != fs) {
-        fsa.set(i, fs); // done this way to record for journaling for delta CAS
+        fsa.set_without_PEAR_conversion(i, fs); // done this way to record for journaling for delta CAS
       }
       i++;
     }
   }
   
   /**
-   * Gl.
-   *
+   * gets either the array list object, or a list operating over the original FS Array.
+   * Note: these forms will get/set the non Pear form of elements
    * @return the list
    */
   private List<T> gl () {
-    return (null == fsArrayAsList) 
+    return (null == fsArray_asList) 
       ? fsArrayList
-      : fsArrayAsList;
+      : fsArray_asList;
   }
   
+  /**
+   * Supports reading only, no update or remove 
+   * @return a list backed by gl(), where the items are pear converted
+   */
+  private List<T> gl_read_pear(List<T> baseItems) {
+    
+    return new List<T>() {
+      /*
+       * @see java.lang.Iterable#forEach(java.util.function.Consumer)
+       */
+      public void forEach(Consumer<? super T> action) {
+        baseItems.forEach(item -> {
+            T pearedItem = _maybeGetPearFs((T) item);
+            action.accept(pearedItem);
+        });
+      }
+
+      /*
+       * @see java.util.List#size()
+       */
+      public int size() {
+        return baseItems.size();
+      }
+
+      /*
+       * @see java.util.List#isEmpty()
+       */
+      public boolean isEmpty() {
+        return baseItems.isEmpty();
+      }
+
+      /*
+       * @see java.util.List#contains(java.lang.Object)
+       */
+      public boolean contains(Object o) {
+        return (o instanceof TOP) 
+                 ? baseItems.contains(_maybeGetBaseForPearFs((TOP)o))
+                 : false;
+      }
+
+      /*
+       * @see java.util.List#iterator()
+       */
+      public Iterator<T> iterator() {
+        return new Iterator<T>() {
+          
+          Iterator<T> outerIt = baseItems.iterator();
+
+          /*
+           * @see java.util.Iterator#hasNext()
+           */
+          public boolean hasNext() {
+            return outerIt.hasNext();
+          }
+
+          /*
+           * @see java.util.Iterator#next()
+           */
+          public T next() {
+            return _maybeGetPearFs(outerIt.next());
+          }
+
+        };
+      }
+
+      /*
+       * @see java.util.List#toArray()
+       */
+      public Object[] toArray() {
+        Object[] a = baseItems.toArray();
+        FSArrayList.this._casView.swapInPearVersion(a);
+        return a;
+      }
+      
+      /*
+       * @see java.util.List#toArray(java.lang.Object[])
+       */
+      public <U> U[] toArray(U[] a) {
+        U[] aa = baseItems.toArray(a);
+        FSArrayList.this._casView.swapInPearVersion(aa);
+        return aa;    
+      }
+
+      /*
+       * @see java.util.List#add(java.lang.Object)
+       */
+      public boolean add(T e) {
+        throw new UnsupportedOperationException();
+     }
+
+      /*
+       * @see java.util.List#remove(java.lang.Object)
+       */
+      public boolean remove(Object o) {
+        throw new UnsupportedOperationException();
+      }
+
+      /*
+       * @see java.util.List#containsAll(java.util.Collection)
+       */
+      public boolean containsAll(Collection<?> c) {
+        for (Object item : c) {
+          if (!contains(item)) {
+            return false;
+          }
+        }
+        return true;
+      }
+
+      /*
+       * @see java.util.List#addAll(java.util.Collection)
+       */
+      public boolean addAll(Collection<? extends T> c) {
+        throw new UnsupportedOperationException();
+      }
+
+      /*
+       * @see java.util.List#addAll(int, java.util.Collection)
+       */
+      public boolean addAll(int index, Collection<? extends T> c) {
+        throw new UnsupportedOperationException();
+      }
+
+      /*
+       * @see java.util.List#removeAll(java.util.Collection)
+       */
+      public boolean removeAll(Collection<?> c) {
+        throw new UnsupportedOperationException();
+      }
+
+      /*
+       * @see java.util.List#retainAll(java.util.Collection)
+       */
+      public boolean retainAll(Collection<?> c) {
+        throw new UnsupportedOperationException();
+      }
+
+      /*
+       * @see java.util.List#replaceAll(java.util.function.UnaryOperator)
+       */
+      public void replaceAll(UnaryOperator<T> operator) {
+        for (int i = size() - 1; i >= 0; i--) {
+          baseItems.set(i, _maybeGetBaseForPearFs(
+              operator.apply(_maybeGetPearFs(baseItems.get(i)))));
+        }
+      }
+
+      /*
+       * @see java.util.Collection#removeIf(java.util.function.Predicate)
+       */
+      public boolean removeIf(Predicate<? super T> filter) {
+        throw new UnsupportedOperationException();
+      }
+
+      /*
+       * @see java.util.List#sort(java.util.Comparator)
+       */
+      public void sort(Comparator<? super T> c) {
+        baseItems.sort((o1, o2) -> c.compare(_maybeGetPearFs(o1), _maybeGetPearFs(o2))); 
+      }
+
+      /*
+       * @see java.util.List#clear()
+       */
+      public void clear() {
+        throw new UnsupportedOperationException();
+      }
+
+      /*
+       * @see java.util.List#equals(java.lang.Object)
+       */
+      public boolean equals(Object o) {
+        return baseItems.equals(o);
+      }
+
+      /*
+       * @see java.util.List#hashCode()
+       */
+      public int hashCode() {
+        return baseItems.hashCode();
+      }
+
+      /*
+       * @see java.util.List#get(int)
+       */
+      public T get(int index) {
+        return _maybeGetPearFs(baseItems.get(index));
+      }
+
+      /*
+       * @see java.util.List#set(int, java.lang.Object)
+       */
+      public T set(int index, T element) {
+        return baseItems.set(index, _maybeGetBaseForPearFs(element));
+      }
+
+      /*
+       * @see java.util.List#add(int, java.lang.Object)
+       */
+      public void add(int index, T element) {
+        throw new UnsupportedOperationException();
+      }
+
+      /*
+       * @see java.util.Collection#stream()
+       */
+      public Stream<T> stream() {
+        return baseItems.stream().map(item -> _maybeGetPearFs(item));
+      }
+
+      /*
+       * @see java.util.List#remove(int)
+       */
+      public T remove(int index) {
+        throw new UnsupportedOperationException();
+      }
+
+      /*
+       * @see java.util.Collection#parallelStream()
+       */
+      public Stream<T> parallelStream() {
+        return baseItems.parallelStream().map(item -> _maybeGetPearFs(item));
+      }
+
+      /*
+       * @see java.util.List#indexOf(java.lang.Object)
+       */
+      public int indexOf(Object o) {
+        return baseItems.indexOf((o instanceof TOP) ? _maybeGetBaseForPearFs((TOP)o) : o);
+      }
+
+      /*
+       * @see java.util.List#lastIndexOf(java.lang.Object)
+       */
+      public int lastIndexOf(Object o) {
+        return baseItems.lastIndexOf((o instanceof TOP) ? _maybeGetBaseForPearFs((TOP)o) : o);
+      }
+
+      /*
+       * @see java.util.List#listIterator()
+       */
+      public ListIterator<T> listIterator() {
+        return listIterator(0);
+      }
+
+      /*
+       * @see java.util.List#listIterator(int)
+       */
+      public ListIterator<T> listIterator(int index) {
+        return new ListIterator<T>() {
+          
+          ListIterator<T> baseIt = baseItems.listIterator(index);
+          
+          /*
+           * @see java.util.ListIterator#hasNext()
+           */
+          public boolean hasNext() {
+            return baseIt.hasNext();
+          }
+
+          /**
+           * @return
+           * @see java.util.ListIterator#next()
+           */
+          public T next() {
+            return _maybeGetPearFs(baseIt.next());
+          }
+
+          /*
+           * @see java.util.ListIterator#hasPrevious()
+           */
+          public boolean hasPrevious() {
+            return baseIt.hasPrevious();
+          }
+
+          /*
+           * @see java.util.Iterator#forEachRemaining(java.util.function.Consumer)
+           */
+          public void forEachRemaining(Consumer<? super T> action) {
+            baseIt.forEachRemaining(item -> action.accept(_maybeGetPearFs(item)));
+          }
+
+          /**
+           * @return
+           * @see java.util.ListIterator#previous()
+           */
+          public T previous() {
+            return baseIt.previous();
+          }
+
+          /**
+           * @return
+           * @see java.util.ListIterator#nextIndex()
+           */
+          public int nextIndex() {
+            return baseIt.nextIndex();
+          }
+
+          /**
+           * @return
+           * @see java.util.ListIterator#previousIndex()
+           */
+          public int previousIndex() {
+            return baseIt.previousIndex();
+          }
+
+          /**
+           * 
+           * @see java.util.ListIterator#remove()
+           */
+          public void remove() {
+            throw new UnsupportedOperationException();
+          }
+
+          /**
+           * @param e
+           * @see java.util.ListIterator#set(java.lang.Object)
+           */
+          public void set(T e) {
+            baseIt.set(_maybeGetBaseForPearFs(e));
+          }
+
+          /**
+           * @param e
+           * @see java.util.ListIterator#add(java.lang.Object)
+           */
+          public void add(T e) {
+            throw new UnsupportedOperationException();
+          }
+        };
+      }
+
+      /*
+       * @see java.util.List#subList(int, int)
+       */
+      public List<T> subList(int fromIndex, int toIndex) {
+        return gl_read_pear(baseItems.subList(fromIndex, toIndex));
+      }
+
+      /*
+       * @see java.util.List#spliterator()
+       */
+      @Override
+      public Spliterator<T> spliterator() {
+        return FSArrayList.this._casView.makePearAware(baseItems.spliterator());
+      }
+    };
+  }
   /* (non-Javadoc)
    * @see java.util.List#get(int)
    */
   @Override
   public T get(int i) {
-    return gl().get(i);
+    return _maybeGetPearFs(gl().get(i));
   }
 
   /**
@@ -293,7 +654,7 @@
       /** Feature Structure {0} belongs to CAS {1}, may not be set as the value of an array or list element in a different CAS {2}.*/
       throw new CASRuntimeException(CASRuntimeException.FS_NOT_MEMBER_OF_CAS, v, v._casView, _casView);
     }
-    return gl().set(i, v);
+    return _maybeGetPearFs(gl().set(i,  _maybeGetBaseForPearFs(v)));
   }
   
   /**
@@ -313,9 +674,10 @@
    * @param srcPos -
    * @param destPos -
    * @param length -
+   * @param <E> the type of the source array being copied from
    * @see org.apache.uima.cas.ArrayFS#copyFromArray(FeatureStructure[], int, int, int)
    */
-  public void copyFromArray(T[] src, int srcPos, int destPos, int length) {
+  public <E extends FeatureStructure> void copyFromArray(E[] src, int srcPos, int destPos, int length) {
     int srcEnd = srcPos + length;
     int destEnd = destPos + length;
     if (srcPos < 0 ||
@@ -325,7 +687,7 @@
           String.format("FSArrayList.copyFromArray, srcPos: %,d destPos: %,d length: %,d",  srcPos, destPos, length));
     }
     for (;srcPos < srcEnd && destPos < destEnd;) {
-      set(destPos++, src[srcPos++]);
+      set(destPos++, (T) src[srcPos++]);
     }
   }
 
@@ -336,9 +698,10 @@
    * @param dest -
    * @param destPos -
    * @param length -
+   * @param <E> the type of the elements of the Array being copied into
    * @see org.apache.uima.cas.ArrayFS#copyToArray(int, FeatureStructure[], int, int)
    */
-  public void copyToArray(int srcPos, FeatureStructure[] dest, int destPos, int length) {
+  public <E extends FeatureStructure> void copyToArray(int srcPos, E[] dest, int destPos, int length) {
     int srcEnd = srcPos + length;
     int destEnd = destPos + length;
     if (srcPos < 0 ||
@@ -348,19 +711,17 @@
           String.format("FSArrayList.copyToArray, srcPos: %,d destPos: %,d length: %,d",  srcPos, destPos, length));
     }
     for (;srcPos < srcEnd && destPos < destEnd;) {
-      dest[destPos++] = get(srcPos++);
+      dest[destPos++] = (E) get(srcPos++);
     }
   }
 
   /**
-   * Note: doesn't convert to pear trampolines!.
-   *
-   * @return the feature structure[]
-   * @see org.apache.uima.cas.ArrayFS#toArray()
+   * returns TOP[] because can't make array of T
+   * Note: converts to pear trampolines.
    */
   @Override
-  public T[] toArray() {
-    T[] r = (T[]) new TOP[size()];
+  public TOP[] toArray() {
+    TOP[] r = new TOP[size()];
     copyToArray(0, r, 0, size());
     return r;
   }
@@ -386,7 +747,8 @@
     
   /**
    * Copies an array of Feature Structures to an Array of Strings.
-   * The strings are the "toString()" representation of the feature structures, 
+   * The strings are the "toString()" representation of the feature structures.
+   * If in Pear context, the Pear form is used. 
    * 
    * @param srcPos
    *                The index of the first element to copy.
@@ -415,7 +777,8 @@
    * 
    * (non-Javadoc)
    * @see org.apache.uima.jcas.cas.CommonArray#copyValuesFrom(org.apache.uima.jcas.cas.CommonArray)
-   * no conversion to Pear trampolines done
+   * The spliterators return PEAR objects, potentially.  The add operation expects PEAR objects,
+   * and converts them to base when storing.
    */
   @Override
   public void copyValuesFrom(CommonArrayFS v) {
@@ -433,15 +796,16 @@
   }
   
   /**
-   * Convenience - create a FSArrayList from an existing FeatureStructure[].
+   * Convenience - create a FSArrayList from an existing Array.
    *
-   * @param <N> generic type of returned FS
+   * @param <E> generic type of returned FS
+   * @param <F> generic type of the elements of the array argument
    * @param jcas -
    * @param a -
    * @return -
    */
-  public static <N extends TOP> FSArrayList<N> create(JCas jcas, N[] a) {
-    FSArrayList<N> fsa = new FSArrayList<>(jcas, a.length);
+  public static <E extends TOP, F extends FeatureStructure> FSArrayList<E> create(JCas jcas, F[] a) {
+    FSArrayList<E> fsa = new FSArrayList<E>(jcas, a.length);
     fsa.copyFromArray(a, 0, 0, a.length);  // does pear and journaling actions as needed
     return fsa;
   }
@@ -452,22 +816,15 @@
   @Override
   public FeatureStructureImplC _superClone() {return clone();}  // enable common clone
   
-  /**
-   * Contains all.
-   *
-   * @param c -
-   * @return -
+  /*
    * @see java.util.AbstractCollection#containsAll(java.util.Collection)
    */
   @Override
   public boolean containsAll(Collection<?> c) {
-    return gl().containsAll(c);
+    return gl_read_pear(gl()).containsAll(c);
   }
 
-  /**
-   * Checks if is empty.
-   *
-   * @return -
+  /*
    * @see java.util.ArrayList#isEmpty()
    */
   @Override
@@ -475,59 +832,42 @@
     return gl().isEmpty();
   }
 
-  /**
-   * Contains.
-   *
-   * @param o -
-   * @return -
+  /*
    * @see java.util.ArrayList#contains(java.lang.Object)
    */
   @Override
   public boolean contains(Object o) {
     if (!(o instanceof TOP)) return false;
     TOP fs = (TOP) o;    
-    return gl().contains(fs);
+    return gl().contains(_maybeGetBaseForPearFs(fs));
   }
 
-  /**
-   * Index of.
-   *
-   * @param o -
-   * @return -
+  /*
    * @see java.util.ArrayList#indexOf(java.lang.Object)
    */
   @Override
   public int indexOf(Object o) {
     if (!(o instanceof TOP)) return -1;
     TOP fs = (TOP) o;    
-    return gl().indexOf(fs);
+    return gl().indexOf(_maybeGetBaseForPearFs(fs));
   }
 
-  /**
-   * Last index of.
-   *
-   * @param o -
-   * @return -
+  /*
    * @see java.util.ArrayList#lastIndexOf(java.lang.Object)
    */
   @Override
   public int lastIndexOf(Object o) {
     if (!(o instanceof TOP)) return -1;
     TOP fs = (TOP) o;    
-    return gl().lastIndexOf(fs);
+    return gl().lastIndexOf(_maybeGetBaseForPearFs(fs));
   }
 
-  /**
-   * To array.
-   *
-   * @param <U> the generic type
-   * @param a -
-   * @return -
+  /*
    * @see java.util.ArrayList#toArray(java.lang.Object[])
    */
   @Override
-  public <U> U[] toArray(U[] a) {
-    return gl().toArray(a);
+  public <U> U[] toArray(U[] a) {    
+    return gl_read_pear(gl()).toArray(a);
   }
 
 
@@ -542,29 +882,21 @@
         + ", fsArrayList="
         + (fsArrayList != null ? fsArrayList.subList(0, Math.min(fsArrayList.size(), maxLen))
             : null)
-        + ", fsArrayAsList=" + (fsArrayAsList != null
-            ? fsArrayAsList.subList(0, Math.min(fsArrayAsList.size(), maxLen)) : null)
+        + ", fsArray_asList=" + (fsArray_asList != null
+            ? fsArray_asList.subList(0, Math.min(fsArray_asList.size(), maxLen)) : null)
         + "]";
   }
 
-  /**
-   * Adds the.
-   *
-   * @param e -
-   * @return -
+  /*
    * @see java.util.ArrayList#add(java.lang.Object)
    */
   @Override
   public boolean add(T e) {
     maybeStartUsingArrayList();
-    return fsArrayList.add(e);
+    return fsArrayList.add(_maybeGetBaseForPearFs(e));
   }
 
-  /**
-   * equals means equal items, same order.
-   *
-   * @param o -
-   * @return -
+  /*
    * @see java.util.AbstractList#equals(java.lang.Object)
    */
   @Override
@@ -573,31 +905,26 @@
     FSArrayList<T> other = (FSArrayList<T>) o;
     if (size() != other.size()) return false;
     
-    Iterator<T> it_other = other.iterator();
-    for (T item : this) {
+    List<T> items = gl();  // non-pear form
+    List<T> other_items = other.gl(); // non-pear form
+    
+    Iterator<T> it_other = other_items.iterator();
+    for (T item : items) {
       if (!item.equals(it_other.next())) return false;
     }
     return true;
   }
 
-  /**
-   * Adds the.
-   *
-   * @param index -
-   * @param element -
+  /*
    * @see java.util.ArrayList#add(int, java.lang.Object)
    */
   @Override
   public void add(int index, T element) {
     maybeStartUsingArrayList();
-    fsArrayList.add(index, element);
+    fsArrayList.add(index, _maybeGetBaseForPearFs(element));
   }
 
-  /**
-   * Removes the.
-   *
-   * @param index -
-   * @return -
+  /*
    * @see java.util.ArrayList#remove(int)
    */
   @Override
@@ -606,38 +933,34 @@
     return fsArrayList.remove(index);
   }
 
-  /**
-   * Removes the.
-   *
-   * @param o -
-   * @return -
+  /*
    * @see java.util.ArrayList#remove(java.lang.Object)
    */
   @Override
   public boolean remove(Object o) {
     maybeStartUsingArrayList();
-    return fsArrayList.remove(o);
+    if (!(o instanceof TOP)) {
+      return false;
+    }
+    return fsArrayList.remove(_maybeGetBaseForPearFs((TOP) o));
   }
 
-  /**
+  /*
    * want hashcode to depend only on equal items, regardless of what format.
    *
-   * @return -
    * @see java.util.AbstractList#hashCode()
    */
   @Override
   public int hashCode() {
     int hc = 1;
     final int prime = 31;
-    for (T item : this) {
+    for (T item : gl()) {  // non pear form
       hc = hc * prime + item.hashCode();
     }
     return hc;
   }
 
-  /**
-   * Clear.
-   *
+  /*
    * @see java.util.ArrayList#clear()
    */
   @Override
@@ -646,186 +969,148 @@
     fsArrayList.clear();
   }
 
-  /**
-   * Adds the all.
-   *
-   * @param c -
-   * @return -
+  /*
    * @see java.util.ArrayList#addAll(java.util.Collection)
    */
   @Override
   public boolean addAll(Collection<? extends T> c) {
-    maybeStartUsingArrayList();
-    return fsArrayList.addAll(c);
+    return addAll(size(), c);
   }
 
-  /**
-   * Adds the all.
-   *
-   * @param index -
-   * @param c -
-   * @return -
+  /*
    * @see java.util.ArrayList#addAll(int, java.util.Collection)
    */
   @Override
   public boolean addAll(int index, Collection<? extends T> c) {
+    if (c.size() == 0) {
+      return false;
+    }
     maybeStartUsingArrayList();
-    return fsArrayList.addAll(index, c);
+//    return fsArrayList.addAll(index, c); // doesn't do pear conversion
+    fsArrayList.ensureCapacity(fsArrayList.size() + c.size());
+    List<T> baseItems = c.stream().map(item -> 
+        _maybeGetBaseForPearFs(item)).collect(Collectors.toList());
+    fsArrayList.addAll(index, baseItems); 
+    return true;
   }
 
-  /**
-   * Removes the all.
-   *
-   * @param c -
-   * @return -
+  /*
    * @see java.util.ArrayList#removeAll(java.util.Collection)
    */
   @Override
   public boolean removeAll(Collection<?> c) {
+    boolean changed = false;
     maybeStartUsingArrayList();
-    return fsArrayList.removeAll(c);
+//    return fsArrayList.removeAll(c); // doesn't do pear conversion
+    for (Object item : c) {
+      if (!(item instanceof TOP)) {
+        continue;
+      }
+                // order important! 
+      changed = fsArrayList.remove(_maybeGetBaseForPearFs((TOP)item)) || changed;
+    }
+    return changed;
   }
 
-  /**
-   * Retain all.
-   *
-   * @param c -
-   * @return -
+  /*
    * @see java.util.ArrayList#retainAll(java.util.Collection)
    */
   @Override
   public boolean retainAll(Collection<?> c) {
-    maybeStartUsingArrayList();
-    return fsArrayList.retainAll(c);
+    Collection<?> cc = _casView.collectNonPearVersions(c);
+    maybeStartUsingArrayList();    
+    return fsArrayList.retainAll(cc);
   }
 
-  /**
-   * Stream.
-   *
-   * @return -
+  /*
    * @see java.util.Collection#stream()
    */
   @Override
   public Stream<T> stream() {
-    return gl().stream();
+    return gl().stream().map(item -> _maybeGetPearFs(item));
   }
 
-  /**
-   * Parallel stream.
-   *
-   * @return -
+  /*
    * @see java.util.Collection#parallelStream()
    */
   @Override
   public Stream<T> parallelStream() {
-    return gl().parallelStream();
+    return gl().parallelStream().map(item -> _maybeGetPearFs(item));
   }
 
-  /**
-   * List iterator.
-   *
-   * @param index -
-   * @return -
+  /*
    * @see java.util.ArrayList#listIterator(int)
    */
   @Override
   public ListIterator<T> listIterator(int index) {
-    return gl().listIterator(index);
+    return gl_read_pear(gl()).listIterator(index);
   }
 
-  /**
-   * List iterator.
-   *
-   * @return -
+  /*
    * @see java.util.ArrayList#listIterator()
    */
   @Override
   public ListIterator<T> listIterator() {
-    return gl().listIterator();
+    return listIterator(0);
   }
 
-  /**
-   * Iterator.
-   *
-   * @return -
+  /*
    * @see java.util.ArrayList#iterator()
    */
   @Override
   public Iterator<T> iterator() {
-    return gl().iterator();
+    return gl_read_pear(gl()).iterator();
   }
 
-  /**
-   * Sub list.
-   *
-   * @param fromIndex -
-   * @param toIndex -
-   * @return -
+  /*
    * @see java.util.ArrayList#subList(int, int)
    */
   @Override
   public List<T> subList(int fromIndex, int toIndex) {
-    return gl().subList(fromIndex, toIndex);
+    return gl_read_pear(gl().subList(fromIndex, toIndex));
   }
 
-  /**
-   * For each.
-   *
-   * @param action -
+  /*
    * @see java.util.ArrayList#forEach(java.util.function.Consumer)
    */
   @Override
   public void forEach(Consumer<? super T> action) {
-    gl().forEach(action);
+    gl_read_pear(gl()).forEach(action);
   }
 
-  /**
-   * Spliterator.
-   *
-   * @return -
+  /*
    * @see java.util.ArrayList#spliterator()
    */
   @Override
   public Spliterator<T> spliterator() {
-    return gl().spliterator();
+    return gl_read_pear(gl()).spliterator();
   }
 
-  /**
-   * Removes the if.
-   *
-   * @param filter -
-   * @return -
+  /*
    * @see java.util.ArrayList#removeIf(java.util.function.Predicate)
    */
   @Override
   public boolean removeIf(Predicate<? super T> filter) {
     maybeStartUsingArrayList();
-    return fsArrayList.removeIf(filter);
+    return fsArrayList.removeIf(item -> filter.test(_maybeGetPearFs(item)));
   }
 
-  /**
-   * Replace all.
-   *
-   * @param operator -
-   * @see java.util.ArrayList#replaceAll(java.util.function.UnaryOperator)
+  /*
+   * @see java.util.List#replaceAll(java.util.function.UnaryOperator)
    */
   @Override
   public void replaceAll(UnaryOperator<T> operator) {
-    maybeStartUsingArrayList();
-    fsArrayList.replaceAll(operator);
+    gl_read_pear(gl()).replaceAll(operator);
   }
 
-  /**
-   * Sort.
-   *
-   * @param c -
+  /*
    * @see java.util.ArrayList#sort(java.util.Comparator)
    */
   @Override
   public void sort(Comparator<? super T> c) {
-    gl().sort(c);
+    gl_read_pear(gl()).sort(c);
   }
-    
+      
 }
 
     
\ No newline at end of file
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSHashSet.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSHashSet.java
index f6a416f..360aefd 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSHashSet.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSHashSet.java
@@ -21,7 +21,10 @@
 
 package org.apache.uima.jcas.cas;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
 import java.lang.reflect.Array;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -38,13 +41,11 @@
 import org.apache.uima.cas.impl.TypeSystemImpl;
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
-import org.apache.uima.jcas.cas.FSArray;
-import org.apache.uima.jcas.cas.SelectViaCopyToArray;
-import org.apache.uima.jcas.cas.TOP;
 import org.apache.uima.util.impl.Constants;
 
 
 /** a hash set of Feature Structures
+ * Is Pear aware - stores non-pear versions but may return pear version in pear contexts
  * Updated by JCasGen Fri Jan 20 11:55:59 EST 2017
  * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-types/src/main/descriptors/java_object_type_descriptors.xml
  * @generated */
@@ -56,7 +57,7 @@
    * @ordered 
    */
   @SuppressWarnings ("hiding")
-  public final static String _TypeName = "org.apache.uima.jcas.type.FSHashSet";
+  public final static String _TypeName = "org.apache.uima.jcas.cas.FSHashSet";
   
   /** @generated
    * @ordered 
@@ -92,7 +93,9 @@
 
 
   /* Feature Adjusted Offsets */
-  public final static int _FI_fsArray = TypeSystemImpl.getAdjustedFeatureOffset("fsArray");
+//  public final static int _FI_fsArray = TypeSystemImpl.getAdjustedFeatureOffset("fsArray");
+  private final static CallSite _FC_fsArray = TypeSystemImpl.createCallSite(FSHashSet.class, "fsArray");
+  private final static MethodHandle _FH_fsArray = _FC_fsArray.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -107,20 +110,28 @@
    * @param type the type of this Feature Structure 
    */
   public FSHashSet(TypeImpl type, CASImpl casImpl) {
+    this(new HashSet<>(), type, casImpl);
+  }
+  
+  public FSHashSet(HashSet<T> set, TypeImpl type, CASImpl casImpl) {
     super(type, casImpl);
-    fsHashSet = new HashSet<>();
+    fsHashSet = set;
 
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
-    }
+    }    
   }
   
   /** @generated
    * @param jcas JCas to which this Feature Structure belongs 
    */
   public FSHashSet(JCas jcas) {
+    this(new HashSet<>(), jcas);
+  } 
+
+  public FSHashSet(HashSet<T> set, JCas jcas) {
     super(jcas);
-    fsHashSet = new HashSet<>();
+    fsHashSet = set;
 
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
@@ -128,21 +139,25 @@
   } 
 
   /**
-   * Make a new ArrayList with an initial size .
+   * Make a new HashSet with an initial size .
    *
    * @param jcas The JCas
    * @param length initial size
    */
   public FSHashSet(JCas jcas, int length) {
+    this (new HashSet<>(length), jcas, length);
+  }
+    
+  public FSHashSet(HashSet<T> set, JCas jcas, int length) {
     super(jcas);
     _casView.validateArraySize(length);
-    fsHashSet = new HashSet<>(length);
+    fsHashSet = set;
 
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
   }
-    
+  
   //*--------------*
   //* Feature: fsArray
 
@@ -150,14 +165,14 @@
    * @generated
    * @return value of the feature 
    */
-  private FSArray getFsArray() { return (FSArray)(_getFeatureValueNc(_FI_fsArray));}
+  private FSArray<T> getFsArray() { return (FSArray<T>)(_getFeatureValueNc(wrapGetIntCatchException(_FH_fsArray)));}
     
   /** setter for fsArray - sets internal use - holds the set of Feature Structures 
    * @generated
    * @param v value to set into the feature 
    */
-  private void setFsArray(FSArray v) {
-    _setFeatureValueNcWj(_FI_fsArray, v);
+  private void setFsArray(FSArray<T> v) {
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_fsArray), v);
   }    
     
   /* (non-Javadoc)
@@ -177,12 +192,10 @@
   private void lazyInit() {  
     isPendingInit = false;
     fsHashSet.clear();
-    FSArray a = getFsArray();
-    if (a != null) {
-      // do element by element to pick up pear trampoline conversion
-      for (TOP fs : a) {
-        fsHashSet.add((T) fs);
-      }
+    FSArray<T> a = getFsArray();
+
+    for (T fs : a) {
+      fsHashSet.add((T) fs);
     }
   }
     
@@ -193,21 +206,20 @@
   public void _save_to_cas_data() {
     if (isSaveNeeded) {
       isSaveNeeded = false;
-      FSArray fsa = getFsArray();
+      FSArray<T> fsa = getFsArray();
       if (fsa == null || fsa.size() != fsHashSet.size()) {
         fsa = new FSArray(_casView.getJCasImpl(), fsHashSet.size());
         setFsArray(fsa);
       }
  
-      // using element by element instead of bulk operations to
-      //   pick up any pear trampoline conversion and
+      // using element by element instead of bulk operations
       //   in case fsa was preallocated and right size, may need journaling
       
       int i = 0;
       for (TOP fs : fsHashSet) {
         TOP currentValue = fsa.get(i);
         if (currentValue != fs) {
-          fsa.set(i, fs); // done this way to record for journaling for delta CAS
+          fsa.set_without_PEAR_conversion(i, fs); // done this way to record for journaling for delta CAS
         }
         i++;
       }
@@ -236,11 +248,7 @@
     return fsa._getTheArray();
   }
   
-  /**
-   * Equals.
-   *
-   * @param o the o
-   * @return true, if successful
+  /*
    * @see java.util.AbstractSet#equals(java.lang.Object)
    */
   @Override
@@ -250,17 +258,13 @@
     if (size() != other.size()) return false;
     if (size() == 0) return true;
     
-    for (T item : this) {
-      if (!other.contains(item)) return false;
-    }
+    maybeLazyInit();
+    other.maybeLazyInit();
     
-    return true;
+    return fsHashSet.equals(other.fsHashSet);
   }
 
-  /**
-   * Hash code.
-   *
-   * @return the int
+  /*
    * @see java.util.AbstractSet#hashCode()
    */
   @Override
@@ -271,23 +275,11 @@
 //    return isSaveNeeded
 //        ? fsHashSet.hashCode()    // no good - hash codes different
 //        : Arrays.hashCode(gta());
-    if (isSaveNeeded) {
-      return fsHashSet.hashCode();
-    }
-    int hc = 0;
-    for (TOP fs : gta()) {
-      if (fs == null) {
-        continue;
-      }
-      hc += fs.hashCode();
-    }
-    return hc;
+    maybeLazyInit();
+    return fsHashSet.hashCode();
   }
 
-  /**
-   * To array.
-   *
-   * @return the feature structure[]
+  /*
    * @see java.util.AbstractCollection#toArray()
    */
   @Override
@@ -295,16 +287,13 @@
     if (isSaveNeeded) {
       T[] r = (T[]) new TOP[size()];
       fsHashSet.toArray(r);
+      
       return r;
     }
-    return (T[]) gta().clone();
+    return (T[]) Arrays.copyOf(gta(), gta().length);
   }
 
-  /**
-   * Removes all elements matching c.
-   *
-   * @param c the elements to remove
-   * @return true, if set changed
+  /*
    * @see java.util.AbstractSet#removeAll(java.util.Collection)
    */
   @Override
@@ -315,19 +304,17 @@
     return r;
   }
 
-  /**
-   * To array.
-   *
-   * @param <N> the generic type
-   * @param a the a
-   * @return the N[]
+  /*
    * @see java.util.AbstractCollection#toArray(Object[])
    */
   @Override
   public <N> N[] toArray(N[] a) {
     if (isSaveNeeded) {
-      return fsHashSet.toArray(a);
+      N[] aa = fsHashSet.toArray(a);
+      _casView.swapInPearVersion(aa);
+      return aa;
     }
+    
     final int sz = size();
     if (a.length < sz) {
       a = (N[]) Array.newInstance(a.getClass().getComponentType(), sz);
@@ -335,13 +322,11 @@
     
     TOP[] d = gta();
     System.arraycopy(d, 0, a, 0, d.length);
+    _casView.swapInPearVersion(a);
     return a;
   }
 
-  /**
-   * Iterator.
-   *
-   * @return the iterator
+  /*
    * @see java.util.HashSet#iterator()
    */
   @Override
@@ -350,11 +335,28 @@
       return Collections.emptyIterator();
     }
     
-    return isSaveNeeded 
-        ? fsHashSet.iterator()
-        : gtaIterator();
+    return new Iterator<T>() {
+
+      final private Iterator<T> baseIt = isSaveNeeded 
+          ? fsHashSet.iterator()
+          : gtaIterator();
+
+      @Override
+      public boolean hasNext() {
+        return baseIt.hasNext();
+      }
+
+      @Override
+      public T next() {
+        return _maybeGetPearFs(baseIt.next());
+      }      
+    };
   }
   
+  /**
+   * 
+   * @return iterator over non-pear versions
+   */
   private Iterator<T> gtaIterator() {
     return (Iterator<T>) getFsArray().iterator(); 
   }
@@ -393,7 +395,7 @@
   @Override
   public boolean contains(Object o) {
     maybeLazyInit();
-    return fsHashSet.contains(o);
+    return fsHashSet.contains((o instanceof TOP) ? _maybeGetBaseForPearFs((TOP)o) : o);
   }
 
   /**
@@ -406,7 +408,7 @@
   @Override
   public boolean add(T e) {
     maybeLazyInit();
-    boolean r = fsHashSet.add(e); 
+    boolean r = fsHashSet.add(_maybeGetBaseForPearFs(e)); 
     if (r) isSaveNeeded = true;
     return r;
   }
@@ -421,7 +423,7 @@
   @Override
   public boolean remove(Object o) {
     maybeLazyInit();
-    boolean r = fsHashSet.remove(o);
+    boolean r = fsHashSet.remove((o instanceof TOP) ? _maybeGetBaseForPearFs((TOP)o) : o);
     if (r) isSaveNeeded = true;
     return r;
   }
@@ -449,7 +451,12 @@
   @Override
   public boolean containsAll(Collection<?> c) {
     maybeLazyInit();
-    return fsHashSet.containsAll(c);
+    for (Object o : c) {
+      if (!contains(o)) {
+        return false;
+      }
+    }
+    return true;
   }
 
   /**
@@ -461,8 +468,16 @@
    */
   @Override
   public boolean addAll(Collection<? extends T> c) {
+    if (c.size() == 0) {
+      return false;
+    }
+    
+    ArrayList<T> a = new ArrayList<>(c.size());
+    for (T item : c) {
+      a.add(_maybeGetBaseForPearFs(item));
+    }
     maybeLazyInit();
-    boolean r = fsHashSet.addAll(c);
+    boolean r = fsHashSet.addAll(a);
     if (r) isSaveNeeded = true;
     return r;
   }
@@ -475,9 +490,11 @@
    */
   @Override
   public Spliterator<T> spliterator() {
-    return isSaveNeeded
+    Spliterator<T> baseSi =  isSaveNeeded
         ? fsHashSet.spliterator()
         : (Spliterator<T>) Arrays.asList(gta()).spliterator();
+        
+    return _casView.makePearAware(baseSi);   
   }
 
   /**
@@ -489,8 +506,15 @@
    */
   @Override
   public boolean retainAll(Collection<?> c) {
+    if (c.size() == 0) {
+      boolean wasNotEmpty = !isEmpty();
+      clear();
+      return wasNotEmpty;
+    }
+    
+    Collection<?> cc = _casView.collectNonPearVersions(c);
     maybeLazyInit();
-    boolean r = fsHashSet.retainAll(c);
+    boolean r = fsHashSet.retainAll(cc);
     if (r) isSaveNeeded = true;
     return r;
   }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSLinkedHashSet.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSLinkedHashSet.java
new file mode 100644
index 0000000..7eaf2ec
--- /dev/null
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSLinkedHashSet.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+   
+/* Apache UIMA v3 - First created by JCasGen Fri Jan 20 11:55:59 EST 2017 */
+
+package org.apache.uima.jcas.cas;
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.RandomAccess;
+import java.util.Set;
+import java.util.Spliterator;
+
+import org.apache.uima.UimaSerializableFSs;
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.FeatureStructureImplC;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.cas.impl.TypeSystemImpl;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.util.impl.Constants;
+
+
+/** a hash set of Feature Structures
+ * Is Pear aware - stores non-pear versions but may return pear version in pear contexts
+ * Updated by JCasGen Fri Jan 20 11:55:59 EST 2017
+ * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-types/src/main/descriptors/java_object_type_descriptors.xml
+ * @generated */
+public class FSLinkedHashSet <T extends TOP> extends FSHashSet<T> {
+  
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "org.apache.uima.jcas.cas.FSHashSet";
+  
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static int typeIndexID = JCasRegistry.register(FSLinkedHashSet.class);
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static int type = typeIndexID;
+  /** @generated
+   * @return index of the type  
+   */
+  @Override
+  public              int getTypeIndexID() {return typeIndexID;}
+   
+  /** Never called.  Disable default constructor
+   * @generated */
+  protected FSLinkedHashSet() {
+    super();
+  }
+    
+  /** Internal - constructor used by generator 
+   * @generated
+   * @param casImpl the CAS this Feature Structure belongs to
+   * @param type the type of this Feature Structure 
+   */
+  public FSLinkedHashSet(TypeImpl type, CASImpl casImpl) {
+    super(new LinkedHashSet<>(), type, casImpl);
+  }
+  
+  /** @generated
+   * @param jcas JCas to which this Feature Structure belongs 
+   */
+  public FSLinkedHashSet(JCas jcas) {
+    super(new LinkedHashSet<>(), jcas);
+  } 
+
+  /**
+   * Make a new FSLinkedHashSet with an initial size .
+   *
+   * @param jcas The JCas
+   * @param length initial size
+   */
+  public FSLinkedHashSet(JCas jcas, int length) {
+    super(new LinkedHashSet<>(), jcas, length);
+  }
+   
+}
+
+    
\ No newline at end of file
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSList.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSList.java
index 3c898b9..f97ad92 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSList.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSList.java
@@ -20,9 +20,9 @@
 package org.apache.uima.jcas.cas;
 
 import java.util.Collections;
+import java.util.IdentityHashMap;
 import java.util.Iterator;
-import java.util.Spliterator;
-import java.util.Spliterators;
+import java.util.Set;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 
@@ -33,12 +33,20 @@
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.SelectFSs_impl;
 import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.internal.util.function.Consumer_withSaxException;
 import org.apache.uima.jcas.JCas;
+import org.xml.sax.SAXException;
 
-public abstract class FSList extends TOP implements CommonList, Iterable<TOP> {
+/**
+ * 
+ *  T extends TOP, v2 already mandated TOP for set/get
+ * @param <T> the type of the elements in the list
+ */
+public abstract class FSList<T extends TOP> extends TOP implements CommonList, Iterable<T> {
  
-	// Never called.
+	// for removed markers
 	protected FSList() {// Disable default constructor
+	  super();
 	}
 
 	public FSList(JCas jcas) {
@@ -56,70 +64,70 @@
      super(t, c);
    }
 	
-   public TOP getNthElement(int i) {
-     CommonList node = getNthNode(i);
+   public T getNthElement(int i) {
+     FSList<T> node = (FSList<T>) getNthNode(i);
      if (node instanceof EmptyFSList) {
        throw new CASRuntimeException(CASRuntimeException.JCAS_GET_NTH_PAST_END, Integer.toString(i));
      }
-     return ((NonEmptyFSList)node).getHead();
+     return ((NonEmptyFSList<T>)node).getHead();
    } 
    
-  public NonEmptyFSList createNonEmptyNode() {
-   return new NonEmptyFSList(this._casView.getJCasImpl());
+  public NonEmptyFSList<T> createNonEmptyNode() {
+   return new NonEmptyFSList<T>(this._casView.getJCasImpl());
   }
   
-  public NonEmptyFSList pushNode() {
-    NonEmptyFSList n = createNonEmptyNode();
+  public NonEmptyFSList<T> pushNode() {
+    NonEmptyFSList<T> n = createNonEmptyNode();
     n.setTail(this);
     return n;
   }
     
   /**
    * Treat an FSArray as a source for SelectFSs. 
-   * @param <T> generic type being selected
+   * @param <U> generic type being selected
    * @return a new instance of SelectFSs
    */
-  public <T extends FeatureStructure> SelectFSs<T> select() {
+  public <U extends T> SelectFSs<U> select() {
     return new SelectFSs_impl<>(this);
   }
 
   /**
    * Treat an FSArray as a source for SelectFSs. 
    * @param filterByType only includes elements of this type
-   * @param <T> generic type being selected
+   * @param <U> generic type being selected
    * @return a new instance of SelectFSs
    */
-  public <T extends FeatureStructure> SelectFSs<T> select(Type filterByType) {
+  public <U extends T> SelectFSs<U> select(Type filterByType) {
     return new SelectFSs_impl<>(this).type(filterByType);
   }
 
   /**
    * Treat an FSArray as a source for SelectFSs.  
    * @param filterByType only includes elements of this JCas class
-   * @param <T> generic type being selected
+   * @param <U> generic type being selected
    * @return a new instance of SelectFSs
    */
-  public <T extends FeatureStructure> SelectFSs<T> select(Class<T> filterByType) {
+  public <U extends T> SelectFSs<U> select(Class<U> filterByType) {
     return new SelectFSs_impl<>(this).type(filterByType);
   }
   
   /**
    * Treat an FSArray as a source for SelectFSs. 
    * @param filterByType only includes elements of this JCas class's type
-   * @param <T> generic type being selected
+   * @param <U> generic type being selected
    * @return a new instance of SelectFSs
    */
-  public <T extends FeatureStructure> SelectFSs<T> select(int filterByType) {
+  public <U extends T> SelectFSs<U> select(int filterByType) {
     return new SelectFSs_impl<>(this).type(filterByType);
   }
   
   /**
    * Treat an FSArray as a source for SelectFSs. 
    * @param filterByType only includes elements of this type (fully qualifined type name)
-   * @param <T> generic type being selected
+   * @param <U> generic type being selected
    * @return a new instance of SelectFSs
    */
-  public <T extends FeatureStructure> SelectFSs<T> select(String filterByType) {
+  public <U extends T> SelectFSs<U> select(String filterByType) {
     return new SelectFSs_impl<>(this).type(filterByType);
   }
   
@@ -127,12 +135,14 @@
    * Create an FSList from an existing array of Feature Structures
    * @param jcas the JCas to use
    * @param a the array of Feature Structures to populate the list with
+   * @param <U> the type of FeatureStructures being stored in the FSList being created
+   * @param <E> the type of the array argument
    * @return an FSList, with the elements from the array
    */
-  public static FSList createFromArray(JCas jcas, FeatureStructure[] a) {
-    FSList fsl = jcas.getCasImpl().getEmptyFSList();   
+  public static <U extends TOP, E extends FeatureStructure> FSList<U> create(JCas jcas, E[] a) {
+    FSList<U> fsl = jcas.getCasImpl().emptyFSList();   
     for (int i = a.length - 1; i >= 0; i--) {
-      fsl = fsl.push((TOP) a[i]);
+      fsl = fsl.push((U) a[i]);
     }   
     return fsl;
   }
@@ -141,8 +151,8 @@
    * @see java.lang.Iterable#iterator()
    */
   @Override
-  public Iterator<TOP> iterator() {
-    return Collections.emptyIterator();  // overridden by NonEmptyFSList
+  public Iterator<T> iterator() {
+    return Collections.<T>emptyIterator();  // overridden by NonEmptyFSList
   }
     
   /**
@@ -150,20 +160,31 @@
    * @param item the item to push onto the list
    * @return the new list, with this item as the head value of the first element
    */
-  public NonEmptyFSList push(TOP item) {
-    return new NonEmptyFSList(_casView.getJCasImpl(), item, this);
+  public NonEmptyFSList<T> push(T item) {
+    return new NonEmptyFSList<T>(_casView.getJCasImpl(), item, this);
   }
 
   /**
-   * @param <T> generic type being returned
    * @return a stream over this FSList
    */
-  public <T extends TOP> Stream<T> stream() {
+  public Stream<T> stream() {
     return (Stream<T>) StreamSupport.stream(spliterator(), false);
   }
   
   @Override
-  public EmptyFSList getEmptyList() {
-    return this._casView.getEmptyFSList();
+  public EmptyFSList emptyList() {
+    return this._casView.emptyFSList();
+  }
+ 
+  public boolean contains(T v) {
+    FSList<T> node = this;
+    while (node instanceof NonEmptyFSList) {
+      NonEmptyFSList<T> n = (NonEmptyFSList<T>) node;
+      if (n.getHead() == v) {
+        return true;
+      }
+      node = n.getTail();
+    }
+    return false;
   }
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FloatArray.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FloatArray.java
index 5cd8776..ee888e8 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FloatArray.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FloatArray.java
@@ -19,6 +19,11 @@
 
 package org.apache.uima.jcas.cas;
 
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CommonArrayFS;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.FloatArrayFSImpl;
@@ -27,10 +32,13 @@
 import org.apache.uima.jcas.JCasRegistry;
 
 /** Java Cas model for Cas FloatArray. */
-public final class FloatArray extends TOP implements CommonPrimitiveArray, FloatArrayFSImpl {
+public final class FloatArray extends TOP 
+                              implements CommonPrimitiveArray<Float>,
+                                         Iterable<Float>,
+                                         FloatArrayFSImpl {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.cas.jcas.FloatArray";
+  public final static String _TypeName = CAS.TYPE_NAME_FLOAT_ARRAY;
 
   /**
    * Each cover class when loaded sets an index. Used in the JCas typeArray to go from the cover
@@ -67,8 +75,8 @@
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(length);
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2Size_arrays(length);
     }    
   }
   
@@ -85,8 +93,8 @@
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(length);
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2Size_arrays(length);
     }    
   }
 
@@ -141,7 +149,7 @@
    * @see org.apache.uima.cas.ArrayFS#toArray()
    */
   public float[] toArray() {
-    return theArray.clone();
+    return Arrays.copyOf(theArray, theArray.length);
   }
 
   /**
@@ -203,9 +211,48 @@
    * @param a the source for the array's initial values
    * @return a newly created and populated array
    */
-  public static FloatArray createFromArray(JCas jcas, float[] a) {
+  public static FloatArray create(JCas jcas, float[] a) {
     FloatArray floatArray = new FloatArray(jcas, a.length);
     floatArray.copyFromArray(a, 0, 0, a.length);
     return floatArray;
   }
+
+  /* (non-Javadoc)
+   * @see java.lang.Iterable#iterator()
+   */
+  @Override
+  public Iterator<Float> iterator() {
+    return new Iterator<Float>() {
+
+      int i = 0;
+      
+      @Override
+      public boolean hasNext() {
+        return i < size();
+      }
+
+      @Override
+      public Float next() {
+        if (!hasNext())
+          throw new NoSuchElementException();
+        return get(i++);
+      }
+      
+    };
+  }
+
+
+  /**
+   * @param item the item to see if is in the array
+   * @return true if the item is in the array
+   */
+  public boolean contains(float item) {
+    for (float b : theArray) {
+      if (b == item) {
+        return true;
+      }
+    }
+    return false;
+  }
+
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FloatList.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FloatList.java
index bea2e00..ac26840 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FloatList.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FloatList.java
@@ -21,8 +21,9 @@
 
 import java.util.Collections;
 import java.util.Iterator;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
-import org.apache.uima.cas.FeatureStructure;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.jcas.JCas;
@@ -76,8 +77,8 @@
   }
   
   @Override
-  public EmptyFloatList getEmptyList() {
-    return this._casView.getEmptyFloatList();
+  public EmptyFloatList emptyList() {
+    return this._casView.emptyFloatList();
   }
   
   /**
@@ -86,12 +87,27 @@
    * @param a the array of Floats to populate the list with
    * @return an FloatList, with the elements from the array
    */
-  public static FloatList createFromArray(JCas jcas, Float[] a) {
-    FloatList floatList = jcas.getCasImpl().getEmptyFloatList();   
+  public static FloatList create(JCas jcas, Float[] a) {
+    FloatList floatList = jcas.getCasImpl().emptyFloatList();   
     for (int i = a.length - 1; i >= 0; i--) {
       floatList = floatList.push(a[i]);
     }   
     return floatList;
   }
-
+  
+  public Stream<Float> stream() {
+    return StreamSupport.stream(spliterator(), false);
+  }
+  
+  public boolean contains(float v) {
+    FloatList node = this;
+    while (node instanceof NonEmptyFloatList) {
+      NonEmptyFloatList n = (NonEmptyFloatList) node;
+      if (n.getHead() == v) {
+        return true;
+      }
+      node = n.getTail();
+    }
+    return false;
+  }
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/Int2FS.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/Int2FS.java
new file mode 100644
index 0000000..55feb08
--- /dev/null
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/Int2FS.java
@@ -0,0 +1,361 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+   
+/* Apache UIMA v3 - First created by JCasGen Fri Jan 20 11:55:59 EST 2017 */
+
+package org.apache.uima.jcas.cas;
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.uima.UimaSerializableFSs;
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.FeatureStructureImplC;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.cas.impl.TypeSystemImpl;
+import org.apache.uima.internal.util.Int2ObjHashMap;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.util.IntEntry;
+import org.apache.uima.util.impl.Constants;
+
+
+/** 
+ * A map from ints to Feature Structures
+ * Is Pear aware - stores non-pear versions but may return pear version in pear contexts
+ */
+public class Int2FS <T extends TOP> extends TOP implements 
+                            UimaSerializableFSs,  
+                            Cloneable {
+  
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "org.apache.uima.jcas.cas.Int2FS";
+  
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static int typeIndexID = JCasRegistry.register(Int2FS.class);
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static int type = typeIndexID;
+  /** @generated
+   * @return index of the type  
+   */
+  @Override
+  public              int getTypeIndexID() {return typeIndexID;}
+ 
+  /** lifecycle   
+   *   - starts as empty array list   
+   *   - becomes non-empty when updated (add)       
+   *   -- used from that point on. */
+  
+  private boolean isPendingInit = false;
+  private boolean isSaveNeeded = false;
+  
+  private final Int2ObjHashMap<TOP, T> int2FS; // not set here to allow initial size version
+
+  /* *******************
+   *   Feature Offsets *
+   * *******************/ 
+   
+  public final static String _FeatName_fsArray = "fsArray";
+
+
+  /* Feature Adjusted Offsets */
+  private final static CallSite _FC_fsArray = TypeSystemImpl.createCallSite(Int2FS.class, "fsArray");
+  private final static MethodHandle _FH_fsArray = _FC_fsArray.dynamicInvoker();
+
+  public final static String _FeatName_intArray = "intArray";
+
+
+  /* Feature Adjusted Offsets */
+  private final static CallSite _FC_intArray = TypeSystemImpl.createCallSite(Int2FS.class, "intArray");
+  private final static MethodHandle _FH_intArray = _FC_intArray.dynamicInvoker();
+   
+  /** Never called.  Disable default constructor
+   * @generated */
+  protected Int2FS() {
+    int2FS = null;
+  }
+    
+  /** Internal - constructor used by generator 
+   * @generated
+   * @param casImpl the CAS this Feature Structure belongs to
+   * @param type the type of this Feature Structure 
+   */
+  public Int2FS(TypeImpl type, CASImpl casImpl) {
+    super(type, casImpl);
+    int2FS = new Int2ObjHashMap<TOP, T>(TOP.class);
+
+    if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
+      _casView.traceFSCreate(this);
+    }    
+  }
+  
+  /** @generated
+   * @param jcas JCas to which this Feature Structure belongs 
+   */
+  public Int2FS(JCas jcas) {
+    super(jcas);
+    int2FS = new Int2ObjHashMap<TOP, T>(TOP.class);
+    
+    if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
+      _casView.traceFSCreate(this);
+    }   
+  } 
+
+  /**
+   * Make a new Int2FS map with an initial capacity.
+   *
+   * @param jcas The JCas
+   * @param length initial size
+   */
+  public Int2FS(JCas jcas, int length) {
+    super(jcas);
+    _casView.validateArraySize(length);
+    int2FS = new Int2ObjHashMap<TOP, T>(TOP.class, length);
+
+    if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
+      _casView.traceFSCreate(this);
+    }
+  }
+  
+  //*--------------*
+  //* Feature: fsArray
+
+  /** getter for fsArray - internal use
+   * @generated
+   * @return value of the feature 
+   */
+  private FSArray<T> getFsArray() { return (FSArray<T>)(_getFeatureValueNc(wrapGetIntCatchException(_FH_fsArray)));}
+    
+  /** setter for fsArray - internal use 
+   * @generated
+   * @param v value to set into the feature 
+   */
+  private void setFsArray(FSArray<T> v) {
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_fsArray), v);
+  }   
+  
+  /** getter for intArray - internal use
+   * @generated
+   * @return value of the feature 
+   */
+  private IntegerArray getIntArray() { return (IntegerArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_intArray)));}
+    
+  /** setter for intArray - sets internal use 
+   * @generated
+   * @param v value to set into the feature 
+   */
+  private void setIntArray(IntegerArray v) {
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_intArray), v);
+  }    
+
+    
+  /* (non-Javadoc)
+   * @see org.apache.uima.UimaSerializable#_init_from_cas_data()
+   */
+  @Override
+  public void _init_from_cas_data() {
+    isPendingInit = true;
+  }
+
+  private void maybeLazyInit() {
+    if (isPendingInit) {
+      lazyInit();
+    }
+  }
+  
+  private void lazyInit() {  
+    isPendingInit = false;
+    int2FS.clear();
+    FSArray<T> a = getFsArray();
+    IntegerArray ii = getIntArray();
+    int size = ii.size();
+    
+    for (int i = 0; i < size; i++) {
+      int2FS.put(ii.get(i), a.get(i));
+    }
+  }
+    
+  /* (non-Javadoc)
+   * @see org.apache.uima.UimaSerializable#_save_to_cas_data()
+   */
+  @Override
+  public void _save_to_cas_data() {
+    if (isSaveNeeded) {
+      isSaveNeeded = false;
+      FSArray<T> fsa = getFsArray();
+      IntegerArray ia = getIntArray();         
+      int newSize = int2FS.size();
+      if (fsa == null || fsa.size() != newSize) {
+        fsa = new FSArray<T>(_casView.getJCasImpl(), newSize);
+        setFsArray(fsa);
+        ia = new IntegerArray(_casView.getJCasImpl(), newSize);
+        setIntArray(ia);
+      }
+ 
+      // using element by element instead of bulk operations
+      //   in case fsa was preallocated and right size, may need journaling
+     
+      Iterator<IntEntry<T>> it = int2FS.iterator();
+      int[] i = new int[1];
+      
+      FSArray<T> fsa_final = fsa;
+      IntegerArray ia_final = ia;
+      
+      it.forEachRemaining( e -> {
+        ia_final.set(i[0], e.getKey());
+        fsa_final.set_without_PEAR_conversion(i[0], (T)e.getValue());  
+        i[0]++;
+      });
+    }
+  }
+
+  /* (non-Javadoc)
+   * @see org.apache.uima.UimaSerializable#_superClone()
+   */
+  @Override
+  public FeatureStructureImplC _superClone() { return clone();}  // enable common clone
+  
+  private TOP[] gta() {
+    FSArray<T> fsa = getFsArray();
+    return (null == fsa) 
+             ? Constants.EMPTY_TOP_ARRAY
+             : fsa._getTheArray();
+  }
+  
+//  private int[] gtia() {
+//    IntegerArray ia = getIntArray();
+//    return (null == ia) 
+//             ? Constants.EMPTY_INT_ARRAY
+//             : ia._getTheArray();
+//  }
+  
+  // no non-default equals and hashcode - is very expensive
+  
+
+  public Collection<T> values() {
+    if (isSaveNeeded) {
+      return (Collection<T>) Arrays.asList(int2FS.valuesArray());
+    }   
+    return (Collection<T>) Arrays.asList(gta().clone());
+  }
+
+
+  /* (non-Javadoc)
+   * @see java.lang.Object#toString()
+   */
+  @Override
+  public String toString() {
+    final int maxLen = 10;
+    return "int2FS [isPendingInit=" + isPendingInit + ", isSaveNeeded=" + isSaveNeeded
+        + ", int2FS=" + (int2FS != null ? toString(int2FS, maxLen) : null) + "]";
+  }
+
+  /**
+   * To string.
+   *
+   * @param collection the collection
+   * @param maxLen the max len
+   * @return the string
+   */
+  private String toString(Int2ObjHashMap<TOP, T> collection, int maxLen) {
+    StringBuilder builder = new StringBuilder();
+    builder.append("[");
+    int i = 0;
+    for (Iterator<?> iterator = collection.iterator(); iterator.hasNext() && i < maxLen; i++) {
+      if (i > 0)
+        builder.append(", ");
+      builder.append(iterator.next());
+    }
+    builder.append("]");
+    return builder.toString();
+  }
+
+  public int size() {
+    return isSaveNeeded 
+        ? int2FS.size()
+        : gta().length;
+  }
+
+  /**
+   * Checks if is empty.
+   *
+   * @return true, if is empty
+   * @see java.util.HashSet#isEmpty()
+   */
+  public boolean isEmpty() {
+    return size() == 0;
+  }
+
+  public boolean containsKey(Object key) {
+    maybeLazyInit();
+    return int2FS.containsKey((int)key);
+  }
+
+  public boolean containsValue(Object value) {
+    if (!(value instanceof TOP)) {
+      return false;
+    }
+    return values().contains(value);
+  }
+
+  public T get(int key) {
+    maybeLazyInit();
+    return int2FS.get(key);
+  }
+
+  public T put(int key, T value) {
+    maybeLazyInit();
+    isSaveNeeded = true;
+    return (T) int2FS.put(key, value);
+    
+  }
+
+  public T remove(int key) {
+    maybeLazyInit();
+    isSaveNeeded = true;
+    return (T) int2FS.remove(key);
+   }
+
+  public void clear() {
+    if (size() == 0) return;
+    maybeLazyInit();
+    isSaveNeeded = true;
+    int2FS.clear();
+  }
+  
+  public Iterator<IntEntry<T>> iterator() {
+    maybeLazyInit();
+    return int2FS.iterator();
+  }
+
+}
+
+    
\ No newline at end of file
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/IntegerArray.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/IntegerArray.java
index 803a1b3..fe89d56 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/IntegerArray.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/IntegerArray.java
@@ -26,6 +26,7 @@
 import java.util.function.IntConsumer;
 import java.util.stream.IntStream;
 
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CommonArrayFS;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.IntArrayFSImpl;
@@ -34,10 +35,10 @@
 import org.apache.uima.jcas.JCasRegistry;
 
 /** The Java Class model corresponding to the Cas IntegerArray_JCasImpl type. */
-public final class IntegerArray extends TOP implements CommonPrimitiveArray, IntArrayFSImpl, Iterable<Integer> {
+public final class IntegerArray extends TOP implements CommonPrimitiveArray<Integer>, IntArrayFSImpl, Iterable<Integer> {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.cas.jcas.IntegerArray";
+  public final static String _TypeName = CAS.TYPE_NAME_INTEGER_ARRAY;
 
   /**
    * Each cover class when loaded sets an index. Used in the JCas typeArray to go from the cover
@@ -53,6 +54,7 @@
    * @return the type array index
    */
   // can't be factored - refs locally defined field
+  @Override
   public int getTypeIndexID() {
     return typeIndexID;
   }
@@ -75,8 +77,8 @@
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(length);
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2Size_arrays(length);
     }    
   }
 
@@ -93,14 +95,15 @@
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(length);
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2Size_arrays(length);
     }    
   }
 
   /**
    * return the indexed value from the corresponding Cas IntegerArray_JCasImpl as an int.
    */
+  @Override
   public int get(int i) {
     return theArray[i];
   }
@@ -108,6 +111,7 @@
   /**
    * update the Cas, setting the indexed value to the passed in Java int value.
    */
+  @Override
   public void set(int i, int v) {
     theArray[i] = v;
     _casView.maybeLogArrayUpdate(this, null, i);
@@ -117,6 +121,7 @@
    * @see org.apache.uima.cas.IntArrayFS#copyFromArray(int[], int, int, int)
    * 
    */
+  @Override
   public void copyFromArray(int[] src, int srcPos, int destPos, int length) {
     System.arraycopy(src, srcPos, theArray, destPos, length);
     _casView.maybeLogArrayUpdates(this, destPos,  length);
@@ -125,6 +130,7 @@
   /**
    * @see org.apache.uima.cas.IntArrayFS#copyToArray(int, int[], int, int)
    */
+  @Override
   public void copyToArray(int srcPos, int[] dest, int destPos, int length) {
     System.arraycopy(theArray, srcPos, dest, destPos, length);
   }
@@ -132,11 +138,13 @@
   /**
    * @see org.apache.uima.cas.IntArrayFS#toArray()
    */
+  @Override
   public int[] toArray() {
-    return theArray.clone();
+    return Arrays.copyOf(theArray, theArray.length);
   }
 
   /** return the size of the array */
+  @Override
   public int size() {
     return theArray.length;
   }
@@ -144,6 +152,7 @@
   /**
    * @see org.apache.uima.cas.IntArrayFS#copyToArray(int, String[], int, int)
    */
+  @Override
   public void copyToArray(int srcOffset, String[] dest, int destOffset, int length) {
     _casView.checkArrayBounds(theArray.length, srcOffset, length);
     for (int i = 0; i < length; i++) {
@@ -154,6 +163,7 @@
   /**
    * @see org.apache.uima.cas.IntArrayFS#copyFromArray(String[], int, int, int)
    */
+  @Override
   public void copyFromArray(String[] src, int srcOffset, int destOffset, int length) {
     _casView.checkArrayBounds(theArray.length, srcOffset, length);
     for (int i = 0; i < length; i++) {
@@ -240,10 +250,34 @@
    * @param a the source for the array's initial values
    * @return a newly created and populated array
    */
-  public static IntegerArray createFromArray(JCas jcas, int[] a) {
+  public static IntegerArray create(JCas jcas, int[] a) {
     IntegerArray intArray = new IntegerArray(jcas, a.length);
     intArray.copyFromArray(a, 0, 0, a.length);
     return intArray;
   }
+  
+  /**
+   * non boxing version 
+   * @param action -
+   */
+  public void forEach(IntConsumer action) {
+    for (int d : theArray) {
+      action.accept(d);
+    }
+  }
+
+
+  /**
+   * @param item the item to see if is in the array
+   * @return true if the item is in the array
+   */
+  public boolean contains(int item) {
+    for (int b : theArray) {
+      if (b == item) {
+        return true;
+      }
+    }
+    return false;
+  }
 
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/IntegerArrayList.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/IntegerArrayList.java
index 29805d1..c810a31 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/IntegerArrayList.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/IntegerArrayList.java
@@ -21,10 +21,13 @@
 
 package org.apache.uima.jcas.cas;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
 import java.util.Arrays;
+import java.util.PrimitiveIterator.OfInt;
 import java.util.RandomAccess;
 import java.util.Spliterator;
-import java.util.PrimitiveIterator.OfInt;
+import java.util.function.IntConsumer;
 import java.util.stream.IntStream;
 import java.util.stream.StreamSupport;
 
@@ -38,14 +41,10 @@
 import org.apache.uima.cas.impl.TypeSystemImpl;
 import org.apache.uima.internal.util.IntListIterator;
 import org.apache.uima.internal.util.IntVector;
-import org.apache.uima.jcas.JCas; 
+import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 
 
-import org.apache.uima.jcas.cas.TOP;
-import org.apache.uima.jcas.cas.IntegerArray;
-
-
 /** an expandable array of ints
  * Updated by JCasGen Fri Jan 20 11:55:59 EST 2017
  * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-types/src/main/descriptors/java_object_type_descriptors.xml
@@ -57,6 +56,7 @@
  *   - it is adjustable, like ArrayList
  *   
  * Implementation notes:
+ *   - implements Iterable + stream, not Collection, because stream returns IntStream
  *   - Uses UimaSerializable APIs
  *   - two implementations of the array list:
  *     -- one uses the original IntegerArray, via a variant of the asList wrapper that returns ints
@@ -69,14 +69,14 @@
 
 public class IntegerArrayList extends TOP implements 
                           Iterable<Integer>,
-                          UimaSerializable, CommonArrayFS, 
+                          UimaSerializable, CommonArrayFS<Integer>, 
                           RandomAccess, Cloneable {
  
   /** @generated
    * @ordered 
    */
   @SuppressWarnings ("hiding")
-  public final static String _TypeName = "org.apache.uima.jcas.type.IntegerArrayList";
+  public final static String _TypeName = "org.apache.uima.jcas.cas.IntegerArrayList";
   
   /** @generated
    * @ordered 
@@ -118,7 +118,9 @@
 
 
   /* Feature Adjusted Offsets */
-  public final static int _FI_intArray = TypeSystemImpl.getAdjustedFeatureOffset("intArray");
+//  public final static int _FI_intArray = TypeSystemImpl.getAdjustedFeatureOffset("intArray");
+  private final static CallSite _FC_intArray = TypeSystemImpl.createCallSite(IntegerArrayList.class, "intArray");
+  private final static MethodHandle _FH_intArray = _FC_intArray.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -173,14 +175,14 @@
    * @generated
    * @return value of the feature 
    */
-  private IntegerArray getIntArray() { return (IntegerArray)(_getFeatureValueNc(_FI_intArray));}
+  private IntegerArray getIntArray() { return (IntegerArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_intArray)));}
     
   /** setter for intArray - sets internal use - holds the ints 
    * @generated
    * @param v value to set into the feature 
    */
   private void setIntArray(IntegerArray v) {
-    _setFeatureValueNcWj(_FI_intArray, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_intArray), v);
   }    
     
   private void maybeStartUsingIntegerArrayList() {
@@ -339,7 +341,7 @@
    * @see org.apache.uima.jcas.cas.CommonArray#copyValuesFrom(org.apache.uima.jcas.cas.CommonArray)
    */
   @Override
-  public void copyValuesFrom(CommonArrayFS v) {
+  public void copyValuesFrom(CommonArrayFS<Integer> v) {
     clear();
     Spliterator.OfInt si;
     
@@ -355,7 +357,7 @@
   }
   
   /**
-   * Convenience - create a IntegerArrayList from an existing FeatureStructure[]
+   * Convenience - create a IntegerArrayList from an existing array.
    * @param jcas -
    * @param a -
    * @return -
@@ -370,14 +372,6 @@
   public FeatureStructureImplC _superClone() {return clone();}  // enable common clone
   
   /**
-   * @return -
-   * @see java.util.ArrayList#isEmpty()
-   */
-  public boolean isEmpty() {
-    return size() == 0;
-  }
-
-  /**
    * @param i -
    * @return -
    */
@@ -557,7 +551,17 @@
   public IntStream stream() {
     return StreamSupport.intStream(spliterator(), false);
   }
-  
+
+  /**
+   * Version of forEach that doesn't box
+   * @param action -
+   */
+  public void forEach(IntConsumer action) {
+    OfInt ii = iterator();
+    while (ii.hasNext()) {
+      action.accept(ii.nextInt());
+    }
+  }
     
 }
 
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/IntegerList.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/IntegerList.java
index c1504d5..86e0dbf 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/IntegerList.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/IntegerList.java
@@ -19,14 +19,31 @@
 
 package org.apache.uima.jcas.cas;
 
-import java.util.Collections;
-import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.PrimitiveIterator.OfInt;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.jcas.JCas;
 
 public abstract class IntegerList extends TOP implements CommonList, Iterable<Integer> {
+  
+  public static OfInt EMPTY_INT_ITERATOR = new OfInt() {
+
+    @Override
+    public boolean hasNext() {
+      return false;
+    }
+
+    @Override
+    public int nextInt() {
+      throw new NoSuchElementException();
+    }
+  };
 
 	// Never called.
 	protected IntegerList() { // Disable default constructor
@@ -66,10 +83,11 @@
   
   /* (non-Javadoc)
    * @see java.lang.Iterable#iterator()
+   * overridden by NonEmptyIntegerList
    */
   @Override
-  public Iterator<Integer> iterator() {
-    return Collections.emptyIterator();  // overridden by NonEmptyXxList
+  public OfInt iterator() {
+    return EMPTY_INT_ITERATOR;
   }
 
   /**
@@ -82,8 +100,8 @@
   }
    
   @Override
-  public EmptyIntegerList getEmptyList() {
-    return this._casView.getEmptyIntegerList();
+  public EmptyIntegerList emptyList() {
+    return this._casView.emptyIntegerList();
   }
 
   /**
@@ -92,11 +110,32 @@
    * @param a the array of ints to populate the list with
    * @return an IntegerList, with the elements from the array
    */
-  public static IntegerList createFromArray(JCas jcas, int[] a) {
-    IntegerList integerList = jcas.getCasImpl().getEmptyIntegerList();   
+  public static IntegerList create(JCas jcas, int[] a) {
+    IntegerList integerList = jcas.getCasImpl().emptyIntegerList();   
     for (int i = a.length - 1; i >= 0; i--) {
       integerList = integerList.push(a[i]);
     }   
     return integerList;
   }
+    
+  public Stream<Integer> stream() {
+    return StreamSupport.stream(spliterator(), false);
+  }
+  
+  @Override
+  public Spliterator.OfInt spliterator() {
+    return Spliterators.spliterator(iterator(), Long.MAX_VALUE, 0);
+  } 
+  
+  public boolean contains(int v) {
+    IntegerList node = this;
+    while (node instanceof NonEmptyIntegerList) {
+      NonEmptyIntegerList n = (NonEmptyIntegerList) node;
+      if (n.getHead() == v) {
+        return true;
+      }
+      node = n.getTail();
+    }
+    return false;
+  }
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/LongArray.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/LongArray.java
index e961a5d..69e7f0f 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/LongArray.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/LongArray.java
@@ -23,10 +23,11 @@
 import java.util.NoSuchElementException;
 import java.util.PrimitiveIterator.OfLong;
 import java.util.Spliterator;
+import java.util.function.LongConsumer;
 import java.util.stream.LongStream;
 
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CommonArrayFS;
-import org.apache.uima.cas.LongArrayFS;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.LongArrayFSImpl;
 import org.apache.uima.cas.impl.TypeImpl;
@@ -34,10 +35,10 @@
 import org.apache.uima.jcas.JCasRegistry;
 
 /** JCas class model for LongArray */
-public final class LongArray extends TOP implements CommonPrimitiveArray, LongArrayFSImpl, Iterable<Long> {
+public final class LongArray extends TOP implements CommonPrimitiveArray<Long>, LongArrayFSImpl, Iterable<Long> {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.cas.jcas.LongArray";
+  public final static String _TypeName = CAS.TYPE_NAME_LONG_ARRAY;
 
   
   /**
@@ -54,6 +55,7 @@
    * @return the type array index
    */
   // can't be factored - refs locally defined field
+  @Override
   public int getTypeIndexID() {
     return typeIndexID;
   }
@@ -76,8 +78,8 @@
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(2); // space for length and ref
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2size_nonHeapStoredArrays(); 
     }     
   }
 
@@ -94,14 +96,15 @@
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(2); // space for length and ref
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2size_nonHeapStoredArrays(); 
     }     
   }
   
   /**
    * @see org.apache.uima.cas.LongArrayFS#get(int)
    */
+  @Override
   public long get(int i) {
     return theArray[i];
   }
@@ -109,6 +112,7 @@
   /**
    * @see org.apache.uima.cas.LongArrayFS#set(int , long)
    */
+  @Override
   public void set(int i, long v) {
     theArray[i] = v;
     _casView.maybeLogArrayUpdate(this, null, i);
@@ -117,6 +121,7 @@
   /**
    * @see org.apache.uima.cas.LongArrayFS#copyFromArray(long[], int, int, int)
    */
+  @Override
   public void copyFromArray(long[] src, int srcPos, int destPos, int length) {
     System.arraycopy(src, srcPos, theArray, destPos, length);
     _casView.maybeLogArrayUpdates(this, destPos, length);
@@ -125,6 +130,7 @@
   /**
    * @see org.apache.uima.cas.LongArrayFS#copyToArray(int, long[], int, int)
    */
+  @Override
   public void copyToArray(int srcPos, long[] dest, int destPos, int length) {
     System.arraycopy(theArray, srcPos, dest, destPos, length);
   }
@@ -132,11 +138,13 @@
   /**
    * @see org.apache.uima.cas.LongArrayFS#toArray()
    */
+  @Override
   public long[] toArray() {
-    return theArray.clone();
+    return Arrays.copyOf(theArray, theArray.length);
   }
 
   /** return the size of the array */
+  @Override
   public int size() {
     return theArray.length;
   }
@@ -144,6 +152,7 @@
   /**
    * @see org.apache.uima.cas.LongArrayFS#copyToArray(int, String[], int, int)
    */
+  @Override
   public void copyToArray(int srcPos, String[] dest, int destPos, int length) {
     _casView.checkArrayBounds(theArray.length, srcPos, length);
     for (int i = 0; i < length; i++) {
@@ -154,6 +163,7 @@
   /**
    * @see org.apache.uima.cas.LongArrayFS#copyFromArray(String[], int, int, int)
    */
+  @Override
   public void copyFromArray(String[] src, int srcPos, int destPos, int length) {
     _casView.checkArrayBounds(theArray.length, destPos, length);
     for (int i = 0; i < length; i++) {
@@ -185,6 +195,7 @@
     set(i, Long.parseLong(v));
   }
   
+  @Override
   public Spliterator.OfLong spliterator() {
     return Arrays.spliterator(theArray);
   }
@@ -199,12 +210,12 @@
         return i < size();
       }
 
-      @Override
-      public Long next() {
-        if (!hasNext())
-          throw new NoSuchElementException();
-        return get(i++);
-      }
+//      @Override   // using default
+//      public Long next() {
+//        if (!hasNext())
+//          throw new NoSuchElementException();
+//        return get(i++);
+//      }
 
       @Override
       public long nextLong() {
@@ -227,10 +238,34 @@
    * @param a the source for the array's initial values
    * @return a newly created and populated array
    */
-  public static LongArray createFromArray(JCas jcas, long[] a) {
+  public static LongArray create(JCas jcas, long[] a) {
     LongArray longArray = new LongArray(jcas, a.length);
     longArray.copyFromArray(a, 0, 0, a.length);
     return longArray;
   }
+  
+  /**
+   * Non Boxing
+   * @param action to be performed on each element
+   */
+  public void forEach(LongConsumer action) {
+    for (long l : theArray) {
+      action.accept(l);
+    }
+  }
+
+
+  /**
+   * @param item the item to see if is in the array
+   * @return true if the item is in the array
+   */
+  public boolean contains(long item) {
+    for (long b : theArray) {
+      if (b == item) {
+        return true;
+      }
+    }
+    return false;
+  }
 
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/NonEmptyFSList.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/NonEmptyFSList.java
index 300f893..409b374 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/NonEmptyFSList.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/NonEmptyFSList.java
@@ -19,21 +19,23 @@
 
 package org.apache.uima.jcas.cas;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASRuntimeException;
-import org.apache.uima.cas.FeatureStructure;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 
-public class NonEmptyFSList extends FSList implements Iterable<TOP>, NonEmptyList {
+public class NonEmptyFSList<T extends TOP> extends FSList<T> implements NonEmptyList {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.jcas.cas.NonEmptyFSList";
+  public final static String _TypeName = CAS.TYPE_NAME_NON_EMPTY_FS_LIST;
 
   public final static int typeIndexID = JCasRegistry.register(NonEmptyFSList.class);
 
@@ -43,15 +45,24 @@
     return typeIndexID;
   }
 
-  public static final int _FI_head = TypeSystemImpl.getAdjustedFeatureOffset("head");
-  public static final int _FI_tail = TypeSystemImpl.getAdjustedFeatureOffset("tail");
-
+  public static final String _FeatName_head = "head";
+  public static final String _FeatName_tail = "tail";
+  
+//  public static final int _FI_head = TypeSystemImpl.getAdjustedFeatureOffset("head");
+//  public static final int _FI_tail = TypeSystemImpl.getAdjustedFeatureOffset("tail");
+  private final static CallSite _FC_head = TypeSystemImpl.createCallSite(NonEmptyFSList.class, "head");
+  private final static MethodHandle _FH_head = _FC_head.dynamicInvoker();
+  private final static CallSite _FC_tail = TypeSystemImpl.createCallSite(NonEmptyFSList.class, "tail");
+  private final static MethodHandle _FH_tail = _FC_tail.dynamicInvoker();
+  
+  
 //  /* local data */
 //  private TOP _F_head;
 //  private FSList _F_tail;
   
-  // Never called. Disable default constructor
-  protected NonEmptyFSList() {
+  // might be called to produce removed marker
+  public NonEmptyFSList() {
+    super();
   }
 
   public NonEmptyFSList(JCas jcas) {
@@ -75,7 +86,7 @@
    * @param head -
    * @param tail -
    */
-  public NonEmptyFSList(JCas jcas, TOP head, CommonList tail) {
+  public NonEmptyFSList(JCas jcas, T head, CommonList tail) {
     this(jcas);
     setHead(head);
     setTail(tail);
@@ -86,30 +97,31 @@
    * @param jcas -
    * @param head -
    */
-  public NonEmptyFSList(JCas jcas, TOP head) {
-    this(jcas, head, jcas.getCasImpl().getEmptyFSList());
+  public NonEmptyFSList(JCas jcas, T head) {
+    this(jcas, head, jcas.getCasImpl().emptyFSList());
   }
   
   // *------------------*
   // * Feature: head
+  // return type is TOP for backwards compatibility with v2
   /* getter for head * */
-  public TOP getHead() { return _getFeatureValueNc(_FI_head); }
+  public T getHead() { return (T) _getFeatureValueNc(wrapGetIntCatchException(_FH_head)); }
 
   /* setter for head * */
-  public void setHead(FeatureStructure v) {
-    TOP vt = (TOP) v;
+  // arg type is TOP for backwards compatibility with v2
+  public void setHead(T vt) {
     if (vt != null && _casView.getBaseCAS() != vt._casView.getBaseCAS()) {
       /** Feature Structure {0} belongs to CAS {1}, may not be set as the value of an array or list element in a different CAS {2}.*/
       throw new CASRuntimeException(CASRuntimeException.FS_NOT_MEMBER_OF_CAS, vt, vt._casView, _casView);
     }
-    _setFeatureValueNcWj(_FI_head, v); }
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_head), vt); }
 
 //  public void _setHeadNcNj(TOP v) { _F_head = v; }
   
   // *------------------*
   // * Feature: tail
   /* getter for tail * */
-  public FSList getTail() { return (FSList) _getFeatureValueNc(_FI_tail); }
+  public FSList<T> getTail() { return (FSList<T>) _getFeatureValueNc(wrapGetIntCatchException(_FH_tail)); }
 
   /* setter for tail * */
   public void setTail(FSList v) {
@@ -117,15 +129,15 @@
       /** Feature Structure {0} belongs to CAS {1}, may not be set as the value of an array or list element in a different CAS {2}.*/
       throw new CASRuntimeException(CASRuntimeException.FS_NOT_MEMBER_OF_CAS, v, v._casView, _casView);
     }
-    _setFeatureValueNcWj(_FI_tail, v); }
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_tail), v); }
    
   @Override
   public void setTail(CommonList v) {
     setTail((FSList) v);
   }
   
-  public TOP getNthElement(int i) {
-    return ((NonEmptyFSList)getNonEmptyNthNode(i)).getHead();
+  public T getNthElement(int i) {
+    return ((NonEmptyFSList<T>)getNonEmptyNthNode(i)).getHead();
   }
 
   /**
@@ -133,18 +145,18 @@
    * @param item to be inserted
    * @return the NonEmptyFSList node created  
    */
-  public NonEmptyFSList add(FeatureStructure item) {
-    FSList tail = getTail();
-    NonEmptyFSList node = tail.push((TOP) item);
+  public NonEmptyFSList<T> add(T item) {
+    FSList<T> tail = getTail();
+    NonEmptyFSList<T> node = tail.push(item);
     setTail(node);
     return node;
   }
 
   @Override
-  public Iterator<TOP> iterator() {
-    return new Iterator<TOP>() {
+  public Iterator<T> iterator() {
+    return new Iterator<T>() {
 
-      FSList node = NonEmptyFSList.this;
+      FSList<T> node = NonEmptyFSList.this;
       
       @Override
       public boolean hasNext() {
@@ -152,12 +164,12 @@
       }
 
       @Override
-      public TOP next() {
+      public T next() {
         if (!hasNext()) {
           throw new NoSuchElementException();
         }
-        NonEmptyFSList nn = (NonEmptyFSList)node; 
-        TOP element = nn.getHead();
+        NonEmptyFSList<T> nn = (NonEmptyFSList<T>)node; 
+        T element = nn.getHead();
         node = nn.getTail();
         return element;
       }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/NonEmptyFloatList.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/NonEmptyFloatList.java
index b5f5130..71c1128 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/NonEmptyFloatList.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/NonEmptyFloatList.java
@@ -19,9 +19,12 @@
 
 package org.apache.uima.jcas.cas;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASRuntimeException;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
@@ -32,7 +35,7 @@
 public class NonEmptyFloatList extends FloatList implements NonEmptyList {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.jcas.cas.NonEmptyFloatList";
+  public final static String _TypeName = CAS.TYPE_NAME_NON_EMPTY_FLOAT_LIST;
 
   public final static int typeIndexID = JCasRegistry.register(NonEmptyFloatList.class);
 
@@ -42,8 +45,15 @@
     return typeIndexID;
   }
 
-  public static final int _FI_head = TypeSystemImpl.getAdjustedFeatureOffset("head");
-  public static final int _FI_tail = TypeSystemImpl.getAdjustedFeatureOffset("tail");
+  public static final String _FeatName_head = "head";
+  public static final String _FeatName_tail = "tail";
+  
+//  public static final int _FI_head = TypeSystemImpl.getAdjustedFeatureOffset("head");
+//  public static final int _FI_tail = TypeSystemImpl.getAdjustedFeatureOffset("tail");
+  private final static CallSite _FC_head = TypeSystemImpl.createCallSite(NonEmptyFloatList.class, "head");
+  private final static MethodHandle _FH_head = _FC_head.dynamicInvoker();
+  private final static CallSite _FC_tail = TypeSystemImpl.createCallSite(NonEmptyFloatList.class, "tail");
+  private final static MethodHandle _FH_tail = _FC_tail.dynamicInvoker();
   
   /* local data */
 //  private float _F_head;
@@ -86,25 +96,25 @@
    * @param v -
    */
   public NonEmptyFloatList(JCas jcas, float v) {
-    this(jcas, v, jcas.getCasImpl().getEmptyFloatList());
+    this(jcas, v, jcas.getCasImpl().emptyFloatList());
   }
   
   // *------------------*
   // * Feature: head
   /* getter for head * */
-  public float getHead() { return _getFloatValueNc(_FI_head); }
+  public float getHead() { return _getFloatValueNc(wrapGetIntCatchException(_FH_head)); }
 
   /* setter for head * */
   public void setHead(float v) {
-    this._setFloatValueNfc(_FI_head, v);
+    this._setFloatValueNfc(wrapGetIntCatchException(_FH_head), v);
   }
 
-//  public void _setHeadNcNj(float v) { setFloatValueNcNj(_getFeat(_FI_head), v); }
+//  public void _setHeadNcNj(float v) { setFloatValueNcNj(_getFeat(wrapGetIntCatchException(_FH_head)), v); }
   
   // *------------------*
   // * Feature: tail
   /* getter for tail * */
-  public FloatList getTail() { return (FloatList) _getFeatureValueNc(_FI_tail); }
+  public FloatList getTail() { return (FloatList) _getFeatureValueNc(wrapGetIntCatchException(_FH_tail)); }
 
   /* setter for tail * */
   public void setTail(FloatList v) {
@@ -112,7 +122,7 @@
       /** Feature Structure {0} belongs to CAS {1}, may not be set as the value of an array or list element in a different CAS {2}.*/
       throw new CASRuntimeException(CASRuntimeException.FS_NOT_MEMBER_OF_CAS, v, v._casView, _casView);
     }
-    _setFeatureValueNcWj(_FI_tail, v); 
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_tail), v); 
   }
 
   public void setTail(CommonList v) { setTail((FloatList) v); }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/NonEmptyIntegerList.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/NonEmptyIntegerList.java
index fc237f7..b2d3ee0 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/NonEmptyIntegerList.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/NonEmptyIntegerList.java
@@ -19,12 +19,13 @@
 
 package org.apache.uima.jcas.cas;
 
-import java.util.Iterator;
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
 import java.util.List;
 import java.util.NoSuchElementException;
-import java.util.PrimitiveIterator;
 import java.util.PrimitiveIterator.OfInt;
 
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASRuntimeException;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
@@ -35,7 +36,7 @@
 public class NonEmptyIntegerList extends IntegerList implements NonEmptyList {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.jcas.cas.NonEmptyIntegerList";
+  public final static String _TypeName = CAS.TYPE_NAME_NON_EMPTY_INTEGER_LIST;
 
   public final static int typeIndexID = JCasRegistry.register(NonEmptyIntegerList.class);
 
@@ -45,8 +46,16 @@
     return typeIndexID;
   }
   
-  public final static int _FI_head = TypeSystemImpl.getAdjustedFeatureOffset("head");
-  public final static int _FI_tail = TypeSystemImpl.getAdjustedFeatureOffset("tail");
+  public static final String _FeatName_head = "head";
+  public static final String _FeatName_tail = "tail";
+
+//  public final static int _FI_head = TypeSystemImpl.getAdjustedFeatureOffset("head");
+//  public final static int _FI_tail = TypeSystemImpl.getAdjustedFeatureOffset("tail");
+  private final static CallSite _FC_head = TypeSystemImpl.createCallSite(NonEmptyIntegerList.class, "head");
+  private final static MethodHandle _FH_head = _FC_head.dynamicInvoker();
+  private final static CallSite _FC_tail = TypeSystemImpl.createCallSite(NonEmptyIntegerList.class, "tail");
+  private final static MethodHandle _FH_tail = _FC_tail.dynamicInvoker();
+
 
 //  /* local data */
 //  private int _F_head;
@@ -89,25 +98,25 @@
    * @param v -
    */
   public NonEmptyIntegerList(JCas jcas, int v) {
-    this(jcas, v, jcas.getCasImpl().getEmptyIntegerList());
+    this(jcas, v, jcas.getCasImpl().emptyIntegerList());
   }
   
   // *------------------*
   // * Feature: head
   /* getter for head * */
-  public int getHead() { return _getIntValueNc(_FI_head); }
+  public int getHead() { return _getIntValueNc(wrapGetIntCatchException(_FH_head)); }
 
   /* setter for head * */
   public void setHead(int v) {
-    _setIntValueNfc(_FI_head, v);
+    _setIntValueNfc(wrapGetIntCatchException(_FH_head), v);
   }
 
-//  public void _setHeadNcNj(int v) { _FI_head = v;}
+//  public void _setHeadNcNj(int v) { wrapGetIntCatchException(_FH_head) = v;}
   
   // *------------------*
   // * Feature: tail
   /* getter for tail * */
-  public IntegerList getTail() { return (IntegerList) _getFeatureValueNc(_FI_tail); }
+  public IntegerList getTail() { return (IntegerList) _getFeatureValueNc(wrapGetIntCatchException(_FH_tail)); }
 
   /* setter for tail * */
   public void setTail(IntegerList v) {
@@ -115,7 +124,7 @@
       /** Feature Structure {0} belongs to CAS {1}, may not be set as the value of an array or list element in a different CAS {2}.*/
       throw new CASRuntimeException(CASRuntimeException.FS_NOT_MEMBER_OF_CAS, v, v._casView, _casView);
     }
-  _setFeatureValueNcWj(_FI_tail, v); 
+  _setFeatureValueNcWj(wrapGetIntCatchException(_FH_tail), v); 
   }
   
   @Override
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/NonEmptyStringList.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/NonEmptyStringList.java
index 7fa1256..8e59f1d 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/NonEmptyStringList.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/NonEmptyStringList.java
@@ -19,9 +19,12 @@
 
 package org.apache.uima.jcas.cas;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASRuntimeException;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
@@ -32,7 +35,7 @@
 public class NonEmptyStringList extends StringList implements Iterable<String>, NonEmptyList {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.jcas.cas.NonEmptyStringList";
+  public final static String _TypeName = CAS.TYPE_NAME_NON_EMPTY_STRING_LIST;
 
   public final static int typeIndexID = JCasRegistry.register(NonEmptyStringList.class);
 
@@ -42,8 +45,17 @@
     return typeIndexID;
   }
 
-  public static final int _FI_head = TypeSystemImpl.getAdjustedFeatureOffset("head");
-  public static final int _FI_tail = TypeSystemImpl.getAdjustedFeatureOffset("tail");
+  public static final String _FeatName_head = "head";
+  public static final String _FeatName_tail = "tail";
+
+//  public static final int _FI_head = TypeSystemImpl.getAdjustedFeatureOffset("head");
+//  public static final int _FI_tail = TypeSystemImpl.getAdjustedFeatureOffset("tail");
+  private final static CallSite _FC_head = TypeSystemImpl.createCallSite(NonEmptyStringList.class, "head");
+  private final static MethodHandle _FH_head = _FC_head.dynamicInvoker();
+  private final static CallSite _FC_tail = TypeSystemImpl.createCallSite(NonEmptyStringList.class, "tail");
+  private final static MethodHandle _FH_tail = _FC_tail.dynamicInvoker();
+
+  
   
 //  /* local data */
 //  private String _F_head;
@@ -86,25 +98,25 @@
    * @param head -
    */
   public NonEmptyStringList(JCas jcas, String head) {
-    this(jcas, head, jcas.getCasImpl().getEmptyStringList());
+    this(jcas, head, jcas.getCasImpl().emptyStringList());
   }
   
 // *------------------*
   // * Feature: head
   /* getter for head * */
-  public String getHead() { return _getStringValueNc(_FI_head); }
+  public String getHead() { return _getStringValueNc(wrapGetIntCatchException(_FH_head)); }
 
   /* setter for head * */
   public void setHead(String v) {
-    _setStringValueNfc(_FI_head, v);
+    _setStringValueNfc(wrapGetIntCatchException(_FH_head), v);
   }
   
-//  public void _setHeadNcNj(String v) {_FI_head = v;};
+//  public void _setHeadNcNj(String v) {wrapGetIntCatchException(_FH_head) = v;};
 
   // *------------------*
   // * Feature: tail
   /* getter for tail * */
-  public StringList getTail() { return (StringList) _getFeatureValueNc(_FI_tail); }
+  public StringList getTail() { return (StringList) _getFeatureValueNc(wrapGetIntCatchException(_FH_tail)); }
 
   /* setter for tail * */
   public void setTail(StringList v) {
@@ -112,7 +124,7 @@
       /** Feature Structure {0} belongs to CAS {1}, may not be set as the value of an array or list element in a different CAS {2}.*/
       throw new CASRuntimeException(CASRuntimeException.FS_NOT_MEMBER_OF_CAS, v, v._casView, _casView);
     }
-    _setFeatureValueNcWj(_FI_tail, v); 
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_tail), v); 
   }
   
   @Override
@@ -120,7 +132,7 @@
     setTail((StringList)v);
   }
   
-//  public void _setTailNcNj(StringList v) { _FI_tail = v; }
+//  public void _setTailNcNj(StringList v) { wrapGetIntCatchException(_FH_tail) = v; }
   
   /* (non-Javadoc)
    * @see org.apache.uima.jcas.cas.CommonList#get_headAsString()
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/SelectViaCopyToArray.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/SelectViaCopyToArray.java
index 76c6a8e..200f25a 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/SelectViaCopyToArray.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/SelectViaCopyToArray.java
@@ -19,7 +19,6 @@
 

 package org.apache.uima.jcas.cas;

 

-import org.apache.uima.cas.CAS;

 import org.apache.uima.cas.FeatureStructure;

 import org.apache.uima.cas.SelectFSs;

 import org.apache.uima.cas.Type;

@@ -30,60 +29,62 @@
  * Classes which provide a toArrayForSelect() method that returns 

  * a FeatureStructure[] can implement this to enable the 

  * class to be used as a "select" source

+ * T extends FeatureStructure because FSArray with no typing needs to default to FeatureStructure

+ *   for backwards compatibility

+ * @param <T> the type of the element

  */

 

 

 

-public interface SelectViaCopyToArray {

+public interface  SelectViaCopyToArray<T extends FeatureStructure> {

   

   FeatureStructure[] _toArrayForSelect();

   CASImpl _getView(); 

   

   /**

-   * @param <T> generic type being selected 

    * @return a new instance of SelectFSs

    */

-  default <T extends FeatureStructure> SelectFSs_impl<T> select() {

-    return new SelectFSs_impl<T>(_toArrayForSelect(), this._getView());

+  default SelectFSs_impl<T> select() {

+    return new SelectFSs_impl<>(_toArrayForSelect(), this._getView());

   }

 

   /**

    * Treat an FSArray as a source for SelectFSs. 

    * @param filterByType only includes elements of this type

-   * @param <T> generic type being selected

+   * @param <U> generic type being selected

    * @return a new instance of SelectFSs

    */

-  default <T extends FeatureStructure> SelectFSs<T> select(Type filterByType) {

+  default <U extends T> SelectFSs<U> select(Type filterByType) {

     return select().type(filterByType);

   }

 

   /**

    * Treat an FSArray as a source for SelectFSs.  

    * @param filterByType only includes elements of this JCas class

-   * @param <T> generic type being selected

+   * @param <U> generic type being selected

    * @return a new instance of SelectFSs

    */

-  default <T extends FeatureStructure> SelectFSs<T> select(Class<T> filterByType) {

+  default <U extends T> SelectFSs<U> select(Class<U> filterByType) {

     return select().type(filterByType);

   }

   

   /**

    * Treat an FSArray as a source for SelectFSs. 

    * @param filterByType only includes elements of this JCas class's type

-   * @param <T> generic type being selected

+   * @param <U> generic type being selected

    * @return a new instance of SelectFSs

    */

-  default <T extends FeatureStructure> SelectFSs<T> select(int filterByType) {

+  default <U extends T> SelectFSs<U> select(int filterByType) {

     return select().type(filterByType);

   }

   

   /**

    * Treat an FSArray as a source for SelectFSs. 

    * @param filterByType only includes elements of this type (fully qualifined type name)

-   * @param <T> generic type being selected

+   * @param <U> generic type being selected

    * @return a new instance of SelectFSs

    */

-  default <T extends FeatureStructure> SelectFSs<T> select(String filterByType) {

+  default <U extends T> SelectFSs<U> select(String filterByType) {

     return select().type(filterByType);

   }

 }

diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/ShortArray.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/ShortArray.java
index a6a4dee..37c3f0a 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/ShortArray.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/ShortArray.java
@@ -19,11 +19,12 @@
 
 package org.apache.uima.jcas.cas;
 
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CommonArrayFS;
-import org.apache.uima.cas.ShortArrayFS;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.ShortArrayFSImpl;
 import org.apache.uima.cas.impl.TypeImpl;
@@ -31,10 +32,10 @@
 import org.apache.uima.jcas.JCasRegistry;
 
 /** JCas class model for ShortArray */
-public final class ShortArray extends TOP implements CommonPrimitiveArray, ShortArrayFSImpl, Iterable<Short> {
+public final class ShortArray extends TOP implements CommonPrimitiveArray<Short>, ShortArrayFSImpl, Iterable<Short> {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.cas.jcas.ShortArray";
+  public final static String _TypeName = CAS.TYPE_NAME_SHORT_ARRAY;
 
   /**
    * Each cover class when loaded sets an index. Used in the JCas typeArray to go from the cover
@@ -72,8 +73,8 @@
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(2); // space for length and ref
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2size_nonHeapStoredArrays(); 
     }     
   }
 
@@ -90,8 +91,8 @@
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(2); // space for length and ref
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2size_nonHeapStoredArrays(); 
     }     
   }
 
@@ -129,7 +130,7 @@
    * @see org.apache.uima.cas.ShortArrayFS#toArray()
    */
   public short[] toArray() {
-    return theArray.clone();
+    return Arrays.copyOf(theArray, theArray.length);
   }
 
   /** return the size of the array */
@@ -202,10 +203,24 @@
    * @param a the source for the array's initial values
    * @return a newly created and populated array
    */
-  public static ShortArray createFromArray(JCas jcas, short[] a) {
+  public static ShortArray create(JCas jcas, short[] a) {
     ShortArray shortArray = new ShortArray(jcas, a.length);
     shortArray.copyFromArray(a, 0, 0, a.length);
     return shortArray;
   }
 
+
+  /**
+   * @param item the item to see if is in the array
+   * @return true if the item is in the array
+   */
+  public boolean contains(short item) {
+    for (short b : theArray) {
+      if (b == item) {
+        return true;
+      }
+    }
+    return false;
+  }
+
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/Sofa.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/Sofa.java
index 6086ec9..cf19c65 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/Sofa.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/Sofa.java
@@ -20,7 +20,10 @@
 package org.apache.uima.jcas.cas;
 
 import java.io.InputStream;
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
 
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASRuntimeException;
 import org.apache.uima.cas.Feature;
 import org.apache.uima.cas.FeatureStructure;
@@ -33,13 +36,13 @@
 public class Sofa extends TOP implements SofaFSImpl {
   
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.jcas.cas.Sofa";
-  public final static String _FeatName_sofaNum    = "sofaNum";
-  public final static String _FeatName_sofaID     = "sofaID";
-  public final static String _FeatName_mimeType   = "mimeType";
-  public final static String _FeatName_sofaArray  = "sofaArray";
-  public final static String _FeatName_sofaString = "sofaString";
-  public final static String _FeatName_sofaURI    = "sofaURI";
+  public final static String _TypeName = CAS.TYPE_NAME_SOFA;
+  public final static String _FeatName_sofaNum    = "sofaNum";  // int
+  public final static String _FeatName_sofaID     = "sofaID";   // string
+  public final static String _FeatName_mimeType   = "mimeType"; // string
+  public final static String _FeatName_sofaArray  = "sofaArray"; // TOP 
+  public final static String _FeatName_sofaString = "sofaString"; // string
+  public final static String _FeatName_sofaURI    = "sofaURI";    // string
 
 	public final static int typeIndexID = JCasRegistry.register(Sofa.class);
 
@@ -51,12 +54,26 @@
   
   /* local data */
   // these static ints are for fast index corruption checking
-  public final static int _FI_sofaNum    = TypeSystemImpl.getAdjustedFeatureOffset("sofaNum");
-  public final static int _FI_sofaID     = TypeSystemImpl.getAdjustedFeatureOffset("sofaID");
-  public final static int _FI_mimeType   = TypeSystemImpl.getAdjustedFeatureOffset("mimeType");
-  public final static int _FI_sofaArray  = TypeSystemImpl.getAdjustedFeatureOffset("sofaArray");
-  public final static int _FI_sofaString = TypeSystemImpl.getAdjustedFeatureOffset("sofaString");
-  public final static int _FI_sofaURI    = TypeSystemImpl.getAdjustedFeatureOffset("sofaURI");
+//  public final static int _FI_sofaNum    = TypeSystemImpl.getAdjustedFeatureOffset("sofaNum");
+//  public final static int _FI_sofaID     = TypeSystemImpl.getAdjustedFeatureOffset("sofaID");
+//  public final static int _FI_mimeType   = TypeSystemImpl.getAdjustedFeatureOffset("mimeType");
+//  public final static int _FI_sofaArray  = TypeSystemImpl.getAdjustedFeatureOffset("sofaArray");
+//  public final static int _FI_sofaString = TypeSystemImpl.getAdjustedFeatureOffset("sofaString");
+//  public final static int _FI_sofaURI    = TypeSystemImpl.getAdjustedFeatureOffset("sofaURI");
+
+  private final static CallSite _FC_sofaNum = TypeSystemImpl.createCallSite(Sofa.class, "sofaNum");
+  private final static CallSite _FC_sofaID = TypeSystemImpl.createCallSite(Sofa.class, "sofaID");
+  private final static CallSite _FC_mimeType = TypeSystemImpl.createCallSite(Sofa.class, "mimeType");
+  private final static CallSite _FC_sofaArray = TypeSystemImpl.createCallSite(Sofa.class, "sofaArray");
+  private final static CallSite _FC_sofaString = TypeSystemImpl.createCallSite(Sofa.class, "sofaString");
+  private final static CallSite _FC_sofaURI = TypeSystemImpl.createCallSite(Sofa.class, "sofaURI");
+
+  private final static MethodHandle _FH_sofaNum = _FC_sofaNum.dynamicInvoker();
+  private final static MethodHandle _FH_sofaID = _FC_sofaID.dynamicInvoker();
+  private final static MethodHandle _FH_mimeType = _FC_mimeType.dynamicInvoker();
+  private final static MethodHandle _FH_sofaArray = _FC_sofaArray.dynamicInvoker();
+  private final static MethodHandle _FH_sofaString = _FC_sofaString.dynamicInvoker();
+  private final static MethodHandle _FH_sofaURI = _FC_sofaURI.dynamicInvoker();
   
 //  private final int _F_sofaNum;
 //  private final String _F_sofaID;  // view name or _InitialView
@@ -85,9 +102,9 @@
   
   public Sofa(TypeImpl t, CASImpl c, int sofaNum, String viewName, String mimeType) {
     super(t, c);
-    _setIntValueNcNj(_FI_sofaNum, sofaNum);
-    _setRefValueCommon(_FI_sofaID, viewName);
-    _setRefValueCommon(_FI_mimeType, mimeType);
+    _setIntValueNcNj(wrapGetIntCatchException(_FH_sofaNum), sofaNum);
+    _setRefValueCommon(wrapGetIntCatchException(_FH_sofaID), viewName);
+    _setRefValueCommon(wrapGetIntCatchException(_FH_mimeType), mimeType);
 //    _F_sofaNum = sofaNum;
 //    _F_sofaID = viewName;
 //    _F_mimeType = mimeType;
@@ -122,7 +139,7 @@
    * getter for sofaNum
    * @return the sofa number
    */
-	public int getSofaNum() { return _getIntValueNc(_FI_sofaNum); }
+	public int getSofaNum() { return _getIntValueNc(wrapGetIntCatchException(_FH_sofaNum)); }
 	
 	// *--------------*
 	// * Feature: sofaID
@@ -132,7 +149,7 @@
    * @return the sofaID, which is the same as the view name
    */
 	@Override
-  public String getSofaID() { return _getStringValueNc(_FI_sofaID); }
+  public String getSofaID() { return _getStringValueNc(wrapGetIntCatchException(_FH_sofaID)); }
 
 	// *--------------*
 	// * Feature: mimeType
@@ -141,7 +158,7 @@
    * getter for mimeType - gets
    * @return the mime type
    */
-	public String getMimeType() { return _getStringValueNc(_FI_mimeType); }
+	public String getMimeType() { return _getStringValueNc(wrapGetIntCatchException(_FH_mimeType)); }
 
 	/**
    * @see org.apache.uima.cas.SofaFS#setLocalSofaData(FeatureStructure) This method is duplicated in
@@ -151,7 +168,7 @@
   @Override
   public void setLocalSofaData(FeatureStructure aFS) {   
     if (isSofaDataSet()) { throwAlreadySet("setLocalSofaData()"); }
-    _setFeatureValueNcWj(_FI_sofaArray, aFS);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_sofaArray), aFS);
   }
 
 	public void setLocalSofaData(FeatureStructure aFS, String mimeType) {
@@ -160,18 +177,25 @@
 	}
 
 	/**
-   * @see org.apache.uima.cas.SofaFS#setLocalSofaData(String) This method is duplicated in
-   *      SofaFSImpl. Any changes should be made in both places.
+   * @see org.apache.uima.cas.SofaFS#setLocalSofaData(String) 
    */
   @Override
   public void setLocalSofaData(String aString) {
-    if (isSofaDataSet()) { throwAlreadySet("setLocalSofaData()"); }
-    _setStringValueNcWj(_FI_sofaString, aString);
-
+    setLocalSofaDataNoDocAnnotUpdate(aString);
+    
     // create or update the document annotation for this Sofa's view
     ((CASImpl)(_casView.getView(this))).updateDocumentAnnotation();
   }
 
+  /**
+   * Internal use: used by deserializers
+   * @param aString the string to update
+   */
+  public void setLocalSofaDataNoDocAnnotUpdate(String aString) {
+    if (isSofaDataSet()) { throwAlreadySet("setLocalSofaData()"); }
+    _setStringValueNcWj(wrapGetIntCatchException(_FH_sofaString), aString);    
+  }
+  
   public void setLocalSofaData(String aString, String mimeType) {
     setLocalSofaData(aString);
     setMimeType(mimeType);
@@ -182,13 +206,13 @@
    * returns an UIMA Array whose data represents the sofa
    */
 	@Override
-  public FeatureStructure getLocalFSData() { return _getFeatureValueNc(_FI_sofaArray); }
+  public FeatureStructure getLocalFSData() { return _getFeatureValueNc(wrapGetIntCatchException(_FH_sofaArray)); }
 
 	/**
    * @see org.apache.uima.cas.SofaFS#getLocalStringData() 
    */
 	@Override
-  public String getLocalStringData() { return _getStringValueNc(_FI_sofaString); }
+  public String getLocalStringData() { return _getStringValueNc(wrapGetIntCatchException(_FH_sofaString)); }
 
 	/**
    * @see org.apache.uima.cas.SofaFS#setRemoteSofaURI(String) This method is duplicated in
@@ -197,7 +221,7 @@
   @Override
   public void setRemoteSofaURI(String aURI) {
     if (isSofaDataSet()) { throwAlreadySet("setRemoteSofaURI()"); }
-    _setStringValueNcWj(_FI_sofaURI, aURI);
+    _setStringValueNcWj(wrapGetIntCatchException(_FH_sofaURI), aURI);
   }
 	
 	public void setRemoteSofaURI(String aURI, String mimeType) {
@@ -212,14 +236,14 @@
 	}
 	
   @Override
-  public String getSofaMime() { return _getStringValueNc(_FI_mimeType); }
+  public String getSofaMime() { return _getStringValueNc(wrapGetIntCatchException(_FH_mimeType)); }
 
   @Override
-  public String getSofaURI() { return _getStringValueNc(_FI_sofaURI); }
+  public String getSofaURI() { return _getStringValueNc(wrapGetIntCatchException(_FH_sofaURI)); }
 
   // ** Note: this gets the feature named "sofaNum"
   @Override
-  public int getSofaRef() { return _getIntValueNc(_FI_sofaNum); }
+  public int getSofaRef() { return _getIntValueNc(wrapGetIntCatchException(_FH_sofaNum)); }
 
   @Override
   public InputStream getSofaDataStream() {
@@ -232,9 +256,9 @@
    *   - used in generic pretty printing routines
    * @return -
    */
-  public TOP getSofaArray() { return _getFeatureValueNc(_FI_sofaArray); }
+  public TOP getSofaArray() { return _getFeatureValueNc(wrapGetIntCatchException(_FH_sofaArray)); }
   
-  public String getSofaString() { return _getStringValueNc(_FI_sofaString); }
+  public String getSofaString() { return _getStringValueNc(wrapGetIntCatchException(_FH_sofaString)); }
     
 
 	// override setStringValue for SofaFS to prohibit setting in this manner!
@@ -258,5 +282,5 @@
 	  throw new CASRuntimeException(CASRuntimeException.SOFADATA_ALREADY_SET, msg);
 	}
 
-	public void setMimeType(String v) { _setStringValueNcWj(_FI_mimeType, v); }
+	public void setMimeType(String v) { _setStringValueNcWj(wrapGetIntCatchException(_FH_mimeType), v); }
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/StringArray.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/StringArray.java
index cf996c9..6528fb9 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/StringArray.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/StringArray.java
@@ -19,22 +19,25 @@
 
 package org.apache.uima.jcas.cas;
 
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
+import java.util.stream.Stream;
 
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CommonArrayFS;
-import org.apache.uima.cas.StringArrayFS;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.StringArrayFSImpl;
 import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.internal.util.Misc;
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 
 /** JCas class model for StringArray */
-public final class StringArray extends TOP implements Iterable<String>, CommonPrimitiveArray, StringArrayFSImpl {
+public final class StringArray extends TOP implements Iterable<String>, CommonPrimitiveArray<String>, StringArrayFSImpl {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.jcas.cas.StringArray";
+  public final static String _TypeName = CAS.TYPE_NAME_STRING_ARRAY;
 
   /**
    * Each cover class when loaded sets an index. Used in the JCas typeArray to go from the cover
@@ -72,8 +75,8 @@
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(length);
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2Size_arrays(length);
     }    
   }
 
@@ -90,8 +93,8 @@
     if (CASImpl.traceFSs) { // tracing done after array setting, skipped in super class
       _casView.traceFSCreate(this);
     }
-    if (CASImpl.IS_USE_V2_IDS) {
-      _casView.adjustLastFsV2size(length);
+    if (_casView.isId2Fs()) {
+      _casView.adjustLastFsV2Size_arrays(length);
     }    
   }
 
@@ -129,7 +132,7 @@
    * @see org.apache.uima.cas.StringArrayFS#toArray()
    */
   public String[] toArray() {
-    return theArray.clone();
+    return Arrays.copyOf(theArray, theArray.length);
   }
 
   /** return the size of the array */
@@ -186,10 +189,22 @@
    * @param a the source for the array's initial values
    * @return a newly created and populated array
    */
-  public static StringArray createFromArray(JCas jcas, String[] a) {
+  public static StringArray create(JCas jcas, String[] a) {
     StringArray stringArray = new StringArray(jcas, a.length);
     stringArray.copyFromArray(a, 0, 0, a.length);
     return stringArray;
   }
+  
+  /**
+   * @param v the compare object
+   * @return true if v is equal to one (or more) of the array elements
+   */
+  public boolean contains(String v) {
+    return Misc.contains(theArray, v);
+  }
+
+  public Stream<String> stream() {
+    return Arrays.stream(theArray);
+  }
 
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/StringList.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/StringList.java
index e9bc7d1..fbb8c65 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/StringList.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/StringList.java
@@ -21,9 +21,12 @@
 
 import java.util.Collections;
 import java.util.Iterator;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.internal.util.Misc;
 import org.apache.uima.jcas.JCas;
 
 public abstract class StringList extends TOP implements CommonList, Iterable<String> {
@@ -69,8 +72,8 @@
   } 
   
   @Override
-  public EmptyStringList getEmptyList() {
-    return this._casView.getEmptyStringList();
+  public EmptyStringList emptyList() {
+    return this._casView.emptyStringList();
   }
 
   /**
@@ -79,12 +82,30 @@
    * @param a the array of Strings to populate the list with
    * @return an StringList, with the elements from the array
    */
-  public static StringList createFromArray(JCas jcas, String[] a) {
-    StringList stringList = jcas.getCasImpl().getEmptyStringList();   
+  public static StringList create(JCas jcas, String[] a) {
+    StringList stringList = jcas.getCasImpl().emptyStringList();   
     for (int i = a.length - 1; i >= 0; i--) {
       stringList = stringList.push(a[i]);
     }   
     return stringList;
   }
   
+  /**
+   * @return a stream over this FSList
+   */
+  public Stream<String> stream() {
+    return StreamSupport.stream(spliterator(), false);
+  }
+ 
+  public boolean contains(String v) {
+    StringList node = this;
+    while (node instanceof NonEmptyStringList) {
+      NonEmptyStringList n = (NonEmptyStringList) node;
+      if (Misc.equalStrings(v, n.getHead())) {
+        return true;
+      }
+      node = n.getTail();
+    }
+    return false;
+  }
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/TOP.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/TOP.java
index 86ddfea..3197b60 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/TOP.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/TOP.java
@@ -19,6 +19,7 @@
 
 package org.apache.uima.jcas.cas;
 
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.FeatureStructureImplC;
 import org.apache.uima.cas.impl.TypeImpl;
@@ -36,7 +37,7 @@
 public class TOP extends FeatureStructureImplC {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.jcas.cas.TOP";
+  public final static String _TypeName = CAS.TYPE_NAME_TOP; // the official xml name
 	/**
    * Each cover class when loaded sets an index. Used in the JCas typeArray to go from the cover
    * class or class instance to the corresponding instance of the _Type class
@@ -87,11 +88,11 @@
 	}
 
   public static TOP _createSearchKey(int id) {
-    return new TOP(id);
+    return new TOP(id);  // special super class, does nothing except create this TOP instance
   }
   
   /**
-   * for internal use only
+   * for internal use only, creates a reserved marker
    * @param id -
    * @return -
    */
@@ -101,5 +102,8 @@
     return r;
   }
 
+  /**
+   * Internal use - used as removed marker in maps 
+   */
 	final public static TOP _singleton = new TOP();
 }
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 9e1c300..f8e33b7 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
@@ -19,10 +19,12 @@
 
 package org.apache.uima.jcas.impl;
 
+import java.util.NoSuchElementException;
 import java.util.function.IntFunction;
 
 import org.apache.uima.internal.util.Misc;
 import org.apache.uima.jcas.cas.TOP;
+import org.apache.uima.util.IteratorNvc;
 
 /**
  * Version 3 (2016, for Java 8) of map between id's (ints) JCasCover Objects
@@ -114,7 +116,7 @@
  *   putIfAbsent(value-to-be-computed, as an IntSupplier)
  *   get
  */
-public class JCasHashMap {
+public class JCasHashMap implements Iterable<TOP> {
 
   // set to true to collect statistics for tuning
   // you have to also put a call to jcas.showJfsFromCaddrHistogram() at the end of the run
@@ -282,7 +284,7 @@
     return (null != oneSubmap) ? oneSubmap : subMaps[hash & concurrencyBitmask];
   }
   
-  public TOP putIfAbsent(int key, IntFunction<TOP> creator) {
+  public final TOP putIfAbsent(int key, IntFunction<TOP> creator) {
     final int hash = hashInt(key);
     final TOP r = getSubMap(hash).putIfAbsent(key, hash >>> concurrencyLevelBits, creator);
     return r;
@@ -292,7 +294,7 @@
    * @param key -
    * @return the item or null
    */
-  public TOP get(int key) {
+  public final TOP get(int key) {
     final int hash = hashInt(key);
     final TOP r = getSubMap(hash).get(key, hash >>> concurrencyLevelBits);
     return r;
@@ -302,7 +304,7 @@
    * @param value -
    * @return previous value or null
    */
-  public TOP put(TOP value) {
+  public final TOP put(TOP value) {
     return put (value._id(), value);
   }
   
@@ -328,12 +330,12 @@
   private static final int C2 = 0x1b873593;
   private static final int seed = 0x39c2ab57;  // arbitrary bunch of bits
 
-  public static int hashInt(int k1) {
+  public static final int hashInt(int k1) {
     k1 *= C1;
     k1 = Integer.rotateLeft(k1, 15);
     k1 *= C2;
     
-    int h1 = seed ^ k1;
+    int h1 = seed ^ k1;  // bitwise exclusive or
     h1 = Integer.rotateLeft(h1, 13);
     h1 = h1 * 5 + 0xe6546b64;
     
@@ -355,6 +357,16 @@
     return r;
   }
   
+  // test case use
+  int[] getSubSizes() {
+    int[] r = new int[subMaps.length];
+    int i = 0;
+    for (JCasHashMapSubMap subMap : subMaps) {
+      r[i++] = subMap.size;
+    }
+    return r;
+  }
+  
   int getCapacity() {
     int r = 0;
     for (JCasHashMapSubMap subMap : subMaps) {
@@ -409,6 +421,44 @@
   public int getConcurrencyLevel() {
     return concurrencyLevel;
   }
+
+  @Override
+  public IteratorNvc<TOP> iterator() {
+    return new IteratorNvc<TOP>() {
+      int i_submap = 0;
+      IteratorNvc<TOP> current_iterator = subMaps[0].iterator();
+      
+      { maybeMoveToNextValidSubmap(); }
+      
+      void maybeMoveToNextValidSubmap() {
+        while (!current_iterator.hasNext()) {
+          i_submap ++;
+          if (i_submap >= subMaps.length) {
+            return;
+          }
+          current_iterator = subMaps[i_submap].iterator();
+        }
+      }
+      
+      @Override
+      public boolean hasNext() {
+        maybeMoveToNextValidSubmap();
+        return i_submap < subMaps.length;
+      }
+
+      @Override
+      public TOP next() {
+        if (!hasNext()) throw new NoSuchElementException();
+        return nextNvc(); 
+      }
+      
+      @Override
+      public TOP nextNvc() {
+        return current_iterator.nextNvc();
+      }
+      
+    };
+  }
     
 //  private static final Thread dumpMeasurements = MEASURE_CACHE ? new Thread(new Runnable() {
 //    @Override
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/impl/JCasHashMapSubMap.java b/uimaj-core/src/main/java/org/apache/uima/jcas/impl/JCasHashMapSubMap.java
index 8a2e59a..4523bc1 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/impl/JCasHashMapSubMap.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/impl/JCasHashMapSubMap.java
@@ -21,16 +21,18 @@
 

 

 import java.util.Arrays;

+import java.util.NoSuchElementException;

 import java.util.function.IntFunction;

 

 import org.apache.uima.internal.util.Misc;

 import org.apache.uima.jcas.cas.TOP;

+import org.apache.uima.util.IteratorNvc;

 

 /**

  * Part of the JCasHashMap.

  * There are multiple instances of this class, one per concurrancy level

  */

-class JCasHashMapSubMap {

+class JCasHashMapSubMap implements Iterable<TOP> {

   

   // set to true to collect statistics for tuning

   // you have to also put a call to jcas.showJfsFromCaddrHistogram() at the end of the run

@@ -163,9 +165,9 @@
     

     int probeDelta = probeInfo[PROBE_DELTA_INDEX];

     //debug

-    if (probeDelta <= 0) {

-      System.out.println("debug");

-    }

+//    if (probeDelta <= 0) {

+//      System.out.println("debug");

+//    }

     assert probeDelta > 0;

     

     // Next modification is overall, slower (very slightly)

@@ -471,7 +473,7 @@
    * @param creator - the new value

    * @return - the previous fs in the table with the same key, or null

    */

-  TOP put(final int key, final TOP value, final int hash) {

+  final TOP put(final int key, final TOP value, final int hash) {

 

     final int[] probeInfo = probeInfoGet.get();

     resetProbeInfo(probeInfo);

@@ -511,7 +513,7 @@
    * @param hash - the hash that was already computed from the key

    * @return - the found fs, or null

    */

-  TOP get(final int key, final int hash) {

+  final TOP get(final int key, final int hash) {

 

     final int[] probeInfo = probeInfoGet.get();

     resetProbeInfo(probeInfo);

@@ -609,6 +611,41 @@
     }

     return find(table, key, hash, probeInfo);

   }

+

+  @Override

+  public IteratorNvc<TOP> iterator() {

+    return new IteratorNvc<TOP>() {

+      int i = moveToNextValid(0);

+

+      @Override

+      public boolean hasNext() {

+        return i < table.length;

+      }

+

+      @Override

+      public TOP next() {

+        if (!hasNext()) throw new NoSuchElementException();

+        return nextNvc();

+      }

+      

+      @Override

+      public TOP nextNvc() {

+        TOP r = table[i];

+        i = moveToNextValid(i+1);

+        return r;        

+      }

+      

+      int moveToNextValid(int pos) {

+        while (pos < table.length && 

+               (table[pos] == null || 

+                table[pos]._isJCasHashMapReserve())) {

+          pos ++;

+        }

+        return pos;

+      }

+    };

+    

+  }

   

 //  private void lockit() {

 //    // might have recursive locking on same thread if creator invokes this recursively

diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/impl/JCasImpl.java b/uimaj-core/src/main/java/org/apache/uima/jcas/impl/JCasImpl.java
index 4415899..7dd3176 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/impl/JCasImpl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/impl/JCasImpl.java
@@ -55,9 +55,13 @@
 import org.apache.uima.cas.text.AnnotationIndex;
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JFSIndexRepository;
+import org.apache.uima.jcas.cas.ByteArray;
+import org.apache.uima.jcas.cas.DoubleArray;
 import org.apache.uima.jcas.cas.FSArray;
 import org.apache.uima.jcas.cas.FloatArray;
 import org.apache.uima.jcas.cas.IntegerArray;
+import org.apache.uima.jcas.cas.LongArray;
+import org.apache.uima.jcas.cas.ShortArray;
 import org.apache.uima.jcas.cas.Sofa;
 import org.apache.uima.jcas.cas.StringArray;
 import org.apache.uima.jcas.cas.TOP;
@@ -151,33 +155,12 @@
   // * We keep one copy per CAS view set          *
   // **********************************************/
   
-  private static class JCasSharedView {
-    // ********************************************************
-    // * Access to this data is assumed to be single threaded *
-    // ********************************************************
-
-    /* convenience holders of CAS constants that may be useful *
-     * initialization done lazily - on first call to getter    *
-     *   Can't be static because needs ref to a JCas instance  */
-
-    public StringArray stringArray0L = null;
-
-    public IntegerArray integerArray0L = null;
-
-    public FloatArray floatArray0L = null;
-
-    public FSArray fsArray0L = null;
-       
-  }
-
   // *******************
   // * Data per (J)CAS *
   // * There may be multiples of these for one base CAS - one per "view"
   // * Access to this data is assumed to be single threaded
   // *******************
 
-  private final JCasSharedView sharedView;
-
   // not public to protect it from accidents
   private final CASImpl casImpl;
 
@@ -286,7 +269,6 @@
 
   // never called, but have to set values to null because they're final
   private JCasImpl() {
-    sharedView = null;
     casImpl = null;
     ll_IndexRepository = null;
     throw new RuntimeException("JCas constructor with no args called, should never be called.");
@@ -311,20 +293,7 @@
     // * that will be loaded.
 
     this.casImpl = cas;
-    
-    /**
-     * create the shared view only for the base case.
-     *   if not the base cas, 
-     *     switch to the base cas, 
-     *     create the shared view if needed
-     *     use that as the shared view
-     */
-    if (casImpl != casImpl.getBaseCAS()) {
-      sharedView = ((JCasImpl) casImpl.getBaseCAS().getJCas()).sharedView;
-    } else {
-      sharedView = new JCasSharedView();
-    }
-
+ 
     this.ll_IndexRepository = casImpl.ll_getIndexRepository();
     this.jfsIndexRepository = new JFSIndexRepositoryImpl(this, cas.getIndexRepository());
   }
@@ -655,19 +624,6 @@
    * associations. 
    */
   public static void clearData(CAS cas) {
-//    JCasImpl jcas = (JCasImpl) ((CASImpl) cas).getExistingJCas();
-//    final JCasSharedView sv = jcas.sharedView;
-//    for (Iterator<Map.Entry<ClassLoader, JCasHashMap>> it = sv.cAddr2JfsByClassLoader.entrySet().iterator(); it.hasNext();) {
-//      Map.Entry<ClassLoader, JCasHashMap> e = it.next();
-//      sv.cAddr2Jfs = e.getValue();
-//      sv.cAddr2Jfs.clear();  // implements resize as well
-//      sv.stringArray0L = null;
-//      sv.floatArray0L = null;
-//      sv.fsArray0L = null;
-//      sv.integerArray0L = null;
-//    }
-//    sv.cAddr2Jfs = sv.cAddr2JfsByClassLoader
-//        .get(((CASImpl) cas).getJCasClassLoader());
   }
 
   /*
@@ -678,7 +634,7 @@
   public void reset() {
     casImpl.reset();
   }
-
+  
 //  /*
 //   * (non-Javadoc)
 //   * 
@@ -910,45 +866,44 @@
    * (non-Javadoc)
    * 
    * @see org.apache.uima.jcas.JCas#getStringArray0L()
+   * @deprecated use emptyXXXArray() instead
    */
-
+  @Deprecated
   public StringArray getStringArray0L() {
-    if (null == sharedView.stringArray0L)
-      sharedView.stringArray0L = new StringArray(this, 0);
-    return sharedView.stringArray0L;
+    return this.getCas().emptyStringArray();
   }
 
   /*
    * (non-Javadoc)
    * 
    * @see org.apache.uima.jcas.JCas#getIntegerArray0L()
+   * @deprecated use emptyXXXArray() instead
    */
+  @Deprecated
   public IntegerArray getIntegerArray0L() {
-    if (null == sharedView.integerArray0L)
-      sharedView.integerArray0L = new IntegerArray(this, 0);
-    return sharedView.integerArray0L;
+    return this.getCas().emptyIntegerArray();
   }
 
   /*
    * (non-Javadoc)
    * 
    * @see org.apache.uima.jcas.JCas#getFloatArray0L()
+   * @deprecated use emptyXXXArray() instead
    */
+  @Deprecated
   public FloatArray getFloatArray0L() {
-    if (null == sharedView.floatArray0L)
-      sharedView.floatArray0L = new FloatArray(this, 0);
-    return sharedView.floatArray0L;
+    return this.getCas().emptyFloatArray();
   }
-
+  
   /*
    * (non-Javadoc)
    * 
    * @see org.apache.uima.jcas.JCas#getFSArray0L()
+   * @deprecated use emptyXXXArray() instead
    */
+  @Deprecated
   public FSArray getFSArray0L() {
-    if (null == sharedView.fsArray0L)
-      sharedView.fsArray0L = new FSArray(this, 0);
-    return sharedView.fsArray0L;
+    return this.getCas().emptyFSArray();
   }
 
   /*
@@ -1198,6 +1153,4 @@
   public <T extends TOP> FSIndex<T> getIndex(String label, Class<T> clazz) {
     return getFSIndexRepository().getIndex(label, getCasType(clazz));
   }
-
-  
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/tcas/Annotation.java b/uimaj-core/src/main/java/org/apache/uima/jcas/tcas/Annotation.java
index 35f5965..c7e4e5d 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/tcas/Annotation.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/tcas/Annotation.java
@@ -19,12 +19,15 @@
 
 package org.apache.uima.jcas.tcas;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.admin.LinearTypeOrder;
 import org.apache.uima.cas.impl.AnnotationImpl;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
-import org.apache.uima.cas.text.AnnotationFS;
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 import org.apache.uima.jcas.cas.AnnotationBase;
@@ -37,7 +40,7 @@
 public class Annotation extends AnnotationBase implements AnnotationImpl {
 
   /* public static string for use where constants are needed, e.g. in some Java Annotations */
-  public final static String _TypeName = "org.apache.uima.jcas.cas.Annotation";
+  public final static String _TypeName = CAS.TYPE_NAME_ANNOTATION;
   public final static String _FeatName_begin = "begin";
   public final static String _FeatName_end = "end";
 
@@ -49,14 +52,25 @@
     return typeIndexID;
   }
   
-  public final static int _FI_begin = TypeSystemImpl.getAdjustedFeatureOffset("begin");
-  public final static int _FI_end   = TypeSystemImpl.getAdjustedFeatureOffset("end");
+  private final static CallSite _FC_begin = TypeSystemImpl.createCallSite(Annotation.class, "begin");
+  private final static MethodHandle _FH_begin = _FC_begin.dynamicInvoker();
+  private final static CallSite _FC_end = TypeSystemImpl.createCallSite(Annotation.class, "end");
+  private final static MethodHandle _FH_end = _FC_end.dynamicInvoker();
+
+//  static {
+//    _FC_begin.setTarget(MethodHandles.constant(int.class, TypeSystemImpl.getAdjustedFeatureOffset("begin")));
+//  }
+  
+  
+//  private final static int _FI_begin = TypeSystemImpl.getAdjustedFeatureOffset("begin");
+//  private final static int _FI_end   = TypeSystemImpl.getAdjustedFeatureOffset("end");
   
 //  /* local data */
 //  private int _F_begin;
 //  private int _F_end;
 
   // Never called. Disable default constructor
+  @Deprecated
   protected Annotation() {
   }
 
@@ -83,13 +97,13 @@
    * getter for begin - gets beginning of span of annotation
    */
 //  public int getBegin() { return _F_begin; }
-  public int getBegin() { return _getIntValueNc(_FI_begin); 
+  public final int getBegin() { return _getIntValueNc( wrapGetIntCatchException(_FH_begin)); 
   }
 
   /*
    * setter for begin - sets beginning of span of annotation
    */
-  public void setBegin(int v) { _setIntValueNfcCJ(_FI_begin, v); }
+  public final void setBegin(int v) { _setIntValueNfcCJ( wrapGetIntCatchException(_FH_begin), v); }
   
   // *------------------*
   // * Feature: end
@@ -98,15 +112,15 @@
   /*
    * getter for end - gets ending of span of annotation
    */
-  public int getEnd() { 
-    return this._getIntValueNc(_FI_end);
+  public final int getEnd() { 
+    return this._getIntValueNc(wrapGetIntCatchException(_FH_end));
   }
 
   /*
    * setter for end - sets ending of span of annotation
    */
-  public void setEnd(int v) {
-    this._setIntValueNfc(_FI_end,  v);
+  public final void setEnd(int v) {
+    this._setIntValueNfc(wrapGetIntCatchException(_FH_end),  v);
   }
   
   /**
@@ -117,8 +131,8 @@
    */
   public Annotation(JCas jcas, int begin, int end) {
     super(jcas); // forward to constructor
-    this._setIntValueNcNj(_FI_begin, begin);
-    this._setIntValueNcNj(_FI_end, end);
+    this._setIntValueNcNj( wrapGetIntCatchException(_FH_begin), begin);
+    this._setIntValueNcNj(wrapGetIntCatchException(_FH_end), end);
   }
 
   /**
@@ -149,11 +163,13 @@
    * @param other -
    * @return -
    */
-  public int compareAnnotation(Annotation other) {
-    int result = Integer.compare(_getIntValueNc(_FI_begin), other._getIntValueNc(_FI_begin));
+  public final int compareAnnotation(Annotation other) {
+    final int b = wrapGetIntCatchException(_FH_begin);
+    int result = Integer.compare(_getIntValueNc(b), other._getIntValueNc(b));
     if (result != 0) return result;
 
-    result = Integer.compare(_getIntValueNc(_FI_end), other._getIntValueNc(_FI_end));
+    final int e = wrapGetIntCatchException(_FH_end);
+    result = Integer.compare(_getIntValueNc(e), other._getIntValueNc(e));
     return (result == 0) ? 0 : -result;  // reverse compare
   }
   
@@ -163,7 +179,7 @@
    * @param lto -
    * @return -
    */
-  public int compareAnnotation(Annotation other, LinearTypeOrder lto) {
+  public final int compareAnnotation(Annotation other, LinearTypeOrder lto) {
     int result = compareAnnotation(other);
     if (result != 0) return result;
     
@@ -176,7 +192,7 @@
    * @param other -
    * @return -
    */
-  public int compareAnnotationWithId(Annotation other) {
+  public final int compareAnnotationWithId(Annotation other) {
     int result = compareAnnotation(other);
     if (result != 0) return result;    
     return Integer.compare(_id,  other._id);
@@ -188,7 +204,7 @@
    * @param lto -
    * @return -
    */
-  public int compareAnnotationWithId(Annotation other, LinearTypeOrder lto) {
+  public final int compareAnnotationWithId(Annotation other, LinearTypeOrder lto) {
     int result = compareAnnotation(other, lto);
     if (result != 0) return result;    
     return Integer.compare(_id,  other._id);
diff --git a/uimaj-core/src/main/java/org/apache/uima/pear/util/XMLUtil.java b/uimaj-core/src/main/java/org/apache/uima/pear/util/XMLUtil.java
index 16a04c2..a990ab3 100644
--- a/uimaj-core/src/main/java/org/apache/uima/pear/util/XMLUtil.java
+++ b/uimaj-core/src/main/java/org/apache/uima/pear/util/XMLUtil.java
@@ -35,6 +35,7 @@
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
 
+import org.apache.uima.internal.util.XMLUtils;
 import org.xml.sax.SAXException;
 import org.xml.sax.SAXParseException;
 import org.xml.sax.helpers.DefaultHandler;
@@ -124,7 +125,7 @@
     SAXParser parser = null;
     try {
       // get SAX parser factory
-      SAXParserFactory factory = SAXParserFactory.newInstance();
+      SAXParserFactory factory = XMLUtils.createSAXParserFactory();
       // set default SAX parser features
       factory.setFeature(NAMESPACES_FEATURE_ID, DEFAULT_NAMESPACES);
       factory.setFeature(NAMESPACE_PREFIXES_FEATURE_ID, DEFAULT_NAMESPACE_PREFIXES);
diff --git a/uimaj-core/src/main/java/org/apache/uima/resource/ResourceConfigurationException.java b/uimaj-core/src/main/java/org/apache/uima/resource/ResourceConfigurationException.java
index 3f22501..8293476 100644
--- a/uimaj-core/src/main/java/org/apache/uima/resource/ResourceConfigurationException.java
+++ b/uimaj-core/src/main/java/org/apache/uima/resource/ResourceConfigurationException.java
@@ -107,6 +107,11 @@
   public static final String EXTERNAL_OVERRIDE_NUMERIC_ERROR = "external_override_numeric_error";
   
   /**
+   * Message key for a standard UIMA exception message: External override variable "{0}" has a circular reference to itself
+   */
+  public static final String EXTERNAL_OVERRIDE_CIRCULAR_REFERENCE = "external_override_circular_reference";
+  
+  /**
    * Creates a new exception with a null message.
    */
   public ResourceConfigurationException() {
diff --git a/uimaj-core/src/main/java/org/apache/uima/resource/ResourceManager.java b/uimaj-core/src/main/java/org/apache/uima/resource/ResourceManager.java
index 6bfe743..9add605 100644
--- a/uimaj-core/src/main/java/org/apache/uima/resource/ResourceManager.java
+++ b/uimaj-core/src/main/java/org/apache/uima/resource/ResourceManager.java
@@ -25,6 +25,7 @@
 import java.util.List;
 import java.util.Map;
 
+import org.apache.uima.resource.impl.ResourceManager_impl;
 import org.apache.uima.resource.metadata.ResourceManagerConfiguration;
 import org.apache.uima.util.XMLizable;
 
@@ -331,6 +332,17 @@
           throws MalformedURLException;
 
   /**
+   * Set an extension class loader into the Resource Manager
+   * @param classLoader the loader to use.  If this is an instance of UIMAClassLoader, it is
+   *               used directly; otherwise, a new UIMAClassLoader with no classpath, having
+   *               the classLoader as a parent is created and used.
+   * @param resolveResources true to also use this to resolve resources
+   */
+  default void setExtensionClassLoader(ClassLoader classLoader, boolean resolveResources) {
+    ((ResourceManager_impl)this).setExtensionClassLoaderImpl(classLoader, resolveResources);
+  }
+  
+  /**
    * Returns the UIMA extension class loader.
    * 
    * @return ClassLoader - returns the UIMA extension class loader of null if it is not available.
diff --git a/uimaj-core/src/main/java/org/apache/uima/resource/Resource_ImplBase.java b/uimaj-core/src/main/java/org/apache/uima/resource/Resource_ImplBase.java
index 11147d2..3a5c6b4 100644
--- a/uimaj-core/src/main/java/org/apache/uima/resource/Resource_ImplBase.java
+++ b/uimaj-core/src/main/java/org/apache/uima/resource/Resource_ImplBase.java
@@ -26,6 +26,11 @@
 import org.apache.uima.UIMA_IllegalStateException;
 import org.apache.uima.UimaContext;
 import org.apache.uima.UimaContextAdmin;
+import org.apache.uima.UimaContextHolder;
+import org.apache.uima.analysis_engine.AnalysisEngine;
+import org.apache.uima.impl.UimaContext_ImplBase;
+import org.apache.uima.impl.Util;
+import org.apache.uima.internal.util.function.Runnable_withException;
 import org.apache.uima.resource.impl.RelativePathResolver_impl;
 import org.apache.uima.resource.impl.ResourceManager_impl;
 import org.apache.uima.resource.metadata.ResourceManagerConfiguration;
@@ -65,6 +70,7 @@
    * multi-thread safe, given that each instance of this class is only called on one thread, once.
    * The critical parts that update shared information (in shared uima context) are inside a synchronize block
    */
+  @Override
   public boolean initialize(ResourceSpecifier aSpecifier, Map<String, Object> aAdditionalParams)
           throws ResourceInitializationException {
 
@@ -114,6 +120,12 @@
 
         // create and initialize UIMAContext
         mUimaContextAdmin = UIMAFramework.newUimaContext(logger, resMgr, configMgr);
+        if (aAdditionalParams != null) {
+          Object limit = aAdditionalParams.get(AnalysisEngine.PARAM_THROTTLE_EXCESSIVE_ANNOTATOR_LOGGING);
+          if (limit != null) {
+            ((UimaContext_ImplBase)mUimaContextAdmin).setLoggingThrottleLimit((Integer)limit);
+          }
+        }
       }
     } else {
       // configure logger of the UIMA context so that class-specific logging
@@ -162,7 +174,7 @@
           }
         }
       }
-
+      
       // initialize configuration
       try {
         // createContext checks and skips repeated calls with same args (on different threads, for example)
@@ -176,36 +188,42 @@
       }
 
       // initialize any external resource declared in this descriptor
+      // UIMA-5274  Set & restore the UimaContextHolder so that resources created on this thread can use the Settings
       ResourceManagerConfiguration resMgrCfg = ((ResourceCreationSpecifier) aSpecifier)
               .getResourceManagerConfiguration();
       if (resMgrCfg != null) {
+        UimaContext prevContext = UimaContextHolder.setContext(mUimaContextAdmin);
         try {
-          resMgrCfg.resolveImports(getResourceManager());
-        } catch (InvalidXMLException e) {
-          throw new ResourceInitializationException(e);
-        }
-        if (aAdditionalParams == null) {
+          try {
+            resMgrCfg.resolveImports(getResourceManager());
+          } catch (InvalidXMLException e) {
+            throw new ResourceInitializationException(e);
+          }
+          if (aAdditionalParams == null) {
             aAdditionalParams = new HashMap<String, Object>();
             aAdditionalParams.put(PARAM_RESOURCE_MANAGER, mUimaContextAdmin.getResourceManager());
-        } else {
-          if (!aAdditionalParams.containsKey(PARAM_RESOURCE_MANAGER)) {
-            // copy in case original is shared on multi-threads, or 
-            // is unmodifiable
-            // and to avoid updating passed - in map
-            aAdditionalParams = new HashMap<String, Object>(aAdditionalParams);
-            aAdditionalParams.put(PARAM_RESOURCE_MANAGER, mUimaContextAdmin.getResourceManager());
+          } else {
+            if (!aAdditionalParams.containsKey(PARAM_RESOURCE_MANAGER)) {
+              // copy in case original is shared on multi-threads, or
+              // is unmodifiable
+              // and to avoid updating passed - in map
+              aAdditionalParams = new HashMap<String, Object>(aAdditionalParams);
+              aAdditionalParams.put(PARAM_RESOURCE_MANAGER, mUimaContextAdmin.getResourceManager());
+            }
           }
+          // initializeExternalResources is synchronized
+
+          // https://issues.apache.org/jira/browse/UIMA-5153
+          final HashMap<String, Object> aAdditionalParmsForExtResources = new HashMap<String, Object>(aAdditionalParams); // copy in case
+          if (aAdditionalParmsForExtResources.get(PARAM_UIMA_CONTEXT) == null) {
+            aAdditionalParmsForExtResources.put(PARAM_UIMA_CONTEXT, mUimaContextAdmin);
+          }
+
+          mUimaContextAdmin.getResourceManager().initializeExternalResources(resMgrCfg,
+                  mUimaContextAdmin.getQualifiedContextName(), aAdditionalParmsForExtResources);
+        } finally {
+          UimaContextHolder.setContext(prevContext);
         }
-        // initializeExternalResources is synchronized
-        
-        // https://issues.apache.org/jira/browse/UIMA-5153
-        final HashMap<String, Object> aAdditionalParmsForExtResources = new HashMap<String, Object>(aAdditionalParams); // copy in case
-        if (aAdditionalParmsForExtResources.get(PARAM_UIMA_CONTEXT) == null) {
-          aAdditionalParmsForExtResources.put(PARAM_UIMA_CONTEXT, mUimaContextAdmin);
-        }
-        
-        mUimaContextAdmin.getResourceManager().initializeExternalResources(resMgrCfg,
-                mUimaContextAdmin.getQualifiedContextName(), aAdditionalParmsForExtResources);
       }
 
       // resolve and validate this component's external resource dependencies
@@ -224,12 +242,14 @@
   /**
    * @see org.apache.uima.resource.Resource#destroy()
    */
+  @Override
   public void destroy() {
   }
 
   /**
    * @see org.apache.uima.resource.Resource#getMetaData()
    */
+  @Override
   public ResourceMetaData getMetaData() {
     return mMetaData;
   }
@@ -252,6 +272,7 @@
    * Get the logger for this UIMA framework class.
    * Note that this is NOT the user's logger in the UimaContext
    */
+  @Override
   public Logger getLogger() {
     return UIMAFramework.getLogger(this.getClass());
   }
@@ -259,6 +280,7 @@
   /**
    * Set the logger in the current UimaContext for use by user annotators. 
    */
+  @Override
   public void setLogger(Logger aLogger) {
     if (getUimaContext() != null) {
       getUimaContextAdmin().setLogger(aLogger);
@@ -268,6 +290,7 @@
   /**
    * @see org.apache.uima.resource.Resource#getResourceManager()
    */
+  @Override
   public ResourceManager getResourceManager() {
     if (getUimaContextAdmin() != null)
       return getUimaContextAdmin().getResourceManager();
@@ -280,6 +303,7 @@
    * 
    * @see org.apache.uima.resource.Resource#getUimaContext()
    */
+  @Override
   public UimaContext getUimaContext() {
     return mUimaContextAdmin;
   }
@@ -287,6 +311,7 @@
   /**
    * Gets the Admin interface to this Resource's UimaContext.
    */
+  @Override
   public UimaContextAdmin getUimaContextAdmin() {
     return mUimaContextAdmin;
   }
@@ -319,5 +344,17 @@
     }
     return relPathResolver;
   }
+
+  public void withContextHolder(Runnable userCode) {
+    Util.withContextHolder(getUimaContext(), userCode);
+  }
   
+  public void setContextHolderX(Runnable_withException userCode) throws Exception {
+    Util.withContextHolderX(getUimaContext(), userCode);
+  } 
+  
+  public UimaContext setContextHolder() {
+    return UimaContextHolder.setContext(getUimaContext());
+  }
+
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/resource/impl/FileResourceSpecifier_impl.java b/uimaj-core/src/main/java/org/apache/uima/resource/impl/FileResourceSpecifier_impl.java
index 7eb388f..e395ef7 100644
--- a/uimaj-core/src/main/java/org/apache/uima/resource/impl/FileResourceSpecifier_impl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/resource/impl/FileResourceSpecifier_impl.java
@@ -47,9 +47,19 @@
   }
 
   /**
+   * UIMA-5274  Expand any references to external overrides when name and location are fetched.
+   * Cache the value if the evaluation succeeds (later fetches may not have the settings defined!)
+   * Leave value unmodified if any settings are undefined and log a warning message.
+   * 
    * @see org.apache.uima.resource.FileResourceSpecifier#getFileUrl()
    */
   public String getFileUrl() {
+    if (mFileUrl != null && mFileUrl.contains("${")) {
+      String value = resolveSettings(mFileUrl);
+      if (value != null) {
+        mFileUrl = value;
+      }
+    }
     return mFileUrl;
   }
 
diff --git a/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManager_impl.java b/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManager_impl.java
index aead6f3..b96ac92 100644
--- a/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManager_impl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/resource/impl/ResourceManager_impl.java
@@ -99,7 +99,9 @@
    */
   protected static final String LOG_RESOURCE_BUNDLE = "org.apache.uima.impl.log_messages";
   
-  protected static final Class<Resource> EMPTY_RESOURCE_CLASS = Resource.class; 
+  protected static final Class<Resource> EMPTY_RESOURCE_CLASS = Resource.class;
+
+  private static final URL[] emptyURLarray = new URL[0]; 
 
   private AtomicBoolean isDestroyed = new AtomicBoolean(false);
   /**
@@ -327,6 +329,19 @@
     }
   }
 
+  // https://issues.apache.org/jira/browse/UIMA-5553
+  // https://issues.apache.org/jira/browse/UIMA-5609
+  // synchronized because the other methods that set the extension class loader are.
+  public synchronized void setExtensionClassLoaderImpl(ClassLoader classLoader, boolean resolveResource) {
+    uimaCL = (classLoader instanceof UIMAClassLoader) 
+               ? ((UIMAClassLoader) classLoader)
+               : new UIMAClassLoader(emptyURLarray, classLoader);
+    if (resolveResource) {
+      // set UIMA extension ClassLoader also to resolve resources
+      getRelativePathResolver().setPathResolverClassLoader(uimaCL);
+    }
+  }
+  
   /**
    * @see org.apache.uima.resource.ResourceManager#getExtensionClassLoader()
    */
diff --git a/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/Import_impl.java b/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/Import_impl.java
index 9609d8d..17aecf6 100644
--- a/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/Import_impl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/Import_impl.java
@@ -27,7 +27,6 @@
 import org.apache.uima.resource.metadata.Import;
 import org.apache.uima.util.InvalidXMLException;
 import org.apache.uima.util.Level;
-import org.apache.uima.util.Logger;
 import org.apache.uima.util.XMLParser;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -42,6 +41,11 @@
 public class Import_impl extends MetaDataObject_impl implements Import {
   
   private static final long serialVersionUID = 6876757002913848998L;
+  
+  /**
+   * resource bundle for log messages
+   */
+  protected static final String LOG_RESOURCE_BUNDLE = "org.apache.uima.impl.log_messages";
 
   private String mName;
 
@@ -50,11 +54,23 @@
   private String byNameSuffix = ".xml";
 
   /*
+   * UIMA-5274  Expand any references to external overrides when name and location are fetched.
+   * Cache the value if the evaluation succeeds (later fetches may not have the settings defined!)
+   * Leave value unmodified if any settings are undefined.
+   */
+
+  /*
    * (non-Javadoc)
    * 
    * @see org.apache.uima.resource.metadata.Import#getName()
    */
   public String getName() {
+    if (mName != null && mName.contains("${")) {
+      String value = resolveSettings(mName);
+      if (value != null) {  // Success!
+        mName = value;
+      }
+    }
     return mName;
   }
 
@@ -73,6 +89,12 @@
    * @see org.apache.uima.resource.metadata.Import#getLocation()
    */
   public String getLocation() {
+    if (mLocation != null && mLocation.contains("${")) {
+      String value = resolveSettings(mLocation);
+      if (value != null) {
+        mLocation = value;
+      }
+    }
     return mLocation;
   }
 
@@ -98,22 +120,26 @@
    * @see org.apache.uima.resource.metadata.Import#findAbsoluteUrl(org.apache.uima.resource.ResourceManager)
    */
   public URL findAbsoluteUrl(ResourceManager aResourceManager) throws InvalidXMLException {
-    Logger logger = UIMAFramework.getLogger(this.getClass());
-    if (getLocation() != null) {
+    String location, name;
+    if ((location=getLocation()) != null) {
       try {
-        URL url = new URL(this.getRelativePathBase(), getLocation());
-        logger.log(Level.CONFIG, "Import by location: " + url);
+        URL url = new URL(this.getRelativePathBase(), location);
+        UIMAFramework.getLogger(this.getClass()).logrb(Level.CONFIG, this.getClass().getName(),
+                "findAbsoluteUrl", LOG_RESOURCE_BUNDLE, "UIMA_import_by__CONFIG",
+                new Object[] {"location", url});
         return url;
       } catch (MalformedURLException e) {
         throw new InvalidXMLException(InvalidXMLException.MALFORMED_IMPORT_URL, new Object[] {
-            getLocation(), getSourceUrlString() }, e);
+            location, getSourceUrlString() }, e);
       }
-    } else if (getName() != null) {
-      String filename = getName().replace('.', '/') + byNameSuffix;
+    } else if ((name=getName()) != null) {
+      String filename = name.replace('.', '/') + byNameSuffix;
       URL url;
       try {
         url = aResourceManager.resolveRelativePath(filename);
-        logger.log(Level.CONFIG, "Import by name: " + url);
+        UIMAFramework.getLogger(this.getClass()).logrb(Level.CONFIG, this.getClass().getName(),
+                "findAbsoluteUrl", LOG_RESOURCE_BUNDLE, "UIMA_import_by__CONFIG",
+                new Object[] {"name", url});
       } catch (MalformedURLException e) {
         throw new InvalidXMLException(InvalidXMLException.IMPORT_BY_NAME_TARGET_NOT_FOUND,
                 new Object[] { filename, getSourceUrlString() }, e);
@@ -178,11 +204,13 @@
     
     String namespace = getXmlizationInfo().namespace;
     AttributesImpl attrs = new AttributesImpl();
-    if (getName() != null) {
-      attrs.addAttribute("", "name", "name", "", getName());
+    String name = getName();
+    if (name != null) {
+      attrs.addAttribute("", "name", "name", "", name);
     }
-    if (getLocation() != null) {
-      attrs.addAttribute("", "location", "location", "", getLocation());
+    String location = getLocation();
+    if (location != null) {
+      attrs.addAttribute("", "location", "location", "", location);
     }
     Node node = serializer.findMatchingSubElement("import");
     serializer.outputStartElement(node, namespace, "import", "import", attrs);
diff --git a/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/MetaDataObject_impl.java b/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/MetaDataObject_impl.java
index 715b7fe..b248165 100644
--- a/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/MetaDataObject_impl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/resource/metadata/impl/MetaDataObject_impl.java
@@ -40,19 +40,24 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.uima.UIMAFramework;
 import org.apache.uima.UIMARuntimeException;
 import org.apache.uima.UIMA_IllegalArgumentException;
 import org.apache.uima.UIMA_UnsupportedOperationException;
+import org.apache.uima.UimaContext;
+import org.apache.uima.UimaContextHolder;
 import org.apache.uima.internal.util.XMLUtils;
 import org.apache.uima.resource.metadata.AllowedValue;
 import org.apache.uima.resource.metadata.MetaDataObject;
 import org.apache.uima.util.ConcurrentHashMapWithProducer;
 import org.apache.uima.util.InvalidXMLException;
+import org.apache.uima.util.Level;
 import org.apache.uima.util.NameClassPair;
 import org.apache.uima.util.XMLParser;
 import org.apache.uima.util.XMLSerializer;
 import org.apache.uima.util.XMLSerializer.CharacterValidatingContentHandler;
 import org.apache.uima.util.XMLizable;
+import org.apache.uima.util.impl.Settings_impl;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
@@ -1650,6 +1655,28 @@
     return (infoset == null) ? null : serialContext.serializer.findMatchingSubElement(name);
   }
   
+
+  /*
+   * UIMA-5274 Resolve any ${variable} entries in the string.
+   * Returns null if the expansion fails, i.e. a missing variable, or if no settings have been loaded.
+   * Logs a warning if settings have been loaded but an entry is missing.
+   */
+  protected String resolveSettings(String text) {
+    UimaContext uimaContext = UimaContextHolder.getContext();
+    if (uimaContext != null) {
+      Settings_impl settings = (Settings_impl) uimaContext.getExternalOverrides();
+      if (settings != null) {
+        try {
+          return settings.resolve(text);
+        } catch (Exception e) {
+          UIMAFramework.getLogger(this.getClass()).log(Level.WARNING, e.toString());
+        }
+      }
+    }
+    return null;
+  }
+  
+  
 //  /*****************************************
 //   * JSON support *
 //   * 
diff --git a/uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP_Type.java b/uimaj-core/src/main/java/org/apache/uima/util/AutoCloseableNoException.java
similarity index 69%
copy from uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP_Type.java
copy to uimaj-core/src/main/java/org/apache/uima/util/AutoCloseableNoException.java
index 92d15c7..06484d4 100644
--- a/uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP_Type.java
+++ b/uimaj-core/src/main/java/org/apache/uima/util/AutoCloseableNoException.java
@@ -17,13 +17,17 @@
  * under the License.

  */

 

-package org.apache.uima.jcas.cas;

+package org.apache.uima.util;

 

+/**

+ * protectIndexes returns instances of this, rather than AutoCloseable, to permit

+ * users to use try with resources without a catch for Exception.

+ */

+public interface AutoCloseableNoException extends AutoCloseable {

 

-

-// *********************************

-// * Implementation of TOP_Type    *

-// * Only for supporting decompiling of v2 JCas classes

-// *********************************

-

-public class TOP_Type {}

+  /* (non-Javadoc)

+   * @see java.lang.AutoCloseable#close()

+   */

+  @Override

+  void close();

+}

diff --git a/uimaj-core/src/main/java/org/apache/uima/util/CasCopier.java b/uimaj-core/src/main/java/org/apache/uima/util/CasCopier.java
index 621e359..63d5b49 100644
--- a/uimaj-core/src/main/java/org/apache/uima/util/CasCopier.java
+++ b/uimaj-core/src/main/java/org/apache/uima/util/CasCopier.java
@@ -19,6 +19,7 @@
 package org.apache.uima.util;
 
 import java.util.ArrayDeque;
+import java.util.Collection;
 import java.util.Deque;
 import java.util.IdentityHashMap;
 import java.util.Iterator;
@@ -29,16 +30,13 @@
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASRuntimeException;
 import org.apache.uima.cas.CommonArrayFS;
-import org.apache.uima.cas.FSIterator;
 import org.apache.uima.cas.FeatureStructure;
 import org.apache.uima.cas.SofaFS;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.FeatureImpl;
 import org.apache.uima.cas.impl.TypeImpl;
-import org.apache.uima.cas.impl.TypeSystemConstants;
 import org.apache.uima.cas.impl.TypeSystemImpl;
 import org.apache.uima.internal.util.Int2ObjListMap;
-import org.apache.uima.internal.util.Misc;
 import org.apache.uima.internal.util.PositiveIntSet;
 import org.apache.uima.internal.util.PositiveIntSet_impl;
 import org.apache.uima.jcas.cas.AnnotationBase;
@@ -253,10 +251,10 @@
 
   /**
    * key is source FS, value is target FS 
-   * Target not set for DocumentAnnotation or SofaFSs
+   * Target not set for SofaFSs
    * Target not set if lenient specified and src type isn't in target
    */
-  final private Map<TOP, TOP> mFsMap;
+  final private Map<TOP, TOP> mFsMap;  // is identity hash map
   
   /**
    * Deferred calls to copy Features of a FS
@@ -576,11 +574,10 @@
       //   FSs when doing a full CAS copy with multiple views - the 2nd and subsequent
       //   views don't copy, but they do index.
       
-      FSIterator<TOP> it = srcCasViewImpl.getIndexRepository().getAllIndexedFS(srcTsi.getTopType());
+      Collection<TOP> c = srcCasViewImpl.getIndexRepository().getIndexedFSs();
   //    LowLevelIterator it = ((FSIndexRepositoryImpl)(srcCasViewImpl.getIndexRepository())).ll_getAllIndexedFS(srcTsi.getTopType());
   
-      while (it.hasNext()) {
-        final TOP fs = it.nextNvc();
+      for (final TOP fs : c) {
   //      System.out.format("debug  id: %,d  type: %s%n", fs.id(), fs._getTypeImpl().getShortName());
   //    Iterator<LowLevelIndex> indexes = srcCasViewImpl.getIndexRepository().ll_getIndexes();
   //    while (indexes.hasNext()) {
@@ -611,10 +608,7 @@
   //          }
   //        }
   
-          // also don't index the DocumentAnnotation (it's indexed by default)
-          if (!isDocumentAnnotation(fs)) {
-            tgtCasViewImpl.getIndexRepository().addFS(copyOfFs);
-          }
+          tgtCasViewImpl.getIndexRepository().addFS(copyOfFs);
           indexedFsAlreadyCopied.add(fs._id());
         }
       }
@@ -733,45 +727,58 @@
       tgtView = tgtCasViewImpl;
     }
     
-    // DocumentAnnotation - instead of creating a new instance, reuse the automatically created
-    // instance in the destination view.
-    if (isDocumentAnnotation(srcFs)) {
-      if (srcFs instanceof UimaSerializable) {
-        ((UimaSerializable)srcFs)._save_to_cas_data();
-      }
-//      Annotation da = (Annotation) srcFs;
-//      String destViewNamex = getDestSofaId(da.getView().getViewName());
-
-      // the DocumentAnnotation could be indexed in a different view than the one being copied
-      //   if it was ref'd for the 1st time from a cross-indexed fs
-      // Note: The view might not exist in the target
-      //   but this is unlikely.  To have this case this would require
-      //   indexing some other feature structure in this view, which, in turn,
-      //   has a reference to the DocumentAnnotation FS belonging to another view
-//      CASImpl destView = (CASImpl) getOrCreateView(originalTgtCas, destViewName);
-      // do the no-create style so we can create it without adding it to the index yet
-      Annotation destDocAnnot = tgtView.getDocumentAnnotationNoCreate();  
-      if (destDocAnnot == null) {
-        destDocAnnot = tgtView.createDocumentAnnotationNoRemoveNoIndex(0);
-        copyFeatures(srcFs, destDocAnnot);
-        tgtView.getIndexRepository().addFS(destDocAnnot);
-      } else {   
-        try (AutoCloseable ac = tgtView.protectIndexes()) {
-          copyFeatures(srcFs, destDocAnnot);
-        } catch (Exception e) {
-          Misc.internalError(e);
-        }
-      }
-      if (destDocAnnot instanceof UimaSerializable) {
-        ((UimaSerializable)destDocAnnot)._init_from_cas_data();
-      }
-
-      // note not put into mFsMap, because each view needs a separate copy
-      // and multiple creations (due to multiple refs) won't happen because
-      //   the create is bypassed if it already exists
-      return destDocAnnot;
+    TypeImpl tgtTi = getTargetType(((TOP)srcFs)._getTypeImpl());
+    if (null == tgtTi) {
+      return null; // not in target, no FS to create
     }
 
+    // DocumentAnntation or subtype:
+    if (isDocumentAnnotation(srcFs)) {
+      Annotation destDocAnnot = tgtView.getDocumentAnnotationNoCreate();
+      if (destDocAnnot != null) {
+        destDocAnnot.removeFromIndexes(); // deleting this one, will be using the copy of the new one
+        // NOTE at this point, if the target cas type system doesn't define the new type, we
+        // won't get to this code.
+        // Fall thru to let normal FS copying happen
+      }
+    }
+//    // DocumentAnnotation - instead of creating a new instance, reuse the automatically created
+//    // instance in the destination view.
+//    if (isDocumentAnnotation(srcFs)) {
+//      if (srcFs instanceof UimaSerializable) {
+//        ((UimaSerializable)srcFs)._save_to_cas_data();
+//      }
+////      Annotation da = (Annotation) srcFs;
+////      String destViewNamex = getDestSofaId(da.getView().getViewName());
+//
+//      // the DocumentAnnotation could be indexed in a different view than the one being copied
+//      //   if it was ref'd for the 1st time from a cross-indexed fs
+//      // Note: The view might not exist in the target
+//      //   but this is unlikely.  To have this case this would require
+//      //   indexing some other feature structure in this view, which, in turn,
+//      //   has a reference to the DocumentAnnotation FS belonging to another view
+////      CASImpl destView = (CASImpl) getOrCreateView(originalTgtCas, destViewName);
+//      // do the no-create style so we can create it without adding it to the index yet
+//      Annotation destDocAnnot = tgtView.getDocumentAnnotationNoCreate();  
+//      if (destDocAnnot == null) {
+//        destDocAnnot = tgtView.createDocumentAnnotationNoRemoveNoIndex(0);
+//        copyFeatures(srcFs, destDocAnnot);
+//        tgtView.getIndexRepository().addFS(destDocAnnot);
+//      } else {   
+//        try (AutoCloseableNoException ac = tgtView.protectIndexes()) {
+//          copyFeatures(srcFs, destDocAnnot);
+//        }
+//      }
+//      if (destDocAnnot instanceof UimaSerializable) {
+//        ((UimaSerializable)destDocAnnot)._init_from_cas_data();
+//      }
+//
+//      // note not put into mFsMap, because each view needs a separate copy
+//      // and multiple creations (due to multiple refs) won't happen because
+//      //   the create is bypassed if it already exists
+//      return destDocAnnot;
+//    }
+
     // Arrays - need to be created a populated differently than "normal" FS
     if (srcFs instanceof CommonArrayFS) {
       copy = copyArray(srcFs);
@@ -781,10 +788,6 @@
       return copy;
     }
 
-    TypeImpl tgtTi = getTargetType(((TOP)srcFs)._getTypeImpl());
-    if (null == tgtTi) {
-      return null; // not in target, no FS to create
-    }
 //    final TypeInfo tInfo = getTypeInfo(srcTypeCode);
 //    final int tgtTypeCode = tInfo.tgtTypeCode;
 //    if (tgtTypeCode == 0) {
@@ -1046,11 +1049,12 @@
   
   /**
    * Determines whether the given FS is the DocumentAnnotation in the srcCasView.  
-   * This is more than just a type check; we actually check if it is the one "special"
-   * DocumentAnnotation that CAS.getDocumentAnnotation() would return.
+   * Supports subtypes of DocumentAnnotation.
+   * Returns true if the FS is the actual one that is being used by the source CAS
+   * as the Document Annotation instance.
    */
   private <T extends FeatureStructure> boolean isDocumentAnnotation(T aFS) {
-    if (((TOP)aFS)._getTypeCode() != TypeSystemConstants.docTypeCode) {
+    if ( ! srcTsi.docType.subsumes(aFS.getType()) ) {
       return false;
     }
     if (srcCasDocumentAnnotation == null) {
diff --git a/uimaj-core/src/main/java/org/apache/uima/util/CasCreationUtils.java b/uimaj-core/src/main/java/org/apache/uima/util/CasCreationUtils.java
index eabf1de..a41dcd4 100644
--- a/uimaj-core/src/main/java/org/apache/uima/util/CasCreationUtils.java
+++ b/uimaj-core/src/main/java/org/apache/uima/util/CasCreationUtils.java
@@ -580,6 +580,7 @@
     
     
     // Check Jcas cache performance setting.  Defaults to true.
+    // in v3, JCasCache is ignored
     boolean useJcasCache = true;
     if (aPerformanceTuningSettings != null) {
       String useJcasCacheString = aPerformanceTuningSettings.getProperty(
@@ -588,7 +589,7 @@
         useJcasCache = false;
       }
     }
-
+    
     // create CAS using either aTypeSystem or aTypeSystemDesc
     CASMgr casMgr;
     if (aTypeSystem != null) {
@@ -601,6 +602,12 @@
 
     } else // no TypeSystem to reuse - create a new one
     {
+      boolean skip_loading_user_jcas = false;
+      if (aPerformanceTuningSettings != null) {
+        String v = aPerformanceTuningSettings.getProperty(UIMAFramework.SKIP_USER_JCAS_LOADING, "false");
+        skip_loading_user_jcas = "true".equalsIgnoreCase(v);
+      }
+
       casMgr = CASFactory.createCAS();
  
       if (aResourceManager.getExtensionClassLoader() != null) {
@@ -610,7 +617,7 @@
       // install type system
       setupTypeSystem(casMgr, aTypeSystemDesc);
       // Commit the type system
-      ((CASImpl) casMgr).commitTypeSystem();
+      ((CASImpl) casMgr).commitTypeSystem(skip_loading_user_jcas);
     }
 
     try {
diff --git a/uimaj-core/src/main/java/org/apache/uima/util/CasIOUtils.java b/uimaj-core/src/main/java/org/apache/uima/util/CasIOUtils.java
index ab001f9..d1d4f1e 100644
--- a/uimaj-core/src/main/java/org/apache/uima/util/CasIOUtils.java
+++ b/uimaj-core/src/main/java/org/apache/uima/util/CasIOUtils.java
@@ -30,7 +30,6 @@
 import java.io.ObjectOutputStream;

 import java.io.OutputStream;

 import java.net.URL;

-import java.util.Arrays;

 

 import org.apache.uima.UIMARuntimeException;

 import org.apache.uima.cas.CAS;

@@ -169,7 +168,7 @@
 

     return load(casUrl, null, aCAS, CasLoadMode.DEFAULT);

   }

-

+  

   /**

    * Loads a CAS from a URL source. The format is determined from the content.

    * 

@@ -346,7 +345,7 @@
   

   private static SerialFormat load(InputStream casInputStream, InputStream tsiInputStream, CAS aCAS,

       CasLoadMode casLoadMode, TypeSystemImpl typeSystem) throws IOException {

-

+   

     if (!casInputStream.markSupported()) {

       casInputStream = new BufferedInputStream(casInputStream);

     }

@@ -379,7 +378,7 @@
        * Binary, Compressed Binary (form 4 or 6)

        ******************************************/

       Header h = CommonSerDes.readHeader(deserIn);

-      return bcsd.reinit(h, casInputStream, readCasManager(tsiInputStream), casLoadMode, null, AllowPreexistingFS.allow, null);

+      return bcsd.reinit(h, casInputStream, readCasManager(tsiInputStream), casLoadMode, null, AllowPreexistingFS.allow, typeSystem);

     

     } else {

       

diff --git a/uimaj-core/src/main/java/org/apache/uima/util/IntEntry.java b/uimaj-core/src/main/java/org/apache/uima/util/IntEntry.java
new file mode 100644
index 0000000..3a267a4
--- /dev/null
+++ b/uimaj-core/src/main/java/org/apache/uima/util/IntEntry.java
@@ -0,0 +1,85 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+package org.apache.uima.util;

+

+/**

+ * like Entry&lt;k, v&gt; except the k is an int. 

+ *

+ * @param <T> the type of the value

+ */

+public class IntEntry<T> {

+  private int key;

+  private T value;

+  

+  public IntEntry(int i, T v) {

+    this.key = i;

+    this.value = v;

+  }

+  

+  /**

+   * 

+   * @return the key 

+   */

+  public int getKey() {

+    return key;

+  }

+  

+  /**

+   * 

+   * @return the Value

+   */

+  public T getValue() {

+    return value;

+  }

+

+  /* (non-Javadoc)

+   * @see java.lang.Object#hashCode()

+   */

+  @Override

+  public int hashCode() {

+    final int prime = 31;

+    int result = 1;

+    result = prime * result + key;

+    result = prime * result + ((value == null) ? 0 : value.hashCode());

+    return result;

+  }

+

+  /* (non-Javadoc)

+   * @see java.lang.Object#equals(java.lang.Object)

+   */

+  @Override

+  public boolean equals(Object obj) {

+    if (this == obj)

+      return true;

+    if (obj == null)

+      return false;

+    if (getClass() != obj.getClass())

+      return false;

+    IntEntry other = (IntEntry) obj;

+    if (key != other.key)

+      return false;

+    if (value == null) {

+      if (other.value != null)

+        return false;

+    } else if (!value.equals(other.value))

+      return false;

+    return true;

+  }

+  

+}

diff --git a/uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP_Type.java b/uimaj-core/src/main/java/org/apache/uima/util/IteratorNvc.java
similarity index 68%
copy from uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP_Type.java
copy to uimaj-core/src/main/java/org/apache/uima/util/IteratorNvc.java
index 92d15c7..73efc2e 100644
--- a/uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP_Type.java
+++ b/uimaj-core/src/main/java/org/apache/uima/util/IteratorNvc.java
@@ -16,14 +16,19 @@
  * specific language governing permissions and limitations

  * under the License.

  */

+package org.apache.uima.util;

 

-package org.apache.uima.jcas.cas;

+import java.util.Iterator;

 

+/**

+ * An Iterator with an extra method nextNvc, which skips the validity check

+ *

+ * @param <E> the class of the element being returned

+ */

+public interface IteratorNvc<E> extends Iterator<E> {

+  /**

+   * @return the element currently being pointed at, and then advance the iterator

+   */

+  E nextNvc();

 

-

-// *********************************

-// * Implementation of TOP_Type    *

-// * Only for supporting decompiling of v2 JCas classes

-// *********************************

-

-public class TOP_Type {}

+}

diff --git a/uimaj-core/src/main/java/org/apache/uima/util/Level.java b/uimaj-core/src/main/java/org/apache/uima/util/Level.java
index ed42012..2db61ec 100644
--- a/uimaj-core/src/main/java/org/apache/uima/util/Level.java
+++ b/uimaj-core/src/main/java/org/apache/uima/util/Level.java
@@ -25,7 +25,7 @@
 public class Level {
   /** level value */
   private int level;
-
+  
   /** level name */
   private String levelText;
 
@@ -56,14 +56,25 @@
   /** level value for level "ALL" */
   public final static int ALL_INT = Integer.MIN_VALUE;
 
+  /** level value for level "ERROR" */
+  public final static int ERROR_INT = SEVERE_INT;
+  /** level value for level "WARN" */
+  public final static int WARN_INT = WARNING_INT;
+  /** level value for level "DEBUG" */
+  public final static int DEBUG_INT = FINE_INT;
+  /** level value for level "TRACE" */
+  public final static int TRACE_INT = FINER_INT;
+  
   /** message level "OFF" */
   final static public Level OFF = new Level(OFF_INT, "OFF");
 
   /** message level "SEVERE" */
   final static public Level SEVERE = new Level(SEVERE_INT, "SEVERE");
+  final static public Level ERROR = SEVERE;
 
   /** message level "WARNING" */
   final static public Level WARNING = new Level(WARNING_INT, "WARNING");
+  final static public Level WARN = WARNING;
 
   /** message level "INFO" */
   final static public Level INFO = new Level(INFO_INT, "INFO");
@@ -73,9 +84,11 @@
 
   /** message level "FINE" */
   final static public Level FINE = new Level(FINE_INT, "FINE");
+  final static public Level DEBUG = FINE;
 
   /** message level "FINER" */
   final static public Level FINER = new Level(FINER_INT, "FINER");
+  final static public Level TRACE = FINER;
 
   /** message level "FINEST" */
   final static public Level FINEST = new Level(FINEST_INT, "FINEST");
diff --git a/uimaj-core/src/main/java/org/apache/uima/util/Logger.java b/uimaj-core/src/main/java/org/apache/uima/util/Logger.java
index 6fc42b0..8b9eb42 100644
--- a/uimaj-core/src/main/java/org/apache/uima/util/Logger.java
+++ b/uimaj-core/src/main/java/org/apache/uima/util/Logger.java
@@ -21,20 +21,42 @@
 
 import java.io.OutputStream;
 import java.io.PrintStream;
+import java.util.function.Supplier;
 
+import org.apache.uima.UIMAException;
+import org.apache.uima.UIMARuntimeException;
 import org.apache.uima.resource.ResourceManager;
+import org.slf4j.Marker;
+import org.slf4j.MarkerFactory;
 
 /**
  * A <code>Logger</code> is a component used to log messages. This interface defines the standard
  * way for UIMA components to produce log output.
  * <p>
- * In the UIMA SDK, this interface is implemented using the Java 1.4 logger as a back end. If you
+ * In the UIMA SDK, this interface is implemented using the Java logger as a back end.
+ * <p>The back end may be changed to Apache Log4j 2  by specifying
+ * <code>-Dorg.apache.uima.logger.class=org.apache.uima.util.impl.Log4jLogger_impl</code>
+ * and including the log4j 2 JARs in the classpath.
+ * <p>  
+ * If you
  * want to configure the logger, for example to specify the location of the log file and the logging
- * level, you should use the standard Java 1.4 logger properties or the java.util.logging APIs. See
+ * level, you use whatever back end logger implementation specifies, or use that logger's APIs.
+ * should use the standard Java logger properties or the java.util.logging APIs. See
  * the section "Specifying the Logging Configuration" in the Annotator and Analysis Engine
  * Developer's Guide chapter of the UIMA documentation for more information.
+ * <p>
+ * Version 3 augments this API with methods to do UIMA-Resource-bundle-based internationalization, 
+ * separate from logging, so the String result can be used with various back end loggers.
+ * <p>
+ * Version 3 augments isLoggable to include the Marker.
+ *
+ *  
  */
-public interface Logger {
+public interface Logger extends org.slf4j.Logger {
+
+  // standard markers
+  static final Marker UIMA_MARKER_CONFIG = MarkerFactory.getMarker("org.apache.uima.config");
+  static final Marker UIMA_MARKER_FINEST = MarkerFactory.getMarker("org.apache.uima.finest");
 
   /**
    * Logs a message.
@@ -243,6 +265,14 @@
    * @return boolean - true if the argument level is greater or equal to the specified level
    */
   public boolean isLoggable(Level level);
+  
+  /**
+   * Checks if this logger is enabled for this level and this marker
+   * @param level the level to test
+   * @param marker null or the marker to test
+   * @return true if the level is greater or equal to the specified level and the marker matches
+   */
+  public boolean isLoggable(Level level, Marker marker);
 
   /**
    * Sets the level of messages that will be logged by this logger. Note that if you call
@@ -269,4 +299,215 @@
    */
   public void setResourceManager(ResourceManager resourceManager);
 
+  /**
+   * Get an internationalized message from a resource bundle by key name, substituting the parameters.
+   * This should be called via a Supplier to avoid computing this until needed
+   * @param resourceBundle -
+   * @param key -
+   * @param params -
+   * @return the internationalized message
+   */
+  public String rb(String resourceBundle, String key, Object... params);
+  
+  default String rb_ue(String key, Object... params) {
+    return rb(UIMAException.STANDARD_MESSAGE_CATALOG, key, params);
+  }
+  
+  /**
+   * This is true if the name of the logger corresponds to a class which implements
+   * AnalysisComponent_ImplBase, which includes basic Annotators, plus Cas Multipliers
+   * and CPP components.
+   * @return true if this logger is an Annotator logger.
+   */
+  public boolean isAnnotatorLogger();
+
+  /**
+   * @param limit the limit
+   * @return a copy of the logger with the throttling limit set, or the same logger if no change
+   */
+  default Logger getLimitedLogger(int limit) {
+    return this;
+  }
+  
+  /* added Supplier APIs */
+  
+  /**
+   * @param msgSupplier A function, which when called, produces the desired log message
+   */
+  void debug(Supplier<String> msgSupplier);
+
+  /**
+   * @param msgSupplier A function, which when called, produces the desired log message
+   * @param throwable the exception to log
+   */
+  public void debug(Supplier<String> msgSupplier, Throwable throwable);
+  
+  /**
+   * @param marker the marker data specific to this log statement
+   * @param message the message to log
+   * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
+   */
+  public void debug(Marker marker, String message, Supplier<?>... paramSuppliers);
+
+  /**
+   * @param message the message to log
+   * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
+   */
+  public void debug(String message, Supplier<?>... paramSuppliers);
+
+  /**
+   * @param marker the marker data specific to this log statement
+   * @param msgSupplier A function, which when called, produces the desired log message
+   */
+  public void debug(Marker marker, Supplier<String> msgSupplier);
+
+  /**
+   * @param marker the marker data specific to this log statement
+   * @param msgSupplier A function, which when called, produces the desired log message
+   * @param throwable the exception to log
+   */
+  public void debug(Marker marker, Supplier<String> msgSupplier, Throwable throwable);
+
+  /**
+   * @param msgSupplier A function, which when called, produces the desired log message
+   */
+  void error(Supplier<String> msgSupplier);
+
+  /**
+   * @param msgSupplier A function, which when called, produces the desired log message
+   * @param throwable the exception to log
+   */
+  public void error(Supplier<String> msgSupplier, Throwable throwable);
+  
+  /**
+   * @param marker the marker data specific to this log statement
+   * @param message the message to log
+   * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
+   */
+  public void error(Marker marker, String message, Supplier<?>... paramSuppliers);
+
+  /**
+   * @param message the message to log
+   * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
+   */
+  public void error(String message, Supplier<?>... paramSuppliers);
+
+  /**
+   * @param marker the marker data specific to this log statement
+   * @param msgSupplier A function, which when called, produces the desired log message
+   */
+  public void error(Marker marker, Supplier<String> msgSupplier);
+
+  /**
+   * @param marker the marker data specific to this log statement
+   * @param msgSupplier A function, which when called, produces the desired log message
+   * @param throwable the exception to log
+   */
+  public void error(Marker marker, Supplier<String> msgSupplier, Throwable throwable);
+
+  /**
+   * @param msgSupplier A function, which when called, produces the desired log message
+   */
+  void info(Supplier<String> msgSupplier);
+
+  /**
+   * @param msgSupplier A function, which when called, produces the desired log message
+   * @param throwable the exception to log
+   */
+  public void info(Supplier<String> msgSupplier, Throwable throwable);
+  
+  /**
+   * @param marker the marker data specific to this log statement
+   * @param message the message to log
+   * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
+   */
+  public void info(Marker marker, String message, Supplier<?>... paramSuppliers);
+
+  /**
+   * @param marker the marker data specific to this log statement
+   * @param msgSupplier A function, which when called, produces the desired log message
+   */
+  public void info(Marker marker, Supplier<String> msgSupplier);
+
+  /**
+   * @param marker the marker data specific to this log statement
+   * @param msgSupplier A function, which when called, produces the desired log message
+   * @param throwable the exception to log
+   */
+  public void info(Marker marker, Supplier<String> msgSupplier, Throwable throwable);
+
+  /**
+   * @param msgSupplier A function, which when called, produces the desired log message
+   */
+  void trace(Supplier<String> msgSupplier);
+
+  /**
+   * @param msgSupplier A function, which when called, produces the desired log message
+   * @param throwable the exception to log
+   */
+  public void trace(Supplier<String> msgSupplier, Throwable throwable);
+  
+  /**
+   * @param marker the marker data specific to this log statement
+   * @param message the message to log
+   * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
+   */
+  public void trace(Marker marker, String message, Supplier<?>... paramSuppliers);
+
+  /**
+   * @param message the message to log
+   * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
+   */
+  public void trace(String message, Supplier<?>... paramSuppliers);
+
+  /**
+   * @param marker the marker data specific to this log statement
+   * @param msgSupplier A function, which when called, produces the desired log message
+   */
+  public void trace(Marker marker, Supplier<String> msgSupplier);
+
+  /**
+   * @param marker the marker data specific to this log statement
+   * @param msgSupplier A function, which when called, produces the desired log message
+   * @param throwable the exception to log
+   */
+  public void trace(Marker marker, Supplier<String> msgSupplier, Throwable throwable);
+
+  /**
+   * @param msgSupplier A function, which when called, produces the desired log message
+   */
+  void warn(Supplier<String> msgSupplier);
+
+  /**
+   * @param msgSupplier A function, which when called, produces the desired log message
+   * @param throwable the exception to log
+   */
+  public void warn(Supplier<String> msgSupplier, Throwable throwable);
+  
+  /**
+   * @param marker the marker data specific to this log statement
+   * @param message the message to log
+   * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
+   */
+  public void warn(Marker marker, String message, Supplier<?>... paramSuppliers);
+
+  /**
+   * @param message the message to log
+   * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
+   */
+  public void warn(String message, Supplier<?>... paramSuppliers);
+
+  /**
+   * @param marker the marker data specific to this log statement
+   * @param msgSupplier A function, which when called, produces the desired log message
+   */
+  public void warn(Marker marker, Supplier<String> msgSupplier);
+
+  /**
+   * @param marker the marker data specific to this log statement
+   * @param msgSupplier A function, which when called, produces the desired log message
+   * @param throwable the exception to log
+   */
+  public void warn(Marker marker, Supplier<String> msgSupplier, Throwable throwable);
+
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/util/MessageReport.java b/uimaj-core/src/main/java/org/apache/uima/util/MessageReport.java
index 5dc42fd..7436580 100644
--- a/uimaj-core/src/main/java/org/apache/uima/util/MessageReport.java
+++ b/uimaj-core/src/main/java/org/apache/uima/util/MessageReport.java
@@ -23,6 +23,7 @@
 import java.io.PrintStream;

 import java.util.concurrent.atomic.AtomicInteger;

 

+// not used in v3, kept for backwards compatibility

 public class MessageReport {

 

   /**

diff --git a/uimaj-core/src/main/java/org/apache/uima/util/Misc.java b/uimaj-core/src/main/java/org/apache/uima/util/Misc.java
new file mode 100644
index 0000000..cda99e2
--- /dev/null
+++ b/uimaj-core/src/main/java/org/apache/uima/util/Misc.java
@@ -0,0 +1,47 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.util;

+

+// not used in v3, kept for backwards compatibility

+public class Misc {

+

+  /**

+   * 

+   * @param name of property

+   * @return true if property is defined, or is defined and set to anything 

+   * except "false"; false if property is not defined, or is defined and set to

+   * "false".

+   */

+  public static boolean getNoValueSystemProperty(String name) {

+    return !System.getProperty(name, "false").equals("false");

+  }

+  

+//  public static void main(String[] args) {

+//    System.out.println("should be false - not defined: " + getNoValueSystemProperty("foo"));

+//    System.setProperty("foo", "");

+//    System.out.println("should be true - defined, 0 len str value: " + getNoValueSystemProperty("foo"));

+//    System.setProperty("foo", "true");

+//    System.out.println("should be true - defined, true value: " + getNoValueSystemProperty("foo"));

+//    System.setProperty("foo", "zzz");

+//    System.out.println("should be true - defined, zzz value: " + getNoValueSystemProperty("foo"));

+//    System.setProperty("foo", "false");

+//    System.out.println("should be false - defined, false value: " + getNoValueSystemProperty("foo"));

+//  }

+}

diff --git a/uimaj-core/src/main/java/org/apache/uima/util/XMLSerializer.java b/uimaj-core/src/main/java/org/apache/uima/util/XMLSerializer.java
index a6dce07..215a7d7 100644
--- a/uimaj-core/src/main/java/org/apache/uima/util/XMLSerializer.java
+++ b/uimaj-core/src/main/java/org/apache/uima/util/XMLSerializer.java
@@ -56,8 +56,7 @@
   //  or the class found in any jar that has an entry: META-INF/service/javax.xml.transform.TransformerFactory
   //  or a platform default.
   
-  private static final SAXTransformerFactory transformerFactory = (SAXTransformerFactory) SAXTransformerFactory
-          .newInstance();
+  private static final SAXTransformerFactory transformerFactory = XMLUtils.createSaxTransformerFactory();
 
   private TransformerHandler mHandler;
 
@@ -376,12 +375,15 @@
     private final void checkForInvalidXmlChars(String s, boolean xml11) throws SAXParseException {
       final int index = XMLUtils.checkForNonXmlCharacters(s, xml11);
       if (index >= 0) {
-        String msg =  String.format("Trying to serialize non-XML %s character: %c, 0x%x at offset %,d in string starting with %s",
+        String startStr = (index == 0) 
+                         ? "[The Very First Character]"
+                         : s.substring(0, Math.min(index, Math.min(100,  s.length())));
+        String msg =  String.format("Trying to serialize non-XML %s character: 0x%x at offset %,d in string starting with %s",
             (xml11 ? "1.1" : "1.0"),
-            s.charAt(index), 
+//            s.charAt(index),  // don't try to output this, causes problems with other tooling 
             (int)s.charAt(index),
             index,
-            s.substring(0, Math.min(100,  s.length()))); 
+            startStr); 
         throw new SAXParseException(msg, null);
       }
     }
@@ -389,12 +391,15 @@
     private final void checkForInvalidXmlChars(char[] ch, int start, int length, boolean xml11) throws SAXParseException {
       final int index = XMLUtils.checkForNonXmlCharacters(ch, start, length, xml11);
       if (index >= 0) {
-        String msg =  String.format("Trying to serialize non-XML %s character: %c, 0x%x at offset %,d in string starting with %s",
+        String startStr = (index == 0) 
+            ? "[The Very First Character]"
+            : new String(ch).substring(0, Math.min(index, Math.min(100,  ch.length)));
+        String msg =  String.format("Trying to serialize non-XML %s character: 0x%x at offset %,d in string starting with %s",
             (xml11 ? "1.1" : "1.0"),
-            ch[index], 
+//            ch[index],  // don't try to output this, causes problems with other tooling  
             (int)(ch[index]),
             index,
-            (new String(ch)).substring(0, Math.min(100,  ch.length))); 
+            startStr); 
         throw new SAXParseException(msg, null);
       }
     }
diff --git a/uimaj-core/src/main/java/org/apache/uima/util/XmlCasDeserializer.java b/uimaj-core/src/main/java/org/apache/uima/util/XmlCasDeserializer.java
index 22c26e0..16e636d 100644
--- a/uimaj-core/src/main/java/org/apache/uima/util/XmlCasDeserializer.java
+++ b/uimaj-core/src/main/java/org/apache/uima/util/XmlCasDeserializer.java
@@ -27,6 +27,7 @@
 import org.apache.uima.cas.impl.OutOfTypeSystemData;
 import org.apache.uima.cas.impl.XCASDeserializer;
 import org.apache.uima.cas.impl.XmiCasDeserializer;
+import org.apache.uima.internal.util.XMLUtils;
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.InputSource;
@@ -34,11 +35,12 @@
 import org.xml.sax.SAXParseException;
 import org.xml.sax.XMLReader;
 import org.xml.sax.helpers.DefaultHandler;
-import org.xml.sax.helpers.XMLReaderFactory;
 
 /**
  * Deserializes a CAS from a standoff-XML format. This class can read the XMI format introduced in
  * UIMA v1.4 as well as the XCAS format from previous versions.
+ * 
+ * This class is abstract, because it only has static methods and should never be instantiated 
  */
 public abstract class XmlCasDeserializer {
   /**
@@ -78,10 +80,7 @@
    */
   public static void deserialize(InputStream aStream, CAS aCAS, boolean aLenient)
           throws SAXException, IOException {
-    XMLReader xmlReader = XMLReaderFactory.createXMLReader();
-    XmlCasDeserializerHandler handler = new XmlCasDeserializerHandler(aCAS, aLenient);
-    xmlReader.setContentHandler(handler);
-    xmlReader.parse(new InputSource(aStream));
+    deserializeR(aStream, aCAS, aLenient);
   }
 
   /**
@@ -104,7 +103,7 @@
    */
   static SerialFormat deserializeR(InputStream aStream, CAS aCAS, boolean aLenient)
       throws SAXException, IOException {
-    XMLReader xmlReader = XMLReaderFactory.createXMLReader();
+    XMLReader xmlReader = XMLUtils.createXMLReader();
     XmlCasDeserializerHandler handler = new XmlCasDeserializerHandler(aCAS, aLenient);
     xmlReader.setContentHandler(handler);
     xmlReader.parse(new InputSource(aStream));
@@ -119,7 +118,7 @@
     private boolean mLenient;
 
     private ContentHandler mDelegateHandler; // will be set to either XMI or XCAS
-
+    
     XmlCasDeserializerHandler(CAS cas, boolean lenient) {
       mCAS = cas;
       mLenient = lenient;
diff --git a/uimaj-core/src/main/java/org/apache/uima/util/impl/JSR47Logger_impl.java b/uimaj-core/src/main/java/org/apache/uima/util/impl/JSR47Logger_impl.java
index 8e40fbc..fce5194 100644
--- a/uimaj-core/src/main/java/org/apache/uima/util/impl/JSR47Logger_impl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/util/impl/JSR47Logger_impl.java
@@ -24,31 +24,28 @@
 import java.text.MessageFormat;
 import java.util.logging.Handler;
 import java.util.logging.LogManager;
+import java.util.logging.LogRecord;
 
-import org.apache.uima.internal.util.I18nUtil;
 import org.apache.uima.internal.util.UIMALogFormatter;
 import org.apache.uima.internal.util.UIMAStreamHandler;
-import org.apache.uima.resource.ResourceManager;
 import org.apache.uima.util.Level;
 import org.apache.uima.util.Logger;
+import org.slf4j.Marker;
+import org.slf4j.helpers.MessageFormatter;
 
 /**
- * UIMA Logging interface implementation for Java Logging Toolkit JSR-47 (JDK 1.4)
+ * UIMA Logging interface implementation for Java Logging Toolkit JSR-47 (JDK 1.4) JUL
+ * Ignores Markers and MDC (not supported in the JUL
  * 
  */
-public class JSR47Logger_impl implements Logger {
-  private static final String EXCEPTION_MESSAGE = "Exception occurred";
+public class JSR47Logger_impl extends Logger_common_impl {
+  
+  final static private Object[] zeroLengthArray = new Object[0];
 
   /**
    * logger object from the underlying JSR-47 logging framework
    */
-  private java.util.logging.Logger logger = null;
-
-  /**
-   * ResourceManager whose extension ClassLoader will be used to locate the message digests. Null
-   * will cause the ClassLoader to default to this.class.getClassLoader().
-   */
-  private ResourceManager mResourceManager = null;
+  final private java.util.logging.Logger logger;
 
   /**
    * create a new LogWrapper class for the specified source class
@@ -57,22 +54,17 @@
    *          specified source class
    */
   private JSR47Logger_impl(Class<?> component) {
-    super();
-
-    if (component != null) {
-      // create new JSR47 logger for this LogWrapper object
-      logger = java.util.logging.Logger.getLogger(component.getName());
-    } else // if class not set, return "org.apache.uima" logger
-    {
-      logger = java.util.logging.Logger.getLogger("org.apache.uima");
-    }
+    super(component);
+    
+    logger = java.util.logging.Logger.getLogger(
+        (component != null)
+          ? component.getName()
+          : "org.apache.uima");
   }
-
-  /**
-   * create a new LogWrapper object with the default logger from the JSR-47 logging framework
-   */
-  private JSR47Logger_impl() {
-    this(null);
+  
+  private JSR47Logger_impl(JSR47Logger_impl l, int limit) {
+    super(l, limit);
+    this.logger = l.logger;
   }
 
   /**
@@ -86,77 +78,29 @@
   public static synchronized Logger getInstance(Class<?> component) {
     return new JSR47Logger_impl(component);
   }
+  
+  public static synchronized Logger getInstance(JSR47Logger_impl l, int limit) {
+    if (limit == Integer.MAX_VALUE) {
+      return l;
+    }
+    return new JSR47Logger_impl(l, limit);
+  }
 
   /**
    * Creates a new JSR47Logger instance with the default JSR-47 framework logger
    * 
    * @return Logger returns the JSR47Logger object with the default JSR-47 framework logger
    */
-  public static synchronized Logger getInstance() {
-    return new JSR47Logger_impl();
+  public static synchronized JSR47Logger_impl getInstance() {
+    return new JSR47Logger_impl(null);
   }
-
-  /**
-   * Logs a message with level INFO.
-   * 
-   * @deprecated use new function with log level
-   * 
-   * @param aMessage
-   *          the message to be logged
-   */
-  @Deprecated
-  public void log(String aMessage) {
-    if (isLoggable(Level.INFO)) {
-      if (aMessage == null || aMessage.equals(""))
-        return;
-
-      String[] sourceInfo = getStackTraceInfo(null, new Throwable());
-
-      logger.logp(java.util.logging.Level.INFO, sourceInfo[0], sourceInfo[1], aMessage);
+  
+  @Override
+  public JSR47Logger_impl getLimitedLogger(int limit) {
+    if (limit == Integer.MAX_VALUE || limit == this.limit_common) {
+      return this;
     }
-  }
-
-  /**
-   * Logs a message with a message key and the level INFO
-   * 
-   * @deprecated use new function with log level
-   * 
-   * @see org.apache.uima.util.Logger#log(java.lang.String, java.lang.String, java.lang.Object[])
-   */
-  @Deprecated
-  public void log(String aResourceBundleName, String aMessageKey, Object[] aArguments) {
-    if (isLoggable(Level.INFO)) {
-      if (aMessageKey == null || aMessageKey.equals(""))
-        return;
-
-      String[] sourceInfo = getStackTraceInfo(null, new Throwable());
-
-      logger.logp(java.util.logging.Level.INFO, sourceInfo[0], sourceInfo[1], I18nUtil
-              .localizeMessage(aResourceBundleName, aMessageKey, aArguments,
-                      getExtensionClassLoader()));
-    }
-  }
-
-  /**
-   * Logs an exception with level INFO
-   * 
-   * @deprecated use new function with log level
-   * 
-   * @param aException
-   *          the exception to be logged
-   */
-  @Deprecated
-  public void logException(Exception aException) {
-    if (isLoggable(Level.INFO)) {
-      if (aException == null)
-        return;
-
-      String[] sourceInfo = getStackTraceInfo(null, new Throwable());
-
-      // log exception
-      logger.logp(java.util.logging.Level.INFO, sourceInfo[0], sourceInfo[1], EXCEPTION_MESSAGE,
-              aException);
-    }
+    return new JSR47Logger_impl(this, limit);
   }
 
   /**
@@ -164,6 +108,7 @@
    * 
    * @deprecated use external configuration possibility
    */
+  @Override
   @Deprecated
   public void setOutputStream(OutputStream out) {
     // if OutputStream is null set root logger level to OFF
@@ -191,6 +136,7 @@
    * 
    * @deprecated use external configuration possibility
    */
+  @Override
   @Deprecated
   public void setOutputStream(PrintStream out) {
     // if PrintStream is null set root logger level to OFF
@@ -213,248 +159,28 @@
     LogManager.getLogManager().getLogger("").addHandler(streamHandler);
   }
 
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#isLoggable(org.apache.uima.util.Level)
-   */
-  public boolean isLoggable(Level level) {
-    // get corresponding JSR-47 level
-    java.util.logging.Level jsr47Level = getJSR47Level(level);
-
-    return logger.isLoggable(jsr47Level);
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#setLevel(org.apache.uima.util.Level)
-   */
-  public void setLevel(Level level) {
-    // get corresponding JSR-47 level
-    java.util.logging.Level jsr47Level = getJSR47Level(level);
-
-    logger.setLevel(jsr47Level);
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#log(org.apache.uima.util.Level, java.lang.String)
-   */
-  public void log(Level level, String aMessage) {
-    if (isLoggable(level)) {
-      if (aMessage == null || aMessage.equals(""))
-        return;
-
-      // get corresponding JSR-47 level
-      java.util.logging.Level jsr47Level = getJSR47Level(level);
-
-      String[] sourceInfo = getStackTraceInfo(null, new Throwable());
-
-      logger.logp(jsr47Level, sourceInfo[0], sourceInfo[1], aMessage);
-    }
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#log(org.apache.uima.util.Level, java.lang.String,
-   *      java.lang.Object)
-   */
-  public void log(Level level, String aMessage, Object param1) {
-    if (isLoggable(level)) {
-      if (aMessage == null || aMessage.equals(""))
-        return;
-
-      // get corresponding JSR-47 level
-      java.util.logging.Level jsr47Level = getJSR47Level(level);
-
-      String[] sourceInfo = getStackTraceInfo(null, new Throwable());
-
-      logger.logp(jsr47Level, sourceInfo[0], sourceInfo[1], MessageFormat.format(aMessage,
-              new Object[] { param1 }));
-    }
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#log(org.apache.uima.util.Level, java.lang.String,
-   *      java.lang.Object[])
-   */
-  public void log(Level level, String aMessage, Object[] params) {
-    if (isLoggable(level)) {
-      if (aMessage == null || aMessage.equals(""))
-        return;
-
-      // get corresponding JSR-47 level
-      java.util.logging.Level jsr47Level = getJSR47Level(level);
-
-      String[] sourceInfo = getStackTraceInfo(null, new Throwable());
-
-      logger.logp(jsr47Level, sourceInfo[0], sourceInfo[1], MessageFormat.format(aMessage, params));
-    }
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#log(org.apache.uima.util.Level, java.lang.String,
-   *      java.lang.Throwable)
-   */
-  public void log(Level level, String aMessage, Throwable thrown) {
-    if (isLoggable(level)) {
-      if (aMessage != null && !aMessage.equals("")) {
-        // get corresponding JSR-47 level
-        java.util.logging.Level jsr47Level = getJSR47Level(level);
-
-        String[] sourceInfo = getStackTraceInfo(null, new Throwable());
-
-        logger.logp(jsr47Level, sourceInfo[0], sourceInfo[1], aMessage, thrown);
-      }
-
-      if (thrown != null && (aMessage == null || aMessage.equals(""))) {
-        // get corresponding JSR-47 level
-        java.util.logging.Level jsr47Level = getJSR47Level(level);
-
-        String[] sourceInfo = getStackTraceInfo(null, new Throwable());
-
-        // log exception
-        logger.logp(jsr47Level, sourceInfo[0], sourceInfo[1], EXCEPTION_MESSAGE, thrown);
-      }
-    }
-
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#logrb(org.apache.uima.util.Level, java.lang.String,
-   *      java.lang.String, java.lang.String, java.lang.String, java.lang.Object)
-   */
-  public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName,
-          String msgKey, Object param1) {
-    if (isLoggable(level)) {
-      if (msgKey == null || msgKey.equals(""))
-        return;
-
-      // get corresponding JSR-47 level
-      java.util.logging.Level jsr47Level = getJSR47Level(level);
-
-      logger.logp(jsr47Level, sourceClass, sourceMethod, I18nUtil.localizeMessage(bundleName,
-              msgKey, new Object[] { param1 }, getExtensionClassLoader()));
-    }
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#logrb(org.apache.uima.util.Level, java.lang.String,
-   *      java.lang.String, java.lang.String, java.lang.String, java.lang.Object[])
-   */
-  public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName,
-          String msgKey, Object[] params) {
-    if (isLoggable(level)) {
-      if (msgKey == null || msgKey.equals(""))
-        return;
-
-      // get corresponding JSR-47 level
-      java.util.logging.Level jsr47Level = getJSR47Level(level);
-
-      logger.logp(jsr47Level, sourceClass, sourceMethod, I18nUtil.localizeMessage(bundleName,
-              msgKey, params, getExtensionClassLoader()));
-    }
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#logrb(org.apache.uima.util.Level, java.lang.String,
-   *      java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable)
-   */
-  public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName,
-          String msgKey, Throwable thrown) {
-    if (isLoggable(level)) {
-      if (msgKey != null && !msgKey.equals("")) {
-        // get corresponding JSR-47 level
-        java.util.logging.Level jsr47Level = getJSR47Level(level);
-
-        logger.logp(jsr47Level, sourceClass, sourceMethod, I18nUtil.localizeMessage(bundleName,
-                msgKey, null, getExtensionClassLoader()), thrown);
-      }
-
-      if (thrown != null && (msgKey == null || msgKey.equals(""))) {
-        // get corresponding JSR-47 level
-        java.util.logging.Level jsr47Level = getJSR47Level(level);
-
-        // log exception
-        logger.logp(jsr47Level, sourceClass, sourceMethod, EXCEPTION_MESSAGE, thrown);
-      }
-    }
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#logrb(org.apache.uima.util.Level, java.lang.String,
-   *      java.lang.String, java.lang.String, java.lang.String)
-   */
-  public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName,
-          String msgKey) {
-    if (isLoggable(level)) {
-      if (msgKey == null || msgKey.equals(""))
-        return;
-
-      // get corresponding JSR-47 level
-      java.util.logging.Level jsr47Level = getJSR47Level(level);
-
-      logger.logp(jsr47Level, sourceClass, sourceMethod, I18nUtil.localizeMessage(bundleName,
-              msgKey, null, getExtensionClassLoader()));
-    }
-  }
-
-  public void log(String wrapperFQCN, Level level, String message, Throwable thrown) {
-    // get corresponding JSR-47 level
-    java.util.logging.Level jsr47Level = getJSR47Level(level);
-    String[] sourceInfo = getStackTraceInfo(wrapperFQCN, new Throwable());
-
-    // log exception
-    logger.logp(jsr47Level, sourceInfo[0], sourceInfo[1], message, thrown);
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#setResourceManager(org.apache.uima.resource.ResourceManager)
-   */
-  public void setResourceManager(ResourceManager resourceManager) {
-    mResourceManager = resourceManager;
-  }
-
-  /**
-   * Gets the extension ClassLoader to used to locate the message digests. If this returns null,
-   * then message digests will be searched for using this.class.getClassLoader().
-   */
-  private ClassLoader getExtensionClassLoader() {
-    if (mResourceManager == null)
-      return null;
-    else
-      return mResourceManager.getExtensionClassLoader();
-  }
-
   /**
    * JSR-47 level mapping to UIMA level mapping.
    * 
-   * SEVERE (highest value) -%gt; SEVERE WARNING -%gt; WARNING INFO -%gt; INFO CONFIG -%gt; CONFIG FINE -%gt; FINE
-   * FINER -%gt; FINER FINEST (lowest value) -%gt; FINEST OFF -%gt; OFF ALL -%gt; ALL
+   * Maps via marker values for UIMA_MARKER_CONFIG and UIMA_MARKER_FINEST
+   * 
+   * SEVERE (highest value) -%gt; SEVERE<br> 
+   * WARNING -%gt; WARNING<br> 
+   * INFO -%gt; INFO <br>
+   * CONFIG -%gt; CONFIG <br>
+   * FINE -%gt; FINE<br>
+   * FINER -%gt; FINER <br>
+   * FINEST (lowest value) -%gt; FINEST<br> 
+   * OFF -%gt; OFF <br>
+   * ALL -%gt; ALL<br>
    * 
    * @param level
    *          uima level
+   * @param m the marker
    * 
    * @return Level - corresponding JSR47 level
    */
-  private java.util.logging.Level getJSR47Level(Level level) {
+  public static java.util.logging.Level getJSR47Level(Level level, Marker m) {
     if (null == level) {
       return null;
     }
@@ -466,69 +192,181 @@
       case org.apache.uima.util.Level.WARNING_INT:
         return java.util.logging.Level.WARNING;
       case org.apache.uima.util.Level.INFO_INT:
-        return java.util.logging.Level.INFO;
+        return (m == UIMA_MARKER_CONFIG) 
+                 ? java.util.logging.Level.CONFIG
+                 : java.util.logging.Level.INFO;
       case org.apache.uima.util.Level.CONFIG_INT:
         return java.util.logging.Level.CONFIG;
       case org.apache.uima.util.Level.FINE_INT:
         return java.util.logging.Level.FINE;
       case org.apache.uima.util.Level.FINER_INT:
-        return java.util.logging.Level.FINER;
+        // could be DEBUG with marker FINEST, DEBUG_INT == FINER_INT
+        return (m == UIMA_MARKER_FINEST)
+                 ? java.util.logging.Level.FINEST
+                 : java.util.logging.Level.FINER;
       case org.apache.uima.util.Level.FINEST_INT:
         return java.util.logging.Level.FINEST;
+          
       default: // for all other cases return Level.ALL
         return java.util.logging.Level.ALL;
     }
   }
 
-  /**
-   * returns the method name and the line number if available
+  /*
+   * (non-Javadoc)
    * 
-   * @param thrown
-   *          the thrown
-   * 
-   * @return String[] - fist element is the source class, second element is the method name with
-   *         linenumber if available
+   * @see org.apache.uima.util.Logger#isLoggable(org.apache.uima.util.Level)
    */
-  private String[] getStackTraceInfo(String wrapperFQCN, Throwable thrown) {
-    StackTraceElement[] stackTraceElement = thrown.getStackTrace();
+  @Override
+  public boolean isLoggable(Level level) {
+    return logger.isLoggable(getJSR47Level(level, null));
+  }
+  
+  @Override
+  public boolean isLoggable(Level level, Marker m) {
+    return logger.isLoggable(getJSR47Level(level, m));
+  }
 
-    String sourceMethod = "";
-    String sourceClass = "";
-    int lineNumber = 0;
-    
-    try {
-      int index = 0;
-      if (wrapperFQCN != null) {
-        boolean found = false;
-        while (index < stackTraceElement.length) {
-          if (wrapperFQCN.equals(stackTraceElement[index].getClassName())) {
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.uima.util.Logger#setLevel(org.apache.uima.util.Level)
+   */
+  @Override
+  public void setLevel(Level level) {
+    logger.setLevel(getJSR47Level(level, null));
+  }
+
+//  /**
+//   * Log the message at the specified level with the specified throwable if any.
+//   * This method creates a LogRecord and fills in caller date before calling
+//   * this instance's JDK14 logger.
+//   * 
+//   * See bug report #13 for more details.
+//   * 
+//   * @param level
+//   * @param msg
+//   * @param t
+//   */
+//  private void log(String callerFQCN, Level level, String msg, Throwable t) {
+//      // millis and thread are filled by the constructor
+//      LogRecord record = new LogRecord(level, msg);
+//      record.setLoggerName(getName());
+//      record.setThrown(t);
+//      // Note: parameters in record are not set because SLF4J only
+//      // supports a single formatting style
+//      fillCallerData(callerFQCN, record);
+//      logger.log(record);
+//  }
+  
+
+  @Override
+  public void log(Marker m, String aFqcn, Level level, String msg, Object[] args, Throwable throwable) {    
+    if (isLoggable(level, m)) {
+      log(m, aFqcn, level, MessageFormat.format(msg, args), throwable);
+    }
+  }
+  
+  @Override
+  public void log(Marker m, String aFqcn, Level level, String msg, Throwable throwable) {
+    if (isLoggable(level, m)) {    
+      LogRecord record = new LogRecord(getJSR47Level(level, m), msg);
+      record.setLoggerName(getName());
+      record.setThrown(throwable);
+      
+      StackTraceElement[] elements = new Throwable().getStackTrace();
+      StackTraceElement top = null;
+      
+      boolean found = false;
+      
+      for (int i = 0; i < elements.length; i++) {
+        final String className = elements[i].getClassName();
+        if (className.equals(aFqcn)) {
+          if (found) {
+            continue;   // keep going until not found
+          } else {
             found = true;
+            continue;
+          }
+        } else {
+          if (found) {
+            top = elements[i];  
             break;
           }
-          index++;
-        }
-        if (!found) {
-          index = 0;
-        }
+        } 
       }
-      index++;
-      
-      lineNumber = stackTraceElement[index].getLineNumber();
-      sourceMethod = stackTraceElement[index].getMethodName();
-      sourceClass = stackTraceElement[index].getClassName();
-    } catch (Exception ex) {
-      // do nothing, use the initialized string members
+  
+      if (top != null) {
+        record.setSourceClassName(top.getClassName());
+        record.setSourceMethodName(top.getMethodName() + "(" + top.getLineNumber() + ")");
+      }
+      logger.log(record);
     }
-
-    if (lineNumber > 0) {
-      StringBuffer buffer = new StringBuffer(25);
-      buffer.append(sourceMethod);
-      buffer.append('(');
-      buffer.append(lineNumber);
-      buffer.append(')');
-      sourceMethod = buffer.toString();
-    }
-
-    return new String[] { sourceClass, sourceMethod };
   }
+
+  
+  @Override
+  public void log2(Marker m, String aFqcn, Level level, String msg, Object[] args, Throwable throwable) {
+    // this version of MessageFormatter does the {} style
+    log(m, aFqcn, level, MessageFormatter.format(msg, args).getMessage(), zeroLengthArray, throwable);
+  }
+  
+  @Override
+  public String getName() {
+    return logger.getName();
+  }
+
+  @Override
+  public boolean isDebugEnabled() {
+    return logger.isLoggable(java.util.logging.Level.FINE);
+  }
+
+  @Override
+  public boolean isDebugEnabled(Marker arg0) {
+    return isDebugEnabled();
+  }
+
+  @Override
+  public boolean isErrorEnabled() {
+    return logger.isLoggable(java.util.logging.Level.SEVERE);
+  }
+
+  @Override
+  public boolean isErrorEnabled(Marker arg0) {
+    return isErrorEnabled();
+  }
+
+  @Override
+  public boolean isInfoEnabled() {
+    return logger.isLoggable(java.util.logging.Level.INFO) ||
+           logger.isLoggable(java.util.logging.Level.CONFIG);
+  }
+
+  @Override
+  public boolean isInfoEnabled(Marker arg0) {
+    return isInfoEnabled();
+  }
+
+  @Override
+  public boolean isTraceEnabled() {
+    return logger.isLoggable(java.util.logging.Level.FINER) ||
+        logger.isLoggable(java.util.logging.Level.FINEST);
+  }
+
+  @Override
+  public boolean isTraceEnabled(Marker arg0) {
+    return isTraceEnabled();
+  }
+
+  @Override
+  public boolean isWarnEnabled() {
+    return logger.isLoggable(java.util.logging.Level.WARNING);
+  }
+
+  @Override
+  public boolean isWarnEnabled(Marker arg0) {
+    return isWarnEnabled();
+  }
+
 }
+
diff --git a/uimaj-core/src/main/java/org/apache/uima/util/impl/Log4jLogger_impl.java b/uimaj-core/src/main/java/org/apache/uima/util/impl/Log4jLogger_impl.java
index 499153a..35946cc 100644
--- a/uimaj-core/src/main/java/org/apache/uima/util/impl/Log4jLogger_impl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/util/impl/Log4jLogger_impl.java
@@ -18,33 +18,127 @@
  */
 package org.apache.uima.util.impl;
 
-import java.io.OutputStream;
-import java.io.PrintStream;
 import java.text.MessageFormat;
 
-import org.apache.uima.internal.util.I18nUtil;
-import org.apache.uima.resource.ResourceManager;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Filter.Result;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.message.MessageFactory;
+import org.apache.logging.log4j.spi.AbstractLogger;
+import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;
 import org.apache.uima.util.Level;
 import org.apache.uima.util.Logger;
+import org.slf4j.Marker;
 
 /**
  * UIMA Logging interface implementation for Log4j
+ * 
+ * This version is for Log4j version 2, from Apache
+ * Built using version 2.8
+ * 
  */
-public class Log4jLogger_impl implements Logger {
+public class Log4jLogger_impl extends Logger_common_impl {
 
-   private static final String EXCEPTION_MESSAGE = "Exception occurred";
+  final static private Object[] zeroLengthArray = new Object[0];
+  /**
+   * <p>Markers that are for marking levels not supported by log4j.
+   * <p>
+   * These are log4j class versions of the slf4j markers.
+   */
+  final static private org.apache.logging.log4j.Marker LOG4J_CONFIG = m(UIMA_MARKER_CONFIG);
+  final static private org.apache.logging.log4j.Marker LOG4J_FINEST = m(UIMA_MARKER_FINEST);
+   
+  /**
+   * Filters for use in setLevel calls, for levels that need marker filtering.
+   * <p>
+   * Filters return NEUTRAL unless it's for the associated level.
+   * For associated level (e.g., INFO or TRACE), they return 
+   *   ACCEPT if the marker is present
+   *   DENY otherwise
+   */
+  
+  static private org.apache.logging.log4j.core.filter.AbstractFilter makeFilter(
+      final org.apache.logging.log4j.Level tLevel, org.apache.logging.log4j.Marker tMarker) {
+    return new org.apache.logging.log4j.core.filter.AbstractFilter() {
 
+      /* (non-Javadoc)
+       * @see org.apache.logging.log4j.core.filter.AbstractFilter#filter(org.apache.logging.log4j.core.LogEvent)
+       */
+      @Override
+      public Result filter(LogEvent event) {
+        if (event.getLevel() == tLevel) {
+          return (event.getMarker() != tMarker) 
+                   ? Result.DENY
+                   : Result.ACCEPT;
+        }
+        return Result.NEUTRAL;
+      }
+
+      /* (non-Javadoc)
+       * @see org.apache.logging.log4j.core.filter.AbstractFilter#filter(org.apache.logging.log4j.core.Logger, org.apache.logging.log4j.Level, org.apache.logging.log4j.Marker, org.apache.logging.log4j.message.Message, java.lang.Throwable)
+       */
+      @Override
+      public Result filter(org.apache.logging.log4j.core.Logger logger,
+          org.apache.logging.log4j.Level level, org.apache.logging.log4j.Marker marker, Message msg,
+          Throwable t) {
+        if (level == tLevel) {
+          return (marker != tMarker) 
+                   ? Result.DENY
+                   : Result.ACCEPT;
+        }
+        return Result.NEUTRAL;
+      }
+
+      /* (non-Javadoc)
+       * @see org.apache.logging.log4j.core.filter.AbstractFilter#filter(org.apache.logging.log4j.core.Logger, org.apache.logging.log4j.Level, org.apache.logging.log4j.Marker, java.lang.Object, java.lang.Throwable)
+       */
+      @Override
+      public Result filter(org.apache.logging.log4j.core.Logger logger,
+          org.apache.logging.log4j.Level level, org.apache.logging.log4j.Marker marker, Object msg,
+          Throwable t) {
+        if (level == tLevel) {
+          return (marker != tMarker) 
+                   ? Result.DENY
+                   : Result.ACCEPT;
+        }
+        return Result.NEUTRAL;
+      }
+
+      /* (non-Javadoc)
+       * @see org.apache.logging.log4j.core.filter.AbstractFilter#filter(org.apache.logging.log4j.core.Logger, org.apache.logging.log4j.Level, org.apache.logging.log4j.Marker, java.lang.String, java.lang.Object[])
+       */
+      @Override
+      public Result filter(org.apache.logging.log4j.core.Logger logger,
+          org.apache.logging.log4j.Level level, org.apache.logging.log4j.Marker marker, String msg,
+          Object... params) {
+        if (level == tLevel) {
+          return (marker != tMarker) 
+                   ? Result.DENY
+                   : Result.ACCEPT;
+        }
+        return Result.NEUTRAL;
+      }
+
+    };
+  }
+  
+  final static private org.apache.logging.log4j.core.filter.AbstractFilter FILTER_CONFIG = 
+      makeFilter(org.apache.logging.log4j.Level.INFO, LOG4J_CONFIG);
+
+  final static private org.apache.logging.log4j.core.filter.AbstractFilter FILTER_FINEST = 
+      makeFilter(org.apache.logging.log4j.Level.TRACE, LOG4J_FINEST);
+         
    /**
     * logger object from the underlying Log4j logging framework
+    * The ExtendedLoggerWrapper includes the ability to specify the wrapper class
     */
-   private org.apache.log4j.Logger logger = null;
+  final private ExtendedLoggerWrapper logger;
 
-   /**
-    * ResourceManager whose extension ClassLoader will be used to locate the
-    * message digests. Null will cause the ClassLoader to default to
-    * this.class.getClassLoader().
-    */
-   private ResourceManager mResourceManager = null;
+  final private org.apache.logging.log4j.core.Logger coreLogger;
+
+  final private MessageFactory mf;
 
    /**
     * create a new LogWrapper class for the specified source class
@@ -53,21 +147,21 @@
     *           specified source class
     */
    private Log4jLogger_impl(Class<?> component) {
-      super();
+      super(component);
 
-      if (component != null) {
-         logger = org.apache.log4j.Logger.getLogger(component);
-      } else {
-         logger = org.apache.log4j.Logger.getLogger("org.apache.uima");
-      }
+      coreLogger = (org.apache.logging.log4j.core.Logger) LogManager.getLogger( (null == component) 
+                                       ?  "org.apache.uima"
+                                       : component.getName());
+      mf = coreLogger.getMessageFactory();
+      
+      logger = new ExtendedLoggerWrapper((AbstractLogger) coreLogger, coreLogger.getName(), mf);
    }
-
-   /**
-    * create a new LogWrapper object with the default logger from the Log4j
-    * logging framework
-    */
-   private Log4jLogger_impl() {
-      this(null);
+   
+   private Log4jLogger_impl(Log4jLogger_impl l, int limit) {
+     super(l, limit);
+     this.logger = l.logger;
+     this.coreLogger = l.coreLogger;
+     this.mf = l.mf;
    }
 
    /**
@@ -88,393 +182,202 @@
     *         framework logger
     */
    public static synchronized Logger getInstance() {
-      return new Log4jLogger_impl();
+      return new Log4jLogger_impl(null);
    }
+   
+   public Log4jLogger_impl getLimitedLogger(int aLimit) {
+     if (aLimit == Integer.MAX_VALUE || aLimit == this.limit_common) {
+       return this;
+     }
+     return new Log4jLogger_impl(this, aLimit);
+   }
+  
 
    /**
-    * Logs a message with level INFO.
+    * log4j level mapping to UIMA level mapping. <br>
+    * SEVERE (highest value) -&gt; SEVERE <br> 
+    * WARNING -&gt; WARNING <br> 
+    * INFO -&gt; INFO <br> 
+    * CONFIG -&gt; INFO <br> 
+    * FINE -&gt; DEBUG <br> 
+    * FINER -&gt; TRACE <br> 
+    * FINEST (lowest value) -&gt; TRACE <br> 
+    * OFF -&gt; OFF <br> 
+    * ALL -&gt; ALL <br>
     * 
-    * @deprecated use new function with log level
-    * @param aMessage
-    *           the message to be logged
+    * @param level uima level
+    * @return Level - corresponding log4j 2 level
     */
-   @Deprecated
-  public void log(String aMessage) {
-      if (isLoggable(Level.INFO)) {
-         if (aMessage == null || aMessage.equals(""))
-            return;
-
-         String[] sourceInfo = getStackTraceInfo(new Throwable());
-
-         org.apache.log4j.Logger.getLogger(sourceInfo[0]).log(getClass().getName(), 
-                 org.apache.log4j.Level.INFO, aMessage, null);
+   static org.apache.logging.log4j.Level getLog4jLevel(Level level) {
+      switch (level.toInteger()) {
+      case org.apache.uima.util.Level.OFF_INT:
+         return org.apache.logging.log4j.Level.OFF;
+      case org.apache.uima.util.Level.SEVERE_INT:
+         return org.apache.logging.log4j.Level.ERROR;
+      case org.apache.uima.util.Level.WARNING_INT:
+         return org.apache.logging.log4j.Level.WARN;
+      case org.apache.uima.util.Level.INFO_INT:
+         return org.apache.logging.log4j.Level.INFO;
+      case org.apache.uima.util.Level.CONFIG_INT:
+         return org.apache.logging.log4j.Level.INFO;
+      case org.apache.uima.util.Level.FINE_INT:
+         return org.apache.logging.log4j.Level.DEBUG;
+      case org.apache.uima.util.Level.FINER_INT:
+        return org.apache.logging.log4j.Level.TRACE;
+      case org.apache.uima.util.Level.FINEST_INT:
+        return org.apache.logging.log4j.Level.TRACE;
+      default: // for all other cases return Level.ALL
+         return org.apache.logging.log4j.Level.ALL;
       }
    }
-
-   /**
-    * Logs a message with a message key and the level INFO
-    * 
-    * @deprecated use new function with log level
-    * @see org.apache.uima.util.Logger#log(java.lang.String, java.lang.String,
-    *      java.lang.Object[])
-    */
-   @Deprecated
-   public void log(String aResourceBundleName, String aMessageKey,
-         Object[] aArguments) {
-      if (isLoggable(Level.INFO)) {
-         if (aMessageKey == null || aMessageKey.equals(""))
-            return;
-
-         String[] sourceInfo = getStackTraceInfo(new Throwable());
-         org.apache.log4j.Logger.getLogger(sourceInfo[0]).log(getClass().getName(), 
-               org.apache.log4j.Level.INFO, 
-               I18nUtil.localizeMessage(aResourceBundleName, aMessageKey,
-                     aArguments, getExtensionClassLoader()), null);
-      }
+   
+   private static org.apache.logging.log4j.Marker m(Marker m) {
+     return (m == null) 
+              ? null
+              : ((org.apache.logging.slf4j.Log4jMarker)m).getLog4jMarker();  
    }
-
-   /**
-    * Logs an exception with level INFO
-    * 
-    * @deprecated use new function with log level
-    * @param aException
-    *           the exception to be logged
-    */
-   @Deprecated
-   public void logException(Exception aException) {
-      if (isLoggable(Level.INFO)) {
-         if (aException == null)
-            return;
-
-         String[] sourceInfo = getStackTraceInfo(new Throwable());
-
-         // log exception
-         org.apache.log4j.Logger.getLogger(sourceInfo[0]).log(getClass().getName(), 
-               org.apache.log4j.Level.INFO, EXCEPTION_MESSAGE, aException);
-      }
-   }
-
-   /**
-    * @see org.apache.uima.util.Logger#setOutputStream(java.io.OutputStream)
-    * @deprecated use external configuration possibility
-    */
-   @Deprecated
-   public void setOutputStream(OutputStream out) {
-      throw new UnsupportedOperationException(
-            "Method setOutputStream(OutputStream out) not supported");
-   }
-
-   /**
-    * @see org.apache.uima.util.Logger#setOutputStream(java.io.PrintStream)
-    * @deprecated use external configuration possibility
-    */
-   @Deprecated
-  public void setOutputStream(PrintStream out) {
-      throw new UnsupportedOperationException(
-            "Method setOutputStream(PrintStream out) not supported");
-   }
-
+            
    /*
     * (non-Javadoc)
     * 
     * @see org.apache.uima.util.Logger#isLoggable(org.apache.uima.util.Level)
     */
    public boolean isLoggable(Level level) {
-      org.apache.log4j.Level log4jLevel = getLog4jLevel(level);
-
-      return logger.isEnabledFor(log4jLevel);
-   }
-
-   /*
-    * (non-Javadoc)
-    * 
-    * @see org.apache.uima.util.Logger#setLevel(org.apache.uima.util.Level)
-    */
-   public void setLevel(Level level) {
-      // get corresponding Log4j level
-      org.apache.log4j.Level log4jLevel = getLog4jLevel(level);
-
-      logger.setLevel(log4jLevel);
-   }
-
-   /*
-    * (non-Javadoc)
-    * 
-    * @see org.apache.uima.util.Logger#log(org.apache.uima.util.Level,
-    *      java.lang.String)
-    */
-   public void log(Level level, String aMessage) {
-      if (isLoggable(level)) {
-         if (aMessage == null || aMessage.equals(""))
-            return;
-
-         org.apache.log4j.Level log4jLevel = getLog4jLevel(level);
-
-         logger.log(getClass().getName(), log4jLevel, aMessage, null);
-      }
-   }
-
-   /*
-    * (non-Javadoc)
-    * 
-    * @see org.apache.uima.util.Logger#log(org.apache.uima.util.Level,
-    *      java.lang.String, java.lang.Object)
-    */
-   public void log(Level level, String aMessage, Object param1) {
-      if (isLoggable(level)) {
-         if (aMessage == null || aMessage.equals(""))
-            return;
-         org.apache.log4j.Level log4jLevel = getLog4jLevel(level);
-
-         logger.log(getClass().getName(), log4jLevel, MessageFormat.format(aMessage,
-               new Object[] { param1 }), null);
-      }
-   }
-
-   /*
-    * (non-Javadoc)
-    * 
-    * @see org.apache.uima.util.Logger#log(org.apache.uima.util.Level,
-    *      java.lang.String, java.lang.Object[])
-    */
-   public void log(Level level, String aMessage, Object[] params) {
-      if (isLoggable(level)) {
-         if (aMessage == null || aMessage.equals(""))
-            return;
-
-         // get corresponding Log4j level
-         org.apache.log4j.Level log4jLevel = getLog4jLevel(level);
-
-         logger.log(getClass().getName(), log4jLevel, MessageFormat.format(aMessage, params), null);
-
-      }
-   }
-
-   /*
-    * (non-Javadoc)
-    * 
-    * @see org.apache.uima.util.Logger#log(org.apache.uima.util.Level,
-    *      java.lang.String, java.lang.Throwable)
-    */
-   public void log(Level level, String aMessage, Throwable thrown) {
-      if (isLoggable(level)) {
-         org.apache.log4j.Level log4jLevel = getLog4jLevel(level);
-
-         if (aMessage != null && !aMessage.equals("")) {
-            // get corresponding Log4j level
-
-            logger.log(getClass().getName(), log4jLevel, aMessage, thrown);
-         }
-
-         if (thrown != null && (aMessage == null || aMessage.equals(""))) {
-            // get corresponding Log4j level
-            // log exception
-            logger.log(getClass().getName(), log4jLevel, EXCEPTION_MESSAGE, thrown);
-         }
-      }
-
-   }
-
-   /*
-    * (non-Javadoc)
-    * 
-    * @see org.apache.uima.util.Logger#logrb(org.apache.uima.util.Level,
-    *      java.lang.String, java.lang.String, java.lang.String,
-    *      java.lang.String, java.lang.Object)
-    */
-   public void logrb(Level level, String sourceClass, String sourceMethod,
-         String bundleName, String msgKey, Object param1) {
-      if (isLoggable(level)) {
-         if (msgKey == null || msgKey.equals(""))
-            return;
-
-         if (sourceClass == null) {
-            sourceClass = "";
-         }
-
-         // get corresponding Log4j level
-         org.apache.log4j.Level log4jLevel = getLog4jLevel(level);
-
-         logger.log(getClass().getName(), log4jLevel, I18nUtil.localizeMessage(bundleName, msgKey,
-               new Object[] { param1 }, getExtensionClassLoader()), null);
-      }
-   }
-
-   /*
-    * (non-Javadoc)
-    * 
-    * @see org.apache.uima.util.Logger#logrb(org.apache.uima.util.Level,
-    *      java.lang.String, java.lang.String, java.lang.String,
-    *      java.lang.String, java.lang.Object[])
-    */
-   public void logrb(Level level, String sourceClass, String sourceMethod,
-         String bundleName, String msgKey, Object[] params) {
-      if (isLoggable(level)) {
-         if (msgKey == null || msgKey.equals(""))
-            return;
-         if (sourceClass == null) {
-            sourceClass = "";
-         }
-
-         // get corresponding Log4j level
-         org.apache.log4j.Level log4jLevel = getLog4jLevel(level);
-
-         logger.log(getClass().getName(), log4jLevel, I18nUtil.localizeMessage(bundleName, msgKey,
-               params, getExtensionClassLoader()), null);
-      }
-   }
-
-   /*
-    * (non-Javadoc)
-    * 
-    * @see org.apache.uima.util.Logger#logrb(org.apache.uima.util.Level,
-    *      java.lang.String, java.lang.String, java.lang.String,
-    *      java.lang.String, java.lang.Throwable)
-    */
-   public void logrb(Level level, String sourceClass, String sourceMethod,
-         String bundleName, String msgKey, Throwable thrown) {
-      if (isLoggable(level)) {
-         org.apache.log4j.Level log4jLevel = getLog4jLevel(level);
-
-         if (sourceClass == null) {
-            sourceClass = "";
-         }
-
-         if (msgKey != null && !msgKey.equals("")) {
-            // get corresponding Log4j level
-            org.apache.log4j.Logger.getLogger(sourceClass).log(getClass().getName(), 
-                  log4jLevel,
-                  I18nUtil.localizeMessage(bundleName, msgKey, null,
-                        getExtensionClassLoader()), thrown);
-         }
-
-         if (thrown != null && (msgKey == null || msgKey.equals(""))) {
-
-            // log exception
-            org.apache.log4j.Logger.getLogger(sourceClass).log(getClass().getName(), log4jLevel,
-                  EXCEPTION_MESSAGE, thrown);
-         }
-      }
-   }
-
-   /*
-    * (non-Javadoc)
-    * 
-    * @see org.apache.uima.util.Logger#logrb(org.apache.uima.util.Level,
-    *      java.lang.String, java.lang.String, java.lang.String,
-    *      java.lang.String)
-    */
-   public void logrb(Level level, String sourceClass, String sourceMethod,
-         String bundleName, String msgKey) {
-      if (isLoggable(level)) {
-
-         if (msgKey == null || msgKey.equals(""))
-            return;
-
-         if (sourceClass == null) {
-            sourceClass = "";
-         }
-         // get corresponding Log4j level
-         org.apache.log4j.Level log4jLevel = getLog4jLevel(level);
-         org.apache.log4j.Logger.getLogger(sourceClass).log(getClass().getName(), log4jLevel,
-               I18nUtil.localizeMessage(bundleName, msgKey, null, getExtensionClassLoader()), null);
-
-         // logger.log(log4jLevel, sourceClass + sourceMethod +
-         // I18nUtil.localizeMessage(bundleName, msgKey, null,
-         // getExtensionClassLoader()));
-      }
-   }
-
-   public void log(String wrapperFQCN, Level level, String message, Throwable thrown) {
-     // get corresponding Log4j level
-     org.apache.log4j.Level log4jLevel = getLog4jLevel(level);
-     logger.log(wrapperFQCN, log4jLevel, message, thrown);
+     if (level == Level.CONFIG) {
+       Result r = filterTest(org.apache.logging.log4j.Level.INFO, LOG4J_CONFIG);       
+       return r == Result.ACCEPT ||
+              (r == Result.NEUTRAL && coreLogger.isEnabled(org.apache.logging.log4j.Level.TRACE));
+     }
+     if (level == Level.FINEST) {
+       Result r = filterTest(org.apache.logging.log4j.Level.TRACE, LOG4J_FINEST);
+       return r == Result.ACCEPT ||
+              (r == Result.NEUTRAL && coreLogger.isEnabled(org.apache.logging.log4j.Level.TRACE));
+       
+     }
+     return coreLogger.isEnabled(getLog4jLevel(level));
    }
    
+   public boolean isLoggable(Level level, Marker marker) {
+     return coreLogger.isEnabled(getLog4jLevel(level), m(marker));
+   }
+   
+   // workaround for bug in log4j 2
+   // where it skips using filters set via APIs for this test
+   /**
+    * 
+    * @param level a log4j level that's equal or above (ERROR is highest) the level being tested
+    * @param marker - the marker that needs to be there to allow this
+    * @return - the result of running the logger filter test if there is one, else NEUTRAL
+    */
+   private Result filterTest(org.apache.logging.log4j.Level level, org.apache.logging.log4j.Marker marker) {
+     Filter filter = coreLogger.get().getFilter();
+     if (null != filter) {
+       return filter.filter(coreLogger, level, marker, (String) null, (Object[])null);
+     }
+     return Result.NEUTRAL;
+   }
+
    /*
-    * (non-Javadoc)
-    * 
-    * @see org.apache.uima.util.Logger#setResourceManager(org.apache.uima.resource.ResourceManager)
+    * ONLY FOR TEST CASE USE
     */
-   public void setResourceManager(ResourceManager resourceManager) {
-      mResourceManager = resourceManager;
+   public void setLevel(Level level) {    
+     if (level == Level.CONFIG) {
+       // next seems to do nothing...
+//       coreLogger.getContext().getConfiguration().getLoggerConfig(coreLogger.getName()).addFilter(FILTER_CONFIG);
+       // next also seems to do nothing...
+//       ((LoggerContext)LogManager.getContext(false)).getConfiguration().getLoggerConfig(coreLogger.getName()).addFilter(FILTER_CONFIG);
+       coreLogger.get().addFilter(FILTER_CONFIG);
+     } else {
+//       coreLogger.getContext().getConfiguration().getLoggerConfig(coreLogger.getName()).removeFilter(FILTER_CONFIG);
+       coreLogger.get().removeFilter(FILTER_CONFIG);
+     }
+     
+     if (level == Level.FINEST) {
+       coreLogger.get().addFilter(FILTER_FINEST);
+     } else {
+       coreLogger.get().removeFilter(FILTER_FINEST);
+     }
+          
+     coreLogger.get().setLevel(getLog4jLevel(level));
+     coreLogger.getContext().updateLoggers();
    }
 
-   /**
-    * Gets the extension ClassLoader to used to locate the message digests. If
-    * this returns null, then message digests will be searched for using
-    * this.class.getClassLoader().
-    */
-   private ClassLoader getExtensionClassLoader() {
-      if (mResourceManager == null)
-         return null;
-      else
-         return mResourceManager.getExtensionClassLoader();
+   public void log(Marker m, String aFqcn, Level level, String message, Object[] args, Throwable thrown) {
+     log(m, aFqcn, level, MessageFormat.format(message, args), thrown);
+   }  
+
+   @Override
+   public void log(Marker m, String aFqcn, Level level, String message, Throwable thrown) {
+     logger.logIfEnabled(aFqcn, getLog4jLevel(level), m(m), message, thrown);
    }
 
-   /**
-    * log4j level mapping to UIMA level mapping. SEVERE (highest value) ->
-    * SEVERE WARNING -%gt; WARNING INFO -%gt; INFO CONFIG -%gt; CONFIG FINE -%gt; FINE FINER ->
-    * FINER FINEST (lowest value) -%gt; FINEST OFF -%gt; OFF ALL -%gt; ALL
-    * 
-    * @param level
-    *           uima level
-    * @return Level - corresponding JSR47 level
-    */
-   private org.apache.log4j.Level getLog4jLevel(Level level) {
-      switch (level.toInteger()) {
-      case org.apache.uima.util.Level.OFF_INT:
-         return org.apache.log4j.Level.OFF;
-      case org.apache.uima.util.Level.SEVERE_INT:
-         return org.apache.log4j.Level.ERROR;
-      case org.apache.uima.util.Level.WARNING_INT:
-         return org.apache.log4j.Level.WARN;
-      case org.apache.uima.util.Level.INFO_INT:
-         return org.apache.log4j.Level.INFO;
-      case org.apache.uima.util.Level.CONFIG_INT:
-         return org.apache.log4j.Level.INFO;
-      case org.apache.uima.util.Level.FINE_INT:
-         return org.apache.log4j.Level.DEBUG;
-      case org.apache.uima.util.Level.FINER_INT:
-         return org.apache.log4j.Level.ALL;
-      case org.apache.uima.util.Level.FINEST_INT:
-         return org.apache.log4j.Level.ALL;
-      default: // for all other cases return Level.ALL
-         return org.apache.log4j.Level.ALL;
-      }
+   public void log2(Marker m, String aFqcn, Level level, String message, Object[] args, Throwable thrown) {
+     if (thrown != null) {
+       assert args == null;
+       logger.logIfEnabled(aFqcn, getLog4jLevel(level), m(m), message, thrown);
+     } else {
+       logger.logIfEnabled(aFqcn, getLog4jLevel(level), m(m), message, args);
+     }
+   }  
+   
+
+   // ---------------------- 
+   
+   @Override
+   public String getName() {
+     return logger.getName();
    }
 
-   /**
-    * returns the method name and the line number if available
-    * 
-    * @param thrown
-    *           the thrown
-    * @return String[] - fist element is the source class, second element is the
-    *         method name with linenumber if available
-    */
-   private String[] getStackTraceInfo(Throwable thrown) {
-      StackTraceElement[] stackTraceElement = thrown.getStackTrace();
+   // ----------------------    
 
-      String sourceMethod = "";
-      String sourceClass = "";
-      int lineNumber = 0;
-      try {
-         lineNumber = stackTraceElement[1].getLineNumber();
-         sourceMethod = stackTraceElement[1].getMethodName();
-         sourceClass = stackTraceElement[1].getClassName();
-      } catch (Exception ex) {
-         // do nothing, use the initialized string members
-      }
-
-      if (lineNumber > 0) {
-         StringBuffer buffer = new StringBuffer(25);
-         buffer.append(sourceMethod);
-         buffer.append('(');
-         buffer.append(lineNumber);
-         buffer.append(')');
-         sourceMethod = buffer.toString();
-      }
-
-      return new String[] { sourceClass, sourceMethod };
+   @Override
+   public boolean isDebugEnabled() {
+     return logger.isDebugEnabled();
    }
+
+   @Override
+   public boolean isDebugEnabled(Marker arg0) {
+     return logger.isDebugEnabled(m(arg0));
+   }
+
+   @Override
+   public boolean isErrorEnabled() {
+     return logger.isErrorEnabled();
+   }
+
+   @Override
+   public boolean isErrorEnabled(Marker arg0) {
+     return logger.isErrorEnabled(m(arg0));
+   }
+
+   @Override
+   public boolean isInfoEnabled() {
+     return logger.isInfoEnabled();
+   }
+
+   @Override
+   public boolean isInfoEnabled(Marker arg0) {
+     return logger.isInfoEnabled(m(arg0));
+   }
+
+   @Override
+   public boolean isTraceEnabled() {
+     return logger.isTraceEnabled();
+   }
+
+   @Override
+   public boolean isTraceEnabled(Marker arg0) {
+     return logger.isTraceEnabled(m(arg0));
+   }
+
+   @Override
+   public boolean isWarnEnabled() {
+     return logger.isWarnEnabled();
+   }
+
+   @Override
+   public boolean isWarnEnabled(Marker arg0) {
+     return logger.isWarnEnabled(m(arg0));
+   }
+   
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/util/impl/Logger_common_impl.java b/uimaj-core/src/main/java/org/apache/uima/util/impl/Logger_common_impl.java
new file mode 100644
index 0000000..12cab65
--- /dev/null
+++ b/uimaj-core/src/main/java/org/apache/uima/util/impl/Logger_common_impl.java
@@ -0,0 +1,1200 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.util.impl;

+

+import java.io.OutputStream;

+import java.io.PrintStream;

+import java.text.MessageFormat;

+import java.util.function.Supplier;

+

+import org.apache.uima.internal.util.I18nUtil;

+import org.apache.uima.internal.util.Misc;

+import org.apache.uima.resource.ResourceManager;

+import org.apache.uima.util.Level;

+import org.apache.uima.util.Logger;

+import org.slf4j.Marker;

+

+/**

+ * UIMA Logging interface common implementation

+ * Specific loggers extend this class

+ * <p>

+ * Logging "location" information:

+ * <ul><li>This is the Classname / Methodname / and maybe line number where the logging statement is</li>

+ *   <li>is passed in on the logrb calls, but is not needed by modern loggers.</li>

+ *   <li>In V3, passed in value is ignored; loggers get what they need as configured.</li>

+ *   <li>In Java 9 this will be efficient</li>

+ * </ul>

+ * 

+ * <p>

+ * Limiting or throttling loggers:

+ * This is normally done using logger configuration.  For cases where UIMA is running as an 

+ * embedded library, sometimes Annotators log excessivly, and users do not have access to 

+ * the logging configuration.  But they do have access to APIs which create the UIMA pipelines.

+ * <p>

+ * V3 supports an additional param, AnalysisEngine.PARAM_THROTTLE_EXCESSIVE_ANNOTATOR_LOGGING

+ * which if set, specifies a limit of the number of log messages issued by Annotator code.

+ * <p>

+ * This requires: 

+ * <ul><li>marking loggers if they are Annotator loggers (e.g., their associated "class" used

+ * in setting the name of the logger, is assignable to AnalysisComponent_ImplBase,

+ * which includes: Annotators, CasMultipliers, and UimacppAnalysisComponents.

+ * </li>

+ * <li>When setting up a logger in the UimaContext logger code (via setLogger), checking if the logger

+ * is an Annotator logger, and if so, setting the limit on it from the parameter associated with

+ * the UIMA context.

+ * </li>

+ * </ul>

+ * 

+ * <p>The loggers with a limit are cloned for the particular pipeline (represented by the 

+ * root UIMA context), so that setting the limit only affects one pipeline.

+ * 

+ * <p>The common part of logging does:

+ *   <ul><li>optional throttling</li>

+ *   <li>the UIMA specific resource bundle message conversions</li>

+ *   <li>the conversion of variants of log methods to standard ones</li>

+ *  </ul>

+ * 

+ */

+public abstract class Logger_common_impl implements Logger {

+  protected static final String EXCEPTION_MESSAGE = "Exception occurred";

+  protected static final String[] EMPTY_STACK_TRACE_INFO = new String[] {null, null};

+   

+  protected final String fqcn =  this.getClass().getName(); // the subclass name

+  protected final String fqcnCmn = Logger_common_impl.class.getName();  // this class

+

+  // for throttling misbehaving Annotator Loggers  

+  private int SEVERE_COUNT = 0;

+  private int WARNING_COUNT = 0;

+  private int INFO_COUNT = 0;

+  private int CONFIG_COUNT = 0;

+  private int FINE_COUNT = 0;

+  private int FINER_COUNT = 0;

+  private int FINEST_COUNT = 0;

+  

+  protected final int limit_common;

+  private final boolean isLimited; // master switch tested first

+

+  /**

+   * ResourceManager whose extension ClassLoader will be used to locate the message digests. Null

+   * will cause the ClassLoader to default to this.class.getClassLoader().

+   */

+  private ResourceManager mResourceManager = null;

+  private boolean isAnnotatorLogger;

+    

+  protected Logger_common_impl(Class<?> component) {

+    this.limit_common = Integer.MAX_VALUE;

+    this.isLimited = false;

+  }

+  

+  /**

+   * Copy constructor for limited loggers

+   * @param lci the original logger to copy

+   * @param limit the limit

+   */

+  protected Logger_common_impl(Logger_common_impl lci, int limit) {

+    this.limit_common = limit;

+    this.isLimited = true;

+    this.isAnnotatorLogger = true;

+    this.mResourceManager = lci.mResourceManager;

+  }   

+  

+  /*********************************************

+   * Abstract methods 

+   * not in Uima Logger interface

+   * that must be implemented by subclasses

+   *********************************************/

+

+  /**

+   * The main log call implemented by subclasses

+   * @param m the marker

+   * @param aFqcn the fully qualified class name of the top-most logging class used

+   *                   to filter the stack trace to get the caller class / method info

+   * @param level the UIMA level

+   * @param message -

+   * @param args - arguments to be substituted into the message

+   * @param throwable - can be null

+   */

+  public abstract void log(Marker m, String aFqcn, Level level, 

+                           String message, Object[] args, Throwable throwable);

+  

+  /**

+   * The version of the main log call implemented by subclasses that uses {}, not {n} as the substitutable syntax.

+   * 

+   * This syntax is used by log4j, slf4j, and others.  But not used by uimaj logger basic syntax, or 

+   * Java Util Logger.

+   *

+   * This version is called by all new logging statments that don't need to be backwards compatible.

+   * e.g. logger.info, logger.error, logger.warn, etc.

+   * 

+   * @param m the marker

+   * @param aFqcn the fully qualified class name of the top-most logging class used

+   *                   to filter the stack trace to get the caller class / method info

+   * @param level the UIMA level

+   * @param message -

+   * @param args - arguments to be substituted into the message

+   * @param throwable - can be null

+   */

+  public abstract void log2(Marker m, String aFqcn, Level level,

+                           String message, Object[] args, Throwable throwable);

+  

+  /**

+   * The version of the main log call implemented by subclasses that skips the substitution

+   *   because it already was done by rb() 

+   * 

+   * @param m the marker

+   * @param aFqcn the fully qualified class name of the top-most logging class used

+   *                   to filter the stack trace to get the caller class / method info

+   * @param level the UIMA level

+   * @param message -

+   * @param throwable - can be null

+   */

+  public abstract void log(Marker m, String aFqcn, Level level,

+                           String message, Throwable throwable);

+  

+  /**

+   * @param level the Uima Level

+   * @return the Marker to use

+   */

+  public static Marker getMarkerForLevel(Level level) {

+    switch(level.toInteger()) {

+    case Level.CONFIG_INT: return UIMA_MARKER_CONFIG;

+    case Level.FINEST_INT: return UIMA_MARKER_FINEST;

+    default: return null;

+    }

+  }

+

+  /**

+   * Convert a standard UIMA call for wrapped loggers

+   * 

+   * @param aFqcn - fully qualified class name of highest level of logging impl.

+   *               The class / method above this in the stack trace is used 

+   *               for identifying where the logging call originated from.

+   * @param level the uima Level

+   * @param message the message

+   * @param thrown may be null              

+   */

+  @Override

+  public void log(String aFqcn, Level level, String message, Throwable thrown) {

+//    log(getMarkerForLevel(level), aFqcn, level, message, null, thrown);

+    log(getMarkerForLevel(level), aFqcn, level, message, thrown);

+  }

+  

+  /**

+   * 

+   * @param level -

+   * @return true if not limited

+   */

+  private boolean isNotLimited(Level level) {

+    if (!isLimited) {

+      return true;

+    }

+    switch(level.toInteger()) {

+    case Level.SEVERE_INT: if (SEVERE_COUNT >= limit_common) return false; SEVERE_COUNT++; return true; 

+    case Level.WARNING_INT: if (WARNING_COUNT >= limit_common) return false; WARNING_COUNT++; return true; 

+    case Level.INFO_INT: if (INFO_COUNT >= limit_common) return false; INFO_COUNT++; return true; 

+    case Level.CONFIG_INT: if (CONFIG_COUNT >= limit_common) return false; CONFIG_COUNT++; return true; 

+    case Level.FINE_INT: if (FINE_COUNT >= limit_common) return false; FINE_COUNT++; return true; 

+    case Level.FINER_INT: if (FINER_COUNT >= limit_common) return false; FINER_COUNT++; return true; 

+    case Level.FINEST_INT: if (FINEST_COUNT >= limit_common) return false; FINEST_COUNT++; return true; 

+    }

+    Misc.internalError();

+    return false;

+  }

+

+  /**

+   * @see org.apache.uima.util.Logger#setOutputStream(java.io.OutputStream)

+   * 

+   * @deprecated use external configuration possibility

+   */

+  @Override

+  @Deprecated

+  public void setOutputStream(OutputStream out) {

+    throw new UnsupportedOperationException();

+  }

+  

+  /**

+   * @see org.apache.uima.util.Logger#setOutputStream(java.io.PrintStream)

+   * 

+   * @deprecated use external configuration possibility

+   */

+  @Override

+  @Deprecated

+  public void setOutputStream(PrintStream out) {

+    throw new UnsupportedOperationException();

+  }

+  

+  /**

+   * Logs a message with level INFO.

+   * 

+   * @deprecated use new function with log level

+   * 

+   * @param aMessage

+   *          the message to be logged

+   */

+  @Override

+  @Deprecated

+  public void log(String aMessage) {

+    if (isLoggable(Level.INFO) && !isEmpty(aMessage) && isNotLimited(Level.INFO)) {

+      log(fqcnCmn, Level.INFO, aMessage, null);

+    }

+  }

+

+  /**

+   * Logs a message with a message key and the level INFO

+   * 

+   * @deprecated use new function with log level

+   * 

+   * @see org.apache.uima.util.Logger#log(java.lang.String, java.lang.String, java.lang.Object[])

+   */

+  @Override

+  @Deprecated

+  public void log(String aResourceBundleName, String aMessageKey, Object[] aArguments) {

+    if (isLoggable(Level.INFO) && !isEmpty(aMessageKey) && isNotLimited(Level.INFO)) {

+      log(fqcnCmn, Level.INFO, rb(aResourceBundleName, aMessageKey, aArguments), null);

+    }

+  }

+

+  /**

+   * Logs an exception with level INFO

+   * 

+   * @deprecated use new function with log level

+   * 

+   * @param aException

+   *          the exception to be logged

+   */

+  @Override

+  @Deprecated

+  public void logException(Exception aException) {

+    if (isLoggable(Level.INFO) && isNotLimited(Level.INFO) && aException != null) {

+      log(fqcnCmn, Level.INFO, EXCEPTION_MESSAGE, aException);

+    }

+  }

+

+  /*

+   * (non-Javadoc)

+   * 

+   * @see org.apache.uima.util.Logger#log(org.apache.uima.util.Level, java.lang.String)

+   */

+  @Override

+  public void log(Level level, String aMessage) {

+    if (isLoggable(level) && !isEmpty(aMessage) && isNotLimited(level)) {

+      log(fqcnCmn, level, aMessage, null);

+    }

+  }

+  

+  /*

+   * (non-Javadoc)

+   * 

+   * @see org.apache.uima.util.Logger#log(org.apache.uima.util.Level, java.lang.String,

+   *      java.lang.Object)

+   */

+  @Override

+  public void log(Level level, String aMessage, Object param1) {

+    if (isLoggable(level) && !isEmpty(aMessage) && isNotLimited(level)) {

+      log(fqcnCmn, level, MessageFormat.format(aMessage, new Object[] { param1 }), null);

+    }

+  }

+

+  /*

+   * (non-Javadoc)

+   * 

+   * @see org.apache.uima.util.Logger#log(org.apache.uima.util.Level, java.lang.String,

+   *      java.lang.Object[])

+   */

+  @Override

+  public void log(Level level, String aMessage, Object[] params) {

+    if (isLoggable(level) && !isEmpty(aMessage) && isNotLimited(level)) {

+      log(fqcnCmn, level, MessageFormat.format(aMessage, params), null);

+    }

+  }

+

+  /*

+   * (non-Javadoc)

+   * 

+   * @see org.apache.uima.util.Logger#log(org.apache.uima.util.Level, java.lang.String,

+   *      java.lang.Throwable)

+   */

+  @Override

+  public void log(Level level, String aMessage, Throwable thrown) {

+    if (isLoggable(level) && isNotLimited(level)) {

+      log(fqcnCmn, 

+          level,

+          (aMessage != null && !aMessage.equals(""))

+            ? aMessage

+            : EXCEPTION_MESSAGE,

+          thrown);

+    }

+  }

+

+  /*

+   * (non-Javadoc)

+   * 

+   * @see org.apache.uima.util.Logger#logrb(org.apache.uima.util.Level, java.lang.String,

+   *      java.lang.String, java.lang.String, java.lang.String, java.lang.Object)

+   */

+  @Override

+  public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName,

+          String msgKey, Object param1) {

+    if (isLoggable(level) && !isEmpty(msgKey) && isNotLimited(level)) {

+      log(fqcnCmn, level, rb(bundleName, msgKey, param1), null);

+    }

+  }

+

+  /*

+   * (non-Javadoc)

+   * 

+   * @see org.apache.uima.util.Logger#logrb(org.apache.uima.util.Level, java.lang.String,

+   *      java.lang.String, java.lang.String, java.lang.String, java.lang.Object[])

+   */

+  @Override

+  public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName,

+          String msgKey, Object[] params) {

+    if (isLoggable(level) && !isEmpty(msgKey) && isNotLimited(level)) {

+      log(fqcnCmn, level, rb(bundleName, msgKey, params), null);

+    }

+  }

+

+  /*

+   * (non-Javadoc)

+   * 

+   * @see org.apache.uima.util.Logger#logrb(org.apache.uima.util.Level, java.lang.String,

+   *      java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable)

+   */

+  @Override

+  public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName,

+          String msgKey, Throwable thrown) {

+    if (isLoggable(level) && isNotLimited(level)) {

+      if (thrown == null && isEmpty(msgKey)) {

+        return;

+      }

+      log(fqcnCmn, 

+          level, 

+          (msgKey != null && !msgKey.equals(""))

+            ? rb(bundleName, msgKey)

+            : EXCEPTION_MESSAGE,

+          thrown);

+    }

+  }

+

+  /*

+   * (non-Javadoc)

+   * 

+   * @see org.apache.uima.util.Logger#logrb(org.apache.uima.util.Level, java.lang.String,

+   *      java.lang.String, java.lang.String, java.lang.String)

+   */

+  @Override

+  public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName,

+          String msgKey) {

+    if (isLoggable(level) && !isEmpty(msgKey) && isNotLimited(level)) {

+      log(fqcnCmn, level, rb(bundleName, msgKey), null);

+    }

+  }

+

+  /*

+   * (non-Javadoc)

+   * 

+   * @see org.apache.uima.util.Logger#setResourceManager(org.apache.uima.resource.ResourceManager)

+   */

+  @Override

+  public void setResourceManager(ResourceManager resourceManager) {

+    mResourceManager = resourceManager;

+  }

+

+  /**

+   * Gets the extension ClassLoader to used to locate the message digests. If this returns null,

+   * then message digests will be searched for using this.class.getClassLoader().

+   */

+  private ClassLoader getExtensionClassLoader() {

+    if (mResourceManager == null)

+      return null;

+    else

+      return mResourceManager.getExtensionClassLoader();

+  }

+ 

+  /*

+   * (non-Javadoc)

+   * 

+   * @see org.apache.uima.util.Logger#rb(String, String, Object...)

+   */

+  @Override

+  public String rb(String bundleName, String msgKey, Object... parameters) {

+    return I18nUtil.localizeMessage(bundleName, msgKey, parameters, getExtensionClassLoader());

+  }

+

+  protected boolean isEmpty(String v) {

+    return (v == null || v.equals(""));

+  }

+

+  @Override

+  public boolean isAnnotatorLogger() {

+    return isAnnotatorLogger;

+  }

+  

+  public void setAnnotatorLogger(boolean v) {

+    isAnnotatorLogger = v;

+  }

+  

+  private Object[] suppliersToArray(Supplier<?>[] suppliers) {

+    Object[] r = new Object[suppliers.length];

+    int i = 0;

+    for (Supplier<?> s : suppliers) {

+      r[i++] = s.get();

+    }

+    return r;

+  }

+  

+  /************************************************

+   * Convert standard call varieties

+   ************************************************/

+  

+  @Override

+  public void debug(String arg0) {

+    if (isLoggable(Level.DEBUG) && isNotLimited(Level.DEBUG)) {

+      log2(null, fqcnCmn, Level.DEBUG, arg0, null, null);

+    }

+  }

+

+  @Override

+  public void debug(String arg0, Object arg1) {

+    if (isLoggable(Level.DEBUG) && isNotLimited(Level.DEBUG)) { 

+      log2(null, fqcnCmn, Level.DEBUG, arg0, new Object[] {arg1}, null);

+    }

+  }

+

+  @Override

+  public void debug(String arg0, Object... arg1) {

+    if (isLoggable(Level.DEBUG) && isNotLimited(Level.DEBUG)) { 

+      log2(null, fqcnCmn, Level.DEBUG, arg0, arg1, null);

+    }

+  }

+

+  @Override

+  public void debug(String arg0, Throwable arg1) {

+    if (isLoggable(Level.DEBUG) && isNotLimited(Level.DEBUG)) { 

+      log2(null, fqcnCmn, Level.DEBUG, arg0, null, arg1);

+    }

+  }

+

+  @Override

+  public void debug(Marker arg0, String arg1) {

+    if (isLoggable(Level.DEBUG, arg0) && isNotLimited(Level.DEBUG)) {

+      log2(arg0, fqcnCmn, Level.DEBUG, arg1, null, null);

+    }

+  }

+

+  @Override

+  public void debug(String arg0, Object arg1, Object arg2) {

+    if (isLoggable(Level.DEBUG) && isNotLimited(Level.DEBUG)) {

+      log2(null, fqcnCmn, Level.DEBUG, arg0, new Object[] {arg1}, null);

+    }

+  }

+

+  @Override

+  public void debug(Marker arg0, String arg1, Object arg2) {

+    if (isLoggable(Level.DEBUG, arg0) && isNotLimited(Level.DEBUG)) {

+      log2(arg0, fqcnCmn, Level.DEBUG, arg1, new Object[] {arg2}, null);

+    }

+  }

+

+  @Override

+  public void debug(Marker arg0, String arg1, Object... arg2) {

+    if (isLoggable(Level.DEBUG, arg0) && isNotLimited(Level.DEBUG)) {

+      log2(arg0, fqcnCmn, Level.DEBUG, arg1, arg2, null);

+    }

+  }

+

+  @Override

+  public void debug(Marker arg0, String arg1, Throwable arg2) {

+    if (isLoggable(Level.DEBUG, arg0) && isNotLimited(Level.DEBUG)) {

+      log2(arg0, fqcnCmn, Level.DEBUG, arg1, null, arg2);

+    }

+  }

+

+  @Override

+  public void debug(Marker arg0, String arg1, Object arg2, Object arg3) {

+    if (isLoggable(Level.DEBUG, arg0) && isNotLimited(Level.DEBUG)) {

+      log2(arg0, fqcnCmn, Level.DEBUG, arg1, new Object[] {arg2, arg3}, null);

+    }

+  }

+

+  // methods from log4j 2 using Java 8 suppliers

+

+  /**

+   * @param msgSupplier A function, which when called, produces the desired log message

+   */

+  @Override

+  public void debug(Supplier<String> msgSupplier) {

+    if (isLoggable(Level.DEBUG) && isNotLimited(Level.DEBUG)) {

+      log2(null, fqcnCmn, Level.DEBUG, msgSupplier.get(), null, null);

+    }   

+  }

+ 

+  /**

+   * @param msgSupplier A function, which when called, produces the desired log message

+   * @param throwable the exception to log

+   */

+  @Override

+  public void debug(Supplier<String> msgSupplier, Throwable throwable) {

+    if (isLoggable(Level.DEBUG) && isNotLimited(Level.DEBUG)) {

+      log2(null, fqcnCmn, Level.DEBUG, msgSupplier.get(), null, throwable);

+    }   

+  }

+

+  /**

+   * @param marker the marker data specific to this log statement

+   * @param message the message to log

+   * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.

+   */

+  @Override

+  public void debug(Marker marker, String message, Supplier<?>... paramSuppliers) {

+    if (isLoggable(Level.DEBUG, marker) && isNotLimited(Level.DEBUG)) {

+      log2(marker, fqcnCmn, Level.DEBUG, message, suppliersToArray(paramSuppliers), null);

+    }  

+  }

+  

+  /**

+   * @param message the message to log

+   * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.

+   */

+  @Override

+  public void debug(String message, Supplier<?>... paramSuppliers) {

+    if (isLoggable(Level.DEBUG) && isNotLimited(Level.DEBUG)) {

+      log2(null, fqcnCmn, Level.DEBUG, message, suppliersToArray(paramSuppliers), null);

+    }  

+  }

+

+  

+ /**

+  * @param marker the marker data specific to this log statement

+  * @param msgSupplier A function, which when called, produces the desired log message

+  */

+ @Override

+public void debug(Marker marker, Supplier<String> msgSupplier) {

+   if (isLoggable(Level.DEBUG, marker) && isNotLimited(Level.DEBUG)) {

+     log2(marker, fqcnCmn, Level.DEBUG, msgSupplier.get(), null, null);

+   }   

+ }

+ 

+ /**

+  * @param marker the marker data specific to this log statement

+  * @param msgSupplier A function, which when called, produces the desired log message

+  */

+ @Override

+public void debug(Marker marker, Supplier<String> msgSupplier, Throwable throwable) {

+   if (isLoggable(Level.DEBUG, marker) && isNotLimited(Level.DEBUG)) {

+     log2(marker, fqcnCmn, Level.DEBUG, msgSupplier.get(), null, throwable);

+   }   

+ }

+      

+  // ---------------------- ERROR    

+           

+  @Override

+  public void error(String arg0) {

+    if (isLoggable(Level.ERROR) && isNotLimited(Level.ERROR)) {

+      log2(null, fqcnCmn, Level.ERROR, arg0, null, null);

+    }

+  }

+

+  @Override

+  public void error(String arg0, Object arg1) {

+    if (isLoggable(Level.ERROR) && isNotLimited(Level.ERROR)) { 

+      log2(null, fqcnCmn, Level.ERROR, arg0, new Object[] {arg1}, null);

+    }

+  }

+

+  @Override

+  public void error(String arg0, Object... arg1) {

+    if (isLoggable(Level.ERROR) && isNotLimited(Level.ERROR)) { 

+      log2(null, fqcnCmn, Level.ERROR, arg0, arg1, null);

+    }

+  }

+

+  @Override

+  public void error(String arg0, Throwable arg1) {

+    if (isLoggable(Level.ERROR) && isNotLimited(Level.ERROR)) { 

+      log2(null, fqcnCmn, Level.ERROR, arg0, null, arg1);

+    }

+  }

+

+  @Override

+  public void error(Marker arg0, String arg1) {

+    if (isLoggable(Level.ERROR, arg0) && isNotLimited(Level.ERROR)) {

+      log2(arg0, fqcnCmn, Level.ERROR, arg1, null, null);

+    }

+  }

+

+  @Override

+  public void error(String arg0, Object arg1, Object arg2) {

+    if (isLoggable(Level.ERROR) && isNotLimited(Level.ERROR)) {

+      log2(null, fqcnCmn, Level.ERROR, arg0, new Object[] {arg1}, null);

+    }

+  }

+

+  @Override

+  public void error(Marker arg0, String arg1, Object arg2) {

+    if (isLoggable(Level.ERROR, arg0) && isNotLimited(Level.ERROR)) {

+      log2(arg0, fqcnCmn, Level.ERROR, arg1, new Object[] {arg2}, null);

+    }

+  }

+

+  @Override

+  public void error(Marker arg0, String arg1, Object... arg2) {

+    if (isLoggable(Level.ERROR, arg0) && isNotLimited(Level.ERROR)) {

+      log2(arg0, fqcnCmn, Level.ERROR, arg1, arg2, null);

+    }

+  }

+

+  @Override

+  public void error(Marker arg0, String arg1, Throwable arg2) {

+    if (isLoggable(Level.ERROR, arg0) && isNotLimited(Level.ERROR)) {

+      log2(arg0, fqcnCmn, Level.ERROR, arg1, null, arg2);

+    }

+  }

+

+  @Override

+  public void error(Marker arg0, String arg1, Object arg2, Object arg3) {

+    if (isLoggable(Level.ERROR, arg0) && isNotLimited(Level.ERROR)) {

+      log2(arg0, fqcnCmn, Level.ERROR, arg1, new Object[] {arg2, arg3}, null);

+    }

+  }

+

+  // methods from log4j 2 using Java 8 suppliers

+

+  /**

+   * @param msgSupplier A function, which when called, produces the desired log message

+   */

+  @Override

+  public void error(Supplier<String> msgSupplier) {

+    if (isLoggable(Level.ERROR) && isNotLimited(Level.ERROR)) {

+      log2(null, fqcnCmn, Level.ERROR, msgSupplier.get(), null, null);

+    }   

+  }

+ 

+  /**

+   * @param msgSupplier A function, which when called, produces the desired log message

+   * @param throwable the exception to log

+   */

+  @Override

+  public void error(Supplier<String> msgSupplier, Throwable throwable) {

+    if (isLoggable(Level.ERROR) && isNotLimited(Level.ERROR)) {

+      log2(null, fqcnCmn, Level.ERROR, msgSupplier.get(), null, throwable);

+    }   

+  }

+

+  /**

+   * @param marker the marker data specific to this log statement

+   * @param message the message to log

+   * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.

+   */

+  @Override

+  public void error(Marker marker, String message, Supplier<?>... paramSuppliers) {

+    if (isLoggable(Level.ERROR, marker) && isNotLimited(Level.ERROR)) {

+      log2(marker, fqcnCmn, Level.ERROR, message, suppliersToArray(paramSuppliers), null);

+    }  

+  }

+  

+  /**

+   * @param message the message to log

+   * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.

+   */

+  @Override

+  public void error(String message, Supplier<?>... paramSuppliers) {

+    if (isLoggable(Level.ERROR) && isNotLimited(Level.ERROR)) {

+      log2(null, fqcnCmn, Level.ERROR, message, suppliersToArray(paramSuppliers), null);

+    }  

+  }

+

+  

+ /**

+  * @param marker the marker data specific to this log statement

+  * @param msgSupplier A function, which when called, produces the desired log message

+  */

+  @Override

+  public void error(Marker marker, Supplier<String> msgSupplier) {

+    if (isLoggable(Level.ERROR, marker) && isNotLimited(Level.ERROR)) {

+      log2(marker, fqcnCmn, Level.ERROR, msgSupplier.get(), null, null);

+    }

+  }

+

+  /**

+   * @param marker

+   *          the marker data specific to this log statement

+   * @param msgSupplier

+   *          A function, which when called, produces the desired log message

+   */

+  @Override

+  public void error(Marker marker, Supplier<String> msgSupplier, Throwable throwable) {

+    if (isLoggable(Level.ERROR, marker) && isNotLimited(Level.ERROR)) {

+      log2(marker, fqcnCmn, Level.ERROR, msgSupplier.get(), null, throwable);

+    }

+  }

+

+  // ---------------------- INFO

+

+  @Override

+  public void info(String arg0) {

+    if (isLoggable(Level.INFO) && isNotLimited(Level.INFO)) {

+      log2(null, fqcnCmn, Level.INFO, arg0, null, null);

+    }

+  }

+

+  @Override

+  public void info(String arg0, Object arg1) {

+    if (isLoggable(Level.INFO) && isNotLimited(Level.INFO)) {

+      log2(null, fqcnCmn, Level.INFO, arg0, new Object[] { arg1 }, null);

+    }

+  }

+

+  @Override

+  public void info(String arg0, Object... arg1) {

+    if (isLoggable(Level.INFO) && isNotLimited(Level.INFO)) {

+      log2(null, fqcnCmn, Level.INFO, arg0, arg1, null);

+    }

+  }

+

+  @Override

+  public void info(String arg0, Throwable arg1) {

+    if (isLoggable(Level.INFO) && isNotLimited(Level.INFO)) {

+      log2(null, fqcnCmn, Level.INFO, arg0, null, arg1);

+    }

+  }

+

+  @Override

+  public void info(Marker arg0, String arg1) {

+    if (isLoggable(Level.INFO, arg0) && isNotLimited(Level.INFO)) {

+      log2(arg0, fqcnCmn, Level.INFO, arg1, null, null);

+    }

+  }

+

+  @Override

+  public void info(String arg0, Object arg1, Object arg2) {

+    if (isLoggable(Level.INFO) && isNotLimited(Level.INFO)) {

+      log2(null, fqcnCmn, Level.INFO, arg0, new Object[] { arg1 }, null);

+    }

+  }

+

+  @Override

+  public void info(Marker arg0, String arg1, Object arg2) {

+    if (isLoggable(Level.INFO, arg0) && isNotLimited(Level.INFO)) {

+      log2(arg0, fqcnCmn, Level.INFO, arg1, new Object[] { arg2 }, null);

+    }

+  }

+

+  @Override

+  public void info(Marker arg0, String arg1, Object... arg2) {

+    if (isLoggable(Level.INFO, arg0) && isNotLimited(Level.INFO)) {

+      log2(arg0, fqcnCmn, Level.INFO, arg1, arg2, null);

+    }

+  }

+

+  @Override

+  public void info(Marker arg0, String arg1, Throwable arg2) {

+    if (isLoggable(Level.INFO, arg0) && isNotLimited(Level.INFO)) {

+      log2(arg0, fqcnCmn, Level.INFO, arg1, null, arg2);

+    }

+  }

+

+  @Override

+  public void info(Marker arg0, String arg1, Object arg2, Object arg3) {

+    if (isLoggable(Level.INFO, arg0) && isNotLimited(Level.INFO)) {

+      log2(arg0, fqcnCmn, Level.INFO, arg1, new Object[] { arg2, arg3 }, null);

+    }

+  }

+

+  // methods from log4j 2 using Java 8 suppliers

+

+  /**

+   * @param msgSupplier

+   *          A function, which when called, produces the desired log message

+   */

+  @Override

+  public void info(Supplier<String> msgSupplier) {

+    if (isLoggable(Level.INFO) && isNotLimited(Level.INFO)) {

+      log2(null, fqcnCmn, Level.INFO, msgSupplier.get(), null, null);

+    }

+  }

+

+  /**

+   * @param msgSupplier

+   *          A function, which when called, produces the desired log message

+   * @param throwable

+   *          the exception to log

+   */

+  @Override

+  public void info(Supplier<String> msgSupplier, Throwable throwable) {

+    if (isLoggable(Level.INFO) && isNotLimited(Level.INFO)) {

+      log2(null, fqcnCmn, Level.INFO, msgSupplier.get(), null, throwable);

+    }

+  }

+

+  /**

+   * @param marker

+   *          the marker data specific to this log statement

+   * @param message

+   *          the message to log

+   * @param paramSuppliers

+   *          An array of functions, which when called, produce the desired log

+   *          message parameters.

+   */

+  @Override

+  public void info(Marker marker, String message, Supplier<?>... paramSuppliers) {

+    if (isLoggable(Level.INFO, marker) && isNotLimited(Level.INFO)) {

+      log2(marker, fqcnCmn, Level.INFO, message, suppliersToArray(paramSuppliers), null);

+    }

+  }

+

+  /**

+   * @param message the message to log

+   * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.

+   */

+  public void info(String message, Supplier<?>... paramSuppliers) {

+    if (isLoggable(Level.INFO) && isNotLimited(Level.INFO)) {

+      log2(null, fqcnCmn, Level.INFO, message, suppliersToArray(paramSuppliers), null);

+    }  

+  }

+

+  /**

+   * @param marker

+   *          the marker data specific to this log statement

+   * @param msgSupplier

+   *          A function, which when called, produces the desired log message

+   */

+  @Override

+  public void info(Marker marker, Supplier<String> msgSupplier) {

+    if (isLoggable(Level.INFO, marker) && isNotLimited(Level.INFO)) {

+      log2(marker, fqcnCmn, Level.INFO, msgSupplier.get(), null, null);

+    }

+  }

+

+  /**

+   * @param marker

+   *          the marker data specific to this log statement

+   * @param msgSupplier

+   *          A function, which when called, produces the desired log message

+   */

+  @Override

+  public void info(Marker marker, Supplier<String> msgSupplier, Throwable throwable) {

+    if (isLoggable(Level.INFO, marker) && isNotLimited(Level.INFO)) {

+      log2(marker, fqcnCmn, Level.INFO, msgSupplier.get(), null, throwable);

+    }

+  }

+

+  // ---------------------- TRACE

+

+  @Override

+  public void trace(String arg0) {

+    if (isLoggable(Level.TRACE) && isNotLimited(Level.TRACE)) {

+      log2(null, fqcnCmn, Level.TRACE, arg0, null, null);

+    }

+  }

+

+  @Override

+  public void trace(String arg0, Object arg1) {

+    if (isLoggable(Level.TRACE) && isNotLimited(Level.TRACE)) {

+      log2(null, fqcnCmn, Level.TRACE, arg0, new Object[] { arg1 }, null);

+    }

+  }

+

+  @Override

+  public void trace(String arg0, Object... arg1) {

+    if (isLoggable(Level.TRACE) && isNotLimited(Level.TRACE)) {

+      log2(null, fqcnCmn, Level.TRACE, arg0, arg1, null);

+    }

+  }

+

+  @Override

+  public void trace(String arg0, Throwable arg1) {

+    if (isLoggable(Level.TRACE) && isNotLimited(Level.TRACE)) {

+      log2(null, fqcnCmn, Level.TRACE, arg0, null, arg1);

+    }

+  }

+

+  @Override

+  public void trace(Marker arg0, String arg1) {

+    if (isLoggable(Level.TRACE, arg0) && isNotLimited(Level.TRACE)) {

+      log2(arg0, fqcnCmn, Level.TRACE, arg1, null, null);

+    }

+  }

+

+  @Override

+  public void trace(String arg0, Object arg1, Object arg2) {

+    if (isLoggable(Level.TRACE) && isNotLimited(Level.TRACE)) {

+      log2(null, fqcnCmn, Level.TRACE, arg0, new Object[] { arg1 }, null);

+    }

+  }

+

+  @Override

+  public void trace(Marker arg0, String arg1, Object arg2) {

+    if (isLoggable(Level.TRACE, arg0) && isNotLimited(Level.TRACE)) {

+      log2(arg0, fqcnCmn, Level.TRACE, arg1, new Object[] { arg2 }, null);

+    }

+  }

+

+  @Override

+  public void trace(Marker arg0, String arg1, Object... arg2) {

+    if (isLoggable(Level.TRACE, arg0) && isNotLimited(Level.TRACE)) {

+      log2(arg0, fqcnCmn, Level.TRACE, arg1, arg2, null);

+    }

+  }

+

+  @Override

+  public void trace(Marker arg0, String arg1, Throwable arg2) {

+    if (isLoggable(Level.TRACE, arg0) && isNotLimited(Level.TRACE)) {

+      log2(arg0, fqcnCmn, Level.TRACE, arg1, null, arg2);

+    }

+  }

+

+  @Override

+  public void trace(Marker arg0, String arg1, Object arg2, Object arg3) {

+    if (isLoggable(Level.TRACE, arg0) && isNotLimited(Level.TRACE)) {

+      log2(arg0, fqcnCmn, Level.TRACE, arg1, new Object[] { arg2, arg3 }, null);

+    }

+  }

+

+  // methods from log4j 2 using Java 8 suppliers

+

+  /**

+   * @param msgSupplier

+   *          A function, which when called, produces the desired log message

+   */

+  @Override

+  public void trace(Supplier<String> msgSupplier) {

+    if (isLoggable(Level.TRACE) && isNotLimited(Level.TRACE)) {

+      log2(null, fqcnCmn, Level.TRACE, msgSupplier.get(), null, null);

+    }

+  }

+

+  /**

+   * @param msgSupplier

+   *          A function, which when called, produces the desired log message

+   * @param throwable

+   *          the exception to log

+   */

+  @Override

+  public void trace(Supplier<String> msgSupplier, Throwable throwable) {

+    if (isLoggable(Level.TRACE) && isNotLimited(Level.TRACE)) {

+      log2(null, fqcnCmn, Level.TRACE, msgSupplier.get(), null, throwable);

+    }

+  }

+

+  /**

+   * @param marker

+   *          the marker data specific to this log statement

+   * @param message

+   *          the message to log

+   * @param paramSuppliers

+   *          An array of functions, which when called, produce the desired log

+   *          message parameters.

+   */

+  @Override

+  public void trace(Marker marker, String message, Supplier<?>... paramSuppliers) {

+    if (isLoggable(Level.TRACE, marker) && isNotLimited(Level.TRACE)) {

+      log2(marker, fqcnCmn, Level.TRACE, message, suppliersToArray(paramSuppliers), null);

+    }

+  }

+

+  /**

+   * @param message the message to log

+   * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.

+   */

+  @Override

+  public void trace(String message, Supplier<?>... paramSuppliers) {

+    if (isLoggable(Level.TRACE) && isNotLimited(Level.TRACE)) {

+      log2(null, fqcnCmn, Level.TRACE, message, suppliersToArray(paramSuppliers), null);

+    }  

+  }

+

+  /**

+   * @param marker

+   *          the marker data specific to this log statement

+   * @param msgSupplier

+   *          A function, which when called, produces the desired log message

+   */

+  @Override

+  public void trace(Marker marker, Supplier<String> msgSupplier) {

+    if (isLoggable(Level.TRACE, marker) && isNotLimited(Level.TRACE)) {

+      log2(marker, fqcnCmn, Level.TRACE, msgSupplier.get(), null, null);

+    }

+  }

+

+  /**

+   * @param marker

+   *          the marker data specific to this log statement

+   * @param msgSupplier

+   *          A function, which when called, produces the desired log message

+   */

+  @Override

+  public void trace(Marker marker, Supplier<String> msgSupplier, Throwable throwable) {

+    if (isLoggable(Level.TRACE, marker) && isNotLimited(Level.TRACE)) {

+      log2(marker, fqcnCmn, Level.TRACE, msgSupplier.get(), null, throwable);

+    }

+  }

+

+  // ---------------------- WARN

+  @Override

+  public void warn(String arg0) {

+    if (isLoggable(Level.WARNING) && isNotLimited(Level.WARNING)) {

+      log2(null, fqcnCmn, Level.WARNING, arg0, null, null);

+    }

+  }

+

+  @Override

+  public void warn(String arg0, Object arg1) {

+    if (isLoggable(Level.WARNING) && isNotLimited(Level.WARNING)) {

+      log2(null, fqcnCmn, Level.WARNING, arg0, new Object[] { arg1 }, null);

+    }

+  }

+

+  @Override

+  public void warn(String arg0, Object... arg1) {

+    if (isLoggable(Level.WARNING) && isNotLimited(Level.WARNING)) {

+      log2(null, fqcnCmn, Level.WARNING, arg0, arg1, null);

+    }

+  }

+

+  @Override

+  public void warn(String arg0, Throwable arg1) {

+    if (isLoggable(Level.WARNING) && isNotLimited(Level.WARNING)) {

+      log2(null, fqcnCmn, Level.WARNING, arg0, null, arg1);

+    }

+  }

+

+  @Override

+  public void warn(Marker arg0, String arg1) {

+    if (isLoggable(Level.WARNING, arg0) && isNotLimited(Level.WARNING)) {

+      log2(arg0, fqcnCmn, Level.WARNING, arg1, null, null);

+    }

+  }

+

+  @Override

+  public void warn(String arg0, Object arg1, Object arg2) {

+    if (isLoggable(Level.WARNING) && isNotLimited(Level.WARNING)) {

+      log2(null, fqcnCmn, Level.WARNING, arg0, new Object[] { arg1 }, null);

+    }

+  }

+

+  @Override

+  public void warn(Marker arg0, String arg1, Object arg2) {

+    if (isLoggable(Level.WARNING, arg0) && isNotLimited(Level.WARNING)) {

+      log2(arg0, fqcnCmn, Level.WARNING, arg1, new Object[] { arg2 }, null);

+    }

+  }

+

+  @Override

+  public void warn(Marker arg0, String arg1, Object... arg2) {

+    if (isLoggable(Level.WARNING, arg0) && isNotLimited(Level.WARNING)) {

+      log2(arg0, fqcnCmn, Level.WARNING, arg1, arg2, null);

+    }

+  }

+

+  @Override

+  public void warn(Marker arg0, String arg1, Throwable arg2) {

+    if (isLoggable(Level.WARNING, arg0) && isNotLimited(Level.WARNING)) {

+      log2(arg0, fqcnCmn, Level.WARNING, arg1, null, arg2);

+    }

+  }

+

+  @Override

+  public void warn(Marker arg0, String arg1, Object arg2, Object arg3) {

+    if (isLoggable(Level.WARNING, arg0) && isNotLimited(Level.WARNING)) {

+      log2(arg0, fqcnCmn, Level.WARNING, arg1, new Object[] { arg2, arg3 }, null);

+    }

+  }

+

+  // methods from log4j 2 using Java 8 suppliers

+

+  /**

+   * @param msgSupplier

+   *          A function, which when called, produces the desired log message

+   */

+  @Override

+  public void warn(Supplier<String> msgSupplier) {

+    if (isLoggable(Level.WARNING) && isNotLimited(Level.WARNING)) {

+      log2(null, fqcnCmn, Level.WARNING, msgSupplier.get(), null, null);

+    }

+  }

+

+  /**

+   * @param msgSupplier

+   *          A function, which when called, produces the desired log message

+   * @param throwable

+   *          the exception to log

+   */

+  @Override

+  public void warn(Supplier<String> msgSupplier, Throwable throwable) {

+    if (isLoggable(Level.WARNING) && isNotLimited(Level.WARNING)) {

+      log2(null, fqcnCmn, Level.WARNING, msgSupplier.get(), null, throwable);

+    }

+  }

+

+  /**

+   * @param marker

+   *          the marker data specific to this log statement

+   * @param message

+   *          the message to log

+   * @param paramSuppliers

+   *          An array of functions, which when called, produce the desired log

+   *          message parameters.

+   */

+  @Override

+  public void warn(Marker marker, String message, Supplier<?>... paramSuppliers) {

+    if (isLoggable(Level.WARNING, marker) && isNotLimited(Level.WARNING)) {

+      log2(marker, fqcnCmn, Level.WARNING, message, suppliersToArray(paramSuppliers), null);

+    }

+  }

+

+  /**

+   * @param message the message to log

+   * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.

+   */

+  @Override

+  public void warn(String message, Supplier<?>... paramSuppliers) {

+    if (isLoggable(Level.WARN) && isNotLimited(Level.WARN)) {

+      log2(null, fqcnCmn, Level.WARN, message, suppliersToArray(paramSuppliers), null);

+    }  

+  }

+

+  /**

+   * @param marker

+   *          the marker data specific to this log statement

+   * @param msgSupplier

+   *          A function, which when called, produces the desired log message

+   */

+  @Override

+  public void warn(Marker marker, Supplier<String> msgSupplier) {

+    if (isLoggable(Level.WARNING, marker) && isNotLimited(Level.WARNING)) {

+      log2(marker, fqcnCmn, Level.WARNING, msgSupplier.get(), null, null);

+    }

+  }

+

+  /**

+   * @param marker

+   *          the marker data specific to this log statement

+   * @param msgSupplier

+   *          A function, which when called, produces the desired log message

+   */

+  @Override

+  public void warn(Marker marker, Supplier<String> msgSupplier, Throwable throwable) {

+    if (isLoggable(Level.WARNING, marker) && isNotLimited(Level.WARNING)) {

+      log2(marker, fqcnCmn, Level.WARNING, msgSupplier.get(), null, throwable);

+    }

+  }

+ 

+}

diff --git a/uimaj-core/src/main/java/org/apache/uima/util/impl/Logger_impl.java b/uimaj-core/src/main/java/org/apache/uima/util/impl/Logger_impl.java
index 06c7bd7..064c745 100644
--- a/uimaj-core/src/main/java/org/apache/uima/util/impl/Logger_impl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/util/impl/Logger_impl.java
@@ -24,21 +24,30 @@
 import java.text.MessageFormat;
 import java.util.Date;
 
-import org.apache.uima.internal.util.I18nUtil;
-import org.apache.uima.resource.ResourceManager;
 import org.apache.uima.util.Level;
 import org.apache.uima.util.Logger;
+import org.slf4j.Marker;
+import org.slf4j.helpers.MessageFormatter;
 
 /**
  * UIMA Logging interface implementation without using an logging toolkit
+ * Logger names are not used 
  * 
+ * The call getInstance() returns a common shared instance.
+ * The call getInstance(String) ignores its argument but returns a
+ *   new instance of this logger class
+ *   
+ * Each instance of this logger class can have a level set via 
+ * the setAPI call - that is the only configuration possible.
+ * If not set, the level is INFO.
+ *
  */
-public class Logger_impl implements Logger {
+public class Logger_impl extends Logger_common_impl {
   /**
    * default PrintStream to which the log messages are printed. Defaults to <code>System.out</code>.
    */
   private static final PrintStream defaultOut = System.out;
-
+  
   /**
    * PrintStream which the object is used to log the messages, is by default set to defaultOut
    */
@@ -49,23 +58,29 @@
    */
   private Level configLevel = Level.INFO;
 
+  private String loggerName;
+
   /**
    * default logger instance
    */
-  private static final Logger_impl defaultLogger = new Logger_impl();
-
-  /**
-   * ResourceManager whose extension ClassLoader will be used to locate the message digests. Null
-   * will cause the ClassLoader to default to this.class.getClassLoader().
-   */
-  private ResourceManager mResourceManager = null;
+  private static final Logger_impl defaultLogger = new Logger_impl(null);
 
   /**
    * creates a new Logger object and set <code>System.out</code> as default output
    */
-  private Logger_impl() {
+  private Logger_impl(Class<?> component) {
+    super(component);
     // set default Output
     mOut = defaultOut;
+    loggerName = (null == component)
+                   ? ""
+                   : component.getName();
+  }
+
+  private Logger_impl(Logger_impl l, int limit) {
+    super(l, limit);
+    this.mOut = l.mOut;
+    this.loggerName = l.loggerName;
   }
 
   /**
@@ -77,7 +92,7 @@
    * @return Logger - returns the Logger object for the specified class
    */
   public static synchronized Logger getInstance(Class<?> component) {
-    return new Logger_impl();
+    return new Logger_impl(component);
   }
 
   /**
@@ -89,55 +104,13 @@
     return defaultLogger;
   }
 
-  /**
-   * Logs a message with message level INFO
-   * 
-   * @deprecated use method with log level as parameter
-   * 
-   * @param aMessage
-   *          the message to be logged
-   */
-  @Deprecated
-  public void log(String aMessage) {
-    if (isLoggable(Level.INFO) && mOut != null) {
-      mOut.print(new Date());
-      mOut.print(": " + Level.INFO.toString() + ": ");
-      mOut.println(aMessage);
+  public Logger_impl getLimitedLogger(int aLimit) {
+    if (aLimit == Integer.MAX_VALUE || aLimit == this.limit_common) {
+      return this;
     }
+    return new Logger_impl(this, aLimit);
   }
-
-  /**
-   * Logs a message with a message key and with the message level INFO
-   * 
-   * @deprecated use method with log level as parameter
-   * 
-   * @see org.apache.uima.util.Logger#log(java.lang.String, java.lang.String, java.lang.Object[])
-   */
-  @Deprecated
-  public void log(String aResourceBundleName, String aMessageKey, Object[] aArguments) {
-    if (isLoggable(Level.INFO)) {
-      log(I18nUtil.localizeMessage(aResourceBundleName, aMessageKey, aArguments,
-              getExtensionClassLoader()));
-    }
-  }
-
-  /**
-   * Logs an exception with message level INFO
-   * 
-   * @deprecated use method with log level as parameter
-   * 
-   * @param aException
-   *          the exception to be logged
-   */
-  @Deprecated
-  public void logException(Exception aException) {
-    if (isLoggable(Level.INFO) && mOut != null) {
-      mOut.print(new Date());
-      mOut.print(": " + Level.INFO.toString() + ": ");
-      aException.printStackTrace(mOut);
-    }
-  }
-
+ 
   /**
    * @deprecated use external configuration possibility
    * 
@@ -162,36 +135,6 @@
     mOut = out;
   }
 
-  /**
-   * Logs an exception.
-   * 
-   * @param level
-   *          message level
-   * @param thrown
-   *          the throwable
-   */
-  private void logException(Level level, Throwable thrown) {
-    mOut.print(new Date());
-    mOut.print(": " + level.toString() + ": ");
-    thrown.printStackTrace(mOut);
-  }
-
-  /**
-   * Logs a message.
-   * 
-   * @param level
-   *          message level
-   * @param aMessage
-   *          the message
-   */
-  private void logMessage(Level level, String aMessage) {
-    if (mOut != null) {
-      mOut.print(new Date());
-      mOut.print(": " + level.toString() + ": ");
-      mOut.println(aMessage);
-    }
-  }
-
   /*
    * (non-Javadoc)
    * 
@@ -200,128 +143,40 @@
   public boolean isLoggable(Level level) {
     return configLevel.isGreaterOrEqual(level);
   }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#log(org.apache.uima.util.Level, java.lang.String)
-   */
-  public void log(Level level, String aMessage) {
-    if (isLoggable(level)) {
-      logMessage(level, aMessage);
-    }
+  
+  public boolean isLoggable(Level level, Marker marker) {
+    return configLevel.isGreaterOrEqual(level);
   }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#log(org.apache.uima.util.Level, java.lang.String,
-   *      java.lang.Object)
-   */
-  public void log(Level level, String aMessage, Object param1) {
-    if (isLoggable(level)) {
-      String result = MessageFormat.format(aMessage, new Object[] { param1 });
-
-      logMessage(level, result);
-    }
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#log(org.apache.uima.util.Level, java.lang.String,
-   *      java.lang.Object[])
-   */
-  public void log(Level level, String aMessage, Object[] params) {
-    if (isLoggable(level)) {
-      String result = MessageFormat.format(aMessage, params);
-
-      logMessage(level, result);
-    }
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#log(org.apache.uima.util.Level, java.lang.String,
-   *      java.lang.Throwable)
-   */
-  public void log(Level level, String aMessage, Throwable thrown) {
-    if (isLoggable(level)) {
-      logMessage(level, aMessage);
-
-      logException(level, thrown);
-    }
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#logrb(org.apache.uima.util.Level, java.lang.String,
-   *      java.lang.String, java.lang.String, java.lang.String, java.lang.Object)
-   */
-  public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName,
-          String msgKey, Object param1) {
-    if (isLoggable(level)) {
-      logMessage(level, I18nUtil.localizeMessage(bundleName, msgKey, new Object[] { param1 },
-              getExtensionClassLoader()));
-    }
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#logrb(org.apache.uima.util.Level, java.lang.String,
-   *      java.lang.String, java.lang.String, java.lang.String, java.lang.Object[])
-   */
-  public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName,
-          String msgKey, Object[] params) {
-    if (isLoggable(level)) {
-      logMessage(level, I18nUtil.localizeMessage(bundleName, msgKey, params,
-              getExtensionClassLoader()));
-    }
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#logrb(org.apache.uima.util.Level, java.lang.String,
-   *      java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable)
-   */
-  public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName,
-          String msgKey, Throwable thrown) {
-    if (isLoggable(level)) {
-      logMessage(level, I18nUtil.localizeMessage(bundleName, msgKey, null,
-              getExtensionClassLoader()));
-
-      logException(level, thrown);
-    }
-  }
-
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#logrb(org.apache.uima.util.Level, java.lang.String,
-   *      java.lang.String, java.lang.String, java.lang.String)
-   */
-  public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName,
-          String msgKey) {
-    if (isLoggable(level)) {
-      logMessage(level, I18nUtil.localizeMessage(bundleName, msgKey, null,
-              getExtensionClassLoader()));
-    }
+    
+  public void log(Marker m, String aFqcn, Level level, String message, Object[] args, Throwable thrown) {
+    log(m, aFqcn, level, MessageFormat.format(message, args), thrown);
   }
   
-  public void log(String wrapperFQCN, Level level, String message, Throwable thrown) {
-    if (isLoggable(level)) {
-      logMessage(level, message);
-
-      if (thrown != null) {
-        logException(level, thrown);
+  @Override
+  public void log(Marker m, String aFqcn, Level level, String message, Throwable thrown) {
+    if (mOut != null) {
+      mOut.print(new Date());
+      mOut.print(": " + level.toString() + ": ");
+      mOut.println(message);
+      if (null != thrown) {
+        thrown.printStackTrace(mOut);
       }
     }
   }
 
+  public void log2(Marker m, String aFqcn, Level level, String message, Object[] args, Throwable thrown) {
+    if (mOut != null) {
+      mOut.print(new Date());
+      mOut.print(": " + level.toString() + ": ");
+      // this version of MessageFormatter handles {} style
+      mOut.println(MessageFormatter.format(message, args).getMessage());
+      if (null != thrown) {
+        thrown.printStackTrace(mOut);
+      }
+    }
+  }
+
+
   /*
    * (non-Javadoc)
    * 
@@ -332,24 +187,62 @@
     configLevel = level;
   }
 
-  /*
-   * (non-Javadoc)
-   * 
-   * @see org.apache.uima.util.Logger#setResourceManager(org.apache.uima.resource.ResourceManager)
-   */
-  public void setResourceManager(ResourceManager resourceManager) {
-    mResourceManager = resourceManager;
+
+  @Override
+  public String getName() {
+    return loggerName;
+  }
+ 
+  @Override
+  public boolean isDebugEnabled() {
+    return isLoggable(Level.FINE);
   }
 
-  /**
-   * Gets the extension ClassLoader to used to locate the message digests. If this returns null,
-   * then message digests will be searched for using this.class.getClassLoader().
-   */
-  private ClassLoader getExtensionClassLoader() {
-    if (mResourceManager == null)
-      return null;
-    else
-      return mResourceManager.getExtensionClassLoader();
+  @Override
+  public boolean isDebugEnabled(Marker arg0) {
+    return isDebugEnabled();
+  }
+
+  @Override
+  public boolean isErrorEnabled() {
+    return isLoggable(Level.SEVERE);
+  }
+
+  @Override
+  public boolean isErrorEnabled(Marker arg0) {
+    return isErrorEnabled();
+  }
+
+  @Override
+  public boolean isInfoEnabled() {
+    return isLoggable(Level.INFO) ||
+           isLoggable(Level.CONFIG);
+  }
+
+  @Override
+  public boolean isInfoEnabled(Marker arg0) {
+    return isInfoEnabled();
+  }
+
+  @Override
+  public boolean isTraceEnabled() {
+    return isLoggable(Level.FINER) ||
+        isLoggable(Level.FINEST);
+  }
+
+  @Override
+  public boolean isTraceEnabled(Marker arg0) {
+    return isTraceEnabled();
+  }
+
+  @Override
+  public boolean isWarnEnabled() {
+    return isLoggable(Level.WARNING);
+  }
+
+  @Override
+  public boolean isWarnEnabled(Marker arg0) {
+    return isWarnEnabled();
   }
 
 }
diff --git a/uimaj-core/src/main/java/org/apache/uima/util/impl/SaxDeserializer_impl.java b/uimaj-core/src/main/java/org/apache/uima/util/impl/SaxDeserializer_impl.java
index bd68321..0a5513e 100644
--- a/uimaj-core/src/main/java/org/apache/uima/util/impl/SaxDeserializer_impl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/util/impl/SaxDeserializer_impl.java
@@ -27,6 +27,7 @@
 import javax.xml.transform.sax.TransformerHandler;
 
 import org.apache.uima.UIMARuntimeException;
+import org.apache.uima.internal.util.XMLUtils;
 import org.apache.uima.util.InvalidXMLException;
 import org.apache.uima.util.SaxDeserializer;
 import org.apache.uima.util.XMLParser;
@@ -52,8 +53,7 @@
 
   static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
 
-  private static final SAXTransformerFactory transformerFactory = (SAXTransformerFactory) SAXTransformerFactory
-          .newInstance();
+  private static final SAXTransformerFactory transformerFactory = XMLUtils.createSaxTransformerFactory();
 
   private DOMResult mDOMResult;
 
diff --git a/uimaj-core/src/main/java/org/apache/uima/util/impl/Settings_impl.java b/uimaj-core/src/main/java/org/apache/uima/util/impl/Settings_impl.java
index 367e3d6..07a78b8 100644
--- a/uimaj-core/src/main/java/org/apache/uima/util/impl/Settings_impl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/util/impl/Settings_impl.java
@@ -60,6 +60,13 @@
 
   private Map<String, String> map;
   
+  // Thread-local map of properties being resolved +for detecting circular references.
+  private ThreadLocal<HashMap<String, Integer>> tlResolving = new ThreadLocal<HashMap<String, Integer>>() {
+    protected synchronized HashMap<String, Integer> initialValue() {
+      return new HashMap<String, Integer>();
+    }
+  };
+
   /*
    * Regex that matches ${...}
    * non-greedy so stops on first '}' -- hence key cannot contain '}'
@@ -130,10 +137,13 @@
   }
 
   /**
-   * Load properties from the comma-separated list of files specified in the system property 
+   * Load properties from the comma-separated list of resources specified in the system property 
    *   UimaExternalOverrides
-   * Files are loaded in list order.  Duplicate properties are ignored so entries in a file override any in following files.
-   * The filesystem is searched first, and if not found and a relative name the datapath and classpath are searched.
+   * Resource names may be specified with a prefix of "file:" or "path:".
+   * If the prefix is "path:" the name must use the Java-style dotted format, similar to an import by name.
+   * The name is converted to a URL with a suffix of ".settings" and is looked up in the datapath and classpath.
+   * If the prefix is "file:" or is omitted the filesystem is searched.
+   * Resources are loaded in list order.  Duplicate properties are ignored so entries in a file override any in following files.
    * 
    * @throws ResourceConfigurationException wraps IOException
    */
@@ -145,20 +155,25 @@
         UIMAFramework.getLogger(this.getClass()).logrb(Level.CONFIG, this.getClass().getName(), "loadSystemDefaults",
                 LOG_RESOURCE_BUNDLE, "UIMA_external_overrides_load__CONFIG",
                 new Object[] { fname });
-        File f = new File(fname);
         try {
           InputStream is = null; 
-          if (f.exists()) {
-            is = new FileInputStream(fname);
-          } else if (f.isAbsolute()) {
-            throw new FileNotFoundException(fname + " - not in filesystem.");
-          } else {  // Look in datapath & classpath if a relative entry not in the filesystem
-            URL relativeUrl = new URL("file", "", fname);
+          if (fname.startsWith("path:")) {  // Convert to a url and search the datapath & classpath
+            URL relativeUrl = new URL("file", "", fname.substring(5).replace('.', '/')+".settings");
             URL relPath = relativePathResolver.resolveRelativePath(relativeUrl);
             if (relPath != null) {
               is = relPath.openStream();
             } else {
-              throw new FileNotFoundException(fname + " - not found in directory " + System.getProperty("user.dir") + " or in the datapath or classpath.");
+              throw new FileNotFoundException(fname + " - not found in the datapath or classpath.");
+            }
+          } else {            // Files may have an optional "file:" prefix
+            if (fname.startsWith("file:")) {
+              fname = fname.substring(5);
+            }
+            File f = new File(fname);
+            if (f.exists()) {
+              is = new FileInputStream(fname);
+            } else {
+              throw new FileNotFoundException(fname + " - not in filesystem.");
             }
           }
           try {
@@ -176,10 +191,10 @@
   
   /**
    * Look up the value for a property.
-   * Perform one substitution pass on ${key} substrings replacing them with the value for key.
-   * Recursively evaluate the value to be substituted.  NOTE: infinite loops not detected!
-   * If the key variable has not been defined, an exception is thrown.
-   * To avoid evaluation and get ${key} in the output escape the $ or {
+   * Recursively evaluate the value replacing references ${key} with the value of the key.
+   * Nested references such as ${name-${suffix}} are supported. 
+   * Exceptions are thrown for circular references and undefined references.
+   * To avoid evaluation and get ${key} in the output escape the $ or {, e.g. \${key}
    * Arrays are returned as a comma-separated string, e.g. "[elem1,elem2]" 
    * Note: escape characters are not removed as they may affect array separators. 
    * 
@@ -190,36 +205,84 @@
    * @throws ResourceConfigurationException if the value references an undefined property
    */
   public String lookUp(String name) throws ResourceConfigurationException {
-    String value;
-    if ((value = map.get(name)) == null) {
+    return lookUp(name, name);
+  }
+  
+  private String lookUp(String from, String name) throws ResourceConfigurationException {
+    // Maintain a set of variables being expanded so can recognize infinite recursion
+    // Needs to be thread-local as multiple threads may be evaluating properties
+    HashMap<String, Integer> resolving = tlResolving.get();
+    if (resolving.containsKey(name)) {
+      System.err.println("Circular evaluation of property: '" + name + "' - definitions are:");
+      for (String s : resolving.keySet()) {
+        System.err.println(resolving.get(s) + ": " + s + " = " + map.get(s));
+      }
+      // Circular reference to external override variable "{0}" when evaluating "{1}"
+      throw new ResourceConfigurationException(ResourceConfigurationException.EXTERNAL_OVERRIDE_CIRCULAR_REFERENCE,
+              new Object[] { name, from });
+    }
+
+    // Add the name for the duration of the lookup
+    resolving.put(name, new Integer(resolving.size()));
+    try {
+      return resolve(from, map.get(name));
+    } finally {
+      resolving.remove(name);
+    }
+  }
+  
+  /**
+   * Replace variable references in a string.
+   * 
+   * @param value - String to scan for variable references
+   * @return - value with all references resolved and escapes processed
+   * @throws Exception -
+   */
+  public String resolve(String value) throws Exception {
+    return unescape(resolve(value, value));
+  }
+
+  private String resolve(String from, String value) throws ResourceConfigurationException {
+    if (value == null) {
       return null;
     }
     Matcher matcher = evalPattern.matcher(value);
+    if (!matcher.find()) {
+      return value;
+    }
     StringBuilder result = new StringBuilder(value.length() + 100);
-    int lastEnd = 0;
-    while (matcher.find()) {
-      // Check if the $ is escaped
-      if (isEscaped(value, matcher.start())) {
-        result.append(value.substring(lastEnd, matcher.start() + 1));
-        lastEnd = matcher.start() + 1; // copy the escaped $ and restart after it
-      } else {
-        result.append(value.substring(lastEnd, matcher.start()));
-        lastEnd = matcher.end();
-        String key = value.substring(matcher.start() + 2, lastEnd - 1);
-        String val = lookUp(key);
-        if (val == null) { // External override variable "{0}" references the undefined variable "{1}"
+
+    // If this ${ is escaped then simply remove the \ and expand everything after the ${
+    if (isEscaped(value, matcher.start())) {
+      result.append(value.substring(0, matcher.start() - 1));
+      result.append("${");
+      result.append(resolve(from, value.substring(matcher.start() + 2)));
+      return result.toString();
+    }
+
+    // Find start of variable, expand all that follows, and then look for the end
+    // so that nested entries are supported, e.g. ${name${suffix}}
+    result.append(value.substring(0, matcher.start()));
+    String remainder = resolve(from, value.substring(matcher.start() + 2));
+    int end = remainder.indexOf('}');
+    // If ending } missing leave the ${ as-is
+    // If there is no variable treat as if omitted, i.e. '${}' => ''
+    if (end < 0) {
+      result.append("${");
+      result.append(remainder);
+    } else {
+      String key = remainder.substring(0, end);
+      if (end > 0) {
+        String val = lookUp(from, key);
+        if (val == null) { // Undefined reference to external override variable "{0}" when evaluating "{1}"
           throw new ResourceConfigurationException(ResourceConfigurationException.EXTERNAL_OVERRIDE_INVALID,
-                  new Object[] { name, key });
+                  new Object[] { key, from });
         }
         result.append(val);
       }
+      result.append(remainder.substring(end + 1));
     }
-    if (lastEnd == 0) {
-      return value;
-    } else {
-      result.append(value.substring(lastEnd));
-      return result.toString();
-    }
+    return result.toString();
   }
   
   /**
@@ -227,7 +290,7 @@
    */
   @Override
   public String getSetting(String name) throws ResourceConfigurationException {
-    String value = lookUp(name);
+    String value = lookUp(name, name);
     if (value == null) {
       return null;
     }
@@ -238,7 +301,7 @@
       throw new ResourceConfigurationException(ResourceConfigurationException.EXTERNAL_OVERRIDE_TYPE_MISMATCH, 
               new Object[] { name });
     }
-    return value;
+    return unescape(value);  // Process escape characters after checking for array syntax
   }
 
   /**
@@ -246,7 +309,7 @@
    */
   @Override
   public String[] getSettingArray(String name) throws ResourceConfigurationException {
-    String value = lookUp(name);
+    String value = lookUp(name, name);
     if (value == null) {
       return null;
     }
@@ -278,14 +341,14 @@
     int i = 0;
     for (String token : tokens) {
       if (token != null) {
-        result[i++] = escape(token.trim());
+        result[i++] = unescape(token.trim());
       }
     }
     return result;
   }
 
   // Final step is to process any escapes by replacing \x by x
-  private String escape(String token) {
+  private String unescape(String token) {
     int next = token.indexOf('\\');
     if (next < 0) {
       return token;
diff --git a/uimaj-core/src/main/java/org/apache/uima/util/impl/Slf4jLogger_impl.java b/uimaj-core/src/main/java/org/apache/uima/util/impl/Slf4jLogger_impl.java
new file mode 100644
index 0000000..156eab1
--- /dev/null
+++ b/uimaj-core/src/main/java/org/apache/uima/util/impl/Slf4jLogger_impl.java
@@ -0,0 +1,410 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.util.impl;

+

+import java.text.MessageFormat;

+

+import org.apache.uima.internal.util.Misc;

+import org.apache.uima.util.Level;

+import org.apache.uima.util.Logger;

+import org.slf4j.Marker;

+import org.slf4j.spi.LocationAwareLogger;

+

+/**

+ * UIMA Logging interface implementation for SLF4j

+ * 

+ * This design gets a logger in static initialization, 

+ * in order to see what the back end is.  If it is JUL or Log4j,

+ * it sets flags so that subsequent calls to getInstance gets those 

+ * UIMA logger impls, not this one, 

+ * in order to slightly reduce indirection at run time.

+ * 

+ */

+public class Slf4jLogger_impl extends Logger_common_impl {

+  

+  public static final String DEFAULT_JUL = "uima.use_jul_as_default_uima_logger";

+  public static final boolean IS_DEFAULT_JUL = Misc.getNoValueSystemProperty(DEFAULT_JUL);

+  

+  static final boolean isJul;

+  static final boolean isLog4j;

+  

+  static {

+    Class<?> staticLoggerBinderClass = null;

+    try {

+      staticLoggerBinderClass = Class.forName("org.slf4j.impl.StaticLoggerBinder");

+    } catch (Exception e) {

+      // empty on purpose, if class not present, no back end logger, and staticLoggerBinderClass is left as null

+    }

+    

+    if (null == staticLoggerBinderClass) {

+      if (IS_DEFAULT_JUL) {

+        isJul = true;

+        isLog4j = false;

+      } else {

+        isJul = false;

+        isLog4j = false;

+      }

+    } else {

+      // have some backend binding

+      boolean tb;

+      org.slf4j.Logger tempLogger = org.slf4j.LoggerFactory.getLogger("org.apache.uima");

+      try {  // for jdk14 impl

+        Class<?> clazz = Class.forName("org.slf4j.impl.JDK14LoggerAdapter");

+        tb = clazz != null && clazz.isAssignableFrom(tempLogger.getClass());

+      } catch (ClassNotFoundException e1) {

+        tb = false;

+      }

+      isJul = tb;

+      

+      tb = false;

+      if (!isJul) {

+        try {  // for log4j 2 impl

+          Class<?> clazz = Class.forName("org.apache.logging.slf4j.Log4jLogger");

+          tb = null != clazz && clazz.isAssignableFrom(tempLogger.getClass());

+        } catch (ClassNotFoundException e1) {

+          tb = false;

+        }

+      }

+      isLog4j = tb;      

+    }

+  }

+  

+  /**

+   * logger object from the underlying Slf4j logging framework

+   */

+  final private org.slf4j.Logger logger;

+  final private boolean isLocationCapable;  // the slf4j simple logger is not 

+  

+  /**

+   * create a new LogWrapper class for the specified source class

+   * 

+   * @param component

+   *          specified source class

+   */

+  private Slf4jLogger_impl(Class<?> component) {

+    super(component);

+    final String loggerName = (component != null) 

+                                 ? component.getName()

+                                 : "org.apache.uima";

+ 

+    logger = org.slf4j.LoggerFactory.getLogger(loggerName);

+    isLocationCapable = logger instanceof org.slf4j.spi.LocationAwareLogger;

+  }

+  

+  private Slf4jLogger_impl(Slf4jLogger_impl l, int limit) {

+    super(l, limit);

+    this.logger = l.logger;

+    isLocationCapable = logger instanceof org.slf4j.spi.LocationAwareLogger;

+  }

+    

+  /**

+   * creates a new Logger instance for the specified source class

+   * 

+   * @param component

+   *          current source class

+   * 

+   * @return Logger - returns the Logger object for the specified class

+   */

+  public static synchronized Logger getInstance(Class<?> component) {

+    if (isJul) {

+      return JSR47Logger_impl.getInstance(component);

+    }

+    if (isLog4j) {

+      return Log4jLogger_impl.getInstance(component); 

+    }

+    return new Slf4jLogger_impl(component);

+  }

+

+  /**

+   * creates a new Logger instance using default name "org.apache.uima"

+   * 

+   * @return Logger - returns the Logger object for the specified class

+   */

+  public static synchronized Logger getInstance() {

+    return getInstance(null);

+  }

+  

+  public Slf4jLogger_impl getLimitedLogger(int aLimit) {

+    if (aLimit == Integer.MAX_VALUE || aLimit == this.limit_common) {

+      return this;

+    }

+    return new Slf4jLogger_impl(this, aLimit);

+  }

+  

+  public static int getSlf4jLevel(Level level) {

+    switch(level.toInteger()) {

+    case Level.SEVERE_INT: return LocationAwareLogger.ERROR_INT;

+    case Level.WARNING_INT: return LocationAwareLogger.WARN_INT;

+    case Level.INFO_INT: return LocationAwareLogger.INFO_INT;

+    case Level.CONFIG_INT: return LocationAwareLogger.INFO_INT;

+    case Level.FINE_INT: return LocationAwareLogger.DEBUG_INT;

+    case Level.FINER_INT: return LocationAwareLogger.TRACE_INT;

+    case Level.FINEST_INT: return LocationAwareLogger.TRACE_INT;

+    }

+    Misc.internalError();

+    return LocationAwareLogger.ERROR_INT; //ignored, just here for compile error avoidance

+  }  

+  

+  /*

+   * (non-Javadoc)

+   * 

+   * @see org.apache.uima.util.Logger#isLoggable(org.apache.uima.util.Level)

+   */

+  public boolean isLoggable(Level level) {

+    switch (level.toInteger()) {

+    case org.apache.uima.util.Level.OFF_INT:

+      return false;

+    case org.apache.uima.util.Level.SEVERE_INT:

+      return logger.isErrorEnabled();

+    case org.apache.uima.util.Level.WARNING_INT:

+      return logger.isWarnEnabled();

+    case org.apache.uima.util.Level.INFO_INT:

+      return logger.isInfoEnabled();

+    case org.apache.uima.util.Level.CONFIG_INT:

+      return logger.isInfoEnabled(UIMA_MARKER_CONFIG);

+    case org.apache.uima.util.Level.FINE_INT:

+      return logger.isDebugEnabled();

+    case org.apache.uima.util.Level.FINER_INT:

+      return logger.isTraceEnabled();

+    case org.apache.uima.util.Level.FINEST_INT:

+      return logger.isTraceEnabled(UIMA_MARKER_FINEST);

+    default: // for Level.ALL return false, that's what jul logger does

+      return false;

+    }

+  }

+

+  public boolean isLoggable(Level level, Marker marker) {

+    switch (level.toInteger()) {

+    case org.apache.uima.util.Level.OFF_INT:

+      return false;

+    case org.apache.uima.util.Level.SEVERE_INT:

+      return logger.isErrorEnabled(marker);

+    case org.apache.uima.util.Level.WARNING_INT:

+      return logger.isWarnEnabled(marker);

+    case org.apache.uima.util.Level.INFO_INT:

+      return logger.isInfoEnabled(marker);

+    case org.apache.uima.util.Level.CONFIG_INT:

+      return logger.isInfoEnabled(marker);

+    case org.apache.uima.util.Level.FINE_INT:

+      return logger.isDebugEnabled(marker);

+    case org.apache.uima.util.Level.FINER_INT:

+      return logger.isTraceEnabled(marker);

+    case org.apache.uima.util.Level.FINEST_INT:

+      return logger.isTraceEnabled(marker);

+    default: // for Level.ALL return false, that's what jul logger does

+      return false;

+    }

+  }

+

+  /*

+   * (non-Javadoc)

+   * 

+   * @see org.apache.uima.util.Logger#setLevel(org.apache.uima.util.Level)

+   */

+  public void setLevel(Level level) {    

+    // allow nop operation

+  }

+  

+  // does the uima-logger style of message formatting

+  public void log(Marker m, String aFqcn, Level level, String message, Object[] args, Throwable thrown) {

+    log(m, aFqcn, level, MessageFormat.format(message, args), thrown);

+  }

+  

+  @Override

+  public void log(Marker m, String aFqcn, Level level, String msg_with_params, Throwable thrown) {

+    m = (m == null) 

+        ? getMarkerForLevel(level) 

+        : m;

+        

+  if (isLocationCapable) {  // slf4j simple logger is not

+    ((org.slf4j.spi.LocationAwareLogger)logger).log(m, aFqcn, getSlf4jLevel(level), msg_with_params, null, thrown);

+  } else {

+    switch(level.toInteger()) {

+    case Level.SEVERE_INT: 

+      // all of these calls to MessageFormat are to the java.text.MessageFormat

+      // to do {n} style format substitution

+      logger.error(m, msg_with_params, thrown); 

+      break;

+    case Level.WARNING_INT: 

+      logger.warn(m, msg_with_params, thrown); 

+      break;

+    case Level.INFO_INT: 

+      logger.info(m, msg_with_params, thrown); 

+      break;

+    case Level.CONFIG_INT: 

+      logger.info(m, msg_with_params, thrown); 

+      break;

+    case Level.FINE_INT: 

+      logger.debug(m, msg_with_params, thrown); 

+      break;

+    case Level.FINER_INT: 

+      logger.trace(m, msg_with_params, thrown); 

+      break;

+    case Level.FINEST_INT: 

+      logger.trace(m, msg_with_params, thrown); 

+      break;

+    default: Misc.internalError();

+    }

+  }

+    

+  }

+

+  // does the slf4j style of message formatting

+  public void log2(Marker m, String aFqcn, Level level, String message, Object[] args, Throwable thrown) {

+    m = (m == null) 

+        ? getMarkerForLevel(level) 

+        : m;

+        

+    if (isLocationCapable) {  // slf4j simple logger is not

+      ((org.slf4j.spi.LocationAwareLogger)logger).log(m, aFqcn, getSlf4jLevel(level), message, args, thrown);

+    } else {

+      if (thrown != null) {

+        Object[] args1 = (args == null) ? new Object[1] : new Object[args.length + 1];

+        if (args != null) {

+          System.arraycopy(args, 0, args1, 0, args.length);

+        }

+        args1[args1.length - 1] = thrown;

+        args = args1;

+      }  

+      switch(level.toInteger()) {

+      case Level.SEVERE_INT: 

+        logger.error(m, message, args); 

+        break;

+      case Level.WARNING_INT: 

+        logger.warn(m, message, args); 

+        break;

+      case Level.INFO_INT: 

+        logger.info(m, message, args); 

+        break;

+      case Level.CONFIG_INT: 

+        logger.info(m, message, args); 

+        break;

+      case Level.FINE_INT: 

+        logger.debug(m, message, args); 

+        break;

+      case Level.FINER_INT: 

+        logger.trace(m, message, args); 

+        break;

+      case Level.FINEST_INT: 

+        logger.trace(m, message, args); 

+        break;

+      default: Misc.internalError();

+      }

+    }

+  }

+  

+  /**

+   * @return the logger name

+   * @see org.slf4j.Logger#getName()

+   */

+  public String getName() {

+    return logger.getName();

+  }

+

+  /**

+   * @return -

+   * @see org.slf4j.Logger#isTraceEnabled()

+   */

+  public boolean isTraceEnabled() {

+    return logger.isTraceEnabled();

+  }

+

+  /**

+   * @param marker -

+   * @return true if trace is enabled for this marker

+   * @see org.slf4j.Logger#isTraceEnabled(org.slf4j.Marker)

+   */

+  public boolean isTraceEnabled(Marker marker) {

+    return logger.isTraceEnabled(marker);

+  }

+

+

+  /**

+   * @return -

+   * @see org.slf4j.Logger#isDebugEnabled()

+   */

+  public boolean isDebugEnabled() {

+    return logger.isDebugEnabled();

+  }

+

+  /**

+   * @param marker -

+   * @return true if is enabled for this marker

+   * @see org.slf4j.Logger#isDebugEnabled(org.slf4j.Marker)

+   */

+  public boolean isDebugEnabled(Marker marker) {

+    return logger.isDebugEnabled(marker);

+  }

+

+

+  /**

+   * @return -

+   * @see org.slf4j.Logger#isInfoEnabled()

+   */

+  public boolean isInfoEnabled() {

+    return logger.isInfoEnabled();

+  }

+

+

+  /**

+   * @param marker -

+   * @return true if is enabled for this marker

+   * @see org.slf4j.Logger#isInfoEnabled(org.slf4j.Marker)

+   */

+  public boolean isInfoEnabled(Marker marker) {

+    return logger.isInfoEnabled(marker);

+  }

+

+

+  /**

+   * @return -

+   * @see org.slf4j.Logger#isWarnEnabled()

+   */

+  public boolean isWarnEnabled() {

+    return logger.isWarnEnabled();

+  }

+

+  /**

+   * @param marker -

+   * @return true if is enabled for this marker

+   * @see org.slf4j.Logger#isWarnEnabled(org.slf4j.Marker)

+   */

+  public boolean isWarnEnabled(Marker marker) {

+    return logger.isWarnEnabled(marker);

+  }

+

+  /**

+   * @return -

+   * @see org.slf4j.Logger#isErrorEnabled()

+   */

+  public boolean isErrorEnabled() {

+    return logger.isErrorEnabled();

+  }

+

+  /**

+   * @param marker -

+   * @return true if is enabled for this marker

+   * @see org.slf4j.Logger#isErrorEnabled(org.slf4j.Marker)

+   */

+  public boolean isErrorEnabled(Marker marker) {

+    return logger.isErrorEnabled(marker);

+  }

+

+}

diff --git a/uimaj-core/src/main/java/org/apache/uima/util/impl/XMLParser_impl.java b/uimaj-core/src/main/java/org/apache/uima/util/impl/XMLParser_impl.java
index e4e5bdb..22401be 100644
--- a/uimaj-core/src/main/java/org/apache/uima/util/impl/XMLParser_impl.java
+++ b/uimaj-core/src/main/java/org/apache/uima/util/impl/XMLParser_impl.java
@@ -105,6 +105,7 @@
     SCHEMA_URL = schemaURL;
     }
 
+  
   /**
    * Map from XML element names to Class objects.
    */
@@ -155,7 +156,7 @@
           XMLParser.ParsingOptions aOptions) throws InvalidXMLException {
     URL urlToParse = aInput.getURL();
     try {
-      SAXParserFactory factory = SAXParserFactory.newInstance();
+      SAXParserFactory factory = XMLUtils.createSAXParserFactory();
 
       // Turn on namespace support
       factory.setNamespaceAware(true);        
diff --git a/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties b/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties
index c8109ad..9fac578 100644
--- a/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties
+++ b/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties
@@ -132,7 +132,7 @@
 directory_not_found = Invalid value for parameter "{0}" in component "{1}" -- \
 	 directory "{2}" does not exist.
 
-external_override_invalid = External override variable "{0}" references the undefined variable "{1}"
+external_override_invalid = Undefined reference to external override variable "{0}" when evaluating "{1}"
 
 external_override_error = Error loading external overrides from "{0}"
 
@@ -140,6 +140,8 @@
 
 external_override_numeric_error = External override value "{0}" is not an integer
 
+external_override_circular_reference = Circular reference to external override variable "{0}" when evaluating "{1}"
+
 #--------------------------------
 #ResourceProcessException
 #--------------------------------
@@ -527,7 +529,8 @@
 JCAS_FEATURE_WRONG_TYPE = The JCAS range type {2} for feature {1} of type {0} does not match the CAS range type {3} for the feature.
 TYPEORDER_UNKNOWN_TYPE = The type sort order cannot be built because type {0} is unknown.
 MUST_COMMIT_TYPE_SYSTEM = Type system has not been committed. The base index cannot be created.
-
+JCAS_NO_TYPE = Cannot do feature accessing for a JCas class, because it is not associated with a committed UIMA Type, either because the type doesn''t exist, or hasn''t been committed.
+JCAS_INCOMPATIBLE_TYPE_SYSTEMS = Loaded JCas Type {0} has feature {1} with two different type systems having different offsets; this is not supported.
 
 #------------------------------------------------------------------------
 # CAS runtime exceptions
@@ -555,7 +558,7 @@
 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.
@@ -563,7 +566,9 @@
 JCAS_OLDSTYLE_REF_TO_NONJCAS_TYPE = JCas is referencing via a JFSIterator or get method, a type, "{0}", which has no JCAS class model.  You must use FSIterator instead of JFSIterator.
 JCAS_MAKING_ABSTRACT_INSTANCE = A CAS iterator or createFS call is trying to make an instance of type "{0}", but that type has been declared "abstract" in JCas, and no instances are allowed to be made.
 JCAS_UNSUPPORTED_OP_NOT_TCAS = The method "{0}" is not supported by this JCAS because it is not associated with a TCAS view of a CAS, but rather just with a base CAS.
-JCAS_CLASS_INITIALIZED_BEFORE_TYPE_SYSTEM_COMMIT = A JCas class field "{0}" is being initialized by non-framework (user) code before Type System Commit for a type system with a corresponding type. Either change the user load code to not do initialize, or to defer it until after the type system commit.
+JCAS_MISSING_GETTER = JCas class {0} with feature {1} but is missing a 0 argument getter.  This feature will not be used to maybe expand the type's feature set.
+JCAS_MISSING_TYPEINDEX = The Class "{0}" matches a UIMA Type, and is a subtype of uima.cas.TOP, but is missing the JCas typeIndexId.
+JCAS_ALPHA_LEVEL_NOT_SUPPORTED = The JCas class being loaded may have been generated for the alpha level of UIMA v3, and may need regenerating.
 SOFANAME_ALREADY_EXISTS = A sofaFS with name {0} has already been created.
 SOFADATA_ALREADY_SET = Data for Sofa feature {0} has already been set.
 SOFANAME_NOT_FOUND = No sofaFS with name {0} found.
@@ -614,6 +619,7 @@
 BLOB_SERIALIZATION = Error trying to do binary serialization of CAS data and write the BLOB to an output stream.
 BLOB_DESERIALIZATION = Error trying to read BLOB data from an input stream and deserialize into a CAS.
 LENIENT_FORM_6_NO_TS = Deserializing Compressed Form 6 with CasLoadMode LENIENT, but no Type System provided.
+DESER_FORM_6_BAD_TYPE_CODE = Deserializing Compressed Form 6, a type code: {0} has no corresponding type. currentFsId: {1} nbrFSs: {2} nextFsAddr: {3} 
 UNRECOGNIZED_SERIALIZED_CAS_FORMAT = Unrecognized serialized CAS format.
 deserialized_type_not_found = While deserializing, no type found for type code {0}.
 SWITCH_CLASS_LOADER_NESTED = Multiply nested classloaders not supported.  Original base loader: {0}, current nested loader: {1}, trying to switch to loader: {2}.
\ No newline at end of file
diff --git a/uimaj-core/src/main/resources/org/apache/uima/impl/factoryConfig.xml b/uimaj-core/src/main/resources/org/apache/uima/impl/factoryConfig.xml
index 14c30cd..4585931 100644
--- a/uimaj-core/src/main/resources/org/apache/uima/impl/factoryConfig.xml
+++ b/uimaj-core/src/main/resources/org/apache/uima/impl/factoryConfig.xml
@@ -24,7 +24,8 @@
 	 Do not edit this file unless you are SURE you know what you are doing. -->
 <factoryConfig>
 	<cpm class="org.apache.uima.collection.impl.cpm.CPMImpl"/>
-    <logger class="org.apache.uima.util.impl.JSR47Logger_impl"/>
+  <logger class="org.apache.uima.util.impl.Slf4jLogger_impl"/>
+  <!-- logger class="org.apache.uima.util.impl.JSR47Logger_impl"/ -->
 	<resourceManager class="org.apache.uima.resource.impl.ResourceManager_impl"/>
   <resourceManagerPearWrapper class="org.apache.uima.resource.impl.ResourceManagerPearWrapper_impl"/>
 	<configurationManager class="org.apache.uima.resource.impl.ConfigurationManager_impl"/>
diff --git a/uimaj-core/src/main/resources/org/apache/uima/impl/log_messages.properties b/uimaj-core/src/main/resources/org/apache/uima/impl/log_messages.properties
index c0e2d8c..4402f50 100644
--- a/uimaj-core/src/main/resources/org/apache/uima/impl/log_messages.properties
+++ b/uimaj-core/src/main/resources/org/apache/uima/impl/log_messages.properties
@@ -80,6 +80,8 @@
 
 UIMA_external_override_ignored__CONFIG = Key "{0}" already in use ... ignoring value "{1}"
 
+UIMA_import_by__CONFIG = Import by {0}: {1}
+
 UIMA_parameter_set__CONFIG = Parameter "{0}" in context {1} = "{2}" {3}
 
 UIMA_overridden_resource__CONFIG = The definition of external resource "{0}" in component {1} was overridden in component {2}.
diff --git a/uimaj-core/src/main/resources/org/apache/uima/semibuiltins.xml b/uimaj-core/src/main/resources/org/apache/uima/semibuiltins.xml
index 7706bd2..4d429f8 100644
--- a/uimaj-core/src/main/resources/org/apache/uima/semibuiltins.xml
+++ b/uimaj-core/src/main/resources/org/apache/uima/semibuiltins.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>

-  <!--

+<!--

    ***************************************************************

    * Licensed to the Apache Software Foundation (ASF) under one

    * or more contributor license agreements.  See the NOTICE file

@@ -19,7 +19,6 @@
    * under the License.

    ***************************************************************

    -->

-

 <typeSystemDescription xmlns="http://uima.apache.org/resourceSpecifier">

     <name>semibuiltins</name>

     <description>Semi-built-in types that can can be optionally imported by name.</description>

@@ -36,6 +35,7 @@
           <description/>

           <rangeTypeName>uima.cas.FSArray</rangeTypeName>

           <elementType>uima.cas.TOP</elementType>

+        <multipleReferencesAllowed>true</multipleReferencesAllowed>

         </featureDescription>

       </features>

     </typeDescription>

@@ -49,6 +49,7 @@
           <description/>

           <rangeTypeName>uima.cas.FSArray</rangeTypeName>

           <elementType>uima.cas.TOP</elementType>

+        <multipleReferencesAllowed>true</multipleReferencesAllowed>

         </featureDescription>

       </features>

     </typeDescription>

@@ -61,6 +62,38 @@
           <name>intArray</name>

           <description/>

           <rangeTypeName>uima.cas.IntegerArray</rangeTypeName>

+        <multipleReferencesAllowed>true</multipleReferencesAllowed>

+        </featureDescription>

+      </features>

+    </typeDescription>

+  <typeDescription>

+      <name>org.apache.uima.jcas.cas.FSLinkedHashSet</name>

+      <description/>

+      <supertypeName>org.apache.uima.jcas.cas.FSHashSet</supertypeName>

+      <features>

+        <featureDescription>

+          <name>fsArray</name>

+          <description>Internal use only</description>

+          <rangeTypeName>uima.cas.FSArray</rangeTypeName>

+          <elementType>uima.cas.TOP</elementType>

+          <multipleReferencesAllowed>true</multipleReferencesAllowed>

+        </featureDescription>

+      </features>

+    </typeDescription>

+  <typeDescription>

+      <name>org.apache.uima.jcas.cas.Int2FS</name>

+      <description>map from ints to Feature Structures</description>

+      <supertypeName>uima.cas.TOP</supertypeName>

+      <features>

+        <featureDescription>

+          <name>fsArray</name>

+          <description>internal use</description>

+          <rangeTypeName>uima.cas.FSArray</rangeTypeName>

+        </featureDescription>

+        <featureDescription>

+          <name>intArray</name>

+          <description>internal use</description>

+          <rangeTypeName>uima.cas.IntegerArray</rangeTypeName>

         </featureDescription>

       </features>

     </typeDescription>

diff --git a/uimaj-core/src/main/resources/resourceSpecifierSchema.xsd b/uimaj-core/src/main/resources/resourceSpecifierSchema.xsd
index b3580a0..bf01d3f 100644
--- a/uimaj-core/src/main/resources/resourceSpecifierSchema.xsd
+++ b/uimaj-core/src/main/resources/resourceSpecifierSchema.xsd
@@ -398,7 +398,7 @@
 
 	<complexType name="FsIndexType">
 		<sequence>
-			<element name="label" type="Name" />
+			<element name="label" type="string" />
 			<element name="typeName" type="Name" />
 			<element name="kind" minOccurs="0" maxOccurs="1">
 				<simpleType>
diff --git a/uimaj-core/src/test/java/aa/AbstractType.java b/uimaj-core/src/test/java/aa/AbstractType.java
index 2e2b92e..ec31e60 100644
--- a/uimaj-core/src/test/java/aa/AbstractType.java
+++ b/uimaj-core/src/test/java/aa/AbstractType.java
@@ -1,10 +1,30 @@
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
    
-/* Apache UIMA v3 - First created by JCasGen Fri Dec 16 10:23:12 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:06:27 EDT 2017 */
 
 package aa;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -16,8 +36,8 @@
 
 
 /** 
- * Updated by JCasGen Fri Dec 16 10:23:12 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
+ * Updated by JCasGen Sun Oct 08 19:06:27 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
  * @generated */
 public class AbstractType extends TOP {
  
@@ -52,7 +72,8 @@
 
 
   /* Feature Adjusted Offsets */
-  public final static int _FI_abstractInt = TypeSystemImpl.getAdjustedFeatureOffset("abstractInt");
+  private final static CallSite _FC_abstractInt = TypeSystemImpl.createCallSite(AbstractType.class, "abstractInt");
+  private final static MethodHandle _FH_abstractInt = _FC_abstractInt.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -96,14 +117,14 @@
    * @generated
    * @return value of the feature 
    */
-  public int getAbstractInt() { return _getIntValueNc(_FI_abstractInt);}
+  public int getAbstractInt() { return _getIntValueNc(wrapGetIntCatchException(_FH_abstractInt));}
     
   /** setter for abstractInt - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAbstractInt(int v) {
-    _setIntValueNfc(_FI_abstractInt, v);
+    _setIntValueNfc(wrapGetIntCatchException(_FH_abstractInt), v);
   }    
     
   }
diff --git a/uimaj-core/src/test/java/aa/ConcreteType.java b/uimaj-core/src/test/java/aa/ConcreteType.java
index 40f6340..8083f61 100644
--- a/uimaj-core/src/test/java/aa/ConcreteType.java
+++ b/uimaj-core/src/test/java/aa/ConcreteType.java
@@ -1,10 +1,30 @@
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
    
-/* Apache UIMA v3 - First created by JCasGen Fri Dec 16 10:23:12 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:06:27 EDT 2017 */
 
 package aa;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -15,8 +35,8 @@
 
 
 /** 
- * Updated by JCasGen Fri Dec 16 10:23:12 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
+ * Updated by JCasGen Sun Oct 08 19:06:27 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
  * @generated */
 public class ConcreteType extends AbstractType {
  
@@ -51,7 +71,8 @@
 
 
   /* Feature Adjusted Offsets */
-  public final static int _FI_concreteString = TypeSystemImpl.getAdjustedFeatureOffset("concreteString");
+  private final static CallSite _FC_concreteString = TypeSystemImpl.createCallSite(ConcreteType.class, "concreteString");
+  private final static MethodHandle _FH_concreteString = _FC_concreteString.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -95,14 +116,14 @@
    * @generated
    * @return value of the feature 
    */
-  public String getConcreteString() { return _getStringValueNc(_FI_concreteString);}
+  public String getConcreteString() { return _getStringValueNc(wrapGetIntCatchException(_FH_concreteString));}
     
   /** setter for concreteString - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setConcreteString(String v) {
-    _setStringValueNfc(_FI_concreteString, v);
+    _setStringValueNfc(wrapGetIntCatchException(_FH_concreteString), v);
   }    
     
   }
diff --git a/uimaj-core/src/test/java/aa/MissingFeatureInCas.java b/uimaj-core/src/test/java/aa/MissingFeatureInCas.java
index d6a876d..8b87fa3 100644
--- a/uimaj-core/src/test/java/aa/MissingFeatureInCas.java
+++ b/uimaj-core/src/test/java/aa/MissingFeatureInCas.java
@@ -1,10 +1,30 @@
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
    
-/* Apache UIMA v3 - First created by JCasGen Fri Dec 16 10:23:12 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:06:27 EDT 2017 */
 
 package aa;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -16,8 +36,8 @@
 
 
 /** 
- * Updated by JCasGen Fri Dec 16 10:23:12 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
+ * Updated by JCasGen Sun Oct 08 19:06:27 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
  * @generated */
 public class MissingFeatureInCas extends TOP {
  
@@ -54,9 +74,12 @@
 
 
   /* Feature Adjusted Offsets */
-  public final static int _FI_haveThisOne = TypeSystemImpl.getAdjustedFeatureOffset("haveThisOne");
-  public final static int _FI_missingThisOne = TypeSystemImpl.getAdjustedFeatureOffset("missingThisOne");
-  public final static int _FI_changedFType = TypeSystemImpl.getAdjustedFeatureOffset("changedFType");
+  private final static CallSite _FC_haveThisOne = TypeSystemImpl.createCallSite(MissingFeatureInCas.class, "haveThisOne");
+  private final static MethodHandle _FH_haveThisOne = _FC_haveThisOne.dynamicInvoker();
+  private final static CallSite _FC_missingThisOne = TypeSystemImpl.createCallSite(MissingFeatureInCas.class, "missingThisOne");
+  private final static MethodHandle _FH_missingThisOne = _FC_missingThisOne.dynamicInvoker();
+  private final static CallSite _FC_changedFType = TypeSystemImpl.createCallSite(MissingFeatureInCas.class, "changedFType");
+  private final static MethodHandle _FH_changedFType = _FC_changedFType.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -100,14 +123,14 @@
    * @generated
    * @return value of the feature 
    */
-  public int getHaveThisOne() { return _getIntValueNc(_FI_haveThisOne);}
+  public int getHaveThisOne() { return _getIntValueNc(wrapGetIntCatchException(_FH_haveThisOne));}
     
   /** setter for haveThisOne - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setHaveThisOne(int v) {
-    _setIntValueNfc(_FI_haveThisOne, v);
+    _setIntValueNfc(wrapGetIntCatchException(_FH_haveThisOne), v);
   }    
     
    
@@ -119,14 +142,14 @@
    * @generated
    * @return value of the feature 
    */
-  public float getMissingThisOne() { return _getFloatValueNc(_FI_missingThisOne);}
+  public float getMissingThisOne() { return _getFloatValueNc(wrapGetIntCatchException(_FH_missingThisOne));}
     
   /** setter for missingThisOne - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setMissingThisOne(float v) {
-    _setFloatValueNfc(_FI_missingThisOne, v);
+    _setFloatValueNfc(wrapGetIntCatchException(_FH_missingThisOne), v);
   }    
     
    
@@ -138,14 +161,14 @@
    * @generated
    * @return value of the feature 
    */
-  public String getChangedFType() { return _getStringValueNc(_FI_changedFType);}
+  public String getChangedFType() { return _getStringValueNc(wrapGetIntCatchException(_FH_changedFType));}
     
   /** setter for changedFType - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setChangedFType(String v) {
-    _setStringValueNfc(_FI_changedFType, v);
+    _setStringValueNfc(wrapGetIntCatchException(_FH_changedFType), v);
   }    
     
   }
diff --git a/uimaj-core/src/test/java/aa/MissingInCas.java b/uimaj-core/src/test/java/aa/MissingInCas.java
index c95f7ae..706c0ae 100644
--- a/uimaj-core/src/test/java/aa/MissingInCas.java
+++ b/uimaj-core/src/test/java/aa/MissingInCas.java
@@ -1,10 +1,30 @@
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
    
-/* Apache UIMA v3 - First created by JCasGen Fri Dec 16 10:23:12 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:06:27 EDT 2017 */
 
 package aa;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -16,8 +36,8 @@
 
 
 /** 
- * Updated by JCasGen Fri Dec 16 10:23:12 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
+ * Updated by JCasGen Sun Oct 08 19:06:27 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
  * @generated */
 public class MissingInCas extends TOP {
  
diff --git a/uimaj-core/src/test/java/aa/Root.java b/uimaj-core/src/test/java/aa/Root.java
index a9f940b..b4978b7 100644
--- a/uimaj-core/src/test/java/aa/Root.java
+++ b/uimaj-core/src/test/java/aa/Root.java
@@ -1,10 +1,30 @@
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
    
-/* Apache UIMA v3 - First created by JCasGen Fri Dec 16 10:23:12 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:06:27 EDT 2017 */
 
 package aa;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -22,8 +42,8 @@
 
 
 /** 
- * Updated by JCasGen Fri Dec 16 10:23:12 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
+ * Updated by JCasGen Sun Oct 08 19:06:27 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
  * @generated */
 public class Root extends TOP {
  
@@ -69,18 +89,30 @@
 
 
   /* Feature Adjusted Offsets */
-  public final static int _FI_arrayInt = TypeSystemImpl.getAdjustedFeatureOffset("arrayInt");
-  public final static int _FI_arrayRef = TypeSystemImpl.getAdjustedFeatureOffset("arrayRef");
-  public final static int _FI_arrayFloat = TypeSystemImpl.getAdjustedFeatureOffset("arrayFloat");
-  public final static int _FI_arrayString = TypeSystemImpl.getAdjustedFeatureOffset("arrayString");
-  public final static int _FI_plainInt = TypeSystemImpl.getAdjustedFeatureOffset("plainInt");
-  public final static int _FI_plainFloat = TypeSystemImpl.getAdjustedFeatureOffset("plainFloat");
-  public final static int _FI_plainString = TypeSystemImpl.getAdjustedFeatureOffset("plainString");
-  public final static int _FI_plainRef = TypeSystemImpl.getAdjustedFeatureOffset("plainRef");
-  public final static int _FI_plainLong = TypeSystemImpl.getAdjustedFeatureOffset("plainLong");
-  public final static int _FI_plainDouble = TypeSystemImpl.getAdjustedFeatureOffset("plainDouble");
-  public final static int _FI_arrayLong = TypeSystemImpl.getAdjustedFeatureOffset("arrayLong");
-  public final static int _FI_arrayDouble = TypeSystemImpl.getAdjustedFeatureOffset("arrayDouble");
+  private final static CallSite _FC_arrayInt = TypeSystemImpl.createCallSite(Root.class, "arrayInt");
+  private final static MethodHandle _FH_arrayInt = _FC_arrayInt.dynamicInvoker();
+  private final static CallSite _FC_arrayRef = TypeSystemImpl.createCallSite(Root.class, "arrayRef");
+  private final static MethodHandle _FH_arrayRef = _FC_arrayRef.dynamicInvoker();
+  private final static CallSite _FC_arrayFloat = TypeSystemImpl.createCallSite(Root.class, "arrayFloat");
+  private final static MethodHandle _FH_arrayFloat = _FC_arrayFloat.dynamicInvoker();
+  private final static CallSite _FC_arrayString = TypeSystemImpl.createCallSite(Root.class, "arrayString");
+  private final static MethodHandle _FH_arrayString = _FC_arrayString.dynamicInvoker();
+  private final static CallSite _FC_plainInt = TypeSystemImpl.createCallSite(Root.class, "plainInt");
+  private final static MethodHandle _FH_plainInt = _FC_plainInt.dynamicInvoker();
+  private final static CallSite _FC_plainFloat = TypeSystemImpl.createCallSite(Root.class, "plainFloat");
+  private final static MethodHandle _FH_plainFloat = _FC_plainFloat.dynamicInvoker();
+  private final static CallSite _FC_plainString = TypeSystemImpl.createCallSite(Root.class, "plainString");
+  private final static MethodHandle _FH_plainString = _FC_plainString.dynamicInvoker();
+  private final static CallSite _FC_plainRef = TypeSystemImpl.createCallSite(Root.class, "plainRef");
+  private final static MethodHandle _FH_plainRef = _FC_plainRef.dynamicInvoker();
+  private final static CallSite _FC_plainLong = TypeSystemImpl.createCallSite(Root.class, "plainLong");
+  private final static MethodHandle _FH_plainLong = _FC_plainLong.dynamicInvoker();
+  private final static CallSite _FC_plainDouble = TypeSystemImpl.createCallSite(Root.class, "plainDouble");
+  private final static MethodHandle _FH_plainDouble = _FC_plainDouble.dynamicInvoker();
+  private final static CallSite _FC_arrayLong = TypeSystemImpl.createCallSite(Root.class, "arrayLong");
+  private final static MethodHandle _FH_arrayLong = _FC_arrayLong.dynamicInvoker();
+  private final static CallSite _FC_arrayDouble = TypeSystemImpl.createCallSite(Root.class, "arrayDouble");
+  private final static MethodHandle _FH_arrayDouble = _FC_arrayDouble.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -124,14 +156,14 @@
    * @generated
    * @return value of the feature 
    */
-  public IntegerArray getArrayInt() { return (IntegerArray)(_getFeatureValueNc(_FI_arrayInt));}
+  public IntegerArray getArrayInt() { return (IntegerArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayInt)));}
     
   /** setter for arrayInt - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setArrayInt(IntegerArray v) {
-    _setFeatureValueNcWj(_FI_arrayInt, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_arrayInt), v);
   }    
     
     
@@ -141,7 +173,7 @@
    * @return value of the element at index i 
    */
   public int getArrayInt(int i) {
-     return ((IntegerArray)(_getFeatureValueNc(_FI_arrayInt))).get(i);} 
+     return ((IntegerArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayInt)))).get(i);} 
 
   /** indexed setter for arrayInt - sets an indexed value - 
    * @generated
@@ -149,7 +181,7 @@
    * @param v value to set into the array 
    */
   public void setArrayInt(int i, int v) {
-    ((IntegerArray)(_getFeatureValueNc(_FI_arrayInt))).set(i, v);
+    ((IntegerArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayInt)))).set(i, v);
   }  
    
     
@@ -160,14 +192,14 @@
    * @generated
    * @return value of the feature 
    */
-  public FSArray getArrayRef() { return (FSArray)(_getFeatureValueNc(_FI_arrayRef));}
+  public FSArray getArrayRef() { return (FSArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayRef)));}
     
   /** setter for arrayRef - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setArrayRef(FSArray v) {
-    _setFeatureValueNcWj(_FI_arrayRef, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_arrayRef), v);
   }    
     
     
@@ -177,7 +209,7 @@
    * @return value of the element at index i 
    */
   public TOP getArrayRef(int i) {
-     return (TOP)(((FSArray)(_getFeatureValueNc(_FI_arrayRef))).get(i));} 
+     return (TOP)(((FSArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayRef)))).get(i));} 
 
   /** indexed setter for arrayRef - sets an indexed value - 
    * @generated
@@ -185,7 +217,7 @@
    * @param v value to set into the array 
    */
   public void setArrayRef(int i, TOP v) {
-    ((FSArray)(_getFeatureValueNc(_FI_arrayRef))).set(i, v);
+    ((FSArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayRef)))).set(i, v);
   }  
    
     
@@ -196,14 +228,14 @@
    * @generated
    * @return value of the feature 
    */
-  public FloatArray getArrayFloat() { return (FloatArray)(_getFeatureValueNc(_FI_arrayFloat));}
+  public FloatArray getArrayFloat() { return (FloatArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayFloat)));}
     
   /** setter for arrayFloat - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setArrayFloat(FloatArray v) {
-    _setFeatureValueNcWj(_FI_arrayFloat, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_arrayFloat), v);
   }    
     
     
@@ -213,7 +245,7 @@
    * @return value of the element at index i 
    */
   public float getArrayFloat(int i) {
-     return ((FloatArray)(_getFeatureValueNc(_FI_arrayFloat))).get(i);} 
+     return ((FloatArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayFloat)))).get(i);} 
 
   /** indexed setter for arrayFloat - sets an indexed value - 
    * @generated
@@ -221,7 +253,7 @@
    * @param v value to set into the array 
    */
   public void setArrayFloat(int i, float v) {
-    ((FloatArray)(_getFeatureValueNc(_FI_arrayFloat))).set(i, v);
+    ((FloatArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayFloat)))).set(i, v);
   }  
    
     
@@ -232,14 +264,14 @@
    * @generated
    * @return value of the feature 
    */
-  public StringArray getArrayString() { return (StringArray)(_getFeatureValueNc(_FI_arrayString));}
+  public StringArray getArrayString() { return (StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayString)));}
     
   /** setter for arrayString - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setArrayString(StringArray v) {
-    _setFeatureValueNcWj(_FI_arrayString, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_arrayString), v);
   }    
     
     
@@ -249,7 +281,7 @@
    * @return value of the element at index i 
    */
   public String getArrayString(int i) {
-     return ((StringArray)(_getFeatureValueNc(_FI_arrayString))).get(i);} 
+     return ((StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayString)))).get(i);} 
 
   /** indexed setter for arrayString - sets an indexed value - 
    * @generated
@@ -257,7 +289,7 @@
    * @param v value to set into the array 
    */
   public void setArrayString(int i, String v) {
-    ((StringArray)(_getFeatureValueNc(_FI_arrayString))).set(i, v);
+    ((StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayString)))).set(i, v);
   }  
    
     
@@ -268,14 +300,14 @@
    * @generated
    * @return value of the feature 
    */
-  public int getPlainInt() { return _getIntValueNc(_FI_plainInt);}
+  public int getPlainInt() { return _getIntValueNc(wrapGetIntCatchException(_FH_plainInt));}
     
   /** setter for plainInt - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setPlainInt(int v) {
-    _setIntValueNfc(_FI_plainInt, v);
+    _setIntValueNfc(wrapGetIntCatchException(_FH_plainInt), v);
   }    
     
    
@@ -287,14 +319,14 @@
    * @generated
    * @return value of the feature 
    */
-  public float getPlainFloat() { return _getFloatValueNc(_FI_plainFloat);}
+  public float getPlainFloat() { return _getFloatValueNc(wrapGetIntCatchException(_FH_plainFloat));}
     
   /** setter for plainFloat - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setPlainFloat(float v) {
-    _setFloatValueNfc(_FI_plainFloat, v);
+    _setFloatValueNfc(wrapGetIntCatchException(_FH_plainFloat), v);
   }    
     
    
@@ -306,14 +338,14 @@
    * @generated
    * @return value of the feature 
    */
-  public String getPlainString() { return _getStringValueNc(_FI_plainString);}
+  public String getPlainString() { return _getStringValueNc(wrapGetIntCatchException(_FH_plainString));}
     
   /** setter for plainString - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setPlainString(String v) {
-    _setStringValueNfc(_FI_plainString, v);
+    _setStringValueNfc(wrapGetIntCatchException(_FH_plainString), v);
   }    
     
    
@@ -325,14 +357,14 @@
    * @generated
    * @return value of the feature 
    */
-  public Root getPlainRef() { return (Root)(_getFeatureValueNc(_FI_plainRef));}
+  public Root getPlainRef() { return (Root)(_getFeatureValueNc(wrapGetIntCatchException(_FH_plainRef)));}
     
   /** setter for plainRef - sets TokenType testMissingImport; 
    * @generated
    * @param v value to set into the feature 
    */
   public void setPlainRef(Root v) {
-    _setFeatureValueNcWj(_FI_plainRef, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_plainRef), v);
   }    
     
    
@@ -344,14 +376,14 @@
    * @generated
    * @return value of the feature 
    */
-  public long getPlainLong() { return _getLongValueNc(_FI_plainLong);}
+  public long getPlainLong() { return _getLongValueNc(wrapGetIntCatchException(_FH_plainLong));}
     
   /** setter for plainLong - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setPlainLong(long v) {
-    _setLongValueNfc(_FI_plainLong, v);
+    _setLongValueNfc(wrapGetIntCatchException(_FH_plainLong), v);
   }    
     
    
@@ -363,14 +395,14 @@
    * @generated
    * @return value of the feature 
    */
-  public double getPlainDouble() { return _getDoubleValueNc(_FI_plainDouble);}
+  public double getPlainDouble() { return _getDoubleValueNc(wrapGetIntCatchException(_FH_plainDouble));}
     
   /** setter for plainDouble - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setPlainDouble(double v) {
-    _setDoubleValueNfc(_FI_plainDouble, v);
+    _setDoubleValueNfc(wrapGetIntCatchException(_FH_plainDouble), v);
   }    
     
    
@@ -382,14 +414,14 @@
    * @generated
    * @return value of the feature 
    */
-  public LongArray getArrayLong() { return (LongArray)(_getFeatureValueNc(_FI_arrayLong));}
+  public LongArray getArrayLong() { return (LongArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayLong)));}
     
   /** setter for arrayLong - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setArrayLong(LongArray v) {
-    _setFeatureValueNcWj(_FI_arrayLong, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_arrayLong), v);
   }    
     
     
@@ -399,7 +431,7 @@
    * @return value of the element at index i 
    */
   public long getArrayLong(int i) {
-     return ((LongArray)(_getFeatureValueNc(_FI_arrayLong))).get(i);} 
+     return ((LongArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayLong)))).get(i);} 
 
   /** indexed setter for arrayLong - sets an indexed value - 
    * @generated
@@ -407,7 +439,7 @@
    * @param v value to set into the array 
    */
   public void setArrayLong(int i, long v) {
-    ((LongArray)(_getFeatureValueNc(_FI_arrayLong))).set(i, v);
+    ((LongArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayLong)))).set(i, v);
   }  
    
     
@@ -418,14 +450,14 @@
    * @generated
    * @return value of the feature 
    */
-  public DoubleArray getArrayDouble() { return (DoubleArray)(_getFeatureValueNc(_FI_arrayDouble));}
+  public DoubleArray getArrayDouble() { return (DoubleArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayDouble)));}
     
   /** setter for arrayDouble - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setArrayDouble(DoubleArray v) {
-    _setFeatureValueNcWj(_FI_arrayDouble, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_arrayDouble), v);
   }    
     
     
@@ -435,7 +467,7 @@
    * @return value of the element at index i 
    */
   public double getArrayDouble(int i) {
-     return ((DoubleArray)(_getFeatureValueNc(_FI_arrayDouble))).get(i);} 
+     return ((DoubleArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayDouble)))).get(i);} 
 
   /** indexed setter for arrayDouble - sets an indexed value - 
    * @generated
@@ -443,7 +475,7 @@
    * @param v value to set into the array 
    */
   public void setArrayDouble(int i, double v) {
-    ((DoubleArray)(_getFeatureValueNc(_FI_arrayDouble))).set(i, v);
+    ((DoubleArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayDouble)))).set(i, v);
   }  
   }
 
diff --git a/uimaj-core/src/test/java/aa/T.java b/uimaj-core/src/test/java/aa/T.java
new file mode 100644
index 0000000..2cc1e8f
--- /dev/null
+++ b/uimaj-core/src/test/java/aa/T.java
@@ -0,0 +1,118 @@
+package aa;
+
+
+   
+/* Apache UIMA v3 - First created by JCasGen Thu Jan 04 17:25:52 EST 2018 */
+
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.cas.impl.TypeSystemImpl;
+import org.apache.uima.jcas.JCas; 
+import org.apache.uima.jcas.JCasRegistry;
+
+
+import org.apache.uima.jcas.cas.TOP;
+
+
+/** 
+ * Updated by JCasGen Thu Jan 04 17:25:52 EST 2018
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/resources/ExampleCas/testTypeSystem_t_1_feature.xml
+ * @generated */
+public class T extends TOP {
+ 
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "T";
+  
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static int typeIndexID = JCasRegistry.register(T.class);
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static int type = typeIndexID;
+  /** @generated
+   * @return index of the type  
+   */
+  @Override
+  public              int getTypeIndexID() {return typeIndexID;}
+ 
+ 
+  /* *******************
+   *   Feature Offsets *
+   * *******************/ 
+   
+  public final static String _FeatName_f1 = "f1";
+
+
+  /* Feature Adjusted Offsets */
+  private final static CallSite _FC_f1 = TypeSystemImpl.createCallSite(T.class, "f1");
+  private final static MethodHandle _FH_f1 = _FC_f1.dynamicInvoker();
+
+  public static void dumpOffset() throws Throwable {
+    System.out.println("_FC_f1 offset value is " + ( (int)_FH_f1.invokeExact()));
+  }
+   
+  /** Never called.  Disable default constructor
+   * @generated */
+  protected T() {/* intentionally empty block */}
+    
+  /** Internal - constructor used by generator 
+   * @generated
+   * @param casImpl the CAS this Feature Structure belongs to
+   * @param type the type of this Feature Structure 
+   */
+  public T(TypeImpl type, CASImpl casImpl) {
+    super(type, casImpl);
+    readObject();
+  }
+  
+  /** @generated
+   * @param jcas JCas to which this Feature Structure belongs 
+   */
+  public T(JCas jcas) {
+    super(jcas);
+    readObject();   
+  } 
+
+
+  /** 
+   * <!-- begin-user-doc -->
+   * Write your own initialization here
+   * <!-- end-user-doc -->
+   *
+   * @generated modifiable 
+   */
+  private void readObject() {/*default - does nothing empty block */}
+     
+ 
+    
+  //*--------------*
+  //* Feature: f1
+
+  /** getter for f1 - gets 
+   * @generated
+   * @return value of the feature 
+   */
+  public int getF1() { return _getIntValueNc(wrapGetIntCatchException(_FH_f1));}
+    
+  /** setter for f1 - sets  
+   * @generated
+   * @param v value to set into the feature 
+   */
+  public void setF1(int v) {
+    _setIntValueNfc(wrapGetIntCatchException(_FH_f1), v);
+  }    
+    
+  }
+
+    
\ No newline at end of file
diff --git a/uimaj-core/src/test/java/org/apache/lang/LanguagePair.java b/uimaj-core/src/test/java/org/apache/lang/LanguagePair.java
index 17803db..9884d88 100644
--- a/uimaj-core/src/test/java/org/apache/lang/LanguagePair.java
+++ b/uimaj-core/src/test/java/org/apache/lang/LanguagePair.java
@@ -1,10 +1,13 @@
 
 
    
-/* Apache UIMA v3 - First created by JCasGen Fri Dec 16 10:23:12 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:06:27 EDT 2017 */
 
 package org.apache.lang;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -16,8 +19,8 @@
 
 
 /** 
- * Updated by JCasGen Fri Dec 16 10:23:12 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
+ * Updated by JCasGen Sun Oct 08 19:06:27 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
  * @generated */
 public class LanguagePair extends TOP {
  
@@ -54,9 +57,12 @@
 
 
   /* Feature Adjusted Offsets */
-  public final static int _FI_lang1 = TypeSystemImpl.getAdjustedFeatureOffset("lang1");
-  public final static int _FI_lang2 = TypeSystemImpl.getAdjustedFeatureOffset("lang2");
-  public final static int _FI_description = TypeSystemImpl.getAdjustedFeatureOffset("description");
+  private final static CallSite _FC_lang1 = TypeSystemImpl.createCallSite(LanguagePair.class, "lang1");
+  private final static MethodHandle _FH_lang1 = _FC_lang1.dynamicInvoker();
+  private final static CallSite _FC_lang2 = TypeSystemImpl.createCallSite(LanguagePair.class, "lang2");
+  private final static MethodHandle _FH_lang2 = _FC_lang2.dynamicInvoker();
+  private final static CallSite _FC_description = TypeSystemImpl.createCallSite(LanguagePair.class, "description");
+  private final static MethodHandle _FH_description = _FC_description.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -100,14 +106,14 @@
    * @generated
    * @return value of the feature 
    */
-  public String getLang1() { return _getStringValueNc(_FI_lang1);}
+  public String getLang1() { return _getStringValueNc(wrapGetIntCatchException(_FH_lang1));}
     
   /** setter for lang1 - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setLang1(String v) {
-    _setStringValueNfc(_FI_lang1, v);
+    _setStringValueNfc(wrapGetIntCatchException(_FH_lang1), v);
   }    
     
    
@@ -119,14 +125,14 @@
    * @generated
    * @return value of the feature 
    */
-  public String getLang2() { return _getStringValueNc(_FI_lang2);}
+  public String getLang2() { return _getStringValueNc(wrapGetIntCatchException(_FH_lang2));}
     
   /** setter for lang2 - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setLang2(String v) {
-    _setStringValueNfc(_FI_lang2, v);
+    _setStringValueNfc(wrapGetIntCatchException(_FH_lang2), v);
   }    
     
    
@@ -138,14 +144,14 @@
    * @generated
    * @return value of the feature 
    */
-  public String getDescription() { return _getStringValueNc(_FI_description);}
+  public String getDescription() { return _getStringValueNc(wrapGetIntCatchException(_FH_description));}
     
   /** setter for description - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setDescription(String v) {
-    _setStringValueNfc(_FI_description, v);
+    _setStringValueNfc(wrapGetIntCatchException(_FH_description), v);
   }    
     
   }
diff --git a/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/AnalysisEngineDescription_implTest.java b/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/AnalysisEngineDescription_implTest.java
index 424d4fa..bb23eff 100644
--- a/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/AnalysisEngineDescription_implTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/AnalysisEngineDescription_implTest.java
@@ -296,6 +296,7 @@
   public void tearDown() {
     primitiveDesc = null;
     aggregateDesc = null;
+    UIMAFramework.getXMLParser().enableSchemaValidation(false);
   }
   
   public void testMulticoreInitialize() throws Exception {
diff --git a/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/AnalysisEngine_implTest.java b/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/AnalysisEngine_implTest.java
index 20f2c5f..98a1cb1 100644
--- a/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/AnalysisEngine_implTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/AnalysisEngine_implTest.java
@@ -60,6 +60,7 @@
 import org.apache.uima.cas.text.AnnotationIndex;
 import org.apache.uima.examples.SourceDocumentInformation;
 import org.apache.uima.jcas.JCas;
+import org.apache.uima.resource.RelativePathResolver;
 import org.apache.uima.resource.Resource;
 import org.apache.uima.resource.ResourceInitializationException;
 import org.apache.uima.resource.ResourceManager;
@@ -321,9 +322,15 @@
       ae.destroy();
 
       // descriptor with configuration parameter external overrides
-      // implicitly load settings values from the system property UimaExternalSettings
+      // implicitly load settings values from the 3 files in the system property UimaExternalOverrides
+      // Load 1st from filesystem, 2nd from classpath, and 3rd from datapath
+
       String resDir = "src/test/resources/TextAnalysisEngineImplTest/";
-      System.setProperty("UimaExternalOverrides", resDir+"testExternalOverride.settings,"+resDir+"testExternalOverride2.settings");
+      String prevDatapath = System.setProperty(RelativePathResolver.UIMA_DATAPATH_PROP, resDir);
+      System.setProperty("UimaExternalOverrides", 
+                      resDir+"testExternalOverride.settings," +
+                      "path:TextAnalysisEngineImplTest.testExternalOverride2," +
+                      "path:testExternalOverride4");
       in = new XMLInputSource(JUnitExtension.getFile("TextAnalysisEngineImplTest/AnnotatorWithExternalOverrides.xml"));
       desc = UIMAFramework.getXMLParser().parseAnalysisEngineDescription(in);
       ae1 = new PrimitiveAnalysisEngine_impl();
@@ -334,6 +341,7 @@
       String[] expect = { "Prefix", "-", "Suffix", "->", "Prefix-Suffix" };
       assertTrue(Arrays.equals(expect, arrayParam));
       Integer[] intArr = (Integer[]) ae1.getUimaContext().getConfigParameterValue("IntegerArrayParam");
+      assertNotNull(intArr);
       assertEquals(4, intArr.length);
       Integer[] intExpect = { 1, 22, 333, 4444 };
       assertTrue(Arrays.equals(intExpect, intArr));
@@ -342,6 +350,11 @@
       Integer intValue = (Integer) ae1.getUimaContext().getConfigParameterValue("IntegerParam");
       assertEquals(43,  intValue.intValue());  // Will be 42 if external override not defined
       System.clearProperty("UimaExternalOverrides");
+      if (prevDatapath == null) {
+        System.clearProperty(RelativePathResolver.UIMA_DATAPATH_PROP);
+      } else {
+        System.setProperty(RelativePathResolver.UIMA_DATAPATH_PROP, prevDatapath);
+      }
       
       ae1.destroy();
       
@@ -361,7 +374,7 @@
       System.clearProperty("UimaExternalOverrides");
       
       // Same aggregate with invalid syntax for an array in the external overrides file
-      System.setProperty("UimaExternalOverrides", resDir+"testExternalOverride3.settings");
+      System.setProperty("UimaExternalOverrides", "file:"+resDir+"testExternalOverride3.settings");
       try {
         UIMAFramework.produceAnalysisEngine(desc);
         fail(); // should not get here
@@ -414,7 +427,7 @@
     if (support240bug) {
       assertNotNull(desc);
     } else {
-      assertNotNull(ex);
+      fail();
     }
   }
 
@@ -1208,7 +1221,8 @@
           assertTrue(iter.hasNext());
           outCas = iter.next();
           fail(); // the above should throw an exception
-        } catch (AnalysisEngineProcessException e) {
+        } catch (Exception e) {
+        } finally {
           UIMAFramework.getLogger().setLevel(Level.INFO); // Restore to apparent default of INFO
         }
         //check that FlowController was notified twice, once for the 
@@ -1247,8 +1261,9 @@
           assertTrue(iter.hasNext());
           outCas = iter.next();
           fail(); // the above should throw an exception
-        } catch (AnalysisEngineProcessException e) {
-          UIMAFramework.getLogger().setLevel(Level.INFO); // Restore to apparent default of INFO
+        } catch (Exception e) {
+        } finally {
+          UIMAFramework.getLogger().setLevel(Level.INFO); 
         }
         //check that FlowController was notified three times, once for the 
         //segment's flow and twice for the complete document's flow (once
@@ -1293,7 +1308,8 @@
           assertTrue(iter.hasNext());
           outCas = iter.next();
           fail(); // the above should throw an exception
-        } catch (AnalysisEngineProcessException e) {
+        } catch (Exception e) {
+        } finally {
           UIMAFramework.getLogger().setLevel(Level.INFO); // Restore to apparent default of INFO
         }
         //check that FlowController was notified three times, once for each level of granularity
@@ -1323,7 +1339,8 @@
         UIMAFramework.getLogger().setLevel(Level.OFF);  // Suppress logging of expected exception
         iter.next();
         fail(); // should not get here
-      } catch (AnalysisEngineProcessException e) {
+      } catch (Exception e) {
+      } finally {
         UIMAFramework.getLogger().setLevel(Level.INFO); // Restore to apparent default of INFO
       }
       
@@ -1349,7 +1366,8 @@
           iter.next();
         }
         fail(); // should not get here
-      } catch (AnalysisEngineProcessException e) {
+      } catch (Exception e) {
+      } finally {
         UIMAFramework.getLogger().setLevel(Level.INFO); // Restore to apparent default of INFO
       }
       assertEquals(1, FlowControllerForErrorTest.abortedDocuments.size());
@@ -1375,8 +1393,11 @@
       //next call should not have aborted, but FC should have been notified of the failiure,
       // and no CAS should come back
       UIMAFramework.getLogger().setLevel(Level.OFF);  // Suppress logging of expected exception
-      assertFalse(iter.hasNext());
-      UIMAFramework.getLogger().setLevel(Level.INFO); // Restore to apparent default of INFO
+      try {
+        assertFalse(iter.hasNext());
+      } finally {
+        UIMAFramework.getLogger().setLevel(Level.INFO); // Restore to apparent default of INFO
+      }
       assertEquals(0, FlowControllerForErrorTest.abortedDocuments.size());
       assertEquals(1, FlowControllerForErrorTest.failedAEs.size());
       assertTrue(FlowControllerForErrorTest.failedAEs.contains("Segmenter"));
@@ -1495,8 +1516,8 @@
         UIMAFramework.getLogger().setLevel(Level.OFF);  // Suppress logging of expected exception
         ae.process(cas);
         fail();
-      }
-      catch(AnalysisEngineProcessException e) {
+      } catch (Exception e) {
+      } finally {
         UIMAFramework.getLogger().setLevel(Level.INFO); // Restore to apparent default of INFO
       }
       assertEquals(1, FlowControllerForErrorTest.abortedDocuments.size());
@@ -1518,8 +1539,11 @@
       cas.reset();
       cas.setDocumentText("ERROR");
       UIMAFramework.getLogger().setLevel(Level.OFF);  // Suppress logging of expected exception
-      ae.process(cas); //should not throw exception now
-      UIMAFramework.getLogger().setLevel(Level.INFO); // Restore to apparent default of INFO
+      try {
+        ae.process(cas); //should not throw exception now
+      } finally {
+        UIMAFramework.getLogger().setLevel(Level.INFO); // Restore to apparent default of INFO
+      }
       
       //document should not have aborted, but FC should have been notified of the failiure
       assertEquals(0, FlowControllerForErrorTest.abortedDocuments.size());
@@ -1531,6 +1555,59 @@
     }    
   }
   
+  public void testThrottleLogging() throws Exception {
+  //This test uses an aggregate AE fails if the document text is set to "ERROR".
+    AnalysisEngineDescription aeDesc = UIMAFramework.getXMLParser()
+            .parseAnalysisEngineDescription(
+                    new XMLInputSource(JUnitExtension.getFile("TextAnalysisEngineImplTest/AggregateForErrorTest.xml")));
+    AnalysisEngine ae = UIMAFramework.produceAnalysisEngine(aeDesc);
+    FlowControllerForErrorTest.reset();
+    CAS cas = ae.newCAS();
+    for (int i = 0; i < 2; i++) {
+      cas.setDocumentText("LOG");
+      try {
+        ae.process(cas);
+      }
+      catch(AnalysisEngineProcessException e) {
+        fail();
+      }
+      cas.reset();
+    }
+    System.err.println("should see 2 WARN loggings above");
+    
+    ae = UIMAFramework.produceAnalysisEngine(aeDesc, Collections.singletonMap(
+        AnalysisEngine.PARAM_THROTTLE_EXCESSIVE_ANNOTATOR_LOGGING, 1));
+    FlowControllerForErrorTest.reset();
+    cas = ae.newCAS();
+    for (int i = 0; i < 2; i++) {
+      cas.setDocumentText("LOG");
+      try {
+        ae.process(cas);
+      }
+      catch(AnalysisEngineProcessException e) {
+        fail();
+      }
+      cas.reset();
+    }
+    System.err.println("should see 1 WARN logging above");
+    
+    ae = UIMAFramework.produceAnalysisEngine(aeDesc, Collections.singletonMap(
+        AnalysisEngine.PARAM_THROTTLE_EXCESSIVE_ANNOTATOR_LOGGING, 0));
+    FlowControllerForErrorTest.reset();
+    cas = ae.newCAS();
+    for (int i = 0; i < 2; i++) {
+      cas.setDocumentText("LOG");
+      try {
+        ae.process(cas);
+      }
+      catch(AnalysisEngineProcessException e) {
+        fail();
+      }
+      cas.reset();
+    }
+    System.err.println("should see no logging above");
+  }
+  
   public void testMissingSuper() throws Exception {
     try {
       // initialize simple primitive TextAnalysisEngine
@@ -1548,9 +1625,11 @@
   public void testManyDelegates() throws Exception {
     // test with and without validation - UIMA-2453
     UIMAFramework.getXMLParser().enableSchemaValidation(true);
-    manyDelegatesCommon();
-    
-    UIMAFramework.getXMLParser().enableSchemaValidation(false);
+    try {
+      manyDelegatesCommon();
+    } finally {
+      UIMAFramework.getXMLParser().enableSchemaValidation(false);
+    }
     manyDelegatesCommon();
   }
   private void manyDelegatesCommon() throws Exception {
@@ -1644,47 +1723,52 @@
     AnalysisEngineDescription desc = UIMAFramework.getXMLParser().parseAnalysisEngineDescription(
             new XMLInputSource(JUnitExtension.getFile("TextAnalysisEngineImplTest/AggregateForMultipleAeTest.xml")));
     UIMAFramework.getLogger().setLevel(Level.CONFIG);
-    AnalysisEngine ae1 = UIMAFramework.produceAnalysisEngine(desc);
-    ae1.newCAS();
-    
-    // Creating a 2nd duplicate engine failed in 2.8.1 if the 2nd of the 2 typesystems imported
-    // is also contained in the 1st (UIMA-5058)
     try {
-      AnalysisEngineDescription desc2 = UIMAFramework.getXMLParser().parseAnalysisEngineDescription(
-              new XMLInputSource(JUnitExtension.getFile("TextAnalysisEngineImplTest/MultipleAeTest.xml")));
-      UIMAFramework.produceAnalysisEngine(desc2, ae1.getResourceManager(), null);
-    } catch (Exception e) {
-      JUnitExtension.handleException(e);
+      AnalysisEngine ae1 = UIMAFramework.produceAnalysisEngine(desc);
+      ae1.newCAS();
+      
+      // Creating a 2nd duplicate engine failed in 2.8.1 if the 2nd of the 2 typesystems imported
+      // is also contained in the 1st (UIMA-5058)
+      try {
+        AnalysisEngineDescription desc2 = UIMAFramework.getXMLParser().parseAnalysisEngineDescription(
+                new XMLInputSource(JUnitExtension.getFile("TextAnalysisEngineImplTest/MultipleAeTest.xml")));
+        UIMAFramework.produceAnalysisEngine(desc2, ae1.getResourceManager(), null);
+      } catch (Exception e) {
+        JUnitExtension.handleException(e);
+      }
+      
+      // Try creating one with at least one different type
+      try {
+        AnalysisEngineDescription desc2 = UIMAFramework.getXMLParser().parseAnalysisEngineDescription(
+                new XMLInputSource(JUnitExtension.getFile("TextAnalysisEngineImplTest/MultipleAeTest2.xml")));
+        UIMAFramework.produceAnalysisEngine(desc2, ae1.getResourceManager(), null);
+        fail();
+      } catch (Exception e) {
+        System.err.println("Expected exception: " + e);
+      }
+      
+      // Try creating one with different type-priorities
+      try {
+        AnalysisEngineDescription desc2 = UIMAFramework.getXMLParser().parseAnalysisEngineDescription(
+                new XMLInputSource(JUnitExtension.getFile("TextAnalysisEngineImplTest/MultipleAeTest3.xml")));
+        UIMAFramework.produceAnalysisEngine(desc2, ae1.getResourceManager(), null);
+        fail();
+      } catch (Exception e) {
+        System.err.println("Expected exception: " + e);
+      }
+      
+      // Try creating one with different indexes
+      try {
+        AnalysisEngineDescription desc2 = UIMAFramework.getXMLParser().parseAnalysisEngineDescription(
+                new XMLInputSource(JUnitExtension.getFile("TextAnalysisEngineImplTest/MultipleAeTest4.xml")));
+        UIMAFramework.produceAnalysisEngine(desc2, ae1.getResourceManager(), null);
+        fail();
+      } catch (Exception e) {
+        System.err.println("Expected exception: " + e);
+      }
+    } finally {
+      UIMAFramework.getLogger().setLevel(Level.INFO);    
     }
-    
-    // Try creating one with at least one different type
-    try {
-      AnalysisEngineDescription desc2 = UIMAFramework.getXMLParser().parseAnalysisEngineDescription(
-              new XMLInputSource(JUnitExtension.getFile("TextAnalysisEngineImplTest/MultipleAeTest2.xml")));
-      UIMAFramework.produceAnalysisEngine(desc2, ae1.getResourceManager(), null);
-      fail();
-    } catch (Exception e) {
-      System.err.println("Expected exception: " + e);
-    }
-    
-    // Try creating one with different type-priorities
-    try {
-      AnalysisEngineDescription desc2 = UIMAFramework.getXMLParser().parseAnalysisEngineDescription(
-              new XMLInputSource(JUnitExtension.getFile("TextAnalysisEngineImplTest/MultipleAeTest3.xml")));
-      UIMAFramework.produceAnalysisEngine(desc2, ae1.getResourceManager(), null);
-      fail();
-    } catch (Exception e) {
-      System.err.println("Expected exception: " + e);
-    }
-    
-    // Try creating one with different indexes
-    try {
-      AnalysisEngineDescription desc2 = UIMAFramework.getXMLParser().parseAnalysisEngineDescription(
-              new XMLInputSource(JUnitExtension.getFile("TextAnalysisEngineImplTest/MultipleAeTest4.xml")));
-      UIMAFramework.produceAnalysisEngine(desc2, ae1.getResourceManager(), null);
-      fail();
-    } catch (Exception e) {
-      System.err.println("Expected exception: " + e);
-    }
-  }
+  } 
+  
 }
diff --git a/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/ErrorAnnotator.java b/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/ErrorAnnotator.java
index d5f1d61..c1c79af 100644
--- a/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/ErrorAnnotator.java
+++ b/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/ErrorAnnotator.java
@@ -20,6 +20,7 @@
 package org.apache.uima.analysis_engine.impl;
 
 import org.apache.uima.analysis_engine.ResultSpecification;
+import org.apache.uima.analysis_engine.annotator.AnnotatorContextException;
 import org.apache.uima.analysis_engine.annotator.AnnotatorProcessException;
 import org.apache.uima.analysis_engine.annotator.Annotator_ImplBase;
 import org.apache.uima.analysis_engine.annotator.TextAnnotator;
@@ -37,5 +38,13 @@
     if ("ERROR".equals(aCAS.getDocumentText())) {
       throw new RuntimeException("Test Error");
     }
+    
+    if ("LOG".equals(aCAS.getDocumentText())) {
+      try {
+        getContext().getLogger().warn("Test Warn Log");
+      } catch (AnnotatorContextException e) {
+        throw new RuntimeException("Internal test failure");
+      }
+    }
   }
 }
diff --git a/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/ResultSpecTest.java b/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/ResultSpecTest.java
index 78c3fb9..81803ba 100644
--- a/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/ResultSpecTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/ResultSpecTest.java
@@ -30,6 +30,7 @@
 import org.apache.uima.cas.CAS;

 import org.apache.uima.cas.Feature;

 import org.apache.uima.cas.Type;

+import org.apache.uima.cas.TypeSystem;

 import org.apache.uima.cas.admin.CASFactory;

 import org.apache.uima.cas.admin.TypeSystemMgr;

 import org.apache.uima.test.junit_extension.JUnitExtension;

@@ -49,11 +50,12 @@
   

   // types

   

-  private static final TypeSystemMgr ts = CASFactory.createTypeSystem();

-  private static final Type t1 = ts.addType("T1", ts.getTopType());

-  private static final Feature f1 = ts.addFeature("F1", t1, t1);

-  private static final Feature f1a = ts.addFeature("F1a", t1, t1);

-  static {ts.commit();};

+  private static final TypeSystemMgr tsm = CASFactory.createTypeSystem();

+  private static final Type t1 = tsm.addType("T1", tsm.getTopType());

+  private static final Feature f1 = tsm.addFeature("F1", t1, t1);

+  private static final Feature f1a = tsm.addFeature("F1a", t1, t1);

+  private static final TypeSystem ts;

+  static {ts = tsm.commit();};

 

   /**

    * Tests for https://issues.apache.org/jira/browse/UIMA-1840

diff --git a/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/ResultSpecWithTypeSystemTest.java b/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/ResultSpecWithTypeSystemTest.java
index 6d030b4..95e0253 100644
--- a/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/ResultSpecWithTypeSystemTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/ResultSpecWithTypeSystemTest.java
@@ -47,16 +47,17 @@
 	

 	// types

   

-  private static final TypeSystemMgr ts = CASFactory.createTypeSystem();

-  private static final Type t1 = ts.addType("T1", ts.getTopType());

-  private static final Type t2 = ts.addType("T2", t1);

-  private static final Type t3 = ts.addType("T3", t2);

-  private static final Type t4 = ts.addType("T4", t1);  // doesn't inherit from t2

-  private static final Feature f1 = ts.addFeature("F1", t1, t1);

-  private static final Feature f2 = ts.addFeature("F2", t2, t3);

-  private static final Feature f3 = ts.addFeature("F3", t3, t3);

-  private static final Feature f4 = ts.addFeature("F4", t4, t4);

-  static {ts.commit();};

+  private static final TypeSystemMgr tsm = CASFactory.createTypeSystem();

+  private static final Type t1 = tsm.addType("T1", tsm.getTopType());

+  private static final Type t2 = tsm.addType("T2", t1);

+  private static final Type t3 = tsm.addType("T3", t2);

+  private static final Type t4 = tsm.addType("T4", t1);  // doesn't inherit from t2

+  private static final Feature f1 = tsm.addFeature("F1", t1, t1);

+  private static final Feature f2 = tsm.addFeature("F2", t2, t3);

+  private static final Feature f3 = tsm.addFeature("F3", t3, t3);

+  private static final Feature f4 = tsm.addFeature("F4", t4, t4);

+  private static final TypeSystem ts;

+  static {ts = tsm.commit();};

   

   // TypeOrFeature instances

   private static TypeOrFeature makeTof(String name, boolean isType, boolean allFeats) {

diff --git a/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/TestAnnotator2.java b/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/TestAnnotator2.java
index 7561ffb..9135893 100644
--- a/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/TestAnnotator2.java
+++ b/uimaj-core/src/test/java/org/apache/uima/analysis_engine/impl/TestAnnotator2.java
@@ -20,22 +20,29 @@
 package org.apache.uima.analysis_engine.impl;
 
 import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.uima.UIMAFramework;
 import org.apache.uima.UimaContext;
 import org.apache.uima.UimaContextHolder;
 import org.apache.uima.analysis_component.CasAnnotator_ImplBase;
+import org.apache.uima.analysis_engine.AnalysisEngineDescription;
 import org.apache.uima.analysis_engine.ResultSpecification;
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.TypeSystem;
 import org.apache.uima.impl.UimaContext_ImplBase;
+import org.apache.uima.resource.Resource;
 import org.apache.uima.resource.ResourceConfigurationException;
 import org.apache.uima.resource.ResourceInitializationException;
+import org.apache.uima.test.junit_extension.JUnitExtension;
 import org.apache.uima.util.Settings;
 import org.apache.uima.util.UimaContextHolderTest;
-
+import org.apache.uima.util.XMLInputSource;
 import org.junit.Assert;
 
 /**
@@ -71,7 +78,7 @@
     // Note: this annotator launched with external overrides loaded from testExternalOverride2.settings 
     String contextName = ((UimaContext_ImplBase) aContext).getQualifiedContextName();
     if ("/ExternalOverrides/".equals(contextName)) {
-      String expected = "Context Holder Test";
+      // Test getting a (0-length) array of strings
       String[] actuals = null;
       try {
         actuals = UimaContextHolder.getContext().getSharedSettingArray("test.externalFloatArray");
@@ -80,17 +87,8 @@
       }
       Assert.assertEquals(0, actuals.length);
       
-      // prefix-suffix     Prefix-${suffix}
-      // suffix = should be ignored
-      String actual = null;
-      try {
-        actual = UimaContextHolder.getContext().getSharedSettingValue("context-holder");
-      } catch (ResourceConfigurationException e) {
-        Assert.fail(e.getMessage());
-      }
-      Assert.assertEquals(expected, actual);
-      
       // Test assigning an array to a string and vice-versa
+      String actual = null;
       try {
         actual = UimaContextHolder.getContext().getSharedSettingValue("test.externalFloatArray");
         Assert.fail("\"bad\" should create an error");
@@ -106,7 +104,12 @@
 
       // Test a stand-alone settings object
       Settings testSettings = UIMAFramework.getResourceSpecifierFactory().createSettings();
-      String lines = "foo = ${bar} \n bar : [ok \n OK] \n bad = ${missing}";
+      String lines = "foo = ${bar} \n" +
+                "bar : [ok \n OK] \n" +
+                "bad = ${missing} \n" +
+                "loop1 = one ${loop2} \n" +
+                "loop2 = two ${loop3} \n" +
+                "loop3 = three ${loop1} \n" ;
       InputStream is;
       try {
         is = new ByteArrayInputStream(lines.getBytes("UTF-8"));
@@ -120,11 +123,18 @@
         } catch (ResourceConfigurationException e) {
           System.err.println("Expected exception: " + e.toString());
         }
+        try {
+          val = testSettings.lookUp("loop2");
+          Assert.fail("\"loop2\" should create an error");
+        } catch (ResourceConfigurationException e) {
+          System.err.println("Expected exception: " + e.toString());
+        }
       } catch (Exception e) {
         Assert.fail(e.toString());
       }
       
       // Test POFO access via UimaContextHolder
+      String expected = "Context Holder Test";
       long threadId = Thread.currentThread().getId();
       UimaContextHolderTest testPojoAccess = new UimaContextHolderTest();
       try {
@@ -161,6 +171,39 @@
         Assert.fail();
       }
       
+      
+      // Test getting a string value
+      try {
+        actual = UimaContextHolder.getContext().getSharedSettingValue("context-holder");
+      } catch (ResourceConfigurationException e) {
+        Assert.fail(e.getMessage());
+      }
+      Assert.assertEquals(expected, actual);
+      
+      // Create a nested engine with a different settings
+      String resDir = "src/test/resources/TextAnalysisEngineImplTest/";
+      try {
+        //XMLInputSource in = new XMLInputSource(JUnitExtension.getFile("TextAnalysisEngineImplTest/AnnotatorWithExternalOverrides.xml"));
+        XMLInputSource in = new XMLInputSource(new File(resDir, "AnnotatorWithExternalOverrides.xml"));
+        AnalysisEngineDescription desc = UIMAFramework.getXMLParser().parseAnalysisEngineDescription(in);
+        Map<String, Object> additionalParams = new HashMap<String, Object>();
+        Settings extSettings = UIMAFramework.getResourceSpecifierFactory().createSettings();
+        FileInputStream fis = new FileInputStream(new File(resDir, "testExternalOverride2.settings"));
+        extSettings.load(fis);
+        fis.close();
+        additionalParams.put(Resource.PARAM_EXTERNAL_OVERRIDE_SETTINGS, extSettings);
+        UIMAFramework.produceAnalysisEngine(desc, additionalParams);
+      } catch (Exception e) {
+        Assert.fail();
+      }
+      
+      try {
+        actual = UimaContextHolder.getContext().getSharedSettingValue("context-holder");
+      } catch (ResourceConfigurationException e) {
+        Assert.fail(e.getMessage());
+      }
+      Assert.assertEquals(expected, actual);
+
     }
     // Used to check initialization order by testManyDelegates
     allContexts  = allContexts + contextName.substring(1);
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/impl/Id2FSTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/impl/Id2FSTest.java
index d634efe..9a3984b 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/impl/Id2FSTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/impl/Id2FSTest.java
@@ -45,14 +45,14 @@
   public void testId2fs() throws InterruptedException {

     

     TOP fs1 = new TOP(jcas);

-    cas.setId2FSs(fs1);

+    cas.setId2FSsMaybeUnconditionally(fs1);

 

     int lastUsedId = fs1._id();

     assertEquals(fs1, cas.<TOP>getFsFromId(lastUsedId));

     // make 20 more that could be gc'd

     

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

-      cas.setId2FSs(new TOP(jcas));

+      cas.setId2FSsMaybeUnconditionally(new TOP(jcas));

     }

    

     // verify they can be found by id #

@@ -83,13 +83,13 @@
     

     cas.reset();

     fs1 = new TOP(jcas);

-    cas.setId2FSs(fs1);

+    cas.setId2FSsMaybeUnconditionally(fs1);

        

     lastUsedId = fs1._id();

     assertEquals(fs1, cas.getFsFromId(lastUsedId));

     

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

-      cas.setId2FSs(new TOP(jcas));

+      cas.setId2FSsMaybeUnconditionally(new TOP(jcas));

     }

     // verify they can be found by id #

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

diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/impl/JCasReinitTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/impl/JCasReinitTest.java
new file mode 100644
index 0000000..9061036
--- /dev/null
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/impl/JCasReinitTest.java
@@ -0,0 +1,95 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+package org.apache.uima.cas.impl;

+

+import java.io.File;

+import java.io.IOException;

+

+import org.apache.uima.UIMAFramework;

+import org.apache.uima.resource.metadata.TypeSystemDescription;

+import org.apache.uima.resource.metadata.impl.TypePriorities_impl;

+import org.apache.uima.test.junit_extension.JUnitExtension;

+import org.apache.uima.util.CasCreationUtils;

+import org.apache.uima.util.InvalidXMLException;

+import org.apache.uima.util.XMLInputSource;

+

+import aa.T;

+import junit.framework.TestCase;

+

+public class JCasReinitTest extends TestCase {

+

+  private TypeSystemDescription typeSystemDescription;

+

+  private CASImpl cas_no_features;

+  private CASImpl cas;

+

+  public void setup() throws Exception {

+   }

+  

+  /**

+   * Make a type system having type T with a features f1

+   * Make a type system having type T with no features

+   * 

+   * Have a JCas class for that type, with f1 defined

+   * 

+   * Create a Cas with a type system with the T(no features)

+   * 

+   * confirm that the JCas class getter for f1 offset returns -1

+   * 

+   * Create a Cas with a type system with the T(with f1)

+   * 

+   * confirm that the JCas class getter for f1 offset returns 0 

+   * @throws Throwable 

+   */

+

+  

+  public void testReinit() throws Throwable {

+    File typeSystemFile1;

+    

+//    // 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_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));

+   

+    cas = (CASImpl) CasCreationUtils.createCas(typeSystemDescription, new TypePriorities_impl(), null);

+    

+    T.dumpOffset();

+

+

+

+   

+  }

+

+}

diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/impl/OrderedFsSet_array_test.java b/uimaj-core/src/test/java/org/apache/uima/cas/impl/OrderedFsSet_array_test.java
new file mode 100644
index 0000000..c1d6956
--- /dev/null
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/impl/OrderedFsSet_array_test.java
@@ -0,0 +1,220 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.cas.impl;

+

+import java.io.File;

+import java.util.ArrayList;

+import java.util.Arrays;

+import java.util.Collections;

+import java.util.Comparator;

+import java.util.List;

+import java.util.Random;

+

+import org.apache.uima.UIMAFramework;

+import org.apache.uima.cas.FSIndex;

+import org.apache.uima.cas.FSIndexRepository;

+import org.apache.uima.cas.FSIterator;

+import org.apache.uima.cas.TypeSystem;

+import org.apache.uima.cas.admin.FSIndexComparator;

+import org.apache.uima.internal.util.Misc;

+import org.apache.uima.internal.util.OrderedFsSet_array;

+import org.apache.uima.jcas.JCas;

+import org.apache.uima.jcas.cas.TOP;

+import org.apache.uima.jcas.tcas.Annotation;

+import org.apache.uima.resource.metadata.FsIndexDescription;

+import org.apache.uima.resource.metadata.TypeSystemDescription;

+import org.apache.uima.resource.metadata.impl.TypePriorities_impl;

+import org.apache.uima.test.junit_extension.JUnitExtension;

+import org.apache.uima.util.CasCreationUtils;

+import org.apache.uima.util.XMLInputSource;

+

+import junit.framework.TestCase;

+

+public class OrderedFsSet_array_test extends TestCase {

+

+  static File typeSystemFile1 = JUnitExtension.getFile("ExampleCas/testTypeSystem.xml");

+  static int SZ = 23;

+  

+  static final Random r = new Random();

+  static long seed =  r.nextLong();

+ //     -4709156741850323232L;

+                     // 1783099358091571349L;

+  static {

+    r.setSeed(seed);

+    System.out.println("OrderedFsSet_array_test random seed: " + seed);

+  }

+    

+  CASImpl cas;

+  JCas jcas;

+  FSIndexRepositoryImpl ir;

+  private Comparator<TOP> comparatorWithID;

+  private Comparator<TOP> comparatorWithoutID;

+  private Annotation[] as = new Annotation[Integer.highestOneBit(SZ) << 1];

+  

+  private OrderedFsSet_array<TOP> a;   

+  

+  protected void setUp() throws Exception {

+    

+    TypeSystemDescription typeSystemDescription = UIMAFramework.getXMLParser().parseTypeSystemDescription(

+        new XMLInputSource(typeSystemFile1));

+    

+    cas = (CASImpl) CasCreationUtils.createCas(typeSystemDescription, new TypePriorities_impl(), null);

+    jcas = cas.getJCas();

+    ir = (FSIndexRepositoryImpl) cas.getIndexRepository();

+    comparatorWithID = ir.getAnnotationFsComparatorWithId(); 

+    comparatorWithoutID = ir.getAnnotationFsComparatorWithoutId();

+    a = new OrderedFsSet_array(comparatorWithID, comparatorWithoutID);

+    

+  }

+  

+  /**

+   * work with 16-32 elements

+   * 

+   * Do a lot of inserts / removes in patterns:

+   *   remove n, insert n in random order

+   * 

+   */

+  public void testInsert() {

+    int i = 0;

+//    for (; i < 100; i++) {  //enable for lots of iterationss, disable for normal test case

+      seed = r.nextLong();

+      r.setSeed(seed);

+      System.out.println("OrderedFsSet_array_test i: " + i + ", seed: " + seed);

+      insert1(i);

+//    }

+  }

+  

+  private void insert1(int iter) {    

+    

+    //prefill

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

+      as[i] = new Annotation(jcas, i, i + 200);

+    }

+    a = new OrderedFsSet_array(comparatorWithID, comparatorWithoutID);

+    

+    add(3, SZ);    

+    a.size();

+    

+    add(0, 3);

+    

+    a.size();  // force batch add

+        

+    rr(0, 3);

+    rr(1, 3);

+        

+    for (int i = 0; i < 100_000; i++) {

+      removeAndReinsertRandom(i);

+//      if ((i % 100000) == 0) {

+//        System.out.println("random testing OrderedFsSet_array, count: " + i);

+//      }

+    }

+

+  }

+  

+  private void add(int ... is) {

+    for (int i : is) {

+      a.add(as[i], comparatorWithID);

+    }

+  }

+  

+  private void add(int start, int end) {

+    for (int i = start; i < end; i++) {

+      a.add(as[i], comparatorWithID);

+    }

+  }

+  

+  private void rmv(int ... is) {

+    for (int i : is) {

+      a.remove(as[i]);

+    }

+  }

+  

+  private void rmv(int start, int end) {

+    for (int i = start; i < end; i++) {

+      a.remove(as[i]);

+    }

+  }

+

+  //debug 87  

+  private void removeAndReinsertRandom(int iteration) {

+    int n_remove = r.nextInt(SZ);

+    if (n_remove == 0) return; 

+//    System.out.println(n_remove);

+    int[] rmvd_i = r.ints(0, SZ - 1).distinct().limit(n_remove).toArray();

+    int[] adds_i = shuffle(rmvd_i);

+//    if (iteration == 12685) {

+//      System.out.println("debug 12685");

+//    }

+    rr(rmvd_i, adds_i);

+  }

+  

+  private void vall() {

+    int i = 0;

+    for (TOP fs : a) {

+      assertTrue(as[i++] == fs);

+//      if (fs != as[i++]) {

+//        System.out.println("debug mismatch");

+//      }

+    }

+//    TOP[] cc = a.getInternalArrayDebug();

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

+//      if (cc[i] == null) {

+//        System.out.println("debug found null");

+//      }

+//    }    

+  }

+  

+  private void rr(int start, int end) {

+    rmv(start, end);

+    add(start, end);

+    a.size();

+    vall();

+  }

+  

+  private void rr(int[] rmv, int[] add) {

+    for (int i : rmv) {

+      a.remove(as[i]);

+    }

+    int splt = r.nextInt(add.length) + 1;

+    

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

+      a.add(as[add[i]], comparatorWithID);

+    }

+    a.size(); 

+    

+    for (int i = splt; i < add.length; i++) {

+      a.add(as[add[i]], comparatorWithID);

+    }

+    a.size();

+    

+    vall();

+  }

+  

+  private int[] shuffle(int[] a) {

+    int[] b = a.clone();

+    for (int i = 0; i < b.length; i++) {

+      int j = r.nextInt(b.length);  

+      int tmp = b[i];

+      b[i] = b[j];

+      b[j] = tmp;

+    }

+    return b;

+  }

+}

diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/impl/SerDesTest4.java b/uimaj-core/src/test/java/org/apache/uima/cas/impl/SerDesTest4.java
index 7c54657..e4eea66 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/impl/SerDesTest4.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/impl/SerDesTest4.java
@@ -60,6 +60,7 @@
 import org.apache.uima.cas.test.CASInitializer;
 import org.apache.uima.internal.util.IntVector;
 import org.apache.uima.jcas.cas.TOP;
+import org.apache.uima.util.AutoCloseableNoException;
 import org.apache.uima.util.CasCreationUtils;
 import org.apache.uima.util.impl.SerializationMeasures;
 
@@ -211,7 +212,7 @@
       akofAstring = tsm.addFeature("akofAstring", akof, typeArrayString);
     }
 
-    public void initIndexes(FSIndexRepositoryMgr irm, TypeSystem ts) {
+    public void initIndexes(FSIndexRepositoryMgr irm, TypeSystem typeSystem) {
     }
 
     void reinitTypeSystem(TypeSystemImpl tsm) {
@@ -275,7 +276,7 @@
 
     try {
       CASTestSetup cts = new CASTestSetup();
-      this.cas = (CASImpl) CASInitializer.initCas(cts, ts -> cts.reinitTypeSystem(ts));
+      this.cas = (CASImpl) CASInitializer.initCas(cts, t -> cts.reinitTypeSystem(t));
       this.ts = (TypeSystemImpl) this.cas.getTypeSystem();
       this.cas2 = (CASImpl) CasCreationUtils.createCas(ts, null, null, null);
       deserCas = (CASImpl) CasCreationUtils.createCas(ts, null, null, null);
@@ -302,7 +303,22 @@
 
   public void testAllKinds() {
     loadCas(lfs);
-    verify("AllKinds");
+    // uncomment this to test toString()
+//    int i = 0;
+//    for (TOP item : cas.getIndexRepository().getAllIndexedFS(TOP.class)) {
+//      System.out.println(Integer.toString(i++) + ": " + item.toString());
+//    }
+    verify("AllKinds");   
+  }
+  
+  public void testAllKindsV2() {
+    try (AutoCloseableNoException a = cas.ll_enableV2IdRefs();
+         AutoCloseableNoException b = deserCas.ll_enableV2IdRefs()) {
+      loadCas(lfs);
+      int id = newAkof(lfs)._id();  // an unreachable fs
+      verify("AllKindsV2");
+      assertEquals(id, deserCas.getLowLevelCAS().ll_getFSForRef(id)._id());
+    }
   }
 
   /**
@@ -336,7 +352,7 @@
     FeatureStructure fs = createFS(cas, akof);
     if (includeUid) fs.setIntValue(akofUid, aint.getAndAdd(1));
     fs.setFeatureValue(akofFs, lfs2.get(0));
-    ArrayFS fsafs = createArrayFS(cas, 4);
+    ArrayFS<FeatureStructure> fsafs = createArrayFS(cas, 4);
     fsafs.set(1, lfs2.get(1));
     fsafs.set(2, lfs2.get(2));
     fsafs.set(3, lfs2.get(3));
@@ -429,7 +445,7 @@
     
     // debug compare before mark
 //    BinaryCasSerDes4 bcs = new BinaryCasSerDes4(ts, false);
-//    assertTrue(bcs.getCasCompare().compareCASes(cas, cas2));
+//    assertTrue(CasCompare.compareCASes(cas, cas2));
     
     marker = (MarkerImpl) cas.createMarker();
 
@@ -1028,7 +1044,7 @@
         bais = new ByteArrayInputStream(readIn(fname));
       }
       deserCas.getBinaryCasSerDes().reinit(bais);
-      assertTrue(bcs.getCasCompare().compareCASes(cas, deserCas));
+      assertTrue(CasCompare.compareCASes(cas, deserCas));
     } catch (IOException e) {
       throw new RuntimeException(e);
     }
@@ -1073,7 +1089,7 @@
 
       BinaryCasSerDes bcsd_cas1 = cas.getBinaryCasSerDes();
       bcsd_cas1.reinit(bais);
-      assertTrue(bcs.getCasCompare().compareCASes(cas, cas2));
+      assertTrue(CasCompare.compareCASes(cas, cas2));
 
       // verify indexed fs same; the order may be different so sort first
       // currently seems broken... not comparing anything of use
@@ -1124,7 +1140,7 @@
       
       BinaryCasSerDes bcsd_cas2 = cas2.getBinaryCasSerDes();
       bcsd_cas2.reinit(bais);
-      assertTrue(bcs.getCasCompare().compareCASes(cas, cas2));
+      assertTrue(CasCompare.compareCASes(cas, cas2));
 
       // verify indexed fs same; the order may be different so sort first
       // currently seems broken... not comparing anything of use
@@ -1199,7 +1215,7 @@
   //
   // BinaryCasSerDes bcsd_deltaCas = deltaCas.getBinaryCasSerDes();
   // bcsd_deltaCas.reinit(bais);
-  // assertTrue(bcs.getCasCompare().compareCASes(cas, deltaCas));
+  // assertTrue(CasCompare.compareCASes(cas, deltaCas));
   //
   // // verify indexed fs same; the order may be different so sort first
   //
@@ -1359,40 +1375,40 @@
     return ((CASImpl)cas).createArray((TypeImpl)type, length);
   }
   
-  private ArrayFS createArrayFS(CAS cas, int length) {
-    return (ArrayFS) createArray(cas, ((CASImpl)cas).getTypeSystemImpl().fsArrayType, length);
+  private ArrayFS<FeatureStructure> createArrayFS(CAS c, int length) {
+    return (ArrayFS<FeatureStructure>) createArray(c, ((CASImpl)c).getTypeSystemImpl().fsArrayType, length);
   }
   
-  private StringArrayFS createStringArrayFS(CAS cas, int length) {
-    return (StringArrayFS) createArray(cas, ((CASImpl)cas).getTypeSystemImpl().stringArrayType, length);    
+  private StringArrayFS createStringArrayFS(CAS c, int length) {
+    return (StringArrayFS) createArray(c, ((CASImpl)c).getTypeSystemImpl().stringArrayType, length);    
   }
   
-  private IntArrayFS createIntArrayFS(CAS cas, int length) {
-    return (IntArrayFS) createArray(cas, ((CASImpl)cas).getTypeSystemImpl().intArrayType, length);    
+  private IntArrayFS createIntArrayFS(CAS c, int length) {
+    return (IntArrayFS) createArray(c, ((CASImpl)c).getTypeSystemImpl().intArrayType, length);    
   }
 
-  private FloatArrayFS createFloatArrayFS(CAS cas, int length) {
-    return (FloatArrayFS) createArray(cas, ((CASImpl)cas).getTypeSystemImpl().floatArrayType, length);    
+  private FloatArrayFS createFloatArrayFS(CAS c, int length) {
+    return (FloatArrayFS) createArray(c, ((CASImpl)c).getTypeSystemImpl().floatArrayType, length);    
   }
 
-  private DoubleArrayFS createDoubleArrayFS(CAS cas, int length) {
-    return (DoubleArrayFS) createArray(cas, ((CASImpl)cas).getTypeSystemImpl().doubleArrayType, length);    
+  private DoubleArrayFS createDoubleArrayFS(CAS c, int length) {
+    return (DoubleArrayFS) createArray(c, ((CASImpl)c).getTypeSystemImpl().doubleArrayType, length);    
   }
 
-  private LongArrayFS createLongArrayFS(CAS cas, int length) {
-    return (LongArrayFS) createArray(cas, ((CASImpl)cas).getTypeSystemImpl().longArrayType, length);    
+  private LongArrayFS createLongArrayFS(CAS c, int length) {
+    return (LongArrayFS) createArray(c, ((CASImpl)c).getTypeSystemImpl().longArrayType, length);    
   }
 
-  private ShortArrayFS createShortArrayFS(CAS cas, int length) {
-    return (ShortArrayFS) createArray(cas, ((CASImpl)cas).getTypeSystemImpl().shortArrayType, length);    
+  private ShortArrayFS createShortArrayFS(CAS c, int length) {
+    return (ShortArrayFS) createArray(c, ((CASImpl)c).getTypeSystemImpl().shortArrayType, length);    
   }
 
-  private ByteArrayFS createByteArrayFS(CAS cas, int length) {
-    return (ByteArrayFS) createArray(cas, ((CASImpl)cas).getTypeSystemImpl().byteArrayType, length);    
+  private ByteArrayFS createByteArrayFS(CAS c, int length) {
+    return (ByteArrayFS) createArray(c, ((CASImpl)c).getTypeSystemImpl().byteArrayType, length);    
   }
   
-  private BooleanArrayFS createBooleanArrayFS(CAS cas, int length) {
-    return (BooleanArrayFS) createArray(cas, ((CASImpl)cas).getTypeSystemImpl().booleanArrayType, length);    
+  private BooleanArrayFS createBooleanArrayFS(CAS c, int length) {
+    return (BooleanArrayFS) createArray(c, ((CASImpl)c).getTypeSystemImpl().booleanArrayType, length);    
   }
 
   @Override
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/impl/SerDesTest6.java b/uimaj-core/src/test/java/org/apache/uima/cas/impl/SerDesTest6.java
index 526dd18..b650ac7 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/impl/SerDesTest6.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/impl/SerDesTest6.java
@@ -32,6 +32,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -61,6 +62,7 @@
 import org.apache.uima.jcas.cas.TOP;
 import org.apache.uima.resource.ResourceInitializationException;
 import org.apache.uima.resource.metadata.TypeSystemDescription;
+import org.apache.uima.util.AutoCloseableNoException;
 import org.apache.uima.util.CasCreationUtils;
 import org.apache.uima.util.impl.SerializationMeasures;
 
@@ -73,10 +75,21 @@
  */
 public class SerDesTest6 extends SerDesTstCommon {
 
+  /**
+   * TwoType, EqTwoTypes, TwoTypesSubsetFeatures, TwoTypesNoFeatures have Akof1 and Akof2
+   *   
+   *
+   */
   enum TypeSystems {
-    TwoTypes, EqTwoTypes, OneType, TwoTypesSubsetFeatures, OneTypeSubsetFeatures, TwoTypesNoFeatures,
+    TwoTypes,    // two types, Akof1 Akof2, with all features, one type system
+    EqTwoTypes,  // two typesystems, made up of a copy of TwoTypes
+    OneType,     // one type, all features
+    TwoTypesSubsetFeatures, // two types, but has only a subset of the features
+    OneTypeSubsetFeatures,  // one type, but has a subset of features
+    TwoTypesNoFeatures,     // two types, no features
   }
 
+  /** the two types Akof1 and Akof2 */
   enum Types {
     Akof1, Akof2,
   }
@@ -96,7 +109,7 @@
 
     public TTypeSystem   m;
     public TypeSystemMgr tsm;
-    final TypeSystems    kind;
+    final TypeSystems    kind; // enum TwoTypes, EqTwoTypes, OneType, TwoTypesSubsetFeatures, OneTypeSubsetFeatures, TwoTypesNoFeatures
 
     public CASTestSetup(TypeSystems kind) {
       this.kind = kind;
@@ -169,14 +182,19 @@
     public void initIndexes(FSIndexRepositoryMgr irm, TypeSystem ts) {
     }
   }
+  
+  /** list of all feature value kinds e.g. Int, Fs, Float, Afloat, Astring */
   static final List<String> featureNameRoots = Arrays.asList(new String[] { 
     "Int", "Fs", "Float", "Double", "Long", "Short", "Byte", "Boolean", "String", 
           "Aint", "Afs", "Afloat", "Adouble", "Along", "Ashort", "Abyte", "Aboolean", "Astring" });
-
+  
+  /** have 2 instances of this, one per type system */
   static class TTypeSystem {
-    final TypeSystems     kind;
+    final TypeSystems     kind; // enum TwoTypes, EqTwoTypes, OneType, TwoTypesSubsetFeatures, OneTypeSubsetFeatures, TwoTypesNoFeatures,
     TypeSystemMgr tsm;
+    /** table, by two types, then sparse table, each slot not empty is a feature indexed by corresponding featureNameRoots */
     Feature[][] featureTable = new Feature[Types.values().length][featureNameRoots.size()];
+    /** short-name to types map: e.g. Aint -> array of int  */
     Map<String, Type>     mapString2Type      = new HashMap<String, Type>();
     public TypeSystemImpl ts;
     public CASImpl cas;  // the Cas setup as part of initialization                                                                    // the
@@ -188,37 +206,45 @@
       this.ts = (TypeSystemImpl) tsm;
     }
 
+    /** add existing type by short name to the map, e.g. Aint -> array of int */
     void addType(Type type, String shortName) {
       mapString2Type.put(shortName, type);
     }
 
+    /** add new type with super type */
     void addType(String type, String superType) {
       addType(tsm.addType(type, getType(superType)), type);
     }
 
+    /** get type by short name */
     Type getType(String shortName) {
       return mapString2Type.get(shortName);
     }
 
+    /** get type by enum Akof1, Akof2 */
     Type getType(Types type) {
       return getType(type.name());
     }
 
+    /** add feature to type, feat = one of feature value kinds e.g. Int, Fs, Float, Afloat, Astring */
     void add(Type type, String featNameRoot) {
       String typeName = type.getShortName();
       int i2 = featureNameRoots.indexOf(featNameRoot);
       featureTable[Types.valueOf(typeName).ordinal()][i2] = tsm.addFeature(typeName + featNameRoot,
           type, mapString2Type.get(featNameRoot));
     }
-
+    
+    /** add feature to type, arg1 is enum, feat = one of feature value kinds e.g. Int, Fs, Float, Afloat, Astring */
     void add(Types typeKind, String featNameRoot) {
       add(getType(typeKind.name()), featNameRoot);
     }
 
+    /** get feature for type by typeEnum + one of feature value kinds: Int, Fs, Float, Afloat, Astring */
     Feature getFeature(Types typeKind, String featNameRoot) {
       return featureTable[typeKind.ordinal()][featureNameRoots.indexOf(featNameRoot)];
     }
 
+    /** get feature for type of FS, + one of feature value kinds: Int, Fs, Float, Afloat, Astring */
     Feature getFeature(FeatureStructure fs, String featNameRoot) {
       Type t = fs.getType();
       return getFeature(Types.valueOf(t.getShortName()), featNameRoot);
@@ -374,6 +400,13 @@
       }
     }
   }
+  
+  public void testAllKindsV2() {
+    try (AutoCloseableNoException a = LowLevelCAS.ll_defaultV2IdRefs();
+         AutoCloseableNoException b = casSrc.ll_enableV2IdRefs()) { // because casSrc set in setup
+      testAllKinds();
+    }
+  }
 
   // Test chains going through filtered type
   // Repeat below with OneType, and TwoTypes with filtered slot == fsRef
@@ -741,6 +774,20 @@
 
   }
 
+  // change tst to test to run this as a looper to catch infrequent errors
+  public void tstLoop() {
+    Random seeder = new Random();
+    for (int i = 0; i < 800; i++) {
+      long seed = seeder.nextLong();
+//          -670766016644278339L;  20, 33 IntegerArray miscompare
+//      -5294919707375572185L;   -28, 33  IntegerArray miscompare
+//      7169526779687013172L;   // ref miscompare
+      System.out.println("i: " + i + "  seed: " + seed);
+      random.setSeed(seed);
+      runCaptureSet();
+    }
+  }
+  
   public void captureGenerated() {
     capture = true;
     initWriteSavedInts();
@@ -1366,6 +1413,14 @@
   }
 
   // casSrc -> remoteCas
+  /**
+   * 
+   * @param casSrc -
+   * @param casTgt -
+   * @param ri -
+   * @param mark -
+   * @return [0] is serialize reuse info, [1] is deserialize reuse info
+   */
   private ReuseInfo[] serializeDeserialize(CASImpl casSrc, CASImpl casTgt, ReuseInfo ri,
       MarkerImpl mark) {
     ReuseInfo[] riToReturn = new ReuseInfo[2];
@@ -1554,10 +1609,10 @@
   }
 
   private List<FeatureStructure> getIndexedFSs(CASImpl cas, TTypeSystem m) {
-    FSIterator<FeatureStructure> it = cas.getIndexRepository().getAllIndexedFS(m.getType(Akof1));
+    Collection<TOP> c = cas.getIndexRepository().getIndexedFSs(m.getType(Akof1));
     List<FeatureStructure> lfs = new ArrayList<FeatureStructure>();
-    while (it.hasNext()) {
-      lfs.add(it.next());
+    for (TOP fs : c) {
+      lfs.add(fs);
     }
     return lfs;
   }
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/impl/SerDesTstCommon.java b/uimaj-core/src/test/java/org/apache/uima/cas/impl/SerDesTstCommon.java
index 93b632b..ac16187 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/impl/SerDesTstCommon.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/impl/SerDesTstCommon.java
@@ -121,9 +121,11 @@
   private final Random randomseed = new Random();

   

   { long seed = randomseed.nextLong();

+    //  8798009300995058889L;

     // long seed = 1_449_257_605_347_913_923L;   // to set a specific seed

+//    seed = 2_505_546_892_701_000_347L;

     randomseed.setSeed(seed);  

-    System.out.format("SerDesTstCommon Initial RandomSeed: %,d%n", seed);

+    System.out.format("SerDesTstCommon Initial RandomSeed: %d%n", seed);

   }

   

   /**

@@ -187,7 +189,7 @@
       dir.mkdirs();

     }

     

-    System.out.println("debug out file name is " + fname);  

+//    System.out.println("debug out file name is " + fname);  

     

 

     return

diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/impl/UnambiguousIteratorTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/impl/UnambiguousIteratorTest.java
index 1062a73..5a80783 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/impl/UnambiguousIteratorTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/impl/UnambiguousIteratorTest.java
@@ -124,7 +124,7 @@
     for (it.moveToFirst(); it.isValid(); it.moveToNext()) {
       ++size;
     }
-    assertEquals(size, it.ll_indexSize());
+    assertEquals(size, it.ll_indexSizeMaybeNotCurrent());
     return size;
   }
 
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/impl/XCASDeserializerTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/impl/XCASDeserializerTest.java
index 3a80c9d..39a31b5 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/impl/XCASDeserializerTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/impl/XCASDeserializerTest.java
@@ -39,18 +39,20 @@
 import org.apache.uima.cas.IntArrayFS;
 import org.apache.uima.cas.StringArrayFS;
 import org.apache.uima.cas.Type;
+import org.apache.uima.cas_data.impl.CasComparer;
+import org.apache.uima.internal.util.XMLUtils;
 import org.apache.uima.resource.metadata.FsIndexDescription;
 import org.apache.uima.resource.metadata.TypeSystemDescription;
 import org.apache.uima.resource.metadata.impl.TypePriorities_impl;
 import org.apache.uima.resource.metadata.impl.TypeSystemDescription_impl;
 import org.apache.uima.test.junit_extension.JUnitExtension;
+import org.apache.uima.util.AutoCloseableNoException;
 import org.apache.uima.util.CasCreationUtils;
 import org.apache.uima.util.XMLInputSource;
 import org.apache.uima.util.XMLSerializer;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.InputSource;
 import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.XMLReaderFactory;
 
 import junit.framework.TestCase;
 
@@ -125,6 +127,13 @@
     doTestDeserializeAndReserialize(false);
     doTestDeserializeAndReserialize(true);
   }
+  
+  public void testDeserializeAndReserializeV2Ids() throws Exception {
+    try (AutoCloseableNoException a = LowLevelCAS.ll_defaultV2IdRefs()) {
+      doTestDeserializeAndReserialize(false);
+      doTestDeserializeAndReserialize(true);      
+    }
+  }
 
   private void doTestDeserializeAndReserialize(boolean useJCas) throws Exception {
     // deserialize a complex CAS
@@ -136,13 +145,17 @@
     TypeSystemImpl tsi = casImpl.getTypeSystemImpl();
     
     InputStream serCasStream = new FileInputStream(JUnitExtension.getFile("ExampleCas/cas.xml"));
-    XCASDeserializer deser = new XCASDeserializer(cas.getTypeSystem());
-    ContentHandler deserHandler = deser.getXCASHandler(cas);
-    SAXParserFactory fact = SAXParserFactory.newInstance();
-    SAXParser parser = fact.newSAXParser();
-    XMLReader xmlReader = parser.getXMLReader();
-    xmlReader.setContentHandler(deserHandler);
-    xmlReader.parse(new InputSource(serCasStream));
+    
+    XCASDeserializer.deserialize(serCasStream, cas, false);  // not lenient
+    
+    // next is missing the support for v2 ids
+//    XCASDeserializer deser = new XCASDeserializer(cas.getTypeSystem());
+//    ContentHandler deserHandler = deser.getXCASHandler(cas);
+//    SAXParserFactory fact = SAXParserFactory.newInstance();
+//    SAXParser parser = fact.newSAXParser();
+//    XMLReader xmlReader = parser.getXMLReader();
+//    xmlReader.setContentHandler(deserHandler);
+//    xmlReader.parse(new InputSource(serCasStream));
     serCasStream.close();
 
 //    //print some statistics to aid in verifying deserialization was correct
@@ -208,22 +221,33 @@
       cas2.getJCas();
     }
 
+    XCASDeserializer.deserialize(new StringReader(xml), cas2, false);  // not lenient
+
+    // next doesn't handle v2 form
     // deserialize into another CAS
-    XCASDeserializer deser2 = new XCASDeserializer(cas2.getTypeSystem());
-    ContentHandler deserHandler2 = deser2.getXCASHandler(cas2);
-    xmlReader.setContentHandler(deserHandler2);
-//    // debug
-//    PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream("debug.log.txt", false)));
-//    ps.println(xml);
-//    ps.close();
-    xmlReader.parse(new InputSource(new StringReader(xml)));
+//    XCASDeserializer deser2 = new XCASDeserializer(cas2.getTypeSystem());
+//    ContentHandler deserHandler2 = deser2.getXCASHandler(cas2);
+//    xmlReader.setContentHandler(deserHandler2);
+////    // debug
+////    PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream("debug.log.txt", false)));
+////    ps.println(xml);
+////    ps.close();
+//    xmlReader.parse(new InputSource(new StringReader(xml)));
 
     // compare
 //    if (cas.getAnnotationIndex().size() != cas2.getAnnotationIndex().size()) {
 //      System.out.println("debug");
 //    }
     assertEquals(cas.getAnnotationIndex().size(), cas2.getAnnotationIndex().size());
-    // CasComparer.assertEquals(cas,cas2);
+    if (XmiCasDeserializerTest.IS_CAS_COMPARE) {
+      long start = System.nanoTime();
+      CasCompare cc = new CasCompare((CASImpl)cas, (CASImpl)cas2);
+      cc.compareIds(((CASImpl)cas).is_ll_enableV2IdRefs());
+      assertTrue(cc.compareCASes());
+      System.out.format("compareCASes, time: %,d millisec%n",(System.nanoTime() - start) / 1000000L);
+    } else {
+      CasComparer.assertEquals(cas,cas2);
+    }
   }
 
   public void testOutOfTypeSystem2() throws Exception {
@@ -283,7 +307,7 @@
             + "<uima.tcas.DocumentAnnotation _indexed=\"1\" _id=\"8\" sofa=\"1\" begin=\"0\" end=\"13\" language=\"en\"/>"
             + "<foo.Bar _indexed=\"1\" _id=\"2\" sofa=\"1\" begin=\"0\" end=\"0\" baz=\"blah\">this is the value feature</foo.Bar></CAS>";
     OutOfTypeSystemData ootsd = new OutOfTypeSystemData();
-    XMLReader xmlReader = XMLReaderFactory.createXMLReader();
+    XMLReader xmlReader = XMLUtils.createXMLReader();
     XCASDeserializer deser = new XCASDeserializer(cas.getTypeSystem());
     ContentHandler handler = deser.getXCASHandler(cas, ootsd);
     xmlReader.setContentHandler(handler);
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/impl/XmiCasDeserializerTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/impl/XmiCasDeserializerTest.java
index 7759f7f..d5c30f4 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/impl/XmiCasDeserializerTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/impl/XmiCasDeserializerTest.java
@@ -57,9 +57,17 @@
 import org.apache.uima.cas_data.impl.CasComparer;
 import org.apache.uima.internal.util.MultiThreadUtils;
 import org.apache.uima.internal.util.MultiThreadUtils.ThreadM;
+import org.apache.uima.internal.util.XMLUtils;
 import org.apache.uima.internal.util.XmlAttribute;
 import org.apache.uima.internal.util.XmlElementNameAndContents;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.cas.EmptyFSList;
+import org.apache.uima.jcas.cas.EmptyStringList;
 import org.apache.uima.jcas.cas.FSArray;
+import org.apache.uima.jcas.cas.FSList;
+import org.apache.uima.jcas.cas.NonEmptyFSList;
+import org.apache.uima.jcas.cas.StringArray;
+import org.apache.uima.jcas.cas.StringList;
 import org.apache.uima.jcas.cas.TOP;
 import org.apache.uima.resource.metadata.FsIndexDescription;
 import org.apache.uima.resource.metadata.TypeDescription;
@@ -67,6 +75,7 @@
 import org.apache.uima.resource.metadata.impl.TypePriorities_impl;
 import org.apache.uima.resource.metadata.impl.TypeSystemDescription_impl;
 import org.apache.uima.test.junit_extension.JUnitExtension;
+import org.apache.uima.util.AutoCloseableNoException;
 import org.apache.uima.util.CasCopier;
 import org.apache.uima.util.CasCreationUtils;
 import org.apache.uima.util.FileUtils;
@@ -81,6 +90,11 @@
 
 
 public class XmiCasDeserializerTest extends TestCase {
+  
+  // normally set to true, set to false for comparative performance measurement
+  //   because this adds ~ 10 seconds or so to the time it takes to run the junit tests
+  
+  public static final boolean IS_CAS_COMPARE = true;
 
   private FsIndexDescription[] indexes;
 
@@ -107,6 +121,192 @@
     indexes = UIMAFramework.getXMLParser().parseFsIndexCollection(new XMLInputSource(indexesFile))
             .getFsIndexes();
   }
+  
+  
+  /**
+   * test case for https://issues.apache.org/jira/projects/UIMA/issues/UIMA-5558
+   * @throws Exception
+   */
+  public void testSerialize_with_0_length_array() throws Exception {
+    
+    TypeSystemDescription typeSystemDescription = UIMAFramework.getXMLParser().parseTypeSystemDescription(
+        new XMLInputSource(JUnitExtension.getFile("ExampleCas/testTypeSystem_small_withoutMultiRefs.xml")));
+    CAS cas = CasCreationUtils.createCas(typeSystemDescription, new TypePriorities_impl(), null);
+    
+    TypeSystem ts = cas.getTypeSystem();
+    Type refType = ts.getType("RefType");  // super is Annotation
+    Feature ref = refType.getFeatureByBaseName("ref");
+    Feature ref_StringArray = refType.getFeatureByBaseName("ref_StringArray");
+    Feature ref_StringList = refType.getFeatureByBaseName("ref_StringList");
+    JCas jcas = cas.getJCas();
+    
+    String xml;
+    
+ // deserialize into another CAS
+    SAXParserFactory fact = SAXParserFactory.newInstance();
+    SAXParser parser = fact.newSAXParser();
+    XMLReader xmlReader = parser.getXMLReader();
+    
+    CAS cas2 = CasCreationUtils.createCas(typeSystemDescription, new TypePriorities_impl(), null);
+    XmiCasDeserializer deser2;
+    ContentHandler deserHandler2;
+    
+    {  
+      StringArray stringArray = new StringArray(jcas, 0);
+      
+      
+      AnnotationFS fsRef = cas.createAnnotation(refType, 0, 0);
+      fsRef.setFeatureValue(ref_StringArray, stringArray);
+      cas.addFsToIndexes(fsRef);                    // gets serialized in=place
+            
+      xml = serialize(cas, null);
+      
+   // deserialize into another CAS
+      fact = SAXParserFactory.newInstance();
+      parser = fact.newSAXParser();
+      xmlReader = parser.getXMLReader();
+      
+      deser2 = new XmiCasDeserializer(cas2.getTypeSystem());
+      deserHandler2 = deser2.getXmiCasHandler(cas2);
+      xmlReader.setContentHandler(deserHandler2);
+      xmlReader.parse(new InputSource(new StringReader(xml)));
+      
+      CasComparer.assertEquals(cas, cas2);
+      AnnotationFS fs2 = cas2.getAnnotationIndex(refType).iterator().get();
+      StringArrayFS fsa2 = (StringArrayFS) fs2.getFeatureValue(ref_StringArray);
+      assertEquals(0, fsa2.size());     
+     }
+    
+    // ------- repeat with lists in place of arrays --------------
+    
+    cas.reset();
+
+    StringList stringlist0 = new EmptyStringList(jcas);
+    
+//    fsarray.addToIndexes(); // if added to indexes, forces serialization of FSArray as an element
+    
+    AnnotationFS fsRef = cas.createAnnotation(refType, 0, 0);
+    fsRef.setFeatureValue(ref_StringList, stringlist0);
+    cas.addFsToIndexes(fsRef);                    // gets serialized in=place
+        
+    xml = serialize(cas, null);
+    
+ // deserialize into another CAS
+    parser = fact.newSAXParser();
+    xmlReader = parser.getXMLReader();
+    
+    cas2.reset();
+
+    deser2 = new XmiCasDeserializer(cas2.getTypeSystem());
+    deserHandler2 = deser2.getXmiCasHandler(cas2);
+    xmlReader.setContentHandler(deserHandler2);
+    xmlReader.parse(new InputSource(new StringReader(xml)));
+    
+    CasComparer.assertEquals(cas, cas2);
+    AnnotationFS fs2 = cas2.getAnnotationIndex(refType).iterator().get();
+    FeatureStructure fsl2 = fs2.getFeatureValue(ref_StringList);
+    assertTrue(fsl2.getType().getShortName().equals("EmptyStringList"));
+    
+  }
+  
+  /**
+   * test case for https://issues.apache.org/jira/browse/UIMA-5532
+   * @throws Exception
+   */
+  public void testSerialize_withPartialMultiRefs() throws Exception {
+   
+    TypeSystemDescription typeSystemDescription = UIMAFramework.getXMLParser().parseTypeSystemDescription(
+        new XMLInputSource(JUnitExtension.getFile("ExampleCas/testTypeSystem_small_withMultiRefs.xml")));
+    CAS cas = CasCreationUtils.createCas(typeSystemDescription, new TypePriorities_impl(), null);
+    
+    TypeSystem ts = cas.getTypeSystem();
+    Type refType = ts.getType("RefType");
+    Feature ref = refType.getFeatureByBaseName("ref");
+    Feature ref_FSArray = refType.getFeatureByBaseName("ref_FSArray");
+    Feature ref_FSList = refType.getFeatureByBaseName("ref_FSList");
+    JCas jcas = cas.getJCas();
+    
+    String xml;  // = serialize(cas, null);
+    
+ // deserialize into another CAS
+    SAXParserFactory fact = SAXParserFactory.newInstance();
+    SAXParser parser = fact.newSAXParser();
+    XMLReader xmlReader = parser.getXMLReader();
+    
+    CAS cas2 = CasCreationUtils.createCas(typeSystemDescription, new TypePriorities_impl(), null);
+    XmiCasDeserializer deser2;
+    ContentHandler deserHandler2;
+    
+    {  
+      FSArray fsarray = new FSArray(jcas, 2);
+      TOP fs1 = new TOP(jcas);
+      TOP fs2 = new TOP(jcas);
+      fsarray.set(0, fs1);
+      fsarray.set(1, fs2);
+      
+  //    fsarray.addToIndexes(); // if added to indexes, forces serialization of FSArray as an element
+      
+      AnnotationFS fsRef = cas.createAnnotation(refType, 0, 0);
+      fsRef.setFeatureValue(ref, fsarray);
+      cas.addFsToIndexes(fsRef);                    // gets serialized in=place
+      
+      fsRef = cas.createAnnotation(refType, 0, 0);
+      fsRef.setFeatureValue(ref_FSArray, fsarray);
+      cas.addFsToIndexes(fsRef);                    // gets serialized as ref
+      
+      xml = serialize(cas, null);
+      
+   // deserialize into another CAS
+      fact = SAXParserFactory.newInstance();
+      parser = fact.newSAXParser();
+      xmlReader = parser.getXMLReader();
+      
+      deser2 = new XmiCasDeserializer(cas2.getTypeSystem());
+      deserHandler2 = deser2.getXmiCasHandler(cas2);
+      xmlReader.setContentHandler(deserHandler2);
+      xmlReader.parse(new InputSource(new StringReader(xml)));
+      
+      CasComparer.assertEquals(cas, cas2);
+      
+      // ------- repeat with lists in place of arrays --------------
+    }
+    
+    cas.reset();
+
+    TOP fs1 = new TOP(jcas); //https://issues.apache.org/jira/browse/UIMA-5544
+    TOP fs2 = new TOP(jcas);
+
+    FSList fslist2 = new EmptyFSList(jcas);
+    FSList fslist1 = new NonEmptyFSList(jcas, fs2, fslist2);
+    FSList fslist0 = new NonEmptyFSList(jcas, fs1, fslist1);
+    
+//    fsarray.addToIndexes(); // if added to indexes, forces serialization of FSArray as an element
+    
+    AnnotationFS fsRef = cas.createAnnotation(refType, 0, 0);
+    fsRef.setFeatureValue(ref, fslist0);
+    cas.addFsToIndexes(fsRef);                    // gets serialized in=place
+    
+    fsRef = cas.createAnnotation(refType, 0, 0);
+    fsRef.setFeatureValue(ref_FSList, fslist0);
+    cas.addFsToIndexes(fsRef);                    // gets serialized as ref
+    
+    xml = serialize(cas, null);
+    
+ // deserialize into another CAS
+    parser = fact.newSAXParser();
+    xmlReader = parser.getXMLReader();
+    
+    cas2.reset();
+//    fs1 = new TOP(jcas);  //https://issues.apache.org/jira/browse/UIMA-5544
+//    fs2 = new TOP(jcas);
+    deser2 = new XmiCasDeserializer(cas2.getTypeSystem());
+    deserHandler2 = deser2.getXmiCasHandler(cas2);
+    xmlReader.setContentHandler(deserHandler2);
+    xmlReader.parse(new InputSource(new StringReader(xml)));
+    
+    CasComparer.assertEquals(cas, cas2);
+
+  }
 
   public void testDeserializeAndReserialize() throws Exception {
     try {
@@ -121,6 +321,21 @@
       JUnitExtension.handleException(e);
     }
   }
+  
+  public void testDeserializeAndReserializeV2() throws Exception {
+    try (AutoCloseableNoException a = LowLevelCAS.ll_defaultV2IdRefs()) {
+      File tsWithNoMultiRefs = JUnitExtension.getFile("ExampleCas/testTypeSystem.xml");
+      doTestDeserializeAndReserialize(tsWithNoMultiRefs,false);
+      File tsWithMultiRefs = JUnitExtension.getFile("ExampleCas/testTypeSystem_withMultiRefs.xml");
+      doTestDeserializeAndReserialize(tsWithMultiRefs,false);
+      //also test with JCas initialized
+      doTestDeserializeAndReserialize(tsWithNoMultiRefs,true);
+      doTestDeserializeAndReserialize(tsWithMultiRefs,true);
+    } catch (Exception e) {
+      JUnitExtension.handleException(e);
+    }
+  }
+  
 
   private void doTestDeserializeAndReserialize(File typeSystemDescriptorFile, boolean useJCas) throws Exception {
     // deserialize a complex CAS from XCAS
@@ -132,13 +347,17 @@
     }
 
     InputStream serCasStream = new FileInputStream(JUnitExtension.getFile("ExampleCas/cas.xml"));
-    XCASDeserializer deser = new XCASDeserializer(cas.getTypeSystem());
-    ContentHandler deserHandler = deser.getXCASHandler(cas);
-    SAXParserFactory fact = SAXParserFactory.newInstance();
-    SAXParser parser = fact.newSAXParser();
-    XMLReader xmlReader = parser.getXMLReader();
-    xmlReader.setContentHandler(deserHandler);
-    xmlReader.parse(new InputSource(serCasStream));
+    
+    XCASDeserializer.deserialize(serCasStream, cas, false);  // not lenient
+    
+    // next is missing the support for v2 ids
+//    XCASDeserializer deser = new XCASDeserializer(cas.getTypeSystem());
+//    ContentHandler deserHandler = deser.getXCASHandler(cas);
+//    SAXParserFactory fact = SAXParserFactory.newInstance();
+//    SAXParser parser = fact.newSAXParser();
+//    XMLReader xmlReader = parser.getXMLReader();
+//    xmlReader.setContentHandler(deserHandler);
+//    xmlReader.parse(new InputSource(serCasStream));
     serCasStream.close();
 
     // reserialize as XMI
@@ -151,12 +370,31 @@
     if (useJCas) {
       cas2.getJCas();
     }
+    
+    XMLReader xmlReader = XMLUtils.createSAXParserFactory().newSAXParser().getXMLReader();
+    
     XmiCasDeserializer deser2 = new XmiCasDeserializer(cas2.getTypeSystem());
     ContentHandler deserHandler2 = deser2.getXmiCasHandler(cas2);
     xmlReader.setContentHandler(deserHandler2);
     xmlReader.parse(new InputSource(new StringReader(xml)));
     
     // compare
+    if (IS_CAS_COMPARE) {
+      CasCompare cc = new CasCompare((CASImpl)cas, (CASImpl)cas2);
+      // ids won't be the same, don't compare these
+      // tune debug
+      long start = System.nanoTime();
+      int i = 0;
+//      for (; i < 1000; i++) {
+        assertTrue(cc.compareCASes());
+//        if (i % 10 == 0) {
+          long end = System.nanoTime();
+          System.out.format("compareCASes i: %d, time: %,d millisec%n", i, (end - start) / 1000000L);
+          start = end;
+//        }
+//      }
+    }
+    
     assertEquals(cas.getAnnotationIndex().size(), cas2.getAnnotationIndex().size());
     assertEquals(cas.getDocumentText(), cas2.getDocumentText());
     CasComparer.assertEquals(cas,cas2);
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/impl/XmiCompare.java b/uimaj-core/src/test/java/org/apache/uima/cas/impl/XmiCompare.java
new file mode 100644
index 0000000..44c0b3b
--- /dev/null
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/impl/XmiCompare.java
@@ -0,0 +1,519 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.cas.impl;

+

+import java.io.File;

+import java.io.FileInputStream;

+import java.io.FileNotFoundException;

+import java.io.IOException;

+import java.nio.file.FileVisitOption;

+import java.nio.file.Files;

+import java.nio.file.Path;

+import java.nio.file.Paths;

+import java.util.ArrayList;

+import java.util.Arrays;

+import java.util.Iterator;

+import java.util.List;

+import java.util.stream.Collectors;

+import java.util.stream.Stream;

+

+import org.apache.uima.UIMAFramework;

+import org.apache.uima.cas.Feature;

+import org.apache.uima.cas.Type;

+import org.apache.uima.cas.TypeSystem;

+import org.apache.uima.cas.text.AnnotationFS;

+import org.apache.uima.internal.util.Misc;

+import org.apache.uima.jcas.cas.FSArray;

+import org.apache.uima.jcas.cas.StringArray;

+import org.apache.uima.jcas.cas.TOP;

+import org.apache.uima.resource.ResourceInitializationException;

+import org.apache.uima.resource.metadata.TypeSystemDescription;

+import org.apache.uima.util.CasCreationUtils;

+import org.apache.uima.util.CasIOUtils;

+import org.apache.uima.util.InvalidXMLException;

+import org.apache.uima.util.XMLInputSource;

+

+/**

+ * This is a utility that compares two xmi CASs and prints out the differences.

+ * 

+ * It is run as a Java Application, not as a test

+ * 

+ * It takes two directories, with the xmi CASs to compare (must be named the same):

+ *   each directory has 1 special file named: CAS_typeSystem_desc.xml - this is the type system

+ *   each has n other files: xmi CASes to compare

+ * It takes an int "skip" argument, to skip over that many CASs before starting comparison.

+ *   

+ * It supports comparing results of UIMA V2 with V3, using a convention:

+ *   The input directories must have names that start with uv2-out  or uv3-out

+ * 

+ * Compare technique:

+ *   Get a set of roots - the items that are in any index

+ *   Sort that by type, and then by content.  

+ *   

+ *   There are 3 sets of compare-relaxers.

+ *     - uv2 to uv2 

+ *     - uv3 to uv3   

+ *     - uv2 to uv3

+ *   

+ */

+public class XmiCompare {

+

+  private static final String BLANKS_89 = Misc.blanks.substring(0, 89);

+

+  Path d1, d2;  // the input directories

+  private String d2String;

+  private String d1String;

+  

+  boolean isV2V2;

+  boolean isV3V3;

+  boolean isV2V3;

+  

+  CASImpl c1, c2;

+  boolean isOk = true;

+

+  private int itemCount = 0;

+

+  private CasCompare cc;

+

+  private int skip;

+

+ 

+

+  public static void main(String[] args) {

+    new XmiCompare().run(args);

+  } 

+

+  void run(String[] args) {

+    try {

+      itemCount = 0;

+      // alternative to supplying args- hard code the path :-)

+      if (args == null || args.length == 0) {

+        d1 = Paths.get("some-explicit-coded-path/uv2-out-some-suffix");

+        d2 = Paths.get("some-explicit-coded-path/uv2-out-some-other-suffix");

+

+        

+//        skip = 725;  // optional skip amount

+      } else {

+        d1 = Paths.get(args[0]);

+        d2 = Paths.get(args[1]);

+        skip = Integer.parseInt(args[2]);

+      }

+      d1String = d1.toString();

+      d2String = d2.toString();

+

+      boolean d1v2 = d1String.contains("uv2-out");

+      boolean d2v2 = d2String.contains("uv2-out");

+      boolean d1v3 = d1String.contains("uv3-out");

+      boolean d2v3 = d2String.contains("uv3-out");

+      

+      isV2V2 = d1v2 && d2v2;

+      isV3V3 = d1v3 && d2v3;

+      isV2V3 = (d1v2 && d2v3) || (d1v3 && d2v2);

+      

+      System.out.println("Comparing " + d1String + " to " + d2String);

+      

+      if (isV2V2) System.out.println("\napplying fixups for v2 versus v2 comparison");

+      if (isV2V3) System.out.println("\napplying fixups for v2 versus v3 comparison");

+      if (isV3V3) System.out.println("\napplying fixups for v3 versus v3 comparison");

+

+      // read the type system descriptor

+      File typeSystemFile = Paths.get(d2String, "CAS_typeSystem_desc.xml").toFile();

+      TypeSystemDescription typeSystemDescription = UIMAFramework.getXMLParser().parseTypeSystemDescription(

+          new XMLInputSource(typeSystemFile));

+      

+      c1 = (CASImpl) CasCreationUtils.createCas(typeSystemDescription, null, null);

+      c2 = (CASImpl) CasCreationUtils.createCas(typeSystemDescription, null, null);

+      

+      Stream<Path> pathStream = Files.walk(d1, FileVisitOption.FOLLOW_LINKS);      

+      pathStream.forEach(p1 -> maybeCompare(p1));

+      pathStream.close();

+      

+    } catch (ResourceInitializationException | InvalidXMLException | IOException e) {

+      throw new RuntimeException(e);

+    }

+  }

+

+  /**

+   * Compares one xmi file, if it can find the other one

+   * Skips non-xmi files

+   * 

+   * @param p1 - path of file to compare

+   * @throws IOException 

+   * @throws FileNotFoundException 

+   */

+  void maybeCompare(Path p1) {

+    String p1name = p1.toString();

+    if (!p1name.endsWith(".xmi")) {

+      return;

+    }

+    

+    Path p2 = Paths.get(d2String, p1.getFileName().toString());

+    

+    if (!p2.toFile().exists()) {

+      return;

+    }

+    

+    itemCount++;

+    

+    System.out.format("%,5d Comparing %s:",

+        itemCount,

+        p1.getFileName().toString());

+    

+    if (itemCount <= skip) {

+      System.out.println(" skipped");

+      return;

+    }

+

+    try {

+      CasIOUtils.load(new FileInputStream(p1.toFile()), c1);

+      CasIOUtils.load(new FileInputStream(p2.toFile()), c2);

+    } catch (IOException e) {

+      throw new RuntimeException(e);

+    }

+             

+    compareNumberOfFSsByType();

+    

+    cc = new CasCompare(c1, c2);

+    cc.compareAll(true);

+

+    

+    // put temporary customizations here.

+//  removeAllExcept("SomeType");

+

+    customizeCompare();

+    

+    isOk = cc.compareCASes();

+     

+    if (isOk) {

+      System.out.println("  compare:OK");

+    } 

+

+  } 

+  

+  private void compareNumberOfFSsByType() {

+    Iterator<FsIndex_singletype<TOP>> il1 = c1.indexRepository.streamNonEmptyIndexes(TOP.class).collect(Collectors.toList()).iterator();

+    Iterator<FsIndex_singletype<TOP>> il2 = c2.indexRepository.streamNonEmptyIndexes(TOP.class).collect(Collectors.toList()).iterator();

+

+    StringBuilder sb = new StringBuilder();

+    StringBuilder sba = new StringBuilder();

+    boolean isSame = il1.hasNext() || il2.hasNext();

+    while( il1.hasNext() || il2.hasNext()) {

+      sb.setLength(0);

+      String ts1 = null, ts2 = null;

+      int sz1 = 0, sz2 = 0;

+      FsIndex_singletype<TOP> idx;

+      if (il1.hasNext()) {

+        idx = il1.next();

+        ts1 = idx.getType().getName();

+        sz1 = idx.size();

+        sb.append(String.format("%-83s %,5d", ts1, sz1));

+      } else {

+        isSame = false;

+        sb.append(BLANKS_89);

+      }

+      if (il2.hasNext()) {

+        idx = il2.next();

+        ts2 = idx.getType().getName();

+        sz2 = idx.size();

+        String m = (ts2.equals(ts1) && sz2 == sz1) 

+                     ? "same"

+                     : ts2;

+        sb.append(String.format(" %,5d %s", sz2, m));

+      } else {

+        isSame = false;

+      }

+      sba.append(sb).append('\n');

+      if (isSame) {

+        isSame = ts1.equals(ts2) && sz1 == sz2;

+      }

+    }

+

+    if (!isSame) {

+      System.out.println(sba);

+    }

+    System.out.format(" %s", isSame ? "Same number of types" : "Different numbers of types");

+//    System.out.println(" skp cpr");

+//    if (true) return;

+  }

+  

+  private void customizeCompare() {

+    if (isV2V2) {

+      customizeV2V2();

+    }

+

+    if (isV3V3) {

+      customizeV3V3();

+    }

+    

+    if (isV2V3) {

+      customizeV2V3();

+    }

+  }

+  

+  private void customizeV2V2() {

+//  List<Runnable> r  = sortFSArray("com.ibm.watsonx.nlp_med.common_types.UMLS.Concept", "innerConcepts");

+//  

+//  for (Runnable a : r) {

+//    if (a != null) {

+//      a.run();

+//    }

+//  }

+  

+  // before sortStringArray

+//  fixupTermMentionTypesUnknown();

+//  cc.compareStringsAsEqual("com.ibm.watsonx.nlp_di.cas_term.Term", "mentionTypes", new String[]{"CATEGORY", "UNKNOWN"}, 1);

+//  cc.compareStringsAsEqual("com.ibm.watsonx.nlp_di.cas_term.Term", "mentionTypes", new String[]{"CATEGORY", "UNKNOWN"}, 0);

+//  cc.compareStringsAsEqual("com.ibm.watsonx.nlp_di.cas_term.Term", "mentionTypes", new String[]{"CATEGORY", "UNKNOWN"}, 2);

+

+//  sortStringArray("com.ibm.watsonx.nlp_di.cas_term.Term", "mentionTypes");

+//  v2FixupMentionType_mi("com.ibm.watsonx.nlp_di.hutt.UnitOfMeasurement");

+    cc.addStringCongruenceSet("com.ibm.watsonx.nlp_di.xsg.PseudoParagraph", "ruleId", new String[]{"Odd", "Even"}, -1);

+//  fixupComponentId("com.ibm.watsonx.nlp_di.hutt.Person",

+//                   "R2/2.2.2/Pre/NONDEFROLE/\\Monitor",

+//                   "R2/2.2.2/Pre/NONDEFROLE/\\monitor");

+//  fixupComponentId("com.ibm.watsonx.nlp_di.hutt.NondefiningRole", 

+//                   "R2/2.2.2/Pre/NONDEFROLE/\\Monitor",

+//                   "R2/2.2.2/Pre/NONDEFROLE/\\monitor");

+//

+//  fixupComponentId("com.ibm.watsonx.nlp_di.hutt.Symptom", 

+//                   "R2/2.2.2/Pre/NONDEFROLE/\\Sleeping",

+//                   "R2/2.2.2/Pre/NONDEFROLE/\\sleeping");

+//  fixupComponentId("com.ibm.watsonx.nlp_di.hutt.Symptom", 

+//      "R2/2.2.2/Main/SYMPTOM/\\Sleeping",

+//      "R2/2.2.2/Main/SYMPTOM/\\sleeping");

+  }

+  

+  private void customizeV3V3() {

+    List<Runnable> r = new ArrayList<>(); 

+//  r.addAll(sortFSArray("com.ibm.watsonx.nlp_di.cas_term.Term", "outgoingLinks"));

+//  r.addAll(sortFSArray("com.ibm.watsonx.nlp_di.cas_term.Term", "incomingLinks"));

+//  r.addAll(sortFSArray("com.ibm.watsonx.nlp_di.hutt.Predicate", "arguments"));

+//  r.addAll(sortFSArray("com.ibm.watsonx.nlp_di.cas_term.Expression", "termLinks"));      

+//  r.addAll(sortFSArray("com.ibm.watsonx.nlp_med.common_types.UMLS.Concept", "innerConcepts"));

+//  r.addAll(sortFSArray("com.ibm.watsonx.nlp_di.common_types.generic_relation.GenericRelation", "args"));

+//  r.addAll(sortFSArray("com.ibm.watsonx.nlp_di.hutt.Predicate", "sources"));

+

+

+  for (Runnable a : r) {

+    if (a != null) {

+      a.run();

+    }

+  }

+

+//  v2FixupMentionType_mi("com.ibm.watsonx.nlp_di.hutt.UnitOfMeasurement");

+//  cc.addStringCongruenceSet("com.ibm.watsonx.nlp_di.xsg.PseudoParagraph", "ruleId", new String[]{"Odd", "Even"}, -1);

+//  fixupTermMentionTypesUnknown();

+//  fixupComponentId("com.ibm.watsonx.nlp_di.hutt.UsState", 

+//      "R2/2.2.2/Pre/STATE/State",

+//      "R2/2.2.2/Pre/STATE/state");

+//  fixupComponentId("com.ibm.watsonx.nlp_di.hutt.UsState", 

+//      "R2/2.2.2/Pre/STATE/\\States",

+//      "R2/2.2.2/Pre/STATE/\\states");

+  }

+  

+  private void customizeV2V3() {

+    List<Runnable> r = new ArrayList<>();

+//  r = sortFSArray("com.ibm.watsonx.nlp_di.cas_term.Term", "outgoingLinks");

+//  r.addAll(sortFSArray("com.ibm.watsonx.nlp_di.cas_term.Term", "incomingLinks"));

+//  r.addAll(sortFSArray("com.ibm.watsonx.nlp_di.hutt.Predicate", "arguments"));

+//  r.addAll(sortFSArray("com.ibm.watsonx.nlp_di.cas_term.Expression", "termLinks"));

+//  r.addAll(sortFSArray("com.ibm.watsonx.nlp_med.common_types.UMLS.Concept", "innerConcepts"));

+//  r.addAll(sortFSArray("com.ibm.watsonx.nlp_di.common_types.generic_relation.GenericRelation", "args"));

+//  r.addAll(sortFSArray("com.ibm.watsonx.nlp_di.hutt.Predicate", "sources"));

+  

+    for (Runnable a : r) {

+      if (a != null) {

+        a.run();

+      }

+    }

+  

+  // from v2:

+  // before sortStringArray

+//  fixupTermMentionTypesUnknown();

+//  sortStringArray("com.ibm.watsonx.nlp_di.cas_term.Term", "mentionTypes");

+//  v2FixupMentionType_mi("com.ibm.watsonx.nlp_di.hutt.UnitOfMeasurement");

+//  fixupComponentId("com.ibm.watsonx.nlp_di.hutt.Person",

+//                   "R2/2.2.2/Pre/NONDEFROLE/\\Monitor",

+//                   "R2/2.2.2/Pre/NONDEFROLE/\\monitor");

+//  fixupComponentId("com.ibm.watsonx.nlp_di.hutt.NondefiningRole", 

+//                   "R2/2.2.2/Pre/NONDEFROLE/\\Monitor",

+//                   "R2/2.2.2/Pre/NONDEFROLE/\\monitor");

+//

+//  fixupComponentId("com.ibm.watsonx.nlp_di.hutt.Symptom", 

+//                   "R2/2.2.2/Pre/NONDEFROLE/\\Sleeping",

+//                   "R2/2.2.2/Pre/NONDEFROLE/\\sleeping");

+//  fixupComponentId("com.ibm.watsonx.nlp_di.hutt.Symptom", 

+//      "R2/2.2.2/Main/SYMPTOM/\\Sleeping",

+//      "R2/2.2.2/Main/SYMPTOM/\\sleeping");

+//

+//  

+//  

+//  sortStringArray("com.ibm.watsonx.nlp_di.hutt.Predicate", "argumentLabels");

+//  canonicalizeStringFirstVariant("com.ibm.watsonx.nlp_med.common_types.UMLS.SignOrSymptom", "conceptName", "variants");

+    cc.addStringCongruenceSet("com.ibm.watsonx.nlp_di.xsg.PseudoParagraph", "ruleId", new String[]{"Odd", "Even"}, -1);

+    canonicalizeString("com.ibm.watsonx.nlp_di.xsg.PseudoParagraph", "ruleId", new String[]{"Odd", "Even"}, "Odd");

+  } 

+ 

+  private List<Runnable> sortFSArray(String typename, String featurename) {

+    List<Runnable> r = sortFSArray(typename, featurename, c1);

+    r.addAll(sortFSArray(typename, featurename, c2));

+    return r;

+  }

+  

+  private void v2FixupMentionType_mi(String t) {

+    v2FixupMentionType_mi(t, c1);

+    v2FixupMentionType_mi(t, c2);    

+  }

+  

+  private void v2FixupMentionType_mi(String t, CASImpl cas) {

+    TypeSystem ts = cas.getTypeSystem();

+    Type type = ts.getType(t);

+    Feature f_mentionType = type.getFeatureByBaseName("mentionType");

+    Feature f_componentId = type.getFeatureByBaseName("componentId");

+    cas.select(type)

+       .allViews()

+       .filter(fs -> "R2/2.2.2/Main/UNITOFM/_mi".equals(fs.getStringValue(f_componentId)))

+       .forEach(fs -> {

+           fs.setStringValue(f_componentId, "R2/2.2.2/Main/UNITOFM/_mile");

+           fs.setStringValue(f_mentionType, "CATEGORY");

+         });

+  }

+  

+  private void fixupComponentId(String t, String s1, String s2) {

+    fixupComponentId(t, s1, s2, c1);

+    fixupComponentId(t, s1, s2, c2);

+  }

+  

+  private void fixupComponentId(String t, String s1, String s2, CASImpl cas) {

+    TypeSystem ts = cas.getTypeSystem();

+    Type type = ts.getType(t);

+    Feature f_componentId = type.getFeatureByBaseName("componentId");

+    cas.select(type)

+       .allViews()

+       .filter(fs -> s1.equals(fs.getStringValue(f_componentId)))

+       .forEach(fs -> {

+           fs.setStringValue(f_componentId, s2);

+         });    

+  }

+  

+  private void fixupTermMentionTypesUnknown() {

+    fixupTermMentionTypesUnknown(c1);

+    fixupTermMentionTypesUnknown(c2);

+  }

+

+  private void fixupTermMentionTypesUnknown(CASImpl cas) {

+    TypeSystem ts = cas.getTypeSystem();

+    Type type = ts.getType("com.ibm.watsonx.nlp_di.cas_term.Term");

+    Feature f_mentionTypes = type.getFeatureByBaseName("mentionTypes");

+    cas.select(type)

+       .allViews()

+       .map(fs -> (StringArray) fs.getFeatureValue(f_mentionTypes))

+       .filter(fs -> fs != null && fs.contains("UNKNOWN"))

+       .forEach(fs -> 

+         {

+           for (int i = 0; i < fs.size(); i++) {

+             if ("UNKNOWN".equals(fs.get(i))) {

+               fs.set(i, "CATEGORY");

+             }

+           }

+         });

+  }

+  

+  private List<Runnable> sortFSArray(String typename, String featurename, CASImpl cas) {

+    TypeSystem ts = cas.getTypeSystem();

+    Type type = ts.getType(typename);

+    Feature feat = ts.getFeatureByFullName(typename + ":" + featurename);

+    return cas.select(type).allViews().map(fs -> 

+        cc.sortFSArray((FSArray)fs.getFeatureValue(feat))).collect(Collectors.toList());

+  }

+  

+  private void sortStringArray(String t, String f) {

+    sortStringArray(t, f, c1);

+    sortStringArray(t, f, c2);

+  }

+  

+  private void sortStringArray(String t, String f, CASImpl cas) {

+    TypeSystem ts = cas.getTypeSystem();

+    Type type = ts.getType(t);

+    Feature feat = ts.getFeatureByFullName(t + ":" + f);

+    cas.select(type).allViews().forEach(fs ->

+      { StringArray sa = (StringArray) fs.getFeatureValue(feat);

+        if (sa != null && sa.size() > 2) {

+          Arrays.sort(sa._getTheArray());

+        }

+      });

+  }

+  

+  

+  

+  private void canonicalizeStringFirstVariant(String t, String f, String v) {

+    canonicalizeStringFirstVariant(t, f, v, c1);

+    canonicalizeStringFirstVariant(t, f, v, c2);

+  }

+  

+  void canonicalizeStringFirstVariant(String t, String f, String v, CASImpl cas) {

+    TypeSystem ts = cas.getTypeSystem();

+    Type type = ts.getType(t);

+    Feature feat = ts.getFeatureByFullName(t + ":" + f);

+    Feature featv = ts.getFeatureByFullName(t + ":" + v);  // v is the variant array

+    cas.select(type).allViews().forEach(fs ->

+      { StringArray sa = (StringArray) fs.getFeatureValue(featv);

+        if (sa != null && sa.size() > 2) {

+          String item = fs.getStringValue(feat);

+          if (sa.contains(item)) {

+            fs.setStringValue(feat, sa.get(0));

+          }

+        }

+      });

+  }

+    

+  private void canonicalizeString(String t, String f, String[] filter, String cv) {

+    canonicalizeString(t, f, filter, cv, c1);

+    canonicalizeString(t, f, filter, cv, c2);

+  }

+

+  void canonicalizeString(String t, String f, String[] filter, String cv, CASImpl cas) {

+    TypeSystem ts = cas.getTypeSystem();

+    Type type = ts.getType(t);

+    Feature feat = ts.getFeatureByFullName(t + ":" + f);

+    cas.select(type).allViews().forEach(fs ->

+      { String item = fs.getStringValue(feat);

+        if (Misc.contains(filter, item)) {

+            fs.setStringValue(feat, cv);

+        }

+      });    

+  }

+

+  void removeAllExcept(String v) {

+    removeAllExcept(v, c1);

+    removeAllExcept(v, c2);

+  }

+  

+  void removeAllExcept(String v, CASImpl c) {

+    Iterator<AnnotationFS> it = c.getAnnotationIndex().iterator();

+    while (it.hasNext()) {

+      TOP item = (TOP) it.next();

+      if (item._getTypeImpl().getName().contains(v)) {

+        continue;

+      }

+      item.removeFromIndexes();

+    }

+  }

+}

diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/AnnotationIndexTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/AnnotationIndexTest.java
new file mode 100644
index 0000000..4d2f0f7
--- /dev/null
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/AnnotationIndexTest.java
@@ -0,0 +1,327 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.cas.test;

+

+import java.io.File;

+import java.util.ArrayList;

+import java.util.Collections;

+import java.util.Comparator;

+import java.util.Random;

+

+import org.apache.uima.UIMAFramework;

+import org.apache.uima.cas.FSIterator;

+import org.apache.uima.cas.Type;

+import org.apache.uima.cas.impl.CASImpl;

+import org.apache.uima.cas.impl.FSIndexRepositoryImpl;

+import org.apache.uima.cas.impl.TypeSystemImpl;

+import org.apache.uima.cas.text.AnnotationIndex;

+import org.apache.uima.jcas.JCas;

+import org.apache.uima.jcas.cas.TOP;

+import org.apache.uima.jcas.tcas.Annotation;

+import org.apache.uima.resource.metadata.TypeSystemDescription;

+import org.apache.uima.resource.metadata.impl.TypePriorities_impl;

+import org.apache.uima.test.junit_extension.JUnitExtension;

+import org.apache.uima.util.CasCreationUtils;

+import org.apache.uima.util.XMLInputSource;

+

+import junit.framework.TestCase;

+

+/**

+ * Class comment for FilteredIteratorTest.java goes here.

+ * 

+ */

+public class AnnotationIndexTest extends TestCase {

+  

+//  static class Miter {

+//    final int outerIter;

+//    final int innerIter;

+//    final int itemNbr;

+//    final long time;

+//    

+//    Miter(int out, int in, int item, long time) {

+//      this.outerIter = out;

+//      this.innerIter = in;

+//      this.itemNbr = item;

+//      this.time = time;

+//    }

+//    

+//    int getOuterIter() { return outerIter;}

+//    int getInnerIter() { return outerIter;}

+//    int getItemNbr() { return outerIter;}

+//    long getTime() { return time; }

+//  }

+  

+  

+  

+  static File typeSystemFile1 = JUnitExtension.getFile("ExampleCas/testTypeSystem.xml");

+//  static int SZ = 1111;

+//  static int SZp2 = 2048;

+  static int SZ = 59;

+  static int SZp2 = 64;

+  

+  static Random r = new Random();

+  static long seed =  r.nextLong();

+  //-5710808747691817430L;

+//-898838165734156852L; 

+            // 1783099358091571349L;

+  static { 

+    r.setSeed(seed); 

+    System.out.println("AnnotationIndexTest random seed: " + seed);

+  }

+  

+  CASImpl cas;

+  JCas jcas;

+  FSIndexRepositoryImpl ir;

+  AnnotationIndex<Annotation> ai;

+  TypeSystemImpl tsi;

+  Type topType;

+  int[] rns;

+  

+  private Annotation[] as = new Annotation[SZp2];

+  private long valTime = 0L;

+  

+//  ArrayList<Miter> iterTimes = new ArrayList<>(110000);

+//  

+//  public static ThreadLocal<long[]> startIter = ThreadLocal.withInitial(() -> new long[1]);

+  

+

+  protected void setUp() throws Exception {

+    long startTime = System.nanoTime();

+    TypeSystemDescription typeSystemDescription = UIMAFramework.getXMLParser().parseTypeSystemDescription(

+        new XMLInputSource(typeSystemFile1));

+    System.out.format("time to parse ts: %,d%n", (System.nanoTime() - startTime)/ 1000000);

+    startTime = System.nanoTime();

+    cas = (CASImpl) CasCreationUtils.createCas(typeSystemDescription, new TypePriorities_impl(), null);

+    jcas = cas.getJCas();

+    ir = (FSIndexRepositoryImpl) cas.getIndexRepository();

+    ai = cas.getAnnotationIndex(); 

+    tsi = cas.getTypeSystemImpl();

+    topType = tsi.getTopType();   

+    System.out.format("time to create CAS: %,d%n", (System.nanoTime() - startTime)/ 1000000);

+    startTime = System.nanoTime();

+    

+    //prefill

+    int[] ttt = new int[SZp2];

+    for (int i = 0; i < SZp2; i++) { ttt[i] = i;}

+    ttt = shuffle(ttt);  

+      

+    

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

+      as[ttt[i]] = new Annotation(jcas, i, i + 200);

+      ir.addFS(as[ttt[i]]);

+    }

+

+    System.out.format("time to create Annotations, add to indexes: %,d%n", (System.nanoTime() - startTime)/ 1000000);

+    startTime = System.nanoTime();

+

+  }

+

+  /**

+   * 

+   * Do a lot of inserts / removes in patterns:

+   *   remove n, insert n in random order

+   * 

+   */

+   public void testInsert() {

+    insert1(0);

+    valTime = 0L;

+    long startTime = System.nanoTime();

+    int ii = 0;

+//    for (; ii < 100; ii++) {  //enable for lots of iterationss, disable for normal test case

+//      System.out.println("testInsert outer loop: " + ii);

+      insert1(ii);

+//    }  

+//    System.out.println("debug end");

+    long v1 = (System.nanoTime() - startTime) / 1000000;

+    long v2 = valTime / 1000000;

+    System.out.format("Test SZ: %d  SZp2: %d took %,d milliseconds%n", SZ, SZp2, v1);

+    System.out.format("val iter time: %,d insert/remove time: %,d%n", v2, v1 - v2);

+    

+//    Collections.sort(iterTimes,                 Comparator.comparingInt(Miter::getOuterIter)

+//                                 .thenComparing(Comparator.comparingLong(Miter::getTime).reversed()));

+//    

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

+//      Miter m = iterTimes.get(i);

+//      System.out.format("outer: %d, time: %,d inner: %,d itemNbr: %,d%n", m.outerIter, m.time, m.innerIter, m.itemNbr);

+//    }

+//    Miter m = iterTimes.get(99999);

+//    System.out.format("outer: %d, time: %,d inner: %,d itemNbr: %,d ref 99999%n", m.outerIter, m.time, m.innerIter, m.itemNbr);

+  }

+  

+  private void insert1(int iter) {

+    

+//    ir.removeAllIncludingSubtypes(topType);

+    for (int i = 0; i < SZ; i++) { ir.removeFS(as[i]); }

+    

+    add(3, SZ);    

+    ai.size();

+    

+    add(0, 3);

+    

+    ai.size();  // force batch add

+        

+    rr(0, 3, -1, -1);

+    rr(1, 3, -1, -1);

+        

+    for (int i = 0; i < 100_000; i++) {

+//      if (i % 1000 == 0) System.out.println("insert test iteration: " + i);

+      removeAndReinsertRandom(iter, i);

+//      if ((i % 100000) == 0) {

+//        System.out.println("random testing OrderedFsSet_array, count: " + i);

+//      }

+    }

+    

+//    System.out.println("debug");

+

+  }

+  

+  private void add(int ... is) {

+    for (int i : is) {

+      ir.addFS(as[i]);

+    }

+  }

+  

+  private void add(int start, int end) {

+    for (int i = start; i < end; i++) {

+      ir.addFS(as[i]);

+    }

+  }

+  

+  private void rmv(int ... is) {

+    for (int i : is) {

+      ir.removeFS(as[i]);

+    }

+  }

+  

+  private void rmv(int start, int end) {

+    for (int i = start; i < end; i++) {

+      ir.removeFS(as[i]);

+    }

+  }

+ 

+  private void removeAndReinsertRandom(int outer, int iteration) {

+    int n_remove = r.nextInt(SZ);

+    if (n_remove == 0) return; 

+//    System.out.println(n_remove);

+//    int[] rmvd_i = r.ints(0, SZ - 1).distinct().limit(n_remove).toArray();  // a java 8 construct

+    

+    rns = new int[SZ];

+    for (int i = 0; i < SZ; i++) { rns[i] = i; }

+    rns = shuffle(rns);

+    

+    int[] rmvd_i = new int[n_remove];

+    System.arraycopy(rns, 0, rmvd_i, 0, n_remove);

+    

+    int[] adds_i = shuffle(rmvd_i);

+    rr(rmvd_i, adds_i, outer, iteration);

+  }

+  

+  private void vall(int outerIter, int innerIter) {

+    long start = System.nanoTime();

+    FSIterator<Annotation> it = ai.iterator();

+   

+//    if (innerIter == 55555) {

+//      System.out.println("debug 55555");

+//    }

+

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

+      Annotation fs = as[i];

+//      startIter.get()[0] = innerIter > 10000 ? System.nanoTime() : -1;

+//      long iterStart = System.nanoTime();

+      it.moveTo(fs);

+//      long inter2 = System.nanoTime();

+//      long inter = inter2 - iterStart;

+//      if (innerIter == 55555) {

+//        System.out.format("moveTo for innerIter:         %,d item: %d took: %,5d %s%n", innerIter, i, inter, fs);

+//      }

+//      inter2 = System.nanoTime();

+      it.moveToPrevious();

+//      inter = System.nanoTime() - inter2;

+//      if (innerIter == 55555) {

+//        System.out.format("moveToPrevious for innerIter: %,d item: %d took: %,5d %s%n", innerIter, i, inter, fs);

+//      }

+//      if (innerIter > 10000) {

+//        iterTimes.add(new Miter(outerIter, innerIter, i, System.nanoTime() - startIter.get()[0]));

+//      }

+      if (it.isValid()) {

+        if (fs.getBegin() != it.get().getBegin() + 1) {

+          System.out.println("debug mismatch");

+          fail();

+        }

+      } else {

+        if (fs.getBegin() != 0) {

+          System.out.println("debug mismatch");

+          fail();

+        }

+      }

+    }

+    long inc = System.nanoTime() - start;

+    valTime += inc;

+    

+//    TOP[] cc = a.getInternalArrayDebug();

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

+//      if (cc[i] == null) {

+//        System.out.println("debug found null");

+//      }

+//    }    

+  }

+  

+  private void rr(int start, int end, int outerIter, int innerIter) {

+    rmv(start, end);

+    add(start, end);

+    ai.size();

+    vall(outerIter, innerIter);

+  }

+  

+  private void rr(int[] rmv, int[] add, int outerIter, int innerIter) {

+    for (int i : rmv) {

+      ir.removeFS(as[i]);

+    }

+    int splt = r.nextInt(add.length) + 1;

+    

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

+      ir.addFS(as[add[i]]);

+    }

+//    if (innerIter == 15) {

+//      System.out.println("debug");

+//    }

+    ai.size(); 

+    //debug

+

+    for (int i = splt; i < add.length; i++) {

+      ir.addFS(as[add[i]]);

+    }

+    ai.size();

+

+    vall(outerIter, innerIter);

+  }

+  

+  private int[] shuffle(int[] a) {

+    int[] b = a.clone();

+    for (int i = 0; i < b.length; i++) {

+      int j = r.nextInt(b.length);  

+      int tmp = b[i];

+      b[i] = b[j];

+      b[j] = tmp;

+    }

+    return b;

+  }

+

+}

diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/AnnotationIteratorTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/AnnotationIteratorTest.java
index d59f87b..6d292fd 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/AnnotationIteratorTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/AnnotationIteratorTest.java
@@ -30,7 +30,6 @@
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASException;
 import org.apache.uima.cas.CASRuntimeException;
-import org.apache.uima.cas.FSIndex;
 import org.apache.uima.cas.FSIndexRepository;
 import org.apache.uima.cas.FSIterator;
 import org.apache.uima.cas.Feature;
@@ -91,7 +90,7 @@
 
   private boolean isSave;
 
-  private List<AnnotationFS> fss;
+  private List<Annotation> fss;
 
   private List<Integer> fssStarts = new ArrayList<Integer>();
 
@@ -168,85 +167,32 @@
     this.endFeature = null;
     this.sentenceType = null;
   }
+  
+//  //debug
+//  // explore which isValid calls can be eliminated
+//  public void testIsValid() {
+//    int annotCount = setupTheCas();
+//    FSIndexRepository ir = this.cas.getIndexRepository();
+//    
+//    FSIterator<AnnotationFS> it = this.cas.getAnnotationIndex().iterator();
+//    it.moveToLast();
+//    int c = 0;
+//    while (it.hasPrevious()) {
+//      it.previous();
+//      c++;
+//    }
+//    System.out.println("debug count = " + c);
+//  }
+  
 
   public void testIterator1() {
-    
-    
-//   Tokens                +---+
-//                        +---+
-//                       +---+
-//   BigBound                      +-----------------------------+
-    final String text = "aaaa bbbb cccc dddd aaaa bbbb cccc dddd aaaa bbbb cccc dddd ";
-//                       +--------+
-//   Sentences                +--------+
-//                                 +----------+
-//
-//   bound4strict                   +------------------+            
-//   sentence4strict                 +-----------------------------+
-    
-    
-    try {
-      this.cas.setDocumentText(text);
-    } catch (CASRuntimeException e) {
-      fail();
-    }
-
-    /***************************************************
-     * Create and index tokens and sentences 
-     ***************************************************/
+    int annotCount = setupTheCas();
     FSIndexRepository ir = this.cas.getIndexRepository();
-    int annotCount = 1; // Init with document annotation.
-    // create token and sentence annotations
-    AnnotationFS fs;
-    for (int i = 0; i < text.length() - 5; i++) {
-      ++annotCount;
-      ir.addFS(fs = this.cas.createAnnotation(this.tokenType, i, i + 5));
-      if (showFSs) {
-        System.out.format("creating: %d begin: %d end: %d type: %s%n", annotCount, fs.getBegin(), fs.getEnd(), fs.getType().getName() );
-      }
-    }
-    // for (int i = 0; i < text.length() - 5; i++) {
-    // cas.getIndexRepository().addFS(cas.createAnnotation(tokenType, i, i+5));
-    // }
-    
-    // create overlapping sentences for unambigious testing
-    //   begin =  0,  5, 10, ...
-    //   end   = 10, 15, 20, ...
-    // non-overlapping:  0-10, 10-20, etc.
-    for (int i = 0; i < text.length() - 10; i += 5) {
-      ++annotCount;
-      ir.addFS(fs = this.cas.createAnnotation(this.sentenceType, i, i + 10));
-      if (showFSs) {
-        System.out.format("creating: %d begin: %d end: %d type: %s%n", annotCount, fs.getBegin(), fs.getEnd(), fs.getType().getName() );
-      }
-    }
-    
-    // create overlapping phrases
-    // begin =  0,  6,  10, 14, ...
-    // end   =  5,  9,  16, 19, ...
-    
-    int beginAlt = 0, endAlt = 0;
-    for (int i = 0; i < text.length() - 10; i += 5) {
-      ++annotCount;
-      ir.addFS(fs = this.cas.createAnnotation(this.phraseType,  i + beginAlt, i + 5 + endAlt));
-      beginAlt = (beginAlt == 1) ? -1 : beginAlt + 1;
-      endAlt = (endAlt == -1) ? 1 : endAlt - 1;
-      if (true ||showFSs) {
-        System.out.format("creating: %d begin: %d end: %d type: %s%n", annotCount, fs.getBegin(), fs.getEnd(), fs.getType().getName() );
-      }
-    }
-    
-    ++annotCount;
-    ir.addFS(fs = this.cas.createAnnotation(this.sentenceType,  12, 31));
-    if (showFSs) {
-      System.out.format("creating: %d begin: %d end: %d type: %s%n", annotCount, fs.getBegin(), fs.getEnd(), fs.getType().getName() );
-    }
-
 
     /***************************************************
      * iterate over them
      ***************************************************/
-    List fss = new ArrayList();
+    fss = new ArrayList<>();
     callCount = -1;
     iterateOverAnnotations(annotCount, fss); // annotCount is the total number of sentences and tokens
     
@@ -265,8 +211,8 @@
     ir.addFS(a2 = this.cas.createAnnotation(this.tokenType, 1, 6));
     a2.setStringValue(lemmaFeat, "lemma2");
     
-    FSIterator<AnnotationFS> it;
-    AnnotationIndex<AnnotationFS> tokenIndex = cas.getAnnotationIndex(tokenType);
+    FSIterator<Annotation> it;
+    AnnotationIndex<Annotation> tokenIndex = cas.getAnnotationIndex(tokenType);
     it = tokenIndex.subiterator(a1);
     assertCount("multi equal", 0, it);
     it = tokenIndex.subiterator(a1);
@@ -294,14 +240,14 @@
    * @param fss
    */
   // called twice, the 2nd time should be with flattened indexes (List fss non empty the 2nd time)
-  private void iterateOverAnnotations(int annotCount, List<AnnotationFS> fss) {
-    this.fss = fss;
+  private void iterateOverAnnotations(int annotCount, List<Annotation> afss) {
+    this.fss = afss;
     isSave = fss.size() == 0;
-    int count;
-    AnnotationIndex<AnnotationFS> annotIndex = this.cas.getAnnotationIndex();
-    AnnotationIndex<AnnotationFS> sentIndex = this.cas.getAnnotationIndex(sentenceType);
-    FSIterator<AnnotationFS> it = annotIndex.iterator(true);  // a normal "ambiguous" iterator
-    FSIterator<AnnotationFS> select_it = cas.<AnnotationFS>select().fsIterator();
+//    int count;
+    AnnotationIndex<Annotation> annotIndex = this.cas.getAnnotationIndex();
+    AnnotationIndex<Annotation> sentIndex = this.cas.getAnnotationIndex(sentenceType);
+    FSIterator<Annotation> it = annotIndex.iterator(true);  // a normal "ambiguous" iterator
+    FSIterator<Annotation> select_it = annotIndex.select().fsIterator();
 //    assertTrue((isSave) ? it instanceof FSIteratorWrapper : 
 //      FSIndexFlat.enabled ? it instanceof FSIndexFlat.FSIteratorFlat : it instanceof FSIteratorWrapper);   
     assertCount("Normal ambiguous annot iterator", annotCount, it);
@@ -309,20 +255,20 @@
     assertEquals(annotCount, select(annotIndex).toArray().length);  // stream op
     assertEquals(annotCount, select(annotIndex).asArray(Annotation.class).length);  // select op
     
-    AnnotationFS[] tokensAndSentences = select(annotIndex).asArray(AnnotationFS.class);
+    Annotation[] tokensAndSentences = annotIndex.select().asArray(Annotation.class);
     JCas jcas = null;
     try {
       jcas = cas.getJCas();
     } catch (CASException e) {
       assertTrue(false);
     }
-    FSArray fsa = FSArray.create(jcas, tokensAndSentences);
-    NonEmptyFSList fslhead = (NonEmptyFSList) FSList.createFromArray(jcas,  tokensAndSentences);
+    FSArray<Annotation> fsa = FSArray.create(jcas, tokensAndSentences);
+    NonEmptyFSList<Annotation> fslhead =  (NonEmptyFSList<Annotation>) FSList.<Annotation, Annotation>create(jcas,  tokensAndSentences);
     
-    select_it = fsa.<AnnotationFS>select().fsIterator();
+    select_it = fsa.select().fsIterator();
     assertCount("fsa ambiguous select annot iterator", annotCount, select_it);
 
-    select_it = fslhead.<AnnotationFS>select().fsIterator();
+    select_it = fslhead.<Annotation>select().fsIterator();
     assertCount("fslhead ambiguous select annot iterator", annotCount, select_it);
     
     // backwards
@@ -331,46 +277,46 @@
     
     it = annotIndex.iterator(false);  // false means create an unambiguous iterator
     assertCount("Unambiguous annot iterator", 1, it);  // because of document Annotation - spans the whole range
-    select_it = cas.<AnnotationFS>select().nonOverlapping().fsIterator();
+    select_it = annotIndex.select().nonOverlapping().fsIterator();
     assertCount("Unambiguous select annot iterator", 1, select_it);  // because of document Annotation - spans the whole range
-    select_it = cas.<AnnotationFS>select().nonOverlapping().backwards(true).fsIterator();
+    select_it = annotIndex.select().nonOverlapping().backwards(true).fsIterator();
     assertCount("Unambiguous select backwards annot iterator", 1, select_it);  // because of document Annotation - spans the whole range
     
     it = sentIndex.iterator(false);  //  false means create an unambiguous iterator
     assertCount("Unambigous sentence iterator", 5, it);
-    select_it = cas.<AnnotationFS>select(sentenceType).nonOverlapping(true).fsIterator();
+    select_it = annotIndex.select(sentenceType).nonOverlapping(true).fsIterator();
     assertCount("Unambigous select sentence iterator", 5, select_it);
-    select_it = sentIndex.<AnnotationFS>select().nonOverlapping().fsIterator();
+    select_it = sentIndex.select().nonOverlapping().fsIterator();
     assertCount("Unambigous select sentence iterator", 5, select_it);
-    select_it = select(sentIndex).nonOverlapping().fsIterator();
+    select_it = sentIndex.select().nonOverlapping().fsIterator();
     assertCount("Unambigous select sentence iterator", 5, select_it);
     
     
     AnnotationFS bigBound = this.cas.createAnnotation(this.sentenceType, 10, 41);
     it = annotIndex.subiterator(bigBound, true, true);  // ambiguous, and strict
     assertCount("Subiterator over annot with big bound, strict", 38, it);
-    select_it = cas.<AnnotationFS>select().coveredBy((Annotation) bigBound).includeAnnotationsWithEndBeyondBounds(false).fsIterator();
+    select_it = annotIndex.select().coveredBy((Annotation) bigBound).includeAnnotationsWithEndBeyondBounds(false).fsIterator();
     assertCount("Subiterator select over annot with big bound, strict", 38, select_it);
 
-    select_it = cas.<AnnotationFS>select().coveredBy(bigBound).limit(7).includeAnnotationsWithEndBeyondBounds().fsIterator();
+    select_it = annotIndex.select().coveredBy(bigBound).limit(7).includeAnnotationsWithEndBeyondBounds().fsIterator();
     assertCountLimit("Subiterator select limit 7 over annot with big bound, strict", 7, select_it);
     
-    FSIndex<Token> token_index = null;
     // uncomment these to check compile-time generic arguments OK
     // comment these out for running, because Token not a type
-//    FSIterator<Token> token_it = token_index.<Token>select().fsIterator();
-//    token_it = select(token_index).fsIterator();
-//    token_it = select(annotIndex, Token.class).fsIterator();
-//    FSIterator<Token> token_it = cas.select(Token.class).fsIterator();
-//    FSIterator<Token> token_it = token_index.select(Token.class).fsIterator();
+//    FSIndex<Token> token_index = annotIndex.subType(Token.class);
+//    token_index.select().fsIterator();
+//    select(token_index).fsIterator();
+//    annotIndex.select(Token.class).fsIterator();
+//    cas.select(Token.class).fsIterator();
+//    token_index.select(Token.class).fsIterator();
     
-    Object[] o = cas.<AnnotationFS>select().coveredBy(bigBound).skip(3).toArray();
+    Object[] o = annotIndex.select().coveredBy(bigBound).skip(3).toArray();
     assertEquals(35, o.length);
     
-    Object[] o1 = cas.<AnnotationFS>select().coveredBy(bigBound).toArray();
-    List<AnnotationFS> l2 = cas.<AnnotationFS>select().coveredBy(bigBound).backwards().asList();
-    Deque<AnnotationFS> l2r = new ArrayDeque<>();
-    for (AnnotationFS fs : l2) {
+    Object[] o1 = annotIndex.select().coveredBy(bigBound).toArray();
+    List<Annotation> l2 = annotIndex.select().coveredBy(bigBound).backwards().asList();
+    Deque<Annotation> l2r = new ArrayDeque<>();
+    for (Annotation fs : l2) {
       l2r.push(fs);
     }
     
@@ -378,9 +324,9 @@
     
     it = annotIndex.subiterator(bigBound, false, true);  // unambiguous, strict
     assertCount("Subiterator over annot unambiguous strict", 3, it);
-    select_it = cas.<AnnotationFS>select().coveredBy((Annotation) bigBound).includeAnnotationsWithEndBeyondBounds(false).nonOverlapping().fsIterator();
+    select_it = annotIndex.select().coveredBy((Annotation) bigBound).includeAnnotationsWithEndBeyondBounds(false).nonOverlapping().fsIterator();
     assertCount("Subiterator select over annot unambiguous strict", 3, select_it);
-    select_it = cas.<AnnotationFS>select().backwards().coveredBy((Annotation) bigBound).includeAnnotationsWithEndBeyondBounds(false).nonOverlapping().fsIterator();
+    select_it = annotIndex.select().backwards().coveredBy((Annotation) bigBound).includeAnnotationsWithEndBeyondBounds(false).nonOverlapping().fsIterator();
     assertCount("Subiterator select over annot unambiguous strict", 3, select_it);
 
 //    it = annotIndex.subiterator(bigBound, true, false);
@@ -395,7 +341,7 @@
     // covered by implies endWithinBounds
     select_it = select(annotIndex).coveredBy(bigBound).fsIterator();
     assertCount("Subiterator select over annot ambiguous strict", 38, select_it);
-    select_it = annotIndex.<AnnotationFS>select().coveredBy(bigBound).includeAnnotationsWithEndBeyondBounds(false).fsIterator();
+    select_it = annotIndex.select().coveredBy(bigBound).includeAnnotationsWithEndBeyondBounds(false).fsIterator();
     assertCount("Subiterator select over annot ambiguous strict", 38, select_it);
     select_it = select(annotIndex).coveredBy(bigBound).includeAnnotationsWithEndBeyondBounds(true).fsIterator();
     assertCount("Subiterator select over annot ambiguous not-strict", 46, select_it);
@@ -408,7 +354,7 @@
     AnnotationFS sent = this.cas.getAnnotationIndex(this.sentenceType).iterator().get();
     it = annotIndex.subiterator(sent, false, true);
     assertCount("Subiterator over annot unambiguous strict", 2, it);
-    select_it = annotIndex.<AnnotationFS>select().nonOverlapping().coveredBy(sent).fsIterator();
+    select_it = annotIndex.select().nonOverlapping().coveredBy(sent).fsIterator();
     assertCount("Subiterator select over annot unambiguous strict", 2, select_it);
     
     // strict skips first item
@@ -422,39 +368,39 @@
     
     // single, get, nullOK
          
-    assertTrue(cas.<AnnotationFS>select().nonOverlapping().get().getType().getShortName().equals("DocumentAnnotation"));
+    assertTrue(annotIndex.select().nonOverlapping().get().getType().getShortName().equals("DocumentAnnotation"));
     boolean x = false;
     try {
-      assertNull(cas.<AnnotationFS>select().nullOK(false).coveredBy(3, 3).get());
+      assertNull(annotIndex.select().nullOK(false).coveredBy(3, 3).get());
     } catch (CASRuntimeException e) {
       if (e.hasMessageKey(CASRuntimeException.SELECT_GET_NO_INSTANCES)) {
         x= true;
       }
     }
     assertTrue(x);
-    assertNull(cas.<AnnotationFS>select().coveredBy(3, 3).get());
-    assertNotNull(cas.<AnnotationFS>select().get(3));
-    assertNull(cas.<AnnotationFS>select().nullOK().coveredBy(3, 5).get(3));
+    assertNull(annotIndex.select().coveredBy(3, 3).get());
+    assertNotNull(annotIndex.select().get(3));
+    assertNull(annotIndex.select().nullOK().coveredBy(3, 5).get(3));
     x = false;
     try {
-      cas.<AnnotationFS>select().coveredBy(3, 5). get(3);
+      annotIndex.select().coveredBy(3, 5). get(3);
     } catch (CASRuntimeException e) {
       if (e.hasMessageKey(CASRuntimeException.SELECT_GET_NO_INSTANCES)) {
         x= true;
       }
     }
     assertTrue(x);
-    assertTrue(cas.<AnnotationFS>select().nonOverlapping().get().getType().getShortName().equals("DocumentAnnotation"));
+    assertTrue(annotIndex.select().nonOverlapping().get().getType().getShortName().equals("DocumentAnnotation"));
     
-    select_it = cas.<AnnotationFS>select().nonOverlapping().fsIterator(); 
+    select_it = annotIndex.select().nonOverlapping().fsIterator(); 
     assertCount("Unambiguous select annot iterator", 1, select_it);  // because of document Annotation - spans the whole range
-    select_it = cas.<AnnotationFS>select().nonOverlapping().backwards(true).fsIterator();
+    select_it = annotIndex.select().nonOverlapping().backwards(true).fsIterator();
     assertCount("Unambiguous select backwards annot iterator", 1, select_it);  // because of document Annotation - spans the whole range
-    assertNotNull(cas.<AnnotationFS>select().nonOverlapping().single());
+    assertNotNull(annotIndex.select().nonOverlapping().single());
 
     x = false;
     try {
-      cas.<AnnotationFS>select().coveredBy(3, 10).single();
+      annotIndex.select().coveredBy(3, 10).single();
     } catch (CASRuntimeException e) {
       if (e.hasMessageKey(CASRuntimeException.SELECT_GET_TOO_MANY_INSTANCES)) {
         x= true;
@@ -463,7 +409,7 @@
     assertTrue(x);
     x = false;
     try {
-      cas.<AnnotationFS>select().coveredBy(3, 10).singleOrNull();
+      annotIndex.select().coveredBy(3, 10).singleOrNull();
     } catch (CASRuntimeException e) {
       if (e.hasMessageKey(CASRuntimeException.SELECT_GET_TOO_MANY_INSTANCES)) {
         x= true;
@@ -472,39 +418,39 @@
     assertTrue(x);
     x = false;
     try {
-      cas.<AnnotationFS>select().coveredBy(3, 5).single();
+      annotIndex.select().coveredBy(3, 5).single();
     } catch (CASRuntimeException e) {
       if (e.hasMessageKey(CASRuntimeException.SELECT_GET_NO_INSTANCES)) {
         x= true;
       }
     }
     assertTrue(x);
-    cas.<AnnotationFS>select().coveredBy(3, 5).singleOrNull();
+    annotIndex.select().coveredBy(3, 5).singleOrNull();
     
     select_it = select(annotIndex).following(2, 39).limit(2).fsIterator();
     assertCountLimit("Following", 2, select_it);
     select_it = select(annotIndex).following(2, 39).backwards().limit(2).fsIterator();
     assertCountLimit("Following", 2, select_it);
     
-    select_it = fsa.<AnnotationFS>select(sentenceType).fsIterator();
+    select_it = fsa.select(sentenceType).fsIterator();
     assertCount("select source array", 21, select_it);
-    select_it = fslhead.<AnnotationFS>select(sentenceType).fsIterator();
+    select_it = fslhead.select(sentenceType).fsIterator();
     assertCount("select source array", 21, select_it);
     
     /** covering **/
-    cas.<AnnotationFS>select(sentenceType).covering(20, 30).forEachOrdered(f ->  
+    annotIndex.select(sentenceType).covering(20, 30).forEachOrdered(f ->  
         System.out.format("found fs start at %d end %d%n", Integer.valueOf(f.getBegin()), Integer.valueOf(f.getEnd())));
     
-    cas.<AnnotationFS>select(sentenceType).covering(15, 19).forEachOrdered(f ->  
+    annotIndex.select(sentenceType).covering(15, 19).forEachOrdered(f ->  
         System.out.format("covering 15, 19:   %s:%d   %d -  %d%n", f.getType().getShortName(), Integer.valueOf(f._id()), Integer.valueOf(f.getBegin()), Integer.valueOf(f.getEnd())));
 
-    cas.<AnnotationFS>select(sentenceType).covering(37, 39).forEachOrdered(f ->  
+    annotIndex.select(sentenceType).covering(37, 39).forEachOrdered(f ->  
         System.out.format("covering sentences 37, 39:   %s:%d   %d -  %d%n", f.getType().getShortName(), Integer.valueOf(f._id()), Integer.valueOf(f.getBegin()), Integer.valueOf(f.getEnd())));
 
-    cas.<AnnotationFS>select(phraseType).covering(15, 19).forEachOrdered(f ->  
+    annotIndex.select(phraseType).covering(15, 19).forEachOrdered(f ->  
        System.out.format("covering phrases 15, 19:   %s:%d   %d -  %d%n", f.getType().getShortName(), Integer.valueOf(f._id()), Integer.valueOf(f.getBegin()), Integer.valueOf(f.getEnd())));
 
-    cas.<AnnotationFS>select(phraseType).covering(37, 39).forEachOrdered(f ->  
+    annotIndex.select(phraseType).covering(37, 39).forEachOrdered(f ->  
        System.out.format("covering phrases 37, 39:   %s:%d   %d -  %d%n", f.getType().getShortName(), Integer.valueOf(f._id()), Integer.valueOf(f.getBegin()), Integer.valueOf(f.getEnd())));
 
   }
@@ -512,7 +458,7 @@
   private String flatStateMsg(String s) {
     return s + (isSave ? "" : " with flattened index");
   }
-  private void assertCount(String msg, int expected,  FSIterator<? extends AnnotationFS> it) {
+  private void assertCount(String msg, int expected,  FSIterator<? extends Annotation> it) {
     int fssStart = assertCountCmn(msg, expected, it);
     msg = flatStateMsg(msg);
     int count = expected;
@@ -521,6 +467,11 @@
       AnnotationFS posFs = fss.get(fssStart + (count >> 1));
 //      //debug
 //      System.out.println(posFs.toString());
+      
+      // debug
+       it.moveToLast();
+       it.next();
+       
        it.moveTo(posFs);
        assertEquals(msg, it.get().hashCode(), posFs.hashCode());
       
@@ -553,7 +504,7 @@
     assertEquals(msg, expected, count);
   }
   
-  private int assertCountCmn(String msg, int expected, FSIterator<? extends AnnotationFS> it) {
+  private int assertCountCmn(String msg, int expected, FSIterator<? extends Annotation> it) {
     msg = flatStateMsg(msg);
     int count = 0;
     callCount  ++;
@@ -565,7 +516,7 @@
     }
     while (it.isValid()) {
       ++count;
-      AnnotationFS fs = it.next();
+      Annotation fs = it.next();
       if (showFSs) {
         System.out.format("%d " + msg + " fs begin: %d end: %d type: %s%n", count, fs.getBegin(), fs.getEnd(), fs.getType().getName() );
       }
@@ -580,7 +531,7 @@
   }
   
     
-  private void assertCountLimit(String msg, int expected,  FSIterator<? extends AnnotationFS> it) {
+  private void assertCountLimit(String msg, int expected,  FSIterator<? extends Annotation> it) {
     assertCountCmn(msg, expected, it);
     it.moveToFirst();
     assertFalse(it.isValid());
@@ -600,7 +551,7 @@
     
     caughtException = false;
     try {
-    	AnnotationIndex<AnnotationFS> ai = this.cas.getAnnotationIndex(ts.getType(CASTestSetup.TOKEN_TYPE_TYPE));
+    	this.cas.getAnnotationIndex(ts.getType(CASTestSetup.TOKEN_TYPE_TYPE));
     } catch (CASRuntimeException e) {
     	caughtException = true;
     }
@@ -624,16 +575,17 @@
       this.cas.setDocumentText("Sentence A with no value. Sentence B with value 377.");
     } catch (CASRuntimeException e) {
       assertTrue(false);
-    }      
+    }   
+    AnnotationIndex<Annotation> ai = cas.getAnnotationIndex();
           
     cas.addFsToIndexes(cas.createAnnotation(this.sentenceType, 0, 25));
     cas.addFsToIndexes(cas.createAnnotation(this.sentenceType, 26, 52));
     cas.addFsToIndexes(cas.createAnnotation(this.tokenType, 48, 51));
-    AnnotationIndex<AnnotationFS> tokenIdx = cas.getAnnotationIndex(this.tokenType);
+    AnnotationIndex<Annotation> tokenIdx = cas.getAnnotationIndex(this.tokenType);
     
-    AnnotationIndex<AnnotationFS> si = cas.getAnnotationIndex(this.sentenceType);
-    for (AnnotationFS sa : si) {
-      FSIterator<AnnotationFS> ti2 = tokenIdx.subiterator(sa, false, false);
+//    AnnotationIndex<AnnotationFS> si = cas.getAnnotationIndex(this.sentenceType);
+    for (Annotation sa : ai.select(this.sentenceType)) {
+      FSIterator<Annotation> ti2 = tokenIdx.subiterator(sa, false, false);
       
       while (ti2.hasNext()) {
         AnnotationFS t = ti2.next();
@@ -641,11 +593,11 @@
       }
     }
 
-    SelectFSs<AnnotationFS> ssi = cas.getAnnotationIndex(this.sentenceType).select();
+    SelectFSs<Annotation> ssi = ai.select(this.sentenceType);
     
     for (AnnotationFS sa : ssi) {
     
-      FSIterator<AnnotationFS> ti2 = tokenIdx.<AnnotationFS>select()
+      FSIterator<Annotation> ti2 = tokenIdx.select()
           .coveredBy(sa).includeAnnotationsWithEndBeyondBounds(false).nonOverlapping().fsIterator();
       
       while (ti2.hasNext()) {
@@ -656,6 +608,83 @@
 
   }
 
+  private int setupTheCas() {
+    
+    
+//  Tokens                +---+
+//                       +---+
+//                      +---+
+//  BigBound                      +-----------------------------+
+   final String text = "aaaa bbbb cccc dddd aaaa bbbb cccc dddd aaaa bbbb cccc dddd ";
+//                      +--------+
+//  Sentences                +--------+
+//                                +----------+
+//
+//  bound4strict                   +------------------+            
+//  sentence4strict                 +-----------------------------+
+   
+   
+   try {
+     this.cas.setDocumentText(text);
+   } catch (CASRuntimeException e) {
+     fail();
+   }
+
+   /***************************************************
+    * Create and index tokens and sentences 
+    ***************************************************/
+   FSIndexRepository ir = this.cas.getIndexRepository();
+   int annotCount = 1; // Init with document annotation.
+   // create token and sentence annotations
+   AnnotationFS fs;
+   for (int i = 0; i < text.length() - 5; i++) {
+     ++annotCount;
+     ir.addFS(fs = this.cas.createAnnotation(this.tokenType, i, i + 5));
+     if (showFSs) {
+       System.out.format("creating: %d begin: %d end: %d type: %s%n", annotCount, fs.getBegin(), fs.getEnd(), fs.getType().getName() );
+     }
+   }
+   // for (int i = 0; i < text.length() - 5; i++) {
+   // cas.getIndexRepository().addFS(cas.createAnnotation(tokenType, i, i+5));
+   // }
+   
+   // create overlapping sentences for unambigious testing
+   //   begin =  0,  5, 10, ...
+   //   end   = 10, 15, 20, ...
+   // non-overlapping:  0-10, 10-20, etc.
+   for (int i = 0; i < text.length() - 10; i += 5) {
+     ++annotCount;
+     ir.addFS(fs = this.cas.createAnnotation(this.sentenceType, i, i + 10));
+     if (showFSs) {
+       System.out.format("creating: %d begin: %d end: %d type: %s%n", annotCount, fs.getBegin(), fs.getEnd(), fs.getType().getName() );
+     }
+   }
+   
+   // create overlapping phrases
+   // begin =  0,  6,  10, 14, ...
+   // end   =  5,  9,  16, 19, ...
+   
+   int beginAlt = 0, endAlt = 0;
+   for (int i = 0; i < text.length() - 10; i += 5) {
+     ++annotCount;
+     ir.addFS(fs = this.cas.createAnnotation(this.phraseType,  i + beginAlt, i + 5 + endAlt));
+     beginAlt = (beginAlt == 1) ? -1 : beginAlt + 1;
+     endAlt = (endAlt == -1) ? 1 : endAlt - 1;
+     if (showFSs) {
+       System.out.format("creating: %d begin: %d end: %d type: %s%n", annotCount, fs.getBegin(), fs.getEnd(), fs.getType().getName() );
+     }
+   }
+   
+   ++annotCount;
+   ir.addFS(fs = this.cas.createAnnotation(this.sentenceType,  12, 31));
+   if (showFSs) {
+     System.out.format("creating: %d begin: %d end: %d type: %s%n", annotCount, fs.getBegin(), fs.getEnd(), fs.getType().getName() );
+   }
+   
+   return annotCount;
+
+ }
+
   public static void main(String[] args) {
     AnnotationIteratorTest test = new AnnotationIteratorTest(null);
     test.run();
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/AnnotationTreeTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/AnnotationTreeTest.java
index 58d7a05..40bdd61 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/AnnotationTreeTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/AnnotationTreeTest.java
@@ -30,7 +30,10 @@
 import org.apache.uima.cas.impl.XCASDeserializer;
 import org.apache.uima.cas.text.AnnotationTreeNode;
 import org.apache.uima.resource.metadata.FsIndexDescription;
+import org.apache.uima.resource.metadata.TypePriorities;
+import org.apache.uima.resource.metadata.TypePriorityList;
 import org.apache.uima.resource.metadata.TypeSystemDescription;
+import org.apache.uima.resource.metadata.impl.TypePriorities_impl;
 import org.apache.uima.test.junit_extension.JUnitExtension;
 import org.apache.uima.util.CasCreationUtils;
 import org.apache.uima.util.XMLInputSource;
@@ -66,21 +69,27 @@
       // instantiate CAS to get type system. Also build style
       // map file if there is none.
       TypeSystemDescription tsDesc = (TypeSystemDescription) descriptor;
-      CAS cas = CasCreationUtils.createCas(tsDesc, null, new FsIndexDescription[0]);
+      
+      TypePriorities typePriorities = new TypePriorities_impl();
+      TypePriorityList priorityList = typePriorities.addPriorityList();
+      priorityList.addType("uima.cas.TOP");
+      priorityList.addType("uima.tcas.Annotation");
+      
+      CAS cas = CasCreationUtils.createCas(tsDesc, typePriorities, new FsIndexDescription[0]);
       SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
       XCASDeserializer xcasDeserializer = new XCASDeserializer(cas.getTypeSystem());
       File xcasFile = new File(xcasDir, sampleXcas1FileName);
       parser.parse(xcasFile, xcasDeserializer.getXCASHandler(cas));
       AnnotationTreeNode root = cas.getAnnotationIndex().tree(cas.getDocumentAnnotation())
-	  .getRoot();
+                           	  .getRoot();
       // There are 7 paragraph annotations in the CAS.
       assertTrue("There should be 7 paragraphs, but are: " + root.getChildCount(), root
-	  .getChildCount() == 7);
+                          	  .getChildCount() == 7);
       // The first paragraph contains 19 sentences, each subsequent one
       // contains only one sentence.
       assertTrue(root.getChild(0).getChildCount() == 19);
       for (int i = 1; i < root.getChildCount(); i++) {
-	assertTrue(root.getChild(i).getChildCount() == 1);
+        assertTrue(root.getChild(i).getChildCount() == 1);
       }
       // First sentence contains 8 tokens.
       assertTrue(root.getChild(0).getChild(0).getChildCount() == 8);
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/CASTestSetup.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/CASTestSetup.java
index ff235b4..184f346 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/CASTestSetup.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/CASTestSetup.java
@@ -108,6 +108,8 @@
   // Index name constants.
   public static final String ANNOT_SET_INDEX = "Annotation Set Index";
 
+  public static final String ANNOT_SET_INDEX_NO_TYPEORDER = "Annotation Set Index No Type Order";
+
   public static final String ANNOT_BAG_INDEX = "Annotation Bag Index";
 
   public static final String ANNOT_SORT_INDEX = "Annotation Sort Index";
@@ -197,7 +199,7 @@
     Type arrayOfIntArray = tsm.getArrayType(intArrayType);
   }
 
-  public void initIndexes(FSIndexRepositoryMgr irm, TypeSystem ts) {
+  private FSIndexComparator makeComp(FSIndexRepositoryMgr irm, TypeSystem ts) {
     FSIndexComparator comp = irm.createComparator();
     Type annotation = ts.getType(CAS.TYPE_NAME_ANNOTATION);
     comp.setType(annotation);
@@ -205,6 +207,12 @@
             FSIndexComparator.STANDARD_COMPARE);
     comp.addKey(annotation.getFeatureByBaseName(CAS.FEATURE_BASE_NAME_END),
             FSIndexComparator.REVERSE_STANDARD_COMPARE);
+    return comp;
+  }
+
+  public void initIndexes(FSIndexRepositoryMgr irm, TypeSystem ts) {
+    FSIndexComparator compNoTypeOrder = makeComp(irm, ts);
+    FSIndexComparator comp = makeComp(irm, ts);
     LinearTypeOrderBuilder tob = irm.createTypeSortOrder();
     try {
       tob.add(new String[] { CAS.TYPE_NAME_ANNOTATION, SENT_TYPE, TOKEN_TYPE });
@@ -215,6 +223,6 @@
     irm.createIndex(comp, ANNOT_BAG_INDEX, FSIndex.BAG_INDEX);
     irm.createIndex(comp, ANNOT_SET_INDEX, FSIndex.SET_INDEX);
     irm.createIndex(comp, ANNOT_SORT_INDEX, FSIndex.SORTED_INDEX);
-
+    irm.createIndex(compNoTypeOrder, ANNOT_SET_INDEX_NO_TYPEORDER, FSIndex.SET_INDEX);
   }
 }
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/CompleteSerializationTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/CompleteSerializationTest.java
index 5a97934..7015d0e 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/CompleteSerializationTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/CompleteSerializationTest.java
@@ -20,12 +20,24 @@
 package org.apache.uima.cas.test;
 
 import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.Feature;
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.Type;
 import org.apache.uima.cas.admin.CASMgr;
 import org.apache.uima.cas.impl.CASCompleteSerializer;
 import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.CasCompare;
+import org.apache.uima.cas.impl.LowLevelCAS;
+import org.apache.uima.cas.impl.LowLevelException;
 import org.apache.uima.cas.impl.Serialization;
+import org.apache.uima.internal.util.Int2ObjHashMap;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.cas.FSArray;
+import org.apache.uima.jcas.cas.TOP;
+import org.apache.uima.jcas.tcas.Annotation;
 import org.apache.uima.resource.metadata.impl.TypeSystemDescription_impl;
 import org.apache.uima.test.junit_extension.JUnitExtension;
+import org.apache.uima.util.AutoCloseableNoException;
 import org.apache.uima.util.CasCreationUtils;
 
 import junit.framework.TestCase;
@@ -80,6 +92,95 @@
       }
       assertTrue(cas.getTypeSystemMgr().getType(CASTestSetup.GROUP_1) != null);
       assertTrue(((CASImpl) newCas).isBackwardCompatibleCas());
+      boolean caught = false;
+      try {
+      ((LowLevelCAS)newCas).ll_enableV2IdRefs();
+      } catch (IllegalStateException e) {
+        caught = true;
+      }
+      assertTrue(caught);
+    } catch (Exception e) {
+      JUnitExtension.handleException(e);
+    }
+    
+
+  }
+
+  public void testSerializationV2IdRefs() throws Exception {
+    try (AutoCloseableNoException a = LowLevelCAS.ll_defaultV2IdRefs()){
+      CAS cas = null;
+      JCas jcas = null;
+      
+      try {
+        cas =  CASInitializer.initCas(new CASTestSetup(), null);
+        jcas = cas.getJCas();
+      } catch (Exception e) {
+        assertTrue(false);
+      }
+      cas.setDocumentText("Create the sofa for the inital view");
+      assertTrue(((CASImpl) cas).isBackwardCompatibleCas());
+      
+      Type t1 = cas.getTypeSystem().getType(CASTestSetup.ARRAYFSWITHSUBTYPE_TYPE);
+      Feature feat1 = t1.getFeatureByBaseName(CASTestSetup.ARRAYFSWITHSUBTYPE_TYPE_FEAT);
+
+
+      FSArray<FeatureStructure> fsa1 = new FSArray<>(jcas, 1);
+      FeatureStructure f1 = cas.createFS(t1);
+      f1.setFeatureValue(feat1, fsa1);
+
+      Annotation myAnnot = new Annotation(jcas);
+      
+      fsa1.set(0, myAnnot);
+
+      myAnnot = new Annotation(jcas);
+      int id = myAnnot._id();
+      myAnnot = new Annotation(jcas);
+      int id2 = myAnnot._id();
+      assertEquals(4, id2 - id);  // type code, sofa, begin, end
+            
+      CASCompleteSerializer ser = Serialization.serializeCASComplete((CASMgr)cas);
+
+      // deserialize into a new CAS with a type system that only contains the builtins
+      CAS newCas = CasCreationUtils.createCas(new TypeSystemDescription_impl(), null, null);
+
+      try {
+        Serialization.deserializeCASComplete(ser, (CASImpl) newCas);
+      } catch (Exception e) {
+        assertTrue(false);
+      }      
+      LowLevelCAS ll = newCas.getLowLevelCAS();
+      boolean caught = false;
+      try {
+      assertEquals(id, ll.ll_getFSForRef(id)._id());
+      } catch (LowLevelException e ) {
+        caught = true;
+      }
+      assertFalse(caught);
+      
+      CasCompare cc = new CasCompare((CASImpl)cas,  (CASImpl)newCas);
+      cc.compareIds(true);
+      assertTrue(cc.compareCASes());
+      
+      Serialization.deserializeCASComplete(ser, (CASImpl) newCas);     
+      assertEquals(id, ll.ll_getFSForRef(id)._id());
+      assertEquals(id2, ll.ll_getFSForRef(id2)._id());        
+      
+      assertEquals(id2, ll.ll_getFSForRef(id2)._id());        
+      assertTrue(((CASImpl) newCas).getTypeSystemMgr().getType(CASTestSetup.GROUP_1) != null);
+      assertTrue(((CASImpl) newCas).isBackwardCompatibleCas());
+      assertEquals("Create the sofa for the inital view", newCas.getDocumentText());
+
+      // make sure JCas can be created
+      newCas.getJCas();
+
+      // deserialize into newCas a second time (OF bug found 7/7/2006)
+      try {
+        Serialization.deserializeCASComplete(ser, (CASImpl) newCas);
+      } catch (Exception e) {
+        assertTrue(false);
+      }
+      assertTrue(((CASMgr)cas).getTypeSystemMgr().getType(CASTestSetup.GROUP_1) != null);
+      assertTrue(((CASImpl) newCas).isBackwardCompatibleCas());
     } catch (Exception e) {
       JUnitExtension.handleException(e);
     }
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/CrossAnnotation.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/CrossAnnotation.java
index 57daa3a..3a4cc7c 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/CrossAnnotation.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/CrossAnnotation.java
@@ -1,10 +1,30 @@
 
+/* Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
    
-/* Apache UIMA v3 - First created by JCasGen Fri Dec 16 10:23:12 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:06:27 EDT 2017 */
 
 package org.apache.uima.cas.test;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -16,8 +36,8 @@
 
 
 /** 
- * Updated by JCasGen Fri Dec 16 10:23:12 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
+ * Updated by JCasGen Sun Oct 08 19:06:27 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
  * @generated */
 public class CrossAnnotation extends Annotation {
  
@@ -52,7 +72,8 @@
 
 
   /* Feature Adjusted Offsets */
-  public final static int _FI_otherAnnotation = TypeSystemImpl.getAdjustedFeatureOffset("otherAnnotation");
+  private final static CallSite _FC_otherAnnotation = TypeSystemImpl.createCallSite(CrossAnnotation.class, "otherAnnotation");
+  private final static MethodHandle _FH_otherAnnotation = _FC_otherAnnotation.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -108,14 +129,14 @@
    * @generated
    * @return value of the feature 
    */
-  public Annotation getOtherAnnotation() { return (Annotation)(_getFeatureValueNc(_FI_otherAnnotation));}
+  public Annotation getOtherAnnotation() { return (Annotation)(_getFeatureValueNc(wrapGetIntCatchException(_FH_otherAnnotation)));}
     
   /** setter for otherAnnotation - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setOtherAnnotation(Annotation v) {
-    _setFeatureValueNcWj(_FI_otherAnnotation, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_otherAnnotation), v);
   }    
     
   }
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/FeatureStructureTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/FeatureStructureTest.java
index 3decd94..fbe4259 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/FeatureStructureTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/FeatureStructureTest.java
@@ -229,7 +229,7 @@
     fsl.addToIndexes(); // otherwise won't be replaced later
     
     Annotation token = this.cas.createFS(tokenType);
-    cas.setId2FSs(token);  
+    cas.setId2FSsMaybeUnconditionally(token);  
     
     // set up some refs; these must be updated if the type changes in a way to require a new FS
     fsa.set(0, token);   // set the 0th  element of a FS Array to point to the "token"
@@ -410,7 +410,7 @@
 			token.setFloatValue(this.sentLenFeat, 0.0f);
 		} catch (CASRuntimeException e) {
 			caughtExc = true;
-			assertTrue(e.getMessageKey().equals(CASRuntimeException.INAPPROP_FEAT));
+			assertTrue(e.getMessageKey().equals(CASRuntimeException.INAPPROP_RANGE));
 		}
 		assertTrue(caughtExc);
 		assertTrue(token.getFloatValue(this.tokenFloatFeat) == f);
@@ -611,14 +611,16 @@
 	public void testToString() {
 		FeatureStructure listFS = this.cas.createFS(this.neListType);
 		listFS.setFeatureValue(this.tlFeature, listFS);
-		// System.out.println(listFS.toString());
+		System.out.println("toString for fslist, tail -> node, head is null");
+		System.out.println(listFS.toString());
 
 		FeatureStructure value = this.cas.createFS(this.tokenType);
 		FeatureStructure newList = this.cas.createFS(this.neListType);
 		newList.setFeatureValue(this.tlFeature, listFS);
 		newList.setFeatureValue(this.hdFeature, value);
 		listFS.setFeatureValue(this.hdFeature, value);
-		// System.out.println("\n" + newList.toString());
+		System.out.println("toString for fslist, tail is prev, prev's head: new token, head is same as rpev's head");
+		System.out.println(newList.toString());
 	}
 
 	public static void main(String[] args) {
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/GetAllIndexedTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/GetAllIndexedTest.java
index 34d1ace..8dc26b9 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/GetAllIndexedTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/GetAllIndexedTest.java
@@ -21,6 +21,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Iterator;
 
 import org.apache.uima.UIMAFramework;
 import org.apache.uima.analysis_engine.AnalysisEngine;
@@ -29,6 +30,7 @@
 import org.apache.uima.cas.FeatureStructure;
 import org.apache.uima.cas.Type;
 import org.apache.uima.cas.TypeSystem;
+import org.apache.uima.jcas.cas.TOP;
 import org.apache.uima.resource.ResourceInitializationException;
 import org.apache.uima.resource.ResourceSpecifier;
 import org.apache.uima.test.junit_extension.JUnitExtension;
@@ -218,6 +220,8 @@
     assertNotNull(tokenType);
     FSIterator<FeatureStructure> tokenIter = this.cas.getIndexRepository().getAllIndexedFS(tokenType);
     assertFalse(tokenIter.hasNext());
+    Iterator<TOP> tokenIter2 = this.cas.getIndexedFSs(tokenType).iterator();
+    assertFalse( tokenIter2.hasNext());
   }
 
   public static void main(String[] args) {
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/GrowingTheCasTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/GrowingTheCasTest.java
index d3e6767..9c3cd8f 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/GrowingTheCasTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/GrowingTheCasTest.java
@@ -21,6 +21,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Iterator;
 import java.util.Properties;
 
 import org.apache.uima.UIMAFramework;
@@ -269,7 +270,8 @@
 }
 
   private void timeIt(int i) {
-    FSIterator<FeatureStructure> it = jcas.getIndexRepository().getAllIndexedFS(jcas.getCasType(Annotation.type));   
+//    FSIterator<FeatureStructure> it = jcas.getIndexRepository().getAllIndexedFS(jcas.getCasType(Annotation.type));   
+    Iterator<Annotation> it = jcas.getIndexedFSs(Annotation.class).iterator();    
     int c = 0;
     long startTime = System.nanoTime();
     while (it.hasNext()) {
@@ -279,7 +281,7 @@
       c ++;
     }
 //    if ((i % 2) == 0) {
-      System.out.format("%,d Moby * 10, nbr of annotations = %,d; took %,d microsec%n",
+      System.out.format("%,d Moby * 10, nbr of annotations = %,d; took %,d microsec to move iterator and count%n",
           i, c, (System.nanoTime() - startTime) / 1000);
 //    }
   }
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/IndexComparitorTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/IndexComparitorTest.java
index 7fb1ce6..af7ed5b 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/IndexComparitorTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/IndexComparitorTest.java
@@ -527,6 +527,36 @@
     }
 
   }
+  
+  /*
+   * test set index:
+   *   put the same FS (by set comparator) into type and typeSub1
+   *   See if index contains both
+   *      see if moveTo finds both
+   *      see if iterator returns both  
+   */
+  public void testSetUsesType() throws Exception {
+    cas.reset();
+    
+    ir.addFS(createFs(type1, 1, 1));
+    ir.addFS(createFs(type1Sub1, 1, 1));  // same fs keys, different type
+    FeatureStructure testprobe = createFs(type1Sub1, 1, 1);  // not in index, used only for key values
+    FeatureStructure testprobe2 = createFs(type1, 1, 1);
+    
+    assertEquals(2, sortedType1.size());
+    assertEquals(2, setType1.size());
+    
+    FSIterator<FeatureStructure> it = setType1.iterator();
+    it.moveTo(testprobe);
+    assertEquals("Type1", it.get().getType().getShortName());
+    it.moveTo(testprobe2);
+    assertEquals("Type1", it.get().getType().getShortName());
+    it.moveToFirst();
+    assertEquals("Type1", it.next().getType().getShortName());
+    assertEquals("Type1Sub1", it.next().getType().getShortName());
+    
+  }
+  
 
   // note: this test is here because the setup is done
   public void testProtectIndex() throws Exception {
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/IndexRepositoryTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/IndexRepositoryTest.java
index b1000f3..c8b47e7 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/IndexRepositoryTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/IndexRepositoryTest.java
@@ -132,6 +132,26 @@
     index = ir.getIndex(CASTestSetup.ANNOT_SORT_INDEX);
     assertEquals(2, index.size());
 
+    // Annotation is supertype of token
+    // test if set observes implicit key of type
+    Type annotType = this.typeSystem.getType(CAS.TYPE_NAME_ANNOTATION);
+    Feature annotBeginFeat = this.typeSystem.getFeatureByFullName(CAS.TYPE_NAME_ANNOTATION + ":begin");
+    cas.getIndexRepository().removeAllIncludingSubtypes(annotType);
+
+    FeatureStructure annotTypeFs3 = this.cas.createFS(annotType);
+    annotTypeFs3.setIntValue(annotBeginFeat, 17);
+
+    cas.addFsToIndexes(tokenTypeFs1);
+    cas.addFsToIndexes(annotTypeFs3);
+
+    index = ir.getIndex(CASTestSetup.ANNOT_SET_INDEX);
+    assertEquals(2, index.size());
+    
+    // shows type is implicit key for set compares
+    index = ir.getIndex(CASTestSetup.ANNOT_SET_INDEX_NO_TYPEORDER);
+    assertEquals(2, index.size());
+    
+
   }
   
   /**
@@ -213,7 +233,7 @@
     
     // warmup and jit
     long prev = Long.MAX_VALUE;
-    for (int i = 0; i < 10; i++) {
+    for (int i = 0; i < 5; i++) {
       cas.getIndexRepository().removeAllIncludingSubtypes(cas.getTypeSystem().getTopType());
       long t = timeAdd2Indexes(fsa, false);
       if (t < prev) {
@@ -223,7 +243,7 @@
     }
     
     prev = Long.MAX_VALUE;
-    for (int i = 0; i < 10; i++) {
+    for (int i = 0; i < 5; i++) {
       cas.getIndexRepository().removeAllIncludingSubtypes(cas.getTypeSystem().getTopType());
       long t = timeAdd2Indexes(fsa, true);
       if (t < prev) {
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/IteratorTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/IteratorTest.java
index 981b529..4ecd37f 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/IteratorTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/IteratorTest.java
@@ -50,6 +50,7 @@
 import org.apache.uima.internal.util.IntVector;
 import org.apache.uima.internal.util.MultiThreadUtils;
 import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.cas.TOP;
 import org.apache.uima.jcas.tcas.Annotation;
 import org.apache.uima.resource.ResourceInitializationException;
 import org.apache.uima.resource.ResourceSpecifier;
@@ -97,26 +98,33 @@
   private Type subsentenceType;
   
   private FSIndex<FeatureStructure> bagIndex;
+  /** ss means snapshot */
   private FSIndex<FeatureStructure> ssBagIndex;
   
   private FSIndex<FeatureStructure> setIndex;
+  /** ss means snapshot */
   private FSIndex<FeatureStructure> ssSetIndex;
 
   private FSIndex<FeatureStructure> sortedIndex;
+  /** ss means snapshot */
   private FSIndex<FeatureStructure> ssSortedIndex;
   
   private FSIndex<?> jcasBagIndex;
+  /** ss means snapshot */
   private FSIndex<?> jcasSsBagIndex;
   
   private FSIndex<?> jcasSetIndex;
+  /** ss means snapshot */
   private FSIndex<?> jcasSsSetIndex;
 
   private FSIndex<?> jcasSortedIndex;
+  /** ss means snapshot */
   private FSIndex<?> jcasSsSortedIndex;
   
   private JCas jcas;
 
   private FSIndex<FeatureStructure> wordSetIndex;
+  /** ss means snapshot */
   private FSIndex<FeatureStructure> ssWordSetIndex;
 
   private Feature wordFeat;
@@ -363,17 +371,27 @@
     this.cas.getIndexRepository().addFS(
         this.cas.createAnnotation(this.annotationType, i * 2, (i * 2) + 1));
     this.cas.getIndexRepository().addFS(
-        this.cas.createAnnotation(this.sentenceType, i * 2, (i * 2) + 1));
+        this.cas.createAnnotation(this.sentenceType,   i * 2, (i * 2) + 1));
     this.cas.getIndexRepository().addFS(
-        fsi = (FeatureStructureImplC) this.cas.createAnnotation(this.tokenType, i * 2, (i * 2) + 1));
+      fsi = 
+        this.cas.createAnnotation(this.tokenType,      i * 2, (i * 2) + 1));
     this.cas.getIndexRepository().addFS(
-        this.cas.createAnnotation(this.tokenType, i * 2, (i * 2) + 1));
+        this.cas.createAnnotation(this.tokenType,      i * 2, (i * 2) + 1));
     this.cas.getIndexRepository().addFS(
-        this.cas.createAnnotation(this.tokenType, i * 2, (i * 2) + 1));
+        this.cas.createAnnotation(this.tokenType,      i * 2, (i * 2) + 1));
 //    //debug
 //    System.out.format("Token at %,d %n", fsi.getAddress());
   }
   
+  private void createFSsU() {
+    this.cas.getIndexRepository().removeAllIncludingSubtypes(TOP.class);
+    
+    for (int i = 0; i < 5; i++) {
+      this.cas.getIndexRepository().addFS(
+         this.cas.createAnnotation(this.annotationType, i * 2, (i * 2) + 1));
+    }  
+  }
+  
 //  private void debugls() {
 //    LowLevelIndexRepository llir = this.cas.ll_getIndexRepository();
 //    LowLevelIndex setIndexForType = llir.ll_getIndex(CASTestSetup.ANNOT_SET_INDEX, ((TypeImpl)tokenType).getCode());
@@ -383,11 +401,13 @@
 //  }
   
   private void setupFSs() {
+    this.cas.getIndexRepository().removeAllIncludingSubtypes(TOP.class);
+
     for (int i = 0; i < 10; i++) {
-      createFSs(i);
+      createFSs(i);  // i = 0 .. 9, 5 annot per: annotation, sentence, token, token, token
     }
     for (int i = 19; i >= 10; i--) {
-      createFSs(i);
+      createFSs(i);  // i = 19 .. 10 5 annot per: annotation, sentence, token, token, token
     }
   }
   
@@ -485,20 +505,38 @@
    
     
     // /////////////////////////////////////////////////////////////////////////
-    // Test fast fail.
+    // Test fast fail. - uima v3 doesn't throw ConcurrentModificationException
 
-    fastFailTst(setIndex, true);
-    fastFailTst(ssSetIndex, false);
+//    fastFailTst(setIndex, true);
+//    fastFailTst(ssSetIndex, false);
+//    
+//    fastFailTst(bagIndex, true);
+//    fastFailTst(ssBagIndex, false);
+//   
+//    fastFailTst(sortedIndex, true);  
+//    fastFailTst(ssSortedIndex, false);
+
+    /**
+     * Test copy-on-write - 
+     *   insure that index mods are ignored in normal iteration
+     *   insure that index mods are picked up for moveTo, moveToFirst, moveToLast
+     */
+
     
-    fastFailTst(bagIndex, true);
-    fastFailTst(ssBagIndex, false);
+    createFSsU();
+    
+    cowTst(setIndex, true);
+    cowTst(ssSetIndex, false);
+    
+    cowTst(bagIndex, true);
+    cowTst(ssBagIndex, false);
    
-    fastFailTst(sortedIndex, true);  
-    fastFailTst(ssSortedIndex, false);
+    cowTst(sortedIndex, true);  
+    cowTst(ssSortedIndex, false);
     
 //    debugls();  //debug
     
-    
+    setupFSs();
 
     // Test find()
     setupWords();
@@ -699,6 +737,62 @@
     assertEquals(end, a.getEnd());
   }
   
+
+  /**
+   * 
+   * @param index - the index to manipulate
+   * @param isCow - false for "snapshot" indexes - these don't do cow (copy on write) things
+   */
+  private void cowTst(FSIndex<FeatureStructure> index, boolean isCow) {
+    LowLevelIterator<FeatureStructure> it = (LowLevelIterator)index.iterator();
+    it.moveToLast();
+    it.moveToFirst();
+    // moved to first, 2.7.0, because new bag iterator is more forgiving re concurrentmodexception
+    FeatureStructure a = it.get();
+    
+    cas.removeFsFromIndexes(a);
+    it.next();  
+    it.previous();
+    assertTrue(it.get() == a);  // gets the removed one
+    it.moveToFirst();  // resets cow, does nothing for snapshot
+    assertTrue(isCow ? (it.get() != a)
+                     : (it.get() == a));
+        
+    cas.addFsToIndexes(a);
+    it.moveToLast();
+    a = it.get();
+    
+    cas.removeFsFromIndexes(a);
+    it.previous();
+    it.next();
+    assertTrue(0 == index.compare(it.get(), a));
+    it.moveToLast();
+    assertTrue(isCow ? (it.get() != a)
+                     : (it.get() == a));
+
+    cas.addFsToIndexes(a);  // index mod causes cow to copy, and index wr_cow to be set to null
+    it.moveToFirst();  // moveToFirst -> maybeReinitIterator (if cow is copy), new cow, index wr_cow refs it
+        
+    it.moveToNext();
+    
+    a = it.get();
+    
+    cas.removeFsFromIndexes(a); // resets wr_cow to null for assoc. index, because it now ref-ng copy
+    it.previous();
+    it.isValid();
+    it.next();
+    assertTrue(it.get() == a);  // gets the removed one
+    it.moveTo(a);  // causes COW reset, a is not present (has been removed)
+//    if (isCow && index == setIndex || index == bagIndex) {
+//      assertFalse(it.isValid());  // moveTo on set with no match gives invalid iterator  
+//    } else {      
+      assertTrue(isCow 
+                  ? (it.isMoveToSupported() ? it.get() != a : true)
+                   : (it.get() == a));
+//    }
+    cas.addFsToIndexes(a);  // add it back for subsequent tests
+  }
+  
   private void fastFailTst(FSIndex<FeatureStructure> index, boolean isShouldFail) {
     FSIterator<FeatureStructure> it = index.iterator();
     it.moveToLast();
@@ -722,7 +816,7 @@
     } catch (ConcurrentModificationException e) {
       ok = true;
     }
-    assertTrue(isShouldFail ? ok : !ok);
+     assertTrue(isShouldFail ? ok : !ok);
     
     it.moveTo(a);  // should reset concurrent mod, 
     ok = true;
@@ -1053,6 +1147,9 @@
     for (int i = 0; i < fsArray.length; i++) {
       ir.removeFS(fsArray[i]);
       ir.removeFS(fsArray[i]);  // a 2nd remove should be a no-op https://issues.apache.org/jira/browse/UIMA-2934
+      
+      // due to copy on write, need a new instance of set_iterator
+      set_iterator = setIndex.iterator();
       set_iterator.moveTo(fsArray[i]);
       if (set_iterator.isValid()) {
         int oldRef = this.cas.ll_getFSRef(fsArray[i]);
@@ -1060,8 +1157,16 @@
         assertTrue(oldRef != newRef);
         assertTrue(!set_iterator.get().equals(fsArray[i]));
       }
+      
+   // due to copy on write, need a new instance of set_iterator
+      bagIt = bagIndex.iterator();
+//      assertFalse(bagIt.hasNext());  // invalid test: removing one item from a bag index doesn't remove the "last" element.
+      assertEquals(99, bagIndex.size());
       bagIt.moveTo(fsArray[i]);
-      assertFalse(bagIt.hasNext());
+      assertFalse(bagIt.isValid());
+      
+      // due to copy on write, need a new instance of set_iterator
+      sortedIt = sortedIndex.iterator();      
       sortedIt.moveTo(fsArray[i]);
       if (sortedIt.isValid()) {
         assertTrue(!sortedIt.get().equals(fsArray[i]));
@@ -1073,10 +1178,19 @@
       ir.removeFS(fsArray[i]);
     }
     // All iterators should be invalidated when being reset.
+    
+    // due to copy on write, need a new instance of set_iterator
+    bagIt = bagIndex.iterator();
     bagIt.moveToFirst();
     assertFalse(bagIt.isValid());
+    
+    // due to copy on write, need a new instance of set_iterator
+    set_iterator = setIndex.iterator();
     set_iterator.moveToFirst();
     assertFalse(set_iterator.isValid());
+
+    // due to copy on write, need a new instance of set_iterator
+    sortedIt = sortedIndex.iterator();      
     sortedIt.moveToFirst();
     assertFalse(sortedIt.isValid());
   }
@@ -1129,28 +1243,38 @@
     verifyMoveToFirst(subsortedIt, true);
     
     // copy on write should prevent any change
-    assertEquals(182, ((LowLevelIterator<FeatureStructure>)setIt).ll_indexSize());
-    assertEquals(200, ((LowLevelIterator<FeatureStructure>)bagIt).ll_indexSize());
-    assertEquals(200, ((LowLevelIterator<AnnotationFS>)sortedIt).ll_indexSize());
-    assertEquals(91,  ((LowLevelIterator<FeatureStructure>)subsetIt).ll_indexSize());
-    assertEquals(100, ((LowLevelIterator<FeatureStructure>)subbagIt).ll_indexSize());
-    assertEquals(100, ((LowLevelIterator<AnnotationFS>)subsortedIt).ll_indexSize());
+    assertEquals(182, ((LowLevelIterator<FeatureStructure>)setIt).ll_indexSizeMaybeNotCurrent());
+    assertEquals(200, ((LowLevelIterator<FeatureStructure>)bagIt).ll_indexSizeMaybeNotCurrent());
+    assertEquals(200, ((LowLevelIterator<AnnotationFS>)sortedIt).ll_indexSizeMaybeNotCurrent());
+    assertEquals(91,  ((LowLevelIterator<FeatureStructure>)subsetIt).ll_indexSizeMaybeNotCurrent());
+    assertEquals(100, ((LowLevelIterator<FeatureStructure>)subbagIt).ll_indexSizeMaybeNotCurrent());
+    assertEquals(100, ((LowLevelIterator<AnnotationFS>)subsortedIt).ll_indexSizeMaybeNotCurrent());
 
     ir.removeAllIncludingSubtypes(sentenceType);
+
+    assertEquals(182, ((LowLevelIterator<FeatureStructure>)setIt).ll_indexSizeMaybeNotCurrent());
+    assertEquals(200, ((LowLevelIterator<FeatureStructure>)bagIt).ll_indexSizeMaybeNotCurrent());
+    assertEquals(200, ((LowLevelIterator<AnnotationFS>)sortedIt).ll_indexSizeMaybeNotCurrent());
+    assertEquals(91,  ((LowLevelIterator<FeatureStructure>)subsetIt).ll_indexSizeMaybeNotCurrent());
+    assertEquals(100, ((LowLevelIterator<FeatureStructure>)subbagIt).ll_indexSizeMaybeNotCurrent());
+    assertEquals(100, ((LowLevelIterator<AnnotationFS>)subsortedIt).ll_indexSizeMaybeNotCurrent());
     
-    assertEquals(182, ((LowLevelIterator<FeatureStructure>)setIt).ll_indexSize());
-    assertEquals(200, ((LowLevelIterator<FeatureStructure>)bagIt).ll_indexSize());
-    assertEquals(200, ((LowLevelIterator<AnnotationFS>)sortedIt).ll_indexSize());
-    assertEquals(91,  ((LowLevelIterator<FeatureStructure>)subsetIt).ll_indexSize());
-    assertEquals(100, ((LowLevelIterator<FeatureStructure>)subbagIt).ll_indexSize());
-    assertEquals(100, ((LowLevelIterator<AnnotationFS>)subsortedIt).ll_indexSize());
-    
-    verifyConcurrantModificationDetected(setIt);
-    verifyConcurrantModificationDetected(bagIt);
-    verifyConcurrantModificationDetected(sortedIt);
-    verifyConcurrantModificationDetected(subsetIt);
-    verifyConcurrantModificationDetected(subbagIt);
-    verifyConcurrantModificationDetected(subsortedIt);
+    // skip - no concurrent mod
+//    verifyConcurrantModificationDetected(setIt);  
+//    verifyConcurrantModificationDetected(bagIt);
+//    verifyConcurrantModificationDetected(sortedIt);
+//    verifyConcurrantModificationDetected(subsetIt);
+//    verifyConcurrantModificationDetected(subbagIt);
+//    verifyConcurrantModificationDetected(subsortedIt);
+
+    // due to copy on write, need to get new iterators
+    setIt = setIndex.iterator();
+    bagIt = bagIndex.iterator();
+    sortedIt = sortedIndex.iterator();
+
+    subsetIt = subsetIndex.iterator();
+    subbagIt = subbagIndex.iterator();
+    subsortedIt = subsortedIndex.iterator();
 
     verifyMoveToFirst(setIt, false);
     verifyMoveToFirst(bagIt, false);
@@ -1166,6 +1290,15 @@
       ir.addFS(fs);
     }
 
+    // due to copy on write, need to get new iterators
+    setIt = setIndex.iterator();
+    bagIt = bagIndex.iterator();
+    sortedIt = sortedIndex.iterator();
+
+    subsetIt = subsetIndex.iterator();
+    subbagIt = subbagIndex.iterator();
+    subsortedIt = subsortedIndex.iterator();
+
     verifyMoveToFirst(setIt, true);
     verifyMoveToFirst(bagIt, true);
     verifyMoveToFirst(sortedIt, true);
@@ -1175,6 +1308,15 @@
 
     ir.removeAllExcludingSubtypes(this.sentenceType);
     
+    // due to copy on write, need to get new iterators
+    setIt = setIndex.iterator();
+    bagIt = bagIndex.iterator();
+    sortedIt = sortedIndex.iterator();
+
+    subsetIt = subsetIndex.iterator();
+    subbagIt = subbagIndex.iterator();
+    subsortedIt = subsortedIndex.iterator();
+    
     verifyHaveSubset(setIt, 91, subsentenceType);
     verifyHaveSubset(bagIt, 100, subsentenceType);
     verifyHaveSubset(sortedIt, 100, subsentenceType);
@@ -1188,6 +1330,15 @@
     
     ir.removeAllExcludingSubtypes(subsentenceType);
 
+    // due to copy on write, need to get new iterators
+    setIt = setIndex.iterator();
+    bagIt = bagIndex.iterator();
+    sortedIt = sortedIndex.iterator();
+
+    subsetIt = subsetIndex.iterator();
+    subbagIt = subbagIndex.iterator();
+    subsortedIt = subsortedIndex.iterator();
+
     verifyHaveSubset(setIt, 91, sentenceType);
     verifyHaveSubset(bagIt, 100, sentenceType);
     verifyHaveSubset(sortedIt, 100, sentenceType);
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/IteratorTestSorted.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/IteratorTestSorted.java
new file mode 100644
index 0000000..7268531
--- /dev/null
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/IteratorTestSorted.java
@@ -0,0 +1,354 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+package org.apache.uima.cas.test;

+

+import java.util.ArrayList;

+import java.util.Random;

+

+import org.apache.uima.cas.CASException;

+import org.apache.uima.cas.FSIterator;

+import org.apache.uima.cas.admin.CASFactory;

+import org.apache.uima.cas.admin.FSIndexRepositoryMgr;

+import org.apache.uima.cas.impl.CASImpl;

+import org.apache.uima.cas.impl.FsIndex_annotation;

+import org.apache.uima.cas.impl.LowLevelIterator;

+import org.apache.uima.cas.impl.TypeImpl;

+import org.apache.uima.cas.impl.TypeSystemImpl;

+import org.apache.uima.jcas.JCas;

+import org.apache.uima.jcas.cas.TOP;

+

+import junit.framework.AssertionFailedError;

+import junit.framework.TestCase;

+

+/**

+ * Test many variations of rattling iterators (sorted)

+ * 

+ * Types arranged in levels, Annotation at top, Level_2, Level_3, etc. inheriting to the left

+ * 

+ * Total number of levels: more than 3 (for sorted part of rattler), something like 5 or 6

+ * 

+ * NBR_INSTANCES instances per level.

+ * 

+ * Levels may be skipped.

+ * 

+ * FSs scattered among levels.  

+ * 

+ * Each FS: has simple incrementing begin / end (or not - for testing equality operations)

+ * 

+ * Movement alternatives:

+ *   at start, move to first/last/FS template.  

+ *   move from arbitrary starting spot to end (detect end, don't move past), 

+ *     then reverse to beginning.

+ *     -- or reverse of above.

+ *     

+ * validation: incremental moves: check next id is sequentially +- 1.

+ * need map from begin to left-most FS of equal set, for testing moveTo.

+ * need to record 1st and last id.

+ * validate leftmost for moveTo

+ * 

+ * Variations:  

+ *   number of levels, 

+ *   levels that are "skipped"

+ *   adding random new elements while iterating, then moveTo

+ *   

+ *    

+ * 

+ */

+public class IteratorTestSorted extends TestCase {

+  static final int REPETITIONS = // 100_000_000; 1000 secs = 17 min

+                                  100_000;  // 1 second + startup time ~ .8 sec

+  static final int NBR_FSS_PER_LEVEL = 5;

+  static final int MAX_LEVELS = 6;  // max is 6 unless adding to the types and JCas class for them

+  

+  JCas jcas;

+  

+  Level_1 firstItem;

+  Level_1 lastItem;

+  int maxBegin;

+  int firstBegin;

+  boolean isWithoutTypeOrder;

+  

+  final ArrayList<Integer> levels = new ArrayList<>();

+  FSIterator<Level_1> it;

+  

+  final static Random r = new Random();

+  final static long seed = r.nextLong();

+//      6658836455455474098L;

+//  4811614709790403903L;

+  static {

+    r.setSeed(seed);

+    System.out.println("Iterator Test Sorted, random seed = " + seed); 

+  }

+    

+  public void setUp() {

+    CASImpl casMgr = (CASImpl) CASFactory.createCAS();

+    TypeSystemImpl tsi = (TypeSystemImpl) casMgr.getTypeSystemMgr();

+    TypeImpl level_1_type = tsi.addType("org.apache.uima.cas.test.Level_1", tsi.annotType);

+    tsi.addFeature("id", level_1_type, tsi.floatType);

+    TypeImpl level_2_type = tsi.addType("org.apache.uima.cas.test.Level_2",  level_1_type);

+    TypeImpl level_3_type = tsi.addType("org.apache.uima.cas.test.Level_3",  level_2_type);

+    TypeImpl level_4_type = tsi.addType("org.apache.uima.cas.test.Level_4",  level_3_type);

+    TypeImpl level_5_type = tsi.addType("org.apache.uima.cas.test.Level_5",  level_4_type);

+    TypeImpl level_6_type = tsi.addType("org.apache.uima.cas.test.Level_6",  level_5_type);

+    

+    casMgr.commitTypeSystem();

+    try {

+      FSIndexRepositoryMgr irm = casMgr.getIndexRepositoryMgr();

+      casMgr.initCASIndexes();

+      irm.commit();

+      

+      jcas = casMgr.getCurrentView().getJCas();

+    } catch (CASException e) {

+      e.printStackTrace();

+      fail();

+    }

+  }

+  

+  public void tearDown() {

+    

+  }

+  

+ 

+  public IteratorTestSorted(String arg) {

+    super(arg);

+  }

+  

+  public void testIterator() {

+    

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

+      try {

+      if (0 == i % 100000) {

+        long seed2 =   r.nextLong();

+//              5680709196975735850L;

+        

+//            -4764445956829722324L;

+//            2151669209502835073L;

+        System.out.format("iteration: %,d seed: %d%n", i, seed2);

+        r.setSeed(seed2);

+        jcas.reset();  // every so often.  got a fs id internal value overflow after looping 45 million times.

+      }

+      jcas.removeAllIncludingSubtypes(TOP.type);

+      makeFSs(r.nextInt(MAX_LEVELS - 1) + 2);  // 2 - 6

+      it = ((FsIndex_annotation)jcas.getAnnotationIndex(Level_1.class)).iterator(LowLevelIterator.IS_ORDERED, isWithoutTypeOrder = r.nextBoolean());

+      if ( ! isWithoutTypeOrder) {

+        firstItem = it.get();

+        firstItem.setId(0.0f);

+      }

+      validate();

+      

+      // current design only allows one of the next two

+      if (r.nextBoolean()) {

+        addRandomFs(randomLevel());    

+        validate();

+      } else {      

+        if (addRandomFsInUnusedType()) {

+          validate();

+        }

+      }

+      } catch (AssertionFailedError | IllegalArgumentException e) {

+        System.err.format("exception, i = %,d%n", i);

+        throw e;

+      }

+    }

+  }

+  

+  private void validate() {

+    it.moveToFirst(); 

+    verifyFirst();

+    it.moveToLast();

+    verifyLast();

+    it.moveTo(randomSpot());

+    verifyLeftmost();

+    

+    if (r.nextBoolean()) {

+      verifySeqToEnd();

+      verifySeqToBegin();

+    } else {

+      verifySeqToBegin();

+      verifySeqToEnd();

+    }    

+  }

+  

+  private boolean addRandomFsInUnusedType() {

+    if (levels.size() < MAX_LEVELS) {

+      int unused;

+      while (true) {

+        if (levels.contains(unused = r.nextInt(MAX_LEVELS))) {

+          break;

+        }

+      }

+      // unused in an index not currently used

+      addRandomFs(unused);

+      return true;

+    }

+    return false;

+  }

+  

+  private void addRandomFs(int level_to_make) {

+    it.moveTo(randomSpot());

+    int begin = it.getNvc().getBegin();

+    // it is at leftmost item with begin value.

+    float so = it.getNvc().getId();

+    // make a new fs, just before this begin  

+    Level_1 fs = makeLevel(level_to_make, begin - 1, so - 0.1f);

+    if (Float.compare(0.0f, so) == 0) {

+      firstItem = fs;

+    }

+  }

+    

+  

+  private Level_1 randomSpot() {

+    return makeLevel_inner(0, r.nextInt(maxBegin + 1));  // between 0 and maxBegin

+  }

+  

+  private void verifyFirst() {

+    if (isWithoutTypeOrder) {

+      assertTrue(it.get() == firstItem);  

+    } else {

+      assertTrue(it.get().getBegin() == firstItem.getBegin());  // because typepriority sort order

+    }

+  }

+  

+  private void verifyLast() {

+    if (isWithoutTypeOrder) {

+      assertTrue(it.get() == lastItem);  

+    } else {

+      assertTrue(it.get().getBegin() == lastItem.getBegin());  // because typepriority sort order

+    }

+  }

+  

+  private void verifyLeftmost() {

+    Level_1 item = it.get();

+//    if (item != firstItem) {

+    it.moveToPreviousNvc();

+    if (it.isValid()) {

+      if (it.get().getBegin() == item.getBegin()) {

+        fail();

+      }

+    } else {

+      it.moveToFirst();

+    }

+  }

+  

+  private void verifySeqToEnd() {

+    Level_1 prev = it.get();

+    while (true) {

+      it.moveToNextNvc();

+      if (!it.isValid()) {

+        it.moveToLast();

+        break;

+      }

+      if (isWithoutTypeOrder) {

+        assertTrue(it.getNvc().getId() > prev.getId());

+      }

+      validateEqualOrdering(prev, it.getNvc());

+      prev = it.getNvc();

+    }

+  }

+  

+  private void validateEqualOrdering(Level_1 before, Level_1 after) {

+    if (before.getBegin() == after.getBegin() &&

+        before.getEnd() == after.getEnd()) {

+      if (before._getTypeImpl() == after._getTypeImpl() || isWithoutTypeOrder) {

+        assertTrue(before._id() < after._id());

+      }

+    }

+  }

+  

+  private void verifySeqToBegin() {

+    Level_1 prev = it.get();

+    while (true) {

+      it.moveToPreviousNvc();

+      if (! it.isValid()) {

+        it.moveToFirst();

+        break;

+      }

+      if (isWithoutTypeOrder) {

+        assertTrue(it.getNvc().getId() < prev.getId());

+      }

+      validateEqualOrdering(it.getNvc(), prev);

+      prev = it.getNvc();

+    }

+  }

+

+  

+  /**

+   * Make a random collection of FSs to iterate over

+   *   Random order among types/subtypes

+   *     random number of types/subtypes used, from 2 - 6

+   *     if number of types < max, the type(s) omitted chosen randomly

+   *   Random creation of equals fss to check moving to "leftmost"

+   *   

+   * @param lvls

+   */

+  void makeFSs(int lvls) {

+    int begin = 0;

+    

+    int totNbr = NBR_FSS_PER_LEVEL * lvls;

+    levels.clear();

+    for (int i = 0; i < MAX_LEVELS; i++) levels.add(i);

+    for (int i = MAX_LEVELS - lvls; i > 0; i--) levels.remove(randomLevel_index());

+

+    float sortOrder = 0;

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

+      int lastBegin = begin;

+

+      if (r.nextBoolean()) {  // make 50% equal fss

+        begin ++;

+      }

+      

+      Level_1 fs = makeLevel(randomLevel(), begin, sortOrder++);

+      if (i == 0) {

+        firstItem = fs;

+        firstBegin = begin;  // 0 or 1

+      }

+      if (i == totNbr - 1) {

+        lastItem = fs;

+        maxBegin = lastBegin;

+      }

+    }

+  }

+  

+  Level_1 makeLevel_inner(int level, int begin) {

+    switch (level) {

+    case 0: return new Level_1(jcas, begin, 0);

+    case 1: return new Level_2(jcas, begin, 0);

+    case 2: return new Level_3(jcas, begin, 0);

+    case 3: return new Level_4(jcas, begin, 0);

+    case 4: return new Level_5(jcas, begin, 0);

+    case 5: return new Level_6(jcas, begin, 0);

+    default: fail(); return null;

+    }    

+  }

+  

+  Level_1 makeLevel(int level, int begin, float sortOrder) {

+    Level_1 fs = makeLevel_inner(level, begin);

+    fs.setId(sortOrder);

+    fs.addToIndexes();

+    return fs;

+  }

+  

+  private int randomLevel_index() {

+    return r.nextInt(levels.size());

+  }

+  

+  private int randomLevel() {

+    return levels.get(randomLevel_index());

+  }

+}

diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_1.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_1.java
new file mode 100644
index 0000000..a79ba4a
--- /dev/null
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_1.java
@@ -0,0 +1,135 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.cas.test;

+

+import java.lang.invoke.CallSite;

+import java.lang.invoke.MethodHandle;

+

+import org.apache.uima.cas.impl.CASImpl;

+import org.apache.uima.cas.impl.TypeImpl;

+import org.apache.uima.cas.impl.TypeSystemImpl;

+import org.apache.uima.jcas.JCas;

+import org.apache.uima.jcas.JCasRegistry;

+import org.apache.uima.jcas.tcas.Annotation;

+

+

+/** 

+ * Updated by JCasGen Fri Dec 16 10:23:12 EST 2016

+ * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml

+ * @generated */

+public class Level_1 extends Annotation {

+ 

+  /** @generated

+   * @ordered 

+   */

+  @SuppressWarnings ("hiding")

+  public final static String _TypeName = "org.apache.uima.cas.test.Level_1";

+  

+  /** @generated

+   * @ordered 

+   */

+  @SuppressWarnings ("hiding")

+  public final static int typeIndexID = JCasRegistry.register(Level_1.class);

+  /** @generated

+   * @ordered 

+   */

+  @SuppressWarnings ("hiding")

+  public final static int type = typeIndexID;

+  /** @generated

+   * @return index of the type  

+   */

+  @Override

+  public              int getTypeIndexID() {return typeIndexID;}

+ 

+ 

+  /* *******************

+   *   Feature Offsets *

+   * *******************/ 

+  /* Feature Adjusted Offsets */

+//  public final static int _FI_id = TypeSystemImpl.getAdjustedFeatureOffset("id");

+

+  private final static CallSite _FC_id = TypeSystemImpl.createCallSite(Level_1.class, "id");

+  private final static MethodHandle _FH_id = _FC_id.dynamicInvoker();

+  

+  /** Never called.  Disable default constructor

+   * @generated */

+  protected Level_1() {/* intentionally empty block */}

+    

+  /** Internal - constructor used by generator 

+   * @generated

+   * @param casImpl the CAS this Feature Structure belongs to

+   * @param type the type of this Feature Structure 

+   */

+  public Level_1(TypeImpl type, CASImpl casImpl) {

+    super(type, casImpl);

+    readObject();

+  }

+  

+  /** @generated

+   * @param jcas JCas to which this Feature Structure belongs 

+   */

+  public Level_1(JCas jcas) {

+    super(jcas);

+    readObject();   

+  } 

+

+

+  /** @generated

+   * @param jcas JCas to which this Feature Structure belongs

+   * @param begin offset to the begin spot in the SofA

+   * @param end offset to the end spot in the SofA 

+  */  

+  public Level_1(JCas jcas, int begin, int end) {

+    super(jcas);

+    setBegin(begin);

+    setEnd(end);

+    readObject();

+  }   

+

+  /** 

+   * <!-- begin-user-doc -->

+   * Write your own initialization here

+   * <!-- end-user-doc -->

+   *

+   * @generated modifiable 

+   */

+  private void readObject() {/*default - does nothing empty block */}

+  

+  //*--------------*

+  //* Feature: id

+

+  /** getter for id - gets id of document. (For example, file:///MyDirectory/myFile.txt for a simple file or http://incubator.apache.org/uima/index.html for content from a web source.)

+   * @generated

+   * @return value of the feature 

+   */

+  public float getId() { return _getFloatValueNc(wrapGetIntCatchException(_FH_id));}

+    

+  /** setter for id - sets id of document. (For example, file:///MyDirectory/myFile.txt for a simple file or http://incubator.apache.org/uima/index.html for content from a web source.) 

+   * @generated

+   * @param v value to set into the feature 

+   */

+  public void setId(float v) {

+    _setFloatValueNfc(wrapGetIntCatchException(_FH_id), v);

+  }    

+

+  

+}

+

+    
\ No newline at end of file
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_2.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_2.java
new file mode 100644
index 0000000..003dcce
--- /dev/null
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_2.java
@@ -0,0 +1,92 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.cas.test;

+

+import org.apache.uima.cas.impl.CASImpl;

+import org.apache.uima.cas.impl.TypeImpl;

+import org.apache.uima.cas.impl.TypeSystemImpl;

+import org.apache.uima.jcas.JCas; 

+import org.apache.uima.jcas.JCasRegistry;

+

+

+import org.apache.uima.jcas.tcas.Annotation;

+

+public class Level_2 extends Level_1 {

+ 

+  @SuppressWarnings ("hiding")

+  public final static String _TypeName = "org.apache.uima.cas.test.Level_2";

+  

+  @SuppressWarnings ("hiding")

+  public final static int typeIndexID = JCasRegistry.register(Level_2.class);

+

+  @SuppressWarnings ("hiding")

+  public final static int type = typeIndexID;

+  

+  @Override

+  public              int getTypeIndexID() {return typeIndexID;}

+  

+   

+  /** Never called.  Disable default constructor

+   * @generated */

+  protected Level_2() {/* intentionally empty block */}

+    

+  /** Internal - constructor used by generator 

+   * @generated

+   * @param casImpl the CAS this Feature Structure belongs to

+   * @param type the type of this Feature Structure 

+   */

+  public Level_2(TypeImpl type, CASImpl casImpl) {

+    super(type, casImpl);

+    readObject();

+  }

+  

+  /** @generated

+   * @param jcas JCas to which this Feature Structure belongs 

+   */

+  public Level_2(JCas jcas) {

+    super(jcas);

+    readObject();   

+  } 

+

+

+  /** @generated

+   * @param jcas JCas to which this Feature Structure belongs

+   * @param begin offset to the begin spot in the SofA

+   * @param end offset to the end spot in the SofA 

+  */  

+  public Level_2(JCas jcas, int begin, int end) {

+    super(jcas);

+    setBegin(begin);

+    setEnd(end);

+    readObject();

+  }   

+

+  /** 

+   * <!-- begin-user-doc -->

+   * Write your own initialization here

+   * <!-- end-user-doc -->

+   *

+   * @generated modifiable 

+   */

+  private void readObject() {/*default - does nothing empty block */}

+  

+}

+

+    
\ No newline at end of file
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_3.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_3.java
new file mode 100644
index 0000000..e232a91
--- /dev/null
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_3.java
@@ -0,0 +1,92 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.cas.test;

+

+import org.apache.uima.cas.impl.CASImpl;

+import org.apache.uima.cas.impl.TypeImpl;

+import org.apache.uima.cas.impl.TypeSystemImpl;

+import org.apache.uima.jcas.JCas; 

+import org.apache.uima.jcas.JCasRegistry;

+

+

+import org.apache.uima.jcas.tcas.Annotation;

+

+public class Level_3 extends Level_2 {

+ 

+  @SuppressWarnings ("hiding")

+  public final static String _TypeName = "org.apache.uima.cas.test.Level_2";

+  

+  @SuppressWarnings ("hiding")

+  public final static int typeIndexID = JCasRegistry.register(Level_3.class);

+

+  @SuppressWarnings ("hiding")

+  public final static int type = typeIndexID;

+  

+  @Override

+  public              int getTypeIndexID() {return typeIndexID;}

+  

+   

+  /** Never called.  Disable default constructor

+   * @generated */

+  protected Level_3() {/* intentionally empty block */}

+    

+  /** Internal - constructor used by generator 

+   * @generated

+   * @param casImpl the CAS this Feature Structure belongs to

+   * @param type the type of this Feature Structure 

+   */

+  public Level_3(TypeImpl type, CASImpl casImpl) {

+    super(type, casImpl);

+    readObject();

+  }

+  

+  /** @generated

+   * @param jcas JCas to which this Feature Structure belongs 

+   */

+  public Level_3(JCas jcas) {

+    super(jcas);

+    readObject();   

+  } 

+

+

+  /** @generated

+   * @param jcas JCas to which this Feature Structure belongs

+   * @param begin offset to the begin spot in the SofA

+   * @param end offset to the end spot in the SofA 

+  */  

+  public Level_3(JCas jcas, int begin, int end) {

+    super(jcas);

+    setBegin(begin);

+    setEnd(end);

+    readObject();

+  }   

+

+  /** 

+   * <!-- begin-user-doc -->

+   * Write your own initialization here

+   * <!-- end-user-doc -->

+   *

+   * @generated modifiable 

+   */

+  private void readObject() {/*default - does nothing empty block */}

+  

+}

+

+    
\ No newline at end of file
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_4.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_4.java
new file mode 100644
index 0000000..f31e4e2
--- /dev/null
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_4.java
@@ -0,0 +1,92 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.cas.test;

+

+import org.apache.uima.cas.impl.CASImpl;

+import org.apache.uima.cas.impl.TypeImpl;

+import org.apache.uima.cas.impl.TypeSystemImpl;

+import org.apache.uima.jcas.JCas; 

+import org.apache.uima.jcas.JCasRegistry;

+

+

+import org.apache.uima.jcas.tcas.Annotation;

+

+public class Level_4 extends Level_3 {

+ 

+  @SuppressWarnings ("hiding")

+  public final static String _TypeName = "org.apache.uima.cas.test.Level_2";

+  

+  @SuppressWarnings ("hiding")

+  public final static int typeIndexID = JCasRegistry.register(Level_4.class);

+

+  @SuppressWarnings ("hiding")

+  public final static int type = typeIndexID;

+  

+  @Override

+  public              int getTypeIndexID() {return typeIndexID;}

+  

+   

+  /** Never called.  Disable default constructor

+   * @generated */

+  protected Level_4() {/* intentionally empty block */}

+    

+  /** Internal - constructor used by generator 

+   * @generated

+   * @param casImpl the CAS this Feature Structure belongs to

+   * @param type the type of this Feature Structure 

+   */

+  public Level_4(TypeImpl type, CASImpl casImpl) {

+    super(type, casImpl);

+    readObject();

+  }

+  

+  /** @generated

+   * @param jcas JCas to which this Feature Structure belongs 

+   */

+  public Level_4(JCas jcas) {

+    super(jcas);

+    readObject();   

+  } 

+

+

+  /** @generated

+   * @param jcas JCas to which this Feature Structure belongs

+   * @param begin offset to the begin spot in the SofA

+   * @param end offset to the end spot in the SofA 

+  */  

+  public Level_4(JCas jcas, int begin, int end) {

+    super(jcas);

+    setBegin(begin);

+    setEnd(end);

+    readObject();

+  }   

+

+  /** 

+   * <!-- begin-user-doc -->

+   * Write your own initialization here

+   * <!-- end-user-doc -->

+   *

+   * @generated modifiable 

+   */

+  private void readObject() {/*default - does nothing empty block */}

+  

+}

+

+    
\ No newline at end of file
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_5.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_5.java
new file mode 100644
index 0000000..a0412f1
--- /dev/null
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_5.java
@@ -0,0 +1,92 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.cas.test;

+

+import org.apache.uima.cas.impl.CASImpl;

+import org.apache.uima.cas.impl.TypeImpl;

+import org.apache.uima.cas.impl.TypeSystemImpl;

+import org.apache.uima.jcas.JCas; 

+import org.apache.uima.jcas.JCasRegistry;

+

+

+import org.apache.uima.jcas.tcas.Annotation;

+

+public class Level_5 extends Level_4 {

+ 

+  @SuppressWarnings ("hiding")

+  public final static String _TypeName = "org.apache.uima.cas.test.Level_2";

+  

+  @SuppressWarnings ("hiding")

+  public final static int typeIndexID = JCasRegistry.register(Level_5.class);

+

+  @SuppressWarnings ("hiding")

+  public final static int type = typeIndexID;

+  

+  @Override

+  public              int getTypeIndexID() {return typeIndexID;}

+  

+   

+  /** Never called.  Disable default constructor

+   * @generated */

+  protected Level_5() {/* intentionally empty block */}

+    

+  /** Internal - constructor used by generator 

+   * @generated

+   * @param casImpl the CAS this Feature Structure belongs to

+   * @param type the type of this Feature Structure 

+   */

+  public Level_5(TypeImpl type, CASImpl casImpl) {

+    super(type, casImpl);

+    readObject();

+  }

+  

+  /** @generated

+   * @param jcas JCas to which this Feature Structure belongs 

+   */

+  public Level_5(JCas jcas) {

+    super(jcas);

+    readObject();   

+  } 

+

+

+  /** @generated

+   * @param jcas JCas to which this Feature Structure belongs

+   * @param begin offset to the begin spot in the SofA

+   * @param end offset to the end spot in the SofA 

+  */  

+  public Level_5(JCas jcas, int begin, int end) {

+    super(jcas);

+    setBegin(begin);

+    setEnd(end);

+    readObject();

+  }   

+

+  /** 

+   * <!-- begin-user-doc -->

+   * Write your own initialization here

+   * <!-- end-user-doc -->

+   *

+   * @generated modifiable 

+   */

+  private void readObject() {/*default - does nothing empty block */}

+  

+}

+

+    
\ No newline at end of file
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_6.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_6.java
new file mode 100644
index 0000000..d9ec306
--- /dev/null
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/Level_6.java
@@ -0,0 +1,92 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.cas.test;

+

+import org.apache.uima.cas.impl.CASImpl;

+import org.apache.uima.cas.impl.TypeImpl;

+import org.apache.uima.cas.impl.TypeSystemImpl;

+import org.apache.uima.jcas.JCas; 

+import org.apache.uima.jcas.JCasRegistry;

+

+

+import org.apache.uima.jcas.tcas.Annotation;

+

+public class Level_6 extends Level_5 {

+ 

+  @SuppressWarnings ("hiding")

+  public final static String _TypeName = "org.apache.uima.cas.test.Level_2";

+  

+  @SuppressWarnings ("hiding")

+  public final static int typeIndexID = JCasRegistry.register(Level_6.class);

+

+  @SuppressWarnings ("hiding")

+  public final static int type = typeIndexID;

+  

+  @Override

+  public              int getTypeIndexID() {return typeIndexID;}

+  

+   

+  /** Never called.  Disable default constructor

+   * @generated */

+  protected Level_6() {/* intentionally empty block */}

+    

+  /** Internal - constructor used by generator 

+   * @generated

+   * @param casImpl the CAS this Feature Structure belongs to

+   * @param type the type of this Feature Structure 

+   */

+  public Level_6(TypeImpl type, CASImpl casImpl) {

+    super(type, casImpl);

+    readObject();

+  }

+  

+  /** @generated

+   * @param jcas JCas to which this Feature Structure belongs 

+   */

+  public Level_6(JCas jcas) {

+    super(jcas);

+    readObject();   

+  } 

+

+

+  /** @generated

+   * @param jcas JCas to which this Feature Structure belongs

+   * @param begin offset to the begin spot in the SofA

+   * @param end offset to the end spot in the SofA 

+  */  

+  public Level_6(JCas jcas, int begin, int end) {

+    super(jcas);

+    setBegin(begin);

+    setEnd(end);

+    readObject();

+  }   

+

+  /** 

+   * <!-- begin-user-doc -->

+   * Write your own initialization here

+   * <!-- end-user-doc -->

+   *

+   * @generated modifiable 

+   */

+  private void readObject() {/*default - does nothing empty block */}

+  

+}

+

+    
\ No newline at end of file
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/Sentence.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/Sentence.java
index 312db4c..995709a 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/Sentence.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/Sentence.java
@@ -1,10 +1,13 @@
 
 
    
-/* Apache UIMA v3 - First created by JCasGen Fri Dec 16 10:23:12 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:06:27 EDT 2017 */
 
 package org.apache.uima.cas.test;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -16,8 +19,8 @@
 
 
 /** 
- * Updated by JCasGen Fri Dec 16 10:23:12 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
+ * Updated by JCasGen Sun Oct 08 19:06:27 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
  * @generated */
 public class Sentence extends Annotation {
  
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/SerializationReinitTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/SerializationReinitTest.java
index 7e22b51..a8714dc 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/SerializationReinitTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/SerializationReinitTest.java
@@ -569,7 +569,7 @@
     newFS2.setIntValue(endFeature, cycle+2);
     ir.addFS(newFS2);
     CASImpl ci = (CASImpl) cas;
-    ci.setId2FSs(newFS2, newBA2, newSA2);
+    ci.setId2FSsMaybeUnconditionally(newFS2, newBA2, newSA2);
     // set string using lowlevel string create API
     final int llfs2 = ll_cas.ll_getFSRef(newFS2);
     final int llba2 = ll_cas.ll_getFSRef(newBA2);
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/StringArrayTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/StringArrayTest.java
index 51e04bb..799b174 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/StringArrayTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/StringArrayTest.java
@@ -188,7 +188,7 @@
      final Feature lemmaList = this.ts.getFeatureByFullName(lemmaListName);
      assertTrue(lemmaList != null);
      StringArrayFS casArray = this.cas.createStringArrayFS(3);
-     ((CASImpl)(casArray.getCAS())).setId2FSs(casArray);
+     ((CASImpl)(casArray.getCAS())).setId2FSsMaybeUnconditionally(casArray);
      casArray.set(0, "1");
      casArray.set(1, null);
      casArray.set(2, "3");
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/StringSubtypeAnnotation.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/StringSubtypeAnnotation.java
index e55a29c..03831e7 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/StringSubtypeAnnotation.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/StringSubtypeAnnotation.java
@@ -1,23 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 
    
-/* Apache UIMA v3 - First created by JCasGen Wed Mar 02 13:51:54 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 20:01:40 EDT 2017 */
 
 package org.apache.uima.cas.test;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
-import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCas; 
 import org.apache.uima.jcas.JCasRegistry;
+
+
 import org.apache.uima.jcas.tcas.Annotation;
 
 
 /** 
- * Updated by JCasGen Wed Mar 02 13:51:54 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/experiment-v3-jcas/uimaj-core/src/test/resources/CASTests/desc/StringSubtypeTest.xml
+ * Updated by JCasGen Sun Oct 08 20:01:40 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/resources/CASTests/desc/StringSubtypeTest.xml
  * @generated */
 public class StringSubtypeAnnotation extends Annotation {
+ 
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "org.apache.uima.cas.test.StringSubtypeAnnotation";
+  
   /** @generated
    * @ordered 
    */
@@ -39,8 +69,12 @@
    *   Feature Offsets *
    * *******************/ 
    
+  public final static String _FeatName_stringSetFeature = "stringSetFeature";
+
+
   /* Feature Adjusted Offsets */
-  public final static int _FI_stringSetFeature = TypeSystemImpl.getAdjustedFeatureOffset("stringSetFeature");
+  private final static CallSite _FC_stringSetFeature = TypeSystemImpl.createCallSite(StringSubtypeAnnotation.class, "stringSetFeature");
+  private final static MethodHandle _FH_stringSetFeature = _FC_stringSetFeature.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -65,6 +99,19 @@
     readObject();   
   } 
 
+
+  /** @generated
+   * @param jcas JCas to which this Feature Structure belongs
+   * @param begin offset to the begin spot in the SofA
+   * @param end offset to the end spot in the SofA 
+  */  
+  public StringSubtypeAnnotation(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }   
+
   /** 
    * <!-- begin-user-doc -->
    * Write your own initialization here
@@ -83,14 +130,14 @@
    * @generated
    * @return value of the feature 
    */
-  public String getStringSetFeature() { return _getStringValueNc(_FI_stringSetFeature);}
+  public String getStringSetFeature() { return _getStringValueNc(wrapGetIntCatchException(_FH_stringSetFeature));}
     
   /** setter for stringSetFeature - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setStringSetFeature(String v) {
-    _setStringValueNfc(_FI_stringSetFeature, v);
+    _setStringValueNfc(wrapGetIntCatchException(_FH_stringSetFeature), v);
   }    
     
   }
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/SubiteratorTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/SubiteratorTest.java
index 52d0664..320c72e 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/SubiteratorTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/SubiteratorTest.java
@@ -117,6 +117,7 @@
     Annotation sentence = jcas.getAnnotationIndex(Sentence.class).iterator().next();
     FSIterator<Token> tokenIterator = tokenIndex.subiterator(sentence);
     Annotation token = tokenIndex.iterator().next();
+    // debug token.toString();
     tokenIterator.moveTo(token); //throws ClassCastException 
     
     // check unambiguous iterator creation
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/Token.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/Token.java
index c42f015..ead0c32 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/Token.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/Token.java
@@ -1,10 +1,13 @@
 
 
    
-/* Apache UIMA v3 - First created by JCasGen Fri Dec 16 10:23:12 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:06:27 EDT 2017 */
 
 package org.apache.uima.cas.test;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -16,8 +19,8 @@
 
 
 /** 
- * Updated by JCasGen Fri Dec 16 10:23:12 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
+ * Updated by JCasGen Sun Oct 08 19:06:27 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
  * @generated */
 public class Token extends Annotation {
  
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/TypePriorityTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/TypePriorityTest.java
index b81a8cb..8357968 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/TypePriorityTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/TypePriorityTest.java
@@ -168,10 +168,16 @@
    *     aaaa        aaab        aaba        aabb       abaa        abab        abba        abbb      baaa ...
    * aaaaa aaaab aaaba aaabb aabaa aabab aabba aabbb abaaa abaab ababa ababb abbaa abbab abbba abbbb baaaa ...
    */
+  
+//  public void testLearnLto() throws CASException {
+//    LinearTypeOrderBuilder order = irm.createTypeSortOrder();
+//    LinearTypeOrder lo = order.getOrder();
+//    System.out.println("debug linearTypeOrder " + lo);
+//  }
   /**
    * Test driver.
    */
-  public void testMain() throws Exception {
+  public void testMain() throws Exception {    
     LinearTypeOrderBuilder order = irm.createTypeSortOrder();
     order = irm.createTypeSortOrder();
     LinearTypeOrder lo;
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 b253409..1f82a99 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
@@ -20,6 +20,7 @@
 package org.apache.uima.cas_data.impl;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.ConcurrentModificationException;
@@ -127,8 +128,8 @@
     
     // allow for different ordering in the getAllIndexedFSs
     
-    List<TOP> list1 = populate(c1.getIndexRepository().getAllIndexedFS(c1.getTypeSystem().getTopType()), alreadyCompared);
-    List<TOP> list2 = populate(c2.getIndexRepository().getAllIndexedFS(c2.getTypeSystem().getTopType()), alreadyCompared);
+    List<TOP> list1 = populate(c1.getIndexRepository().getIndexedFSs(), alreadyCompared);
+    List<TOP> list2 = populate(c2.getIndexRepository().getIndexedFSs(), alreadyCompared);
     
     Assert.assertEquals(list1.size(),  list2.size());
     
@@ -370,10 +371,9 @@
   /* 
    * When populating, skip items already visted and compared in other views (but always include sofas)
    */
-  private static List<TOP> populate(FSIterator<TOP> it, Set<TOP> visited) {
+  private static List<TOP> populate(Collection<TOP> items, Set<TOP> visited) {
     List<TOP> s = new ArrayList<TOP>();
-    while (it.hasNext()) {
-      TOP fs = it.next();
+    for (TOP fs : items) {
       if (!(fs instanceof Sofa) && !visited.contains(fs)) {
         s.add(fs);
       }
diff --git a/uimaj-core/src/test/java/org/apache/uima/impl/UimaContext_implTest.java b/uimaj-core/src/test/java/org/apache/uima/impl/UimaContext_implTest.java
index b0977e6..48816a6 100644
--- a/uimaj-core/src/test/java/org/apache/uima/impl/UimaContext_implTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/impl/UimaContext_implTest.java
@@ -128,6 +128,14 @@
     }
   }
 
+  /*
+   * @see TestCase#tearDown()
+   */
+  protected void tearDown() throws Exception {
+    super.tearDown();
+    UIMAFramework.getXMLParser().enableSchemaValidation(false);
+  }
+
   public void testGetConfigParameterValueString() throws Exception {
     try {
       String str = (String) mContext.getConfigParameterValue("StringParam");
diff --git a/uimaj-core/src/test/java/org/apache/uima/internal/util/Int2ObjHashMapTest.java b/uimaj-core/src/test/java/org/apache/uima/internal/util/Int2ObjHashMapTest.java
new file mode 100644
index 0000000..1a97d0e
--- /dev/null
+++ b/uimaj-core/src/test/java/org/apache/uima/internal/util/Int2ObjHashMapTest.java
@@ -0,0 +1,133 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+package org.apache.uima.internal.util;

+

+import java.util.Random;

+

+import org.apache.uima.util.IntEntry;

+

+import junit.framework.TestCase;

+

+public class Int2ObjHashMapTest extends TestCase {

+  

+  // a number of extras needed to cause rebalance

+  // is > 1 because it might turn out randomly that

+  // the puts clear all the REMOVED_KEY values

+  // needs to be > than 1/2 the capacity/2

+  private static final int  REBAL = 32;  

+

+  Int2ObjHashMap<Integer, Integer> ihm;

+  

+  public void setUp() {

+    ihm = new Int2ObjHashMap<>(Integer.class);

+  }

+

+  public void testBasic() {

+    

+    ihm.put(15, 150);

+    ihm.put(188, 1880);

+    assertEquals(2, ihm.size());

+    assertEquals(150, (int)ihm.get(15));

+    assertEquals(1880, (int)ihm.get(188));

+

+    assertEquals(null, ihm.remove(18));

+    assertEquals(150, (int)ihm.remove(15));

+    assertEquals(1, ihm.size());

+    

+    for (IntEntry<Integer> ie : ihm) {

+      assertEquals(ie.getKey(), 188);

+    }

+    

+    assertEquals(1880, (int)ihm.remove(188));

+    assertEquals(0, ihm.size());

+    for (IntEntry<Integer> ie : ihm) {

+      fail();  // should be empty

+    }

+    

+  }

+  

+  public void testRebalance() {

+    // 100 elements, require 256 table (128 * .66 = 85)

+    for (int i = 1; i < 101; i++) {

+      ihm.put(i, i * 10);

+    }

+    

+    // have 100 elements, remove 100 elements

+    for (int i = 1; i < 101; i++) {

+      assertEquals(i*10, (int)ihm.remove(i));

+    }

+    

+    

+    assertEquals(0, ihm.size());

+    

+    assertEquals(64, ihm.getCapacity());

+    

+    for (int i = 1; i < 101 + REBAL; i++) {

+      ihm.put(i + 100, i * 10);  // add different keys, so may use some new slots

+    }

+    

+    assertEquals(256, ihm.getCapacity()); //because above are different adds, likely into non-removed positions

+    

+    // have 100 elements, remove 100 elements

+    for (int i = 1; i < 101 + REBAL; i++) {

+      assertEquals(i*10, (int)ihm.remove(i + 100));

+    }

+   

+    assertEquals(64, ihm.getCapacity());

+    

+  }

+  

+  public void testRandom() {

+    int countAdd = 0;

+    int dupsA = 0;

+    int notPres = 0;

+    int countRmv = 0;

+    

+    long seed = // -6616473831883690L;

+        new Random().nextLong();

+    System.out.println("Random seed for Int2ObjHashMapTest: " + seed);

+    Random r = new Random(seed);

+    

+    for (int i = 1; i < 1024 * 512; i++) {

+      int k = i & 1024 - 1;

+      if (k == 0) continue;

+      if (r.nextInt(3) > 0) {

+        int sz = ihm.size();

+        if (ihm.put(k, -k) == null) {

+          countAdd ++;

+          assertEquals(sz + 1, ihm.size());

+        } else {

+          dupsA++;

+        }

+      } else {

+        int sz = ihm.size();

+        if (ihm.remove(k) != null) {

+          countRmv ++;

+          assertEquals(sz - 1, ihm.size());

+        } else {

+          notPres++;

+        }

+        

+      }

+    }

+    System.out.format("%s testRandom added: %,d dups: %,d rmvd: %,d notPres: %,d, size: %d%n",         

+        this.getClass().getName(), countAdd, dupsA, countRmv, notPres, ihm.size());

+    assertEquals(countAdd - countRmv, ihm.size() );

+  }

+}

diff --git a/uimaj-core/src/test/java/org/apache/uima/internal/util/IntBitSetTest.java b/uimaj-core/src/test/java/org/apache/uima/internal/util/IntBitSetTest.java
index 9f86d5f..e802811 100644
--- a/uimaj-core/src/test/java/org/apache/uima/internal/util/IntBitSetTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/internal/util/IntBitSetTest.java
@@ -43,9 +43,9 @@
     

     IntListIterator it = ibs.iterator();    

     assertTrue(it.hasNext());

-    assertEquals(15, it.next());

+    assertEquals(15, it.nextNvc());

     assertTrue(it.hasNext());

-    assertEquals(188, it.next());

+    assertEquals(188, it.nextNvc());

     assertFalse(it.hasNext());

     assertEquals(3*64, ibs.getSpaceUsed_in_bits_no_overhead());

     assertEquals(6, ibs.getSpaceUsed_in_words_no_overhead());

@@ -56,9 +56,9 @@
     ibs.add(1188);

     it = ibs.iterator();    

     assertTrue(it.hasNext());

-    assertEquals(1015, it.next());

+    assertEquals(1015, it.nextNvc());

     assertTrue(it.hasNext());

-    assertEquals(1188, it.next());

+    assertEquals(1188, it.nextNvc());

     assertFalse(it.hasNext());

     assertEquals(2,ibs.size());

     

@@ -92,7 +92,7 @@
     IntListIterator it = ibs.iterator();

     List<Integer> ints = new ArrayList<Integer>();

     while (it.hasNext()) {

-      ints.add(it.next());

+      ints.add(it.nextNvc());

     }

     assertTrue(Arrays.equals(ints.toArray(), new Object[]{Integer.valueOf(1064)}));

     

@@ -100,7 +100,7 @@
     it = ibs.iterator();

     ints.clear();

     while (it.hasNext()) {

-      ints.add(it.next());

+      ints.add(it.nextNvc());

     }

     assertTrue(Arrays.equals(ints.toArray(), new Object[]{1063, 1064}));

     

@@ -111,7 +111,7 @@
     it.moveToStart();

     ints.clear();

     while (it.hasNext()) {

-      ints.add(it.next());

+      ints.add(it.nextNvc());

     }

     assertTrue(Arrays.equals(ints.toArray(), new Object[]{1, 10}));

   }

@@ -125,9 +125,9 @@
     assertEquals(2,ibs.size());

     IntListIterator it = ibs.iterator();    

     assertTrue(it.hasNext());

-    assertEquals(15, it.next());

+    assertEquals(15, it.nextNvc());

     assertTrue(it.hasNext());

-    assertEquals(101, it.next());

+    assertEquals(101, it.nextNvc());

     assertFalse(it.hasNext());

     assertEquals(3*64, ibs.getSpaceUsed_in_bits_no_overhead());

     

@@ -157,7 +157,7 @@
     IntListIterator it = ibs.iterator();

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

       assertTrue(it.hasNext());

-      assertEquals(1000 + i, it.next());        

+      assertEquals(1000 + i, it.nextNvc());        

     }

     assertFalse(it.hasNext());

   }

diff --git a/uimaj-core/src/test/java/org/apache/uima/internal/util/IntHashSetPerfTest.java b/uimaj-core/src/test/java/org/apache/uima/internal/util/IntHashSetPerfTest.java
index 86d8ec7..5adfa28 100644
--- a/uimaj-core/src/test/java/org/apache/uima/internal/util/IntHashSetPerfTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/internal/util/IntHashSetPerfTest.java
@@ -43,7 +43,7 @@
   IntArrayRBT m1;

   IntBitSet m3;

   

-  final int[] keys10000 = new int[111111];

+  final int[] keys10000 = new int[511111];

   int k10ki = 0;

   

   

@@ -53,10 +53,10 @@
     m2 = new IntHashSet(16);

     m3 = new IntBitSet(16);

      

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

-      int k = r.nextInt(100000);

-      while (k == 0) { k = r.nextInt(100000);}

-      keys10000[i] = k;

+    for (int i = 0; i < keys10000.length; i++) {

+      int k = r.nextInt(511110);

+     

+      keys10000[i] = k + 1;

     }

 

     System.out.format("%n%n W A R M U P %n%n");

@@ -72,14 +72,21 @@
     System.out.format("%n%n Time 100000 %n%n");

     timelp(100000);

     

+    System.out.format("%n%n Time 500000 %n%n");

+    timelp(500000);

+

+    

     System.out.println(dmv);

   }

   private void time2(int n) {

-    float f1 = time(m1, n);

+//    float f1 = time(m1, n);

     float f2 = time(m2, n);

     float f3 = time(m3, n);

-    System.out.format(" ratio RBT/hash = %.3f   RTB/bitset = %.3f  hash/bitset = %.3f%n", 

-        f1/f2,  f1/f3, f2/f3);   

+    System.out.format(" ratio "

+//        + "RBT/hash = %.3f   RTB/bitset = %.3f  "

+        + "hash/bitset = %.3f%n", 

+//        f1/f2,  f1/f3, 

+        f2/f3);   

   }

   

   private void timelp(int n) {

diff --git a/uimaj-core/src/test/java/org/apache/uima/internal/util/IntHashSetTest.java b/uimaj-core/src/test/java/org/apache/uima/internal/util/IntHashSetTest.java
index 66b8abe..bf10130 100644
--- a/uimaj-core/src/test/java/org/apache/uima/internal/util/IntHashSetTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/internal/util/IntHashSetTest.java
@@ -29,6 +29,8 @@
   

   IntHashSet ihs;

   

+  Random random;

+  

   public void setUp() {

     ihs = new IntHashSet();

   }

@@ -88,7 +90,7 @@
     int[] r = new int[s.size()];

     int i = 0;

     while (it.hasNext()) {

-      r[i++] = it.next();

+      r[i++] = it.nextNvc();

     }

     Arrays.sort(r);

     return r;

@@ -103,11 +105,11 @@
     assertFalse(ihs.contains(99));  

   }

   

-  public void testTableSpace() {

-    assertEquals(32, IntHashSet.tableSpace(19, 0.6f));    // 19 / .6 = 31.xxx, round to 32

-    assertEquals(64, IntHashSet.tableSpace(21, 0.6f));

-    assertEquals(32, ihs.tableSpace(21));

-  }

+//  public void testTableSpace() {

+//    assertEquals(32, IntHashSet.tableSpace(19, 0.6f));    // 19 / .6 = 31.xxx, round to 32

+//    assertEquals(64, IntHashSet.tableSpace(21, 0.6f));

+//    assertEquals(32, ihs.tableSpace(21));

+//  }

   

   public void testWontExpand() {

     ihs = new IntHashSet(21);

@@ -126,10 +128,18 @@
   }

   

   public void testAddIntoRemovedSlot() {

+    long seed = // 6738591171221169418L;

+        new Random().nextLong();

+    System.out.println("Random seed for testAddIntoRemovedSlot in " + this.getClass().getName() + ": "  + seed);

+    random = new Random(seed);

+

     for (int i = 1; i < 100; i++) {

       ihs.add(i);

+      assertEquals(i, ihs.size());

     }

     

+    assertEquals(99, ihs.size());

+    

     /** Test with 2 byte numbers */

     checkRemovedReuse(true);

     

@@ -142,27 +152,38 @@
   }

   

   private void checkRemovedReuse(boolean is2) {

-    Random r = new Random();

     assertTrue(ihs.getSpaceUsedInWords() == ((is2) ? 128 : 256));

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

-      int v = 1 + r.nextInt(100 + (i % 30000));

-      ihs.remove(v);

+      int v = 1 + random.nextInt(100 + (i % 30000)); // random between 1 and 30,101

+      int sz = ihs.size();

+      boolean wasRemoved = ihs.remove(v);

+      assertEquals(sz - (wasRemoved ? 1 : 0), ihs.size());

       assertTrue(!(ihs.contains(v)));

-      v = 1 + r.nextInt(100 + (i % 30000));

-      ihs.add(v);

+      v = 1 + random.nextInt(100 + (i % 30000));

+      sz = ihs.size();

+      boolean wasAdded = ihs.add(v);

+      assertEquals(sz + (wasAdded ? 1 : 0), ihs.size());

       assertTrue(ihs.contains(v));

     }

     assertTrue(ihs.getSpaceUsedInWords() == ((is2) ? 16384 : 32768) );

     

-    for (int i = ((is2) ? 16384 : 32768); i > 128; i = i / 2) {

-      ihs.clear();

-      assertTrue(ihs.getSpaceUsedInWords() == ((is2 || i == 32768) ? i : i/2));

-      ihs.clear();

-      assertTrue(ihs.getSpaceUsedInWords() == ((is2 || i == 32768) ? i : i/2));

-    }

-    ihs.clear();

+    //  32,768, 16,384, 8,192, 4096, 2048, 1024, 512, 256

+    // for 2 byte storage, is2 = true, and expected is: i / 2

+    // for 4 byte storage, is2 = false, and expected is i

     

-    assertTrue(ihs.getSpaceUsedInWords() == (is2 ? 128 : 64));

+    ihs.clear(); // doesn't set 2nd time because size + removed > 1/2 the capacity

+    

+    for (int i = 32768; i > 128; i = i / 2) {

+      ihs.clear(); // sets 2nd time shrinkable

+      assertTrue(ihs.getSpaceUsedInWords() == (is2 ? i/2 : i));

+      ihs.clear();  // shrinks

+      assertTrue(ihs.getSpaceUsedInWords() == (is2 ? i/4 : i/2));

+    }

+//    ihs.clear();

+//    

+    assertTrue(ihs.getSpaceUsedInWords() == (is2 ? 64: 128));

+

+    // table size should be 128, adding 100 items should cause expansion (84 == .66 * 128)

     for (int i = 1; i < ((is2) ? 100 : 99); i++) {

       ihs.add(i);

     }

@@ -172,15 +193,53 @@
     

     assertTrue(ihs.getSpaceUsedInWords() == ((is2) ? 128 : 256));

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

-      int v = 1 + r.nextInt(100);

+      int v = 1 + random.nextInt(100);

       ihs.remove(v);

       assertTrue(!(ihs.contains(v)));

       ihs.add(v);

       assertTrue(ihs.contains(v));

     }

+    

     assertTrue(ihs.getSpaceUsedInWords() == ((is2) ? 128 : 256));

     

   }

  

-  

+  public void testRandom() {

+    int countAdd = 0;

+    int dupsA = 0;

+    int notPres = 0;

+    int countRmv = 0;

+    

+    long seed = 

+        new Random().nextLong();

+    System.out.println("Random seed for testRandom in " + this.getClass().getName() + ": "  + seed);

+    random = new Random(seed);

+    

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

+      int k = i & (1024 * 256) - 1;

+      if (k == 0) continue;

+      if (random.nextInt(3) > 0) {

+        int sz = ihs.size();

+        if (ihs.add(k)) {

+          countAdd ++;

+          assertEquals(sz + 1, ihs.size());

+        } else {

+          dupsA ++;

+        }

+        

+      } else {

+        int sz = ihs.size();

+        if (ihs.remove(k)) {

+          countRmv ++;

+          assertEquals(sz - 1, ihs.size());

+        } else {

+          notPres ++;

+        }

+        

+      }

+    }

+    

+    System.out.format("added: %,d dups: %,d rmvd: %,d notPres: %,d, size: %d%n", countAdd, dupsA, countRmv, notPres, ihs.size());

+    assertEquals(countAdd - countRmv, ihs.size() );

+  }

 }

diff --git a/uimaj-core/src/test/java/org/apache/uima/internal/util/Obj2IntIdentityHashMapTest.java b/uimaj-core/src/test/java/org/apache/uima/internal/util/Obj2IntIdentityHashMapTest.java
new file mode 100644
index 0000000..6c529b3
--- /dev/null
+++ b/uimaj-core/src/test/java/org/apache/uima/internal/util/Obj2IntIdentityHashMapTest.java
@@ -0,0 +1,147 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+package org.apache.uima.internal.util;

+

+import java.util.HashMap;

+import java.util.Map;

+import java.util.Random;

+

+import junit.framework.TestCase;

+

+public class Obj2IntIdentityHashMapTest extends TestCase {

+  

+  // a number of extras needed to cause rebalance

+  // is > 1 because it might turn out randomly that

+  // the puts clear all the REMOVED_KEY values

+  // needs to be > than 1/2 the capacity/2

+  private static final int  REBAL = 32;  

+

+  Obj2IntIdentityHashMap<Integer> ihm;

+  

+  private static Integer[] I = new Integer[300];

+  static {for (int i = 0; i < I.length; i++) I[i] = i;}

+

+  Map<Integer, Integer> im = new HashMap<>();

+  

+  public void setUp() {

+    ihm = new Obj2IntIdentityHashMap<>(Integer.class, new Integer(Integer.MIN_VALUE));

+  }

+

+  public void testBasic() {

+    

+    Integer I15 = 15;

+    Integer I188 = 188;

+    

+    ihm.put(I15, 150);

+    ihm.put(I188, 1880);

+    assertEquals(2, ihm.size());

+    assertEquals(150, (int)ihm.get(I15));

+    assertEquals(1880, (int)ihm.get(I188));

+    assertEquals(0, (int)ihm.get(188));  // not identity equal

+

+    assertEquals(0, ihm.remove(18));

+    assertEquals(150, (int)ihm.remove(I15));

+    assertEquals(1, ihm.size());

+    

+//    for (IntEntry<Integer> ie : ihm) {

+//      assertEquals(ie.getKey(), 188);

+//    }

+    

+    assertEquals(1880, (int)ihm.remove(I188));

+    assertEquals(0, ihm.size());

+//    for (IntEntry<Integer> ie : ihm) {

+//      fail();  // should be empty

+//    }

+    

+  }

+  

+  public void testRebalance() {

+    // 100 elements, require 256 table (128 * .66 = 85)

+    for (int i = 1; i < 101; i++) {

+      ihm.put(I[i], i * 10);

+    }

+    

+    // have 100 elements, remove 100 elements

+    for (int i = 1; i < 101; i++) {

+      assertEquals(i*10, (int)ihm.remove(I[i]));

+    }

+    

+    

+    assertEquals(0, ihm.size());

+    

+    assertEquals(64, ihm.getCapacity());

+    

+    for (int i = 1; i < 101 + REBAL; i++) {

+      ihm.put(I[i + 100], i * 10);  // add different keys, so may use some new slots

+    }

+    

+    assertEquals(256, ihm.getCapacity()); //because above are different adds, likely into non-removed positions

+    

+    // have 100 elements, remove 100 elements

+    for (int i = 1; i < 101 + REBAL; i++) {

+      assertEquals(i*10, (int)ihm.remove(I[i + 100]));

+    }

+   

+    assertEquals(64, ihm.getCapacity());

+    

+  }

+  

+  private Integer J(int v) {

+    im.putIfAbsent(v, v);

+    return im.get(v);

+  }

+  

+  public void testRandom() {

+    int countAdd = 0;

+    int dupsA = 0;

+    int notPres = 0;

+    int countRmv = 0;

+    

+    long seed = // -6616473831883690L;

+        new Random().nextLong();

+    System.out.println("Random seed for Obj2IntIdentityHashMapTest: " + seed);

+    Random r = new Random(seed);

+    

+    for (int i = 1; i < 1024 * 512; i++) {

+      int k = i & 1024 - 1;

+      if (k == 0) continue;

+      if (r.nextInt(3) > 0) {

+        int sz = ihm.size();

+        if (ihm.put(J(k), -k) == 0) {

+          countAdd ++;

+          assertEquals(sz + 1, ihm.size());

+        } else {

+          dupsA++;

+        }

+      } else {

+        int sz = ihm.size();

+        if (ihm.remove(J(k)) != 0) {

+          countRmv ++;

+          assertEquals(sz - 1, ihm.size());

+        } else {

+          notPres++;

+        }

+        

+      }

+    }

+    System.out.format("%s testRandom added: %,d dups: %,d rmvd: %,d notPres: %,d, size: %d%n",         

+        this.getClass().getName(), countAdd, dupsA, countRmv, notPres, ihm.size());

+    assertEquals(countAdd - countRmv, ihm.size() );

+  }

+}

diff --git a/uimaj-core/src/test/java/org/apache/uima/internal/util/ObjHashSetTest.java b/uimaj-core/src/test/java/org/apache/uima/internal/util/ObjHashSetTest.java
new file mode 100644
index 0000000..1caaf1b
--- /dev/null
+++ b/uimaj-core/src/test/java/org/apache/uima/internal/util/ObjHashSetTest.java
@@ -0,0 +1,186 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.internal.util;

+

+import java.util.Arrays;

+import java.util.Random;

+

+import junit.framework.TestCase;

+

+

+public class ObjHashSetTest extends TestCase {

+  

+  ObjHashSet<Integer> ihs;

+  

+  Random random;

+  

+  public void setUp() {

+    ihs = new ObjHashSet<>(Integer.class, new Integer(Integer.MIN_VALUE));

+  }

+  

+  public void testBasic() {

+    

+    ihs.add(15);

+    ihs.add(188);

+    Integer[] sv = ihs.toArray();

+    assertEquals(2, sv.length);

+    assertEquals(15 + 188, sv[0].intValue() + sv[1].intValue());

+    

+    // test most positive / negative

+    ihs.clear();

+    ihs.add(189);

+    ihs.add(1000);

+    ihs.add(-1000);

+    ihs.add(500);

+    ihs.add(-500);

+    ihs.remove(1000);

+    ihs.add(1001);    

+  }

+  

+  public void testContains() {

+    ihs.add(1188);

+    ihs.add(1040);

+    assertTrue(ihs.contains(1188));

+    assertTrue(ihs.contains(1040));

+    assertFalse(ihs.contains(1));

+    assertFalse(ihs.contains(99));  

+  }

+  

+//  public void testTableSpace() {

+//    assertEquals(32, ObjHashSet.tableSpace(19, 0.6f));    // 19 / .6 = 31.xxx, round to 32

+//    assertEquals(64, ObjHashSet.tableSpace(21, 0.6f));

+//    assertEquals(32, ihs.tableSpace(21));

+//  }

+    

+  public void testExpandNpe() {

+    ihs.add(15);

+    ihs.add(150000);  // makes 4 byte table entries

+    

+    for (int i = 1; i < 256; i++) {  // 0 is invalid key

+      ihs.add(i);  // causes resize, check no NPE etc thrown.

+    }

+  }

+  

+  public void testAddIntoRemovedSlot() {

+    long seed = // -4571976104270514645L;

+        new Random().nextLong();

+    System.out.println("Random seed for testAddIntoRemovedSlot in " + this.getClass().getName() + ": "  + seed);

+    random = new Random(seed);

+

+    for (int i = 1; i < 100; i++) {

+      ihs.add(i);

+      assertEquals(i, ihs.size());

+    }

+    

+    assertEquals(99, ihs.size());

+    

+    /** Test with 2 byte numbers */

+    checkRemovedReuse(true);

+    

+    ihs = new ObjHashSet<>(Integer.class, new Integer(Integer.MIN_VALUE));

+    for (int i = 1; i < 99; i++) {

+      ihs.add(i);

+    }

+    ihs.add(100000);  // force 4 byte

+    checkRemovedReuse(false);

+  }

+  

+  private void checkRemovedReuse(boolean is2) {

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

+      int v = 1 + random.nextInt(100 + (i % 30000)); // random between 1 and 30,101

+      int sz = ihs.size();

+      boolean wasRemoved = ihs.remove(v);

+      assertEquals(sz - (wasRemoved ? 1 : 0), ihs.size());

+      assertTrue(!(ihs.contains(v)));

+      v = 1 + random.nextInt(100 + (i % 30000));

+      sz = ihs.size();

+      boolean wasAdded = ihs.add(v);

+      assertEquals(sz + (wasAdded ? 1 : 0), ihs.size());

+      assertTrue(ihs.contains(v));

+    }

+    

+    ihs.clear(); // doesn't set 2nd time because size + removed > 1/2 the capacity

+    

+    for (int i = 32768; i > 128; i = i / 2) {

+      ihs.clear(); // sets 2nd time shrinkable

+      assertEquals(i, ihs.getCapacity());

+      ihs.clear();  // shrinks

+      assertEquals(i/2, ihs.getCapacity());

+    }

+//    ihs.clear();

+//    

+

+    // table size should be 128, adding 100 items should cause expansion (84 == .66 * 128)

+    for (int i = 1; i < 100; i++) {

+      ihs.add(i);

+    }

+    

+    assertEquals(256, ihs.getCapacity());

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

+      int v = 1 + random.nextInt(100);

+      ihs.remove(v);

+      assertTrue(!(ihs.contains(v)));

+      ihs.add(v);

+      assertTrue(ihs.contains(v));

+    }

+    

+    assertEquals(256, ihs.getCapacity());

+    

+  }

+ 

+  public void testRandom() {

+    int countAdd = 0;

+    int dupsA = 0;

+    int notPres = 0;

+    int countRmv = 0;

+    

+    long seed = 

+        new Random().nextLong();

+    System.out.println("Random seed for testRandom in " + this.getClass().getName() + ": "  + seed);

+    random = new Random(seed);

+    

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

+      int k = i & (1024 * 256) - 1;

+      if (k == 0) continue;

+      if (random.nextInt(3) > 0) {

+        int sz = ihs.size();

+        if (ihs.add(k)) {

+          countAdd ++;

+          assertEquals(sz + 1, ihs.size());

+        } else {

+          dupsA ++;

+        }

+        

+      } else {

+        int sz = ihs.size();

+        if (ihs.remove(k)) {

+          countRmv ++;

+          assertEquals(sz - 1, ihs.size());

+        } else {

+          notPres ++;

+        }

+        

+      }

+    }

+    

+    System.out.format("added: %,d dups: %,d rmvd: %,d notPres: %,d, size: %d%n", countAdd, dupsA, countRmv, notPres, ihs.size());

+    assertEquals(countAdd - countRmv, ihs.size() );

+  }

+}

diff --git a/uimaj-core/src/test/java/org/apache/uima/internal/util/PositiveIntSetTest.java b/uimaj-core/src/test/java/org/apache/uima/internal/util/PositiveIntSetTest.java
index 088221f..620f88a 100644
--- a/uimaj-core/src/test/java/org/apache/uima/internal/util/PositiveIntSetTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/internal/util/PositiveIntSetTest.java
@@ -85,9 +85,9 @@
     

     IntListIterator it = s.getOrderedIterator();

     assertTrue(it.hasNext());

-    assertEquals(128, it.next());

+    assertEquals(128, it.nextNvc());

     assertTrue(it.hasNext());

-    assertEquals(128128, it.next());

+    assertEquals(128128, it.nextNvc());

     assertFalse(it.hasNext());

 

     // test offset

@@ -352,7 +352,7 @@
     IntListIterator it2 = s.iterator();

     i = 0;

     while (it2.hasNext()) {

-      v1[i++] = it2.next();

+      v1[i++] = it2.nextNvc();

     }

     Arrays.sort(v1);

     assertTrue(Arrays.equals(v1, v2));    

diff --git a/uimaj-core/src/test/java/org/apache/uima/internal/util/UIMAClassLoaderTest.java b/uimaj-core/src/test/java/org/apache/uima/internal/util/UIMAClassLoaderTest.java
index ffeba4c..da5fe21 100644
--- a/uimaj-core/src/test/java/org/apache/uima/internal/util/UIMAClassLoaderTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/internal/util/UIMAClassLoaderTest.java
@@ -67,12 +67,14 @@
     while (!(classOfLoader.getName().equals("java.lang.ClassLoader"))) {
       classOfLoader = classOfLoader.getSuperclass(); 
     }
-    Method m = classOfLoader.getDeclaredMethod("getClassLoadingLock", String.class);
-    m.setAccessible(true);
-    Object o = m.invoke(cl, "someString");
-    Object o2 = m.invoke(cl, "s2");
-    assertTrue(o != o2);
-    assertTrue(cl != o);      
+    if (!Misc.isJava9ea) { // skip for java 9
+      Method m = classOfLoader.getDeclaredMethod("getClassLoadingLock", String.class);
+      m.setAccessible(true);
+      Object o = m.invoke(cl, "someString");
+      Object o2 = m.invoke(cl, "s2");
+      assertTrue(o != o2);
+      assertTrue(cl != o);      
+    }
   }
 
   public void testAdvancedRsrcMgrCLassLoaderCreation() throws Exception {
diff --git a/uimaj-core/src/test/java/org/apache/uima/internal/util/rb_trees/Int2IntRBTtest.java b/uimaj-core/src/test/java/org/apache/uima/internal/util/rb_trees/Int2IntRBTtest.java
index e77b76f..31c6166 100644
--- a/uimaj-core/src/test/java/org/apache/uima/internal/util/rb_trees/Int2IntRBTtest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/internal/util/rb_trees/Int2IntRBTtest.java
@@ -60,7 +60,7 @@
     IntListIterator itl = ia.keyIterator();
 
     while(itl.hasNext()){
-      r[i++] = itl.next();  
+      r[i++] = itl.nextNvc();  
     }
     assertEquals(i, vs.length - 1);
     assertTrue(Arrays.equals(r, new Integer[] {1, 2, 3, 4, 5, 6, 7, null}));
diff --git a/uimaj-core/src/test/java/org/apache/uima/internal/util/rb_trees/IntArrayRBTtest.java b/uimaj-core/src/test/java/org/apache/uima/internal/util/rb_trees/IntArrayRBTtest.java
index 4344825..c17704f 100644
--- a/uimaj-core/src/test/java/org/apache/uima/internal/util/rb_trees/IntArrayRBTtest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/internal/util/rb_trees/IntArrayRBTtest.java
@@ -31,7 +31,8 @@
   private final static int NIL = 0;
   static final Random rand = new Random();    
   static {  
-     long seed = -585739628489294672L /* rand.nextLong() */ ;
+//     long seed = -585739628489294672L;
+     long seed = rand.nextLong();
      rand.setSeed(seed);
      System.out.println("IntArrayRBTtest seed is " + seed);
   }
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 720e4a6..0a4502c 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
@@ -24,6 +24,7 @@
 import java.util.concurrent.ConcurrentHashMap;

 import java.util.concurrent.ConcurrentMap;

 import java.util.concurrent.atomic.AtomicBoolean;

+import java.util.zip.DataFormatException;

 

 import org.apache.uima.internal.util.Misc;

 import org.apache.uima.internal.util.MultiThreadUtils;

@@ -34,12 +35,22 @@
 public class JCasHashMapTest extends TestCase {

   

   static final int SIZE = 20000;  // set > 2 million for cache avoidance timing tests

-  static final long SEED = 12345;

-  static Random r = new Random(SEED);

-  static private int[] addrs = new int[SIZE];

-  static int prev = 0;

+

+  static final Random r = new Random();

+  static final long SEED = r.nextLong();

+//      -6419339010654937562L;  // causes skew

+  // 12345;

+  static {

+    System.out.println("JCasHashMapTest load: set random seed to " + SEED);

+    r.setSeed(SEED);

+  }

   

-  static {  

+  static private int[] addrs = new int[SIZE];

+  

+  static { createAddrs(); } 

+

+  private static void createAddrs() {

+    int prev = 0;

     // unique numbers

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

       addrs[i] = prev = prev + r.nextInt(14) + 1;

@@ -50,7 +61,7 @@
       int temp = addrs[i];

       addrs[i] = addrs[ir];

       addrs[ir] = temp;

-    }

+    }    

   }

   

   private final AtomicBoolean okToProceed = new AtomicBoolean(); 

@@ -132,7 +143,7 @@
 

   public void testMultiThreadCompare() throws Exception {

     final Random random = new Random();

-    random.setSeed(1234L);  // debug

+//    random.setSeed(1234L);  // debug

     int numberOfThreads = Misc.numberOfCores;    

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

 

@@ -364,7 +375,7 @@
     JCasHashMap m = new JCasHashMap(200); // true = do use cache 

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

        

-    long start = System.currentTimeMillis();

+    long start = System.nanoTime();

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

       final int key = addrs[i];

       m.putIfAbsent(key, k -> TOP._createSearchKey(k));

@@ -375,11 +386,11 @@
 //        m.put(fs);

 //      }

     }

-    

+    long stop = System.nanoTime();

     assertEquals(m.getApproximateSize(), n);

     

-    System.out.format("time for v1 %,d is %,d ms%n",

-        n, System.currentTimeMillis() - start);

+    System.out.format("time for v1 %,d is %,d microsecs%n",

+        n, (stop - start)/1000);

     m.showHistogram();

 

   }

@@ -405,20 +416,20 @@
     for (int i = 0; i < n; i++) {

       final int key = addrs[i];

       TOP fs = (TOP) m.get(key);

-      if (fs == null) {  // for debugging

-        System.out.println("stop");

-      }

+//      if (fs == null) {  // for debugging

+//        System.out.println("debug stop");

+//        fail();

+//      }

       assertTrue(null != fs);

     }

 

   }

   

-  public void testGrowth() {

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

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

+  private void innerTstGrowth() throws DataFormatException {

+    for (int th = 2; th <= 128; th *= 2) {  // 2 4 8 16   32 64 128 256

       JCasHashMap.setDEFAULT_CONCURRENCY_LEVEL(th);

       double loadfactor = .6;  // from JCasHashMap impl

-      int sub_capacity = 32;   // from JCasHashMap impl

+      final int sub_capacity = 32;   // from JCasHashMap impl

       int subs = th;

       int agg_capacity = subs * sub_capacity;

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

@@ -426,7 +437,7 @@
       assertEquals(agg_capacity, m.getCapacity());

        

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

-      fill(switchpoint, m);

+      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:  ");

@@ -468,10 +479,26 @@
 //      System.out.print("JCasHashMapTest: clear (size below 4th time: ");

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

     }

+    

+  }

+  

+  public void testGrowth() {

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

+    while (true) { // loop for skew retry

+      boolean skewOk = true;

+      try {  // catch for skew retry

+        innerTstGrowth();

+      } catch (DataFormatException e) {  // hijacked this exception to avoid making a custom one

+        skewOk = false;

+      }

+      if (skewOk) break;

+      System.out.println("\n*******************\nJCasHashMapTest growth excessive skew retry\n*******************\n");

+      createAddrs();  // do a new set, hope it has less skew

+    }

   }

 

   private boolean checkSubsCapacity(JCasHashMap m, int v) {

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

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

   }

   

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

@@ -488,6 +515,18 @@
     return true;

   }

   

+  private boolean isSkewed(JCasHashMap m, int n) throws DataFormatException {

+    int[] subsizes = m.getSubSizes();

+    int limit = n / subsizes.length;  // for 128 entries, over 4 submaps, = 32 avg size

+    limit = limit * 2; // allow 4x

+    for (int i : subsizes) {

+      if (i >= limit) {

+        throw new DataFormatException();

+      }

+    }

+    return false;

+  }

+  

   private String intList(int[] a) {

     StringBuilder sb = new StringBuilder();

     for (int i : a) {

@@ -512,7 +551,7 @@
     return sb.toString();

   }

   

-  private void fill (int n, JCasHashMap m) {

+  private void fill (int n, JCasHashMap m) throws DataFormatException {

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

       final int key = addrs[i];

       m.putIfAbsent(key, k -> TOP._createSearchKey(k));

@@ -522,5 +561,7 @@
 //      m.put(fs);

 //      System.out.format("JCasHashMapTest fill %s%n",  intList(m.getCapacities()));

     }

+    

+    isSkewed(m, n);  // throws if skewed to retry test from top

   }

 }

diff --git a/uimaj-core/src/test/java/org/apache/uima/jcas/test/CASTestSetup.java b/uimaj-core/src/test/java/org/apache/uima/jcas/test/CASTestSetup.java
index 8fc8f10..a568411 100644
--- a/uimaj-core/src/test/java/org/apache/uima/jcas/test/CASTestSetup.java
+++ b/uimaj-core/src/test/java/org/apache/uima/jcas/test/CASTestSetup.java
@@ -112,6 +112,10 @@
   public static final String FS_ARRAY_LIST = "org.apache.uima.jcas.cas.FSArrayList";
 
   public static final String FS_HASH_SET = "org.apache.uima.jcas.cas.FSHashSet";
+  
+  public static final String FS_LINKED_HASH_SET = "org.apache.uima.jcas.cas.FSLinkedHashSet";
+  
+  public static final String INT_2_FS = "org.apache.uima.jcas.cas.Int2FS";
 
   /**
    * Constructor for CASTestSetup.
@@ -236,7 +240,10 @@
     tsm.addFeature("fsArray", fsArrayListType, typeArrayRef);
     Type fsHashSetType = tsm.addType(FS_HASH_SET, topType);
     tsm.addFeature("fsArray", fsHashSetType, typeArrayRef);
-
+    Type fsLinkedHashSetType = tsm.addType(FS_LINKED_HASH_SET, fsHashSetType);
+    Type int2FSType = tsm.addType(INT_2_FS, topType);
+    tsm.addFeature("fsArray", int2FSType, typeArrayRef);
+    tsm.addFeature("intArray",  int2FSType,  typeArrayInt);     
   }
 
   public void initIndexes(FSIndexRepositoryMgr irm, TypeSystem ts) {
diff --git a/uimaj-core/src/test/java/org/apache/uima/jcas/test/FSArrayListTest.java b/uimaj-core/src/test/java/org/apache/uima/jcas/test/FSArrayListTest.java
index 1705c7a..ed8781d 100644
--- a/uimaj-core/src/test/java/org/apache/uima/jcas/test/FSArrayListTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/jcas/test/FSArrayListTest.java
@@ -56,7 +56,7 @@
 

 	public void setUp() throws Exception {

 		this.cas = CASInitializer.initCas(new CASTestSetup(),

-		    null

+		    null  // FsArrayList type setup in CASTestSetup's initTypeSystem

 //		    (tsm -> {

 //		      Type fsat = tsm.addType("org.apache.uima.jcas.cas.FSArrayList", tsm.getTopType());

 //		      tsm.addFeature("fsArray", fsat, tsm.getType("uima.cas.FSArray"));

diff --git a/uimaj-core/src/test/java/org/apache/uima/jcas/test/FSHashSetTest.java b/uimaj-core/src/test/java/org/apache/uima/jcas/test/FSHashSetTest.java
index c213887..e8c7110 100644
--- a/uimaj-core/src/test/java/org/apache/uima/jcas/test/FSHashSetTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/jcas/test/FSHashSetTest.java
@@ -26,6 +26,9 @@
 import org.apache.uima.jcas.JCas;

 import org.apache.uima.jcas.cas.FSArray;

 import org.apache.uima.jcas.cas.FSHashSet;

+import org.apache.uima.jcas.cas.FSLinkedHashSet;

+import org.apache.uima.jcas.cas.Int2FS;

+import org.apache.uima.util.IntEntry;

 

 import junit.framework.TestCase;

 import x.y.z.EndOfSentence;

@@ -41,8 +44,6 @@
 

 	private JCas jcas;

 

-	private TypeSystem ts;

-

 	public EndOfSentence endOfSentenceInstance;

 

 	public FSHashSetTest(String arg0) {

@@ -58,30 +59,59 @@
 //		    }

 //		    )

 		    );

-		this.ts = this.cas.getTypeSystem();

 		this.jcas = cas.getJCas();

 	}

 

-	public void testBasic() {

-	  FSHashSet<Token> set = new FSHashSet<>(jcas);

-	  Token t1 = new Token(jcas);

+	private void basic(FSHashSet<Token> s) {

+    FSHashSet<Token> set = s;

+    Token t1 = new Token(jcas);

     Token t2 = new Token(jcas);

-	  set.add(t1);

-	  set.add(t2);

-	  set.remove(t1);

-	  

-	  assertEquals(1, set.size());

-	  

+    set.add(t1);

+    set.add(t2);

+    set.remove(t1);

+    

+    assertEquals(1, set.size());

+    

     Iterator<Token> it = set.iterator();

     Token k = null;

-	  while (it.hasNext()) {

-	    assertNotNull(k = it.next());

-	  }

-	  assertNotNull(k);

-	  set._save_fsRefs_to_cas_data();

-	  FSArray fa = (FSArray) set.getFeatureValue(set.getType().getFeatureByBaseName("fsArray"));

-	  assertNotNull(fa);

-	  assertEquals(fa.get(0), k);

+    while (it.hasNext()) {

+      assertNotNull(k = it.next());

+    }

+    assertNotNull(k);

+    set._save_fsRefs_to_cas_data();

+    FSArray fa = (FSArray) set.getFeatureValue(set.getType().getFeatureByBaseName("fsArray"));

+    assertNotNull(fa);

+    assertEquals(fa.get(0), k);	  

+	}

+	

+	public void testBasic() {

+	  basic(new FSHashSet<>(jcas));

+	  basic(new FSLinkedHashSet<>(jcas));

+	}

+	

+	public void testBasicInt2FS() {

+	  Int2FS<Token> m = new Int2FS<>(jcas);

+	  Int2FS<Token> m2 = new Int2FS<>(jcas, 11);

+

+    Token t1 = new Token(jcas);

+    Token t2 = new Token(jcas);

+    m.put(t1._id(), t1);

+    m.put(t2._id(), t2);

+    m.remove(t1._id());

+

+    assertEquals(1, m.size());

+    

+    Iterator<IntEntry<Token>> it = m.iterator();

+    IntEntry<Token> k = null;

+    while (it.hasNext()) {

+      assertNotNull(k = it.next());

+    }

+    assertNotNull(k);

+    m._save_fsRefs_to_cas_data();

+    FSArray fa = (FSArray) m.getFeatureValue(m.getType().getFeatureByBaseName("fsArray"));

+    assertNotNull(fa);

+    assertEquals(fa.get(0), k.getValue());   

+

 	}

 	

 

diff --git a/uimaj-core/src/test/java/org/apache/uima/jcas/test/JCasTest.java b/uimaj-core/src/test/java/org/apache/uima/jcas/test/JCasTest.java
index ad4c014..0a43299 100644
--- a/uimaj-core/src/test/java/org/apache/uima/jcas/test/JCasTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/jcas/test/JCasTest.java
@@ -23,6 +23,7 @@
 import java.util.Iterator;
 import java.util.PrimitiveIterator.OfInt;
 
+import org.apache.uima.UIMARuntimeException;
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASException;
 import org.apache.uima.cas.CASRuntimeException;
@@ -83,7 +84,7 @@
 
 	private JCas jcas;
 
-	private TypeSystem ts;
+//	private TypeSystem ts;
 
 	public EndOfSentence endOfSentenceInstance;
 
@@ -100,7 +101,7 @@
 		try {
 			try {
 				this.cas = CASInitializer.initCas(new CASTestSetup(), null);
-				this.ts = this.cas.getTypeSystem();
+//				this.ts = this.cas.getTypeSystem();
 				this.jcas = cas.getJCas();
 				endOfSentenceInstance = new EndOfSentence(jcas);
 			} catch (Exception e1) {
@@ -128,8 +129,8 @@
 	}
 
 	public void checkExpectedBadCASError(Exception e1, String err) {
-		if (e1 instanceof CASRuntimeException) {
-			CASRuntimeException e = (CASRuntimeException) e1;
+		if (e1 instanceof UIMARuntimeException) {
+			UIMARuntimeException e = (UIMARuntimeException) e1;
 			System.out.print("\nCaught CAS Exception with message: ");
 			String m = e1.getMessage();
 			System.out.println(m);
@@ -142,7 +143,7 @@
 
 	public void tearDown() {
 		this.cas = null;
-		this.ts = null;
+//		this.ts = null;
 		this.jcas = null;
 		this.endOfSentenceInstance = null;
 	}
@@ -150,12 +151,12 @@
 	public void testMissingFeatureInCas() throws Exception {
 		try {
 			// jcasCasMisMatch(CASTestSetup.BAD_MISSING_FEATURE_IN_CAS, CASException.JCAS_INIT_ERROR);
-			CAS localCas;
-			JCas localJcas = null;
-			boolean errFound = false;
+//			CAS localCas;
+//			JCas localJcas = null;
+//			boolean errFound = false;
 			try {
 			  // error happens during setup
-				localCas = CASInitializer.initCas(new CASTestSetup(CASTestSetup.BAD_MISSING_FEATURE_IN_CAS), null);
+				/*localCas =*/ CASInitializer.initCas(new CASTestSetup(CASTestSetup.BAD_MISSING_FEATURE_IN_CAS), null);
 			} catch (CASRuntimeException e) {
 				assertTrue(e.getMessageKey().equals(CASException.JCAS_INIT_ERROR));
 			}
@@ -166,7 +167,7 @@
 
 	public void testChangedFType() throws Exception {
 		try {
-			jcasCasMisMatch(CASTestSetup.BAD_CHANGED_FEATURE_TYPE, CASException.JCAS_INIT_ERROR);
+			jcasCasMisMatch(CASTestSetup.BAD_CHANGED_FEATURE_TYPE, UIMARuntimeException.INTERNAL_ERROR);
 		} catch (Exception e) {
 			JUnitExtension.handleException(e);
 		}
@@ -174,11 +175,11 @@
 
 	public void jcasCasMisMatch(int testId, String expectedErr) throws Exception {
 		try {
-			CAS localCas;
-			JCas localJcas;
+//			CAS localCas;
+//			JCas localJcas;
 			boolean errFound = false;
 			try {
-				localCas = CASInitializer.initCas(new CASTestSetup(testId), null);
+				/*localCas = */CASInitializer.initCas(new CASTestSetup(testId), null);
 //				ts = this.cas.getTypeSystem();
 //				try {
 //					localJcas = localCas.getJCas();
@@ -201,9 +202,9 @@
 		something.addToIndexes();
 
 		JFSIndexRepository ir = jcas.getJFSIndexRepository();
-		FSIterator i1 = ir.getAnnotationIndex().iterator();
-		FSIterator i2 = i1.copy();
-		FSIterator i3 = i2.copy();
+		FSIterator<Annotation> i1 = ir.getAnnotationIndex().iterator();
+		FSIterator<Annotation> i2 = i1.copy();
+		FSIterator<Annotation> i3 = i2.copy();
 		assertTrue(i3 != null);
 	}
 
@@ -255,7 +256,7 @@
 			CASImpl casImpl = jcas.getCasImpl();
 			assertTrue(casImpl == this.cas);
 
-			Annotation a1 = new Annotation(jcas, 4, 5);
+			/* Annotation a1 =*/ new Annotation(jcas, 4, 5);
 		} catch (Exception e) {
 			JUnitExtension.handleException(e);
 		}
@@ -348,8 +349,8 @@
 			r1.addToIndexes();
 
 			JFSIndexRepository jfsi = jcas.getJFSIndexRepository();
-			FSIndex fsi1 = jfsi.getIndex("all", Root.type);
-			FSIterator fsit1 = fsi1.iterator();
+			FSIndex<Root> fsi1 = jfsi.getIndex("all", Root.type);
+			FSIterator<Root> fsit1 = fsi1.iterator();
 			assertTrue(fsit1.isValid());
 			Root[] fetched = new Root[2];
 			
@@ -409,7 +410,7 @@
 				// System.out.print("m");
 			}
 			JFSIndexRepository jir = jcas.getJFSIndexRepository();
-			FSIterator it = jir.getIndex("all", Root.type).iterator();
+			FSIterator<Root> it = jir.<Root>getIndex("all", Root.type).iterator();
 			// System.out.print("\nTesting Random: ");
 			while (it.isValid()) {
 				root1.test(it.get());
@@ -466,7 +467,7 @@
 		try {
 			try {
 				CAS cas2 = CASInitializer.initCas(new CASTestSetup(), null);
-				TypeSystem ts2 = cas2.getTypeSystem();
+//				TypeSystem ts2 = cas2.getTypeSystem();
 				JCas jcas2 = cas2.getJCas();
 				if (TypeSystemImpl.IS_DISABLE_TYPESYSTEM_CONSOLIDATION) {
   				assertTrue(jcas.getCasType(Annotation.type).equals(jcas2.getCasType(Annotation.type)));
@@ -516,8 +517,8 @@
 			localCas.getIndexRepository().addFS(f1);
 
 			JFSIndexRepository ir = jcas.getJFSIndexRepository();
-			FSIndex index = ir.getAnnotationIndex();
-			FSIterator it = index.iterator();
+			FSIndex<Annotation> index = ir.getAnnotationIndex();
+			FSIterator<Annotation> it = index.iterator();
 
 			try {
 
@@ -548,7 +549,7 @@
 
 	public void testCreateFSafterReset() throws Exception {
 		try {
-			CAS localCas = jcas.getCas();
+//			CAS localCas = jcas.getCas();
 			cas.reset();
 			TypeSystem ts = cas.getTypeSystem();
 			Type fsl = ts.getType("uima.cas.NonEmptyFSList");
@@ -563,7 +564,7 @@
 		try {
 			Token tok1 = new Token(jcas);
 			tok1.addToIndexes();
-			FSIterator it = jcas.getJFSIndexRepository().getIndex("all", Token.type).iterator();
+			FSIterator<Token> it = jcas.getJFSIndexRepository().<Token>getIndex("all", Token.type).iterator();
 			while (it.hasNext()) {
 				Token token = (Token) it.next();
 				token.addToIndexes(); // something to do to keep Java from optimizing this away.
@@ -573,18 +574,62 @@
 		}
 	}
 
+	// THis test is Java impl specific, works with Oracle Java 7 and 8, not tested with other Javas
+	// uncomment to run, but normally commented out.
+//  public void testSubiterator() throws Exception {
+//    for (int i = 0; i < 5; i++) {   // tokens: 0,1,  1,3   2,5,  3,7  4,9
+//      Token tok1 = new Token(jcas, i, 1 + 2*i);
+//      tok1.addToIndexes();
+//    }
+//    FSIndexRepositoryMgr irm = (FSIndexRepositoryMgr)jcas.getIndexRepository();
+//    TypeSystem ts = cas.getTypeSystem();
+//    LinearTypeOrder lo = irm.getDefaultTypeOrder();
+//    Type tokenType = ts.getType("x.y.z.Token");
+//    Type sentenceType = ts.getType("x.y.z.Sentence");
+//    Type annotType = ts.getType(CAS.TYPE_NAME_ANNOTATION);
+//
+//    boolean java7 = System.getProperty("java.version").startsWith("1.7");
+//    
+//    /*********************************************************
+//     * Surprise: Type Order is different between Java 7 and 8
+//     *********************************************************/
+//    assertEquals(java7, lo.lessThan(annotType, tokenType));   // annotation < token for java 7, opposite for Java 8
+//    assertTrue(lo.lessThan(sentenceType, tokenType));
+//    
+//    
+//    /********************************************************
+//     * This iterator is always empty 
+//     ********************************************************/
+//    Iterator<Annotation> iter = jcas.getAnnotationIndex(Token.type).subiterator(new Token(jcas, 2, 5));
+//    assertFalse(iter.hasNext()); // because is empty because of definition of where to start, step #2 (see above)
+//
+//    /*********************************************************
+//     * Surprise: This iterator is empty only for Java 8
+//     *   due to type ordering
+//     *********************************************************/
+//    iter = jcas.getAnnotationIndex(Token.type).subiterator(new Annotation(jcas, 2, 5));
+//    assertEquals(java7, iter.hasNext()); // Ok for java 7, empty for java 8 because of type order difference 
+//
+//    /*********************************************************
+//     * This iterator is never empty because type order for
+//     * Sentence is before Token in both Java 7 and 8
+//     *********************************************************/
+//    iter = jcas.getAnnotationIndex(Token.type).subiterator(new Sentence(jcas, 2, 5));
+//    assertTrue(iter.hasNext());    // OK for both, because Sentence is before Token in both Java 7 and 8    
+//  }  
+  
 	public void testGetNthFSList() throws Exception {
 		try {
 			Token tok1 = new Token(jcas);
 			Token tok2 = new Token(jcas);
 
-			NonEmptyFSList fsList1 = new NonEmptyFSList(jcas);
+			NonEmptyFSList<Token> fsList1 = new NonEmptyFSList<>(jcas);
 			fsList1.setHead(tok2);
-			fsList1.setTail(new EmptyFSList(jcas));
-			NonEmptyFSList fsList = new NonEmptyFSList(jcas);
+			fsList1.setTail(new EmptyFSList<>(jcas));
+			NonEmptyFSList<Token> fsList = new NonEmptyFSList<>(jcas);
 			fsList.setHead(tok1);
 			fsList.setTail(fsList1);
-			EmptyFSList emptyFsList = new EmptyFSList(jcas);
+			/* EmptyFSList emptyFsList = */ new EmptyFSList<Token>(jcas);
 
 //			try {
 //				emptyFsList.getNthElement(0);
@@ -781,7 +826,7 @@
 	}
 
   public void testFSListAPI() {
-    FSList sl = new EmptyFSList(jcas);
+    FSList<TOP> sl = new EmptyFSList<>(jcas);
     TOP fs1 = new TOP(jcas);
     TOP fs2 = new TOP(jcas);
     sl = sl.push(fs2);
@@ -789,6 +834,12 @@
    
     TOP[] fss = new TOP[2];
     int i = 0;
+    Iterator<TOP> it = sl.iterator();
+    while (it.hasNext()) {
+      fss[i++] = it.next();
+    }
+    
+    i = 0;   
     for (TOP s : sl) {
       fss[i++] = s;
     }
@@ -798,14 +849,16 @@
   }
 	  
   public void testFSArrayAPI() {
-    FSArray sa = new FSArray(jcas, 2);
+    FSArray sa = new FSArray<>(jcas, 2);
     TOP fs1 = new TOP(jcas);
     TOP fs2 = new TOP(jcas);
     TOP[] values = {fs1, fs2}; 
     sa.copyFromArray(values, 0, 0, 2);
     
     int i = 0;
-    for (FeatureStructure s : sa) {
+    sa.iterator();
+    
+    for (Object s : sa) {
       assert(s.equals(values[i++]));
     }
   }
@@ -908,22 +961,22 @@
       assertEquals(expectedDoa[i++], v);
     }
     
-  }
-
+  }  
+  
   public void testUndefinedType() throws Exception {
     //create jcas with no type system
-    JCas jcas = CasCreationUtils.createCas(new TypeSystemDescription_impl(), null, null).getJCas();
-    jcas.setDocumentText("This is a test.");
+    JCas localJcas = CasCreationUtils.createCas(new TypeSystemDescription_impl(), null, null).getJCas();
+    localJcas.setDocumentText("This is a test.");
     try {
       //this should throw an exception
-      jcas.getCasType(Sentence.type);
+      localJcas.getCasType(Sentence.type);
       fail(); 
     } catch(CASRuntimeException e) {
       assertEquals(CASRuntimeException.JCAS_TYPE_NOT_IN_CAS, e.getMessageKey());
     }
     //check that this does not leave JCAS in an inconsistent state
     //(a check for bug UIMA-738)
-    Iterator<Annotation> iter = jcas.getAnnotationIndex().iterator();
+    Iterator<Annotation> iter = localJcas.getAnnotationIndex().iterator();
     assertTrue(iter.hasNext());
     Annotation annot = iter.next();
     assertEquals("This is a test.", annot.getCoveredText());
diff --git a/uimaj-core/src/test/java/org/apache/uima/resource/metadata/impl/FsIndexCollection_implTest.java b/uimaj-core/src/test/java/org/apache/uima/resource/metadata/impl/FsIndexCollection_implTest.java
index 8c157d4..abaa8a7 100644
--- a/uimaj-core/src/test/java/org/apache/uima/resource/metadata/impl/FsIndexCollection_implTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/resource/metadata/impl/FsIndexCollection_implTest.java
@@ -57,6 +57,7 @@
    */
   protected void tearDown() throws Exception {
     super.tearDown();
+    UIMAFramework.getXMLParser().enableSchemaValidation(false);
   }
 
   public void testBuildFromXmlElement() throws Exception {
diff --git a/uimaj-core/src/test/java/org/apache/uima/resource/metadata/impl/ResourceManagerConfiguration_implTest.java b/uimaj-core/src/test/java/org/apache/uima/resource/metadata/impl/ResourceManagerConfiguration_implTest.java
index b2d83e7..f9be566 100644
--- a/uimaj-core/src/test/java/org/apache/uima/resource/metadata/impl/ResourceManagerConfiguration_implTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/resource/metadata/impl/ResourceManagerConfiguration_implTest.java
@@ -57,6 +57,7 @@
    */
   protected void tearDown() throws Exception {
     super.tearDown();
+    UIMAFramework.getXMLParser().enableSchemaValidation(false);
   }
 
   public void testBuildFromXmlElement() throws Exception {
diff --git a/uimaj-core/src/test/java/org/apache/uima/resource/metadata/impl/TypePriorities_implTest.java b/uimaj-core/src/test/java/org/apache/uima/resource/metadata/impl/TypePriorities_implTest.java
index 631f24e..79084b6 100644
--- a/uimaj-core/src/test/java/org/apache/uima/resource/metadata/impl/TypePriorities_implTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/resource/metadata/impl/TypePriorities_implTest.java
@@ -57,6 +57,7 @@
    */
   protected void tearDown() throws Exception {
     super.tearDown();
+    UIMAFramework.getXMLParser().enableSchemaValidation(false);
   }
 
   public void testBuildFromXmlElement() throws Exception {
diff --git a/uimaj-core/src/test/java/org/apache/uima/resource/metadata/impl/TypeSystemDescription_implTest.java b/uimaj-core/src/test/java/org/apache/uima/resource/metadata/impl/TypeSystemDescription_implTest.java
index 79a1af7..8cb9eaa 100644
--- a/uimaj-core/src/test/java/org/apache/uima/resource/metadata/impl/TypeSystemDescription_implTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/resource/metadata/impl/TypeSystemDescription_implTest.java
@@ -61,6 +61,7 @@
    */
   protected void tearDown() throws Exception {
     super.tearDown();
+    UIMAFramework.getXMLParser().enableSchemaValidation(false);
   }
 
   public void testBuildFromXmlElement() throws Exception {
diff --git a/uimaj-core/src/test/java/org/apache/uima/testTypeSystem_arrays/OfShorts.java b/uimaj-core/src/test/java/org/apache/uima/testTypeSystem_arrays/OfShorts.java
index b873fb0..97ea6d4 100644
--- a/uimaj-core/src/test/java/org/apache/uima/testTypeSystem_arrays/OfShorts.java
+++ b/uimaj-core/src/test/java/org/apache/uima/testTypeSystem_arrays/OfShorts.java
@@ -19,24 +19,36 @@
 
 
    
-/* Apache UIMA v3 - First created by JCasGen Wed Mar 02 13:49:16 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:26:22 EDT 2017 */
 
 package org.apache.uima.testTypeSystem_arrays;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
-import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCas; 
 import org.apache.uima.jcas.JCasRegistry;
+
+
 import org.apache.uima.jcas.cas.ShortArray;
 import org.apache.uima.jcas.tcas.Annotation;
 
 
 /** 
- * Updated by JCasGen Wed Mar 02 13:49:16 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/experiment-v3-jcas/uimaj-core/src/test/resources/ExampleCas/testTypeSystem_arrays.xml
+ * Updated by JCasGen Sun Oct 08 19:26:22 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/resources/ExampleCas/testTypeSystem_arrays.xml
  * @generated */
 public class OfShorts extends Annotation {
+ 
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "org.apache.uima.testTypeSystem_arrays.OfShorts";
+  
   /** @generated
    * @ordered 
    */
@@ -58,8 +70,12 @@
    *   Feature Offsets *
    * *******************/ 
    
+  public final static String _FeatName_f1Shorts = "f1Shorts";
+
+
   /* Feature Adjusted Offsets */
-  public final static int _FI_f1Shorts = TypeSystemImpl.getAdjustedFeatureOffset("f1Shorts");
+  private final static CallSite _FC_f1Shorts = TypeSystemImpl.createCallSite(OfShorts.class, "f1Shorts");
+  private final static MethodHandle _FH_f1Shorts = _FC_f1Shorts.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -84,6 +100,19 @@
     readObject();   
   } 
 
+
+  /** @generated
+   * @param jcas JCas to which this Feature Structure belongs
+   * @param begin offset to the begin spot in the SofA
+   * @param end offset to the end spot in the SofA 
+  */  
+  public OfShorts(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }   
+
   /** 
    * <!-- begin-user-doc -->
    * Write your own initialization here
@@ -102,14 +131,14 @@
    * @generated
    * @return value of the feature 
    */
-  public ShortArray getF1Shorts() { return (ShortArray)(_getFeatureValueNc(_FI_f1Shorts));}
+  public ShortArray getF1Shorts() { return (ShortArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_f1Shorts)));}
     
   /** setter for f1Shorts - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setF1Shorts(ShortArray v) {
-    _setFeatureValueNcWj(_FI_f1Shorts, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_f1Shorts), v);
   }    
     
     
@@ -119,7 +148,7 @@
    * @return value of the element at index i 
    */
   public short getF1Shorts(int i) {
-     return ((ShortArray)(_getFeatureValueNc(_FI_f1Shorts))).get(i);} 
+     return ((ShortArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_f1Shorts)))).get(i);} 
 
   /** indexed setter for f1Shorts - sets an indexed value - 
    * @generated
@@ -127,7 +156,7 @@
    * @param v value to set into the array 
    */
   public void setF1Shorts(int i, short v) {
-    ((ShortArray)(_getFeatureValueNc(_FI_f1Shorts))).set(i, v);
+    ((ShortArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_f1Shorts)))).set(i, v);
   }  
   }
 
diff --git a/uimaj-core/src/test/java/org/apache/uima/testTypeSystem_arrays/OfStrings.java b/uimaj-core/src/test/java/org/apache/uima/testTypeSystem_arrays/OfStrings.java
index d04cefb..a7feedb 100644
--- a/uimaj-core/src/test/java/org/apache/uima/testTypeSystem_arrays/OfStrings.java
+++ b/uimaj-core/src/test/java/org/apache/uima/testTypeSystem_arrays/OfStrings.java
@@ -19,24 +19,36 @@
 
 
    
-/* Apache UIMA v3 - First created by JCasGen Wed Mar 02 13:49:16 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:26:22 EDT 2017 */
 
 package org.apache.uima.testTypeSystem_arrays;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
-import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCas; 
 import org.apache.uima.jcas.JCasRegistry;
+
+
 import org.apache.uima.jcas.cas.StringArray;
 import org.apache.uima.jcas.tcas.Annotation;
 
 
 /** 
- * Updated by JCasGen Wed Mar 02 13:49:16 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/experiment-v3-jcas/uimaj-core/src/test/resources/ExampleCas/testTypeSystem_arrays.xml
+ * Updated by JCasGen Sun Oct 08 19:26:22 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/resources/ExampleCas/testTypeSystem_arrays.xml
  * @generated */
 public class OfStrings extends Annotation {
+ 
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "org.apache.uima.testTypeSystem_arrays.OfStrings";
+  
   /** @generated
    * @ordered 
    */
@@ -58,8 +70,12 @@
    *   Feature Offsets *
    * *******************/ 
    
+  public final static String _FeatName_f1Strings = "f1Strings";
+
+
   /* Feature Adjusted Offsets */
-  public final static int _FI_f1Strings = TypeSystemImpl.getAdjustedFeatureOffset("f1Strings");
+  private final static CallSite _FC_f1Strings = TypeSystemImpl.createCallSite(OfStrings.class, "f1Strings");
+  private final static MethodHandle _FH_f1Strings = _FC_f1Strings.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -84,6 +100,19 @@
     readObject();   
   } 
 
+
+  /** @generated
+   * @param jcas JCas to which this Feature Structure belongs
+   * @param begin offset to the begin spot in the SofA
+   * @param end offset to the end spot in the SofA 
+  */  
+  public OfStrings(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }   
+
   /** 
    * <!-- begin-user-doc -->
    * Write your own initialization here
@@ -102,14 +131,14 @@
    * @generated
    * @return value of the feature 
    */
-  public StringArray getF1Strings() { return (StringArray)(_getFeatureValueNc(_FI_f1Strings));}
+  public StringArray getF1Strings() { return (StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_f1Strings)));}
     
   /** setter for f1Strings - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setF1Strings(StringArray v) {
-    _setFeatureValueNcWj(_FI_f1Strings, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_f1Strings), v);
   }    
     
     
@@ -119,7 +148,7 @@
    * @return value of the element at index i 
    */
   public String getF1Strings(int i) {
-     return ((StringArray)(_getFeatureValueNc(_FI_f1Strings))).get(i);} 
+     return ((StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_f1Strings)))).get(i);} 
 
   /** indexed setter for f1Strings - sets an indexed value - 
    * @generated
@@ -127,7 +156,7 @@
    * @param v value to set into the array 
    */
   public void setF1Strings(int i, String v) {
-    ((StringArray)(_getFeatureValueNc(_FI_f1Strings))).set(i, v);
+    ((StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_f1Strings)))).set(i, v);
   }  
   }
 
diff --git a/uimaj-core/src/test/java/org/apache/uima/util/CasCopierTest.java b/uimaj-core/src/test/java/org/apache/uima/util/CasCopierTest.java
index 8ab2de7..eb99670 100644
--- a/uimaj-core/src/test/java/org/apache/uima/util/CasCopierTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/util/CasCopierTest.java
@@ -304,7 +304,8 @@
 
     CasComparer cci = new CasComparer();
     // copy all entities
-    Iterator<TOP> it = srcCas.getIndexRepository().getAllIndexedFS(srcCas.getTypeSystem().getType("org.apache.uima.testTypeSystem.Entity"));
+    Iterator<TOP> it = srcCas.getIndexRepository().getIndexedFSs(srcCas.getTypeSystem().getType("org.apache.uima.testTypeSystem.Entity")).iterator();
+//    Iterator<TOP> it = srcCas.getIndexRepository().getAllIndexedFS(srcCas.getTypeSystem().getType("org.apache.uima.testTypeSystem.Entity"));
 //    while(it.hasNext()) {
       TOP fs = it.next();
       TOP fsc = (TOP) copier.copyFs(fs);
diff --git a/uimaj-core/src/test/java/org/apache/uima/util/CasIOUtilsTest.java b/uimaj-core/src/test/java/org/apache/uima/util/CasIOUtilsTest.java
index 86fe49b..91064de 100644
--- a/uimaj-core/src/test/java/org/apache/uima/util/CasIOUtilsTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/util/CasIOUtilsTest.java
@@ -28,21 +28,22 @@
 import java.io.ObjectOutput;
 import java.io.ObjectOutputStream;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 
 import org.apache.uima.UIMAFramework;
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASRuntimeException;
-import org.apache.uima.cas.FSIterator;
-import org.apache.uima.cas.FeatureStructure;
 import org.apache.uima.cas.SerialFormat;
+import org.apache.uima.jcas.cas.TOP;
 import org.apache.uima.resource.metadata.FsIndexDescription;
 import org.apache.uima.resource.metadata.TypeSystemDescription;
 import org.apache.uima.resource.metadata.impl.TypePriorities_impl;
 import org.apache.uima.test.junit_extension.JUnitExtension;
-
 import org.junit.Assert;
+
 import junit.framework.TestCase;
 
 public class CasIOUtilsTest extends TestCase{
@@ -117,12 +118,12 @@
   
   public void testXCAS() throws Exception
   {
-    testXMI(false);
+    testXCAS(false);
   }
 
   public void testXCASLenient() throws Exception
   {
-    testXMI(true);
+    testXCAS(true);
   }
 
   public void testXCAS(boolean leniently) throws Exception {
@@ -218,11 +219,14 @@
     }
     
     List<String> fsTypes = new ArrayList<>();
-    FSIterator<FeatureStructure> fsi = cas.getIndexRepository()
-            .getAllIndexedFS(cas.getTypeSystem().getTopType());
+//    FSIterator<FeatureStructure> fsi = cas.getIndexRepository()
+//            .getAllIndexedFS(cas.getTypeSystem().getTopType());
+    Collection<TOP> s = cas.getIndexedFSs();
+    Iterator<TOP> fsi = s.iterator();
     int fsCount = 0;
     while (fsi.hasNext()) {
-      String typeName = fsi.next().getType().getName();
+      TOP fs = (TOP) fsi.next();
+      String typeName = fs.getType().getName();
       if (!fsTypes.contains(typeName)) {
         fsTypes.add(typeName);
       }
diff --git a/uimaj-core/src/test/java/org/apache/uima/util/CasToInlineXmlTest.java b/uimaj-core/src/test/java/org/apache/uima/util/CasToInlineXmlTest.java
index 7e1ee4b..52f1821 100644
--- a/uimaj-core/src/test/java/org/apache/uima/util/CasToInlineXmlTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/util/CasToInlineXmlTest.java
@@ -27,6 +27,7 @@
 import org.apache.uima.UIMAFramework;
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.impl.XmiCasDeserializer;
+import org.apache.uima.internal.util.Misc;
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.cas.ShortArray;
 import org.apache.uima.jcas.cas.StringArray;
@@ -138,10 +139,15 @@
     int s = result.indexOf("<Document>");
     result = result.substring(s);
     result = canonicalizeNl(result);
+    
+    // Java 9 xml formatter formats the text with a new line and indentations
     String expected = "<Document>\n" +
         IND+"<uima.tcas.DocumentAnnotation sofa=\"Sofa\" begin=\"0\" end=\"17\" language=\"x-unspecified\">\n" +
         IND+IND+"<org.apache.uima.testTypeSystem_arrays.OfStrings sofa=\"Sofa\" begin=\"0\" end=\"0\" f1Strings=\"[0s,1s,2s]\"/>\n"  +
-        IND+IND+"<org.apache.uima.testTypeSystem_arrays.OfShorts sofa=\"Sofa\" begin=\"0\" end=\"0\" f1Shorts=\"[0,1,2]\"/>1 2 3 4 5 6 7 8 9</uima.tcas.DocumentAnnotation>\n" +
+        IND+IND+"<org.apache.uima.testTypeSystem_arrays.OfShorts sofa=\"Sofa\" begin=\"0\" end=\"0\" f1Shorts=\"[0,1,2]\"/>"
+        		+ (Misc.isJava9ea() ? "\n        " : "") + 
+        		"1 2 3 4 5 6 7 8 9"
+        		+ (Misc.isJava9ea() ? "\n    " : "") + "</uima.tcas.DocumentAnnotation>\n" +
         "</Document>";
     for (int i = 0; i < result.length(); i++ ) {
       if (result.charAt(i) != expected.charAt(i)) {
diff --git a/uimaj-core/src/test/java/org/apache/uima/util/XMLSerializerTest.java b/uimaj-core/src/test/java/org/apache/uima/util/XMLSerializerTest.java
index b6c92b9..57edec6 100644
--- a/uimaj-core/src/test/java/org/apache/uima/util/XMLSerializerTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/util/XMLSerializerTest.java
@@ -20,10 +20,12 @@
 

 import java.io.ByteArrayOutputStream;

 

+import javax.xml.XMLConstants;

 import javax.xml.transform.OutputKeys;

 import javax.xml.transform.Transformer;

 import javax.xml.transform.TransformerFactory;

 

+import org.apache.uima.internal.util.XMLUtils;

 import org.xml.sax.ContentHandler;

 import org.xml.sax.SAXParseException;

 import org.xml.sax.helpers.AttributesImpl;

@@ -57,7 +59,8 @@
 //    if (xmlStr.contains("1.0")) {

     // useful to investigate issues when bad XML output is produced

     //   related to which Java implementation is being used

-      Transformer t = TransformerFactory.newInstance().newTransformer();

+      TransformerFactory transformerFactory = XMLUtils.createTransformerFactory();

+      Transformer t = transformerFactory.newTransformer();

       t.setOutputProperty(OutputKeys.VERSION, "1.1");

       

       System.out.println("Java version is " + 

@@ -86,7 +89,7 @@
       ch.characters(data, 0, 4);

     } catch (SAXParseException e) {

       String msg = e.getMessage();

-      String expected = "Trying to serialize non-XML 1.0 character: " + (char)5 + ", 0x5 at offset 2";

+      String expected = "Trying to serialize non-XML 1.0 character: " + "0x5 at offset 2";

       assertEquals(msg.substring(0, expected.length()), expected);

       eh = true;

     }  

@@ -126,7 +129,7 @@
     } catch (SAXParseException e) {

       String msg = e.getMessage();

       System.out.println(msg);

-      String expected = "Trying to serialize non-XML 1.1 character: " + (char)0 + ", 0x0 at offset 2";

+      String expected = "Trying to serialize non-XML 1.1 character: " + "0x0 at offset 2";

       assertEquals(msg.substring(0, expected.length()), expected);

       eh = true;

     }  

diff --git a/uimaj-core/src/test/java/org/apache/uima/util/impl/JSR47Logger_implTest.java b/uimaj-core/src/test/java/org/apache/uima/util/impl/JSR47Logger_implTest.java
index 7a29a9a..25686d4 100644
--- a/uimaj-core/src/test/java/org/apache/uima/util/impl/JSR47Logger_implTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/util/impl/JSR47Logger_implTest.java
@@ -55,6 +55,7 @@
     // Set the root logger's level to INFO ... may not be the default
     java.util.logging.Logger.getLogger("").setLevel(java.util.logging.Level.INFO);
 
+    try {
     org.apache.uima.util.Logger uimaLogger = JSR47Logger_impl.getInstance();
     org.apache.uima.util.Logger classLogger = JSR47Logger_impl.getInstance(this.getClass());
     uimaLogger.setLevel(null);  // causes it to inherit from above
@@ -65,24 +66,29 @@
     Assert.assertNotNull(classLogger);
     Assert.assertTrue(uimaLogger.isLoggable(Level.INFO));
     Assert.assertTrue(classLogger.isLoggable(Level.INFO));
+    } finally {
+      java.util.logging.Logger.getLogger("").setLevel(java.util.logging.Level.INFO);
+
+    }
   }
 
   public void testIsLoggable() throws Exception {
     // create logger
     org.apache.uima.util.Logger uimaLogger = JSR47Logger_impl.getInstance();
     org.apache.uima.util.Logger classLogger = JSR47Logger_impl.getInstance(this.getClass());
-    uimaLogger.setLevel(null);  // causes it to inherit from above
-    classLogger.setLevel(null);  // causes it to inherit from above
-
     //get uimaLogger log level, get parent logger of "org.apache.uima" until we have the
     //JSR47 root logger that defines the default log level
     Logger jsrLogger = java.util.logging.Logger.getLogger("org.apache.uima");
     while(jsrLogger.getLevel() == null) {
       jsrLogger = jsrLogger.getParent(); 
     }
-        
     Level defaultLogLevel = logLevels.get(jsrLogger.getLevel().toString());
-    
+
+    try {
+    uimaLogger.setLevel(null);  // causes it to inherit from above
+    classLogger.setLevel(null);  // causes it to inherit from above
+
+       
     // check message logging for root logger based on default log level
     Assert.assertEquals(defaultLogLevel.isGreaterOrEqual(Level.ALL), uimaLogger
             .isLoggable(Level.ALL));
@@ -162,14 +168,18 @@
     Assert.assertTrue(classLogger.isLoggable(Level.SEVERE));
     Assert.assertTrue(classLogger.isLoggable(Level.OFF));
 
-    // reset log level to default log level
-    classLogger.setLevel(defaultLogLevel);
+    } finally {
+      // reset log level to default log level
+      classLogger.setLevel(Level.INFO);
+      uimaLogger.setLevel(Level.INFO);      
+    }
   }
 
   public void testMessageLogMethods() throws Exception {
     // create Logger
     final org.apache.uima.util.Logger logger = JSR47Logger_impl.getInstance();
     // reset log level to INFO
+    try {
     logger.setLevel(Level.INFO);
 
     // File file = File.createTempFile("LoggingTest","log");
@@ -225,11 +235,16 @@
     Exception ex = new Exception("My sixth test message");
     logger.logException(ex);
     logger.logException(null);
+    } finally {
+      logger.setLevel(Level.INFO);
+    }
   }
 
   public void testMessageKeyLogMethods() throws Exception {
     // create Logger
     org.apache.uima.util.Logger logger = JSR47Logger_impl.getInstance();
+    
+    try {
     // reset log level to INFO
     logger.setLevel(Level.INFO);
 
@@ -285,6 +300,11 @@
     thrown = null;
     logger.logrb(Level.INFO, "testClass", "testMethod", bundle, msgKey, thrown);
     logger.logrb(Level.INFO, "testClass", "testMethod", null, null, thrown);
-
+    
+    // https://issues.apache.org/jira/browse/UIMA-5719
+    logger.logrb(Level.WARNING, "testClass", "testMethod", "org.apache.uima.impl.log_messages", "UIMA_external_override_ignored__CONFIG", new Object[] { "n1", "${abc}" });
+  } finally {
+    logger.setLevel(Level.INFO);
+  }
   }
 }
diff --git a/uimaj-core/src/test/java/org/apache/uima/util/impl/Logger_implTest.java b/uimaj-core/src/test/java/org/apache/uima/util/impl/Logger_implTest.java
index 98bcb2a..130c27d 100644
--- a/uimaj-core/src/test/java/org/apache/uima/util/impl/Logger_implTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/util/impl/Logger_implTest.java
@@ -55,9 +55,11 @@
 
   public void testMessageLeveling() throws Exception {
     // create logger
+    
     org.apache.uima.util.Logger rootLogger = Logger_impl.getInstance();
     org.apache.uima.util.Logger classLogger = Logger_impl.getInstance(this.getClass());
 
+    try {
     rootLogger.setLevel(Level.INFO);
 
     // check message leveling root logger
@@ -117,6 +119,9 @@
     Assert.assertTrue(classLogger.isLoggable(Level.WARNING));
     Assert.assertTrue(classLogger.isLoggable(Level.SEVERE));
     Assert.assertTrue(classLogger.isLoggable(Level.OFF));
-
+    } finally {
+      rootLogger.setLevel(Level.INFO);
+      classLogger.setLevel(Level.INFO);
+    }
   }
 }
diff --git a/uimaj-core/src/test/java/org/apache/uima/util/impl/LoggingTest.java b/uimaj-core/src/test/java/org/apache/uima/util/impl/LoggingTest.java
index 2910b0a..74d4a98 100644
--- a/uimaj-core/src/test/java/org/apache/uima/util/impl/LoggingTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/util/impl/LoggingTest.java
@@ -56,6 +56,9 @@
 
       // test base logging functions
       logger.log(Level.SEVERE, "Log test messege with Level SEVERE");
+
+      // https://issues.apache.org/jira/browse/UIMA-5719
+      logger.logrb(Level.WARNING, "testClass", "testMethod", "org.apache.uima.impl.log_messages", "UIMA_external_override_ignored__CONFIG", new Object[] { "n1", "${abc}" });
     } catch (Exception ex) {
       JUnitExtension.handleException(ex);
     }
@@ -81,17 +84,21 @@
 
       // test base logging functions
       logger.log(Level.SEVERE, "Log test messege with Level SEVERE");
+      
+      // https://issues.apache.org/jira/browse/UIMA-5719
+      logger.logrb(Level.WARNING, "testClass", "testMethod", "org.apache.uima.impl.log_messages", "UIMA_external_override_ignored__CONFIG", new Object[] { "n1", "${abc}" });
     } catch (Exception ex) {
       JUnitExtension.handleException(ex);
     }
   }
 
   public void testSetLevel() throws Exception {
+    Logger uimaLogger = UIMAFramework.getLogger(); // should affect everything in
+    // org.apache.uima.*
     try {
+
       // get class logger
       Logger logger = UIMAFramework.getLogger(this.getClass());
-      Logger uimaLogger = UIMAFramework.getLogger(); // should affect everything in
-      // org.apache.uima.*
 
       // set level to WARNING
       uimaLogger.setLevel(Level.WARNING);
@@ -114,9 +121,10 @@
       Assert.assertTrue(logger.isLoggable(Level.INFO));
       Assert.assertFalse(logger.isLoggable(Level.FINER));
       Assert.assertFalse(logger.isLoggable(Level.ALL));
-      uimaLogger.setLevel(Level.INFO);
     } catch (Exception ex) {
       JUnitExtension.handleException(ex);
+    } finally {
+      uimaLogger.setLevel(Level.INFO); // otherwise, is stuck at INFO, too much logging
     }
 
   }
diff --git a/uimaj-core/src/test/java/org/apache/uima/util/impl/OptimizeStringsTest.java b/uimaj-core/src/test/java/org/apache/uima/util/impl/OptimizeStringsTest.java
index 392d3cd..661a791 100644
--- a/uimaj-core/src/test/java/org/apache/uima/util/impl/OptimizeStringsTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/util/impl/OptimizeStringsTest.java
@@ -25,32 +25,39 @@
 
 public class OptimizeStringsTest extends TestCase {
 
-  private static Field STRING_OFFSET;
-  static {
-    try {
-      STRING_OFFSET = String.class.getDeclaredField("offset");
-      STRING_OFFSET.setAccessible(true);
-    } catch (SecurityException e) {
-      throw new RuntimeException(e);
-    } catch (NoSuchFieldException e) {
-      System.err.println("OptimizeStringsTest could not find the String offset field, skipping that part of the test.");
-      STRING_OFFSET = null;
-    }
-  }
-    
-  public static int getStringOffset(String s) {
-    try {
-      if (STRING_OFFSET != null) {
-        return STRING_OFFSET.getInt(s);
-      }
-      return -1;
-    } catch (IllegalArgumentException e) {
-      throw new RuntimeException(e);
-    } catch (IllegalAccessException e) {
-      throw new RuntimeException(e);
-    }
-  }
-   
+  // modern Javas do this in various ways, can't depend on internal impl
+//private static Field STRING_OFFSET;
+//static {
+//  try {
+// // Found that IBM Java 8 version 8.0.4.2 returns a value for the field "offset", but it's 0
+//    // and there doesn't seem to be an offset field in that class.
+//    if (System.getProperty("java.version").startsWith("1.8")) {
+//      STRING_OFFSET = null;
+//    } else {
+//      STRING_OFFSET =  String.class.getDeclaredField("offset");
+//      STRING_OFFSET.setAccessible(true);
+//    }
+//  } catch (SecurityException e) {
+//    throw new RuntimeException(e);
+//  } catch (NoSuchFieldException e) {
+//    System.err.println("OptimizeStringsTest could not find the String offset field, skipping that part of the test.");
+//    STRING_OFFSET = null;
+//  }
+//}
+  
+public static int getStringOffset(String s) {
+  return -1;  // disabled
+//  try {
+//    if (STRING_OFFSET != null) {
+//      return STRING_OFFSET.getInt(s);
+//    }
+//    return -1;
+//  } catch (IllegalArgumentException e) {
+//    throw new RuntimeException(e);
+//  } catch (IllegalAccessException e) {
+//    throw new RuntimeException(e);
+//  }
+}   
   public void testOpStr() {
     OptimizeStrings os = new OptimizeStrings(true, 6);
     os.add("a0");
diff --git a/uimaj-core/src/test/java/org/apache/uima/util/impl/TestLog4jLogger_impl.java b/uimaj-core/src/test/java/org/apache/uima/util/impl/TestLog4jLogger_impl.java
index af2c133..715389c 100644
--- a/uimaj-core/src/test/java/org/apache/uima/util/impl/TestLog4jLogger_impl.java
+++ b/uimaj-core/src/test/java/org/apache/uima/util/impl/TestLog4jLogger_impl.java
@@ -18,15 +18,12 @@
  */
 package org.apache.uima.util.impl;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-import org.apache.log4j.Appender;
-import org.apache.log4j.BasicConfigurator;
-import org.apache.log4j.Logger;
-import org.apache.log4j.spi.LocationInfo;
-import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.ConsoleAppender;
+import org.apache.logging.log4j.core.filter.AbstractFilter;
 import org.apache.uima.UIMAFramework;
 import org.apache.uima.util.Level;
 
@@ -39,27 +36,27 @@
 
    @Override
   public void setUp() throws Exception {
-      BasicConfigurator.configure();
+//      BasicConfigurator.configure();
    }
 
    @Override
   public void tearDown() throws Exception {
-      BasicConfigurator.resetConfiguration();
+//      BasicConfigurator.resetConfiguration();
    }
 
-   private static HashMap<String, Level> logLevels = new HashMap<String, Level>(
-         9);
-   static {
-      logLevels.put("OFF", Level.OFF);
-      logLevels.put("ERROR", Level.SEVERE);
-      logLevels.put("WARN", Level.WARNING);
-      logLevels.put("INFO", Level.INFO);
-      logLevels.put("INFO", Level.CONFIG);
-      logLevels.put("DEBUG", Level.FINE);
-      logLevels.put("ALL", Level.FINER);
-      logLevels.put("ALL", Level.FINEST);
-      logLevels.put("ALL", Level.ALL);
-   }
+//   private static HashMap<String, Level> logLevels = new HashMap<String, Level>(
+//         9);
+//   static {
+//      logLevels.put("OFF", Level.OFF);
+//      logLevels.put("ERROR", Level.SEVERE);
+//      logLevels.put("WARN", Level.WARNING);
+//      logLevels.put("INFO", Level.INFO);
+//      logLevels.put("INFO", Level.CONFIG);
+//      logLevels.put("DEBUG", Level.FINE);
+//      logLevels.put("ALL", Level.FINER);
+//      logLevels.put("ALL", Level.FINEST);
+//      logLevels.put("ALL", Level.ALL);
+//   }
 
    public void testLogWrapperCreation() throws Exception {
       org.apache.uima.util.Logger uimaLogger = Log4jLogger_impl.getInstance();
@@ -75,24 +72,33 @@
       classLogger.log(Level.INFO, "OLA in info");
 
       uimaLogger.log(Level.INFO, "UIMA OLA in info");
+      https://issues.apache.org/jira/browse/UIMA-5719
+      uimaLogger.logrb(Level.WARNING, "testClass", "testMethod", "org.apache.uima.impl.log_messages", "UIMA_external_override_ignored__CONFIG", new Object[] { "n1", "${abc}" });
    }
 
    public void testIsLoggable() throws Exception {
       // create logger
-      org.apache.uima.util.Logger uimaLogger = Log4jLogger_impl.getInstance();
+     org.apache.uima.util.Logger uimaLogger = null;
+      try {
+        uimaLogger = Log4jLogger_impl.getInstance();
+      } catch (Exception e) {
+        System.err.println(e);
+        e.printStackTrace(System.err);
+        throw e;
+      }
       org.apache.uima.util.Logger classLogger = Log4jLogger_impl
             .getInstance(this.getClass());
 
       assertNotNull(uimaLogger);
       assertNotNull(classLogger);
-      Logger log4jLogger = org.apache.log4j.Logger.getLogger("org.apache.uima");
+      Logger log4jLogger = org.apache.logging.log4j.LogManager.getLogger("org.apache.uima");
       while (log4jLogger.getLevel() == null) {
-         log4jLogger = Logger.getRootLogger();
+         log4jLogger = LogManager.getRootLogger();
       }
 
-      String key = log4jLogger.getLevel().toString();
+      String key = "INFO"; // log4jLogger.getLevel().toString();
 
-      Level defaultLogLevel = logLevels.get(key);
+      Level defaultLogLevel = Level.INFO; // logLevels.get(key); // doesn't work
 
       assertNotNull(defaultLogLevel);
       // check message logging for root logger based on default log level
@@ -179,29 +185,54 @@
    }
 
    public void testMessageLogMethods() throws Exception {
-     final List<LoggingEvent> records = new ArrayList<LoggingEvent>();
+//     final List<LoggingEvent> records = new ArrayList<LoggingEvent>();
+     final int[] nbrcalls = new int[1];
+     nbrcalls[0] = 0;
      
      // Tell the logger to log everything
-     Logger rootLogger = org.apache.log4j.LogManager.getRootLogger();
-     rootLogger.setLevel(org.apache.log4j.Level.ALL);
-     Appender appender = (Appender) rootLogger.getAllAppenders().nextElement();
+//     long start = System.nanoTime();
+     org.apache.logging.log4j.core.Logger rootLogger = (org.apache.logging.log4j.core.Logger) org.apache.logging.log4j.LogManager.getRootLogger();
+//     System.out.format("debug time to init logger is %f%n ",  ((double)(System.nanoTime() - start)) / 1000000000.0d);
+     rootLogger.get().setLevel(org.apache.logging.log4j.Level.ALL);
+     rootLogger.getContext().updateLoggers();
+//     Configurator.setLevel(null, org.apache.logging.log4j.Level.ALL);
+//     final LoggerContext loggerContext = LoggerContext.getContext(false);
+//     final LoggerConfig loggerConfig = loggerContext.getConfiguration().getRootLogger();
+//     
+//     Appender appender = (Appender) rootLogger.getAllAppenders().nextElement();
      // Capture the logging output without actually logging it
-     appender.addFilter(new org.apache.log4j.spi.Filter() {
+//     ConsoleAppender app = (ConsoleAppender) rootLogger.getAppenders().values().stream().findFirst().get();
+     // add the filter to the shared Logger Context appender
+     ConsoleAppender app = (ConsoleAppender) rootLogger.get().getAppenders().values().stream().findFirst().get();
+     Filter filter = new AbstractFilter() {
        @Override
-       public int decide(LoggingEvent event) {
-         records.add(event);
-         LocationInfo l = event.getLocationInformation();
-         System.out.printf("[%s:%s] %s%n", l.getFileName(), l.getLineNumber(), event.getMessage());
-         assertEquals(TestLog4jLogger_impl.this.getClass().getSimpleName()+".java", 
-                 l.getFileName());
-         return org.apache.log4j.spi.Filter.DENY;
+       public Result filter(LogEvent event) {
+         nbrcalls[0] ++;
+         StackTraceElement ste = event.getSource();
+         System.out.printf("[%s:%s] %s%n", ste.getFileName(), ste.getLineNumber(), event.getMessage().getFormattedMessage());
+         assertEquals(TestLog4jLogger_impl.this.getClass().getName() , ste.getClassName());
+         return Result.DENY;
        }
-     }); 
+     };
      
+     app.addFilter(filter);
+
+     try {
       // create Logger
-      final org.apache.uima.util.Logger logger = Log4jLogger_impl.getInstance(getClass());
+       // debug
+      org.apache.uima.util.Logger tempLogger = null;
+      try {
+        tempLogger = Log4jLogger_impl.getInstance(getClass());
+      } catch (Throwable e) {
+        System.err.println("debug Caught throwable");
+        e.printStackTrace(System.err);
+        System.err.println("debug finished stacktrace");
+        throw e;
+      }
+      final org.apache.uima.util.Logger logger = tempLogger;
       // reset log level to INFO
       logger.setLevel(Level.INFO);
+//      Configurator.setLevel("Console", org.apache.logging.log4j.Level.INFO);
 
       // File file = File.createTempFile("LoggingTest","log");
       // file.deleteOnExit();
@@ -210,6 +241,7 @@
       // logger.setOutputStream(new PrintStream(new FileOutputStream(file)));
 
       // log test with method log(Level,String)
+
       logger.log(Level.INFO, "My first test message");
       logger.log(Level.INFO, "");
       logger.log(Level.INFO, null);
@@ -256,31 +288,58 @@
       logger.logException(ex);
       logger.logException(null);
       
-      assertEquals(16, records.size());  // all calls except those with null or "" msgs (including non-null throwable/exception)
+      assertEquals(16, nbrcalls[0]);  // all calls except those with null or "" msgs (including non-null throwable/exception)
+      // https://issues.apache.org/jira/browse/UIMA-5719
+      logger.logrb(Level.WARNING, "testClass", "testMethod", "org.apache.uima.impl.log_messages", "UIMA_external_override_ignored__CONFIG", new Object[] { "n1", "${abc}" });
+      
+     } finally {
+       app.removeFilter(filter);
+     }
+
    }
 
+   
    public void testMessageKeyLogMethods() throws Exception {
-     final List<LoggingEvent> records = new ArrayList<LoggingEvent>();
+     final int[] nbrcalls = new int[1];
+     nbrcalls[0] = 0;
      
      // Tell the logger to log everything
-     Logger rootLogger = org.apache.log4j.LogManager.getRootLogger();
-     rootLogger.setLevel(org.apache.log4j.Level.ALL);
-     Appender appender = (Appender) rootLogger.getAllAppenders().nextElement();
+     org.apache.logging.log4j.core.Logger rootLogger = (org.apache.logging.log4j.core.Logger) org.apache.logging.log4j.LogManager.getRootLogger();
+     // create Logger
+     org.apache.uima.util.Logger logger = Log4jLogger_impl.getInstance();
+  
+     try {
+     rootLogger.get().setLevel(org.apache.logging.log4j.Level.ALL);
+     rootLogger.getContext().updateLoggers();
+//     Appender appender = (Appender) rootLogger.getAllAppenders().nextElement();
      // Capture the logging output without actually logging it
-     appender.addFilter(new org.apache.log4j.spi.Filter() {
+//     appender.addFilter(new org.apache.logging.log4j.spi.Filter() {
+     
+     Filter filter = new AbstractFilter() {
        @Override
-       public int decide(LoggingEvent event) {
-         records.add(event);
-         LocationInfo l = event.getLocationInformation();
-         System.out.printf("[%s:%s] %s%n", l.getFileName(), l.getLineNumber(), event.getMessage());
-         assertEquals(TestLog4jLogger_impl.this.getClass().getSimpleName()+".java", 
-                 l.getFileName());
-         return org.apache.log4j.spi.Filter.DENY;
+       public Result filter(LogEvent event) { 
+         nbrcalls[0] ++;
+         StackTraceElement ste = event.getSource();
+         System.out.printf("[%s:%s] %s%n", ste.getFileName(), ste.getLineNumber(), event.getMessage().getFormattedMessage());
+         assertEquals(TestLog4jLogger_impl.this.getClass().getSimpleName()+".java", ste.getFileName());
+         return Result.DENY;
        }
-     }); 
+    }; 
+     
+     ConsoleAppender app = (ConsoleAppender) rootLogger.get().getAppenders().values().stream().findFirst().get();
+     app.addFilter(filter);
+     try {
+//       @Override
+//       public int decide(LoggingEvent event) {
+//         nbrcalss[0] ++;
+//         LocationInfo l = event.getLocationInformation();
+//         System.out.printf("[%s:%s] %s%n", l.getFileName(), l.getLineNumber(), event.getMessage());
+//         assertEquals(TestLog4jLogger_impl.this.getClass().getSimpleName()+".java", 
+//                 l.getFileName());
+//         return org.apache.logging.log4j.spi.Filter.DENY;
+//       }
+//     }); 
 
-      // create Logger
-      org.apache.uima.util.Logger logger = Log4jLogger_impl.getInstance();
       // reset log level to INFO
       logger.setLevel(Level.INFO);
 
@@ -339,7 +398,15 @@
             thrown);
       logger.logrb(Level.INFO, "testClass", "testMethod", null, null, thrown);
 
-      assertEquals(18, records.size());
+      assertEquals(18, nbrcalls[0]);
+     } finally {
+       app.removeFilter(filter);  // otherwise, subsequent test's filter gets appended, not replace
+     }
+    
+     } finally {
+       logger.setLevel(Level.INFO);
+       rootLogger.setLevel(org.apache.logging.log4j.Level.INFO);
+     }
    }
 
    public void testLoggerFromUIMAFramework() {
@@ -358,8 +425,13 @@
       logger.log(Level.INFO,
             "------------------------------------------------------------");
       logger.log(Level.INFO, "My first test message");
-      logger.log(Level.INFO, "");
-      logger.log(Level.INFO, null);
+      logger.log(Level.INFO, "message with \"{0}\"", "substitute");
+      logger.info("message with \"{}\"", "substitute");  // new logger style
+      logger.info("message with \"{}\"", new Object[] {"substitute"});  // new logger style
+      
+      // https://issues.apache.org/jira/browse/UIMA-5719
+      logger.logrb(Level.WARNING, "testClass", "testMethod", "org.apache.uima.impl.log_messages", "UIMA_external_override_ignored__CONFIG", new Object[] { "n1", "${abc}" });
+
 
    }
 }
diff --git a/uimaj-core/src/test/java/org/apache/uima/util/impl/XMLParser_implTest.java b/uimaj-core/src/test/java/org/apache/uima/util/impl/XMLParser_implTest.java
index 77ea715..f84829f 100644
--- a/uimaj-core/src/test/java/org/apache/uima/util/impl/XMLParser_implTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/util/impl/XMLParser_implTest.java
@@ -66,6 +66,15 @@
     // schema validation will be enabled for the whole suite.
     mXmlParser.enableSchemaValidation(true);
   }
+  
+  /*
+   * @see TestCase#tearDown()
+   */
+  protected void tearDown() throws Exception {
+    super.tearDown();
+    UIMAFramework.getXMLParser().enableSchemaValidation(false);
+  }
+
 
   public void testParse() throws Exception {
     try {
diff --git a/uimaj-core/src/test/java/sofa/test/CrossAnnotation.java b/uimaj-core/src/test/java/sofa/test/CrossAnnotation.java
index f67bb31..6d49f1a 100644
--- a/uimaj-core/src/test/java/sofa/test/CrossAnnotation.java
+++ b/uimaj-core/src/test/java/sofa/test/CrossAnnotation.java
@@ -1,23 +1,50 @@
+/* Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
-
-   
-/* Apache UIMA v3 - First created by JCasGen Wed Mar 02 13:49:48 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:06:27 EDT 2017 */
 
 package sofa.test;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
-import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCas; 
 import org.apache.uima.jcas.JCasRegistry;
+
+
 import org.apache.uima.jcas.tcas.Annotation;
 
 
 /** 
- * Updated by JCasGen Wed Mar 02 13:49:48 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/experiment-v3-jcas/uimaj-core/src/test/resources/ExampleCas/testTypeSystem.xml
+ * Updated by JCasGen Sun Oct 08 19:06:27 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
  * @generated */
 public class CrossAnnotation extends Annotation {
+ 
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "org.apache.uima.cas.test.CrossAnnotation";
+  
   /** @generated
    * @ordered 
    */
@@ -39,8 +66,12 @@
    *   Feature Offsets *
    * *******************/ 
    
+  public final static String _FeatName_otherAnnotation = "otherAnnotation";
+
+
   /* Feature Adjusted Offsets */
-  public final static int _FI_otherAnnotation = TypeSystemImpl.getAdjustedFeatureOffset("otherAnnotation");
+  private final static CallSite _FC_otherAnnotation = TypeSystemImpl.createCallSite(CrossAnnotation.class, "otherAnnotation");
+  private final static MethodHandle _FH_otherAnnotation = _FC_otherAnnotation.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -65,6 +96,19 @@
     readObject();   
   } 
 
+
+  /** @generated
+   * @param jcas JCas to which this Feature Structure belongs
+   * @param begin offset to the begin spot in the SofA
+   * @param end offset to the end spot in the SofA 
+  */  
+  public CrossAnnotation(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }   
+
   /** 
    * <!-- begin-user-doc -->
    * Write your own initialization here
@@ -83,14 +127,14 @@
    * @generated
    * @return value of the feature 
    */
-  public Annotation getOtherAnnotation() { return (Annotation)(_getFeatureValueNc(_FI_otherAnnotation));}
+  public Annotation getOtherAnnotation() { return (Annotation)(_getFeatureValueNc(wrapGetIntCatchException(_FH_otherAnnotation)));}
     
   /** setter for otherAnnotation - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setOtherAnnotation(Annotation v) {
-    _setFeatureValueNcWj(_FI_otherAnnotation, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_otherAnnotation), v);
   }    
     
   }
diff --git a/uimaj-core/src/test/java/x/y/z/EndOfSentence.java b/uimaj-core/src/test/java/x/y/z/EndOfSentence.java
index 5cd35ad..a07a609 100644
--- a/uimaj-core/src/test/java/x/y/z/EndOfSentence.java
+++ b/uimaj-core/src/test/java/x/y/z/EndOfSentence.java
@@ -1,22 +1,21 @@
 
 
    
-/* Apache UIMA v3 - First created by JCasGen Fri Dec 16 10:23:12 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:06:27 EDT 2017 */
 
 package x.y.z;
 
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
-import org.apache.uima.cas.impl.TypeSystemImpl;
-import org.apache.uima.jcas.JCas; 
+import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 
 
 
 
 /** 
- * Updated by JCasGen Fri Dec 16 10:23:12 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
+ * Updated by JCasGen Sun Oct 08 19:06:27 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
  * @generated */
 public class EndOfSentence extends TokenType {
  
diff --git a/uimaj-core/src/test/java/x/y/z/Sentence.java b/uimaj-core/src/test/java/x/y/z/Sentence.java
index ae6026f..2c93054 100644
--- a/uimaj-core/src/test/java/x/y/z/Sentence.java
+++ b/uimaj-core/src/test/java/x/y/z/Sentence.java
@@ -1,10 +1,13 @@
 
 
    
-/* Apache UIMA v3 - First created by JCasGen Fri Dec 16 10:23:12 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:06:27 EDT 2017 */
 
 package x.y.z;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -16,8 +19,8 @@
 
 
 /** 
- * Updated by JCasGen Fri Dec 16 10:23:12 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
+ * Updated by JCasGen Sun Oct 08 19:06:27 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
  * @generated */
 public class Sentence extends Annotation {
  
@@ -52,7 +55,8 @@
 
 
   /* Feature Adjusted Offsets */
-  public final static int _FI_sentenceLength = TypeSystemImpl.getAdjustedFeatureOffset("sentenceLength");
+  private final static CallSite _FC_sentenceLength = TypeSystemImpl.createCallSite(Sentence.class, "sentenceLength");
+  private final static MethodHandle _FH_sentenceLength = _FC_sentenceLength.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -108,14 +112,14 @@
    * @generated
    * @return value of the feature 
    */
-  public int getSentenceLength() { return _getIntValueNc(_FI_sentenceLength);}
+  public int getSentenceLength() { return _getIntValueNc(wrapGetIntCatchException(_FH_sentenceLength));}
     
   /** setter for sentenceLength - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setSentenceLength(int v) {
-    _setIntValueNfc(_FI_sentenceLength, v);
+    _setIntValueNfc(wrapGetIntCatchException(_FH_sentenceLength), v);
   }    
     
   }
diff --git a/uimaj-core/src/test/java/x/y/z/Separator.java b/uimaj-core/src/test/java/x/y/z/Separator.java
index 37cf9b5..605347b 100644
--- a/uimaj-core/src/test/java/x/y/z/Separator.java
+++ b/uimaj-core/src/test/java/x/y/z/Separator.java
@@ -1,10 +1,13 @@
 
 
    
-/* Apache UIMA v3 - First created by JCasGen Fri Dec 16 10:23:12 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:06:27 EDT 2017 */
 
 package x.y.z;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -15,8 +18,8 @@
 
 
 /** 
- * Updated by JCasGen Fri Dec 16 10:23:12 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
+ * Updated by JCasGen Sun Oct 08 19:06:27 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
  * @generated */
 public class Separator extends TokenType {
  
diff --git a/uimaj-core/src/test/java/x/y/z/Token.java b/uimaj-core/src/test/java/x/y/z/Token.java
index 82700e8..a433cf7 100644
--- a/uimaj-core/src/test/java/x/y/z/Token.java
+++ b/uimaj-core/src/test/java/x/y/z/Token.java
@@ -1,10 +1,13 @@
 
 
    
-/* Apache UIMA v3 - First created by JCasGen Fri Dec 16 10:23:12 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:06:27 EDT 2017 */
 
 package x.y.z;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -17,8 +20,8 @@
 
 
 /** 
- * Updated by JCasGen Fri Dec 16 10:23:12 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
+ * Updated by JCasGen Sun Oct 08 19:06:27 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
  * @generated */
 public class Token extends Annotation {
  
@@ -56,10 +59,14 @@
 
 
   /* Feature Adjusted Offsets */
-  public final static int _FI_ttype = TypeSystemImpl.getAdjustedFeatureOffset("ttype");
-  public final static int _FI_tokenFloatFeat = TypeSystemImpl.getAdjustedFeatureOffset("tokenFloatFeat");
-  public final static int _FI_lemma = TypeSystemImpl.getAdjustedFeatureOffset("lemma");
-  public final static int _FI_lemmaList = TypeSystemImpl.getAdjustedFeatureOffset("lemmaList");
+  private final static CallSite _FC_ttype = TypeSystemImpl.createCallSite(Token.class, "ttype");
+  private final static MethodHandle _FH_ttype = _FC_ttype.dynamicInvoker();
+  private final static CallSite _FC_tokenFloatFeat = TypeSystemImpl.createCallSite(Token.class, "tokenFloatFeat");
+  private final static MethodHandle _FH_tokenFloatFeat = _FC_tokenFloatFeat.dynamicInvoker();
+  private final static CallSite _FC_lemma = TypeSystemImpl.createCallSite(Token.class, "lemma");
+  private final static MethodHandle _FH_lemma = _FC_lemma.dynamicInvoker();
+  private final static CallSite _FC_lemmaList = TypeSystemImpl.createCallSite(Token.class, "lemmaList");
+  private final static MethodHandle _FH_lemmaList = _FC_lemmaList.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -115,14 +122,14 @@
    * @generated
    * @return value of the feature 
    */
-  public TokenType getTtype() { return (TokenType)(_getFeatureValueNc(_FI_ttype));}
+  public TokenType getTtype() { return (TokenType)(_getFeatureValueNc(wrapGetIntCatchException(_FH_ttype)));}
     
   /** setter for ttype - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setTtype(TokenType v) {
-    _setFeatureValueNcWj(_FI_ttype, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_ttype), v);
   }    
     
    
@@ -134,14 +141,14 @@
    * @generated
    * @return value of the feature 
    */
-  public float getTokenFloatFeat() { return _getFloatValueNc(_FI_tokenFloatFeat);}
+  public float getTokenFloatFeat() { return _getFloatValueNc(wrapGetIntCatchException(_FH_tokenFloatFeat));}
     
   /** setter for tokenFloatFeat - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setTokenFloatFeat(float v) {
-    _setFloatValueNfc(_FI_tokenFloatFeat, v);
+    _setFloatValueNfc(wrapGetIntCatchException(_FH_tokenFloatFeat), v);
   }    
     
    
@@ -153,14 +160,14 @@
    * @generated
    * @return value of the feature 
    */
-  public String getLemma() { return _getStringValueNc(_FI_lemma);}
+  public String getLemma() { return _getStringValueNc(wrapGetIntCatchException(_FH_lemma));}
     
   /** setter for lemma - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setLemma(String v) {
-    _setStringValueNfc(_FI_lemma, v);
+    _setStringValueNfc(wrapGetIntCatchException(_FH_lemma), v);
   }    
     
    
@@ -172,14 +179,14 @@
    * @generated
    * @return value of the feature 
    */
-  public StringArray getLemmaList() { return (StringArray)(_getFeatureValueNc(_FI_lemmaList));}
+  public StringArray getLemmaList() { return (StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_lemmaList)));}
     
   /** setter for lemmaList - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setLemmaList(StringArray v) {
-    _setFeatureValueNcWj(_FI_lemmaList, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_lemmaList), v);
   }    
     
     
@@ -189,7 +196,7 @@
    * @return value of the element at index i 
    */
   public String getLemmaList(int i) {
-     return ((StringArray)(_getFeatureValueNc(_FI_lemmaList))).get(i);} 
+     return ((StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_lemmaList)))).get(i);} 
 
   /** indexed setter for lemmaList - sets an indexed value - 
    * @generated
@@ -197,7 +204,7 @@
    * @param v value to set into the array 
    */
   public void setLemmaList(int i, String v) {
-    ((StringArray)(_getFeatureValueNc(_FI_lemmaList))).set(i, v);
+    ((StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_lemmaList)))).set(i, v);
   }  
   }
 
diff --git a/uimaj-core/src/test/java/x/y/z/TokenType.java b/uimaj-core/src/test/java/x/y/z/TokenType.java
index 889e5c6..8c4676b 100644
--- a/uimaj-core/src/test/java/x/y/z/TokenType.java
+++ b/uimaj-core/src/test/java/x/y/z/TokenType.java
@@ -1,10 +1,13 @@
 
 
    
-/* Apache UIMA v3 - First created by JCasGen Fri Dec 16 10:23:12 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:06:27 EDT 2017 */
 
 package x.y.z;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -16,8 +19,8 @@
 
 
 /** 
- * Updated by JCasGen Fri Dec 16 10:23:12 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
+ * Updated by JCasGen Sun Oct 08 19:06:27 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
  * @generated */
 public class TokenType extends TOP {
  
diff --git a/uimaj-core/src/test/java/x/y/z/Word.java b/uimaj-core/src/test/java/x/y/z/Word.java
index 4c36519..67701ab 100644
--- a/uimaj-core/src/test/java/x/y/z/Word.java
+++ b/uimaj-core/src/test/java/x/y/z/Word.java
@@ -1,10 +1,13 @@
 
 
    
-/* Apache UIMA v3 - First created by JCasGen Fri Dec 16 10:23:12 EST 2016 */
+/* Apache UIMA v3 - First created by JCasGen Sun Oct 08 19:06:27 EDT 2017 */
 
 package x.y.z;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -15,8 +18,8 @@
 
 
 /** 
- * Updated by JCasGen Fri Dec 16 10:23:12 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
+ * Updated by JCasGen Sun Oct 08 19:06:27 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-core/src/test/java/org/apache/uima/jcas/test/generatedx.xml
  * @generated */
 public class Word extends TokenType {
  
diff --git a/uimaj-core/src/test/resources/ExampleCas/testTypeSystem_small_withMultiRefs.xml b/uimaj-core/src/test/resources/ExampleCas/testTypeSystem_small_withMultiRefs.xml
new file mode 100644
index 0000000..e69973f
--- /dev/null
+++ b/uimaj-core/src/test/resources/ExampleCas/testTypeSystem_small_withMultiRefs.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ -->

+<typeSystemDescription xmlns="http://uima.apache.org/resourceSpecifier">

+  <types>

+    <typeDescription>

+      <name>RefType</name>

+      <description/>

+      <supertypeName>uima.tcas.Annotation</supertypeName>

+      <features>

+        <featureDescription>

+          <name>ref_FSList</name>

+          <description/>

+          <rangeTypeName>uima.cas.FSList</rangeTypeName>

+          <multipleReferencesAllowed>true</multipleReferencesAllowed>

+        </featureDescription>

+        <featureDescription>

+          <name>ref_FSArray</name>

+          <description/>

+          <rangeTypeName>uima.cas.FSArray</rangeTypeName>

+          <multipleReferencesAllowed>true</multipleReferencesAllowed>

+        </featureDescription>

+        <featureDescription>

+          <name>ref</name>

+          <description/>

+          <rangeTypeName>uima.cas.TOP</rangeTypeName>

+        </featureDescription>

+        

+      </features>

+    </typeDescription>

+  </types>

+</typeSystemDescription>

diff --git a/uimaj-core/src/test/resources/ExampleCas/testTypeSystem_small_withoutMultiRefs.xml b/uimaj-core/src/test/resources/ExampleCas/testTypeSystem_small_withoutMultiRefs.xml
new file mode 100644
index 0000000..ad4826e
--- /dev/null
+++ b/uimaj-core/src/test/resources/ExampleCas/testTypeSystem_small_withoutMultiRefs.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ -->

+<typeSystemDescription xmlns="http://uima.apache.org/resourceSpecifier">

+  <types>

+    <typeDescription>

+      <name>RefType</name>

+      <description/>

+      <supertypeName>uima.tcas.Annotation</supertypeName>

+      <features>

+        <featureDescription>

+          <name>ref_StringList</name>

+          <description/>

+          <rangeTypeName>uima.cas.StringList</rangeTypeName>

+        </featureDescription>

+        <featureDescription>

+          <name>ref_StringArray</name>

+          <description/>

+          <rangeTypeName>uima.cas.StringArray</rangeTypeName>

+        </featureDescription>

+        <featureDescription>

+          <name>ref</name>

+          <description/>

+          <rangeTypeName>uima.cas.TOP</rangeTypeName>

+        </featureDescription>

+        

+      </features>

+    </typeDescription>

+  </types>

+</typeSystemDescription>

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl_javaObject.java b/uimaj-core/src/test/resources/ExampleCas/testTypeSystem_t_1_feature.xml
similarity index 60%
copy from uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl_javaObject.java
copy to uimaj-core/src/test/resources/ExampleCas/testTypeSystem_t_1_feature.xml
index 47c1228..3efa1a5 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl_javaObject.java
+++ b/uimaj-core/src/test/resources/ExampleCas/testTypeSystem_t_1_feature.xml
@@ -1,4 +1,5 @@
-/*

+<?xml version="1.0" encoding="UTF-8"?>

+<!--

  * Licensed to the Apache Software Foundation (ASF) under one

  * or more contributor license agreements.  See the NOTICE file

  * distributed with this work for additional information

@@ -15,20 +16,20 @@
  * KIND, either express or implied.  See the License for the

  * specific language governing permissions and limitations

  * under the License.

- */

-

-package org.apache.uima.cas.impl;

-

-/**

- * A version of TypeImpl for types that are JavaObject types

- * Note: these are non-creatable (as FeatureStructures), but they may be the

- * values of Feature slots.

- *

- */

-public class TypeImpl_javaObject extends TypeImpl_primitive {

-  

-  public TypeImpl_javaObject(String name, TypeSystemImpl tsi, TypeImpl supertype, Class<?> javaClass) {

-    super(name, tsi, supertype, javaClass);

-  }

-  

-}

+ -->

+<typeSystemDescription xmlns="http://uima.apache.org/resourceSpecifier">

+  <types>

+    <typeDescription>

+      <name>aa.T</name>

+      <description/>

+      <supertypeName>uima.cas.TOP</supertypeName>

+      <features>

+        <featureDescription>

+          <name>f1</name>

+          <description/>

+          <rangeTypeName>uima.cas.Integer</rangeTypeName>

+        </featureDescription>

+      </features>

+    </typeDescription>

+  </types>

+</typeSystemDescription>

diff --git a/uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP_Type.java b/uimaj-core/src/test/resources/ExampleCas/testTypeSystem_t_nofeatures.xml
similarity index 66%
copy from uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP_Type.java
copy to uimaj-core/src/test/resources/ExampleCas/testTypeSystem_t_nofeatures.xml
index 92d15c7..857f93f 100644
--- a/uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP_Type.java
+++ b/uimaj-core/src/test/resources/ExampleCas/testTypeSystem_t_nofeatures.xml
@@ -1,4 +1,5 @@
-/*

+<?xml version="1.0" encoding="UTF-8"?>

+<!--

  * Licensed to the Apache Software Foundation (ASF) under one

  * or more contributor license agreements.  See the NOTICE file

  * distributed with this work for additional information

@@ -15,15 +16,17 @@
  * KIND, either express or implied.  See the License for the

  * specific language governing permissions and limitations

  * under the License.

- */

-

-package org.apache.uima.jcas.cas;

-

-

-

-// *********************************

-// * Implementation of TOP_Type    *

-// * Only for supporting decompiling of v2 JCas classes

-// *********************************

-

-public class TOP_Type {}

+ -->

+<typeSystemDescription xmlns="http://uima.apache.org/resourceSpecifier">

+  <name>testTypeSystem_t_nofeature</name>

+  <description/>

+  <version/>

+  <vendor/>

+  <types>

+    <typeDescription>

+      <name>aa.T</name>

+      <description/>

+      <supertypeName>uima.cas.TOP</supertypeName>

+    </typeDescription>

+  </types>

+</typeSystemDescription>

diff --git a/uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP_Type.java b/uimaj-core/src/test/resources/ExampleCas/testTypeSystem_token_no_features.xml
similarity index 70%
copy from uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP_Type.java
copy to uimaj-core/src/test/resources/ExampleCas/testTypeSystem_token_no_features.xml
index 92d15c7..f1369de 100644
--- a/uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP_Type.java
+++ b/uimaj-core/src/test/resources/ExampleCas/testTypeSystem_token_no_features.xml
@@ -1,4 +1,5 @@
-/*

+<?xml version="1.0" encoding="UTF-8"?>

+<!--

  * Licensed to the Apache Software Foundation (ASF) under one

  * or more contributor license agreements.  See the NOTICE file

  * distributed with this work for additional information

@@ -15,15 +16,13 @@
  * KIND, either express or implied.  See the License for the

  * specific language governing permissions and limitations

  * under the License.

- */

-

-package org.apache.uima.jcas.cas;

-

-

-

-// *********************************

-// * Implementation of TOP_Type    *

-// * Only for supporting decompiling of v2 JCas classes

-// *********************************

-

-public class TOP_Type {}

+ -->

+<typeSystemDescription xmlns="http://uima.apache.org/resourceSpecifier">

+  <types>

+    <typeDescription>

+      <name>x.y.z.Token</name>

+      <description/>

+      <supertypeName>uima.tcas.Annotation</supertypeName>

+    </typeDescription>

+  </types>

+</typeSystemDescription>

diff --git a/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/AggregateWithExternalOverrides.xml b/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/AggregateWithExternalOverrides.xml
index 54f1a37..43b6d47 100644
--- a/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/AggregateWithExternalOverrides.xml
+++ b/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/AggregateWithExternalOverrides.xml
@@ -23,7 +23,7 @@
   <primitive>false</primitive>
   <delegateAnalysisEngineSpecifiers>
     <delegateAnalysisEngine key="ExternalOverrides">
-      <import location="AnnotatorWithExternalOverrides.xml"/>
+      <import location="Annotator${with}ExternalOverrides.xml"/>
     </delegateAnalysisEngine>
   </delegateAnalysisEngineSpecifiers>
   <analysisEngineMetaData>
diff --git a/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride.settings b/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride.settings
index 58f7d35..7c04cff 100644
--- a/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride.settings
+++ b/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride.settings
@@ -1,24 +1,23 @@
- #  ***************************************************************

- #  * Licensed to the Apache Software Foundation (ASF) under one

- #  * or more contributor license agreements.  See the NOTICE file

- #  * distributed with this work for additional information

- #  * regarding copyright ownership.  The ASF licenses this file

- #  * to you under the Apache License, Version 2.0 (the

- #  * "License"); you may not use this file except in compliance

- #  * with the License.  You may obtain a copy of the License at

- #  *

- #  *   http://www.apache.org/licenses/LICENSE-2.0

- #  * 

- #  * Unless required by applicable law or agreed to in writing,

- #  * software distributed under the License is distributed on an

- #  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

- #  * KIND, either express or implied.  See the License for the

- #  * specific language governing permissions and limitations

- #  * under the License.

- #  ***************************************************************

-prefix    Prefix

-suffix    Suffix

-test.externalStringArray = [${prefix},\-,${suffix},->,${prefix-suffix}]

-test.externalIntegerArray : [1 , 22 , 3\33,4444]  

-test.externalInteger         43

-

+ #  ***************************************************************
+ #  * Licensed to the Apache Software Foundation (ASF) under one
+ #  * or more contributor license agreements.  See the NOTICE file
+ #  * distributed with this work for additional information
+ #  * regarding copyright ownership.  The ASF licenses this file
+ #  * to you under the Apache License, Version 2.0 (the
+ #  * "License"); you may not use this file except in compliance
+ #  * with the License.  You may obtain a copy of the License at
+ #  *
+ #  *   http://www.apache.org/licenses/LICENSE-2.0
+ #  * 
+ #  * Unless required by applicable law or agreed to in writing,
+ #  * software distributed under the License is distributed on an
+ #  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ #  * KIND, either express or implied.  See the License for the
+ #  * specific language governing permissions and limitations
+ #  * under the License.
+ #  ***************************************************************
+prefix    Prefix
+suffix    Suffix
+test.externalStringArray = [${prefix},\-,${suffix},->,${prefix-suffix}]
+test.externalIntegerArray : [1 , 22 , 3\33,4444]  
+
diff --git a/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride2.settings b/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride2.settings
index 8058da5..b423940 100644
--- a/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride2.settings
+++ b/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride2.settings
@@ -1,24 +1,30 @@
- #  ***************************************************************

- #  * Licensed to the Apache Software Foundation (ASF) under one

- #  * or more contributor license agreements.  See the NOTICE file

- #  * distributed with this work for additional information

- #  * regarding copyright ownership.  The ASF licenses this file

- #  * to you under the Apache License, Version 2.0 (the

- #  * "License"); you may not use this file except in compliance

- #  * with the License.  You may obtain a copy of the License at

- #  *

- #  *   http://www.apache.org/licenses/LICENSE-2.0

- #  * 

- #  * Unless required by applicable law or agreed to in writing,

- #  * software distributed under the License is distributed on an

- #  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

- #  * KIND, either express or implied.  See the License for the

- #  * specific language governing permissions and limitations

- #  * under the License.

- #  ***************************************************************

-prefix-suffix     Prefix-${suffix}

-# The following key should have already been set by an earlier import

-suffix = should be ignored

-# Empty array

-test.externalFloatArray =  []

-context-holder = Context Holder Test

+ #  ***************************************************************
+ #  * Licensed to the Apache Software Foundation (ASF) under one
+ #  * or more contributor license agreements.  See the NOTICE file
+ #  * distributed with this work for additional information
+ #  * regarding copyright ownership.  The ASF licenses this file
+ #  * to you under the Apache License, Version 2.0 (the
+ #  * "License"); you may not use this file except in compliance
+ #  * with the License.  You may obtain a copy of the License at
+ #  *
+ #  *   http://www.apache.org/licenses/LICENSE-2.0
+ #  * 
+ #  * Unless required by applicable law or agreed to in writing,
+ #  * software distributed under the License is distributed on an
+ #  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ #  * KIND, either express or implied.  See the License for the
+ #  * specific language governing permissions and limitations
+ #  * under the License.
+ #  ***************************************************************
+prefix-suffix     Prefix-${suffix}
+# The following key should have already been set by an earlier import
+suffix = should be ignored
+# Empty array
+test.externalFloatArray =  []
+context-holder = Context Holder Test
+
+# Part of an import by location
+with = ${W${i}}${TH}
+i = I
+WI = Wi
+TH = th
diff --git a/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride4.settings b/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride4.settings
new file mode 100644
index 0000000..01be97a
--- /dev/null
+++ b/uimaj-core/src/test/resources/TextAnalysisEngineImplTest/testExternalOverride4.settings
@@ -0,0 +1,19 @@
+ #  ***************************************************************
+ #  * Licensed to the Apache Software Foundation (ASF) under one
+ #  * or more contributor license agreements.  See the NOTICE file
+ #  * distributed with this work for additional information
+ #  * regarding copyright ownership.  The ASF licenses this file
+ #  * to you under the Apache License, Version 2.0 (the
+ #  * "License"); you may not use this file except in compliance
+ #  * with the License.  You may obtain a copy of the License at
+ #  *
+ #  *   http://www.apache.org/licenses/LICENSE-2.0
+ #  * 
+ #  * Unless required by applicable law or agreed to in writing,
+ #  * software distributed under the License is distributed on an
+ #  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ #  * KIND, either express or implied.  See the License for the
+ #  * specific language governing permissions and limitations
+ #  * under the License.
+ #  ***************************************************************
+test.externalInteger         43
diff --git a/uimaj-core/src/test/resources/log4j2.xml b/uimaj-core/src/test/resources/log4j2.xml
new file mode 100644
index 0000000..115f556
--- /dev/null
+++ b/uimaj-core/src/test/resources/log4j2.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ -->

+ <!-- This configuration is used by the TestLog4jLogger_impl test -->

+<Configuration status="WARN">

+  <Appenders>

+    <Console name="Console" target="SYSTEM_OUT">

+      <!-- this pattern includes caller stack info 

+      <PatternLayout pattern="%l %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>

+      -->

+      <!-- this next pattern is more like V2 -->

+      <PatternLayout pattern="%d{MMM dd, yyyy HH:mm:ss} %C %M (%L)\n%level: %msg%n"/>  

+    </Console>

+  </Appenders>

+  <Loggers>

+    <Root level="info">

+      <AppenderRef ref="Console"/>

+    </Root>

+  </Loggers>

+</Configuration>
\ No newline at end of file
diff --git a/uimaj-core/src/test/resources/org/apache/uima/util/impl/logger_test_messages.properties b/uimaj-core/src/test/resources/org/apache/uima/util/impl/logger_test_messages.properties
index c419fc9..77cccc9 100644
--- a/uimaj-core/src/test/resources/org/apache/uima/util/impl/logger_test_messages.properties
+++ b/uimaj-core/src/test/resources/org/apache/uima/util/impl/logger_test_messages.properties
@@ -17,4 +17,4 @@
 #	 * under the License.

 #	 ***************************************************************

 

-UIMA_logger_test = Exception test message
\ No newline at end of file
+UIMA_logger_test = Exception test message substitute part {0}
\ No newline at end of file
diff --git a/uimaj-core/src/test/resources/pearTests/DateTime.pear b/uimaj-core/src/test/resources/pearTests/DateTime.pear
index 0d09796..77d935e 100644
--- a/uimaj-core/src/test/resources/pearTests/DateTime.pear
+++ b/uimaj-core/src/test/resources/pearTests/DateTime.pear
Binary files differ
diff --git a/uimaj-core/src/test/resources/pearTests/RoomNumber.pear b/uimaj-core/src/test/resources/pearTests/RoomNumber.pear
index 6b02004..50ecc83 100644
--- a/uimaj-core/src/test/resources/pearTests/RoomNumber.pear
+++ b/uimaj-core/src/test/resources/pearTests/RoomNumber.pear
Binary files differ
diff --git a/uimaj-core/src/test/resources/pearTests/analysisEngine.pear b/uimaj-core/src/test/resources/pearTests/analysisEngine.pear
index 531ce31..cdf0c30 100644
--- a/uimaj-core/src/test/resources/pearTests/analysisEngine.pear
+++ b/uimaj-core/src/test/resources/pearTests/analysisEngine.pear
Binary files differ
diff --git a/uimaj-core/src/test/resources/pearTests/analysisEngine2.pear b/uimaj-core/src/test/resources/pearTests/analysisEngine2.pear
index c697bd7..c4ac9f5 100644
--- a/uimaj-core/src/test/resources/pearTests/analysisEngine2.pear
+++ b/uimaj-core/src/test/resources/pearTests/analysisEngine2.pear
Binary files differ
diff --git a/uimaj-core/src/test/resources/pearTests/pearSofaMap.pear b/uimaj-core/src/test/resources/pearTests/pearSofaMap.pear
index c033967..18acb8b 100644
--- a/uimaj-core/src/test/resources/pearTests/pearSofaMap.pear
+++ b/uimaj-core/src/test/resources/pearTests/pearSofaMap.pear
Binary files differ
diff --git a/uimaj-core/src/test/resources/pearTests/typeSystem.pear b/uimaj-core/src/test/resources/pearTests/typeSystem.pear
index 3ada4b2..8f2ee03 100644
--- a/uimaj-core/src/test/resources/pearTests/typeSystem.pear
+++ b/uimaj-core/src/test/resources/pearTests/typeSystem.pear
Binary files differ
diff --git a/uimaj-cpe/pom.xml b/uimaj-cpe/pom.xml
index 42431c1..ef7a448 100644
--- a/uimaj-cpe/pom.xml
+++ b/uimaj-cpe/pom.xml
@@ -44,13 +44,13 @@
        element, and just changing the following two properties -->  
   <scm>
     <connection>
-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-cpe
+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-cpe
     </connection>
     <developerConnection>
-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-cpe
+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-cpe
     </developerConnection>
     <url>
-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-cpe
+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-cpe
     </url>
   </scm>
   
@@ -84,6 +84,11 @@
 			<version>${project.parent.version}</version>
 			<scope>test</scope>
 		</dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-jdk14</artifactId>
+      <scope>test</scope>
+    </dependency>
 	</dependencies>
 	<build>
 		<finalName>uima-cpe</finalName>
diff --git a/uimaj-cpe/src/main/java/org/apache/uima/collection/impl/cpm/container/deployer/vinci/VinciCasProcessorDeployer.java b/uimaj-cpe/src/main/java/org/apache/uima/collection/impl/cpm/container/deployer/vinci/VinciCasProcessorDeployer.java
index 6809387..8bef471 100644
--- a/uimaj-cpe/src/main/java/org/apache/uima/collection/impl/cpm/container/deployer/vinci/VinciCasProcessorDeployer.java
+++ b/uimaj-cpe/src/main/java/org/apache/uima/collection/impl/cpm/container/deployer/vinci/VinciCasProcessorDeployer.java
@@ -1879,7 +1879,7 @@
    * Used during a launch of the managed (local) Cas Processor this method returns a port number on
    * which the Cas Processor is waiting for requests. Each Cas Processor was a given a port by the
    * local vns where it is expected to accept requests from clients. The ports assigned to Cas
-   * Processors are managed by the local instance of the VNS and available in the queue <i>portQueue</>.
+   * Processors are managed by the local instance of the VNS and available in the queue <i>portQueue</i>.
    * 
    * @param portQueue -
    *          queue containing ports assigned to services by local VNS
diff --git a/uimaj-document-annotation/pom.xml b/uimaj-document-annotation/pom.xml
index f56ab86..c3f086b 100644
--- a/uimaj-document-annotation/pom.xml
+++ b/uimaj-document-annotation/pom.xml
@@ -44,13 +44,13 @@
        element, and just changing the following two properties -->  
   <scm>
     <connection>
-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-document-annotation
+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-document-annotation
     </connection>
     <developerConnection>
-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-document-annotation
+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-document-annotation
     </developerConnection>
     <url>
-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-document-annotation
+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-document-annotation
     </url>
   </scm>
   
@@ -72,7 +72,12 @@
 			<version>${project.parent.version}</version>
 			<scope>test</scope>
 		</dependency>
- 	</dependencies>
+		<dependency>
+		  <groupId>org.slf4j</groupId>
+		  <artifactId>slf4j-jdk14</artifactId>
+		  <scope>test</scope>
+		</dependency>
+	</dependencies>
 	<build>
 		<finalName>uima-document-annotation</finalName>
 	</build>  
diff --git a/uimaj-document-annotation/src/main/java/org/apache/uima/jcas/tcas/DocumentAnnotation.java b/uimaj-document-annotation/src/main/java/org/apache/uima/jcas/tcas/DocumentAnnotation.java
index 7d82ea4..a499a0a 100644
--- a/uimaj-document-annotation/src/main/java/org/apache/uima/jcas/tcas/DocumentAnnotation.java
+++ b/uimaj-document-annotation/src/main/java/org/apache/uima/jcas/tcas/DocumentAnnotation.java
@@ -19,6 +19,9 @@
 
 package org.apache.uima.jcas.tcas;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
@@ -35,6 +38,10 @@
  */
 public class DocumentAnnotation extends Annotation {
 
+  /* public static string for use where constants are needed, e.g. in some Java Annotations */
+  public final static String _TypeName = CAS.TYPE_NAME_DOCUMENT_ANNOTATION;
+  public final static String _FeatName_language = "language";
+  
   public final static int typeIndexID = JCasRegistry.register(DocumentAnnotation.class);
 
   public final static int type = typeIndexID;
@@ -43,7 +50,8 @@
     return typeIndexID;
   }
 
-  public final static int _FI_language = TypeSystemImpl.getAdjustedFeatureOffset("language"); 
+  private final static CallSite _FC_language = TypeSystemImpl.createCallSite(DocumentAnnotation.class, "language");
+  private final static MethodHandle _FH_language = _FC_language.dynamicInvoker();
         
   // Never called. Disable default constructor
   protected DocumentAnnotation() {
@@ -70,13 +78,13 @@
    * getter for language
    * @return the language
    */
-  public String getLanguage() { return _getStringValueNc(_FI_language); }
+  public String getLanguage() { return _getStringValueNc(wrapGetIntCatchException(_FH_language)); }
 
   /**
    * setter for language
    * @param v the language
    */
   public void setLanguage(String v) {
-    _setStringValueNfc(_FI_language, v);
+    _setStringValueNfc(wrapGetIntCatchException(_FH_language), v);
   }
 }
diff --git a/uimaj-document-annotation/src/test/java/org/apache/uima/jcas/tcas/DocMeta.java b/uimaj-document-annotation/src/test/java/org/apache/uima/jcas/tcas/DocMeta.java
new file mode 100644
index 0000000..472ed5d
--- /dev/null
+++ b/uimaj-document-annotation/src/test/java/org/apache/uima/jcas/tcas/DocMeta.java
@@ -0,0 +1,306 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+   
+/* Apache UIMA v3 - First created by JCasGen Mon Oct 02 16:32:10 EDT 2017 */
+
+package org.apache.uima.jcas.tcas;
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.cas.impl.TypeSystemImpl;
+import org.apache.uima.jcas.JCas; 
+import org.apache.uima.jcas.JCasRegistry;
+
+
+import org.apache.uima.jcas.cas.FSArray;
+import org.apache.uima.jcas.cas.StringArray;
+import org.apache.uima.jcas.cas.IntegerArray;
+
+
+/** 
+ * Updated by JCasGen Mon Oct 02 16:32:10 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-document-annotation/src/test/resources/ExampleCas/testTypeSystem_docmetadata.xml
+ * @generated */
+public class DocMeta extends DocumentAnnotation {
+ 
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "org.apache.uima.jcas.tcas.DocMeta";
+  
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static int typeIndexID = JCasRegistry.register(DocMeta.class);
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static int type = typeIndexID;
+  /** @generated
+   * @return index of the type  
+   */
+  @Override
+  public              int getTypeIndexID() {return typeIndexID;}
+ 
+ 
+  /* *******************
+   *   Feature Offsets *
+   * *******************/ 
+   
+  public final static String _FeatName_feat = "feat";
+  public final static String _FeatName_feat2 = "feat2";
+  public final static String _FeatName_feat3 = "feat3";
+  public final static String _FeatName_arraystr = "arraystr";
+  public final static String _FeatName_arrayints = "arrayints";
+  public final static String _FeatName_arrayFs = "arrayFs";
+
+
+  /* Feature Adjusted Offsets */
+  private final static CallSite _FC_feat = TypeSystemImpl.createCallSite(DocMeta.class, "feat");
+  private final static MethodHandle _FH_feat = _FC_feat.dynamicInvoker();
+  private final static CallSite _FC_feat2 = TypeSystemImpl.createCallSite(DocMeta.class, "feat2");
+  private final static MethodHandle _FH_feat2 = _FC_feat2.dynamicInvoker();
+  private final static CallSite _FC_feat3 = TypeSystemImpl.createCallSite(DocMeta.class, "feat3");
+  private final static MethodHandle _FH_feat3 = _FC_feat3.dynamicInvoker();
+  private final static CallSite _FC_arraystr = TypeSystemImpl.createCallSite(DocMeta.class, "arraystr");
+  private final static MethodHandle _FH_arraystr = _FC_arraystr.dynamicInvoker();
+  private final static CallSite _FC_arrayints = TypeSystemImpl.createCallSite(DocMeta.class, "arrayints");
+  private final static MethodHandle _FH_arrayints = _FC_arrayints.dynamicInvoker();
+  private final static CallSite _FC_arrayFs = TypeSystemImpl.createCallSite(DocMeta.class, "arrayFs");
+  private final static MethodHandle _FH_arrayFs = _FC_arrayFs.dynamicInvoker();
+
+   
+  /** Never called.  Disable default constructor
+   * @generated */
+  protected DocMeta() {/* intentionally empty block */}
+    
+  /** Internal - constructor used by generator 
+   * @generated
+   * @param casImpl the CAS this Feature Structure belongs to
+   * @param type the type of this Feature Structure 
+   */
+  public DocMeta(TypeImpl type, CASImpl casImpl) {
+    super(type, casImpl);
+    readObject();
+  }
+  
+  /** @generated
+   * @param jcas JCas to which this Feature Structure belongs 
+   */
+  public DocMeta(JCas jcas) {
+    super(jcas);
+    readObject();   
+  } 
+
+
+  /** @generated
+   * @param jcas JCas to which this Feature Structure belongs
+   * @param begin offset to the begin spot in the SofA
+   * @param end offset to the end spot in the SofA 
+  */  
+  public DocMeta(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }   
+
+  /** 
+   * <!-- begin-user-doc -->
+   * Write your own initialization here
+   * <!-- end-user-doc -->
+   *
+   * @generated modifiable 
+   */
+  private void readObject() {/*default - does nothing empty block */}
+     
+ 
+    
+  //*--------------*
+  //* Feature: feat
+
+  /** getter for feat - gets 
+   * @generated
+   * @return value of the feature 
+   */
+  public String getFeat() { return _getStringValueNc(wrapGetIntCatchException(_FH_feat));}
+    
+  /** setter for feat - sets  
+   * @generated
+   * @param v value to set into the feature 
+   */
+  public void setFeat(String v) {
+    _setStringValueNfc(wrapGetIntCatchException(_FH_feat), v);
+  }    
+    
+   
+    
+  //*--------------*
+  //* Feature: feat2
+
+  /** getter for feat2 - gets 
+   * @generated
+   * @return value of the feature 
+   */
+  public String getFeat2() { return _getStringValueNc(wrapGetIntCatchException(_FH_feat2));}
+    
+  /** setter for feat2 - sets  
+   * @generated
+   * @param v value to set into the feature 
+   */
+  public void setFeat2(String v) {
+    _setStringValueNfc(wrapGetIntCatchException(_FH_feat2), v);
+  }    
+    
+   
+    
+  //*--------------*
+  //* Feature: feat3
+
+  /** getter for feat3 - gets 
+   * @generated
+   * @return value of the feature 
+   */
+  public String getFeat3() { return _getStringValueNc(wrapGetIntCatchException(_FH_feat3));}
+    
+  /** setter for feat3 - sets  
+   * @generated
+   * @param v value to set into the feature 
+   */
+  public void setFeat3(String v) {
+    _setStringValueNfc(wrapGetIntCatchException(_FH_feat3), v);
+  }    
+    
+   
+    
+  //*--------------*
+  //* Feature: arraystr
+
+  /** getter for arraystr - gets 
+   * @generated
+   * @return value of the feature 
+   */
+  public StringArray getArraystr() { return (StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arraystr)));}
+    
+  /** setter for arraystr - sets  
+   * @generated
+   * @param v value to set into the feature 
+   */
+  public void setArraystr(StringArray v) {
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_arraystr), v);
+  }    
+    
+    
+  /** indexed getter for arraystr - gets an indexed value - 
+   * @generated
+   * @param i index in the array to get
+   * @return value of the element at index i 
+   */
+  public String getArraystr(int i) {
+     return ((StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arraystr)))).get(i);} 
+
+  /** indexed setter for arraystr - sets an indexed value - 
+   * @generated
+   * @param i index in the array to set
+   * @param v value to set into the array 
+   */
+  public void setArraystr(int i, String v) {
+    ((StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arraystr)))).set(i, v);
+  }  
+   
+    
+  //*--------------*
+  //* Feature: arrayints
+
+  /** getter for arrayints - gets 
+   * @generated
+   * @return value of the feature 
+   */
+  public IntegerArray getArrayints() { return (IntegerArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayints)));}
+    
+  /** setter for arrayints - sets  
+   * @generated
+   * @param v value to set into the feature 
+   */
+  public void setArrayints(IntegerArray v) {
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_arrayints), v);
+  }    
+    
+    
+  /** indexed getter for arrayints - gets an indexed value - 
+   * @generated
+   * @param i index in the array to get
+   * @return value of the element at index i 
+   */
+  public int getArrayints(int i) {
+     return ((IntegerArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayints)))).get(i);} 
+
+  /** indexed setter for arrayints - sets an indexed value - 
+   * @generated
+   * @param i index in the array to set
+   * @param v value to set into the array 
+   */
+  public void setArrayints(int i, int v) {
+    ((IntegerArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayints)))).set(i, v);
+  }  
+   
+    
+  //*--------------*
+  //* Feature: arrayFs
+
+  /** getter for arrayFs - gets 
+   * @generated
+   * @return value of the feature 
+   */
+  public FSArray getArrayFs() { return (FSArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayFs)));}
+    
+  /** setter for arrayFs - sets  
+   * @generated
+   * @param v value to set into the feature 
+   */
+  public void setArrayFs(FSArray v) {
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_arrayFs), v);
+  }    
+    
+    
+  /** indexed getter for arrayFs - gets an indexed value - 
+   * @generated
+   * @param i index in the array to get
+   * @return value of the element at index i 
+   */
+  public Annotation getArrayFs(int i) {
+     return (Annotation)(((FSArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayFs)))).get(i));} 
+
+  /** indexed setter for arrayFs - sets an indexed value - 
+   * @generated
+   * @param i index in the array to set
+   * @param v value to set into the array 
+   */
+  public void setArrayFs(int i, Annotation v) {
+    ((FSArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_arrayFs)))).set(i, v);
+  }  
+  }
+
+    
\ No newline at end of file
diff --git a/uimaj-document-annotation/src/test/java/org/apache/uima/jcas/tcas/DocumentAnnotationTest.java b/uimaj-document-annotation/src/test/java/org/apache/uima/jcas/tcas/DocumentAnnotationTest.java
index 1edb083..32cc738 100644
--- a/uimaj-document-annotation/src/test/java/org/apache/uima/jcas/tcas/DocumentAnnotationTest.java
+++ b/uimaj-document-annotation/src/test/java/org/apache/uima/jcas/tcas/DocumentAnnotationTest.java
@@ -20,15 +20,37 @@
 
 import junit.framework.TestCase;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.uima.UIMAFramework;
 import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.CASException;
+import org.apache.uima.cas.SerialFormat;
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.CasCompare;
+import org.apache.uima.cas.text.AnnotationFS;
 import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.cas.FSArray;
+import org.apache.uima.jcas.cas.IntegerArray;
+import org.apache.uima.jcas.cas.StringArray;
+import org.apache.uima.resource.ResourceInitializationException;
+import org.apache.uima.resource.metadata.TypeSystemDescription;
+import org.apache.uima.resource.metadata.impl.TypePriorities_impl;
 import org.apache.uima.resource.metadata.impl.TypeSystemDescription_impl;
 import org.apache.uima.test.junit_extension.JUnitExtension;
 import org.apache.uima.util.CasCreationUtils;
+import org.apache.uima.util.CasIOUtils;
+import org.apache.uima.util.InvalidXMLException;
+import org.apache.uima.util.XMLInputSource;
 
 
 public class DocumentAnnotationTest extends TestCase {
   JCas jcas;
+  private CAS source;
+  private CAS target;
   
   public void setUp() throws Exception {
     try {
@@ -55,5 +77,75 @@
     } catch (Exception e) {
       JUnitExtension.handleException(e);
     }
-  }  
+  }
+  
+  public void testDocMeta() throws Exception {
+    File typeSystemFile = JUnitExtension.getFile("ExampleCas/testTypeSystem_docmetadata.xml");
+    TypeSystemDescription typeSystem = UIMAFramework.getXMLParser().parseTypeSystemDescription(
+            new XMLInputSource(typeSystemFile));
+    
+    source = CasCreationUtils.createCas(typeSystem, new TypePriorities_impl(), null);
+    target = CasCreationUtils.createCas(typeSystem, new TypePriorities_impl(), null);
+    
+    jcas = source.getJCas();
+    
+    tstSerdesB4Sofa(SerialFormat.XMI);
+    tstSerdesB4Sofa(SerialFormat.XCAS);
+    tstSerdesB4Sofa(SerialFormat.BINARY);
+    tstSerdesB4Sofa(SerialFormat.COMPRESSED);
+    tstSerdesB4Sofa(SerialFormat.COMPRESSED_FILTERED);    
+  }
+  
+  private void tstSerdesB4Sofa(SerialFormat format) throws IOException {
+    source.reset();
+    target.reset();
+    
+    new DocMeta(jcas).addToIndexes();
+    
+    jcas.setDocumentText("something");
+    
+    new Annotation(jcas);
+    
+    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    CasIOUtils.save(source, bos, format);
+    bos.close();
+    
+    CasIOUtils.load(new ByteArrayInputStream(bos.toByteArray()), target);
+    AnnotationFS c = target.getDocumentAnnotation();
+    System.out.println(c);
+    System.out.println(target.<DocMeta>getDocumentAnnotation());
+    assertTrue(CasCompare.compareCASes((CASImpl)source, (CASImpl)target));
+  }
+  
+  public void testToString() throws InvalidXMLException, IOException, ResourceInitializationException, CASException {
+    File typeSystemFile = JUnitExtension.getFile("ExampleCas/testTypeSystem_docmetadata.xml");
+    TypeSystemDescription typeSystem = UIMAFramework.getXMLParser().parseTypeSystemDescription(
+            new XMLInputSource(typeSystemFile));
+    
+    source = CasCreationUtils.createCas(typeSystem, new TypePriorities_impl(), null);
+    jcas = source.getJCas();
+    
+    DocMeta d = new DocMeta(jcas);
+    d.setFeat("a string");
+    d.setFeat2("b string");
+    d.setFeat3("c string");
+    
+    FSArray fsa = new FSArray(jcas, 2);
+    fsa.set(0, new Annotation(jcas, 1,2));
+    fsa.set(1, new Annotation(jcas, 3,4));
+    d.setArrayFs(fsa);
+    
+    IntegerArray intarr = new IntegerArray(jcas, 2);
+    intarr.set(0,  10);
+    intarr.set(1,  -10);
+    d.setArrayints(intarr);
+    
+    StringArray strarr = new StringArray(jcas, 2);
+    strarr.set(0,  "first");
+    strarr.set(1,  "second");
+    d.setArraystr(strarr);
+    
+    System.out.println(d.toString());
+  }
+
 }
diff --git a/uimaj-document-annotation/src/test/resources/ExampleCas/testTypeSystem_docmetadata.xml b/uimaj-document-annotation/src/test/resources/ExampleCas/testTypeSystem_docmetadata.xml
new file mode 100644
index 0000000..048a85e
--- /dev/null
+++ b/uimaj-document-annotation/src/test/resources/ExampleCas/testTypeSystem_docmetadata.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ -->

+ <typeSystemDescription xmlns="http://uima.apache.org/resourceSpecifier">

+    <name>docmetadata</name>

+    <description/>

+    <version>1.0</version>

+    <vendor/>

+  <types>

+    <typeDescription>

+      <name>org.apache.uima.jcas.tcas.DocMeta</name>

+      <description/>

+      <supertypeName>uima.tcas.DocumentAnnotation</supertypeName>

+      <features>

+        <featureDescription>

+          <name>feat</name>

+          <description/>

+          <rangeTypeName>uima.cas.String</rangeTypeName>

+        </featureDescription>

+        <featureDescription>

+          <name>feat2</name>

+          <description/>

+          <rangeTypeName>uima.cas.String</rangeTypeName>

+        </featureDescription>

+        <featureDescription>

+          <name>feat3</name>

+          <description/>

+          <rangeTypeName>uima.cas.String</rangeTypeName>

+        </featureDescription>

+        

+      <featureDescription>

+          <name>arraystr</name>

+          <description/>

+          <rangeTypeName>uima.cas.StringArray</rangeTypeName>

+        </featureDescription>

+        <featureDescription>

+          <name>arrayints</name>

+          <description/>

+          <rangeTypeName>uima.cas.IntegerArray</rangeTypeName>

+        </featureDescription>

+        <featureDescription>

+          <name>arrayFs</name>

+          <description/>

+          <rangeTypeName>uima.cas.FSArray</rangeTypeName>

+          <elementType>uima.tcas.Annotation</elementType>

+        </featureDescription>

+      </features>

+    </typeDescription>

+  </types>

+</typeSystemDescription>

diff --git a/uimaj-eclipse-feature-runtime/pom.xml b/uimaj-eclipse-feature-runtime/pom.xml
index 734c8bc..6e8ad71 100644
--- a/uimaj-eclipse-feature-runtime/pom.xml
+++ b/uimaj-eclipse-feature-runtime/pom.xml
@@ -45,13 +45,13 @@
        element, and just changing the following two properties -->  

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-eclipse-feature-runtime

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-eclipse-feature-runtime

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-eclipse-feature-runtime

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-eclipse-feature-runtime

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-eclipse-feature-runtime

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-eclipse-feature-runtime

     </url>

   </scm>

   

diff --git a/uimaj-eclipse-feature-runtime/src/main/resources/feature.xml b/uimaj-eclipse-feature-runtime/src/main/resources/feature.xml
index 54c1f60..ffe2ad0 100644
--- a/uimaj-eclipse-feature-runtime/src/main/resources/feature.xml
+++ b/uimaj-eclipse-feature-runtime/src/main/resources/feature.xml
@@ -43,4 +43,9 @@
          version="${parsedVersion.osgiVersion}"

          unpack="false"/>

 

+   <requires>

+      <import plugin="org.slf4j.api"/>

+      <import plugin="org.eclipse.m2e.maven.runtime.slf4j.simple"/>

+   </requires>

+     

 </feature>

diff --git a/uimaj-eclipse-feature-tools/pom.xml b/uimaj-eclipse-feature-tools/pom.xml
index ca41eeb..5fec8ef 100644
--- a/uimaj-eclipse-feature-tools/pom.xml
+++ b/uimaj-eclipse-feature-tools/pom.xml
@@ -43,13 +43,13 @@
        element, and just changing the following two properties -->  

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-eclipse-feature-tools

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-eclipse-feature-tools

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-eclipse-feature-tools

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-eclipse-feature-tools

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-eclipse-feature-tools

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-eclipse-feature-tools

     </url>

   </scm>

   

diff --git a/uimaj-eclipse-update-site/pom.xml b/uimaj-eclipse-update-site/pom.xml
index e620ba0..30b4acd 100644
--- a/uimaj-eclipse-update-site/pom.xml
+++ b/uimaj-eclipse-update-site/pom.xml
@@ -17,13 +17,13 @@
    specific language governing permissions and limitations

    under the License.

 -->

-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

   <modelVersion>4.0.0</modelVersion>

 

   <parent>

     <groupId>org.apache.uima</groupId>

     <artifactId>uimaj-parent</artifactId>

-    <version>2.8.0</version>

+    <version>3.0.0</version>

     <relativePath />

   </parent>

 

@@ -37,13 +37,13 @@
 

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/branches/experiment-v3-jcas/uimaj-eclipse-update-site

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/trunk/uimaj-eclipse-update-site

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/branches/experiment-v3-jcas/uimaj-eclipse-update-site

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/trunk/uimaj-eclipse-update-site

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-eclipse-update-site

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/trunk/uimaj-eclipse-update-site

     </url>

   </scm>

 

@@ -51,14 +51,14 @@
     <uimaScmRoot>uimaj</uimaScmRoot>

     <uimaScmProject>${project.artifactId}</uimaScmProject>

 

-    <eclipseUpdateSiteComponent>uimaj</eclipseUpdateSiteComponent>

+    <eclipseUpdateSiteComponent>uimaj-uv3</eclipseUpdateSiteComponent>

 

     <eclipseUpdateSubSite>${project.build.directory}/eclipse-update-site/${eclipseUpdateSiteComponent}</eclipseUpdateSubSite>

 

   </properties>

 

   <build>

-

+    

     <plugins>

       <plugin>

         <groupId>org.apache.maven.plugins</groupId>

@@ -76,14 +76,14 @@
                             Name must be the same as the ID for the plugin or feature

                 ======================================================================= -->

               <artifactItems>

-                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-ep-cas-editor</artifactId>    <version>${project.version}</version><destFileName>org.apache.uima.caseditor_${project.version}.jar    </destFileName></artifactItem>

-                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-ep-cas-editor-ide</artifactId><version>${project.version}</version><destFileName>org.apache.uima.caseditor.ide_${project.version}.jar</destFileName></artifactItem>

-                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-ep-configurator</artifactId>  <version>${project.version}</version><destFileName>org.apache.uima.desceditor_${project.version}.jar   </destFileName></artifactItem>

-                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-ep-debug</artifactId>         <version>${project.version}</version><destFileName>org.apache.uima.debug_${project.version}.jar        </destFileName></artifactItem>

-                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-ep-jcasgen</artifactId>       <version>${project.version}</version><destFileName>org.apache.uima.jcas.jcasgenp_${project.version}.jar</destFileName></artifactItem>

-                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-ep-pear-packager</artifactId> <version>${project.version}</version><destFileName>org.apache.uima.pear_${project.version}.jar         </destFileName></artifactItem>

-                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-ep-runtime</artifactId>       <version>${project.version}</version><destFileName>org.apache.uima.runtime_${project.version}.jar      </destFileName></artifactItem>

-                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-ep-launcher</artifactId>      <version>${project.version}</version><destFileName>org.apache.uima.launcher_${project.version}.jar     </destFileName></artifactItem>

+                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-ep-cas-editor</artifactId>    <version>${project.version}</version><destFileName>org.apache.uima.caseditor_${parsedVersion.osgiVersion}.jar    </destFileName></artifactItem>

+                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-ep-cas-editor-ide</artifactId><version>${project.version}</version><destFileName>org.apache.uima.caseditor.ide_${parsedVersion.osgiVersion}.jar</destFileName></artifactItem>

+                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-ep-configurator</artifactId>  <version>${project.version}</version><destFileName>org.apache.uima.desceditor_${parsedVersion.osgiVersion}.jar   </destFileName></artifactItem>

+                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-ep-debug</artifactId>         <version>${project.version}</version><destFileName>org.apache.uima.debug_${parsedVersion.osgiVersion}.jar        </destFileName></artifactItem>

+                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-ep-jcasgen</artifactId>       <version>${project.version}</version><destFileName>org.apache.uima.jcas.jcasgenp_${parsedVersion.osgiVersion}.jar</destFileName></artifactItem>

+                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-ep-pear-packager</artifactId> <version>${project.version}</version><destFileName>org.apache.uima.pear_${parsedVersion.osgiVersion}.jar         </destFileName></artifactItem>

+                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-ep-runtime</artifactId>       <version>${project.version}</version><destFileName>org.apache.uima.runtime_${parsedVersion.osgiVersion}.jar      </destFileName></artifactItem>

+                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-ep-launcher</artifactId>      <version>${project.version}</version><destFileName>org.apache.uima.launcher_${parsedVersion.osgiVersion}.jar     </destFileName></artifactItem>

               </artifactItems>

               <outputDirectory>${toBePacked}</outputDirectory>

             </configuration>

@@ -102,10 +102,169 @@
                             Name must be the same as the ID for the plugin or feature

                 ======================================================================= -->

               <artifactItems>

-                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-eclipse-feature-runtime</artifactId><version>${project.version}</version><destFileName>org.apache.uima.runtime_${project.version}.jar</destFileName></artifactItem>

-                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-eclipse-feature-tools</artifactId>  <version>${project.version}</version><destFileName>org.apache.uima.tools_${project.version}.jar  </destFileName></artifactItem>

+                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-eclipse-feature-runtime</artifactId><version>${project.version}</version><destFileName>org.apache.uima.runtime_${parsedVersion.osgiVersion}.jar</destFileName></artifactItem>

+                <artifactItem><groupId>org.apache.uima</groupId><artifactId>uimaj-eclipse-feature-tools</artifactId>  <version>${project.version}</version><destFileName>org.apache.uima.tools_${parsedVersion.osgiVersion}.jar  </destFileName></artifactItem>

               </artifactItems>

-              <outputDirectory>${project.build.directory}/eus-work/features</outputDirectory>

+              <outputDirectory>${eusWork}/features</outputDirectory>

+            </configuration>

+          </execution>

+        </executions>

+      </plugin>

+

+      <plugin>

+        <artifactId>maven-antrun-plugin</artifactId>

+        <executions>

+           <execution>

+            <id>BuildUpdateSite-pack-svnget-buildMetadata-commit-to-dev</id>

+            <phase>package</phase>

+            <goals>

+              <goal>run</goal>

+            </goals>

+            <configuration combine.self="override">

+              <target>

+                <taskdef classname="net.sf.antcontrib.logic.IfTask" name="if" />

+                

+                <condition property="eclipse.home" value="${uima-maven-build-eclipse-home}">

+                  <not>

+                    <equals arg1="${uima-maven-build-eclipse-home}" arg2="$${uima-maven-build-eclipse-home}" />

+                  </not>

+                </condition>

+

+                <property environment="envVar" />

+                <condition property="eclipse.home" value="${envVar.ECLIPSE_HOME}">

+                  <isset property="envVar.ECLIPSE_HOME" />

+                </condition>

+                

+                <fail unless="eclipse.home" message="********** Please set up and use an ant property eclipse.home set to an Eclipse installation at level 3.3 or later, e.g. c:/eclipses/3.3/eclipse" />

+                <fail unless="uima-eclipse-jar-processor" message="********** Please add to your settings.xml file the property uima-eclipse-jar-processor, point to this within an Eclipse installation at level 4.2 or later, e.g. \$\{uima-maven-build-eclipse-home\}/plugins/org.eclipse.equinox.p2.jarprocessor_1.0.200.v20110808-1657.jar" />

+                <!--  skip this for first release, only want latest there

+                <if>

+                  <equals arg2="true" arg1="${isApacheRelease}" />

+                  <then>

+                    

+                    <echo>checking out eclipse update subsite uimaj-v3-pre-production from dist ...release...</echo>

+                    <delete quiet="true" dir="${eclipseUpdateSubSite}" />

+                    <exec failonerror="true" executable="svn">

+                      <arg value="checkout" />

+                      <arg value="https://dist.apache.org/repos/dist/release/uima/eclipse-update-site/uimaj-v3-pre-production" />

+                      <arg value="${eclipseUpdateSubSite}" />

+                    </exec>

+                    

+                    <echo>Saving original content and artifacts for the site</echo>

+                    <copy todir="${project.build.directory}/saved" failonerror="true"> 

+                      <fileset dir="${eclipseUpdateSubSite}" includes="content.jar,artifacts.jar" />

+                    </copy>

+                    

+                  </then>

+                  <else>

+                    <echo>skipping checkout of current svn dist release (because not apache-release)</echo>

+                    <delete quiet="true" dir="${eclipseUpdateSubSite}" />

+                  </else>

+                </if>

+                   -->

+                    

+                <echo>Compress plugin Jars using pack200 - this may take a minute or 2</echo>

+                <java fork="true" maxmemory="256m" jar="${uima-eclipse-jar-processor}" failonerror="true">

+                  <arg line="-processAll" />

+                  <arg line="-repack" />

+                  <arg line="-pack" />

+                  <arg line="-verbose" />

+                  <arg line="-outputDir ${eusWork}/plugins" />

+                  <arg line="${toBePacked}" />

+                </java>

+                

+                <echo>Save conditioned Jars prior to signing, in case of redo</echo>

+                <echo>-------------------------------------------------------</echo> 

+                <copy todir="${project.build.directory}/saved/features" failonerror="true">

+                  <fileset dir="${eusWork}/features" includes="*.jar" />                 

+                </copy>

+                <copy todir="${project.build.directory}/saved/plugins" failonerror="true">

+                   <fileset dir="${eusWork}/plugins" includes="*.jar" />                 

+                </copy>

+                

+                <echo>Generate the p2 metadata and publish new artifacts</echo>

+                <java fork="true" maxmemory="256m" jar="${eclipse-equinox-launcher}" failonerror="true">

+                  <arg line="-application org.eclipse.equinox.p2.publisher.FeaturesAndBundlesPublisher" />

+                  <arg line="-metadataRepository file:///${eclipseUpdateSubSite}" />

+                  <arg line="-artifactRepository file:///${eclipseUpdateSubSite}" />

+                  <arg line="-source ${eusWork}" />

+                  <arg line="-configs ANY.ANY.ANY" />

+                  <arg line="-publishArtifacts" />

+                  <arg line="-reusePack200Files" />

+                  <arg line="-compress" />

+                  <arg line="-append" />

+                </java>

+                <echo>Augment p2 metadata with category information</echo>

+                <java fork="true" maxmemory="256m" jar="${eclipse-equinox-launcher}" failonerror="true">

+                  <arg line="-application org.eclipse.equinox.p2.publisher.CategoryPublisher" />

+                  <arg line="-metadataRepository file:///${eclipseUpdateSubSite}" />

+                  <arg line="-categoryDefinition file:///${basedir}/category.xml" />

+                  <arg line="-categoryQualifier apache-uima" />

+                  <arg line="-compress" />

+                </java>

+                <if>

+                  <equals arg2="true" arg1="${isApacheRelease}" />

+                  <then>

+                    <echo message="Generating checksums for new features and plugins" />

+                    <checksum format="MD5SUM" algorithm="sha1">

+                      <fileset dir="${eusWork}">

+                        <include name="**/*.gz" />

+                        <include name="**/*.jar" />

+                      </fileset>

+                    </checksum>

+                    <checksum format="MD5SUM" algorithm="md5">

+                      <fileset dir="${eusWork}">

+                        <include name="**/*.gz" />

+                        <include name="**/*.jar" />

+                      </fileset>

+                    </checksum>

+                    <echo message="Generating gpg signatures for new features and plugins" />

+                    <apply failonerror="true" dir="${eusWork}" executable="gpg">

+                      <arg value="--detach-sign" />

+                      <arg value="--armor" />

+                      <arg value="--batch" />

+                      <fileset dir="${eusWork}">

+                        <include name="**/*.jar" />

+                        <include name="**/*.jar.pack.gz" />

+                      </fileset>

+                    </apply>

+                    <echo message="Copying the checksums and signatures to the update subsite" />

+                    <copy todir="${eclipseUpdateSubSite}" failonerror="true">

+                      <fileset dir="${eusWork}">

+                        <include name="**/*.asc" />

+                        <include name="**/*.md5" />

+                        <include name="**/*.sha1" />

+                      </fileset>

+                    </copy>

+                    <echo message="Clearing previous checksums and signatures for update artifacts.jar and content.jar" />

+                    <delete dir="${eclipseUpdateSubSite}">

+                      <include name="*.sha1" />

+                      <include name="*.md5" />

+                      <include name="*.asc" />

+                    </delete>

+                    <echo message="Generating checksums for updated artifacts.jar and content.jar" />

+                    <checksum format="MD5SUM" algorithm="sha1">

+                      <fileset dir="${eclipseUpdateSubSite}">

+                        <include name="*.jar" />

+                      </fileset>

+                    </checksum>

+                    <checksum format="MD5SUM" algorithm="md5">

+                      <fileset dir="${eclipseUpdateSubSite}">

+                        <include name="*.jar" />

+                      </fileset>

+                    </checksum>

+                    <echo message="Generating gpg signatures for artifacts.jar and content.jar" />

+                    <apply failonerror="true" dir="${eclipseUpdateSubSite}" executable="gpg">

+                      <arg value="--detach-sign" />

+                      <arg value="--armor" />

+                      <arg value="--batch" />

+                      <fileset dir="${eclipseUpdateSubSite}">

+                        <include name="*.jar" />

+                      </fileset>

+                    </apply>

+                  </then>

+                </if>

+              </target>

             </configuration>

           </execution>

         </executions>

diff --git a/uimaj-ep-cas-editor-ide/pom.xml b/uimaj-ep-cas-editor-ide/pom.xml
index 9ae8643..8f5d47e 100644
--- a/uimaj-ep-cas-editor-ide/pom.xml
+++ b/uimaj-ep-cas-editor-ide/pom.xml
@@ -43,13 +43,13 @@
        element, and just changing the following two properties -->  

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-cas-editor-ide

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-cas-editor-ide

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-cas-editor-ide

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-cas-editor-ide

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-cas-editor-ide

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-cas-editor-ide

     </url>

   </scm>

   

diff --git a/uimaj-ep-cas-editor/pom.xml b/uimaj-ep-cas-editor/pom.xml
index 6fccf97..a49936b 100644
--- a/uimaj-ep-cas-editor/pom.xml
+++ b/uimaj-ep-cas-editor/pom.xml
@@ -43,13 +43,13 @@
        element, and just changing the following two properties -->  

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-cas-editor

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-cas-editor

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-cas-editor

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-cas-editor

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-cas-editor

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-cas-editor

     </url>

   </scm>

   

diff --git a/uimaj-ep-cas-editor/src/main/java/org/apache/uima/caseditor/core/model/dotcorpus/DotCorpusSerializer.java b/uimaj-ep-cas-editor/src/main/java/org/apache/uima/caseditor/core/model/dotcorpus/DotCorpusSerializer.java
index 81a04c2..2bb2579 100644
--- a/uimaj-ep-cas-editor/src/main/java/org/apache/uima/caseditor/core/model/dotcorpus/DotCorpusSerializer.java
+++ b/uimaj-ep-cas-editor/src/main/java/org/apache/uima/caseditor/core/model/dotcorpus/DotCorpusSerializer.java
@@ -30,6 +30,7 @@
 

 import org.apache.uima.caseditor.CasEditorPlugin;

 import org.apache.uima.caseditor.editor.AnnotationStyle;

+import org.apache.uima.internal.util.XMLUtils;

 import org.apache.uima.util.XMLSerializer;

 import org.eclipse.core.runtime.CoreException;

 import org.eclipse.core.runtime.IStatus;

@@ -110,7 +111,7 @@
    * @throws CoreException -

    */

   public static DotCorpus parseDotCorpus(InputStream dotCorpusStream) throws CoreException {

-    DocumentBuilderFactory documentBuilderFacoty = DocumentBuilderFactory.newInstance();

+    DocumentBuilderFactory documentBuilderFacoty = XMLUtils.createDocumentBuilderFactory();

 

     DocumentBuilder documentBuilder;

 

diff --git a/uimaj-ep-configurator/pom.xml b/uimaj-ep-configurator/pom.xml
index 50d93bd..ced735a 100644
--- a/uimaj-ep-configurator/pom.xml
+++ b/uimaj-ep-configurator/pom.xml
@@ -44,13 +44,13 @@
        element, and just changing the following two properties -->  
   <scm>
     <connection>
-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-configurator
+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-configurator
     </connection>
     <developerConnection>
-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-configurator
+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-configurator
     </developerConnection>
     <url>
-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-configurator
+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-configurator
     </url>
   </scm>
   
@@ -365,8 +365,8 @@
               !org.eclipse.ui.dialogs,
               !org.eclipse.ui.part,
               !org.eclipse.core.runtime,
-              *,
-              org.eclipse.jdt.ui
+              org.eclipse.jdt.ui,
+              *
             </Import-Package>
 
             
diff --git a/uimaj-ep-configurator/src/main/java/org/apache/uima/taeconfigurator/editors/MultiPageEditor.java b/uimaj-ep-configurator/src/main/java/org/apache/uima/taeconfigurator/editors/MultiPageEditor.java
index 0909f35..d67215c 100644
--- a/uimaj-ep-configurator/src/main/java/org/apache/uima/taeconfigurator/editors/MultiPageEditor.java
+++ b/uimaj-ep-configurator/src/main/java/org/apache/uima/taeconfigurator/editors/MultiPageEditor.java
@@ -2828,7 +2828,8 @@
           try {

             jg.mainForCde(new MergerImpl(), new JCasGenProgressMonitor(progressMonitor),

                     jCasGenThrower, inputFile, outputDirectory, types, (CASImpl) getCurrentView(),

-                    getProject().getLocationURI().getPath(),

+                    getProject().getLocation().toString(),  // https://issues.apache.org/jira/browse/UIMA-5715

+                         // getLocationURI().getPath(),  // on linux/mars, was returning /default/project.name etc

                     limitJCasGenToProjectScope,

                     mergedTypesAddingFeatures);

           } catch (IOException e) {

diff --git a/uimaj-ep-configurator/src/main/java/org/apache/uima/taeconfigurator/model/AbstractModelPart.java b/uimaj-ep-configurator/src/main/java/org/apache/uima/taeconfigurator/model/AbstractModelPart.java
index ca5742b..985ce29 100644
--- a/uimaj-ep-configurator/src/main/java/org/apache/uima/taeconfigurator/model/AbstractModelPart.java
+++ b/uimaj-ep-configurator/src/main/java/org/apache/uima/taeconfigurator/model/AbstractModelPart.java
@@ -34,6 +34,7 @@
   public static final Properties casCreateProperties = new Properties();
   static {
     casCreateProperties.setProperty(UIMAFramework.CAS_INITIAL_HEAP_SIZE, "200");
+    casCreateProperties.setProperty(UIMAFramework.SKIP_USER_JCAS_LOADING, "true");
   }
 
   /** The model root. */
diff --git a/uimaj-ep-debug/plugin.xml b/uimaj-ep-debug/plugin.xml
index 28b8f9a..aa772b5 100644
--- a/uimaj-ep-debug/plugin.xml
+++ b/uimaj-ep-debug/plugin.xml
@@ -109,5 +109,6 @@
    </extension>
    <extension
          point="org.eclipse.ui.startup">
+      <startup class="org.apache.uima.ep_debug.DebugPluginStartup"/>
    </extension>
 </plugin>
diff --git a/uimaj-ep-debug/pom.xml b/uimaj-ep-debug/pom.xml
index ea21019..8a08e39 100644
--- a/uimaj-ep-debug/pom.xml
+++ b/uimaj-ep-debug/pom.xml
@@ -45,13 +45,13 @@
        element, and just changing the following two properties -->  
   <scm>
     <connection>
-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-debug
+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-debug
     </connection>
     <developerConnection>
-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-debug
+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-debug
     </developerConnection>
     <url>
-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-debug
+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-debug
     </url>
   </scm>
   
diff --git a/uimaj-ep-debug/src/main/java/org/apache/uima/ep_debug/DebugPlugin.java b/uimaj-ep-debug/src/main/java/org/apache/uima/ep_debug/DebugPlugin.java
index 6cb374f..af2ce90 100644
--- a/uimaj-ep-debug/src/main/java/org/apache/uima/ep_debug/DebugPlugin.java
+++ b/uimaj-ep-debug/src/main/java/org/apache/uima/ep_debug/DebugPlugin.java
@@ -29,13 +29,7 @@
 /**
  * The main plugin class to be used in the desktop.
  */
-public class DebugPlugin extends Plugin implements IStartup {
-
-  /** The Constant PREF_ALREADY_SET_PREF_SHOW_DETAILS. */
-  public static final String PREF_ALREADY_SET_PREF_SHOW_DETAILS = "org.apache.uima.ep_debug.already_set_pref_show_details";
-
-  /** The Constant ALREADY_SET_PREF_SHOW_DETAILS. */
-  public static final String ALREADY_SET_PREF_SHOW_DETAILS = "already_set_pref_show_details";
+public class DebugPlugin extends Plugin {
 
   /** The plugin. */
   // The shared instance.
@@ -47,37 +41,38 @@
   public DebugPlugin() {
     plugin = this;
   }
-
-  /**
-   * This method is called upon plug-in activation.
-   *
-   * @param context the context
-   * @throws Exception the exception
-   */
-  @Override
-  public void start(BundleContext context) throws Exception {
-    super.start(context);
-    // Intent of next code
-    // For users installing this plugin for the first time, set the pref-show-details preference,
-    // but only once (per fresh workspace) - to allow it to be set to the value which makes
-    // debugging
-    // display work, initially, but allowing the user to set it to something else without having
-    // this
-    // be overridden every time the pluging starts.
-    String doneOnce = JDIDebugUIPlugin.getDefault().getPreferenceStore().getString(
-            PREF_ALREADY_SET_PREF_SHOW_DETAILS);
-    if (ALREADY_SET_PREF_SHOW_DETAILS.equals(doneOnce))
-      return;
-    JDIDebugUIPlugin.getDefault().getPreferenceStore().setValue(PREF_ALREADY_SET_PREF_SHOW_DETAILS,
-            ALREADY_SET_PREF_SHOW_DETAILS);
-
-    String preference = JDIDebugUIPlugin.getDefault().getPreferenceStore().getString(
-            IJDIPreferencesConstants.PREF_SHOW_DETAILS);
-    if (IJDIPreferencesConstants.INLINE_ALL.equals(preference))
-      return;
-    JDIDebugUIPlugin.getDefault().getPreferenceStore().setValue(
-            IJDIPreferencesConstants.PREF_SHOW_DETAILS, IJDIPreferencesConstants.INLINE_ALL);
-  }
+  
+// next moved to DebugPluginStartup class, per change in Eclipse Platform Design
+//  /**
+//   * This method is called upon plug-in activation.
+//   *
+//   * @param context the context
+//   * @throws Exception the exception
+//   */
+//  @Override
+//  public void start(BundleContext context) throws Exception {
+//    super.start(context);
+//    // Intent of next code
+//    // For users installing this plugin for the first time, set the pref-show-details preference,
+//    // but only once (per fresh workspace) - to allow it to be set to the value which makes
+//    // debugging
+//    // display work, initially, but allowing the user to set it to something else without having
+//    // this
+//    // be overridden every time the pluging starts.
+//    String doneOnce = JDIDebugUIPlugin.getDefault().getPreferenceStore().getString(
+//            PREF_ALREADY_SET_PREF_SHOW_DETAILS);
+//    if (ALREADY_SET_PREF_SHOW_DETAILS.equals(doneOnce))
+//      return;
+//    JDIDebugUIPlugin.getDefault().getPreferenceStore().setValue(PREF_ALREADY_SET_PREF_SHOW_DETAILS,
+//            ALREADY_SET_PREF_SHOW_DETAILS);
+//
+//    String preference = JDIDebugUIPlugin.getDefault().getPreferenceStore().getString(
+//            IJDIPreferencesConstants.PREF_SHOW_DETAILS);
+//    if (IJDIPreferencesConstants.INLINE_ALL.equals(preference))
+//      return;
+//    JDIDebugUIPlugin.getDefault().getPreferenceStore().setValue(
+//            IJDIPreferencesConstants.PREF_SHOW_DETAILS, IJDIPreferencesConstants.INLINE_ALL);
+//  }
 
   /**
    * This method is called when the plug-in is stopped.
@@ -100,13 +95,4 @@
     return plugin;
   }
 
-  // this method is required by the Startup extension, which, in turn, is required
-  /* (non-Javadoc)
-   * @see org.eclipse.ui.IStartup#earlyStartup()
-   */
-  // to get the plugin started (no other event gets it started)
-  @Override
-  public void earlyStartup() {
-  }
-
 }
diff --git a/uimaj-ep-debug/src/main/java/org/apache/uima/ep_debug/DebugPluginStartup.java b/uimaj-ep-debug/src/main/java/org/apache/uima/ep_debug/DebugPluginStartup.java
new file mode 100644
index 0000000..c8d09f6
--- /dev/null
+++ b/uimaj-ep-debug/src/main/java/org/apache/uima/ep_debug/DebugPluginStartup.java
@@ -0,0 +1,66 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.ep_debug;

+

+import org.eclipse.jdt.internal.debug.ui.IJDIPreferencesConstants;

+import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;

+import org.eclipse.ui.IStartup;

+

+/**

+ * The class that has the startup code. 

+ * Per Eclipse platform design, it must be in a different class than the main plugin code.

+ */

+public class DebugPluginStartup implements IStartup {

+

+  /** The Constant PREF_ALREADY_SET_PREF_SHOW_DETAILS. */

+  public static final String PREF_ALREADY_SET_PREF_SHOW_DETAILS = "org.apache.uima.ep_debug.already_set_pref_show_details";

+

+  /** The Constant ALREADY_SET_PREF_SHOW_DETAILS. */

+  public static final String ALREADY_SET_PREF_SHOW_DETAILS = "already_set_pref_show_details";

+ 

+  /* (non-Javadoc)

+   * @see org.eclipse.ui.IStartup#earlyStartup()

+   * This method will be called on a different thread after the workbench initializes.

+   */

+  @Override

+  public void earlyStartup() {

+    // Intent of next code

+    // For users installing this plugin for the first time, set the pref-show-details preference,

+    // but only once (per fresh workspace) - to allow it to be set to the value which makes

+    // debugging

+    // display work, initially, but allowing the user to set it to something else without having

+    // this

+    // be overridden every time the pluging starts.

+    String doneOnce = JDIDebugUIPlugin.getDefault().getPreferenceStore().getString(

+            PREF_ALREADY_SET_PREF_SHOW_DETAILS);

+    if (ALREADY_SET_PREF_SHOW_DETAILS.equals(doneOnce))

+      return;

+    JDIDebugUIPlugin.getDefault().getPreferenceStore().setValue(PREF_ALREADY_SET_PREF_SHOW_DETAILS,

+            ALREADY_SET_PREF_SHOW_DETAILS);

+

+    String preference = JDIDebugUIPlugin.getDefault().getPreferenceStore().getString(

+            IJDIPreferencesConstants.PREF_SHOW_DETAILS);

+    if (IJDIPreferencesConstants.INLINE_ALL.equals(preference))

+      return;

+    JDIDebugUIPlugin.getDefault().getPreferenceStore().setValue(

+            IJDIPreferencesConstants.PREF_SHOW_DETAILS, IJDIPreferencesConstants.INLINE_ALL);    

+  }

+

+}

diff --git a/uimaj-ep-jcasgen/pom.xml b/uimaj-ep-jcasgen/pom.xml
index 9b06ddd..937033f 100644
--- a/uimaj-ep-jcasgen/pom.xml
+++ b/uimaj-ep-jcasgen/pom.xml
@@ -44,13 +44,13 @@
        element, and just changing the following two properties -->  
   <scm>
     <connection>
-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-jcasgen
+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-jcasgen
     </connection>
     <developerConnection>
-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-jcasgen
+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-jcasgen
     </developerConnection>
     <url>
-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-jcasgen
+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-jcasgen
     </url>
   </scm>
   
@@ -104,12 +104,6 @@
       <version>2.1.0</version>
       <scope>provided</scope>
     </dependency>
-		<!-- dependency>
-			<groupId>org.eclipse.emf</groupId>
-			<artifactId>org.eclipse.emf.codegen</artifactId>
-			<version>2.10.0-v20150123-0452</version>
-			<scope>provided</scope>
-		</dependency-->
     <dependency>
       <groupId>org.eclipse.emf</groupId>
       <artifactId>common</artifactId>
@@ -201,7 +195,6 @@
       <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
-        <version>2.3.7</version> <!-- using 3.0.1 causes the subsequent update site generation to skip this plugin for unknown reasons -->
         <configuration>
           <instructions>
             <!-- turn off "uses" generation because Eclipse 3.2.x doesn't work with them -->
@@ -224,9 +217,9 @@
                  not needed by maven -->
             <Import-Package>
               !org.eclipse.core.runtime,                 
-              *,  
               org.osgi.framework, 
-              org.eclipse.jdt.core.jdom
+              org.eclipse.jdt.core.jdom,
+              *  
             </Import-Package> 
             <Bundle-SymbolicName>org.apache.uima.jcas.jcasgenp;singleton:=true</Bundle-SymbolicName>
             <Eclipse-AutoStart>true</Eclipse-AutoStart>
diff --git a/uimaj-ep-launcher/pom.xml b/uimaj-ep-launcher/pom.xml
index fbac44a..1695704 100644
--- a/uimaj-ep-launcher/pom.xml
+++ b/uimaj-ep-launcher/pom.xml
@@ -44,13 +44,13 @@
        element, and just changing the following two properties -->  

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-launcher

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-launcher

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-launcher

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-launcher

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-launcher

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-launcher

     </url>

   </scm>

   

@@ -213,7 +213,6 @@
       <plugin>

         <groupId>org.apache.felix</groupId>

         <artifactId>maven-bundle-plugin</artifactId>

-        <version>3.0.1</version>  <!-- override 2.3.7 - getting unresolved refs to some dependencies, fixed by 3.0.1 -->

         <configuration>

           <manifestLocation>META-INF</manifestLocation>

           <instructions>

diff --git a/uimaj-ep-pear-packager/pom.xml b/uimaj-ep-pear-packager/pom.xml
index 65f1fb1..9820c4f 100644
--- a/uimaj-ep-pear-packager/pom.xml
+++ b/uimaj-ep-pear-packager/pom.xml
@@ -44,13 +44,13 @@
        element, and just changing the following two properties -->  

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-pear-packager

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-pear-packager

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-pear-packager

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-pear-packager

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-pear-packager

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-pear-packager

     </url>

   </scm>

   

diff --git a/uimaj-ep-runtime/pom.xml b/uimaj-ep-runtime/pom.xml
index a0ae9c6..8aa73aa 100644
--- a/uimaj-ep-runtime/pom.xml
+++ b/uimaj-ep-runtime/pom.xml
@@ -44,13 +44,13 @@
        element, and just changing the following two properties -->  

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-runtime

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-runtime

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-runtime

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-runtime

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-ep-runtime

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-ep-runtime

     </url>

   </scm>

   

@@ -67,6 +67,21 @@
       <artifactId>uimaj-core</artifactId>

       <version>${project.parent.version}</version>

       <scope>compile</scope>

+      <!-- exclude log4j -->

+      <exclusions>

+        <exclusion>

+          <groupId>org.apache.logging.log4j</groupId>

+          <artifactId>log4j-slf4j-impl</artifactId>

+        </exclusion>

+        <exclusion>

+          <groupId>org.apache.logging.log4j</groupId>

+          <artifactId>log4j-api</artifactId>

+        </exclusion>

+        <exclusion>

+          <groupId>org.apache.logging.log4j</groupId>

+          <artifactId>log4j-core</artifactId>

+        </exclusion>       

+      </exclusions>

     </dependency>

 

     <dependency>

@@ -120,7 +135,6 @@
       <plugin>

         <groupId>org.apache.felix</groupId>

         <artifactId>maven-bundle-plugin</artifactId>

-        <version>3.0.1</version> <!-- 2.3.7 throws array out of bounds looking for runtime class file version (is v 8) -->

         <executions>

           <execution>

             <id>uima-bundle</id>

@@ -222,11 +236,13 @@
                    org.apache.uima.adapter.soap,

                    org.apache.uima.adapter.soap.axis11,

                  -->

-                <Import-Package>org.apache.log4j;resolution:=optional,

+                <Import-Package>org.slf4j*,

                    !com.strobel.assembler,

                    !com.strobel.assembler.metadata,

                    !com.strobel.decompiler,

                    !javax.annotation.meta,

+                   !org.apache.logging.slf4j*,

+                   !org.apache.logging.log4j*,

                    *

                 </Import-Package>

                 <!-- causes the other Jars from the maven

diff --git a/uimaj-examples/pom.xml b/uimaj-examples/pom.xml
index 7c696da..de1c8f1 100644
--- a/uimaj-examples/pom.xml
+++ b/uimaj-examples/pom.xml
@@ -43,13 +43,13 @@
        element, and just changing the following two properties -->

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-examples

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-examples

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-examples

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-examples

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-examples

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-examples

     </url>

   </scm>

   

diff --git a/uimaj-examples/src/main/eclipseProject/classpath b/uimaj-examples/src/main/eclipseProject/classpath
index e4b50a7..6936505 100644
--- a/uimaj-examples/src/main/eclipseProject/classpath
+++ b/uimaj-examples/src/main/eclipseProject/classpath
@@ -24,31 +24,40 @@
 		<attributes>

 		  <!-- Strings file:/C:/Program Files/apache-uima are replaced

 		       by the adjustExamplePaths script with the UIMA install location -->

-			<attribute value="file:/C:/Program Files/apache-uima/docs/api" name="javadoc_location"/>

+			<attribute value="file:/C:/Program Files/apache-uima/docs/d/api" name="javadoc_location"/>

 		</attributes>

 	</classpathentry>		

 	<classpathentry kind="var" path="UIMA_HOME/lib/uima-document-annotation.jar">

 		<attributes>

-			<attribute value="file:/C:/Program Files/apache-uima/docs/api" name="javadoc_location"/>

+			<attribute value="file:/C:/Program Files/apache-uima/docs/d/api" name="javadoc_location"/>

 		</attributes>

 	</classpathentry>		

 	<classpathentry kind="var" path="UIMA_HOME/lib/uima-cpe.jar">

 		<attributes>

-			<attribute value="file:/C:/Program Files/apache-uima/docs/api" name="javadoc_location"/>

+			<attribute value="file:/C:/Program Files/apache-uima/docs/d/api" name="javadoc_location"/>

 		</attributes>

 	</classpathentry>		

 	<classpathentry kind="var" path="UIMA_HOME/lib/uima-tools.jar">

 			<attributes>

-			<attribute value="file:/C:/Program Files/apache-uima/docs/api" name="javadoc_location"/>

+			<attribute value="file:/C:/Program Files/apache-uima/docs/d/api" name="javadoc_location"/>

 		</attributes>

-	</classpathentry>			

+	</classpathentry>	

+  <classpathentry kind="var" path="UIMA_HOME/lib/uimaj-json.jar">

+    <attributes>

+      <attribute value="file:/C:/Program Files/apache-uima/docs/d/api" name="javadoc_location"/>

+    </attributes>

+  </classpathentry>     

+			

 	<classpathentry kind="var" path="UIMA_HOME/lib/uima-adapter-vinci.jar"/>

 	<classpathentry kind="var" path="UIMA_HOME/lib/uima-adapter-soap.jar"/>

 	<classpathentry kind="var" path="UIMA_HOME/lib/jVinci.jar"/>

+	<classpathentry kind="var" path="UIMA_HOME/lib/jackson-core-2.9.2.jar"/>

 	<classpathentry kind="var" path="UIMA_HOME/lib/uimaj-v3migration-jcas.jar"/>

-	<classpathentry kind="var" path="UIMA_HOME/lib/procyon-compilertools-0.5.28.jar"/>

-  <classpathentry kind="var" path="UIMA_HOME/lib/procyon-core-0.5.28.jar"/>

-  <classpathentry kind="var" path="UIMA_HOME/lib/javaparser-core-2.5.1.jar"/>

+	<classpathentry kind="var" path="UIMA_HOME/lib/procyon-compilertools-0.5.32.jar"/>

+  <classpathentry kind="var" path="UIMA_HOME/lib/procyon-core-0.5.32.jar"/>

+  <classpathentry kind="var" path="UIMA_HOME/lib/javaparser-core-3.2.2.jar"/>

+  <classpathentry kind="var" path="UIMA_HOME/lib/slf4j-api-1.7.25.jar"/>

+  <classpathentry kind="var" path="UIMA_HOME/lib/slf4j-jdk14-1.7.25.jar"/>

 	<classpathentry kind="lib" path="resources"/>

 	<classpathentry kind="output" path="bin"/>

 </classpath>

diff --git a/uimaj-examples/src/main/java/example/PersonTitle.java b/uimaj-examples/src/main/java/example/PersonTitle.java
index 9d47295..fe179f3 100644
--- a/uimaj-examples/src/main/java/example/PersonTitle.java
+++ b/uimaj-examples/src/main/java/example/PersonTitle.java
@@ -18,6 +18,9 @@
  */
 package example;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 import org.apache.uima.jcas.tcas.Annotation;
@@ -34,6 +37,12 @@
  */
 public class PersonTitle extends Annotation {
 
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "example.PersonTitle";
+  
     /**
      * The Constant typeIndexID.
      *
@@ -56,21 +65,27 @@
      * @return the type index ID
      * @generated 
      */
-    public int getTypeIndexID() {
-        return typeIndexID;
-    }
+    public int getTypeIndexID() {return typeIndexID;}
+ 
+ 
+  /* *******************
+   *   Feature Offsets *
+   * *******************/ 
+   
+  public final static String _FeatName_Kind = "Kind";
 
-    /** The Constant _FI_Kind. */
-    public static final int _FI_Kind = TypeSystemImpl.getAdjustedFeatureOffset("Kind");
 
-    /**
+  /* Feature Adjusted Offsets */
+  private final static CallSite _FC_Kind = TypeSystemImpl.createCallSite(PersonTitle.class, "Kind");
+  private final static MethodHandle _FH_Kind = _FC_Kind.dynamicInvoker();
+
+  /**
    * Never called. Disable default constructor
    *
    * @generated
    */
-    protected  PersonTitle() {
-    }
-
+    protected  PersonTitle() {/* intentionally empty block */}
+    
     /**
      * Internal - constructor used by generator.
      *
@@ -79,10 +94,10 @@
      * @generated 
      */
     public  PersonTitle(TypeImpl type, CASImpl casImpl) {
-        super(type, casImpl);
-        readObject();
-    }
-
+    super(type, casImpl);
+    readObject();
+  }
+  
     /**
      * Instantiates a new person title.
      *
@@ -90,9 +105,10 @@
      * @generated 
      */
     public  PersonTitle(JCas jcas) {
-        super(jcas);
-        readObject();
-    }
+    super(jcas);
+    readObject();   
+  } 
+
 
     /**
      * Instantiates a new person title.
@@ -108,11 +124,10 @@
         readObject();
     }
 
-    /**
-     * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->.
-     *
-     * @generated modifiable
-     */
+  /** 
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->*
+   * @generated modifiable 
+   */
     private void readObject() {
     }
 
@@ -124,10 +139,8 @@
      * @return the kind
      * @generated 
      */
-    public String getKind() {
-        return _getStringValueNc(_FI_Kind);
-    }
-
+    public String getKind() { return _getStringValueNc(wrapGetIntCatchException(_FH_Kind));}
+    
     /**
      * setter for Kind - sets The kind of title - Civilian, Military, or Government.
      *
@@ -135,6 +148,7 @@
      * @generated 
      */
     public void setKind(String v) {
-        _setStringValueNfc(_FI_Kind, v);
-    }
-}
+    _setStringValueNfc(wrapGetIntCatchException(_FH_Kind), v);
+  }    
+    
+  }
diff --git a/uimaj-examples/src/main/java/org/apache/uima/examples/PrintAnnotations.java b/uimaj-examples/src/main/java/org/apache/uima/examples/PrintAnnotations.java
index 36da794..9d1108c 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/examples/PrintAnnotations.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/examples/PrintAnnotations.java
@@ -36,6 +36,7 @@
 import org.apache.uima.cas.StringArrayFS;
 import org.apache.uima.cas.Type;
 import org.apache.uima.cas.text.AnnotationFS;
+import org.apache.uima.jcas.tcas.Annotation;
 import org.apache.uima.resource.ResourceSpecifier;
 import org.apache.uima.util.FileUtils;
 import org.apache.uima.util.XMLInputSource;
@@ -59,15 +60,26 @@
    *          the PrintStream to which output will be written
    */
   public static void printAnnotations(CAS aCAS, PrintStream aOut) {
-    // get iterator over annotations
-    FSIterator iter = aCAS.getAnnotationIndex().iterator();
+    
+    // Version 3 using select with Stream support
+    aCAS.select(Annotation.class).forEach(fs -> printFS(fs, aCAS, 0, aOut));
 
-    // iterate
-    while (iter.isValid()) {
-      FeatureStructure fs = iter.get();
-      printFS(fs, aCAS, 0, aOut);
-      iter.moveToNext();
-    }
+//    // Version 3 using select with extended for
+//    for (Annotation fs : aCAS.getAnnotationIndex().select(Annotation.class)) {
+//      printFS(fs, aCAS, 0, aOut);
+//    }
+//    
+//    // version 2 style using iterators
+//    FSIterator<AnnotationFS> iter = aCAS.getAnnotationIndex().iterator();
+//
+//    // iterate
+//    while (iter.isValid()) {
+//      FeatureStructure fs = iter.get();
+//      printFS(fs, aCAS, 0, aOut);
+//      iter.moveToNext();
+//    }
+    
+    
   }
 
   /**
diff --git a/uimaj-examples/src/main/java/org/apache/uima/examples/SofaExampleApplication.java b/uimaj-examples/src/main/java/org/apache/uima/examples/SofaExampleApplication.java
index b06a9e4..ac8a213 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/examples/SofaExampleApplication.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/examples/SofaExampleApplication.java
@@ -31,6 +31,7 @@
 import org.apache.uima.cas.Feature;
 import org.apache.uima.cas.Type;
 import org.apache.uima.cas.text.AnnotationFS;
+import org.apache.uima.jcas.tcas.Annotation;
 import org.apache.uima.util.XMLInputSource;
 
 
@@ -71,39 +72,55 @@
     // and puts the translation into a German Sofa
     seAnnotator.process(cas);
 
-    // get annotation iterator for the English CAS view
-    FSIndex anIndex = englishView.getAnnotationIndex();
-    FSIterator anIter = anIndex.iterator();
-
-    // and print out all annotations found
     System.out.println("---Printing all annotations for English Sofa---");
-    while (anIter.isValid()) {
-      AnnotationFS annot = (AnnotationFS) anIter.get();
-      System.out.println(" " + annot.getType().getName() + ": " + annot.getCoveredText());
-      anIter.moveToNext();
-    }
+    englishView.select(Annotation.class).forEach(annot -> 
+          System.out.println(" " + annot.getType().getName() + ": " + annot.getCoveredText()));
+    
+//    // get annotation iterator for the English CAS view
+//    FSIndex anIndex = englishView.getAnnotationIndex();
+//    FSIterator anIter = anIndex.iterator();
+//
+//    // and print out all annotations found
+//    while (anIter.isValid()) {
+//      AnnotationFS annot = (AnnotationFS) anIter.get();
+//      System.out.println(" " + annot.getType().getName() + ": " + annot.getCoveredText());
+//      anIter.moveToNext();
+//    }
 
     // now try to get the CAS view for the German Sofa
     System.out.println();
     CAS germanView = cas.getView("GermanDocument");
-
-    // and annotator iterator for the German CAS View
-    anIndex = germanView.getAnnotationIndex();
-    anIter = anIndex.iterator();
     Type cross = germanView.getTypeSystem().getType("sofa.test.CrossAnnotation");
     Feature other = cross.getFeatureByBaseName("otherAnnotation");
 
-    // print out all annotations for the German Sofa
     System.out.println("---Printing all annotations for German Sofa---");
-    while (anIter.isValid()) {
-      AnnotationFS annot = (AnnotationFS) anIter.get();
+    
+    for (Annotation annot : germanView.select(Annotation.class)) {
       System.out.println(" " + annot.getType().getName() + ": " + annot.getCoveredText());
       if (annot.getType() == cross) {
-        AnnotationFS crossAnnot = (AnnotationFS) annot.getFeatureValue(other);
+        Annotation crossAnnot = (Annotation) annot.getFeatureValue(other);
         System.out.println("   other annotation feature: " + crossAnnot.getCoveredText());
       }
-      anIter.moveToNext();
     }
+    
+    
+//    // and annotator iterator for the German CAS View
+//    anIndex = germanView.getAnnotationIndex();
+//    anIter = anIndex.iterator();
+//    Type cross = germanView.getTypeSystem().getType("sofa.test.CrossAnnotation");
+//    Feature other = cross.getFeatureByBaseName("otherAnnotation");
+//
+//    // print out all annotations for the German Sofa
+//    System.out.println("---Printing all annotations for German Sofa---");
+//    while (anIter.isValid()) {
+//      AnnotationFS annot = (AnnotationFS) anIter.get();
+//      System.out.println(" " + annot.getType().getName() + ": " + annot.getCoveredText());
+//      if (annot.getType() == cross) {
+//        AnnotationFS crossAnnot = (AnnotationFS) annot.getFeatureValue(other);
+//        System.out.println("   other annotation feature: " + crossAnnot.getCoveredText());
+//      }
+//      anIter.moveToNext();
+//    }
 
     // Clean up
     seAnnotator.destroy();
diff --git a/uimaj-examples/src/main/java/org/apache/uima/examples/SourceDocumentInformation.java b/uimaj-examples/src/main/java/org/apache/uima/examples/SourceDocumentInformation.java
index 200a799..c4a4cf4 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/examples/SourceDocumentInformation.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/examples/SourceDocumentInformation.java
@@ -21,6 +21,9 @@
 
 package org.apache.uima.examples;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -31,14 +34,9 @@
 import org.apache.uima.jcas.tcas.Annotation;
 
 
-/** 
- * Stores detailed information about the original source document from which the current CAS was initialized. 
- * All information (like size) refers to the source document and not to the document in the CAS 
- *  which may be converted and filtered by a CAS Initializer. 
- * For example this information will be written to the Semantic Search index so that 
- *  the original document contents can be retrieved by queries.
- * Updated by JCasGen Wed Dec 21 14:40:40 EST 2016
- * XML source: C:/au/svnCheckouts/branches/uimaj/v3-alpha/uimaj-examples/src/main/resources/org/apache/uima/examples/SourceDocumentInformation.xml
+/** Stores detailed information about the original source document from which the current CAS was initialized. All information (like size) refers to the source document and not to the document in the CAS which may be converted and filtered by a CAS Initializer. For example this information will be written to the Semantic Search index so that the original document contents can be retrieved by queries.
+ * Updated by JCasGen Sun Oct 08 19:24:05 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-examples/src/main/resources/org/apache/uima/examples/SourceDocumentInformation.xml
  * @generated */
 public class SourceDocumentInformation extends Annotation {
   /** @generated
@@ -65,7 +63,7 @@
  
  
   /* *******************
-   *   Feature Offsets *
+   *   Feature Names   *
    * *******************/ 
    
   public final static String _FeatName_uri = "uri";
@@ -74,16 +72,15 @@
   public final static String _FeatName_lastSegment = "lastSegment";
 
 
-  /* *******************
-   *   Feature Offsets *
-   * *******************/ 
-   
   /* Feature Adjusted Offsets */
-  public final static int _FI_uri = TypeSystemImpl.getAdjustedFeatureOffset("uri");
-  public final static int _FI_offsetInSource = TypeSystemImpl.getAdjustedFeatureOffset("offsetInSource");
-  public final static int _FI_documentSize = TypeSystemImpl.getAdjustedFeatureOffset("documentSize");
-  public final static int _FI_lastSegment = TypeSystemImpl.getAdjustedFeatureOffset("lastSegment");
-
+  private final static CallSite _FC_uri = TypeSystemImpl.createCallSite(SourceDocumentInformation.class, "uri");
+  private final static MethodHandle _FH_uri = _FC_uri.dynamicInvoker();
+  private final static CallSite _FC_offsetInSource = TypeSystemImpl.createCallSite(SourceDocumentInformation.class, "offsetInSource");
+  private final static MethodHandle _FH_offsetInSource = _FC_offsetInSource.dynamicInvoker();
+  private final static CallSite _FC_documentSize = TypeSystemImpl.createCallSite(SourceDocumentInformation.class, "documentSize");
+  private final static MethodHandle _FH_documentSize = _FC_documentSize.dynamicInvoker();
+  private final static CallSite _FC_lastSegment = TypeSystemImpl.createCallSite(SourceDocumentInformation.class, "lastSegment");
+  private final static MethodHandle _FH_lastSegment = _FC_lastSegment.dynamicInvoker();
    
   /** Never called.  Disable default constructor
    * @generated */
@@ -138,14 +135,14 @@
    * @generated
    * @return value of the feature 
    */
-  public String getUri() { return _getStringValueNc(_FI_uri);}
+  public String getUri() { return _getStringValueNc(wrapGetIntCatchException(_FH_uri));}
     
   /** setter for uri - sets URI of document. (For example, file:///MyDirectory/myFile.txt for a simple file or http://incubator.apache.org/uima/index.html for content from a web source.) 
    * @generated
    * @param v value to set into the feature 
    */
   public void setUri(String v) {
-    _setStringValueNfc(_FI_uri, v);
+    _setStringValueNfc(wrapGetIntCatchException(_FH_uri), v);
   }    
     
    
@@ -157,14 +154,14 @@
    * @generated
    * @return value of the feature 
    */
-  public int getOffsetInSource() { return _getIntValueNc(_FI_offsetInSource);}
+  public int getOffsetInSource() { return _getIntValueNc(wrapGetIntCatchException(_FH_offsetInSource));}
     
   /** setter for offsetInSource - sets Byte offset of the start of document content within original source file or other input source. Only used if the CAS document was retrieved from an source where one physical source file contained several conceptual documents. Zero otherwise. 
    * @generated
    * @param v value to set into the feature 
    */
   public void setOffsetInSource(int v) {
-    _setIntValueNfc(_FI_offsetInSource, v);
+    _setIntValueNfc(wrapGetIntCatchException(_FH_offsetInSource), v);
   }    
     
    
@@ -176,14 +173,14 @@
    * @generated
    * @return value of the feature 
    */
-  public int getDocumentSize() { return _getIntValueNc(_FI_documentSize);}
+  public int getDocumentSize() { return _getIntValueNc(wrapGetIntCatchException(_FH_documentSize));}
     
   /** setter for documentSize - sets Size of original document in bytes before processing by CAS Initializer. Either absolute file size of size within file or other source. 
    * @generated
    * @param v value to set into the feature 
    */
   public void setDocumentSize(int v) {
-    _setIntValueNfc(_FI_documentSize, v);
+    _setIntValueNfc(wrapGetIntCatchException(_FH_documentSize), v);
   }    
     
    
@@ -195,14 +192,14 @@
    * @generated
    * @return value of the feature 
    */
-  public boolean getLastSegment() { return _getBooleanValueNc(_FI_lastSegment);}
+  public boolean getLastSegment() { return _getBooleanValueNc(wrapGetIntCatchException(_FH_lastSegment));}
     
   /** setter for lastSegment - sets For a CAS that represents a segment of a larger source document, this flag indicates whether this CAS is the final segment of the source document.  This is useful for downstream components that want to take some action after having seen all of the segments of a particular source document. 
    * @generated
    * @param v value to set into the feature 
    */
   public void setLastSegment(boolean v) {
-    _setBooleanValueNfc(_FI_lastSegment, v);
+    _setBooleanValueNfc(wrapGetIntCatchException(_FH_lastSegment), v);
   }    
     
   }
diff --git a/uimaj-examples/src/main/java/org/apache/uima/examples/XmlDetagger.java b/uimaj-examples/src/main/java/org/apache/uima/examples/XmlDetagger.java
index 3a9534f..f6212e1 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/examples/XmlDetagger.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/examples/XmlDetagger.java
@@ -20,7 +20,6 @@
 package org.apache.uima.examples;
 
 import java.io.InputStream;
-import java.util.Iterator;
 
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
@@ -32,6 +31,7 @@
 import org.apache.uima.cas.FeatureStructure;
 import org.apache.uima.cas.Type;
 import org.apache.uima.cas.TypeSystem;
+import org.apache.uima.internal.util.XMLUtils;
 import org.apache.uima.resource.ResourceInitializationException;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
@@ -52,8 +52,8 @@
    */
   public static final String PARAM_XMLTAG = "XmlTagContainingText";
   
-  private SAXParserFactory parserFactory = SAXParserFactory.newInstance();
-
+  private SAXParserFactory parserFactory = XMLUtils.createSAXParserFactory();
+ 
   private Type sourceDocInfoType;
 
   private String mXmlTagContainingText = null;
@@ -90,12 +90,15 @@
 
     // Index the SourceDocumentInformation object, if there is one, in the new sofa.
     // This is needed by the SemanticSearchCasIndexer
-    Iterator iter = xmlCas.getAnnotationIndex(sourceDocInfoType).iterator();
-    if (iter.hasNext()) {
-      FeatureStructure sourceDocInfoFs = (FeatureStructure) iter.next();
-      plainTextView.getIndexRepository().addFS(sourceDocInfoFs);
-
+    FeatureStructure sourceDocInfoFs = xmlCas.select(sourceDocInfoType).singleOrNull();
+    if (null != sourceDocInfoFs) {
+      plainTextView.addFsToIndexes(sourceDocInfoFs);
     }
+//    Iterator iter = xmlCas.getAnnotationIndex(sourceDocInfoType).iterator();
+//    if (iter.hasNext()) {
+//      FeatureStructure sourceDocInfoFs = (FeatureStructure) iter.next();
+//      plainTextView.getIndexRepository().addFS(sourceDocInfoFs);
+//    }
 
   }
 
diff --git a/uimaj-examples/src/main/java/org/apache/uima/examples/cas/PersonTitleAnnotator.java b/uimaj-examples/src/main/java/org/apache/uima/examples/cas/PersonTitleAnnotator.java
index e271eef..b489bd9 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/examples/cas/PersonTitleAnnotator.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/examples/cas/PersonTitleAnnotator.java
@@ -26,11 +26,11 @@
 import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
 import org.apache.uima.analysis_engine.annotator.AnnotatorInitializationException;
 import org.apache.uima.cas.CAS;
-import org.apache.uima.cas.FSIterator;
 import org.apache.uima.cas.Feature;
 import org.apache.uima.cas.Type;
 import org.apache.uima.cas.TypeSystem;
 import org.apache.uima.cas.text.AnnotationFS;
+import org.apache.uima.jcas.tcas.Annotation;
 import org.apache.uima.resource.ResourceInitializationException;
 import org.apache.uima.util.Level;
 import org.apache.uima.util.Logger;
@@ -102,7 +102,7 @@
     mGovernmentTitles = (String[]) getContext().getConfigParameterValue("GovernmentTitles");
 
     // write log messages
-    logger = getContext().getLogger();
+    logger = getLogger();
     logger.log(Level.CONFIG, "PersonTitleAnnotator initialized");
     logger.log(Level.CONFIG, "CivilianTitles = " + Arrays.asList(mCivilianTitles));
     logger.log(Level.CONFIG, "MilitaryTitles = " + Arrays.asList(mMilitaryTitles));
@@ -175,21 +175,32 @@
       } else {
         // Search only within annotations of type mContainingType
 
-        // Get an iterator over the annotations of type mContainingType.
-        FSIterator it = aCAS.getAnnotationIndex(mContainingType).iterator();
-        // Loop over the iterator.
-        while (it.isValid()) {
-          // Get the next annotation from the iterator
-          AnnotationFS annot = (AnnotationFS) it.get();
-          // Get text covered by this annotation
-          String coveredText = annot.getCoveredText();
-          // Get begin position of this annotation
-          int annotBegin = annot.getBegin();
-          // search for matches within this
-          annotateRange(aCAS, coveredText, annotBegin);
-          // Advance the iterator.
-          it.moveToNext();
+        //v3
+        
+        for (Annotation annot : aCAS.<Annotation>select(mContainingType)) {
+          
+          String coveredText = annot.getCoveredText();  // Get text covered by this annotation
+          int annotBegin = annot.getBegin();            // Get begin position of this annotation
+          annotateRange(aCAS, coveredText, annotBegin); // search for matches within this
+        
         }
+        
+        // v2
+//        // Get an iterator over the annotations of type mContainingType.
+//        FSIterator it = aCAS.getAnnotationIndex(mContainingType).iterator();
+//        // Loop over the iterator.
+//        while (it.isValid()) {
+//          // Get the next annotation from the iterator
+//          AnnotationFS annot = (AnnotationFS) it.get();
+//          // Get text covered by this annotation
+//          String coveredText = annot.getCoveredText();
+//          // Get begin position of this annotation
+//          int annotBegin = annot.getBegin();
+//          // search for matches within this
+//          annotateRange(aCAS, coveredText, annotBegin);
+//          // Advance the iterator.
+//          it.moveToNext();
+//        }
       }
     } catch (Exception e) {
       throw new AnalysisEngineProcessException(e);
@@ -232,6 +243,7 @@
   protected void annotateRange(CAS aCAS, String aText, int aBeginPos, String aTitleType,
           String[] aTitles) {
     // Loop over the matchStrings.
+    
     for (int i = 0; i < aTitles.length; i++) {
       // logger.log("Looking for string: " + matchStrings[i]);
       // Find a first match, if it exists.
@@ -244,7 +256,7 @@
         int absStart = aBeginPos + start;
         int absEnd = aBeginPos + end;
         // Write log message
-        getContext().getLogger().log(Level.FINER,
+        logger.log(Level.FINER,
                 "Found \"" + aTitles[i] + "\" at (" + absStart + "," + absEnd + ")");
         // Create a new annotation for the most recently discovered match.
         createAnnotation(aCAS, absStart, absEnd, aTitleType);
diff --git a/uimaj-examples/src/main/java/org/apache/uima/examples/casMultiplier/CasMultiplierExampleApplication.java b/uimaj-examples/src/main/java/org/apache/uima/examples/casMultiplier/CasMultiplierExampleApplication.java
index 14cc9b2..7f66ac7 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/examples/casMultiplier/CasMultiplierExampleApplication.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/examples/casMultiplier/CasMultiplierExampleApplication.java
@@ -74,6 +74,7 @@
 
       // pass the CAS to the AnalysisEngine and get back
       // a CasIterator for stepping over the output CASes that are produced.
+      
       CasIterator casIterator = ae.processAndOutputNewCASes(initialCas);
       while (casIterator.hasNext()) {
         CAS outCas = casIterator.next();
diff --git a/uimaj-examples/src/main/java/org/apache/uima/examples/flow/WhiteboardFlowController2.java b/uimaj-examples/src/main/java/org/apache/uima/examples/flow/WhiteboardFlowController2.java
index c44301f..df79ac4 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/examples/flow/WhiteboardFlowController2.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/examples/flow/WhiteboardFlowController2.java
@@ -182,8 +182,8 @@
      */
     private boolean casContainsTypes(CAS aCAS, Type[] aTypes) {
       for (int i = 0; i < aTypes.length; i++) {
-        Iterator iter = aCAS.getIndexRepository().getAllIndexedFS(aTypes[i]);
-        if (!iter.hasNext())
+        Collection c = aCAS.getIndexRepository().getIndexedFSs(aTypes[i]);
+        if (c.isEmpty())
           return false;
       }
       return true;
diff --git a/uimaj-examples/src/main/java/org/apache/uima/examples/tokenizer/Sentence.java b/uimaj-examples/src/main/java/org/apache/uima/examples/tokenizer/Sentence.java
index e31f24a..bd5efa3 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/examples/tokenizer/Sentence.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/examples/tokenizer/Sentence.java
@@ -18,6 +18,9 @@
  */
 package org.apache.uima.examples.tokenizer;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 import org.apache.uima.jcas.tcas.Annotation;
@@ -31,6 +34,12 @@
  */
 public class Sentence extends Annotation {
 
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "org.apache.uima.examples.tokenizer.Sentence";
+  
     /** The Constant typeIndexID. */
     public static final int typeIndexID = JCasRegistry.register(Sentence.class);
 
@@ -80,4 +89,13 @@
     public  Sentence(JCas jcas, int start, int end) {
         super(jcas, start, end);
     }
+  /** 
+   * <!-- begin-user-doc -->
+   * Write your own initialization here
+   * <!-- end-user-doc -->
+   *
+   * @generated modifiable 
+   */
+  private void readObject() {/*default - does nothing empty block */}
+     
 }
diff --git a/uimaj-examples/src/main/java/org/apache/uima/examples/tokenizer/Token.java b/uimaj-examples/src/main/java/org/apache/uima/examples/tokenizer/Token.java
index e10624d..4a44305 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/examples/tokenizer/Token.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/examples/tokenizer/Token.java
@@ -18,6 +18,9 @@
  */
 package org.apache.uima.examples.tokenizer;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 import org.apache.uima.jcas.tcas.Annotation;
@@ -31,6 +34,12 @@
  */
 public class Token extends Annotation {
 
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "org.apache.uima.examples.tokenizer.Token";
+  
     /** The Constant typeIndexID. */
     public static final int typeIndexID = JCasRegistry.register(Token.class);
 
@@ -80,4 +89,13 @@
     public  Token(JCas jcas, int start, int end) {
         super(jcas, start, end);
     }
+  /** 
+   * <!-- begin-user-doc -->
+   * Write your own initialization here
+   * <!-- end-user-doc -->
+   *
+   * @generated modifiable 
+   */
+  private void readObject() {/*default - does nothing empty block */}
+     
 }
diff --git a/uimaj-examples/src/main/java/org/apache/uima/tutorial/DateAnnot.java b/uimaj-examples/src/main/java/org/apache/uima/tutorial/DateAnnot.java
index c0d715f..0aae589 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/tutorial/DateAnnot.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/tutorial/DateAnnot.java
@@ -18,6 +18,9 @@
  */
 package org.apache.uima.tutorial;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 import org.apache.uima.cas.impl.CASImpl;
@@ -25,14 +28,18 @@
 import org.apache.uima.cas.impl.TypeSystemImpl;
 
 
-/**
- * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004 XML source: C:/Program
- * Files/apache/uima/examples/descriptors/tutorial/ex6/TutorialTypeSystem.xml
- *
- * @generated
- */
+/** 
+ * Updated by JCasGen Sun Oct 08 19:34:17 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-examples/src/main/descriptors/tutorial/ex6/TutorialTypeSystem.xml
+ * @generated */
 public class DateAnnot extends DateTimeAnnot {
 
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "org.apache.uima.tutorial.DateAnnot";
+  
     /**
      * The Constant typeIndexID.
      *
@@ -55,18 +62,16 @@
      * @return the type index ID
      * @generated 
      */
-    public int getTypeIndexID() {
-        return typeIndexID;
-    }
-
+    public int getTypeIndexID() {return typeIndexID;}
+ 
+ 
     /**
    * Never called. Disable default constructor
    *
    * @generated
    */
-    protected  DateAnnot() {
-    }
-
+    protected  DateAnnot() {/* intentionally empty block */}
+    
     /**
      * Internal - constructor used by generator.
      *
@@ -75,10 +80,10 @@
      * @generated 
      */
     public  DateAnnot(TypeImpl type, CASImpl casImpl) {
-        super(type, casImpl);
-        readObject();
-    }
-
+    super(type, casImpl);
+    readObject();
+  }
+  
     /**
      * Instantiates a new date annot.
      *
@@ -86,9 +91,10 @@
      * @generated 
      */
     public  DateAnnot(JCas jcas) {
-        super(jcas);
-        readObject();
-    }
+    super(jcas);
+    readObject();   
+  } 
+
 
     /**
      * Instantiates a new date annot.
@@ -104,11 +110,10 @@
         readObject();
     }
 
-    /**
-     * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->.
-     *
-     * @generated modifiable
-     */
+  /** 
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->*
+   * @generated modifiable 
+   */
     private void readObject() {
     }
 }
diff --git a/uimaj-examples/src/main/java/org/apache/uima/tutorial/DateTimeAnnot.java b/uimaj-examples/src/main/java/org/apache/uima/tutorial/DateTimeAnnot.java
index 743eb42..fd3f656 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/tutorial/DateTimeAnnot.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/tutorial/DateTimeAnnot.java
@@ -18,6 +18,9 @@
  */
 package org.apache.uima.tutorial;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 import org.apache.uima.jcas.tcas.Annotation;
@@ -26,14 +29,18 @@
 import org.apache.uima.cas.impl.TypeSystemImpl;
 
 
-/**
- * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004 XML source: C:/Program
- * Files/apache/uima/examples/descriptors/tutorial/ex6/TutorialTypeSystem.xml
- *
- * @generated
- */
+/** 
+ * Updated by JCasGen Sun Oct 08 19:34:17 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-examples/src/main/descriptors/tutorial/ex6/TutorialTypeSystem.xml
+ * @generated */
 public class DateTimeAnnot extends Annotation {
 
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "org.apache.uima.tutorial.DateTimeAnnot";
+  
     /**
      * The Constant typeIndexID.
      *
@@ -56,21 +63,28 @@
      * @return the type index ID
      * @generated 
      */
-    public int getTypeIndexID() {
-        return typeIndexID;
-    }
+    public int getTypeIndexID() {return typeIndexID;}
+ 
+ 
+  /* *******************
+   *   Feature Offsets *
+   * *******************/ 
+   
+  public final static String _FeatName_shortDateString = "shortDateString";
 
-    /** The Constant _FI_shortDateString. */
-    public static final int _FI_shortDateString = TypeSystemImpl.getAdjustedFeatureOffset("shortDateString");
 
-    /**
+  /* Feature Adjusted Offsets */
+  private final static CallSite _FC_shortDateString = TypeSystemImpl.createCallSite(DateTimeAnnot.class, "shortDateString");
+  private final static MethodHandle _FH_shortDateString = _FC_shortDateString.dynamicInvoker();
+
+   
+  /**
    * Never called. Disable default constructor
    *
    * @generated
    */
-    protected  DateTimeAnnot() {
-    }
-
+    protected  DateTimeAnnot() {/* intentionally empty block */}
+    
     /**
      * Internal - constructor used by generator.
      *
@@ -79,10 +93,10 @@
      * @generated 
      */
     public  DateTimeAnnot(TypeImpl type, CASImpl casImpl) {
-        super(type, casImpl);
-        readObject();
-    }
-
+    super(type, casImpl);
+    readObject();
+  }
+  
     /**
      * Instantiates a new date time annot.
      *
@@ -90,9 +104,10 @@
      * @generated 
      */
     public  DateTimeAnnot(JCas jcas) {
-        super(jcas);
-        readObject();
-    }
+    super(jcas);
+    readObject();   
+  } 
+
 
     /**
      * Instantiates a new date time annot.
@@ -108,11 +123,10 @@
         readObject();
     }
 
-    /**
-     * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->.
-     *
-     * @generated modifiable
-     */
+  /** 
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->*
+   * @generated modifiable 
+   */
     private void readObject() {
     }
 
@@ -124,10 +138,8 @@
      * @return the short date string
      * @generated 
      */
-    public String getShortDateString() {
-        return _getStringValueNc(_FI_shortDateString);
-    }
-
+    public String getShortDateString() { return _getStringValueNc(wrapGetIntCatchException(_FH_shortDateString));}
+    
     /**
      * setter for shortDateString - sets.
      *
@@ -135,6 +147,7 @@
      * @generated 
      */
     public void setShortDateString(String v) {
-        _setStringValueNfc(_FI_shortDateString, v);
-    }
-}
+    _setStringValueNfc(wrapGetIntCatchException(_FH_shortDateString), v);
+  }    
+    
+  }
diff --git a/uimaj-examples/src/main/java/org/apache/uima/tutorial/Meeting.java b/uimaj-examples/src/main/java/org/apache/uima/tutorial/Meeting.java
index a9835b1..f6a0ea6 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/tutorial/Meeting.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/tutorial/Meeting.java
@@ -18,6 +18,9 @@
  */
 package org.apache.uima.tutorial;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 import org.apache.uima.jcas.tcas.Annotation;
@@ -26,14 +29,18 @@
 import org.apache.uima.cas.impl.TypeSystemImpl;
 
 
-/**
- * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004 XML source: C:/Program
- * Files/apache/uima/examples/descriptors/tutorial/ex6/TutorialTypeSystem.xml
- *
- * @generated
- */
+/** 
+ * Updated by JCasGen Sun Oct 08 19:34:17 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-examples/src/main/descriptors/tutorial/ex6/TutorialTypeSystem.xml
+ * @generated */
 public class Meeting extends Annotation {
 
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "org.apache.uima.tutorial.Meeting";
+  
     /**
      * The Constant typeIndexID.
      *
@@ -56,30 +63,38 @@
      * @return the type index ID
      * @generated 
      */
-    public int getTypeIndexID() {
-        return typeIndexID;
-    }
+    public int getTypeIndexID() {return typeIndexID;}
+ 
+ 
+  /* *******************
+   *   Feature Offsets *
+   * *******************/ 
+   
+  public final static String _FeatName_room = "room";
+  public final static String _FeatName_date = "date";
+  public final static String _FeatName_startTime = "startTime";
+  public final static String _FeatName_endTime = "endTime";
 
-    /** The Constant _FI_room. */
-    public static final int _FI_room = TypeSystemImpl.getAdjustedFeatureOffset("room");
 
-    /** The Constant _FI_date. */
-    public static final int _FI_date = TypeSystemImpl.getAdjustedFeatureOffset("date");
+  /* Feature Adjusted Offsets */
+  private final static CallSite _FC_room = TypeSystemImpl.createCallSite(Meeting.class, "room");
+  private final static MethodHandle _FH_room = _FC_room.dynamicInvoker();
+  private final static CallSite _FC_date = TypeSystemImpl.createCallSite(Meeting.class, "date");
+  private final static MethodHandle _FH_date = _FC_date.dynamicInvoker();
+  private final static CallSite _FC_startTime = TypeSystemImpl.createCallSite(Meeting.class, "startTime");
+  private final static MethodHandle _FH_startTime = _FC_startTime.dynamicInvoker();
+  private final static CallSite _FC_endTime = TypeSystemImpl.createCallSite(Meeting.class, "endTime");
+  private final static MethodHandle _FH_endTime = _FC_endTime.dynamicInvoker();
 
-    /** The Constant _FI_startTime. */
-    public static final int _FI_startTime = TypeSystemImpl.getAdjustedFeatureOffset("startTime");
-
-    /** The Constant _FI_endTime. */
-    public static final int _FI_endTime = TypeSystemImpl.getAdjustedFeatureOffset("endTime");
+   
 
     /**
    * Never called. Disable default constructor
    *
    * @generated
    */
-    protected  Meeting() {
-    }
-
+    protected  Meeting() {/* intentionally empty block */}
+    
     /**
      * Internal - constructor used by generator.
      *
@@ -88,10 +103,10 @@
      * @generated 
      */
     public  Meeting(TypeImpl type, CASImpl casImpl) {
-        super(type, casImpl);
-        readObject();
-    }
-
+    super(type, casImpl);
+    readObject();
+  }
+  
     /**
      * Instantiates a new meeting.
      *
@@ -99,9 +114,10 @@
      * @generated 
      */
     public  Meeting(JCas jcas) {
-        super(jcas);
-        readObject();
-    }
+    super(jcas);
+    readObject();   
+  } 
+
 
     /**
      * Instantiates a new meeting.
@@ -117,11 +133,10 @@
         readObject();
     }
 
-    /**
-     * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->.
-     *
-     * @generated modifiable
-     */
+  /** 
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->*
+   * @generated modifiable 
+   */
     private void readObject() {
     }
 
@@ -133,10 +148,8 @@
      * @return the room
      * @generated 
      */
-    public RoomNumber getRoom() {
-        return (RoomNumber) (_getFeatureValueNc(_FI_room));
-    }
-
+    public RoomNumber getRoom() { return (RoomNumber)(_getFeatureValueNc(wrapGetIntCatchException(_FH_room)));}
+    
     /**
      * setter for room - sets.
      *
@@ -144,9 +157,11 @@
      * @generated 
      */
     public void setRoom(RoomNumber v) {
-        _setFeatureValueNcWj(_FI_room, v);
-    }
-
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_room), v);
+  }    
+    
+   
+    
     // *--------------*
     // * Feature: date
     /**
@@ -155,10 +170,8 @@
      * @return the date
      * @generated 
      */
-    public DateAnnot getDate() {
-        return (DateAnnot) (_getFeatureValueNc(_FI_date));
-    }
-
+    public DateAnnot getDate() { return (DateAnnot)(_getFeatureValueNc(wrapGetIntCatchException(_FH_date)));}
+    
     /**
      * setter for date - sets.
      *
@@ -166,9 +179,11 @@
      * @generated 
      */
     public void setDate(DateAnnot v) {
-        _setFeatureValueNcWj(_FI_date, v);
-    }
-
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_date), v);
+  }    
+    
+   
+    
     // *--------------*
     // * Feature: startTime
     /**
@@ -177,10 +192,8 @@
      * @return the start time
      * @generated 
      */
-    public TimeAnnot getStartTime() {
-        return (TimeAnnot) (_getFeatureValueNc(_FI_startTime));
-    }
-
+    public TimeAnnot getStartTime() { return (TimeAnnot)(_getFeatureValueNc(wrapGetIntCatchException(_FH_startTime)));}
+    
     /**
      * setter for startTime - sets.
      *
@@ -188,9 +201,11 @@
      * @generated 
      */
     public void setStartTime(TimeAnnot v) {
-        _setFeatureValueNcWj(_FI_startTime, v);
-    }
-
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_startTime), v);
+  }    
+    
+   
+    
     // *--------------*
     // * Feature: endTime
     /**
@@ -199,10 +214,8 @@
      * @return the end time
      * @generated 
      */
-    public TimeAnnot getEndTime() {
-        return (TimeAnnot) (_getFeatureValueNc(_FI_endTime));
-    }
-
+    public TimeAnnot getEndTime() { return (TimeAnnot)(_getFeatureValueNc(wrapGetIntCatchException(_FH_endTime)));}
+    
     /**
      * setter for endTime - sets.
      *
@@ -210,10 +223,10 @@
      * @generated 
      */
     public void setEndTime(TimeAnnot v) {
-        _setFeatureValueNcWj(_FI_endTime, v);
-    }
-
-    /**
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_endTime), v);
+  }    
+    
+        /**
      *  Custom constructor taking all parameters.
      *
      * @param jcas the jcas
diff --git a/uimaj-examples/src/main/java/org/apache/uima/tutorial/RoomNumber.java b/uimaj-examples/src/main/java/org/apache/uima/tutorial/RoomNumber.java
index f9f087c..2d60cce 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/tutorial/RoomNumber.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/tutorial/RoomNumber.java
@@ -18,6 +18,9 @@
  */
 package org.apache.uima.tutorial;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 import org.apache.uima.jcas.tcas.Annotation;
@@ -26,14 +29,18 @@
 import org.apache.uima.cas.impl.TypeSystemImpl;
 
 
-/**
- * Updated by JCasGen Mon Nov 29 15:02:37 EST 2004 XML source: C:/Program
- * Files/apache/uima/examples/descriptors/tutorial/ex6/TutorialTypeSystem.xml
- *
- * @generated
- */
+/** 
+ * Updated by JCasGen Sun Oct 08 19:34:17 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-examples/src/main/descriptors/tutorial/ex6/TutorialTypeSystem.xml
+ * @generated */
 public class RoomNumber extends Annotation {
 
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "org.apache.uima.tutorial.RoomNumber";
+  
     /**
      * The Constant typeIndexID.
      *
@@ -56,21 +63,27 @@
      * @return the type index ID
      * @generated 
      */
-    public int getTypeIndexID() {
-        return typeIndexID;
-    }
+    public int getTypeIndexID() {return typeIndexID;}
+ 
+ 
+  /* *******************
+   *   Feature Offsets *
+   * *******************/ 
+   
+  public final static String _FeatName_building = "building";
 
-    /** The Constant _FI_building. */
-    public static final int _FI_building = TypeSystemImpl.getAdjustedFeatureOffset("building");
+
+  /* Feature Adjusted Offsets */
+  private final static CallSite _FC_building = TypeSystemImpl.createCallSite(RoomNumber.class, "building");
+  private final static MethodHandle _FH_building = _FC_building.dynamicInvoker();
 
     /**
    * Never called. Disable default constructor
    *
    * @generated
    */
-    protected  RoomNumber() {
-    }
-
+    protected  RoomNumber() {/* intentionally empty block */}
+    
     /**
      * Internal - constructor used by generator.
      *
@@ -79,10 +92,10 @@
      * @generated 
      */
     public  RoomNumber(TypeImpl type, CASImpl casImpl) {
-        super(type, casImpl);
-        readObject();
-    }
-
+    super(type, casImpl);
+    readObject();
+  }
+  
     /**
      * Instantiates a new room number.
      *
@@ -90,9 +103,10 @@
      * @generated 
      */
     public  RoomNumber(JCas jcas) {
-        super(jcas);
-        readObject();
-    }
+    super(jcas);
+    readObject();   
+  } 
+
 
     /**
      * Instantiates a new room number.
@@ -108,11 +122,10 @@
         readObject();
     }
 
-    /**
-     * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->.
-     *
-     * @generated modifiable
-     */
+  /** 
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->*
+   * @generated modifiable 
+   */
     private void readObject() {
     }
 
@@ -124,10 +137,8 @@
      * @return the building
      * @generated 
      */
-    public String getBuilding() {
-        return _getStringValueNc(_FI_building);
-    }
-
+    public String getBuilding() { return _getStringValueNc(wrapGetIntCatchException(_FH_building));}
+    
     /**
      * setter for building - sets Building containing this room.
      *
@@ -135,6 +146,7 @@
      * @generated 
      */
     public void setBuilding(String v) {
-        _setStringValueNfc(_FI_building, v);
-    }
-}
+    _setStringValueNfc(wrapGetIntCatchException(_FH_building), v);
+  }    
+    
+  }
diff --git a/uimaj-examples/src/main/java/org/apache/uima/tutorial/TimeAnnot.java b/uimaj-examples/src/main/java/org/apache/uima/tutorial/TimeAnnot.java
index 87c4b6b..3df20ea 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/tutorial/TimeAnnot.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/tutorial/TimeAnnot.java
@@ -18,6 +18,9 @@
  */
 package org.apache.uima.tutorial;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 import org.apache.uima.cas.impl.CASImpl;
@@ -25,14 +28,18 @@
 import org.apache.uima.cas.impl.TypeSystemImpl;
 
 
-/**
- * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004 XML source: C:/Program
- * Files/apache/uima/examples/descriptors/tutorial/ex6/TutorialTypeSystem.xml
- *
- * @generated
- */
+/** 
+ * Updated by JCasGen Sun Oct 08 19:34:17 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-examples/src/main/descriptors/tutorial/ex6/TutorialTypeSystem.xml
+ * @generated */
 public class TimeAnnot extends DateTimeAnnot {
 
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "org.apache.uima.tutorial.TimeAnnot";
+  
     /**
      * The Constant typeIndexID.
      *
@@ -55,18 +62,16 @@
      * @return the type index ID
      * @generated 
      */
-    public int getTypeIndexID() {
-        return typeIndexID;
-    }
-
+    public int getTypeIndexID() {return typeIndexID;}
+ 
+ 
     /**
    * Never called. Disable default constructor
    *
    * @generated
    */
-    protected  TimeAnnot() {
-    }
-
+    protected  TimeAnnot() {/* intentionally empty block */}
+    
     /**
      * Internal - constructor used by generator.
      *
@@ -75,10 +80,10 @@
      * @generated 
      */
     public  TimeAnnot(TypeImpl type, CASImpl casImpl) {
-        super(type, casImpl);
-        readObject();
-    }
-
+    super(type, casImpl);
+    readObject();
+  }
+  
     /**
      * Instantiates a new time annot.
      *
@@ -86,9 +91,10 @@
      * @generated 
      */
     public  TimeAnnot(JCas jcas) {
-        super(jcas);
-        readObject();
-    }
+    super(jcas);
+    readObject();   
+  } 
+
 
     /**
      * Instantiates a new time annot.
@@ -104,11 +110,10 @@
         readObject();
     }
 
-    /**
-     * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->.
-     *
-     * @generated modifiable
-     */
+  /** 
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->*
+   * @generated modifiable 
+   */
     private void readObject() {
     }
 }
diff --git a/uimaj-examples/src/main/java/org/apache/uima/tutorial/UimaAcronym.java b/uimaj-examples/src/main/java/org/apache/uima/tutorial/UimaAcronym.java
index 9f9592b..40874bb 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/tutorial/UimaAcronym.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/tutorial/UimaAcronym.java
@@ -18,6 +18,9 @@
  */
 package org.apache.uima.tutorial;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 import org.apache.uima.jcas.tcas.Annotation;
@@ -26,14 +29,18 @@
 import org.apache.uima.cas.impl.TypeSystemImpl;
 
 
-/**
- * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004 XML source: C:/Program
- * Files/apache/uima/examples/descriptors/tutorial/ex6/TutorialTypeSystem.xml
- *
- * @generated
- */
+/** 
+ * Updated by JCasGen Sun Oct 08 19:34:17 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-examples/src/main/descriptors/tutorial/ex6/TutorialTypeSystem.xml
+ * @generated */
 public class UimaAcronym extends Annotation {
 
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "org.apache.uima.tutorial.UimaAcronym";
+  
     /**
      * The Constant typeIndexID.
      *
@@ -56,21 +63,28 @@
      * @return the type index ID
      * @generated 
      */
-    public int getTypeIndexID() {
-        return typeIndexID;
-    }
+    public int getTypeIndexID() {return typeIndexID;}
+ 
+ 
+  /* *******************
+   *   Feature Offsets *
+   * *******************/ 
+   
+  public final static String _FeatName_expandedForm = "expandedForm";
 
-    /** The Constant _FI_expandedForm. */
-    public static final int _FI_expandedForm = TypeSystemImpl.getAdjustedFeatureOffset("expandedForm");
 
-    /**
+  /* Feature Adjusted Offsets */
+  private final static CallSite _FC_expandedForm = TypeSystemImpl.createCallSite(UimaAcronym.class, "expandedForm");
+  private final static MethodHandle _FH_expandedForm = _FC_expandedForm.dynamicInvoker();
+
+   
+  /**
    * Never called. Disable default constructor
    *
    * @generated
    */
-    protected  UimaAcronym() {
-    }
-
+    protected  UimaAcronym() {/* intentionally empty block */}
+    
     /**
      * Internal - constructor used by generator.
      *
@@ -79,10 +93,10 @@
      * @generated 
      */
     public  UimaAcronym(TypeImpl type, CASImpl casImpl) {
-        super(type, casImpl);
-        readObject();
-    }
-
+    super(type, casImpl);
+    readObject();
+  }
+  
     /**
      * Instantiates a new uima acronym.
      *
@@ -90,9 +104,10 @@
      * @generated 
      */
     public  UimaAcronym(JCas jcas) {
-        super(jcas);
-        readObject();
-    }
+    super(jcas);
+    readObject();   
+  } 
+
 
     /**
      * Instantiates a new uima acronym.
@@ -108,11 +123,10 @@
         readObject();
     }
 
-    /**
-     * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->.
-     *
-     * @generated modifiable
-     */
+  /** 
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->*
+   * @generated modifiable 
+   */
     private void readObject() {
     }
 
@@ -124,10 +138,8 @@
      * @return the expanded form
      * @generated 
      */
-    public String getExpandedForm() {
-        return _getStringValueNc(_FI_expandedForm);
-    }
-
+    public String getExpandedForm() { return _getStringValueNc(wrapGetIntCatchException(_FH_expandedForm));}
+    
     /**
      * setter for expandedForm - sets.
      *
@@ -135,10 +147,10 @@
      * @generated 
      */
     public void setExpandedForm(String v) {
-        _setStringValueNfc(_FI_expandedForm, v);
-    }
-
-    /**
+    _setStringValueNfc(wrapGetIntCatchException(_FH_expandedForm), v);
+  }    
+    
+        /**
      *  Custom constructor taking all parameters.
      *
      * @param jcas the jcas
diff --git a/uimaj-examples/src/main/java/org/apache/uima/tutorial/UimaMeeting.java b/uimaj-examples/src/main/java/org/apache/uima/tutorial/UimaMeeting.java
index 4459960..860b5ce 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/tutorial/UimaMeeting.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/tutorial/UimaMeeting.java
@@ -18,6 +18,9 @@
  */
 package org.apache.uima.tutorial;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 import org.apache.uima.cas.impl.CASImpl;
@@ -25,14 +28,18 @@
 import org.apache.uima.cas.impl.TypeSystemImpl;
 
 
-/**
- * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004 XML source: C:/Program
- * Files/apache/uima/examples/descriptors/tutorial/ex6/TutorialTypeSystem.xml
- *
- * @generated
- */
+/** 
+ * Updated by JCasGen Sun Oct 08 19:34:17 EDT 2017
+ * XML source: C:/au/svnCheckouts/uv3/trunk/uimaj-v3/uimaj-examples/src/main/descriptors/tutorial/ex6/TutorialTypeSystem.xml
+ * @generated */
 public class UimaMeeting extends Meeting {
 
+  /** @generated
+   * @ordered 
+   */
+  @SuppressWarnings ("hiding")
+  public final static String _TypeName = "org.apache.uima.tutorial.UimaMeeting";
+  
     /**
      * The Constant typeIndexID.
      *
@@ -55,18 +62,16 @@
      * @return the type index ID
      * @generated 
      */
-    public int getTypeIndexID() {
-        return typeIndexID;
-    }
-
+    public int getTypeIndexID() {return typeIndexID;}
+ 
+ 
     /**
    * Never called. Disable default constructor
    *
    * @generated
    */
-    protected  UimaMeeting() {
-    }
-
+    protected  UimaMeeting() {/* intentionally empty block */}
+    
     /**
      * Internal - constructor used by generator.
      *
@@ -75,10 +80,10 @@
      * @generated 
      */
     public  UimaMeeting(TypeImpl type, CASImpl casImpl) {
-        super(type, casImpl);
-        readObject();
-    }
-
+    super(type, casImpl);
+    readObject();
+  }
+  
     /**
      * Instantiates a new uima meeting.
      *
@@ -86,9 +91,10 @@
      * @generated 
      */
     public  UimaMeeting(JCas jcas) {
-        super(jcas);
-        readObject();
-    }
+    super(jcas);
+    readObject();   
+  } 
+
 
     /**
      * Instantiates a new uima meeting.
@@ -104,11 +110,10 @@
         readObject();
     }
 
-    /**
-     * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->.
-     *
-     * @generated modifiable
-     */
+  /** 
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->*
+   * @generated modifiable 
+   */
     private void readObject() {
     }
 
diff --git a/uimaj-examples/src/main/java/org/apache/uima/tutorial/ex1/RoomNumberAnnotator.java b/uimaj-examples/src/main/java/org/apache/uima/tutorial/ex1/RoomNumberAnnotator.java
index f4e097b..cd6a9e8 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/tutorial/ex1/RoomNumberAnnotator.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/tutorial/ex1/RoomNumberAnnotator.java
@@ -41,22 +41,18 @@
     // get document text
     String docText = aJCas.getDocumentText();
     // search for Yorktown room numbers
-    Matcher matcher = mYorktownPattern.matcher(docText);
-    while (matcher.find()) {
+    Matcher m = mYorktownPattern.matcher(docText);
+    while (m.find()) {
       // found one - create annotation
-      RoomNumber annotation = new RoomNumber(aJCas);
-      annotation.setBegin(matcher.start());
-      annotation.setEnd(matcher.end());
+      RoomNumber annotation = new RoomNumber(aJCas, m.start(), m.end());
       annotation.setBuilding("Yorktown");
       annotation.addToIndexes();
     }
     // search for Hawthorne room numbers
-    matcher = mHawthornePattern.matcher(docText);
-    while (matcher.find()) {
+    m = mHawthornePattern.matcher(docText);
+    while (m.find()) {
       // found one - create annotation
-      RoomNumber annotation = new RoomNumber(aJCas);
-      annotation.setBegin(matcher.start());
-      annotation.setEnd(matcher.end());
+      RoomNumber annotation = new RoomNumber(aJCas, m.start(), m.end());
       annotation.setBuilding("Hawthorne");
       annotation.addToIndexes();
     }
diff --git a/uimaj-examples/src/main/java/org/apache/uima/tutorial/ex2/RoomNumberAnnotator.java b/uimaj-examples/src/main/java/org/apache/uima/tutorial/ex2/RoomNumberAnnotator.java
index e412cf2..c70e789 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/tutorial/ex2/RoomNumberAnnotator.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/tutorial/ex2/RoomNumberAnnotator.java
@@ -67,12 +67,13 @@
       Matcher matcher = mPatterns[i].matcher(docText);
       while (matcher.find()) {
         // found one - create annotation
-        RoomNumber annotation = new RoomNumber(aJCas);
-        annotation.setBegin(matcher.start());
-        annotation.setEnd(matcher.end());
+        RoomNumber annotation = new RoomNumber(aJCas, matcher.start(), matcher.end());
         annotation.addToIndexes();
         annotation.setBuilding(mLocations[i]);
-        getContext().getLogger().log(Level.FINEST, "Found: " + annotation);
+        getLogger().log(Level.FINEST, "Found: " + annotation);
+        // or, using slf4j
+        // note: this call skips constructing the message if tracing is not enabled
+//        getSlf4jLogger().trace("Found: {}", annotation);
       }
     }
   }
diff --git a/uimaj-examples/src/main/java/org/apache/uima/tutorial/ex4/MeetingAnnotator.java b/uimaj-examples/src/main/java/org/apache/uima/tutorial/ex4/MeetingAnnotator.java
index 9969e96..4f805dc 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/tutorial/ex4/MeetingAnnotator.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/tutorial/ex4/MeetingAnnotator.java
@@ -57,54 +57,40 @@
    */
   public void process(JCas aJCas) {
     // get annotation indexes
-    FSIndex roomNumberIndex = aJCas.getAnnotationIndex(RoomNumber.type);
-    FSIndex dateIndex = aJCas.getAnnotationIndex(DateAnnot.type);
-    FSIndex timeIndex = aJCas.getAnnotationIndex(TimeAnnot.type);
+    FSIndex<RoomNumber> roomNumberIndex = aJCas.getAnnotationIndex(RoomNumber.class);
+    FSIndex<DateAnnot> dateIndex = aJCas.getAnnotationIndex(DateAnnot.class);
+    FSIndex<TimeAnnot> timeIndex = aJCas.getAnnotationIndex(TimeAnnot.class);
 
     // store end position of last meeting we identified, to prevent multiple
     // annotations over same span
     int lastMeetingEnd = -1;
 
-    // iterate over all combinations
-    Iterator roomNumberIter = roomNumberIndex.iterator();
-    while (roomNumberIter.hasNext()) {
-      RoomNumber room = (RoomNumber) roomNumberIter.next();
-
-      Iterator dateIter = dateIndex.iterator();
-      while (dateIter.hasNext()) {
-        DateAnnot date = (DateAnnot) dateIter.next();
-
-        Iterator time1Iter = timeIndex.iterator();
-        while (time1Iter.hasNext()) {
-          TimeAnnot time1 = (TimeAnnot) time1Iter.next();
-
-          Iterator time2Iter = timeIndex.iterator();
-          while (time2Iter.hasNext()) {
-            TimeAnnot time2 = (TimeAnnot) time2Iter.next();
+    for (RoomNumber room : roomNumberIndex.select()) {
+      for (DateAnnot date : dateIndex.select()) {
+        for(TimeAnnot time1 : timeIndex.select()) {
+          for (TimeAnnot time2 : timeIndex.select()) {
 
             // times must be different annotations
             if (time1 != time2) {
               // compute the begin and end of the span
-              int minBegin = Math.min(Math.min(time1.getBegin(), time2.getBegin()), Math.min(date
-                      .getBegin(), room.getBegin()));
-              int maxEnd = Math.max(Math.max(time1.getEnd(), time2.getEnd()), Math.max(date
-                      .getEnd(), room.getEnd()));
+              int minBegin = Math.min(Math.min(time1.getBegin(), time2.getBegin()), 
+                                      Math.min(date .getBegin(), room .getBegin()));
+              int maxEnd = Math.max(Math.max(time1.getEnd(), time2.getEnd()), 
+                                    Math.max(date .getEnd(), room .getEnd()));
 
               // span must be smaller than the window size?
-              if (maxEnd - minBegin < mWindowSize) {
+              if (maxEnd - minBegin < mWindowSize && 
                 // span must not overlap the last annotation we made
-                if (minBegin > lastMeetingEnd) {
-                  // annotate
-                  Meeting mtg = new Meeting(aJCas, minBegin, maxEnd, room, date, time1, time2);
-                  mtg.addToIndexes();
-                  lastMeetingEnd = maxEnd;
-                }
+                  minBegin > lastMeetingEnd) {
+                // annotate
+                Meeting mtg = new Meeting(aJCas, minBegin, maxEnd, room, date, time1, time2);
+                mtg.addToIndexes();
+                lastMeetingEnd = maxEnd;
               }
             }
           }
         }
-      }
+      }   
     }
   }
-
 }
diff --git a/uimaj-examples/src/main/java/org/apache/uima/tutorial/ex5/RoomNumberAnnotator.java b/uimaj-examples/src/main/java/org/apache/uima/tutorial/ex5/RoomNumberAnnotator.java
index 6d061cb..87dbace 100644
--- a/uimaj-examples/src/main/java/org/apache/uima/tutorial/ex5/RoomNumberAnnotator.java
+++ b/uimaj-examples/src/main/java/org/apache/uima/tutorial/ex5/RoomNumberAnnotator.java
@@ -74,11 +74,9 @@
       Matcher matcher = mPatterns[i].matcher(docText);
       while (matcher.find()) {
         // found one - create annotation
-        RoomNumber annotation = new RoomNumber(aJCas);
-        annotation.setBegin(matcher.start());
-        annotation.setEnd(matcher.end());
-        annotation.addToIndexes();
+        RoomNumber annotation = new RoomNumber(aJCas, matcher.start(), matcher.end());
         annotation.setBuilding(mLocations[i]);
+        annotation.addToIndexes();
         getContext().getLogger().log(Level.FINEST, "Found: " + annotation);
       }
     }
diff --git a/uimaj-examples/src/main/run_configuration/UIMA Run V3 migrate JCas from classes roots.launch b/uimaj-examples/src/main/run_configuration/UIMA Run V3 migrate JCas from classes roots.launch
index dfd8c1c..717adc3 100644
--- a/uimaj-examples/src/main/run_configuration/UIMA Run V3 migrate JCas from classes roots.launch
+++ b/uimaj-examples/src/main/run_configuration/UIMA Run V3 migrate JCas from classes roots.launch
@@ -19,6 +19,11 @@
 -->

 <launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">

 <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.apache.uima.migratev3.jcas.MigrateJCas"/>

-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-classesRoots &quot;${folder_prompt:root dir for compiled classes and jars and PEARs}&quot; &#13;&#10;-outputDirectory &quot;${folder_prompt:output file, something like /temp/uima-v3-migrated/:/temp/uima_v3_migrate}&quot; &#13;&#10;-migrateClasspath ${project_classpath}"/>

+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-classesRoots &quot;${folder_prompt:root dir for compiled classes and jars and PEARs}&quot;  &#13;&#10;-migrateClasspath ${project_classpath}"/>

 <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="uimaj-examples"/>

+

+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">

+  <listEntry value="4"/>

+</listAttribute>

+

 </launchConfiguration>

diff --git a/uimaj-examples/src/main/run_configuration/UIMA Run V3 migrate JCas from sources roots.launch b/uimaj-examples/src/main/run_configuration/UIMA Run V3 migrate JCas from sources roots.launch
index db4434b..fd61e8e 100644
--- a/uimaj-examples/src/main/run_configuration/UIMA Run V3 migrate JCas from sources roots.launch
+++ b/uimaj-examples/src/main/run_configuration/UIMA Run V3 migrate JCas from sources roots.launch
@@ -19,6 +19,11 @@
 -->

 <launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">

 <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.apache.uima.migratev3.jcas.MigrateJCas"/>

-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-sourcesRoots &quot;${folder_prompt:root dir for sources}&quot; &#13;&#10;-outputDirectory &quot;${folder_prompt:output file, something like /temp/uima-v3-migrated/:/temp/uima_v3_migrate}&quot; &#13;&#10;-migrateClasspath ${project_classpath}"/>

 <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="uimaj-examples"/>

+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-sourcesRoots ${selected_resource_loc}&#13;&#10;-migrateClasspath ${project_classpath}"/>

+

+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">

+  <listEntry value="4"/>

+</listAttribute>

+

 </launchConfiguration>

diff --git a/uimaj-jet-expander/Readme.txt b/uimaj-jet-expander/Readme.txt
index 46bfa47..b56f193 100644
--- a/uimaj-jet-expander/Readme.txt
+++ b/uimaj-jet-expander/Readme.txt
@@ -26,7 +26,7 @@
  It is not part of the Maven build (at this time).

  

  To get it into your Eclipse workspace, use the SVN Repo view, and

- do an eclipse SVN checkout.

+ do an eclipse SVN checkout as uimaj-jet-expander

 

  It is set up with launchers for use within the Eclipse

  IDE.  There are 2 launchers - one creates Java code

diff --git a/uimaj-json/pom.xml b/uimaj-json/pom.xml
index cc3bc33..53ae63e 100644
--- a/uimaj-json/pom.xml
+++ b/uimaj-json/pom.xml
@@ -30,9 +30,9 @@
   <description>JSON support for UIMA SDK</description>

   

   <scm>

-    <connection>scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-json</connection>

-    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-json</developerConnection>

-    <url>http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-json</url>

+    <connection>scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-json</connection>

+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-json</developerConnection>

+    <url>http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-json</url>

   </scm>

   

   <properties>

@@ -49,7 +49,7 @@
     <dependency>

       <groupId>com.fasterxml.jackson.core</groupId>

       <artifactId>jackson-core</artifactId>

-      <version>2.4.2</version>

+      <version>${jackson.version}</version>

     </dependency>

     

     <dependency>

@@ -59,6 +59,11 @@
       <scope>test</scope>

     </dependency>

 

+    <dependency>

+      <groupId>org.slf4j</groupId>

+      <artifactId>slf4j-jdk14</artifactId>

+      <scope>test</scope>

+    </dependency>

   </dependencies>

   

   <build>

diff --git a/uimaj-json/src/main/java/org/apache/uima/json/JsonCasSerializer.java b/uimaj-json/src/main/java/org/apache/uima/json/JsonCasSerializer.java
index 02df322..0212a97 100644
--- a/uimaj-json/src/main/java/org/apache/uima/json/JsonCasSerializer.java
+++ b/uimaj-json/src/main/java/org/apache/uima/json/JsonCasSerializer.java
@@ -936,7 +936,7 @@
         // if we're not going to write the actual FS here, 

         //   and are just going to write the ref, 

         //   skip the start object

-        if (cds.multiRefFSs == null || !cds.multiRefFSs.contains(fs)) {         

+        if (!cds.isDynamicMultiRef || !cds.multiRefFSs.contains(fs)) {         

           jch.writeNlJustBeforeNext();

           jg.writeStartObject();  // start of feat : value

         }

@@ -1101,7 +1101,7 @@
      * @throws IOException

      */

     private void writeFsOrRef(TOP fs) throws IOException {

-      if (fs == null || null == cds.multiRefFSs || cds.multiRefFSs.contains(fs)) {

+      if (fs == null || !cds.isDynamicMultiRef || cds.multiRefFSs.contains(fs)) {

         jg.writeNumber(cds.getXmiIdAsInt(fs));

       } else {

         isEmbeddedFromFsFeature = false;

@@ -1125,7 +1125,7 @@
     }

     

     private void writeFsOrRef(TOP fs, FeatureImpl fi) throws IOException {

-      if (fs == null || null == cds.multiRefFSs || cds.multiRefFSs.contains(fs)) {

+      if (fs == null || !cds.isDynamicMultiRef || cds.multiRefFSs.contains(fs)) {

         jg.writeFieldName(getShortFeatureName(fi));

         jg.writeNumber(cds.getXmiIdAsInt(fs));

       } else {

@@ -1420,13 +1420,13 @@
     }

     

     private boolean isDynamicOrStaticMultiRef(FeatureImpl fi, TOP fs) {

-      return (cds.multiRefFSs == null) ? 

+      return (!cds.isDynamicMultiRef) ? 

                 cds.isStaticMultiRef(fi) : 

                 cds.multiRefFSs.contains(fs);

     }

     

     private boolean isDynamicOrStaticMultiRef(FeatureImpl fi, TOP fs, boolean isListAsFSs) {

-      return (cds.multiRefFSs == null) ? 

+      return (!cds.isDynamicMultiRef) ? 

                 (isListAsFSs || cds.isStaticMultiRef(fi)) : 

                 cds.multiRefFSs.contains(fs);

     }

diff --git a/uimaj-json/src/main/java/org/apache/uima/json/impl/JsonContentHandlerJacksonWrapper.java b/uimaj-json/src/main/java/org/apache/uima/json/impl/JsonContentHandlerJacksonWrapper.java
index 744e89c..238d6f2 100644
--- a/uimaj-json/src/main/java/org/apache/uima/json/impl/JsonContentHandlerJacksonWrapper.java
+++ b/uimaj-json/src/main/java/org/apache/uima/json/impl/JsonContentHandlerJacksonWrapper.java
@@ -37,6 +37,7 @@
 import com.fasterxml.jackson.core.JsonGenerationException;

 import com.fasterxml.jackson.core.JsonGenerator;

 import com.fasterxml.jackson.core.PrettyPrinter;

+import com.fasterxml.jackson.core.util.DefaultIndenter;

 import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;

 import com.fasterxml.jackson.core.util.DefaultPrettyPrinter.FixedSpaceIndenter;

 

@@ -351,7 +352,12 @@
   

   public void withNl() {

     if (isFormattedOutput) {

-      uimaPrettyPrinter.indentObjectsWith(DefaultPrettyPrinter.Lf2SpacesIndenter.instance);

+      // upgrade from Lf2SpacesIndenter - removed in v 2.7

+      

+      uimaPrettyPrinter.indentObjectsWith(

+//          DefaultPrettyPrinter.Lf2SpacesIndenter.instance

+            DefaultIndenter.SYSTEM_LINEFEED_INSTANCE

+          );

     }

   }

   

diff --git a/uimaj-json/src/test/java/org/apache/uima/json/JsonCasSerializerTest.java b/uimaj-json/src/test/java/org/apache/uima/json/JsonCasSerializerTest.java
index 16b984a..a8855f4 100644
--- a/uimaj-json/src/test/java/org/apache/uima/json/JsonCasSerializerTest.java
+++ b/uimaj-json/src/test/java/org/apache/uima/json/JsonCasSerializerTest.java
@@ -25,8 +25,6 @@
 import java.io.IOException;

 import java.io.StringWriter;

 

-import junit.framework.TestCase;

-

 import org.apache.uima.UIMAFramework;

 import org.apache.uima.cas.CAS;

 import org.apache.uima.cas.CASException;

@@ -42,14 +40,12 @@
 import org.apache.uima.jcas.cas.ByteArray;

 import org.apache.uima.jcas.cas.EmptyFSList;

 import org.apache.uima.jcas.cas.FSArray;

-import org.apache.uima.jcas.cas.FSList;

 import org.apache.uima.jcas.cas.IntegerList;

 import org.apache.uima.jcas.cas.NonEmptyFSList;

 import org.apache.uima.jcas.cas.NonEmptyIntegerList;

 import org.apache.uima.json.JsonCasSerializer.JsonContextFormat;

 import org.apache.uima.resource.ResourceInitializationException;

 import org.apache.uima.resource.metadata.TypeSystemDescription;

-import org.apache.uima.test.AllTypes;

 import org.apache.uima.test.RefTypes;

 import org.apache.uima.test.junit_extension.JUnitExtension;

 import org.apache.uima.util.CasCreationUtils;

@@ -61,6 +57,8 @@
 import org.custommonkey.xmlunit.XMLAssert;

 import org.xml.sax.SAXException;

 

+import junit.framework.TestCase;

+

 public class JsonCasSerializerTest extends TestCase {

   /*********************************************************************

    *    I N S T R U C T I O N S                                        *

@@ -236,9 +234,9 @@
     Type a2t = tsMgr.getType(CAS.TYPE_NAME_ANNOTATION);

     // filter out the 2 types causing namespaces to be needed.

     tsMgr.addType("org.apache.uima.test.Token", a2t);

-    tsMgr.commit();

+    TypeSystemImpl tsi = (TypeSystemImpl) tsMgr.commit();

     jcs = new JsonCasSerializer().setOmit0Values(true);

-    jcs.setFilterTypes((TypeSystemImpl) tsMgr);

+    jcs.setFilterTypes(tsi);

     serializeAndCompare("nameSpaceNoCollsionFiltered.txt");

     

     // filter, but not enough - should have 1 collison

@@ -247,8 +245,8 @@
     // filter out the 2 types causing namespaces to be needed.

     tsMgr.addType("org.apache.uima.test.Token", a2t);

     tsMgr.addType("org.apache.uimax.test.Token", a2t);

-    tsMgr.commit();

-    jcs.setFilterTypes((TypeSystemImpl) tsMgr);

+    tsi = (TypeSystemImpl) tsMgr.commit();

+    jcs.setFilterTypes(tsi);

     serializeAndCompare("nameSpaceCollsionFiltered.txt");    

     

   }

@@ -345,6 +343,11 @@
   }

 

   public void arrayOrListRefstst(boolean tstArray) throws Exception {

+    

+    // using dynamic embedding

+    // an element is multiply-referenced if it is both in the index (referenced by the "view") and is referenced 

+    //   by an FSRef in a feature or a slot in an FSArray

+    

     jcas.reset();

     

     //  make root FS that is indexed and has a ref 

@@ -374,16 +377,18 @@
     l2.setHead(refa3);;

          

     if (tstArray) {

-      root.setAArrayFS(a);

+      root.setAArrayFS(a);  // is not (yet) multiply referenced

     } else {

       root.setAListFs(l0);

     }

     

     String sfx = (tstArray) ? "a" : "l";

     // all embeddable:

+    //   because ref1,2,3 are not index, and FSArray isn't either

     serializeAndCompare("array-all-embeddable-" + sfx + ".txt");

     // 1 not embeddable, at all 3 positions

     refa1.addToIndexes();

+    //   ref1 is multiply indexed

     serializeAndCompare("array-a1-not-" + sfx + ".txt");

     refa1.removeFromIndexes();

     refa2.addToIndexes();

diff --git a/uimaj-json/src/test/java/org/apache/uima/test/AllTypes.java b/uimaj-json/src/test/java/org/apache/uima/test/AllTypes.java
index 0143f75..20ea9f7 100644
--- a/uimaj-json/src/test/java/org/apache/uima/test/AllTypes.java
+++ b/uimaj-json/src/test/java/org/apache/uima/test/AllTypes.java
@@ -5,6 +5,9 @@
 
 package org.apache.uima.test;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -50,30 +53,54 @@
    * *******************/ 
    
   /* Feature Adjusted Offsets */
-  public final static int _FI_aBoolean = TypeSystemImpl.getAdjustedFeatureOffset("aBoolean");
-  public final static int _FI_aByte = TypeSystemImpl.getAdjustedFeatureOffset("aByte");
-  public final static int _FI_aShort = TypeSystemImpl.getAdjustedFeatureOffset("aShort");
-  public final static int _FI_aInteger = TypeSystemImpl.getAdjustedFeatureOffset("aInteger");
-  public final static int _FI_aLong = TypeSystemImpl.getAdjustedFeatureOffset("aLong");
-  public final static int _FI_aFloat = TypeSystemImpl.getAdjustedFeatureOffset("aFloat");
-  public final static int _FI_aDouble = TypeSystemImpl.getAdjustedFeatureOffset("aDouble");
-  public final static int _FI_aString = TypeSystemImpl.getAdjustedFeatureOffset("aString");
-  public final static int _FI_aFS = TypeSystemImpl.getAdjustedFeatureOffset("aFS");
-  public final static int _FI_aArrayBoolean = TypeSystemImpl.getAdjustedFeatureOffset("aArrayBoolean");
-  public final static int _FI_aArrayMrBoolean = TypeSystemImpl.getAdjustedFeatureOffset("aArrayMrBoolean");
-  public final static int _FI_aArrayMrByte = TypeSystemImpl.getAdjustedFeatureOffset("aArrayMrByte");
-  public final static int _FI_aArrayByte = TypeSystemImpl.getAdjustedFeatureOffset("aArrayByte");
-  public final static int _FI_aArrayShort = TypeSystemImpl.getAdjustedFeatureOffset("aArrayShort");
-  public final static int _FI_aArrayMrShort = TypeSystemImpl.getAdjustedFeatureOffset("aArrayMrShort");
-  public final static int _FI_aArrayString = TypeSystemImpl.getAdjustedFeatureOffset("aArrayString");
-  public final static int _FI_aArrayMrString = TypeSystemImpl.getAdjustedFeatureOffset("aArrayMrString");
-  public final static int _FI_aListInteger = TypeSystemImpl.getAdjustedFeatureOffset("aListInteger");
-  public final static int _FI_aListMrInteger = TypeSystemImpl.getAdjustedFeatureOffset("aListMrInteger");
-  public final static int _FI_aListString = TypeSystemImpl.getAdjustedFeatureOffset("aListString");
-  public final static int _FI_aListMrString = TypeSystemImpl.getAdjustedFeatureOffset("aListMrString");
-  public final static int _FI_aListFs = TypeSystemImpl.getAdjustedFeatureOffset("aListFs");
-  public final static int _FI_aListMrFs = TypeSystemImpl.getAdjustedFeatureOffset("aListMrFs");
-  public final static int _FI_aArrayFS = TypeSystemImpl.getAdjustedFeatureOffset("aArrayFS");
+  private final static CallSite _FC_aBoolean = TypeSystemImpl.createCallSite(AllTypes.class, "aBoolean");
+  private final static MethodHandle _FH_aBoolean = _FC_aBoolean.dynamicInvoker();
+  private final static CallSite _FC_aByte = TypeSystemImpl.createCallSite(AllTypes.class, "aByte");
+  private final static MethodHandle _FH_aByte = _FC_aByte.dynamicInvoker();
+  private final static CallSite _FC_aShort = TypeSystemImpl.createCallSite(AllTypes.class, "aShort");
+  private final static MethodHandle _FH_aShort = _FC_aShort.dynamicInvoker();
+  private final static CallSite _FC_aInteger = TypeSystemImpl.createCallSite(AllTypes.class, "aInteger");
+  private final static MethodHandle _FH_aInteger = _FC_aInteger.dynamicInvoker();
+  private final static CallSite _FC_aLong = TypeSystemImpl.createCallSite(AllTypes.class, "aLong");
+  private final static MethodHandle _FH_aLong = _FC_aLong.dynamicInvoker();
+  private final static CallSite _FC_aFloat = TypeSystemImpl.createCallSite(AllTypes.class, "aFloat");
+  private final static MethodHandle _FH_aFloat = _FC_aFloat.dynamicInvoker();
+  private final static CallSite _FC_aDouble = TypeSystemImpl.createCallSite(AllTypes.class, "aDouble");
+  private final static MethodHandle _FH_aDouble = _FC_aDouble.dynamicInvoker();
+  private final static CallSite _FC_aString = TypeSystemImpl.createCallSite(AllTypes.class, "aString");
+  private final static MethodHandle _FH_aString = _FC_aString.dynamicInvoker();
+  private final static CallSite _FC_aFS = TypeSystemImpl.createCallSite(AllTypes.class, "aFS");
+  private final static MethodHandle _FH_aFS = _FC_aFS.dynamicInvoker();
+  private final static CallSite _FC_aArrayBoolean = TypeSystemImpl.createCallSite(AllTypes.class, "aArrayBoolean");
+  private final static MethodHandle _FH_aArrayBoolean = _FC_aArrayBoolean.dynamicInvoker();
+  private final static CallSite _FC_aArrayMrBoolean = TypeSystemImpl.createCallSite(AllTypes.class, "aArrayMrBoolean");
+  private final static MethodHandle _FH_aArrayMrBoolean = _FC_aArrayMrBoolean.dynamicInvoker();
+  private final static CallSite _FC_aArrayMrByte = TypeSystemImpl.createCallSite(AllTypes.class, "aArrayMrByte");
+  private final static MethodHandle _FH_aArrayMrByte = _FC_aArrayMrByte.dynamicInvoker();
+  private final static CallSite _FC_aArrayByte = TypeSystemImpl.createCallSite(AllTypes.class, "aArrayByte");
+  private final static MethodHandle _FH_aArrayByte = _FC_aArrayByte.dynamicInvoker();
+  private final static CallSite _FC_aArrayShort = TypeSystemImpl.createCallSite(AllTypes.class, "aArrayShort");
+  private final static MethodHandle _FH_aArrayShort = _FC_aArrayShort.dynamicInvoker();
+  private final static CallSite _FC_aArrayMrShort = TypeSystemImpl.createCallSite(AllTypes.class, "aArrayMrShort");
+  private final static MethodHandle _FH_aArrayMrShort = _FC_aArrayMrShort.dynamicInvoker();
+  private final static CallSite _FC_aArrayString = TypeSystemImpl.createCallSite(AllTypes.class, "aArrayString");
+  private final static MethodHandle _FH_aArrayString = _FC_aArrayString.dynamicInvoker();
+  private final static CallSite _FC_aArrayMrString = TypeSystemImpl.createCallSite(AllTypes.class, "aArrayMrString");
+  private final static MethodHandle _FH_aArrayMrString = _FC_aArrayMrString.dynamicInvoker();
+  private final static CallSite _FC_aListInteger = TypeSystemImpl.createCallSite(AllTypes.class, "aListInteger");
+  private final static MethodHandle _FH_aListInteger = _FC_aListInteger.dynamicInvoker();
+  private final static CallSite _FC_aListMrInteger = TypeSystemImpl.createCallSite(AllTypes.class, "aListMrInteger");
+  private final static MethodHandle _FH_aListMrInteger = _FC_aListMrInteger.dynamicInvoker();
+  private final static CallSite _FC_aListString = TypeSystemImpl.createCallSite(AllTypes.class, "aListString");
+  private final static MethodHandle _FH_aListString = _FC_aListString.dynamicInvoker();
+  private final static CallSite _FC_aListMrString = TypeSystemImpl.createCallSite(AllTypes.class, "aListMrString");
+  private final static MethodHandle _FH_aListMrString = _FC_aListMrString.dynamicInvoker();
+  private final static CallSite _FC_aListFs = TypeSystemImpl.createCallSite(AllTypes.class, "aListFs");
+  private final static MethodHandle _FH_aListFs = _FC_aListFs.dynamicInvoker();
+  private final static CallSite _FC_aListMrFs = TypeSystemImpl.createCallSite(AllTypes.class, "aListMrFs");
+  private final static MethodHandle _FH_aListMrFs = _FC_aListMrFs.dynamicInvoker();
+  private final static CallSite _FC_aArrayFS = TypeSystemImpl.createCallSite(AllTypes.class, "aArrayFS");
+  private final static MethodHandle _FH_aArrayFS = _FC_aArrayFS.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -116,14 +143,14 @@
    * @generated
    * @return value of the feature 
    */
-  public boolean getABoolean() { return _getBooleanValueNc(_FI_aBoolean);}
+  public boolean getABoolean() { return _getBooleanValueNc(wrapGetIntCatchException(_FH_aBoolean));}
     
   /** setter for aBoolean - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setABoolean(boolean v) {
-    _setBooleanValueNfc(_FI_aBoolean, v);
+    _setBooleanValueNfc(wrapGetIntCatchException(_FH_aBoolean), v);
   }    
     
    
@@ -135,14 +162,14 @@
    * @generated
    * @return value of the feature 
    */
-  public byte getAByte() { return _getByteValueNc(_FI_aByte);}
+  public byte getAByte() { return _getByteValueNc(wrapGetIntCatchException(_FH_aByte));}
     
   /** setter for aByte - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAByte(byte v) {
-    _setByteValueNfc(_FI_aByte, v);
+    _setByteValueNfc(wrapGetIntCatchException(_FH_aByte), v);
   }    
     
    
@@ -154,14 +181,14 @@
    * @generated
    * @return value of the feature 
    */
-  public short getAShort() { return _getShortValueNc(_FI_aShort);}
+  public short getAShort() { return _getShortValueNc(wrapGetIntCatchException(_FH_aShort));}
     
   /** setter for aShort - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAShort(short v) {
-    _setShortValueNfc(_FI_aShort, v);
+    _setShortValueNfc(wrapGetIntCatchException(_FH_aShort), v);
   }    
     
    
@@ -173,14 +200,14 @@
    * @generated
    * @return value of the feature 
    */
-  public int getAInteger() { return _getIntValueNc(_FI_aInteger);}
+  public int getAInteger() { return _getIntValueNc(wrapGetIntCatchException(_FH_aInteger));}
     
   /** setter for aInteger - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAInteger(int v) {
-    _setIntValueNfc(_FI_aInteger, v);
+    _setIntValueNfc(wrapGetIntCatchException(_FH_aInteger), v);
   }    
     
    
@@ -192,14 +219,14 @@
    * @generated
    * @return value of the feature 
    */
-  public long getALong() { return _getLongValueNc(_FI_aLong);}
+  public long getALong() { return _getLongValueNc(wrapGetIntCatchException(_FH_aLong));}
     
   /** setter for aLong - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setALong(long v) {
-    _setLongValueNfc(_FI_aLong, v);
+    _setLongValueNfc(wrapGetIntCatchException(_FH_aLong), v);
   }    
     
    
@@ -211,14 +238,14 @@
    * @generated
    * @return value of the feature 
    */
-  public float getAFloat() { return _getFloatValueNc(_FI_aFloat);}
+  public float getAFloat() { return _getFloatValueNc(wrapGetIntCatchException(_FH_aFloat));}
     
   /** setter for aFloat - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAFloat(float v) {
-    _setFloatValueNfc(_FI_aFloat, v);
+    _setFloatValueNfc(wrapGetIntCatchException(_FH_aFloat), v);
   }    
     
    
@@ -230,14 +257,14 @@
    * @generated
    * @return value of the feature 
    */
-  public double getADouble() { return _getDoubleValueNc(_FI_aDouble);}
+  public double getADouble() { return _getDoubleValueNc(wrapGetIntCatchException(_FH_aDouble));}
     
   /** setter for aDouble - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setADouble(double v) {
-    _setDoubleValueNfc(_FI_aDouble, v);
+    _setDoubleValueNfc(wrapGetIntCatchException(_FH_aDouble), v);
   }    
     
    
@@ -249,14 +276,14 @@
    * @generated
    * @return value of the feature 
    */
-  public String getAString() { return _getStringValueNc(_FI_aString);}
+  public String getAString() { return _getStringValueNc(wrapGetIntCatchException(_FH_aString));}
     
   /** setter for aString - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAString(String v) {
-    _setStringValueNfc(_FI_aString, v);
+    _setStringValueNfc(wrapGetIntCatchException(_FH_aString), v);
   }    
     
    
@@ -268,14 +295,14 @@
    * @generated
    * @return value of the feature 
    */
-  public Annotation getAFS() { return (Annotation)(_getFeatureValueNc(_FI_aFS));}
+  public Annotation getAFS() { return (Annotation)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aFS)));}
     
   /** setter for aFS - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAFS(Annotation v) {
-    _setFeatureValueNcWj(_FI_aFS, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aFS), v);
   }    
     
    
@@ -287,14 +314,14 @@
    * @generated
    * @return value of the feature 
    */
-  public BooleanArray getAArrayBoolean() { return (BooleanArray)(_getFeatureValueNc(_FI_aArrayBoolean));}
+  public BooleanArray getAArrayBoolean() { return (BooleanArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayBoolean)));}
     
   /** setter for aArrayBoolean - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAArrayBoolean(BooleanArray v) {
-    _setFeatureValueNcWj(_FI_aArrayBoolean, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aArrayBoolean), v);
   }    
     
     
@@ -304,7 +331,7 @@
    * @return value of the element at index i 
    */
   public boolean getAArrayBoolean(int i) {
-     return ((BooleanArray)(_getFeatureValueNc(_FI_aArrayBoolean))).get(i);} 
+     return ((BooleanArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayBoolean)))).get(i);} 
 
   /** indexed setter for aArrayBoolean - sets an indexed value - 
    * @generated
@@ -312,7 +339,7 @@
    * @param v value to set into the array 
    */
   public void setAArrayBoolean(int i, boolean v) {
-    ((BooleanArray)(_getFeatureValueNc(_FI_aArrayBoolean))).set(i, v);
+    ((BooleanArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayBoolean)))).set(i, v);
   }  
    
     
@@ -323,14 +350,14 @@
    * @generated
    * @return value of the feature 
    */
-  public BooleanArray getAArrayMrBoolean() { return (BooleanArray)(_getFeatureValueNc(_FI_aArrayMrBoolean));}
+  public BooleanArray getAArrayMrBoolean() { return (BooleanArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayMrBoolean)));}
     
   /** setter for aArrayMrBoolean - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAArrayMrBoolean(BooleanArray v) {
-    _setFeatureValueNcWj(_FI_aArrayMrBoolean, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aArrayMrBoolean), v);
   }    
     
     
@@ -340,7 +367,7 @@
    * @return value of the element at index i 
    */
   public boolean getAArrayMrBoolean(int i) {
-     return ((BooleanArray)(_getFeatureValueNc(_FI_aArrayMrBoolean))).get(i);} 
+     return ((BooleanArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayMrBoolean)))).get(i);} 
 
   /** indexed setter for aArrayMrBoolean - sets an indexed value - 
    * @generated
@@ -348,7 +375,7 @@
    * @param v value to set into the array 
    */
   public void setAArrayMrBoolean(int i, boolean v) {
-    ((BooleanArray)(_getFeatureValueNc(_FI_aArrayMrBoolean))).set(i, v);
+    ((BooleanArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayMrBoolean)))).set(i, v);
   }  
    
     
@@ -359,14 +386,14 @@
    * @generated
    * @return value of the feature 
    */
-  public ByteArray getAArrayMrByte() { return (ByteArray)(_getFeatureValueNc(_FI_aArrayMrByte));}
+  public ByteArray getAArrayMrByte() { return (ByteArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayMrByte)));}
     
   /** setter for aArrayMrByte - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAArrayMrByte(ByteArray v) {
-    _setFeatureValueNcWj(_FI_aArrayMrByte, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aArrayMrByte), v);
   }    
     
     
@@ -376,7 +403,7 @@
    * @return value of the element at index i 
    */
   public byte getAArrayMrByte(int i) {
-     return ((ByteArray)(_getFeatureValueNc(_FI_aArrayMrByte))).get(i);} 
+     return ((ByteArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayMrByte)))).get(i);} 
 
   /** indexed setter for aArrayMrByte - sets an indexed value - 
    * @generated
@@ -384,7 +411,7 @@
    * @param v value to set into the array 
    */
   public void setAArrayMrByte(int i, byte v) {
-    ((ByteArray)(_getFeatureValueNc(_FI_aArrayMrByte))).set(i, v);
+    ((ByteArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayMrByte)))).set(i, v);
   }  
    
     
@@ -395,14 +422,14 @@
    * @generated
    * @return value of the feature 
    */
-  public ByteArray getAArrayByte() { return (ByteArray)(_getFeatureValueNc(_FI_aArrayByte));}
+  public ByteArray getAArrayByte() { return (ByteArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayByte)));}
     
   /** setter for aArrayByte - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAArrayByte(ByteArray v) {
-    _setFeatureValueNcWj(_FI_aArrayByte, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aArrayByte), v);
   }    
     
     
@@ -412,7 +439,7 @@
    * @return value of the element at index i 
    */
   public byte getAArrayByte(int i) {
-     return ((ByteArray)(_getFeatureValueNc(_FI_aArrayByte))).get(i);} 
+     return ((ByteArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayByte)))).get(i);} 
 
   /** indexed setter for aArrayByte - sets an indexed value - 
    * @generated
@@ -420,7 +447,7 @@
    * @param v value to set into the array 
    */
   public void setAArrayByte(int i, byte v) {
-    ((ByteArray)(_getFeatureValueNc(_FI_aArrayByte))).set(i, v);
+    ((ByteArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayByte)))).set(i, v);
   }  
    
     
@@ -431,14 +458,14 @@
    * @generated
    * @return value of the feature 
    */
-  public ShortArray getAArrayShort() { return (ShortArray)(_getFeatureValueNc(_FI_aArrayShort));}
+  public ShortArray getAArrayShort() { return (ShortArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayShort)));}
     
   /** setter for aArrayShort - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAArrayShort(ShortArray v) {
-    _setFeatureValueNcWj(_FI_aArrayShort, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aArrayShort), v);
   }    
     
     
@@ -448,7 +475,7 @@
    * @return value of the element at index i 
    */
   public short getAArrayShort(int i) {
-     return ((ShortArray)(_getFeatureValueNc(_FI_aArrayShort))).get(i);} 
+     return ((ShortArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayShort)))).get(i);} 
 
   /** indexed setter for aArrayShort - sets an indexed value - 
    * @generated
@@ -456,7 +483,7 @@
    * @param v value to set into the array 
    */
   public void setAArrayShort(int i, short v) {
-    ((ShortArray)(_getFeatureValueNc(_FI_aArrayShort))).set(i, v);
+    ((ShortArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayShort)))).set(i, v);
   }  
    
     
@@ -467,14 +494,14 @@
    * @generated
    * @return value of the feature 
    */
-  public ShortArray getAArrayMrShort() { return (ShortArray)(_getFeatureValueNc(_FI_aArrayMrShort));}
+  public ShortArray getAArrayMrShort() { return (ShortArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayMrShort)));}
     
   /** setter for aArrayMrShort - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAArrayMrShort(ShortArray v) {
-    _setFeatureValueNcWj(_FI_aArrayMrShort, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aArrayMrShort), v);
   }    
     
     
@@ -484,7 +511,7 @@
    * @return value of the element at index i 
    */
   public short getAArrayMrShort(int i) {
-     return ((ShortArray)(_getFeatureValueNc(_FI_aArrayMrShort))).get(i);} 
+     return ((ShortArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayMrShort)))).get(i);} 
 
   /** indexed setter for aArrayMrShort - sets an indexed value - 
    * @generated
@@ -492,7 +519,7 @@
    * @param v value to set into the array 
    */
   public void setAArrayMrShort(int i, short v) {
-    ((ShortArray)(_getFeatureValueNc(_FI_aArrayMrShort))).set(i, v);
+    ((ShortArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayMrShort)))).set(i, v);
   }  
    
     
@@ -503,14 +530,14 @@
    * @generated
    * @return value of the feature 
    */
-  public StringArray getAArrayString() { return (StringArray)(_getFeatureValueNc(_FI_aArrayString));}
+  public StringArray getAArrayString() { return (StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayString)));}
     
   /** setter for aArrayString - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAArrayString(StringArray v) {
-    _setFeatureValueNcWj(_FI_aArrayString, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aArrayString), v);
   }    
     
     
@@ -520,7 +547,7 @@
    * @return value of the element at index i 
    */
   public String getAArrayString(int i) {
-     return ((StringArray)(_getFeatureValueNc(_FI_aArrayString))).get(i);} 
+     return ((StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayString)))).get(i);} 
 
   /** indexed setter for aArrayString - sets an indexed value - 
    * @generated
@@ -528,7 +555,7 @@
    * @param v value to set into the array 
    */
   public void setAArrayString(int i, String v) {
-    ((StringArray)(_getFeatureValueNc(_FI_aArrayString))).set(i, v);
+    ((StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayString)))).set(i, v);
   }  
    
     
@@ -539,14 +566,14 @@
    * @generated
    * @return value of the feature 
    */
-  public StringArray getAArrayMrString() { return (StringArray)(_getFeatureValueNc(_FI_aArrayMrString));}
+  public StringArray getAArrayMrString() { return (StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayMrString)));}
     
   /** setter for aArrayMrString - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAArrayMrString(StringArray v) {
-    _setFeatureValueNcWj(_FI_aArrayMrString, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aArrayMrString), v);
   }    
     
     
@@ -556,7 +583,7 @@
    * @return value of the element at index i 
    */
   public String getAArrayMrString(int i) {
-     return ((StringArray)(_getFeatureValueNc(_FI_aArrayMrString))).get(i);} 
+     return ((StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayMrString)))).get(i);} 
 
   /** indexed setter for aArrayMrString - sets an indexed value - 
    * @generated
@@ -564,7 +591,7 @@
    * @param v value to set into the array 
    */
   public void setAArrayMrString(int i, String v) {
-    ((StringArray)(_getFeatureValueNc(_FI_aArrayMrString))).set(i, v);
+    ((StringArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayMrString)))).set(i, v);
   }  
    
     
@@ -575,14 +602,14 @@
    * @generated
    * @return value of the feature 
    */
-  public IntegerList getAListInteger() { return (IntegerList)(_getFeatureValueNc(_FI_aListInteger));}
+  public IntegerList getAListInteger() { return (IntegerList)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aListInteger)));}
     
   /** setter for aListInteger - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAListInteger(IntegerList v) {
-    _setFeatureValueNcWj(_FI_aListInteger, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aListInteger), v);
   }    
     
    
@@ -594,14 +621,14 @@
    * @generated
    * @return value of the feature 
    */
-  public IntegerList getAListMrInteger() { return (IntegerList)(_getFeatureValueNc(_FI_aListMrInteger));}
+  public IntegerList getAListMrInteger() { return (IntegerList)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aListMrInteger)));}
     
   /** setter for aListMrInteger - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAListMrInteger(IntegerList v) {
-    _setFeatureValueNcWj(_FI_aListMrInteger, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aListMrInteger), v);
   }    
     
    
@@ -613,14 +640,14 @@
    * @generated
    * @return value of the feature 
    */
-  public StringList getAListString() { return (StringList)(_getFeatureValueNc(_FI_aListString));}
+  public StringList getAListString() { return (StringList)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aListString)));}
     
   /** setter for aListString - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAListString(StringList v) {
-    _setFeatureValueNcWj(_FI_aListString, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aListString), v);
   }    
     
    
@@ -632,14 +659,14 @@
    * @generated
    * @return value of the feature 
    */
-  public StringList getAListMrString() { return (StringList)(_getFeatureValueNc(_FI_aListMrString));}
+  public StringList getAListMrString() { return (StringList)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aListMrString)));}
     
   /** setter for aListMrString - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAListMrString(StringList v) {
-    _setFeatureValueNcWj(_FI_aListMrString, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aListMrString), v);
   }    
     
    
@@ -651,14 +678,14 @@
    * @generated
    * @return value of the feature 
    */
-  public FSList getAListFs() { return (FSList)(_getFeatureValueNc(_FI_aListFs));}
+  public FSList getAListFs() { return (FSList)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aListFs)));}
     
   /** setter for aListFs - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAListFs(FSList v) {
-    _setFeatureValueNcWj(_FI_aListFs, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aListFs), v);
   }    
     
    
@@ -670,14 +697,14 @@
    * @generated
    * @return value of the feature 
    */
-  public FSList getAListMrFs() { return (FSList)(_getFeatureValueNc(_FI_aListMrFs));}
+  public FSList getAListMrFs() { return (FSList)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aListMrFs)));}
     
   /** setter for aListMrFs - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAListMrFs(FSList v) {
-    _setFeatureValueNcWj(_FI_aListMrFs, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aListMrFs), v);
   }    
     
    
@@ -689,14 +716,14 @@
    * @generated
    * @return value of the feature 
    */
-  public FSArray getAArrayFS() { return (FSArray)(_getFeatureValueNc(_FI_aArrayFS));}
+  public FSArray getAArrayFS() { return (FSArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayFS)));}
     
   /** setter for aArrayFS - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAArrayFS(FSArray v) {
-    _setFeatureValueNcWj(_FI_aArrayFS, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aArrayFS), v);
   }    
     
     
@@ -706,7 +733,7 @@
    * @return value of the element at index i 
    */
   public Annotation getAArrayFS(int i) {
-     return (Annotation)(((FSArray)(_getFeatureValueNc(_FI_aArrayFS))).get(i));} 
+     return (Annotation)(((FSArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayFS)))).get(i));} 
 
   /** indexed setter for aArrayFS - sets an indexed value - 
    * @generated
@@ -714,7 +741,7 @@
    * @param v value to set into the array 
    */
   public void setAArrayFS(int i, Annotation v) {
-    ((FSArray)(_getFeatureValueNc(_FI_aArrayFS))).set(i, v);
+    ((FSArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayFS)))).set(i, v);
   }  
   }
 
diff --git a/uimaj-json/src/test/java/org/apache/uima/test/RefTypes.java b/uimaj-json/src/test/java/org/apache/uima/test/RefTypes.java
index fed6cd6..3873b75 100644
--- a/uimaj-json/src/test/java/org/apache/uima/test/RefTypes.java
+++ b/uimaj-json/src/test/java/org/apache/uima/test/RefTypes.java
@@ -5,6 +5,9 @@
 
 package org.apache.uima.test;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
@@ -44,9 +47,12 @@
    * *******************/ 
    
   /* Feature Adjusted Offsets */
-  public final static int _FI_aFS = TypeSystemImpl.getAdjustedFeatureOffset("aFS");
-  public final static int _FI_aListFs = TypeSystemImpl.getAdjustedFeatureOffset("aListFs");
-  public final static int _FI_aArrayFS = TypeSystemImpl.getAdjustedFeatureOffset("aArrayFS");
+  private final static CallSite _FC_aFS = TypeSystemImpl.createCallSite(RefTypes.class, "aFS");
+  private final static MethodHandle _FH_aFS = _FC_aFS.dynamicInvoker();
+  private final static CallSite _FC_aListFs = TypeSystemImpl.createCallSite(RefTypes.class, "aListFs");
+  private final static MethodHandle _FH_aListFs = _FC_aListFs.dynamicInvoker();
+  private final static CallSite _FC_aArrayFS = TypeSystemImpl.createCallSite(RefTypes.class, "aArrayFS");
+  private final static MethodHandle _FH_aArrayFS = _FC_aArrayFS.dynamicInvoker();
 
    
   /** Never called.  Disable default constructor
@@ -89,14 +95,14 @@
    * @generated
    * @return value of the feature 
    */
-  public Annotation getAFS() { return (Annotation)(_getFeatureValueNc(_FI_aFS));}
+  public Annotation getAFS() { return (Annotation)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aFS)));}
     
   /** setter for aFS - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAFS(Annotation v) {
-    _setFeatureValueNcWj(_FI_aFS, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aFS), v);
   }    
     
    
@@ -108,18 +114,16 @@
    * @generated
    * @return value of the feature 
    */
-  public FSList getAListFs() { return (FSList)(_getFeatureValueNc(_FI_aListFs));}
+  public FSList getAListFs() { return (FSList)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aListFs)));}
     
   /** setter for aListFs - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAListFs(FSList v) {
-    _setFeatureValueNcWj(_FI_aListFs, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aListFs), v);
   }    
-    
-   
-    
+       
   //*--------------*
   //* Feature: aArrayFS
 
@@ -127,14 +131,14 @@
    * @generated
    * @return value of the feature 
    */
-  public FSArray getAArrayFS() { return (FSArray)(_getFeatureValueNc(_FI_aArrayFS));}
+  public FSArray getAArrayFS() { return (FSArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayFS)));}
     
   /** setter for aArrayFS - sets  
    * @generated
    * @param v value to set into the feature 
    */
   public void setAArrayFS(FSArray v) {
-    _setFeatureValueNcWj(_FI_aArrayFS, v);
+    _setFeatureValueNcWj(wrapGetIntCatchException(_FH_aArrayFS), v);
   }    
     
     
@@ -144,7 +148,7 @@
    * @return value of the element at index i 
    */
   public Annotation getAArrayFS(int i) {
-     return (Annotation)(((FSArray)(_getFeatureValueNc(_FI_aArrayFS))).get(i));} 
+     return (Annotation)(((FSArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayFS)))).get(i));} 
 
   /** indexed setter for aArrayFS - sets an indexed value - 
    * @generated
@@ -152,7 +156,7 @@
    * @param v value to set into the array 
    */
   public void setAArrayFS(int i, Annotation v) {
-    ((FSArray)(_getFeatureValueNc(_FI_aArrayFS))).set(i, v);
+    ((FSArray)(_getFeatureValueNc(wrapGetIntCatchException(_FH_aArrayFS)))).set(i, v);
   }  
   }
 
diff --git a/uimaj-json/src/test/resources/CasSerialization/expected/json/array-a1-not-a.txt b/uimaj-json/src/test/resources/CasSerialization/expected/json/array-a1-not-a.txt
index 3d77950..57de273 100644
--- a/uimaj-json/src/test/resources/CasSerialization/expected/json/array-a1-not-a.txt
+++ b/uimaj-json/src/test/resources/CasSerialization/expected/json/array-a1-not-a.txt
@@ -2,9 +2,9 @@
   "_views" : {
     "_InitialView" : {
       "RefTypes" : [
-        {"sofa" : 2,  "aArrayFS" : [3,  4,  5 ] },  3 ] } }, 
+        {"sofa" : 2,  "aArrayFS" : [3, 
+            {"_type" : "RefTypes",  "sofa" : 2 }, 
+            {"_type" : "RefTypes",  "sofa" : 2 } ] },  3 ] } }, 
   "_referenced_fss" : {
     "2" : {"_type" : "Sofa",  "sofaNum" : 1,  "sofaID" : "_InitialView" }, 
-    "3" : {"_type" : "RefTypes",  "sofa" : 2 }, 
-    "4" : {"_type" : "RefTypes",  "sofa" : 2 }, 
-    "5" : {"_type" : "RefTypes",  "sofa" : 2 } } }
\ No newline at end of file
+    "3" : {"_type" : "RefTypes",  "sofa" : 2 } } }
\ No newline at end of file
diff --git a/uimaj-json/src/test/resources/CasSerialization/expected/json/array-a2-not-a.txt b/uimaj-json/src/test/resources/CasSerialization/expected/json/array-a2-not-a.txt
index e05dc6a..02735de 100644
--- a/uimaj-json/src/test/resources/CasSerialization/expected/json/array-a2-not-a.txt
+++ b/uimaj-json/src/test/resources/CasSerialization/expected/json/array-a2-not-a.txt
@@ -2,9 +2,9 @@
   "_views" : {
     "_InitialView" : {
       "RefTypes" : [
-        {"sofa" : 2,  "aArrayFS" : [3,  4,  5 ] },  4 ] } }, 
+        {"sofa" : 2,  "aArrayFS" : [
+            {"_type" : "RefTypes",  "sofa" : 2 },  4, 
+            {"_type" : "RefTypes",  "sofa" : 2 } ] },  4 ] } }, 
   "_referenced_fss" : {
     "2" : {"_type" : "Sofa",  "sofaNum" : 1,  "sofaID" : "_InitialView" }, 
-    "3" : {"_type" : "RefTypes",  "sofa" : 2 }, 
-    "4" : {"_type" : "RefTypes",  "sofa" : 2 }, 
-    "5" : {"_type" : "RefTypes",  "sofa" : 2 } } }
\ No newline at end of file
+    "4" : {"_type" : "RefTypes",  "sofa" : 2 } } }
\ No newline at end of file
diff --git a/uimaj-json/src/test/resources/CasSerialization/expected/json/array-a3-not-a.txt b/uimaj-json/src/test/resources/CasSerialization/expected/json/array-a3-not-a.txt
index 40bfff7..6682bf2 100644
--- a/uimaj-json/src/test/resources/CasSerialization/expected/json/array-a3-not-a.txt
+++ b/uimaj-json/src/test/resources/CasSerialization/expected/json/array-a3-not-a.txt
@@ -2,9 +2,9 @@
   "_views" : {
     "_InitialView" : {
       "RefTypes" : [
-        {"sofa" : 2,  "aArrayFS" : [3,  4,  5 ] },  5 ] } }, 
+        {"sofa" : 2,  "aArrayFS" : [
+            {"_type" : "RefTypes",  "sofa" : 2 }, 
+            {"_type" : "RefTypes",  "sofa" : 2 },  5 ] },  5 ] } }, 
   "_referenced_fss" : {
     "2" : {"_type" : "Sofa",  "sofaNum" : 1,  "sofaID" : "_InitialView" }, 
-    "3" : {"_type" : "RefTypes",  "sofa" : 2 }, 
-    "4" : {"_type" : "RefTypes",  "sofa" : 2 }, 
     "5" : {"_type" : "RefTypes",  "sofa" : 2 } } }
\ No newline at end of file
diff --git a/uimaj-json/src/test/resources/CasSerialization/expected/json/array-all-embeddable-a.txt b/uimaj-json/src/test/resources/CasSerialization/expected/json/array-all-embeddable-a.txt
index eb4f3a7..74d13d8 100644
--- a/uimaj-json/src/test/resources/CasSerialization/expected/json/array-all-embeddable-a.txt
+++ b/uimaj-json/src/test/resources/CasSerialization/expected/json/array-all-embeddable-a.txt
@@ -2,9 +2,9 @@
   "_views" : {
     "_InitialView" : {
       "RefTypes" : [
-        {"sofa" : 2,  "aArrayFS" : [3,  4,  5 ] } ] } }, 
+        {"sofa" : 2,  "aArrayFS" : [
+            {"_type" : "RefTypes",  "sofa" : 2 }, 
+            {"_type" : "RefTypes",  "sofa" : 2 }, 
+            {"_type" : "RefTypes",  "sofa" : 2 } ] } ] } }, 
   "_referenced_fss" : {
-    "2" : {"_type" : "Sofa",  "sofaNum" : 1,  "sofaID" : "_InitialView" }, 
-    "3" : {"_type" : "RefTypes",  "sofa" : 2 }, 
-    "4" : {"_type" : "RefTypes",  "sofa" : 2 }, 
-    "5" : {"_type" : "RefTypes",  "sofa" : 2 } } }
\ No newline at end of file
+    "2" : {"_type" : "Sofa",  "sofaNum" : 1,  "sofaID" : "_InitialView" } } }
\ No newline at end of file
diff --git a/uimaj-json/src/test/resources/CasSerialization/expected/xmi/multipleViews.xml b/uimaj-json/src/test/resources/CasSerialization/expected/xmi/multipleViews.xml
index 2573f9f..9d85044 100644
--- a/uimaj-json/src/test/resources/CasSerialization/expected/xmi/multipleViews.xml
+++ b/uimaj-json/src/test/resources/CasSerialization/expected/xmi/multipleViews.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?><xmi:XMI xmlns:tcas="http:///uima/tcas.ecore" xmlns:xmi="http://www.omg.org/XMI" xmlns:cas="http:///uima/cas.ecore" xmlns:test="http:///org/apache/uima/test.ecore" xmi:version="2.0">
     <cas:NULL xmi:id="0"/>
-    <test:AllTypes xmi:id="2" sofa="1" begin="0" end="0" aBoolean="false" aByte="0" aShort="0" aInteger="1" aLong="4321" aFloat="NaN" aDouble="-Infinity" aString="some &quot;String&quot;" aFS="3" aArrayBoolean="" aArrayMrBoolean="12" aArrayMrByte="13" aArrayByte="" aArrayShort="0 0" aArrayMrShort="14" aArrayMrString="15" aListInteger="" aListFs="0">
+    <test:AllTypes xmi:id="2" sofa="1" begin="0" end="0" aBoolean="false" aByte="0" aShort="0" aInteger="1" aLong="4321" aFloat="NaN" aDouble="-Infinity" aString="some &quot;String&quot;" aFS="3" aArrayBoolean="" aArrayMrBoolean="12" aArrayMrByte="13" aArrayByte="" aArrayShort="0 0" aArrayMrShort="14" aArrayString="" aArrayMrString="15" aListInteger="" aListFs="0">
         <aListString>testStr</aListString>
     </test:AllTypes>
     <test:AllTypes xmi:id="22" sofa="1" begin="0" end="0" aBoolean="true" aByte="-117" aShort="-112" aInteger="0" aLong="1234" aFloat="1.3" aDouble="2.6" aString="some &quot;String&quot;" aFS="23" aArrayBoolean="false" aArrayMrBoolean="32" aArrayMrByte="33" aArrayByte="0FEE" aArrayShort="" aArrayMrShort="34" aArrayMrString="35" aListInteger="" aListFs="0">
diff --git a/uimaj-parent/pom.xml b/uimaj-parent/pom.xml
index 7ecc8eb..ce097e7 100644
--- a/uimaj-parent/pom.xml
+++ b/uimaj-parent/pom.xml
@@ -32,7 +32,7 @@
     <groupId>org.apache.uima</groupId>

     <artifactId>parent-pom</artifactId>

     <relativePath />

-    <version>10</version>

+    <version>11</version>

   </parent>

 

   <groupId>org.apache.uima</groupId>

@@ -53,13 +53,13 @@
        element, and just changing the following two properties -->

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-parent

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-parent

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-parent

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-parent

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-parent

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-parent

     </url>

   </scm>

 

@@ -139,25 +139,24 @@
   <properties>

     <uimaScmRoot>uimaj</uimaScmRoot>

     <uimaScmProject>${project.artifactId}</uimaScmProject>

-    <!-- 

-     BACKWARD_COMPATIBLE_IMPLEMENTER - patch version (=.=.+)

-     BACKWARD_COMPATIBLE_USER        - minor version (=.+.0)

-     NON_BACKWARD_COMPATIBLE         - major version (+.0.0)

-     -->

-    <compat.level>NON_BACKWARD_COMPATIBLE</compat.level>

-    <compat.previous.version>2.9.0</compat.previous.version>

 

     <!-- 

      Configuring settings is best done through default properties that multiple plugins.

      Local configurations within plugins should be avoided. Where plugins do not pick up default

      properties already, they should be injected manually into the plugins. 

-    -->    

-    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

+    --> 

+    <slf4j.version>1.7.25</slf4j.version>

+    <log4j.version>2.10.0</log4j.version>

+    <jackson.version>2.9.2</jackson.version>

+    

     <maven.compiler.target>1.8</maven.compiler.target>

     <maven.compiler.source>1.8</maven.compiler.source>

     <maven.surefire.heap>512m</maven.surefire.heap>

     <maven.surefire.argLine />

+    <maven.surefire.java9 />

+    

     <jacoco.argLine />

+    <api_check_oldVersion>2.10.2</api_check_oldVersion>

   </properties>

   

   <dependencyManagement>

@@ -168,6 +167,17 @@
         <version>4.12</version>

         <scope>test</scope>

       </dependency>

+      <!-- set dependency versions for logger parts -->

+      <dependency>

+        <groupId>org.slf4j</groupId>

+        <artifactId>slf4j-jdk14</artifactId>

+        <version>${slf4j.version}</version>

+      </dependency>

+      <dependency>

+        <groupId>org.slf4j</groupId>

+        <artifactId>slf4j-api</artifactId>

+        <version>${slf4j.version}</version>

+      </dependency>

     </dependencies>

   </dependencyManagement>

   

@@ -178,93 +188,27 @@
       <groupId>com.github.stephenc.findbugs</groupId>

       <artifactId>findbugs-annotations</artifactId>

       <version>1.3.9-1</version>

-      <scope>compile</scope>

+      <scope>provided</scope>

     </dependency>

   </dependencies>

   

   <build>

     <pluginManagement>

       <plugins>

+         

         <plugin>

-          <artifactId>maven-dependency-plugin</artifactId>

-          <version>2.9</version>

-        </plugin>

-        <plugin>

-          <artifactId>maven-compiler-plugin</artifactId>

-          <version>3.1</version>

-          <configuration>

-            <source>${maven.compiler.source}</source>

-            <target>${maven.compiler.target}</target>

-          </configuration>

-        </plugin>

-     

-        <plugin>

-          <groupId>org.apache.maven.plugins</groupId>

-          <artifactId>maven-javadoc-plugin</artifactId>

-          <configuration>

-            <source>8</source>

-          </configuration>

-          <executions>

-            <execution>

-              <id>attach-javadocs</id>

-              <configuration>

-                <source>${maven.compiler.source}</source>

-              </configuration> 

-            </execution>

-            <execution>

-              <id>default-cli</id>  <!-- Jenkins runs this apparently 3/2015 -->

-              <configuration>

-                <source>${maven.compiler.source}</source>

-              </configuration> 

-            </execution>

-          </executions>

+          <artifactId>maven-invoker-plugin</artifactId>

+          <version>3.0.1</version>

         </plugin>

         

         <plugin>

           <groupId>org.apache.maven.plugins</groupId>

           <artifactId>maven-surefire-plugin</artifactId>

-          <version>2.19.1</version>

           <configuration>

-            <argLine>@{jacoco.argLine} -Xmx${maven.surefire.heap} -Xms${maven.surefire.heap} ${maven.surefire.argLine}</argLine>

+            <argLine>@{jacoco.argLine} -Xmx@{maven.surefire.heap} -Xms@{maven.surefire.heap} @{maven.surefire.argLine} @{maven.surefire.java9}</argLine>

           </configuration>

         </plugin>

-        

-        <!-- Code quality checking plugins mostly used for CI builds -->

-        <plugin>

-          <groupId>org.apache.maven.plugins</groupId>

-          <artifactId>maven-pmd-plugin</artifactId>

-          <version>3.6</version>

-        </plugin>

-        <plugin>

-          <groupId>org.codehaus.mojo</groupId>

-          <artifactId>findbugs-maven-plugin</artifactId>

-          <version>3.0.3</version>

-        </plugin>

-        <plugin>

-          <groupId>org.codehaus.mojo</groupId>

-          <artifactId>cobertura-maven-plugin</artifactId>

-          <version>2.7</version>

-        </plugin>               

-        <plugin>

-          <groupId>org.jacoco</groupId>

-          <artifactId>jacoco-maven-plugin</artifactId>

-          <version>0.7.6.201602180812</version>

-        </plugin>

-        <plugin>

-          <groupId>org.apache.felix</groupId>

-          <artifactId>maven-bundle-plugin</artifactId>

-          <!-- version 2.0.0 fails -->

-          <!-- version 2.3.4 eliminates spurious warning messages -->

-          <!-- version 2.5 has accidental dependency on Java 6 -->

-          <!-- version 2.5.0 gives error - default pkg '.' not permitted, o.a.u.cas.impl -->

-          <!-- version 2.3.7 failing in some projects  -->  <!-- doesnt support java 8 -->

-             <!-- currently only overridden in uimaj-ep-configuration because otherwise, that is excluded from 

-                  update site plugins/ folder -->

-          <!--  version>3.0.1</version causes 2 plugins to go missing when FeaturesAndBundlesPublisher runs -->

-          <version>2.3.7</version> <!-- override to 3.0.1 just in those 2-3 projects that require it --> 

-                  

-        </plugin>

-        

+                

         <plugin>

           <groupId>org.apache.rat</groupId>

           <artifactId>apache-rat-plugin</artifactId>

@@ -278,31 +222,51 @@
               </configuration>

             </execution>

           </executions>

-        </plugin>       

+        </plugin>   

+        

+        <!-- https://issues.apache.org/jira/browse/UIMA-5367 -->

+        <plugin> 

+          <groupId>org.apache.maven.plugins</groupId> 

+          <artifactId>maven-deploy-plugin</artifactId>

+          <configuration> 

+            <retryFailedDeploymentCount>10</retryFailedDeploymentCount> 

+          </configuration> 

+        </plugin>

+         

       </plugins>

     </pluginManagement>

-    <plugins>

-      <plugin>

-        <artifactId>maven-enforcer-plugin</artifactId>

-        <executions>

-          <execution>

-            <id>enforce-versions</id>

-            <configuration>

-              <rules>

-                <requireMavenVersion>

-                  <version>3.0</version>

-                </requireMavenVersion>

-                <requireJavaVersion>

-                  <version>${maven.compiler.target}</version>

-                </requireJavaVersion>

-              </rules>

-            </configuration>

-          </execution>

-        </executions>

-      </plugin>

-    </plugins>

+    

   </build>

   <profiles>

+    <!-- ************ Java 9 enablement ************** -->

+    <profile>

+      <id>java9</id>

+      <activation>

+        <jdk>9</jdk>

+      </activation>

+      <properties>

+        <maven.surefire.java9>--add-modules java.xml.bind</maven.surefire.java9>

+      </properties>

+      <build>

+        <pluginManagement>

+          <plugins>

+            <plugin>

+              <groupId>org.apache.maven.plugins</groupId>

+              <artifactId>maven-compiler-plugin</artifactId>

+              <configuration>

+                <compilerArgs>

+                  <arg>--add-modules</arg>

+                  <arg>java.xml.bind</arg>

+                </compilerArgs>

+                <target>1.9</target>

+              </configuration>

+            </plugin>

+            

+          </plugins>

+        </pluginManagement>

+      </build>

+    </profile>

+    

     <profile>

       <id>pmd</id>

       <build>

@@ -420,6 +384,8 @@
         </plugins>

       </build>

     </profile>

+    

+    <!-- **********  Backwards compatibility report generation profile ************** -->

     <profile>

       <id>enforce-compatibility</id>

       <activation>

@@ -428,44 +394,88 @@
         </file>

       </activation>

       <build>

+

         <pluginManagement>

           <plugins>

             <plugin>

-              <artifactId>maven-enforcer-plugin</artifactId>

-              <dependencies>

-                <dependency>

-                  <groupId>org.semver</groupId>

-                  <artifactId>enforcer-rule</artifactId>

-                  <version>0.9.33</version>

-                </dependency>

-              </dependencies>

-              <executions>

-                <execution>

-                  <id>enforce-compatibility</id>

-                  <phase>verify</phase>

-                  <goals>

-                    <goal>enforce</goal>

-                  </goals>

-                  <configuration>

-                    <rules>

-                      <requireBackwardCompatibility implementation="org.semver.enforcer.RequireBackwardCompatibility">

-                        <previousVersion>${compat.previous.version}</previousVersion>

-                        <dumpDetails>true</dumpDetails>

-                        <compatibilityType>${compat.level}</compatibilityType>

-                        <excludes>

-                          <exclude>**/impl/**/*</exclude>

-                          <exclude>**/internal/**/*</exclude>

-                        </excludes>

-                      </requireBackwardCompatibility>

-                    </rules>

-                  </configuration>

-                </execution>

-              </executions>

-            </plugin>

+	            <groupId>org.apache.rat</groupId>

+		          <artifactId>apache-rat-plugin</artifactId>

+              <version>${rat.version}</version>

+		          <executions>

+		            <execution>

+		              <id>default-cli</id>

+		              <configuration>

+		                <excludes combine.children="append">

+	                    <exclude>**/api-change-report/**/*.*</exclude>

+		                </excludes>

+		              </configuration>

+		            </execution>

+	          </executions>

+	          </plugin>

           </plugins>

         </pluginManagement>

+         

+        <plugins>

+          <!-- https://siom79.github.io/japicmp/MavenPlugin.html -->

+          <plugin>              

+            <groupId>com.github.siom79.japicmp</groupId>

+            <artifactId>japicmp-maven-plugin</artifactId>

+            <version>0.9.4</version>

+            <configuration>

+              <!--  fixed in 0.94 -->

+              <oldVersion>

+                <dependency>

+                  <groupId>${project.groupId}</groupId>

+                  <artifactId>${project.artifactId}</artifactId>

+                  <version>${api_check_oldVersion}</version>

+                </dependency>

+              </oldVersion> 

+              <parameter>

+                <onlyModified>true</onlyModified>

+                <!-- filter out classes with impl in their package or class name -->

+                <postAnalysisScript>${project.basedir}/../uimaj-parent/src/main/groovy/api-report.groovy</postAnalysisScript>                  

+              </parameter>

+            </configuration>

+            <executions>

+              <execution>

+                <phase>verify</phase>

+                <goals>

+                  <goal>cmp</goal>

+                </goals>

+              </execution>

+            </executions>

+          </plugin>

+          

+          <!-- This copy is to have the api change report included in the source distribution -->

+          <plugin>

+            <artifactId>maven-antrun-plugin</artifactId>

+            <executions>

+              <execution>

+                <id>copy-API-change-report</id>

+                <phase>install</phase>  <!-- must follow verify -->

+                <goals><goal>run</goal></goals>

+                <configuration>

+                  <target>

+                    <taskdef name="if" classname="net.sf.antcontrib.logic.IfTask" />

+                    <if>

+                      <available file="${project.build.directory}/japicmp/" />

+                      <then>

+                        <copy toDir="${basedir}/api-change-report">

+                          <fileset dir="${project.build.directory}/japicmp" />

+                        </copy>

+                      </then>

+                    </if>

+                  </target>

+                </configuration>

+              </execution>

+            </executions>

+            

+          </plugin>

+        </plugins>

       </build>

     </profile>

+    

+    <!-- ************** m2e  profile ************* -->

     <profile>

       <id>m2e</id>

       <activation>

@@ -475,9 +485,8 @@
       </activation>

       <build>

         <pluginManagement>

-          <plugins>

-          

-            <!--This plugin's configuration is used to store Eclipse m2e settings 

+          <plugins>         

+            <!-- This plugin's configuration is used to store Eclipse m2e settings 

                 only. It has no influence on the Maven build itself. -->

             <plugin>

               <groupId>org.eclipse.m2e</groupId>

diff --git a/uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP_Type.java b/uimaj-parent/src/main/groovy/api-report.groovy
similarity index 72%
rename from uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP_Type.java
rename to uimaj-parent/src/main/groovy/api-report.groovy
index 92d15c7..1a5df66 100644
--- a/uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP_Type.java
+++ b/uimaj-parent/src/main/groovy/api-report.groovy
@@ -16,14 +16,15 @@
  * specific language governing permissions and limitations

  * under the License.

  */

-

-package org.apache.uima.jcas.cas;

-

-

-

-// *********************************

-// * Implementation of TOP_Type    *

-// * Only for supporting decompiling of v2 JCas classes

-// *********************************

-

-public class TOP_Type {}

+  def it = jApiClasses.iterator()

+  while (it.hasNext()) {

+    def jApiClass = it.next()

+    def fqn = jApiClass.getFullyQualifiedName()

+    if (fqn.contains(".impl.") || 

+        fqn.contains(".internal.") ||

+        fqn.endsWith("_Type") 

+       ) {

+      it.remove()

+    }

+  }  

+  return jApiClasses
\ No newline at end of file
diff --git a/uimaj-test-util/pom.xml b/uimaj-test-util/pom.xml
index 407b698..56ce83c 100644
--- a/uimaj-test-util/pom.xml
+++ b/uimaj-test-util/pom.xml
@@ -44,13 +44,13 @@
        element, and just changing the following two properties -->  

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/jvinci

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/jvinci

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/jvinci

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/jvinci

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/jvinci

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/jvinci

     </url>

   </scm>

   

diff --git a/uimaj-tools/pom.xml b/uimaj-tools/pom.xml
index 366d1e8..fc49145 100644
--- a/uimaj-tools/pom.xml
+++ b/uimaj-tools/pom.xml
@@ -43,13 +43,13 @@
        element, and just changing the following two properties -->  

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-tools

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-tools

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-tools

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-tools

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-tools

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-tools

     </url>

   </scm>

   

@@ -76,7 +76,13 @@
 			<artifactId>uimaj-test-util</artifactId>

 			<version>${project.parent.version}</version>

 			<scope>test</scope>

-		</dependency>    

+		</dependency>  

+    <dependency>

+      <groupId>org.slf4j</groupId>

+      <artifactId>slf4j-jdk14</artifactId>

+      <scope>test</scope>

+    </dependency>

+      

 	</dependencies>

 	<build>

 		<finalName>uima-tools</finalName>

diff --git a/uimaj-tools/src/main/java/org/apache/uima/tools/components/XmlDetagger.java b/uimaj-tools/src/main/java/org/apache/uima/tools/components/XmlDetagger.java
index a906501..d6e9845 100644
--- a/uimaj-tools/src/main/java/org/apache/uima/tools/components/XmlDetagger.java
+++ b/uimaj-tools/src/main/java/org/apache/uima/tools/components/XmlDetagger.java
@@ -23,6 +23,7 @@
 import java.net.URL;
 import java.util.Iterator;
 
+import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
 
@@ -35,11 +36,14 @@
 import org.apache.uima.cas.FeatureStructure;
 import org.apache.uima.cas.Type;
 import org.apache.uima.cas.TypeSystem;
+import org.apache.uima.internal.util.XMLUtils;
 import org.apache.uima.resource.ResourceInitializationException;
 import org.apache.uima.util.InvalidXMLException;
 import org.apache.uima.util.XMLInputSource;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
 import org.xml.sax.helpers.DefaultHandler;
 
 /**
@@ -57,7 +61,7 @@
    */
   public static final String PARAM_TEXT_TAG = "XmlTagContainingText";
   
-  private SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+  private SAXParserFactory parserFactory = XMLUtils.createSAXParserFactory();
 
   private Type sourceDocInfoType;
 
diff --git a/uimaj-tools/src/main/java/org/apache/uima/tools/cvd/MainFrame.java b/uimaj-tools/src/main/java/org/apache/uima/tools/cvd/MainFrame.java
index 349baa0..51f3b07 100644
--- a/uimaj-tools/src/main/java/org/apache/uima/tools/cvd/MainFrame.java
+++ b/uimaj-tools/src/main/java/org/apache/uima/tools/cvd/MainFrame.java
@@ -100,6 +100,7 @@
 import org.apache.uima.cas.impl.CASImpl;

 import org.apache.uima.cas.impl.XmiCasDeserializer;

 import org.apache.uima.internal.util.Timer;

+import org.apache.uima.internal.util.XMLUtils;

 import org.apache.uima.resource.ResourceManager;

 import org.apache.uima.resource.ResourceSpecifier;

 import org.apache.uima.tools.cpm.PerformanceReportDialog;

@@ -724,7 +725,8 @@
       setXcasFileOpenDir(xmiCasFile.getParentFile());

       Timer time = new Timer();

       time.start();

-      SAXParser parser = SAXParserFactory.newInstance().newSAXParser();

+      SAXParserFactory saxParserFactory = XMLUtils.createSAXParserFactory();

+      SAXParser parser = saxParserFactory.newSAXParser();

       XmiCasDeserializer xmiCasDeserializer = new XmiCasDeserializer(getCas().getTypeSystem());

       getCas().reset();

       parser.parse(xmiCasFile, xmiCasDeserializer.getXmiCasHandler(getCas(), true));

diff --git a/uimaj-tools/src/main/java/org/apache/uima/tools/cvd/control/XCASFileOpenEventHandler.java b/uimaj-tools/src/main/java/org/apache/uima/tools/cvd/control/XCASFileOpenEventHandler.java
index 796249b..a16655e 100644
--- a/uimaj-tools/src/main/java/org/apache/uima/tools/cvd/control/XCASFileOpenEventHandler.java
+++ b/uimaj-tools/src/main/java/org/apache/uima/tools/cvd/control/XCASFileOpenEventHandler.java
@@ -30,6 +30,7 @@
 
 import org.apache.uima.cas.impl.XCASDeserializer;
 import org.apache.uima.internal.util.Timer;
+import org.apache.uima.internal.util.XMLUtils;
 import org.apache.uima.tools.cvd.MainFrame;
 
 
@@ -72,7 +73,8 @@
           this.main.setXcasFileOpenDir(xcasFile.getParentFile());
           Timer time = new Timer();
           time.start();
-          SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
+          SAXParserFactory saxParserFactory = XMLUtils.createSAXParserFactory();
+          SAXParser parser = saxParserFactory.newSAXParser();
           XCASDeserializer xcasDeserializer = new XCASDeserializer(this.main.getCas()
               .getTypeSystem());
           this.main.getCas().reset();
diff --git a/uimaj-tools/src/main/java/org/apache/uima/tools/docanalyzer/AnnotationViewerDialog.java b/uimaj-tools/src/main/java/org/apache/uima/tools/docanalyzer/AnnotationViewerDialog.java
index dc00565..3d625ae 100644
--- a/uimaj-tools/src/main/java/org/apache/uima/tools/docanalyzer/AnnotationViewerDialog.java
+++ b/uimaj-tools/src/main/java/org/apache/uima/tools/docanalyzer/AnnotationViewerDialog.java
@@ -55,13 +55,16 @@
 import javax.swing.JPanel;
 import javax.swing.JRadioButton;
 import javax.swing.JScrollPane;
+import javax.swing.JTextField;
 import javax.swing.ListCellRenderer;
 import javax.swing.SpringLayout;
 import javax.swing.UIManager;
 import javax.swing.UnsupportedLookAndFeelException;
 import javax.swing.WindowConstants;
+import javax.swing.border.EmptyBorder;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
 import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.FactoryConfigurationError;
 import javax.xml.parsers.ParserConfigurationException;
 
@@ -72,6 +75,7 @@
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.TypeSystem;
 import org.apache.uima.internal.util.BrowserUtil;
+import org.apache.uima.internal.util.XMLUtils;
 import org.apache.uima.resource.ResourceInitializationException;
 import org.apache.uima.tools.images.Images;
 import org.apache.uima.tools.stylemap.ColorParser;
@@ -120,9 +124,9 @@
   /** The style map file. */
   private File styleMapFile;
 
-  /** The analyzed results list. */
-  JList analyzedResultsList;
-
+  /** the list of analyzed results */
+  JList<String> analyzedResultsList;
+  
   /** The input dir path. */
   String inputDirPath = null;
 
@@ -185,6 +189,19 @@
             tempDir);
   }
 
+  private void resetFiles(String filenameFilter) {
+    File dir = new File(inputDirPath);
+    // Select documents via filter. JMP
+    final InteractiveFilter iFilter = new InteractiveFilter(filenameFilter);
+    String[] documents = dir.list(iFilter);
+    //create an empty array to display
+    if(documents == null) {
+      documents = new String[] {};
+    }
+
+    analyzedResultsList.setListData(documents);
+  }
+
   /**
    * Instantiates a new annotation viewer dialog.
    *
@@ -224,15 +241,9 @@
 
     // create an jlist to list the the analyzed documents
     inputDirPath = med.getOutputDir();
-    File dir = new File(inputDirPath);
-    // Select documents via filter. JMP
-    FilenameFilter iFilter = new InteractiveFilter();
-    String[] documents = dir.list(iFilter);
-    //create an empty array to display
-    if(documents == null) {
-       documents = new String[] {};
-    }
-    analyzedResultsList = new JList(documents);
+    analyzedResultsList = new JList<>();
+    resetFiles("");
+
     /*
      * File[] documents = dir.listFiles(); Vector docVector = new Vector(); for (int i = 0; i <
      * documents.length; i++) { if (documents[i].isFile()) { docVector.add(documents[i].getName()); } }
@@ -244,6 +255,30 @@
     JPanel southernPanel = new JPanel();
     southernPanel.setLayout(new BoxLayout(southernPanel, BoxLayout.Y_AXIS));
 
+    JPanel filterPanel = new JPanel();
+    filterPanel.setLayout(new BoxLayout(filterPanel, BoxLayout.X_AXIS));
+    filterPanel.add(new JLabel("Filter: Filename contains "));
+    final JTextField filenameFilter = new JTextField();
+    filenameFilter.getDocument().addDocumentListener(new DocumentListener() {
+      @Override
+      public void insertUpdate(DocumentEvent e) {
+        resetFiles(filenameFilter.getText());
+      }
+
+      @Override
+      public void removeUpdate(DocumentEvent e) {
+        resetFiles(filenameFilter.getText());
+      }
+
+      @Override
+      public void changedUpdate(DocumentEvent e) {
+        resetFiles(filenameFilter.getText());
+      }
+    });
+    filterPanel.add(filenameFilter);
+    filterPanel.setBorder(new EmptyBorder(4, 4, 4, 4));
+    southernPanel.add(filterPanel);
+
     JPanel controlsPanel = new JPanel();
     controlsPanel.setLayout(new SpringLayout());
 
@@ -393,6 +428,12 @@
    * Filter to not show the two interactive-mode directories in the file list.
    */
   static class InteractiveFilter implements FilenameFilter {
+   
+    private final String filenameFilter;
+
+    public InteractiveFilter(String filenameFilter) {
+      this.filenameFilter = filenameFilter;
+    }
     
     /* (non-Javadoc)
      * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
@@ -403,6 +444,8 @@
         return false;
       if (name.equals("interactive_out"))
         return false;
+      if (!name.isEmpty())
+        return name.contains(filenameFilter);  
       return true;
     }
   }
@@ -590,7 +633,7 @@
       Document parse = null;
       try {
         stream = new FileInputStream(aStyleMapFile);
-        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+        DocumentBuilder db = XMLUtils.createDocumentBuilderFactory().newDocumentBuilder();
         parse = db.parse(stream);
       } catch (FileNotFoundException e) {
         throw new UIMARuntimeException(e);
diff --git a/uimaj-tools/src/main/java/org/apache/uima/tools/jcasgen/JCasTypeTemplate.java b/uimaj-tools/src/main/java/org/apache/uima/tools/jcasgen/JCasTypeTemplate.java
index 70b3247..47d01b9 100644
--- a/uimaj-tools/src/main/java/org/apache/uima/tools/jcasgen/JCasTypeTemplate.java
+++ b/uimaj-tools/src/main/java/org/apache/uima/tools/jcasgen/JCasTypeTemplate.java
@@ -23,16 +23,8 @@
 import org.apache.uima.resource.metadata.TypeDescription;
 import org.apache.uima.resource.metadata.FeatureDescription;
 
-
-/**
- * The Class JCasTypeTemplate.
- */
 public class JCasTypeTemplate implements Jg.IJCasTypeTemplate {
 
-  /* (non-Javadoc)
-   * @see org.apache.uima.tools.jcasgen.Jg.IJCasTypeTemplate#generate(java.lang.Object)
-   */
-  @Override
   public String generate(Object argument) {
     StringBuilder stringBuilder = new StringBuilder();
 
@@ -52,7 +44,7 @@
    else 
      jg.error.newError(IError.WARN, 
 		jg.getString("pkgMissing", new Object[] {td.getName()}), null); 
-    stringBuilder.append("\nimport org.apache.uima.cas.impl.CASImpl;\nimport org.apache.uima.cas.impl.TypeImpl;\nimport org.apache.uima.cas.impl.TypeSystemImpl;\nimport org.apache.uima.jcas.JCas; \nimport org.apache.uima.jcas.JCasRegistry;\n\n\n");
+    stringBuilder.append("\nimport java.lang.invoke.CallSite;\nimport java.lang.invoke.MethodHandle;\n\nimport org.apache.uima.cas.impl.CASImpl;\nimport org.apache.uima.cas.impl.TypeImpl;\nimport org.apache.uima.cas.impl.TypeSystemImpl;\nimport org.apache.uima.jcas.JCas; \nimport org.apache.uima.jcas.JCasRegistry;\n\n\n");
    for(Iterator i=jg.collectImports(td, false).iterator(); i.hasNext();) { 
     stringBuilder.append("import ");
     stringBuilder.append((String)i.next());
@@ -99,8 +91,12 @@
      String elemType = jg.getJavaRangeArrayElementType(fd);
      
      localData   .append("  public final static String _FeatName_").append(featName).append(" = \"").append(featName).append("\";\n");
-     featRegistry.append("  public final static int _FI_").append(featName).append(" = TypeSystemImpl.getAdjustedFeatureOffset(\"")
-                 .append(featName).append("\");\n");   
+     
+     featRegistry.append("  private final static CallSite _FC_").append(featName)
+                 .append(" = TypeSystemImpl.createCallSite(").append(typeName).append(".class, ")
+                 .append("\"").append(featName).append("\");\n"); 
+     featRegistry.append("  private final static MethodHandle _FH_").append(featName)
+                 .append(" = _FC_").append(featName).append(".dynamicInvoker();\n"); 
       
    } /* of Features iteration */ 
     stringBuilder.append("\n  /* *******************\n   *   Feature Offsets *\n   * *******************/ \n   \n");
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 8666ebf..9ed718c 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
@@ -52,11 +52,11 @@
 
 import org.apache.uima.UIMAFramework;
 import org.apache.uima.analysis_engine.AnalysisEngineDescription;
-import org.apache.uima.cas.BuiltinTypeKinds;
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.Feature;
 import org.apache.uima.cas.Type;
 import org.apache.uima.cas.TypeSystem;
+import org.apache.uima.cas.impl.BuiltinTypeKinds;
 import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeImpl_string;
@@ -81,8 +81,9 @@
 
 public class Jg {
 
+  private final static boolean IS_TRACE_LIMITED = false;
   /**
-   * Interface implemeted by JCAS code generation's templates.
+   * Interface implemented by JCAS code generation's templates.
    */
   public interface IJCasTypeTemplate {
     
@@ -102,7 +103,7 @@
   static final FeatureDescription[] featureDescriptionArray0 = new FeatureDescription[0];
 
   /** The Constant reservedFeatureNames. */
-  static final Collection reservedFeatureNames = new ArrayList();
+  static final Collection<String> reservedFeatureNames = new ArrayList<>();
   {
 
     reservedFeatureNames.add("Address");
@@ -125,7 +126,7 @@
    * Set of types not generated from the CAS type set because they're already in existence as
    * builtins in the JCas impl. and if they're generated, the generated forms are wrong.
    */
-  static final Set noGenTypes = new HashSet();
+  static final Set<String> noGenTypes = new HashSet<>();
 
   /** The Constant casCreateProperties. */
   public static final Properties casCreateProperties = new Properties();
@@ -134,7 +135,7 @@
   }
 
   /** The Constant extendableBuiltInTypes. */
-  static final Map extendableBuiltInTypes = new HashMap();
+  static final Map<String, FeatureDescription[]> extendableBuiltInTypes = new HashMap<>();
 
   // create a hash map of built-in types, where the
   // key is the fully-qualified name "uima.tcas.Annotation"
@@ -161,8 +162,13 @@
     ((CASImpl) tcas).commitTypeSystem();
     builtInTypeSystem = ((CASImpl) tcas).getTypeSystemImpl();  // follow commit because commit may reuse existing type system
 
-    for (Iterator it = builtInTypeSystem.getTypeIterator(); it.hasNext();) {
-      Type type = (Type) it.next();
+    // setup noGen for semibuiltin types 
+    noGenTypes.add("org.apache.uima.jcas.cas.FSArrayList");
+    noGenTypes.add("org.apache.uima.jcas.cas.IntegerArrayList");
+    noGenTypes.add("org.apache.uima.jcas.cas.FSHashSet");
+    
+    for (Iterator<Type> it = builtInTypeSystem.getTypeIterator(); it.hasNext();) {
+      Type type = it.next();
       if (type.isFeatureFinal()) {
         noGenTypes.add(type.getName());
         continue;  // skip if feature final
@@ -283,10 +289,10 @@
 
   /** The imports. */
   // Instance fields
-  final Map imports = new HashMap(); // can't be final - one per instance running
+  final Map<String, String> imports = new HashMap<>(); // can't be final - one per instance running
 
   /** The imports. */
-  final Map _imports = new HashMap();
+  final Map<String, String> _imports = new HashMap<>();
 
   /** The class path. */
   String classPath = "";
@@ -456,21 +462,21 @@
    * @param outputDirectory the output directory
    * @param tds the tds
    * @param aCas the a cas
-   * @param projectPathDir the project path dir
-   * @param limitJCasGenToProjectScope the limit J cas gen to project scope
-   * @param mergedTypesAddingFeatures the merged types adding features
+   * @param pProjectPathDir the project path dir
+   * @param limitToProjectScope the limit J cas gen to project scope
+   * @param pMergedTypesAddingFeatures the merged types adding features
    * @throws IOException Signals that an I/O exception has occurred.
    */
   public void mainForCde(IMerge aMerger, IProgressMonitor aProgressMonitor, IError aError,
           String inputFile, String outputDirectory, TypeDescription[] tds, CASImpl aCas, 
-          String projectPathDir, boolean limitJCasGenToProjectScope, 
-          Map<String, Set<String>> mergedTypesAddingFeatures)
+          String pProjectPathDir, boolean limitToProjectScope, 
+          Map<String, Set<String>> pMergedTypesAddingFeatures)
           throws IOException {
     try {
       // Generate type classes by using DEFAULT templates
       mainGenerateAllTypesFromTemplates(aMerger, aProgressMonitor, aError, inputFile,
               outputDirectory, tds, aCas, JCasTypeTemplate.class,
-              projectPathDir, limitJCasGenToProjectScope, mergedTypesAddingFeatures);
+              pProjectPathDir, limitToProjectScope, pMergedTypesAddingFeatures);
       // convert thrown things to IOExceptions to avoid changing API for this
       // FIXME later
     } catch (InstantiationException e) {
@@ -499,8 +505,8 @@
   // use template classes to generate code
   public void mainGenerateAllTypesFromTemplates(IMerge aMerger, IProgressMonitor aProgressMonitor,
       IError aError, String inputFile, String outputDirectory, TypeDescription[] tds,
-      CASImpl aCas, Class jcasTypeClass, // Template class
-      Class jcas_TypeClass) // Template class
+      CASImpl aCas, Class<JCasTypeTemplate> jcasTypeClass, // Template class
+      Class<JCasTypeTemplate> jcas_TypeClass) // Template class
       throws IOException, InstantiationException, IllegalAccessException {
     mainGenerateAllTypesFromTemplates(aMerger, aProgressMonitor, 
              aError, inputFile, outputDirectory, tds, aCas, 
@@ -518,26 +524,26 @@
    * @param tds the tds
    * @param aCas the a cas
    * @param jcasTypeClass the jcas type class
-   * @param projectPathDir the project path dir
-   * @param limitJCasGenToProjectScope the limit J cas gen to project scope
-   * @param mergedTypesAddingFeatures the merged types adding features
+   * @param pProjectPathDir the project path dir
+   * @param limitToProjectScope the limit J cas gen to project scope
+   * @param pMergedTypesAddingFeatures the merged types adding features
    * @throws IOException Signals that an I/O exception has occurred.
    * @throws InstantiationException the instantiation exception
    * @throws IllegalAccessException the illegal access exception
    */
   public void mainGenerateAllTypesFromTemplates(IMerge aMerger, IProgressMonitor aProgressMonitor,
           IError aError, String inputFile, String outputDirectory, TypeDescription[] tds,
-          CASImpl aCas, Class jcasTypeClass, // Template class
-          String projectPathDir, boolean limitJCasGenToProjectScope,
-          Map<String, Set<String>> mergedTypesAddingFeatures) // Template class
+          CASImpl aCas, Class<JCasTypeTemplate> jcasTypeClass, // Template class
+          String pProjectPathDir, boolean limitToProjectScope,
+          Map<String, Set<String>> pMergedTypesAddingFeatures) // Template class
           throws IOException, InstantiationException, IllegalAccessException {
     this.merger = aMerger;
     this.error = aError;
     this.progressMonitor = aProgressMonitor;
     xmlSourceFileName = inputFile.replaceAll("\\\\", "/");
-    this.projectPathDir = projectPathDir;
-    this.limitJCasGenToProjectScope = limitJCasGenToProjectScope;
-    this.mergedTypesAddingFeatures = mergedTypesAddingFeatures;
+    this.projectPathDir = pProjectPathDir;
+    this.limitJCasGenToProjectScope = limitToProjectScope;
+    this.mergedTypesAddingFeatures = pMergedTypesAddingFeatures;
 
     // Generate type classes by using SPECIFIED templates
     generateAllTypesFromTemplates(outputDirectory, tds, aCas, jcasTypeClass);
@@ -742,23 +748,19 @@
    * @return the string
    */
   // message: TypeName = ".....", URLs defining this type = "xxxx", "xxxx", ....
-  private String makeMergeMessage(Map m) {
+  private String makeMergeMessage(Map<String, Set<String>> m) {
     StringBuffer sb = new StringBuffer();
-    for (Iterator it = m.entrySet().iterator(); it.hasNext();) {
-      Map.Entry entry = (Map.Entry) it.next();
-      String typeName = (String) entry.getKey();
+    for (Map.Entry<String, Set<String>> entry :  m.entrySet()) {
+      String typeName = entry.getKey();
       sb.append("\n  ");
       sb.append("TypeName having merged features = ").append(typeName).append(
               "\n    URLs defining this type =");
-      Set urls = (Set) entry.getValue();
+      Set<String> urls = entry.getValue();
       boolean afterFirst = false;
-      for (Iterator itUrls = urls.iterator(); itUrls.hasNext();) {
-        if (afterFirst)
-          sb.append(",\n        ");
-        else
-          sb.append("\n        ");
+      for (String url : urls) {
+        sb.append(afterFirst ? ',' : "")
+          .append("\n        \"");
         afterFirst = true;
-        String url = (String) itUrls.next();
         sb.append('"').append(url).append('"');
       }
     }
@@ -778,13 +780,13 @@
    */
   // This is also the interface for CDE
   private void generateAllTypesFromTemplates(String outputDirectory, TypeDescription[] tds,
-          CASImpl aCas, Class jcasTypeClass) throws IOException,
+          CASImpl aCas, Class<JCasTypeTemplate> jcasTypeClass) throws IOException,
           InstantiationException, IllegalAccessException {
 
     // Create instances of Template classes
     IJCasTypeTemplate jcasTypeInstance = (IJCasTypeTemplate) jcasTypeClass.newInstance();
 
-    Set generatedBuiltInTypes = new TreeSet();
+    Set<String> generatedBuiltInTypes = new TreeSet<>();
 
     this.cas = aCas;
     this.typeSystem = cas.getTypeSystem();
@@ -817,7 +819,7 @@
               .getName());
       if (null != builtInFeatures) {
         generatedBuiltInTypes.add(td.getName());
-        List newFeatures = setDifference(td.getFeatures(), builtInFeatures);
+        List<FeatureDescription> newFeatures = setDifference(td.getFeatures(), builtInFeatures);
         int newFeaturesSize = newFeatures.size();
         if (newFeaturesSize > 0) {
           int newSize = builtInFeatures.length + newFeaturesSize;
@@ -879,7 +881,7 @@
    */
 
   /**
-   * return true if td is not defined in this project, of
+   * return true if td is not defined in this project, or
    *   it is defined, but is also in merged and any of the other
    *   merged urls are not defined in this project.
    *
@@ -892,6 +894,9 @@
     try {
       typeDefinitionUri = new URI (td.getSourceUrlString());
     } catch (URISyntaxException e) {
+      if (IS_TRACE_LIMITED) {
+        error.newError(IError.INFO, "debug isOutOfScope: got URISyntaxException, td.getSourceUrlstring: " + ((td.getSourceUrlString() == null) ? "null" : td.getSourceUrlString()), e);
+      }
       return true; // may be overkill - but if td's source can't be parsed ... likely out of project
     }
     String tdPath = typeDefinitionUri.getPath();
@@ -899,6 +904,9 @@
     // Issue UIMA-4080 - If a type system resides in a JAR, then the path is null and it is
     // certainly out of scope.
     if (tdPath == null) {
+      if (IS_TRACE_LIMITED) {
+        error.newError(IError.INFO, "debug isOutOfScope: typeDefinitionUri had null path. " + typeDefinitionUri.toString(), null);
+      }
         return true;
     }
 
@@ -909,7 +917,7 @@
     // as well as clients that use file-system notation (e.g. jcasgen-maven-plugin or a simple
     // invocation from the command line.
     String resolvedProjectPath;
-    if (!projectDirPath.startsWith("/")) {
+    if (!projectDirPath.startsWith("/")) { 
         resolvedProjectPath = new File(projectDirPath).getAbsoluteFile().toURI().getPath();
     }
     else {
@@ -928,6 +936,10 @@
 
     boolean r = !tdPath.startsWith(resolvedProjectPath);
     if (r) {
+      if (IS_TRACE_LIMITED) {
+        error.newError(IError.INFO, "debug isOutOfScope: tdPath doesn't start with resolved ProjectPath, tdPath: "
+             + tdPath + ", resolvedProjectPath: " + resolvedProjectPath, null);
+      }
       return true;
     }
     Set<String> mergedPaths = mergedTypesAddingFeatures.get(td.getName());
@@ -941,6 +953,9 @@
         }
         String tempPath = tempURI.getPath();
         if (!tempPath.startsWith(resolvedProjectPath)) {
+          if (IS_TRACE_LIMITED) {
+            error.newError(IError.INFO, "debug isOutOfScope due to mergedType adding feature", null);
+          }
           return true; 
         }
       }
@@ -1156,7 +1171,7 @@
   }
 
   /** The non importable java names. */
-  private static ArrayList nonImportableJavaNames = new ArrayList(8);
+  private static ArrayList<String> nonImportableJavaNames = new ArrayList<>(8);
   static {
     nonImportableJavaNames.add("String");
     nonImportableJavaNames.add("float");
@@ -1203,7 +1218,7 @@
    * @param _Type the type
    * @return the collection
    */
-  Collection collectImports(TypeDescription td, boolean _Type) {
+  Collection<String> collectImports(TypeDescription td, boolean _Type) {
     if (_Type)
       _imports.clear();
     else
@@ -1397,9 +1412,10 @@
     String v = ", v";
 //    if (get_set.equals("set") && range.equals("Feature"))
 //      v = ", jcasType.ll_cas.ll_getFSRef(v)";
-    boolean isInInt = ! (range.equals("String") || range.equals("Feature") || range.equals("JavaObject"));
+//    boolean isInInt = ! (range.equals("String") || range.equals("Feature") || range.equals("JavaObject"));
     String chksfx = getCheckSuffix(get_set, range);
-    String featOrOffset = "_FI_" + fname;
+    //wrapGetIntCatchException(_FH_begin)
+    String featOrOffset = "wrapGetIntCatchException(_FH_" + fname + ")";
     return "_" + get_set + range + "Value" + chksfx + "(" + featOrOffset  +
         ((get_set.equals("set")) ? v : "") + ")";
   }
@@ -1556,10 +1572,15 @@
   public ResourceManager createResourceManager() {
     ResourceManager resourceManager = UIMAFramework.newDefaultResourceManager();
 
-    try {
-      resourceManager.setExtensionClassPath(this.getClass().getClassLoader(), classPath, true);
-    } catch (MalformedURLException e1) {
-      error.newError(IError.ERROR, getString("Internal Error", null), e1);
+    if (classPath != null && classPath.trim().length() > 0) {
+      try {
+        resourceManager.setExtensionClassPath(this.getClass().getClassLoader(), classPath, true);
+      } catch (MalformedURLException e1) {
+        error.newError(IError.ERROR, getString("Internal Error", null), e1);
+      }
+    }
+    else {
+        resourceManager.setExtensionClassLoader(this.getClass().getClassLoader(), true);
     }
     return resourceManager;
   }
@@ -1573,8 +1594,8 @@
    */
   private TypeSystemDescription mergeTypeSystemImports(TypeSystemDescription tsd)
           throws ResourceInitializationException {
-    Collection tsdc = new ArrayList(1);
-    tsdc.add(tsd.clone());
+    Collection<TypeSystemDescription> tsdc = new ArrayList<>(1);
+    tsdc.add((TypeSystemDescription) tsd.clone());
     mergedTypesAddingFeatures.clear();
     TypeSystemDescription mergedTsd = CasCreationUtils.mergeTypeSystems(tsdc,
             createResourceManager(), mergedTypesAddingFeatures);
@@ -1588,8 +1609,8 @@
    * @param alreadyDefinedFeatures the already defined features
    * @return the list
    */
-  List setDifference(FeatureDescription[] newFeatures, FeatureDescription[] alreadyDefinedFeatures) {
-    List result = new ArrayList();
+  List<FeatureDescription> setDifference(FeatureDescription[] newFeatures, FeatureDescription[] alreadyDefinedFeatures) {
+    List<FeatureDescription> result = new ArrayList<>();
     outerLoop: for (int i = 0; i < newFeatures.length; i++) {
       for (int j = 0; j < alreadyDefinedFeatures.length; j++) {
         if (isSameFeatureDescription(newFeatures[i], alreadyDefinedFeatures[j]))
diff --git a/uimaj-tools/src/main/java/org/apache/uima/tools/stylemap/StyleMapXmlParser.java b/uimaj-tools/src/main/java/org/apache/uima/tools/stylemap/StyleMapXmlParser.java
index 2ee2404..ef15390 100644
--- a/uimaj-tools/src/main/java/org/apache/uima/tools/stylemap/StyleMapXmlParser.java
+++ b/uimaj-tools/src/main/java/org/apache/uima/tools/stylemap/StyleMapXmlParser.java
@@ -28,6 +28,7 @@
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
 
+import org.apache.uima.internal.util.XMLUtils;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
@@ -71,7 +72,9 @@
   public StyleMapXmlParser(String xmlFile) {
     try {
       // create new SAX Parser
-      SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
+      SAXParserFactory saxParserFactory = XMLUtils.createSAXParserFactory();
+      SAXParser parser = saxParserFactory.newSAXParser();
+
       XMLReader reader = parser.getXMLReader();
       // set the content handler
       reader.setContentHandler(this);
diff --git a/uimaj-tools/src/main/java/org/apache/uima/tools/util/htmlview/AnnotationViewGenerator.java b/uimaj-tools/src/main/java/org/apache/uima/tools/util/htmlview/AnnotationViewGenerator.java
index 2f62c1c..3573642 100644
--- a/uimaj-tools/src/main/java/org/apache/uima/tools/util/htmlview/AnnotationViewGenerator.java
+++ b/uimaj-tools/src/main/java/org/apache/uima/tools/util/htmlview/AnnotationViewGenerator.java
@@ -29,6 +29,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 
+import javax.xml.XMLConstants;
 import javax.xml.transform.Templates;
 import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerConfigurationException;
@@ -41,6 +42,7 @@
 import org.apache.uima.analysis_engine.AnalysisEngine;
 import org.apache.uima.analysis_engine.TypeOrFeature;
 import org.apache.uima.analysis_engine.metadata.AnalysisEngineMetaData;
+import org.apache.uima.internal.util.XMLUtils;
 import org.apache.uima.resource.metadata.Capability;
 import org.apache.uima.resource.metadata.TypeDescription;
 import org.apache.uima.resource.metadata.TypeSystemDescription;
@@ -86,7 +88,7 @@
    */
   public AnnotationViewGenerator(File aOutputDir) {
     mOutputDir = aOutputDir;
-    mTFactory = TransformerFactory.newInstance();
+    mTFactory = XMLUtils.createTransformerFactory();
 
     // the viewer uses several files located via the classpath
     // parse xsl files into templates
diff --git a/uimaj-tools/src/main/javajet/jcasgen/templates/JCasType.javajet b/uimaj-tools/src/main/javajet/jcasgen/templates/JCasType.javajet
index 279e3a4..c28f7cc 100644
--- a/uimaj-tools/src/main/javajet/jcasgen/templates/JCasType.javajet
+++ b/uimaj-tools/src/main/javajet/jcasgen/templates/JCasType.javajet
@@ -32,6 +32,9 @@
      jg.error.newError(IError.WARN, 

 		jg.getString("pkgMissing", new Object[] {td.getName()}), null); %>

 

+import java.lang.invoke.CallSite;

+import java.lang.invoke.MethodHandle;

+

 import org.apache.uima.cas.impl.CASImpl;

 import org.apache.uima.cas.impl.TypeImpl;

 import org.apache.uima.cas.impl.TypeSystemImpl;

@@ -97,8 +100,12 @@
      String elemType = jg.getJavaRangeArrayElementType(fd);

      

      localData   .append("  public final static String _FeatName_").append(featName).append(" = \"").append(featName).append("\";\n");

-     featRegistry.append("  public final static int _FI_").append(featName).append(" = TypeSystemImpl.getAdjustedFeatureOffset(\"")

-                 .append(featName).append("\");\n");   

+     

+     featRegistry.append("  private final static CallSite _FC_").append(featName)

+                 .append(" = TypeSystemImpl.createCallSite(").append(typeName).append(".class, ")

+                 .append("\"").append(featName).append("\");\n"); 

+     featRegistry.append("  private final static MethodHandle _FH_").append(featName)

+                 .append(" = _FC_").append(featName).append(".dynamicInvoker();\n"); 

       

    } /* of Features iteration */ %>

 

diff --git a/uimaj-tools/src/test/resources/pearTests/pearMergerTests/uima.example.DateTime.pear b/uimaj-tools/src/test/resources/pearTests/pearMergerTests/uima.example.DateTime.pear
index 0d09796..1992721 100644
--- a/uimaj-tools/src/test/resources/pearTests/pearMergerTests/uima.example.DateTime.pear
+++ b/uimaj-tools/src/test/resources/pearTests/pearMergerTests/uima.example.DateTime.pear
Binary files differ
diff --git a/uimaj-tools/src/test/resources/pearTests/pearMergerTests/uima.example.RoomNumber.pear b/uimaj-tools/src/test/resources/pearTests/pearMergerTests/uima.example.RoomNumber.pear
index 6b02004..a4ce14f 100644
--- a/uimaj-tools/src/test/resources/pearTests/pearMergerTests/uima.example.RoomNumber.pear
+++ b/uimaj-tools/src/test/resources/pearTests/pearMergerTests/uima.example.RoomNumber.pear
Binary files differ
diff --git a/uimaj-v3migration-jcas/pom.xml b/uimaj-v3migration-jcas/pom.xml
index ff389e1..c698360 100644
--- a/uimaj-v3migration-jcas/pom.xml
+++ b/uimaj-v3migration-jcas/pom.xml
@@ -35,13 +35,13 @@
   

   <scm>

     <connection>

-      scm:svn:http://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-jcas

+      scm:svn:http://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-jcas

     </connection>

     <developerConnection>

-      scm:svn:https://svn.apache.org/repos/asf/uima/uimaj/tags/uimaj-3.0.0/uimaj-jcas

+      scm:svn:https://svn.apache.org/repos/asf/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-jcas

     </developerConnection>

     <url>

-      http://svn.apache.org/viewvc/uima/uimaj/tags/uimaj-3.0.0/uimaj-jcas

+      http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/tags/uimaj-3.0.0/uimaj-jcas

     </url>

   </scm>

   

@@ -65,13 +65,14 @@
     <dependency>    <!-- apache v2 license  2016 checked -->

       <groupId>com.github.javaparser</groupId>

       <artifactId>javaparser-core</artifactId>

-      <version>2.5.1</version>

+      <!-- version>3.1.1</version -->

+      <version>3.2.2</version>  <!-- latest as of May 2017 -->

     </dependency>

     

 <!--     <dependency>     is included from uimaj-core, not needed for this project

       <groupId>org.bitbucket.mstrobel</groupId>

       <artifactId>procyon-compilertools</artifactId>

-      <version>0.5.28</version>

+      <version>0.5.32</version>

     </dependency>

  -->    

     <!-- for reading / transforming / generating JCas cover classes -->

diff --git a/uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/AnnotationBase.java b/uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/AnnotationBase.java
deleted file mode 100644
index 02e546e..0000000
--- a/uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/AnnotationBase.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*

- * Licensed to the Apache Software Foundation (ASF) under one

- * or more contributor license agreements.  See the NOTICE file

- * distributed with this work for additional information

- * regarding copyright ownership.  The ASF licenses this file

- * to you under the Apache License, Version 2.0 (the

- * "License"); you may not use this file except in compliance

- * with the License.  You may obtain a copy of the License at

- * 

- *   http://www.apache.org/licenses/LICENSE-2.0

- * 

- * Unless required by applicable law or agreed to in writing,

- * software distributed under the License is distributed on an

- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

- * KIND, either express or implied.  See the License for the

- * specific language governing permissions and limitations

- * under the License.

- */

-

-package org.apache.uima.jcas.cas;

-

-import org.apache.uima.cas.AnnotationBaseFS;

-import org.apache.uima.cas.CAS;

-import org.apache.uima.cas.CASRuntimeException;

-import org.apache.uima.cas.impl.CASImpl;

-import org.apache.uima.cas.impl.TypeImpl;

-import org.apache.uima.cas.impl.TypeSystemImpl;

-import org.apache.uima.jcas.JCas;

-import org.apache.uima.jcas.JCasRegistry;

-

-

-/**

- * the JCas class model for the CAS type uima.cas.AnnotationBase. 

- * The AnnotationBase type defines one system-used feature which 

- * specifies for an annotation the subject of analysis (Sofa) to which it refers. 

- * Various annotation types (including the built-in uima.tcas.Annotation)

- * may be defined as subtypes of this type.

- * 

- * uima.tcas.Annotation is a subtype of this type, appropriate for

- * Subjects of Analysis which are text strings.  Other (not-built-in)

- * subtypes may be defined for other kinds of Subjects of Analysis.  For instance

- * an audio sample Subject of Analysis might define a start and end position as time points 

- * in the stream.  An image Subject of Analysis might define rectangular coordiantes

- * describing a sub-area of the image.

- * 

- * If you are defining a type which needs a reference to the Subject of Analysis

- * (which is view-specific),

- * it should be a subtype of this base type.

- */

-

-/**

- *  DUMMY VERSION ONLY USED FOR DECOMPILING 

- *

- */

-public class AnnotationBase extends TOP implements AnnotationBaseFS {

-

-  public final static int typeIndexID = JCasRegistry.register(AnnotationBase.class);

-

-  public final static int type = typeIndexID;

-

-  @Override

-  public int getTypeIndexID() {

-    return typeIndexID;

-  }

-  

-  // private final static int _FI_sofa = JCasRegistry.registerFeature();  // only for journal-able or corruptable feature slots

-

-  /* local data */

-  public final static int _FI_sofa = TypeSystemImpl.getAdjustedFeatureOffset("sofa");

-  

-//  private final Sofa _F_sofa;

-  

-  // Never called. Disable default constructor

-  protected AnnotationBase() {

-  }

-

-  // not used, just here to make decompiling of v2 work

-  protected AnnotationBase(int addr, TOP_Type type) {

-    super();

-  }

- 

-// /* Internal - Constructor used by generator */

-//  public AnnotationBase(int addr, TOP_Type type) {

-//    super(addr, type);

-//  }

-

-  public AnnotationBase(JCas jcas) {

-    super(jcas);

-    if (_casView.isBaseCas()) {

-      throw new CASRuntimeException(CASRuntimeException.DISALLOW_CREATE_ANNOTATION_IN_BASE_CAS, this.getClass().getName());

-    }

-    // no journaling, no index corruption checking

-//    _getRefData()[_FI_sofa] = _casView.getSofa();  // this is a dummy version only used for decompiling

-  }

-

-  /**

-   * used by generator

-   * Make a new AnnotationBase

-   * @param c -

-   * @param t -

-   */

-

-  public AnnotationBase(TypeImpl t, CASImpl c) {

-    super(t, c);

-    if (_casView.isBaseCas()) {

-      throw new CASRuntimeException(CASRuntimeException.DISALLOW_CREATE_ANNOTATION_IN_BASE_CAS, this.getClass().getName());

-    }

-    // no journaling, no index corruption checking

-//    _getRefData()[_FI_sofa] = _casView.getSofa();  // this is a dummy version only used for decompiling

-  }

-

-  // *------------------*

-  // * Feature: sofa

-  // * Sofa reference of the annotation

-  /*

-   * getter for sofa - gets Sofaref for annotation

-   */

-  public Sofa getSofa() { return (Sofa) _getFeatureValueNc(_FI_sofa); }

-  

-  // There is no setter for this

-  //   The value is set and is fixed when this is created

-    

-  @Override

-  public CAS getView() {

-    return _casView;

-  }

-   

-}

diff --git a/uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP.java b/uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP.java
deleted file mode 100644
index ce44e07..0000000
--- a/uimaj-v3migration-jcas/src/main/java/org/apache/uima/jcas/cas/TOP.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*

- * Licensed to the Apache Software Foundation (ASF) under one

- * or more contributor license agreements.  See the NOTICE file

- * distributed with this work for additional information

- * regarding copyright ownership.  The ASF licenses this file

- * to you under the Apache License, Version 2.0 (the

- * "License"); you may not use this file except in compliance

- * with the License.  You may obtain a copy of the License at

- * 

- *   http://www.apache.org/licenses/LICENSE-2.0

- * 

- * Unless required by applicable law or agreed to in writing,

- * software distributed under the License is distributed on an

- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

- * KIND, either express or implied.  See the License for the

- * specific language governing permissions and limitations

- * under the License.

- */

-

-package org.apache.uima.jcas.cas;

-

-import org.apache.uima.cas.impl.CASImpl;

-import org.apache.uima.cas.impl.FeatureStructureImplC;

-import org.apache.uima.cas.impl.TypeImpl;

-import org.apache.uima.jcas.JCas;

-import org.apache.uima.jcas.JCasRegistry;

-import org.apache.uima.jcas.impl.JCasImpl;

-

-// *********************************

-// * Implementation of TOP         *

-// *   D U M M Y   VERSION ONLY USED FOR DECOMPILING *

-// *********************************

-/**

- * The JCas Class model corresponding to the Cas TOP type. This type is the super type of all

- * JCas feature structures.

- */

-public class TOP extends FeatureStructureImplC {

-

-	/**

-   * Each cover class when loaded sets an index. Used in the JCas typeArray to go from the cover

-   * class or class instance to the corresponding instance of the _Type class

-   */

-	public final static int typeIndexID = JCasRegistry.register(TOP.class);  

-

-	public final static int type = typeIndexID;

-

-	/**

-   * 

-   * @return the type array index

-   */

-	// can't be factored - refs locally defined field

-	@Override

-	public int getTypeIndexID() {

-		return typeIndexID;

-	}

-

-  /** used to reference the corresponding TOP_Type instance */

-  public TOP_Type jcasType;

-

-  // maybe called to create unique removed marker, but not otherwise used

-  public TOP() {

-  }

-  

-  /**

-   * For use when creating a search key

-   * @param id -

-   */

-  private TOP(int id) {

-    super(id);

-  }

-

-  /**

-   * used by generator

-   * Make a new TOP

-   * @param c -

-   * @param t -

-   */

-

-	public TOP(TypeImpl t, CASImpl c) {

-	  super(t, c);

-	}

-

-	/**

-	 * This version is used by user code new XXX(jcas)

-	 * @param jcas -

-	 */

-	public TOP(JCas jcas) {

-	  super((JCasImpl) jcas);	  

-	}

-

-	// not used, just here to make decompiling of v2 work

-	protected TOP(int addr, TOP_Type type) {

-	  super();

-	}

-	

-  public static TOP createSearchKey(int id) {

-    return new TOP(id);

-  }

-

-	final public static TOP singleton = new TOP();

-

-}

diff --git a/uimaj-v3migration-jcas/src/main/java/org/apache/uima/migratev3/jcas/MigrateJCas.java b/uimaj-v3migration-jcas/src/main/java/org/apache/uima/migratev3/jcas/MigrateJCas.java
index 5927e03..ebd2801 100644
--- a/uimaj-v3migration-jcas/src/main/java/org/apache/uima/migratev3/jcas/MigrateJCas.java
+++ b/uimaj-v3migration-jcas/src/main/java/org/apache/uima/migratev3/jcas/MigrateJCas.java
@@ -23,7 +23,7 @@
 import java.io.File;

 import java.io.IOException;

 import java.io.StringReader;

-import java.lang.reflect.Modifier;

+import java.io.Writer;

 import java.net.MalformedURLException;

 import java.net.URL;

 import java.net.URLClassLoader;

@@ -37,25 +37,26 @@
 import java.nio.file.Paths;

 import java.nio.file.StandardCopyOption;

 import java.nio.file.StandardOpenOption;

-import java.util.ArrayDeque;

 import java.util.ArrayList;

 import java.util.Arrays;

 import java.util.Collections;

-import java.util.Comparator;

 import java.util.Date;

-import java.util.Deque;

+import java.util.EnumSet;

 import java.util.HashMap;

 import java.util.HashSet;

 import java.util.Iterator;

 import java.util.List;

 import java.util.Map;

-import java.util.Map.Entry;

+import java.util.Optional;

 import java.util.Set;

 import java.util.TreeMap;

+import java.util.TreeSet;

 import java.util.regex.Matcher;

 import java.util.regex.Pattern;

 import java.util.stream.Stream;

 

+import javax.tools.Diagnostic;

+import javax.tools.DiagnosticCollector;

 import javax.tools.JavaCompiler;

 import javax.tools.JavaFileObject;

 import javax.tools.StandardJavaFileManager;

@@ -68,29 +69,29 @@
 import org.apache.uima.internal.util.CommandLineParser;

 import org.apache.uima.internal.util.Misc;

 import org.apache.uima.internal.util.UIMAClassLoader;

+import org.apache.uima.internal.util.function.Runnable_withException;

 import org.apache.uima.pear.tools.PackageBrowser;

 import org.apache.uima.pear.tools.PackageInstaller;

 import org.apache.uima.util.FileUtils;

 

-import com.github.javaparser.ASTHelper;

 import com.github.javaparser.JavaParser;

-import com.github.javaparser.ParseException;

 import com.github.javaparser.ast.CompilationUnit;

 import com.github.javaparser.ast.ImportDeclaration;

+import com.github.javaparser.ast.Modifier;

 import com.github.javaparser.ast.Node;

+import com.github.javaparser.ast.NodeList;

 import com.github.javaparser.ast.PackageDeclaration;

 import com.github.javaparser.ast.body.AnnotationDeclaration;

 import com.github.javaparser.ast.body.BodyDeclaration;

 import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;

 import com.github.javaparser.ast.body.ConstructorDeclaration;

-import com.github.javaparser.ast.body.EmptyTypeDeclaration;

 import com.github.javaparser.ast.body.EnumDeclaration;

 import com.github.javaparser.ast.body.FieldDeclaration;

 import com.github.javaparser.ast.body.MethodDeclaration;

 import com.github.javaparser.ast.body.Parameter;

 import com.github.javaparser.ast.body.TypeDeclaration;

 import com.github.javaparser.ast.body.VariableDeclarator;

-import com.github.javaparser.ast.body.VariableDeclaratorId;

+import com.github.javaparser.ast.comments.Comment;

 import com.github.javaparser.ast.expr.AssignExpr;

 import com.github.javaparser.ast.expr.BinaryExpr;

 import com.github.javaparser.ast.expr.CastExpr;

@@ -98,9 +99,11 @@
 import com.github.javaparser.ast.expr.Expression;

 import com.github.javaparser.ast.expr.FieldAccessExpr;

 import com.github.javaparser.ast.expr.MethodCallExpr;

+import com.github.javaparser.ast.expr.Name;

 import com.github.javaparser.ast.expr.NameExpr;

 import com.github.javaparser.ast.expr.NullLiteralExpr;

 import com.github.javaparser.ast.expr.ObjectCreationExpr;

+import com.github.javaparser.ast.expr.SimpleName;

 import com.github.javaparser.ast.expr.StringLiteralExpr;

 import com.github.javaparser.ast.stmt.BlockStmt;

 import com.github.javaparser.ast.stmt.EmptyStmt;

@@ -111,98 +114,241 @@
 import com.github.javaparser.ast.stmt.Statement;

 import com.github.javaparser.ast.type.ClassOrInterfaceType;

 import com.github.javaparser.ast.type.PrimitiveType;

-import com.github.javaparser.ast.type.ReferenceType;

 import com.github.javaparser.ast.type.Type;

 import com.github.javaparser.ast.visitor.VoidVisitorAdapter;

+import com.github.javaparser.printer.PrettyPrinter;

+import com.github.javaparser.printer.PrettyPrinterConfiguration;

 

 /**

- * A driver that scans given roots for source and/or class Java files that contain JCas classes

+ * <p>A driver that scans given roots for source and/or class Java files that contain JCas classes

  * 

- *   - identifies which ones appear to be JCas classes (heuristic)

- *     -- identifies which ones appear to be v2

- *       --- converts these to v3

- *

- *   - also can receive a list of individual class names

+ * <ul><li>identifies which ones appear to be JCas classes (heuristic)

+ *   <ul><li>of these, identifies which ones appear to be v2

+ *     <ul><li>converts these to v3</li></ul></li></ul>

+ * 

+ *   <li>also can receive a list of individual class names</li>

+ * </ul>

  *   

- * Creates summary and detailed reports of its actions.

+ * <p>Creates summary and detailed reports of its actions.

  * 

- * Outputs converted files to an output file tree.

+ * <p>Files representing JCas classes to convert are discovered by walking file system 

+ * directories from various roots, specified as input.  The tool operates in 1 of two exclusive

+ * "modes":  migrating from sources (e.g., .java files) and migrating using compiled classes.

  * 

- *   - includes reporting on multiple definitions of the same class

+ * <p>Compiled classes are decompiled and then migrated.  This decompilation step usually

+ * requires a java classpath, which is supplied using the -migrateClasspath parameter.

+ * Exception: migrating PEAR files, which contain their own specification for a classpath. 

+ * 

+ * <p>The same JCas class may be encountered multiple

+ * times while walking the directory tree from the roots, 

+ * with the same or different definition.  All of these definitions are migrated.

+ * 

+ * <p>Copies of the original and the converted files are put into the output file tree.

  *   

- *   Directory structure, starting at -outputDirectory

- *     converted/

- *       v2/

- *         x/y/z/javapath/.../Classname.java

- *         x/y/z/javapath/.../Classname.java

+ * <p>Directory structure, starting at -outputDirectory (which if not specified, is a new temp directory).

+ * The "a0", "a1" represent non-identical alternative definitions for the same class.

+ * <pre>

+ *     converted/      

+ *       v2/    these are the decompiled or "found" source files

+ *         a0/x/y/z/javapath/.../Classname.java   root-id + fully qualified java class + package as slashified name

+ *                             /Classname2.java etc.

+ *         a1/x/y/z/javapath/.../Classname.java  if there are different root-ids

  *         ...

  *       v3/

- *         x/y/z/javapath/.../Classname.java

- *         x/y/z/javapath/.../Classname.java

+ *         a0/x/y/z/javapath/.../Classname.java   fully qualified java class + package as slashified name

+ *                             /Classname2.java etc.

+ *         a1/x/y/z/javapath/.../Classname.java   if there are different root-ids

  *         ...

- *         1/                                   &lt;&lt; for duplicates, each set is for identical dups, different sets for non-identical

- *           x/y/z/javapath/.../Classname.java  &lt;&lt; for duplicates, each set is for identical dups, different sets for non-identical  

- *           x/y/z/javapath/.../Classname.java  &lt;&lt; for duplicates, each set is for identical dups, different sets for non-identical

- *           ...                                    

- *         2/                                   &lt;&lt; for duplicates, each set is for identical dups, different sets for non-identical  

- *           x/y/z/javapath/.../Classname.java  &lt;&lt; for duplicates, each set is for identical dups, different sets for non-identical

- *           x/y/z/javapath/.../Classname.java  &lt;&lt; for duplicates, each set is for identical dups, different sets for non-identical

- *           ...

+ *        

+ *       v3-classes - the compiled form if from classes and a java compiler was available

+ *                    The first directory is the id of the Jar or PEAR container.

+ *                    The second directory is the alternative.

+ *                  

+ *         23/a0/fully/slashified/package/class-name.class  &lt;&lt; parallel structure as v3/       

  *         

- *     not-converted/

+ *       jars/ - copies of the original JARs with the converted JCas classes

+ *               The first directory is the id of the Jar or PEAR container

+ *         7/jar-file-name-last-part.jar

+ *         12/jar-file-name-last-part.jar

+ *         14/   etc.

+ *       

+ *       pears - copies of the original PEARs with the converted JCas classes, if there were no duplicates

+ *         8/pear-file-name-last-art.pear

+ *         9/   etc.

+ *       

+ *     not-converted/   (skipped)

  *     logs/

+ *       jar-map.txt   list of index to paths

+ *       pear-map.txt  list of index to paths

  *       processed.txt

+ *       duplicates.txt

  *       builtinsNotExtended.txt

+ *       failed.txt

+ *       skippedBuiltins.txt

+ *       nonJCasFiles.txt

+ *       woraroundDir.txt

+ *       deletedCheckModified.txt

+ *       manualInspection.txt

+ *       pearFileUpdates.txt

+ *       jarFileUpdates.txt

  *       ...

- *  

- * Operates in one of two modes:

- *   Mode 1: Given classes-roots and/or individual class names, and a classpath, 

- *     scans the classes-routes looking for classes candidates, or iterate through the individual class names

+ * </pre>

+ *     

+ * <p>Operates in one of two modes:

+ * <pre>

+ *   Mode 1: Given classes-roots and/or individual class names, and a migrateClasspath, 

+ *     scans the classes-routes looking for classes candidates

  *       - determines the class name,

- *       - looks up the right "version" in the provided classpath, and decompiles that

+ *       - decompiles that

  *       - migrates that decompiled source.

- *       -- duplicates are also processed. If different they are put into v3/nnn/etc.   

+ *      

+ *     if a Java compiler (JDK) is available,

+ *       - compiles the results

+ *       - does reassembly for Jars and PEARs, replacing the JCas classes.   

  *       

  *   Mode 2: Given sources-roots 

- *     Duplicates are migrated, results are put into a v3/nnn/ rest-of-path-identical

+ *     scans the sources-routes looking for candidates

+ *       - migrates that decompiled source.

+ * </pre>

  * 

- * Note: Each run clears the output directory before starting the migration.

+ * <p>Note: Each run clears the output directory before starting the migration.

+ * 

+ * <p>Note: classpath may be specified using -migrateClassPath or as the class path used to run this tool. 

  */

 public class MigrateJCas extends VoidVisitorAdapter<Object> {

   

-  private static final String SOURCE_FILE_ROOTS = "-sourcesRoots";

+  /* *****************************************************

+   * Internals

+   * 

+   *   Unique IDs of v2 and v3 artifacts:

+   *     RootId + classname

+   *     

+   *   RootIdContainers (Set<RootId>) hold all discovered rootIds, at each Jar/Pear nesting level

+   *     including outer level (no Jar/Pear).

+   *     These are kept in a push-down stack

+   *     

+   *       

+   *   Processing roots collection: done for source or class

+   *     - iterate, for all roots

+   *       -- processCollection for candidates rooted at that root 

+   *         --- candidate is .java or .class, with path, with pearClasspath string

+   *           ---- migrate called on each candidate

+   *             ----- check to see if already done, and if so, skip.

+   *               ------ means: same byte or source code associated with same fqcn  

+   * 

+   *   Root-ids: created for each unique pathpart in front of fully-qualified class name

+   *             created for each unique path to Jar or PEAR

+   *   

+   *   Caching to speed up duplicate processing:

+   *     - decompiling: if the byte[] is already done, use other value (if augmented migrateClasspath is the same)

+   *     - source-migrating: if the source strings are the same.

+   *       

+   *   Multiple sources for single class:

+   *     classname2multiSources: TreeMap from fqcn to CommonConverted (string or bytes)

+   *     CommonConverted: supports multiple paths having identical string/bytes.

+   *     

+   *   Compiling: driven from c2ps array of fqcn, path

+   *      - may have multiple entries for same fqcn, with different paths, 

+   *        -- only if different values for the impl

+   *      - set when visiting top-level compilation unit non-built-in type

+   *     

+   */

+  

+  /** manange the indention of printing routines */

+  private static final int[] indent = new int[1];

+  

+  private static StringBuilder si(StringBuilder sb) { return Misc.indent(sb, indent); }

+  

+  private static StringBuilder flush(StringBuilder sb) {

+    System.out.print(sb);

+    sb.setLength(0);

+    return sb;

+  }

+  

+  private static final Integer INTEGER0 = Integer.valueOf(0);

+  

+  private static int nextContainerId = 0;

+  /******************************************************************

+   * Container - exists in tree structure, has super, sub containers

+   *              -- subcontainers: has path to it

+   *           - holds set of rootIds in that container

+   *           - topmost one has null parent, and null pathToJarOrPear

+   ******************************************************************/

+  private static class Container implements Comparable<Container> {

+    final int id = nextContainerId++;

+    final Container parent;      // null if at top level

+    /**  root to scan from.  

+     *     Pears: is the loc in temp space of installed pear

+     *     Jars: is the file system mounted on the Jar

+     *             -- for inner Jars, the Jar is copied out into temp space. */

+    Path root;  

+    final Path rootOrig; // for Jars and Pears, the original path ending in jar or pear

+    final Set<Container> subContainers = new TreeSet<>();  // tree set for better ordering

+    final List<Path> candidates = new ArrayList<>();

+    final List<CommonConverted> convertedItems = new ArrayList<>();

+    final List<V3CompiledPathAndContainerItemPath> v3CompiledPathAndContainerItemPath = new ArrayList<>();

+    final boolean isPear; 

+    final boolean isJar;

+    /** can't use Path as the type, because the equals for Path is object == */

+    final Set<String> _Types = new HashSet<>(); // has the non_Type path only if the _Type is found

+    boolean haveDifferentCapitalizedNamesCollidingOnWindows = false;

 

-  private static final String CLASS_FILE_ROOTS = "-classesRoots";

-

-  private static final String OUTPUT_DIRECTORY = "-outputDirectory";

-  

-  private static final String SKIP_TYPE_CHECK = "-skipTypeCheck";

-  

-  private static final String MIGRATE_CLASSPATH = "-migrateClasspath"; 

-  

-  private static final String CLASSES = "-classes"; // individual classes to migrate, get from supplied classpath

-  

-  /*****************

-   * Candidate

-   *****************/

-  private static final class Candidate {

-    /** 

-     * path to the .class or .java file

-     */

-    final Path p;

+    String pearClasspath;  // not final - set by subroutine after defaulting

     

-    /**

-     *  null or (if in a Pear), the pear's classpath (from installing and then getting the classpath)

-     *    - includes jars in lib/ dir and the bin/ classes

-     */

-    String pearClasspath;

-    Candidate(Path p) {

-      this.p = p;

+    /** Cache of already done compiled classes, to avoid redoing them 

+     *  Kept by container, because the classpath could change the decompile */

+    private Map<byte[], CommonConverted> origBytesToCommonConverted = new HashMap<>();

+ 

+    Container(Container parent, Path root) {

+      this.parent = parent;

+      if (parent != null) {

+        parent.subContainers.add(this);

+        this.pearClasspath = parent.pearClasspath;  // default, when expanding Jars.

+      }

+      this.rootOrig = root;

+      String s = root.toString().toLowerCase();

+      isJar = s.endsWith(".jar");

+      isPear = s.endsWith(".pear");

+      this.root = (isPear || isJar) 

+                   ? installJarOrPear()

+                   : root;

+//      // debug

+//      if (!isPear && isJar) {

+//        System.out.println("debug prepare jar: " + this);

+//      }

     }

-    

-    Candidate(Path p, String pearClasspath) {

-      this.p = p;

-      this.pearClasspath = pearClasspath;

+      

+    /**

+     * Called when a new container is created

+     * @param container

+     * @param path

+     * @return install directory

+     */

+    private Path installJarOrPear() {

+      try {

+        Path theJarOrPear = rootOrig;

+        if (!theJarOrPear.getFileSystem().equals(FileSystems.getDefault())) {

+          // pear is embedded in another pear or jar, so copy the Jar (intact) to a temp spot so it's no longer embedded

+          theJarOrPear = getTempOutputPathForJarOrPear(theJarOrPear);

+          Files.copy(rootOrig, theJarOrPear, StandardCopyOption.REPLACE_EXISTING);

+        }

+        

+        if (isPear) {

+          // extract the pear just to get the classpath 

+          File pearInstallDir = Files.createTempDirectory(getTempDir(), "installedPear").toFile();

+          PackageBrowser ip = PackageInstaller.installPackage(pearInstallDir, rootOrig.toFile(), false);

+          String newClasspath = ip.buildComponentClassPath();

+          String parentClasspath = parent.pearClasspath;

+          this.pearClasspath = (null == parentClasspath || 0 == parentClasspath.length()) 

+                    ? newClasspath

+                    : newClasspath + File.pathSeparator + parentClasspath;

+        }        

+        

+        FileSystem pfs = FileSystems.newFileSystem(theJarOrPear, null);

+        return pfs.getPath("/");

+      } catch (IOException e) {

+        throw new RuntimeException(e);

+      }

     }

 

     /* (non-Javadoc)

@@ -210,83 +356,197 @@
      */

     @Override

     public String toString() {

-      String pear = (pearClasspath == null) ? "" :

-                      ", pearClasspath=" + pearClasspath;

-      return "Candidate [p=" + p + pear + "]";

-      

+      StringBuilder sb = toString1();

+      indent[0] += 2;

+      try {

+      si(sb);  // new line + indent

+      sb.append("subContainers=");

+      Misc.addElementsToStringBuilder(indent, sb, Misc.setAsList(subContainers), -1, (sbx, i) -> sbx.append(i.id)).append(',');

+      si(sb).append("paths migrated=");  // new line + indent

+      Misc.addElementsToStringBuilder(indent, sb, candidates, -1, StringBuilder::append).append(',');

+//      si(sb).append("v3CompilePath=");  // new line + indent

+//      Misc.addElementsToStringBuilder(indent,  sb, v3CompiledPathAndContainerItemPath, 100, StringBuilder::append);

+      } finally {

+        indent[0] -=2;

+        si(sb).append(']');

+      }

+      return sb.toString();

     }

     

-    

-  }

-    

-  /*****************

-   *  P E A R or J A R 

-   *  

-   * Information for each PEAR or JAR that is processed

-   * Used when post-processing pears

-   *****************/

-  private static final class PearOrJar {

-    

-    /**

-     * path to original .pear or .jar file among the roots

-     */

-    final Path pathToPearOrJar;

-    

-    /** 

-     * path to .class file in pear e.g. bin/org/apache/uima/examples/tutorial/Sentence.class

-     *                  or in jar  e.g. org/apache/uima/examples/tutorial/Sentence.class 

-     */

-    

-    final List<String> pathsToCandidateFiles = new ArrayList<>();

-        

-    PearOrJar(Path pathToPearOrJar) {

-      this.pathToPearOrJar = pathToPearOrJar; 

+    public StringBuilder toString1() {

+      StringBuilder sb = new StringBuilder();

+      si(sb); // initial nl and indentation

+      sb.append(isJar ? "Jar " : isPear ? "PEAR " : "");

+      sb.append("container [id=").append(id)

+          .append(", parent.id=").append((null == parent) ? "null" : parent.id)

+          .append(", root or pathToJarOrPear=").append(rootOrig).append(',');

+      return sb;

     }

-  }

-  

-  /**

-   * Map 

-   *   key

-   */

-  final List<String> classnames = new ArrayList<>();

 

-  private Path tempDir = null;

+    /* (non-Javadoc)

+     * @see java.lang.Object#hashCode()

+     */

+    @Override

+    public int hashCode() {

+      return 31 * id;

+    }

+

+    /* (non-Javadoc)

+     * @see java.lang.Object#equals(java.lang.Object)

+     */

+    @Override

+    public boolean equals(Object obj) {

+      if (this == obj)

+        return true;

+      if (obj == null)

+        return false;

+      if (getClass() != obj.getClass())

+        return false;

+      Container other = (Container) obj;

+      if (id != other.id)

+        return false;

+      return true;

+    }

+

+

+    @Override

+    public int compareTo(Container o) {

+      return Integer.compare(id,  o.id);

+    }    

+  }

+  

+  /**

+   * A path to a .java or .class file in some container, for the v2 version

+   * For Jars and Pears, the path is relative to the zip "/" dir

+   */

+  private static class ContainerAndPath implements Comparable<ContainerAndPath> {

+    final Path path;

+    final Container container;

     

-  private boolean isSource = false;

-  

-  private Candidate candidate;

-  private List<Candidate> candidates;

-  

-  private PearOrJar pear_current;

-  private Deque<PearOrJar> jar_current_stack = new ArrayDeque<>();  

-  private List<PearOrJar> pears = new ArrayList<>();

-  private List<PearOrJar> jars = new ArrayList<>();

+    ContainerAndPath(Path path, Container container) {

+      this.path = path;

+      this.container = container;          

+    }

+    

+    /* (non-Javadoc)

+     * @see java.lang.Comparable#compareTo(java.lang.Object)

+     */

+    @Override

+    public int compareTo(ContainerAndPath o) {

+      int r = path.compareTo(o.path);

+      if (r != 0) {

+        return r;

+      }

+      return Integer.compare(container.id, o.container.id);

+    }

+

+

+

+    /* (non-Javadoc)

+     * @see java.lang.Object#toString()

+     */

+    @Override

+    public String toString() {

+      StringBuilder sb = new StringBuilder();

+      sb.append("ContainerAndPath [path=").append(path).append(", container=").append(container.id).append("]");

+      return sb.toString();

+    }

+  }

   

   /**

-   * current Pear install path + 1 more dir in temp dir

-   * used in candidate generation to relativize the path to just the part inside the pear

+   * This class holds information used to replace compiled items in Jars and Pears.

+   * 

+   * a pair of the v3CompiledPath (which is the container nbr/a0/ + the package-class-name slash + ".class"

+   *   and the Container origRoot up to the start of the package and class name

+   * for the item being compiled.

+   *   - Note: if a Jar has the same compiled class at multiple nesting levels, each one will have 

+   *     an instance of this class 

    */

-  private Path pearResolveStart;

+  private static class V3CompiledPathAndContainerItemPath {

+    final Path v3CompiledPath;

+    final String pathInContainer; 

+    

+    public V3CompiledPathAndContainerItemPath(Path v3CompiledPath, String pathInContainer) {

+      this.v3CompiledPath = v3CompiledPath;

+      this.pathInContainer = pathInContainer;

+    }

+

+    /* (non-Javadoc)

+     * @see java.lang.Object#toString()

+     */

+    @Override

+    public String toString() {

+      StringBuilder sb = new StringBuilder();

+      si(sb).append("v3CompiledPathAndContainerPartPath [");

+      indent[0] += 2;

+      try {

+        si(sb).append("v3CompiledPath=").append(v3CompiledPath);

+        si(sb).append("pathInContainer=").append(pathInContainer);

+      } finally {

+        indent[0] -= 2;

+        si(sb).append("]");

+      }

+      return sb.toString();

+    }

+    

+    

+  }

   

-  /**

-   * Map created when adding a pear's .class/.source file to candidates

-   *   Key: path string to .class or .java file in an installed Pear

-   *   Value: path part corresponding to inside pear - delete install dir + 1 more dir from front

-   */

-  private Map<String, String> path2InsidePearOrJarPath = new HashMap<>();

+  private static final JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();

   

-  /**

-   * Map created when adding a pear's .class/.source file to candidates

-   *   Key: path string to .class or .java file in an installed Pear

-   *   Value: path part corresponding to just the classname

-   */

-  private Map<String, String> path2classname = new HashMap<>();

+  /****************************************************************

+   * Command line parameters

+   ****************************************************************/

+  private static final String SOURCE_FILE_ROOTS = "-sourcesRoots";

+

+  private static final String CLASS_FILE_ROOTS = "-classesRoots";

+

+  private static final String OUTPUT_DIRECTORY = "-outputDirectory";

   

-  private String packageName;

+//  private static final String SKIP_TYPE_CHECK = "-skipTypeCheck";

+  

+  private static final String MIGRATE_CLASSPATH = "-migrateClasspath"; 

+  

+//  private static final String CLASSES = "-classes"; // individual classes to migrate, get from supplied classpath

+  

+

+  private static final Type intType = PrimitiveType.intType();

+  

+  private static final Type callSiteType = JavaParser.parseType("CallSite");

+  

+  private static final Type methodHandleType = JavaParser.parseType("MethodHandle");

+  

+  private static final Type stringType = JavaParser.parseType("String");

+  

+  private static final EnumSet<Modifier> public_static_final = 

+      EnumSet.of(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL);

+  private static final EnumSet<Modifier> private_static_final = 

+      EnumSet.of(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL);

+  

+  private static final PrettyPrinterConfiguration printWithoutComments = 

+      new PrettyPrinterConfiguration();

+  static { printWithoutComments.setPrintComments(false); }

+

+  private static final PrettyPrinterConfiguration printCu = 

+      new PrettyPrinterConfiguration();

+  static { printCu.setIndent("  "); }

+  

+  private static final String ERROR_DECOMPILING = "!!! ERROR:";

+  

+  static private boolean isSource = false;

+

+  static private Path tempDir = null;

+

+/***************************************************************************************************/

+  

+  private String packageName;  // with dots?

   private String className;  // (omitting package)

   private String packageAndClassNameSlash;  

-  private final Set<String> usedPackageAndClassNames = new HashSet<>();

-  private int packageAndClassNameSlash_i;

+  

+  // next 3 set at start of migrate for item being migrated

+  private CommonConverted current_cc;  

+  private Path current_path;

+  private Container current_container;

   

   /** includes trailing / */

   private String outputDirectory;

@@ -297,8 +557,8 @@
   /** includes trailing / */

   private String outDirLog;

    

-  private String[] sourcesRoots = new String[0];

-  private String[] classesRoots = new String[0];

+  private Container[] sourcesRoots = null; // only one of these has 1 or more Container instances

+  private Container[] classesRoots = null;

   

   private CompilationUnit cu;

   

@@ -307,54 +567,154 @@
   

   private String migrateClasspath = null;

   

-  private String individualClasses = null;  // to decompile

-  

-  private class ConvertedSource {

-    String rOrigSource;  // remembered original source

-    byte[] rOrigBytes;   // remembered original bytes

-    List<Path> paths;

-    ConvertedSource(String origSource, byte[] origBytes, Path path) {

-      this.rOrigSource = origSource;

-      this.rOrigBytes = origBytes;

-      paths = new ArrayList<>();

-      add(path);

+//  private String individualClasses = null;  // to decompile

+

+  /**

+   * CommonConverted next id, by fqcn

+   * key: fqcn_slashes value: next id

+   */

+  private Map<String, Integer> nextCcId = new HashMap<>();  

+  /**

+   * Common info about a particular source-code instance of a class

+   *   Used to avoid duplicate work for the same JCas definition

+   *   Used to track identical and non-identical duplicate defs

+   * 

+   *   When processing from sourcesRoots: 

+   *     use map: origSourceToCommonConverted  key = source string

+   *     if found, skip conversion, use previous converted result.

+   *     

+   *   When processing from classesRoots:

+   *     use map: origBytesToCommonConverted  key = byte[], kept by container in container

+   *     if found, use previous converted results

+   */

+  private class CommonConverted {

+    /**

+     * starts at 0, incr for each new instance for a particular fqcn_slash

+     * can't be assigned until fqcn known

+     */

+    int id = -1;            // temp value

+    final String v2Source;  // remembered original source

+    final byte[] v2ByteCode;   // remembered original bytes

+    

+    /** all paths + their containers having the same converted result 

+     *  Need container because might change classpath for compiling 

+     *    - path is to v2 source or compiled class*/

+    final Set<ContainerAndPath> containersAndV2Paths = new HashSet<>(); 

+ 

+    String v3Source;           // if converted, the result

+    /** converted/v3/id-of-cc/pkg/name/classname.java */

+    Path v3SourcePath;       // path to converted source or null

+    

+    String fqcn_slash;           // full name of the class e.g. java/util/Foo.  unknown for sources at first

+    

+    CommonConverted(String origSource, byte[] v2ByteCode, Path path, Container container, String fqcn_slash) {

+      this.v2Source = origSource;

+      this.v2ByteCode = v2ByteCode;

+      containersAndV2Paths.add(new ContainerAndPath(path, container));

+      this.fqcn_slash = fqcn_slash;

+    }

+

+    /**

+     * 

+     * @param container having this commonConverted instance

+     * @return the path to .java or .class file.  

+     *         If the container is a Jar or PEAR, it is the path within that Jar or Pear FileSystem

+     */

+    Path getV2SourcePath(Container container) {

+      for (ContainerAndPath cp : containersAndV2Paths) {

+        if (cp.container == container) {

+          return cp.path;

+        }

+      }

+      throw new RuntimeException("internalError");

     }

     

-    void add(Path path) {

-      paths.add(path);

+    int getId() {

+      if (id < 0) {

+        Integer nextId = nextCcId.computeIfAbsent(fqcn_slash, s -> INTEGER0);

+        nextCcId.put(fqcn_slash, nextId + 1);

+        this.id = nextId;

+      }

+      return id;

     }

-  }

+    

+    /* (non-Javadoc)

+     * @see java.lang.Object#hashCode()

+     */

+    @Override

+    public int hashCode() {

+      return v2Source == null ? 0 : v2Source.hashCode();

+    }

+

+    /* equal if the v2source is equal

+     */

+    @Override

+    public boolean equals(Object obj) {

+      return obj instanceof CommonConverted &&

+             v2Source != null &&

+             v2Source.equals(((CommonConverted)obj).v2Source);

+    }

+

+    /* (non-Javadoc)

+     * @see java.lang.Object#toString()

+     */

+    @Override

+    public String toString() {

+      StringBuilder sb = new StringBuilder();

+      int maxLen = 10;

+      si(sb).append("CommonConverted [v2Source=").append(Misc.elide(v2Source, 100));

+      indent[0] += 2;

+      try {

+      si(sb).append("v2ByteCode=");

+      sb.append(v2ByteCode != null

+                  ? Arrays.toString(Arrays.copyOf(v2ByteCode, Math.min(v2ByteCode.length, maxLen))) : 

+                  "null").append(',');

+      si(sb).append("containersAndPaths=")

+            .append(containersAndV2Paths != null 

+                      ? Misc.ppList(indent, Misc.setAsList(containersAndV2Paths), -1, StringBuilder::append)

+                      : "null").append(',');

+      si(sb).append("v3SourcePath=").append(v3SourcePath).append(',');

+      si(sb).append("fqcn_slash=").append(fqcn_slash).append("]").append('\n');

+      } finally {

+        indent[0] -= 2;

+      }

+      return sb.toString();

+    }

+  }      

+  /** Cache of already converted source classes, to avoid redoing them; 

+   *    - key is the actual source

+   *    - value is CommonConverted 

+   *  This cache is over all containers 

+   *  */

+  private Map<String, CommonConverted> sourceToCommonConverted = new HashMap<>();

   

   /**

-   * A map from classnames (fully qualified, with slashes) to a list of converted sources

+   * A map from fqcn_slash to a list of converted sources

    *   one per non-duplicated source

    */

-  private Map<String, List<ConvertedSource>> classname2multiSources = new TreeMap<>();

-  

-  private Map<byte[], String> origBytesToClassName = new HashMap<>();

-  private Map<String, String> origSourceToClassName = new HashMap<>();

-    

+  private Map<String, List<CommonConverted>> classname2multiSources = new TreeMap<>();

+      

   /************************************

    * Reporting

    ************************************/

-  private final List<Path> v2JCasFiles = new ArrayList<>();

-  private final List<Path> v3JCasFiles = new ArrayList<>();

+//  private final List<Path> v2JCasFiles = new ArrayList<>();  // unused

+//  private final List<Path> v3JCasFiles = new ArrayList<>();  // unused

   

-  private final List<PathAndReason> nonJCasFiles = new ArrayList<>();  // path, reason

-  private final List<PathAndReason> failedMigration = new ArrayList<>(); // path, reason

-  private final List<ClassnameAndPath> c2ps = new ArrayList<>();            // class, path

-  private final List<ClassnameAndPath> skippedBuiltins = new ArrayList<>();  // class, path

-  private final List<PathAndReason> deletedCheckModified = new ArrayList<>();  // path, deleted check string

+  private final List<PathContainerAndReason> nonJCasFiles = new ArrayList<>();  // path, reason

+  private final List<PathContainerAndReason> failedMigration = new ArrayList<>(); // path, reason

+  private final List<PathContainerAndReason> skippedBuiltins = new ArrayList<>();  // path, "built-in"

+  private final List<PathContainerAndReason> deletedCheckModified = new ArrayList<>();  // path, deleted check string

   private final List<String1AndString2> pathWorkaround = new ArrayList<>(); // original, workaround

   private final List<String1AndString2> pearClassReplace = new ArrayList<>(); // pear, classname

   private final List<String1AndString2> jarClassReplace  = new ArrayList<>(); // jar, classname

   

-  private final List<PathAndReason> manualInspection = new ArrayList<>(); // path, reason

+  private final List<PathContainerAndReason> manualInspection = new ArrayList<>(); // path, reason

 //  private final List<PathAndPath> embeddedJars = new ArrayList<>(); // source, temp   

   

-  private boolean v2;  // false at start of migrate, set to true if a v2 class candidate is discovered

-  private boolean v3;  // true at start of migrate, set to false if no conversion done

-      

+  private boolean isV2JCas;  // false at start of migrate, set to true if a v2 class candidate is discovered

+  private boolean isConvert2v3;  // true at start of migrate, set to false if conversion fails, left true if already a v3

+  private boolean isBuiltinJCas; // false at start of migrate, set to true if a built-in class is discovered

+        

   /************************************ 

    * Context for visits    

    ************************************/

@@ -380,23 +740,24 @@
   /**

    * temp place to insert static final int feature declarations

    */

-  private List<BodyDeclaration> fi_fields = new ArrayList<>();

+  private NodeList<BodyDeclaration<?>> fi_fields = new NodeList<>();

   private Set<String> featNames = new HashSet<>();

 

   private boolean hasV2Constructors;

   private boolean hasV3Constructors;

 

-  private boolean isSkipTypeCheck = false;

+  private boolean error_decompiling = false;

 

+  private boolean badClassName;

+

+  private int itemCount;

+

+  /**

+   * set if getAndProcessCasndidatesInContainer encounters a class where it cannot do the compile

+   */

+  private boolean unableToCompile;

   

-  private byte[] origBytes;   // set by getSource()

-  private String origSource;  // set by getSource()

-  private String alreadyDone; // the slashifiedClassName

-

-  private boolean isOk;

-

-

-

+  final private StringBuilder psb = new StringBuilder();

 

 

   public MigrateJCas() {

@@ -413,27 +774,38 @@
   void run(String[] args) {

     CommandLineParser clp = parseCommandArgs(args);

     

+    System.out.format("Output top directory: %s%n", outputDirectory);

+    

     // clear output dir

     FileUtils.deleteRecursive(new File(outputDirectory));

-    

-    isSource = true;

-    processRootsCollection("source", sourcesRoots, clp);

-    

-    isSource = false;

-    processRootsCollection("classes", classesRoots, clp);

-    

-    if (individualClasses != null) {

-      processCollection("individual classes: ", new Iterator<String>() {

-        Iterator<String> it = Arrays.asList(individualClasses.split(File.pathSeparator)).iterator();

-        public boolean hasNext() {return it.hasNext();}

-        public String next() {

-          return prepareIndividual(it.next());}

-      });

-    }

 

-    isOk = report();

+    isSource = sourcesRoots != null;

+    boolean isOk;

+    if (isSource) {

+      isOk = processRootsCollection("source", sourcesRoots, clp);

+    } else {

+      if (javaCompiler == null) {

+        System.out.println("The migration tool cannot compile the migrated files, \n"

+            + "  because no Java compiler is available.\n"

+            + "  To make one available, run this tool using a Java JDK, not JRE");

+      } 

+      isOk = processRootsCollection("classes", classesRoots, clp);

+    }

     

-    postProcessing();

+//    if (individualClasses != null) {

+//      processCollection("individual classes: ", new Iterator<String>() {

+//        Iterator<String> it = Arrays.asList(individualClasses.split(File.pathSeparator)).iterator();

+//        public boolean hasNext() {return it.hasNext();}

+//        public String next() {

+//          return prepareIndividual(it.next());}

+//      });

+//    }

+

+    if (error_decompiling) { 

+      isOk = false;

+    }

+    

+    isOk = report() && isOk;

     

     System.out.println("Migration finished " + 

        (isOk 

@@ -441,90 +813,69 @@
            : "with 1 or more unusual conditions that need manual checking."));

   }

   

-  private void postProcessing() {

-    if (javaCompilerAvailable()) {

-      compileV3sources();

-      

-      postProcessPearsOrJars("jars" , jars ,  jarClassReplace);

-      postProcessPearsOrJars("pears", pears, pearClassReplace);

-      

-//    

-//      try {

-//        Path pearOutDir = Paths.get(outputDirectory, "pears");

-//        FileUtils.deleteRecursive(pearOutDir.toFile());

-//        Files.createDirectories(pearOutDir);

-//      } catch (IOException e) {

-//        throw new RuntimeException(e);

-//      }

-//        

-//      System.out.format("replacing .class files in %,d PEARs%n", pears.size());

-//      for (PearOrJar p : pears) {

-//        pearOrJarPostProcessing(p);

-//      }

-//      try {

-//        reportPaths("Reports of updated Pears", "pearFileUpdates.txt", pearClassReplace);

-//      } catch (IOException e) {

-//        throw new RuntimeException(e);

-//      }

-    }

-  }

   

-  private void postProcessPearsOrJars(String kind, List<PearOrJar> pearsOrJars, List<String1AndString2> classReplace) {  // pears or jars

+  /**

+   * called for compiled input when a compiler is available and don't have name collision

+   *        if the container is a PEAR or a Jar

+   * Updates a copy of the Pear or Jar

+   * @param container

+   */

+  private void postProcessPearOrJar(Container container) {

+    Path outDir = Paths.get(outputDirectory, 

+                            container.isJar ? "jars" : "pears",

+                            Integer.toString(container.id));

+    withIOX(() -> Files.createDirectories(outDir));

+    si(psb).append("Replacing .class files in copy of ").append(container.rootOrig);

+    flush(psb);

     try {

-      Path outDir = Paths.get(outputDirectory, kind);

-      FileUtils.deleteRecursive(outDir.toFile());

-      Files.createDirectories(outDir);

-    } catch (IOException e) {

-      throw new RuntimeException(e);

-    }

-    

-    if (pearsOrJars.size() == 0) {

-      System.out.format("No .class files were replaced in %s%n.", kind);

-    } else {

-      System.out.format("replacing .class files in %,d %s%n", pearsOrJars.size(), kind);

-      for (PearOrJar p : pearsOrJars) {

-        pearOrJarPostProcessing(p, kind);

-      }

-      try {

-        reportPaths("Reports of updated " + kind, kind + "FileUpdates.txt", classReplace);

-       

-      } catch (IOException e) {

-        throw new RuntimeException(e);

-      }

-    }

-    

-  }

-  

-  private void pearOrJarPostProcessing(PearOrJar pearOrJar, String kind) { // pears or jars

-    try {

-      final boolean isPear = kind.equals("pears");

-      // copy the pear so we don't change the original

-      Path pearOrJarCopy = Paths.get(outputDirectory, kind, pearOrJar.pathToPearOrJar.getFileName().toString());

+      // copy the pear or jar so we don't change the original

+      Path lastPartOfPath = container.rootOrig.getFileName();

+      if (null == lastPartOfPath) throw new RuntimeException("Internal Error");

+      Path pearOrJarCopy = Paths.get(outputDirectory,

+                                     container.isJar ? "jars" : "pears",

+                                     Integer.toString(container.id), 

+                                     lastPartOfPath.toString());

      

-      Files.copy(pearOrJar.pathToPearOrJar, pearOrJarCopy);    

+      Files.copy(container.rootOrig, pearOrJarCopy);    

 

       // put up a file system on the pear or jar

       FileSystem pfs = FileSystems.newFileSystem(pearOrJarCopy, null);

     

-      // replace the .class files in this pear with corresponding v3 ones

-      for (int i = 0; i < pearOrJar.pathsToCandidateFiles.size(); i++) {

-        String candidatePath = pearOrJar.pathsToCandidateFiles.get(i);

-        String path_in_v3_classes = isPear

-                                      ? getPath_in_v3_classes(candidatePath)

-                                      : candidatePath;

-      

-        Path src = Paths.get(outputDirectory, "converted/v3-classes", path_in_v3_classes 

-            + (isPear ? ".class" : ""));

-        Path tgt = pfs.getPath(

-            "/", 

-            isPear 

-              ? path2InsidePearOrJarPath.get(candidatePath) // needs to be bin/org/... etc

-              : candidatePath);  // needs to be org/... etc

-        if (Files.exists(src)) {

-          Files.copy(src, tgt, StandardCopyOption.REPLACE_EXISTING);

-          reportPearOrJarClassReplace(pearOrJarCopy.toString(), path_in_v3_classes, kind);

-        }

-      }

+      // replace the .class files in this PEAR or Jar with corresponding v3 ones

+      indent[0] += 2;

+      String[] previousSkip = {""};

+      container.v3CompiledPathAndContainerItemPath.forEach(c_p -> {

+            if (Files.exists(c_p.v3CompiledPath)) {

+              withIOX(() -> Files.copy(c_p.v3CompiledPath, pfs.getPath(c_p.pathInContainer), StandardCopyOption.REPLACE_EXISTING));

+              reportPearOrJarClassReplace(pearOrJarCopy.toString(), c_p.v3CompiledPath.toString(), container);

+            } else {

+              String pstr = c_p.v3CompiledPath.toString();

+              String pstr2 = pstr;

+              if (previousSkip[0] != "") {

+                int cmn = findFirstCharDifferent(previousSkip[0], pstr);

+                pstr2 = cmn > 5 

+                          ? ("..." + pstr.substring(cmn))

+                          : pstr;    

+              } 

+              previousSkip[0] = pstr;

+              si(psb).append("Skipping replacing ").append(pstr2)

+                     .append(" because it could not be found, perhaps due to compile errors.");

+              flush(psb);

+            }

+          });

+      indent[0] -= 2;

+//      for (CommonConverted cc : container.convertedItems) {

+//        Map<Container, Path> v3ccs = cc.v3CompiledResultPaths;

+//        v3ccs.forEach((v3ccc, v3cc_path) ->

+//          {

+//            if (v3ccc == container) {

+//              String path_in_v3_classes = cc.v3CompiledResultPaths.get(container).toString();

+//              

+//              withIOX(() -> Files.copy(v3cc_path,  pfs.getPath(path_in_v3_classes)));

+//              reportPearOrJarClassReplace(pearOrJarCopy.toString(), path_in_v3_classes, container);

+//            }

+//          });

+//      }

       

       pfs.close();     

       

@@ -534,118 +885,277 @@
   }

   

   /**

-   * @param pathInPear a complete path to a class inside an (installed) pear

-   * @return the part starting after the top node of the install dir

+   * Compile all the migrated JCas classes in this container, adjusting the classpath

+   * if the container is a Jar or Pear to include the Jar or PEAR.

+   * 

+   * As a side effect, it saves in the container, a list of all the compiled things together 

+   *   with the path in container part, for use by a subsequent step to update copies of the jars/pears.

+   *   

+   * The items in the container are broken into batches of multiple classes to be compiled together.

+   *   - The grouping is to group by alternative number.  This insures that multiple 

+   *     definitions of the same class are done separately (otherwise the compiler complains 

+   *     about multiple definitions).

+   *     

+   * As a side effect. compiling update the container, adding all the compiled items

+   * to v3CompiledPathAndContainerItemPath

+   *    

+   * @param container -

+   * @return true if compiled 1 or more sources, false if nothing was compiled

    */

-  private String getPath_in_v3_classes(String pathInPear) { 

-    return path2classname.get(pathInPear);  

-  }

-  

-  /**

-   * When running the compiler to compile v3 sources, we need a classpath that at a minimum

-   * includes uimaj-core.  The strategy is to use the invoker of this tool's classpath as

-   * specified from the application class loader

-   */

-  private void compileV3sources() {

-    if (c2ps.size() == 0) {

-      return;

-    }

-    System.out.format("Compiling converted %,d classes%n", c2ps.size());

-    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

-    StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, Charset.forName("UTF-8"));

-    Iterable<String> compilationUnitStrings = new Iterable<String>() {

-      @Override

-      public Iterator<String> iterator() {

-        return new Iterator<String>() {

-          int pos = 0;

-          @Override

-          public boolean hasNext() {

-            return pos < c2ps.size();

-          }

-          @Override

-          public String next() {

-            ClassnameAndPath classnameAndPath = c2ps.get(pos++);

-            return outDirConverted + "v3/" + classnameAndPath.classname + ".java";

-          }          

-        };

-      }  

-    };

-    Iterable<? extends JavaFileObject> compilationUnits = 

-        fileManager.getJavaFileObjectsFromStrings(compilationUnitStrings);

+  private boolean compileV3SourcesCommon2(Container container) {

     

-    // specify where the output classes go

-    String classesBaseDir = outDirConverted + "v3-classes";

-    try {

-      Files.createDirectories(Paths.get(classesBaseDir));

-    } catch (IOException e) {

-      throw new UIMARuntimeException(e);

+    String classesBaseDir = outDirConverted + "v3-classes/" + container.id;

+    

+    // specify the classpath.  For PEARs use a class loader that loads first.

+    String classpath = getCompileClassPath(container);

+    

+//    // debug

+//    String[] cpa = classpath.split(File.pathSeparator);

+//    System.out.println("debug - compilation classpath");

+//    int j = 0;

+//    for (String s : cpa) System.out.println("debug classpath: " + (++j) + " " + s);

+    

+    // get a list of compilation unit path strings to the converted/v3/nnn/path

+    /**

+     * containerRoot is

+     * rootOrig or for Jars/Pears the Path to "/" in the zip file system 

+     */

+    Path containerRoot = null;

+         

+    /**

+     * The Cu Path Strings for one container might have multiple instances of the class.

+     * These might be for identical or different sources. 

+     *   - This happens when a root has multiple paths to instances of the same class.

+     *   - Multiple compiled-paths might be for the same classname

+     *   

+     * For non-identical sources, the commonContainer instance "id" is spliced into the 

+     *   v3 migrated source path:  see getBaseOutputPath,  e.g. converted/2/a3/fqcn/slashed/name.java  

+     *   

+     * The compiler will complain if you feed it the same compilation unit classname twice, with

+     *   different paths saying "duplicate class definition".  

+     *   - Fix:  do compilation in batches, one for each different commonConverted id.   

+     */

+    

+    Map<Integer, ArrayList<String>>  cu_path_strings_by_ccId = new TreeMap<>();  // tree map to have nice order of keys

+    

+    indent[0] += 2;

+    boolean isEmpty = true;

+    for (CommonConverted cc : container.convertedItems) {

+      if (cc.v3SourcePath == null) continue;  // skip items that failed migration

+      isEmpty = false;

+      // relativePathInContainer = the whole path with the first part (up to the end of the container root) stripped off

+      /**

+       * itemPath is the original path in the container to where the source or class file is

+       * For Jars and PEARs, it is relative to the Jar or PEAR

+       */

+      Path itemPath = cc.getV2SourcePath(container);

+      if (null == containerRoot) {

+        // lazy setup on first call

+        // for Pears, must use the == filesystem, otherwise get

+        //   ProviderMismatchException

+        containerRoot = (container.isJar || container.isPear) 

+            ? itemPath.getFileSystem().getPath("/")

+            : container.rootOrig;

+      }

+      /**

+       * relativePathInContainer might be x/y/z/a/b/c/name.class

+       * (ends in .class because we only get here when the input is class files)

+       */

+      String relativePathInContainer = containerRoot.relativize(itemPath).toString();

+      

+      container.v3CompiledPathAndContainerItemPath.add(

+          new V3CompiledPathAndContainerItemPath(

+              Paths.get(classesBaseDir, "a" + cc.id, cc.fqcn_slash + ".class"  /*relativePathInContainer*/),

+              relativePathInContainer));

+      ArrayList<String> items = cu_path_strings_by_ccId.computeIfAbsent(cc.id, x -> new ArrayList<>());

+      items.add(cc.v3SourcePath.toString());

     }

-    // specify the classpath

-    String classpath = getAppClassPath();

-    Iterable<String> options = Arrays.asList("-d", classesBaseDir,

-        "-classpath", classpath);

-    compiler.getTask(null, fileManager, null, options, null, compilationUnits).call();    

-  }

-  

-  /**

-   * The classpath used to compile is

-   *   - the classpath for this migration app except the target/classes for this project

-   *   - any passed in migrate classpath

-   * @return the classpath to use in compiling the jcasgen'd sources

-   */

-  private String getAppClassPath() {

-    URL[] urls = ((URLClassLoader)MigrateJCas.class.getClassLoader()).getURLs();

-    StringBuilder cp = new StringBuilder();

-    for (URL url : urls) {

-      String p = url.getFile().toString();

-      if (!p.endsWith("uimaj-v3migration-jcas/target/classes/")) {

-        cp.append(url.getFile().toString());

-        cp.append(File.pathSeparatorChar);

-      }   

-    }

-    if (null != migrateClasspath) {

-      cp.append(migrateClasspath);

-    }

-//    System.out.println("debug: classpath = " + cp.toString());

-    return cp.toString();

-  }

-  

-  

-  private boolean javaCompilerAvailable() {

-    if (null == ToolProvider.getSystemJavaCompiler()) {

-      System.out.println("The migration tool would like to compile the migrated files, \n"

-          + "  but no Java compiler is available.\n"

-          + "  To make one available, run this tool using a Java JDK, not JRE");

+    

+    if (isEmpty) {

+      si(psb).append("Skipping compiling for container ").append(container.id).append(" ").append(container.rootOrig);

+      si(psb).append("  because non of the v2 classes were migrated (might have been built-ins)");

+      flush(psb);

       return false;

     }

+    else { 

+      si(psb).append("Compiling for container ").append(container.id).append(" ").append(container.rootOrig);

+      flush(psb);

+    }

+    

+//    List<String> cu_path_strings = container.convertedItems.stream()

+//        .filter(cc -> cc.v3SourcePath != null)

+//        .peek(cc -> container.v3CompiledPathAndContainerItemPath.add(

+//            new V3CompiledPathAndContainerItemPath(

+//                Paths.get(classesBaseDir, cc.v3SourcePath.toString()),

+//                getPathInContainer(container, cc).toString())))

+//        .map(cc -> cc.v3SourcePath.toString())

+//        .collect(Collectors.toList());

+    

+    boolean resultOk = true;

+    

+    for (int ccId = 0;; ccId++) {  // do each version of classes separately

+      List<String> cups = cu_path_strings_by_ccId.get(ccId);

+      if (cups == null) {

+        break;

+      }

+      

+      StandardJavaFileManager fileManager = javaCompiler.getStandardFileManager(null, null, Charset.forName("UTF-8"));

+

+      Iterable<? extends JavaFileObject> compilationUnits = 

+          fileManager.getJavaFileObjectsFromStrings(cups);

+      

+//      //debug

+//      System.out.println("Debug: list of compilation unit strings for iteration " + i);

+//      int[] k = new int[] {0};

+//      cups.forEach(s -> System.out.println(Integer.toString(++(k[0])) + " " + s));

+//      System.out.println("debug end");  

+    

+      String classesBaseDirN = classesBaseDir + "/a" + ccId;

+      withIOX(() -> Files.createDirectories(Paths.get(classesBaseDirN)));

+      Iterable<String> options = Arrays.asList("-d", classesBaseDirN, "-classpath", classpath);

+  

+      si(psb).append("Compiling for commonConverted version ").append(ccId)

+             .append(", ").append(cups.size()).append(" classes");

+      flush(psb);

+      DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();

+

+      /***********  Compile ***********/

+      resultOk = javaCompiler.getTask(null, fileManager, diagnostics, options, null, compilationUnits).call() && resultOk;

+      /********************************/

+      

+      indent[0] += 2;

+      for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {

+        JavaFileObject s = diagnostic.getSource();

+        si(psb).append(diagnostic.getKind());

+        int lineno = (int) diagnostic.getLineNumber();

+        if (lineno != Diagnostic.NOPOS) {

+          psb.append(" on line ").append(diagnostic.getLineNumber());

+        }

+        int pos = (int) diagnostic.getPosition();

+        if (pos != Diagnostic.NOPOS) {

+          psb.append(", position: ").append(diagnostic.getColumnNumber());

+        }

+        if (s != null) {

+          psb.append(" in ").append(s.toUri());

+        }

+        si(psb).append("  ").append(diagnostic.getMessage(null));

+        flush(psb);

+      }

+      withIOX( () -> fileManager.close());

+      indent[0] -= 2;

+      si(psb).append("Compilation finished").append(

+          resultOk ? " with no errors." : "with some errors.");

+      flush(psb);

+    }

+    indent[0] -= 2;

+    unableToCompile = !resultOk;

     return true;

   }

   

-  private void processRootsCollection(String kind, String[] roots, CommandLineParser clp) {

-    for (String root : roots) {

-      processCollection("from " + kind + "  root: " + root, new Iterator<String>() { 

-        Iterator<Candidate> it = getCandidates(clp, root).iterator();

-        public boolean hasNext() {return it.hasNext();}

-        public String next() {

-          return prepare(it.next());}

-      });

-    }

-  }

   

   

-  private void processCollection(String sourceName, Iterator<String> sourceIterator) {

-    System.out.println("Migrating " + sourceName + ", number of classes migrated:");

-    int i = 1;

-    System.out.print("    ");

+  /**

+   * The classpath used to compile is (in precedence order)

+   *   - the classpath for this migration app  (first in order to pick up v3 support, overriding others)

+   *   - any Pears, going up the parent chain, closest ones first

+   *   - any Jars, going up the parent chain, closest ones last

+   *   - passed in migrate classpath

+   * @return the classpath to use in compiling the jcasgen'd sources

+   */

+  private String getCompileClassPath(Container container) {

+ 

+    // start with this (the v3migration tool) app's classpath to a cp string

+    URLClassLoader systemClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();

+    URL[] urls = systemClassLoader.getURLs();

+    StringBuilder cp = new StringBuilder();

     

-    while (sourceIterator.hasNext()) {

-      migrate(sourceIterator.next());

-      if ((i % 50) == 0) System.out.format("%4d%s", Integer.valueOf(i), "\r");

-      i++;

+    boolean firstTime = true;

+    for (URL url : urls) {

+      if (! firstTime) {

+        cp.append(File.pathSeparatorChar);

+      } else {

+        firstTime = false;

+      }

+      cp.append(url.getPath());

     }

-    System.out.format("%4d%n", Integer.valueOf(i - 1));   

+    

+    // pears up the classpath, closest first

+    Container c = container;

+    while (c != null) {

+      if (c.isPear) {

+        cp.append(File.pathSeparator).append(c.pearClasspath);

+      }

+      c = c.parent;

+    }

+    

+    // add the migrateClasspath, expanded

+    

+    if (null != migrateClasspath) {

+      cp.append(File.pathSeparator).append(Misc.expandClasspath(migrateClasspath));

+    }

+ 

+    // add the Jars, closest last

+    c = container;

+    List<String> ss = new ArrayList<>();

+    while (c != null) {

+      if (c.isJar) {

+        ss.add(c.root.toString());

+      }

+      c = c.parent;

+    }

+    Collections.reverse(ss);

+    ss.forEach(s -> cp.append(File.pathSeparator).append(s));

+        

+//    System.out.println("debug: compile classpath = " + cp.toString());

+    return cp.toString();

+  }

+      

+  /** 

+   * iterate to process collections from all roots

+   * Called once, to process either sources or classes

+   * @return false if unable to compile, true otherwise

+   */

+  private boolean processRootsCollection(String kind, Container[] roots, CommandLineParser clp) {

+    unableToCompile = false; // preinit

+    

+    psb.setLength(0);

+    indent[0] = 0;

+    itemCount = 1;

+

+    

+    for (Container rootContainer : roots) { 

+      showWorkStart(rootContainer);      

+      

+      // adds candidates to root containers, and adds sub containers for Jars and Pears

+      getAndProcessCandidatesInContainer(rootContainer);

+      

+//      for (Path path : rootContainer.candidates) {

+//        

+//        CommonConverted cc = getSource(path, rootContainer);

+//        migrate(cc, rootContainer, path);

+//        

+//        if ((i % 50) == 0) System.out.format("%4d%n    ", Integer.valueOf(i));

+//        i++;

+//      }

+    }

+    si(psb).append("Total number of candidates processed: ").append(itemCount - 1);

+    flush(psb);

+    indent[0] = 0;

+    return !unableToCompile;

   }

   

+  private void showWorkStart(Container rootContainer) {

+    si(psb).append("Migrating " + rootContainer.rootOrig.toString());

+    indent[0] += 2;

+    si(psb).append("Each character is one class");

+    si(psb).append("  . means normal class");

+    si(psb).append("  b means built in");

+    si(psb).append("  i means identical duplicate");

+    si(psb).append("  d means non-identical definition for the same JCas class");

+    si(psb).append("  nnn at the end of the line is the number of classes migrated\n");

+    flush(psb);

+  }

+    

   /**

    * parse command line args

    * @param args - 

@@ -674,51 +1184,90 @@
     return clp;

   }

     

-  private String[] getRoots(CommandLineParser clp, String kind) {

-    return clp.getParamArgument(kind).split("\\" + File.pathSeparator);

+  private Container[] getRoots(CommandLineParser clp, String kind) {

+    String[] paths = clp.getParamArgument(kind).split("\\" + File.pathSeparator);

+    Container[] cs = new Container[paths.length];

+    int i = 0;

+    for (String path : paths) {

+      cs[i++] = new Container(null, Paths.get(path));

+    }

+    return cs;

   }

   

   /**

-   * If working with .class files:

-   *   - read the byte array

-   *   - see if it has already been decompiled; if so, return false

-   *   

-   * Side effect, set origSource and origBytes and alreadyDone

-   * @param c

-   * @return the source to maybe migrate

-   */

-  private String getSource(Candidate c) {

+   * @param p the path to the compiled or non-compiled source

+   * @param container the container

+   * @return the instance of the CommonConverted object, 

+   *         and update the container's convertedItems list if needed to include it

+   */ 

+  private CommonConverted getSource(Path p, Container container) {

     try {

-      origSource = null;

-      origBytes = null;

-      if (isSource) {

-        origSource = FileUtils.reader2String(Files.newBufferedReader(c.p));

-        alreadyDone = origSourceToClassName.get(origSource);

-//        System.out.println("debug read " + s.length());

+      byte[] localV2ByteCode = null;

+      

+      CommonConverted cc;

+      String v2Source;

+      

+      if (!isSource) {

+        localV2ByteCode = Files.readAllBytes(p);

+        

+        // only use prev decompiled if same container

+        cc = container.origBytesToCommonConverted.get(localV2ByteCode);

+        if (null != cc) {

+          return cc;

+        }

+        // decompile side effect: sets fqcn

+        try {

+          v2Source = decompile(localV2ByteCode, container.pearClasspath);

+        } catch (RuntimeException e) {

+          badClassName = true;

+          e.printStackTrace();

+          v2Source = null;

+        }

+        if (badClassName) {

+          System.err.println("Candidate with bad Class Name is: " + p.toString());

+          return null;

+        }

+        final byte[] finalbc = localV2ByteCode;  

+        cc = sourceToCommonConverted.computeIfAbsent(v2Source, 

+                src -> new CommonConverted(src, finalbc, p, container, packageAndClassNameSlash));

+//        cc = new CommonConverted(v2Source, localV2ByteCode, p, container, packageAndClassNameSlash);

+        container.origBytesToCommonConverted.put(localV2ByteCode, cc);

       } else {

-        origBytes = Files.readAllBytes(c.p);

-        alreadyDone = origBytesToClassName.get(origBytes);

-        if (null == alreadyDone) {

-          origSource = decompile(origBytes, c.pearClasspath);

+        

+        v2Source = FileUtils.reader2String(Files.newBufferedReader(p));

+        cc = sourceToCommonConverted.get(v2Source);

+        if (null == cc) {

+          cc = new CommonConverted(v2Source, null, p, container, "unknown");

+          sourceToCommonConverted.put(v2Source,  cc);

+        } else {

+          // add this new path + container to set of pathsAndContainers kept by this CommonConverted object

+          cc.containersAndV2Paths.add(new ContainerAndPath(p, container));  

         }

       }

-      if (alreadyDone != null) {

-        return null;

+

+      //Containers have list of CommonConverted, which, in turn 

+      //             have Set of ContainerAndPath elements.

+      //               (the same JCas class might appear in two different paths in a container)

+      if (!container.convertedItems.contains(cc)) {

+        container.convertedItems.add(cc);

       }

-            

-      return origSource;

+      

+      return cc;      

     } catch (IOException e) {

       throw new RuntimeException(e);

     }

   }

   

   /**

-   * Migrate one JCas definition.

+   * Migrate one JCas definition, writes to Sysem.out 1 char to indicate progress.

    * 

    * The source is either direct, or a decompiled version of a .class file (missing comments, etc.).

    * 

    * This method only called if heuristics indicate this is a V2 JCas class definition.

    * 

+   * Skips the migration if already done.

+   * Skips if decompiling, and it failed.

+   * 

    * The goal is to preserve as much as possible of existing customization.

    * The general approach is to parse the source into an AST, and use visitor methods.

    *   For getter/setter methods that are for features (heurstic), set up a context for inner visitors

@@ -739,112 +1288,175 @@
    *   

    * @param source - the source, either directly from a .java file, or a decompiled .class file

    */

-  private void migrate(String source) {

+  private void migrate(CommonConverted cc, Container container, Path path) {

+    

+    if (null == cc) {

+      System.err.println("Skipping this component due to decompile failure: " + path.toString());

+      System.err.println("  in container: " + container);

+      isConvert2v3 = false;  

+      error_decompiling  = true;

+      return;

+    }

+    

+    if (cc.v3Source != null) {

+      // next updates classname2multiSources for tracking non-identical defs

+      boolean identical = collectInfoForReports(cc);

+      assert identical;

+      psb.append("i");

+      flush(psb);

+      cc.containersAndV2Paths.add(new ContainerAndPath(path, container));

+      return;

+    }

+     

+    assert cc.v2Source != null;

 

-    if (alreadyDone == null) {

-      v3 = true;  // preinit

-      v2 = false;

-      featNames.clear();

-      fi_fields.clear();

-      

-  //    System.out.println("Migrating source before migration:\n");

-  //    System.out.println(source);

-  //    System.out.println("\n\n\n");

-  

+    packageName = null;

+    className = null;

+    packageAndClassNameSlash = null;

+    cu = null;

+    

+    String source = cc.v2Source;

+    isConvert2v3 = true;  // preinit, set false if convert fails

+    isV2JCas = false;     // preinit, set true by reportV2Class, called by visit to ClassOrInterfaceDeclaration,

+                          //   when it has v2 constructors, and the right type and type_index_id field declares

+    isBuiltinJCas = false;

+    featNames.clear();

+    fi_fields.clear();

+    

+    try {  // to reset the next 3 items

+      current_cc = cc;

+      current_container = container;

+      current_path = path;

+        

+    //    System.out.println("Migrating source before migration:\n");

+    //    System.out.println(source);

+    //    System.out.println("\n\n\n");

+      if (source.startsWith(ERROR_DECOMPILING)) {

+        System.err.println("Decompiling failed for class: " + cc.toString() + "\n got: " + Misc.elide(source, 300, false));

+        System.err.println("Please check the migrateClasspath");

+        if (null == migrateClasspath) {

+          System.err.println("classpath of this app is");

+          System.err.println(System.getProperty("java.class.path"));

+        } else {

+          System.err.println(" first part of migrateClasspath argument was: " + Misc.elide(migrateClasspath, 300, false));

+          System.err.println("  Value used was:");

+          URL[] urls = Misc.classpath2urls(migrateClasspath);

+          for (URL url : urls) {

+            System.err.println("    " + url.toString());

+          }

+        }

+        System.err.println("Skipping this component");

+        isConvert2v3 = false;  

+        error_decompiling  = true;

+        return;

+      }

+        

       StringReader sr = new StringReader(source);

       try {

-        cu = JavaParser.parse(sr, true);

-        

+        cu = JavaParser.parse(sr); 

+              

+        addImport("java.lang.invoke.CallSite");

+        addImport("java.lang.invoke.MethodHandle");

         addImport("org.apache.uima.cas.impl.CASImpl");

         addImport("org.apache.uima.cas.impl.TypeImpl");

         addImport("org.apache.uima.cas.impl.TypeSystemImpl");

         

-        this.visit(cu, null);      

+        this.visit(cu, null);    // side effect: sets the className, packageAndClassNameSlash, packageName  

+        

         new removeEmptyStmts().visit(cu, null);

-        if (v3) {

+        if (isConvert2v3) {

           removeImport("org.apache.uima.jcas.cas.TOP_Type");

         }

         

-        if (v3 && fi_fields.size() > 0) {

-          List<BodyDeclaration> classMembers = cu.getTypes().get(0).getMembers();

+        if (isConvert2v3 && fi_fields.size() > 0) {

+          NodeList<BodyDeclaration<?>> classMembers = cu.getTypes().get(0).getMembers();

           int positionOfFirstConstructor = findConstructor(classMembers);

           if (positionOfFirstConstructor < 0) {

             throw new RuntimeException();

           }

           classMembers.addAll(positionOfFirstConstructor, fi_fields);

-        }      

+        }

+        

+        ImportDeclaration firstImport = cu.getImports().get(0);

+        String transformedMessage = String.format(" Migrated by uimaj-v3-migration-jcas, %s%n" +

+                                  " Container: %s%n" + 

+                                  " Path in container: %s%n",

+                                  new Date(),

+                                  container.toString1(),

+                                  path.toString()).replace('\\','/'); 

+        

+        Optional<Comment> existingComment = firstImport.getComment();

+        if (existingComment.isPresent()) {

+          Comment comment = existingComment.get();

+          comment.setContent(comment.getContent() + "\n" + transformedMessage);

+        } else {

+          firstImport.setBlockComment(transformedMessage);

+        }

                 

         if (isSource) {

-          origSourceToClassName.put(origSource, packageAndClassNameSlash);

-        } else {

-          origBytesToClassName.put(origBytes, packageAndClassNameSlash);

+          sourceToCommonConverted.put(source, cc);

+        } 

+  

+        boolean identicalFound = collectInfoForReports(cc);

+        assert ! identicalFound;

+  

+        if (isV2JCas) { 

+          writeV2Orig(cc, isConvert2v3);

         }

-

-        boolean identicalFound = collectInfoForReports();

-

-        if (!identicalFound) {  // don't write out identicals

-          getBaseOutputPath();

-          if (v2) { 

-            writeV2Orig(source, v3);

-          }

-          if (v3) {

-            String s = cu.toString();

-            writeV3(s);  

-          }

-          System.out.print(".");

-        } else {

-          System.out.print("d");

+        if (isConvert2v3) {

+          cc.v3Source = new PrettyPrinter(printCu).print(cu);

+          writeV3(cc);  

         }

-      } catch (ParseException e) {

-        reportParseException();

+        

+        psb.append(isBuiltinJCas 

+                     ? "b" 

+                     : (classname2multiSources.get(cc.fqcn_slash).size() == 1)

+                         ? "."

+                         : "d");  // means non-identical duplicate

+        flush(psb);

       } catch (IOException e) {

-        throw new RuntimeException(e);

+        e.printStackTrace();

+        throw new UIMARuntimeException(e);

+      } catch (Exception e) {

+        System.out.println("debug: exception caught, source was\n" + source);

+        throw new UIMARuntimeException(e);

       }

-    } else {

-      collectInfoForReports();

-      System.out.print("d");

+    } finally {

+      current_cc = null;

+      current_container = null;

+      current_path = null;

     }

   }

 

   /**

+   * Called when have already converted this exact source or

+   *   when we just finished converting this source.

    * Add this instance to the tracking information for multiple versions (identical or not) of a class

    * @return true if this is an identical duplicate of one already done

    */

   

-  private boolean collectInfoForReports() {

-    String fqcn = (alreadyDone == null)    // fully qualified class name with slashes

-                    ? packageAndClassNameSlash

-                    : alreadyDone;

-    // for a given fully qualified class name (slashified), 

-    //   find the list of ConvertedSources - one per each different version

-    //     create it if null

-    List<ConvertedSource> convertedSources = classname2multiSources.get(fqcn);

-    if (convertedSources == null) {

-      convertedSources = new ArrayList<>();

-      classname2multiSources.put(fqcn, convertedSources);

-    }

+  private boolean collectInfoForReports(CommonConverted cc) {

+    String fqcn_slash = cc.fqcn_slash;

     

+    // track, by fqcn, all duplicates (identical or not)

+    

+//    // for a given fully qualified class name (slashified), 

+//    //   find the list of CommonConverteds - one per each different version

+//    //     create it if null

+    List<CommonConverted> commonConverteds = classname2multiSources

+        .computeIfAbsent(fqcn_slash, k -> new ArrayList<CommonConverted>());

+

     // search to see if this instance already in the set

     //   if so, add the path to the set of identicals

-    boolean found = false;

-    for (ConvertedSource cs : convertedSources) {

-      if ((isSource && cs.rOrigSource.equals(origSource)) ||

-          (!isSource && Arrays.equals(cs.rOrigBytes, origBytes))) {

-        cs.add(candidate.p);

-        found = true;

-        break;

-      }

-    }

-

-    

+    // For class sources case, we compare the decompiled version

+    boolean found = commonConverteds.contains(cc);

     if (!found) {

-      ConvertedSource cs = new ConvertedSource(origSource, origBytes, candidate.p);

-      convertedSources.add(cs);

-    }    

+      commonConverteds.add(cc);

+    }  

     

     return found;

   }

-  

+    

   /******************

    *  Visitors

    ******************/

@@ -859,11 +1471,11 @@
     super.visit(n,  ignore);

   }

 

-  @Override

-  public void visit(EmptyTypeDeclaration n, Object ignore) {

-    updateClassName(n);

-    super.visit(n,  ignore);

-  }

+//  @Override

+//  public void visit(EmptyTypeDeclaration n, Object ignore) {

+//    updateClassName(n);

+//    super.visit(n,  ignore);

+//  }

 

   @Override

   public void visit(EnumDeclaration n, Object ignore) {

@@ -888,42 +1500,51 @@
   public void visit(ClassOrInterfaceDeclaration n, Object ignore) {

     // do checks to see if this is a JCas class; if not report skipped

    

-    if (n.getParentNode() instanceof CompilationUnit) {

-      updateClassName(n);

-      List<ClassOrInterfaceType> supers = n.getExtends();

-      if (supers == null || supers.size() == 0) {

-        reportNotJCasClass("class doesn't extend a superclass");

-        super.visit(n, ignore);

-        return; 

+    Optional<Node> maybeParent = n.getParentNode();

+    if (maybeParent.isPresent()) {

+      Node parent = maybeParent.get();

+      if (parent instanceof CompilationUnit) {

+        updateClassName(n);

+        if (isBuiltinJCas) {

+          // is a built-in class, skip it

+          super.visit(n, ignore);

+          return;

+        }

+        NodeList<ClassOrInterfaceType> supers = n.getExtendedTypes();

+        if (supers == null || supers.size() == 0) {

+          reportNotJCasClass("class doesn't extend a superclass");

+          super.visit(n, ignore);

+          return; 

+        }

+        

+        NodeList<BodyDeclaration<?>> members = n.getMembers();

+        setHasJCasConstructors(members);

+        if (hasV2Constructors && hasTypeFields(members)) {

+          reportV2Class();

+          super.visit(n,  ignore);

+          return;

+        }

+        if (hasV2Constructors) {

+          reportNotJCasClassMissingTypeFields();

+          return;

+        }

+        if (hasV3Constructors) {

+          reportV3Class();

+          return;

+        }

+        reportNotJCasClass("missing v2 constructors");

+        return;        

       }

-      

-      List<BodyDeclaration> members = n.getMembers();

-      setHasJCasConstructors(members);

-      if (hasV2Constructors && hasTypeFields(members)) {

-        reportV2Class();

-        super.visit(n,  ignore);

-        return;

-      }

-      if (hasV2Constructors) {

-        reportNotJCasClassMissingTypeFields();

-        return;

-      }

-      if (hasV3Constructors) {

-        reportV3Class();

-        return;

-      }

-      reportNotJCasClass("missing v2 constructors");

-      return;

-      

-    } else { // do standard processing for non-outer class

-      super.visit(n,  ignore);

-      return;

     }

+    

+    super.visit(n,  ignore);

+    return;

+    

   }

   

   @Override

   public void visit(PackageDeclaration n, Object ignored) {

-    packageName = n.getName().toString();

+    packageName = n.getNameAsString();

     super.visit(n, ignored);

   }

     

@@ -936,7 +1557,7 @@
   @Override

   public void visit(ConstructorDeclaration n, Object ignored) {

     super.visit(n, ignored);  // processes the params 

-    if (!v3) {  // for enums, annotations

+    if (!isConvert2v3) {  // for enums, annotations

       return;

     }

     List<Parameter> ps = n.getParameters();

@@ -953,12 +1574,12 @@
       setParameter(ps, 1, "CASImpl", "casImpl");

       

       // Body: change the 1st statement (must be super)

-      List<Statement> stmts = n.getBlock().getStmts();

+      NodeList<Statement> stmts = n.getBody().getStatements();

       if (!(stmts.get(0) instanceof ExplicitConstructorInvocationStmt)) {

         recordBadConstructor("missing super call");

         return;

       }

-      List<Expression> args = ((ExplicitConstructorInvocationStmt)(stmts.get(0))).getArgs();

+      NodeList<Expression> args = ((ExplicitConstructorInvocationStmt)(stmts.get(0))).getArguments();

       args.set(0, new NameExpr("type"));

       args.set(1,  new NameExpr("casImpl"));

      

@@ -984,9 +1605,10 @@
    *****************************/

   @Override

   public void visit(MethodDeclaration n, Object ignore) {

-    String name = n.getName();

+    String name = n.getNameAsString();

     isGetter = isArraySetter = false;

     do {  // to provide break exit

+      

       if (name.length() >= 4 && 

           ((isGetter = name.startsWith("get")) || name.startsWith("set")) &&

           Character.isUpperCase(name.charAt(3)) &&

@@ -1004,7 +1626,7 @@
         }

         

         // get the range-part-name and convert to v3 range ("Ref" changes to "Feature")

-        String bodyString = n.getBody().toStringWithoutComments();

+        String bodyString = n.getBody().get().toString(printWithoutComments);

         int i = bodyString.indexOf("jcasType.ll_cas.ll_");

         if (i < 0) break; 

         String s = bodyString.substring(i + "jcasType.ll_cas.ll_get".length()); // also for ...ll_set - same length!

@@ -1044,16 +1666,39 @@
             reportMismatchedFeatureName(String.format("%-25s %s", featName, name));

           }

         }

+        // add _FI_xxx = TypeSystemImpl.getAdjustedFeatureOffset("xxx");

+        // replaced Sept 2017

+//        NodeList<Expression> args = new NodeList<>();

+//        args.add(new StringLiteralExpr(featName));

+//        VariableDeclarator vd = new VariableDeclarator(

+//            intType, 

+//            "_FI_" + featName, 

+//            new MethodCallExpr(new NameExpr("TypeSystemImpl"), new SimpleName("getAdjustedFeatureOffset"), args));

+//        if (featNames.add(featName)) {  // returns true if it was added, false if already in the set of featNames

+//          fi_fields.add(new FieldDeclaration(public_static_final, vd));

+//        }

         

-        List<Expression> args = Collections.singletonList(new StringLiteralExpr(featName));

-        VariableDeclarator vd = new VariableDeclarator(

-            new VariableDeclaratorId("_FI_" + featName),

-            new MethodCallExpr(null, "TypeSystemImpl.getAdjustedFeatureOffset", args));

-        if (featNames.add(featName)) {

-          fi_fields.add(new FieldDeclaration(

-              Modifier.PUBLIC + Modifier.STATIC + Modifier.FINAL, 

-              ASTHelper.INT_TYPE, 

-              vd));

+        // add _FC_xxx = TypeSystemImpl.createCallSite(ccc.class, "xxx");

+        // add _FH_xxx = _FC_xxx.dynamicInvoker();

+        // add _FeatName_xxx = "xxx"  //  https://issues.apache.org/jira/browse/UIMA-5575

+        

+        if (featNames.add(featName)) {  // returns true if it was added, false if already in the set of featNames

+          // _FC_xxx = TypeSystemImpl.createCallSite(ccc.class, "xxx");

+          MethodCallExpr initCallSite = new MethodCallExpr(new NameExpr("TypeSystemImpl"), "createCallSite");

+          initCallSite.addArgument(new FieldAccessExpr(new NameExpr(className), "class"));

+          initCallSite.addArgument(new StringLiteralExpr(featName));

+          VariableDeclarator vd_FC = new VariableDeclarator(callSiteType, "_FC_" + featName, initCallSite);

+          fi_fields.add(new FieldDeclaration(private_static_final, vd_FC));

+          

+          // _FH_xxx = _FC_xxx.dynamicInvoker();

+          MethodCallExpr initInvoker = new MethodCallExpr(new NameExpr(vd_FC.getName()), "dynamicInvoker");

+          VariableDeclarator vd_FH = new VariableDeclarator(methodHandleType, "_FH_" + featName, initInvoker);

+          fi_fields.add(new FieldDeclaration(private_static_final, vd_FH));

+          

+          // _FeatName_xxx = "xxx"  //  https://issues.apache.org/jira/browse/UIMA-5575

+          VariableDeclarator vd_fn = new VariableDeclarator(stringType, "_FeatName_" + featName, new StringLiteralExpr(featName));

+          fi_fields.add(new FieldDeclaration(public_static_final, vd_fn));

+           

         }

         

         /**

@@ -1065,11 +1710,11 @@
          *       ll_getRefArrayValue  

          */

         if (isGetter && "Feature".equals(rangeNamePart)) {

-          for (Statement stmt : n.getBody().getStmts()) {

+          for (Statement stmt : n.getBody().get().getStatements()) {

             if (stmt instanceof ReturnStmt) {

-              Expression e = getUnenclosedExpr(((ReturnStmt)stmt).getExpr());

+              Expression e = getUnenclosedExpr(((ReturnStmt)stmt).getExpression().get());

               if ((e instanceof MethodCallExpr)) {

-                String methodName = ((MethodCallExpr)e).getName();

+                String methodName = ((MethodCallExpr)e).getNameAsString();

                 if (refGetter.matcher(methodName).matches()) { // ll_getRefValue or ll_getRefArrayValue

                   addCastExpr(stmt, n.getType());

                 }

@@ -1102,7 +1747,7 @@
       List<Statement> stmts;

       if ((c instanceof BinaryExpr) &&

           ((be = (BinaryExpr)c).getLeft() instanceof FieldAccessExpr) &&

-          ((FieldAccessExpr)be.getLeft()).getField().equals("featOkTst")) {

+          ((FieldAccessExpr)be.getLeft()).getNameAsString().equals("featOkTst")) {

         // remove the feature missing if statement

         

         // verify the remaining form 

@@ -1111,12 +1756,12 @@
          || ! (be2.getLeft() instanceof FieldAccessExpr)

 

          || ! ((e = getExpressionFromStmt(n.getThenStmt())) instanceof MethodCallExpr)

-         || ! (((MethodCallExpr)e).getName()).equals("throwFeatMissing")) {

+         || ! (((MethodCallExpr)e).getNameAsString()).equals("throwFeatMissing")) {

           reportDeletedCheckModified("The featOkTst was modified:\n" + n.toString() + '\n');

         }

               

-        BlockStmt parent = (BlockStmt) n.getParentNode();

-        stmts = parent.getStmts();

+        BlockStmt parent = (BlockStmt) n.getParentNode().get();

+        stmts = parent.getStatements();

         stmts.set(stmts.indexOf(n), new EmptyStmt()); //dont remove

                                             // otherwise iterators fail

 //        parent.getStmts().remove(n);

@@ -1131,26 +1776,27 @@
    */

   @Override

   public void visit(MethodCallExpr n, Object ignore) {

-    Node p1, p2, updatedNode = null;

-    List<Expression> args;

+    Optional<Node> p1, p2, p3 = null; 

+    Node updatedNode = null;

+    NodeList<Expression> args;

     

     do {

       if (get_set_method == null) break;

-

+     

       /** remove checkArraybounds statement **/

-      if (n.getName().equals("checkArrayBounds") &&

-          ((p1 = n.getParentNode()) instanceof ExpressionStmt) &&

-          ((p2 = p1.getParentNode()) instanceof BlockStmt) &&

-          p2.getParentNode() == get_set_method) {

-        List<Statement> stmts = ((BlockStmt)p2).getStmts();

-        stmts.set(stmts.indexOf(p1), new EmptyStmt());

+      if (n.getNameAsString().equals("checkArrayBounds") &&

+          ((p1 = n.getParentNode()).isPresent() && p1.get() instanceof ExpressionStmt) &&

+          ((p2 = p1.get().getParentNode()).isPresent() && p2.get() instanceof BlockStmt) &&

+          ((p3 = p2.get().getParentNode()).isPresent() && p3.get() == get_set_method)) {

+        NodeList<Statement> stmts = ((BlockStmt)p2.get()).getStatements();

+        stmts.set(stmts.indexOf(p1.get()), new EmptyStmt());

         return;

       }

            

       // convert simpleCore expression ll_get/setRangeValue

       boolean useGetter = isGetter || isArraySetter;

-      if (n.getName().startsWith("ll_" + (useGetter ? "get" : "set") + rangeNameV2Part + "Value")) {

-        args = n.getArgs();

+      if (n.getNameAsString().startsWith("ll_" + (useGetter ? "get" : "set") + rangeNameV2Part + "Value")) {

+        args = n.getArguments();

         if (args.size() != (useGetter ? 2 : 3)) break;

         String suffix = useGetter ? "Nc" : rangeNamePart.equals("Feature") ? "NcWj" : "Nfc";

         String methodName = "_" + (useGetter ? "get" : "set") + rangeNamePart + "Value" + suffix; 

@@ -1162,26 +1808,27 @@
       

       // convert array sets/gets

       String z = "ll_" + (isGetter ? "get" : "set");

-      if (n.getName().startsWith(z) &&

-          n.getName().endsWith("ArrayValue")) {

+      String nname = n.getNameAsString();

+      if (nname.startsWith(z) &&

+          nname.endsWith("ArrayValue")) {

         

-        String s = n.getName().substring(z.length());

+        String s = nname.substring(z.length());

         s = s.substring(0,  s.length() - "Value".length()); // s = "ShortArray",  etc.

         if (s.equals("RefArray")) s = "FSArray";

         if (s.equals("IntArray")) s = "IntegerArray";

         EnclosedExpr ee = new EnclosedExpr(

-            new CastExpr(new ClassOrInterfaceType(s), n.getArgs().get(0)));

+            new CastExpr(new ClassOrInterfaceType(s), n.getArguments().get(0)));

         

         n.setScope(ee);    // the getter for the array fs

         n.setName(isGetter ? "get" : "set");

-        n.getArgs().remove(0);

+        n.getArguments().remove(0);

       }

       

       /** remove ll_getFSForRef **/

       /** remove ll_getFSRef **/

-      if (n.getName().equals("ll_getFSForRef") ||

-          n.getName().equals("ll_getFSRef")) {

-        updatedNode = replaceInParent(n, n.getArgs().get(0));        

+      if (n.getNameAsString().equals("ll_getFSForRef") ||

+          n.getNameAsString().equals("ll_getFSRef")) {

+        updatedNode = replaceInParent(n, n.getArguments().get(0));        

       }

       

       

@@ -1204,15 +1851,23 @@
   @Override

   public void visit(FieldAccessExpr n, Object ignore) {

     Expression e;

+    Optional<Expression> oe;

+    String nname = n.getNameAsString();

     

     if (get_set_method != null) {  

-      if (n.getField().startsWith("casFeatCode_") &&

-          ((e = getUnenclosedExpr(n.getScope())) instanceof CastExpr) &&

-          ("jcasType".equals(getName(((CastExpr)e).getExpr())))) {

-        String featureName = n.getField().substring("casFeatCode_".length());

-        replaceInParent(n, new NameExpr("_FI_" + featureName)); // repl last in List<Expression> (args)

+      if (nname.startsWith("casFeatCode_") &&

+          ((oe = n.getScope()).isPresent()) &&

+          ((e = getUnenclosedExpr(oe.get())) instanceof CastExpr) &&

+          ("jcasType".equals(getName(((CastExpr)e).getExpression())))) {

+        String featureName = nname.substring("casFeatCode_".length());

+//        replaceInParent(n, new NameExpr("_FI_" + featureName)); // repl last in List<Expression> (args)

+        

+        MethodCallExpr getint = new MethodCallExpr(null, "wrapGetIntCatchException");

+        getint.addArgument(new NameExpr("_FH_" + featureName));

+        replaceInParent(n, getint);

+        

         return;

-      } else if (n.getField().startsWith("casFeatCode_")) {

+      } else if (nname.startsWith("casFeatCode_")) {

         reportMigrateFailed("Found field casFeatCode_ ... without a previous cast expr using jcasType");

       }

     }

@@ -1222,7 +1877,7 @@
   private class removeEmptyStmts extends VoidVisitorAdapter<Object> {

     @Override

     public void visit(BlockStmt n, Object ignore) {

-      Iterator<Statement> it = n.getStmts().iterator();

+      Iterator<Statement> it = n.getStatements().iterator();

       while (it.hasNext()) {

         if (it.next() instanceof EmptyStmt) {

           it.remove();

@@ -1233,11 +1888,11 @@
     

 //    @Override

 //    public void visit(MethodDeclaration n, Object ignore) {

-//      if (n.getName().equals("getModifiablePrimitiveNodes")) {

+//      if (n.getNameAsString().equals("getModifiablePrimitiveNodes")) {

 //        System.out.println("debug");

 //      }

 //      super.visit(n,  ignore);

-//      if (n.getName().equals("getModifiablePrimitiveNodes")) {

+//      if (n.getNameAsString().equals("getModifiablePrimitiveNodes")) {

 //        System.out.println("debug");

 //      }

 //    }

@@ -1259,38 +1914,66 @@
     pprintRoots("Sources", sourcesRoots);

     pprintRoots("Classes", classesRoots);

 

-    boolean isOk = true;

+    boolean isOk2 = true;

     try {

-      isOk = isOk && reportPaths("Workaround Directories", "workaroundDir.txt", pathWorkaround);

-      isOk = isOk && reportPaths("Reports of converted files where a deleted check was customized", "deletedCheckModified.txt", deletedCheckModified);

-      isOk = isOk && reportPaths("Reports of converted files needing manual inspection", "manualInspection.txt", manualInspection);

-      isOk = isOk && reportPaths("Reports of files which failed migration", "failed.txt", failedMigration);

-      isOk = isOk && reportPaths("Reports of non-JCas files", "NonJCasFiles.txt", nonJCasFiles);

-      isOk = isOk && reportPaths("Builtin JCas classes - skipped - need manual checking to see if they are modified",

-          "skippedBuiltins.txt", skippedBuiltins);

-      // can't do the pear report here - post processing not yet done.      

+      // these reports, if non-empty items, imply something needs manual checking, so reset isOk2

+      isOk2 = reportPaths("Workaround Directories", "workaroundDir.txt", pathWorkaround) && isOk2;

+      isOk2 = reportPaths("Reports of converted files where a deleted check was customized", "deletedCheckModified.txt", deletedCheckModified) && isOk2;

+      isOk2 = reportPaths("Reports of converted files needing manual inspection", "manualInspection.txt", manualInspection) && isOk2;

+      isOk2 = reportPaths("Reports of files which failed migration", "failed.txt", failedMigration) && isOk2;

+      isOk2 = reportPaths("Reports of non-JCas files", "NonJCasFiles.txt", nonJCasFiles) && isOk2;

+      isOk2 = reportPaths("Builtin JCas classes - skipped - need manual checking to see if they are modified",

+          "skippedBuiltins.txt", skippedBuiltins) && isOk2;

+

+      // these reports, if non-empty, do not imply OK issues

+      reportPaths("Reports of updated Jars", "jarFileUpdates.txt", jarClassReplace);

+      reportPaths("Reports of updated PEARs", "pearFileUpdates.txt", pearClassReplace);

+         

 //      computeDuplicates();

 //      reportPaths("Report of duplicates - not identical", "nonIdenticalDuplicates.txt", nonIdenticalDuplicates);

 //      reportPaths("Report of duplicates - identical", "identicalDuplicates.txt", identicalDuplicates);

-      isOk = isOk && reportDuplicates();

-      

-      reportPaths("Report of processed files", "processed.txt", c2ps);

-      return isOk;

+//      isOk2 = reportDuplicates() && isOk2;  // false if non-identical duplicates

+           

+      return isOk2;

     } catch (IOException e) {

       throw new RuntimeException(e);

     }

   }

 

-  private void pprintRoots(String kind, String[] roots) {

-    if (roots.length > 0) {

-      System.out.println(kind + " Roots:");

-      for (String s : roots) {

-        System.out.format("    %s%n",  s);

+  private void pprintRoots(String kind, Container[] roots) {

+    if (roots != null && roots.length > 0) {

+      try {

+        try (BufferedWriter bw = Files.newBufferedWriter(makePath(outDirLog + "ItemsProcessed"), StandardOpenOption.CREATE)) {

+          logPrintNl(kind + " Roots:", bw);

+          indent[0] += 2;

+          try {

+          for (Container container : roots) {

+            pprintContainer(container, bw);

+          }

+          logPrintNl("", bw);

+          } finally {

+            indent[0] -= 2;

+          }

+        }

+      } catch (IOException e) {

+        throw new UIMARuntimeException(e);

       }

-      System.out.println("\n");

     }

   }

   

+  private void pprintContainer(Container container, BufferedWriter bw) throws IOException {

+    logPrintNl(container.toString(), bw);

+    if (container.subContainers.size() > 1) {

+      logPrintNl("", bw);

+      indent[0] += 2;

+      for (Container subc : container.subContainers) {

+        pprintContainer(subc, bw);

+      }

+    }

+    

+    

+  }

+  

 //  private void computeDuplicates() {

 //    List<ClassnameAndPath> toCheck = new ArrayList<>(c2ps);

 //    toCheck.addAll(extendableBuiltins);

@@ -1332,8 +2015,8 @@
 //   * @return

 //   */

 //  private boolean isFilesMiscompare(Path p1, Path p2) {

-//      String s1 = getSource(p1);

-//      String s2 = getSource(p2);

+//      String s1 = (p1);

+//      String s2 = (p2);

 //      return !s1.equals(s2);

 //  }

   

@@ -1347,77 +2030,68 @@
 //    }

 //  }

  

+  /**

+   * 

+   * @param name

+   * @return a path made from name, with directories created

+   * @throws IOException

+   */

   private Path makePath(String name) throws IOException {

     Path p = Paths.get(name);

-    Path parent = p.getParent();

+    Path parent = p.getParent();  // all the parts of the path up to the final segment

+    if (parent == null) {

+      return p;

+    }

     try {

       Files.createDirectories(parent);

-    } catch (FileAlreadyExistsException e) {

+    } catch (FileAlreadyExistsException e) { // parent already exists but is not a directory!

       // caused by running on Windows system which ignores "case"

       // there's a file at /x/y/  named "z", but the path wants to be /x/y/Z/

       //   Workaround: change "z" to "z_c"  c for capitalization issue

-      String newDir = parent.getFileName().toString() + "_c";

-      Path p2 = Paths.get(parent.getParent().toString(), newDir);

-      Files.createDirectories(p2);

+      current_container.haveDifferentCapitalizedNamesCollidingOnWindows = true;

+      Path fn = parent.getFileName();

+      if (fn == null) {

+        throw new IllegalArgumentException();

+      }

+      String newDir = fn.toString() + "_c";

+      Path parent2 = parent.getParent();

+      

+      Path p2 = parent2 == null ? Paths.get(newDir) : Paths.get(parent2.toString(), newDir);

+      try {

+        Files.createDirectories(p2);

+      } catch (FileAlreadyExistsException e2) { // parent already exists but is not a directory!

+        throw new RuntimeException(e2);

+      }

+      

       reportPathWorkaround(parent.toString(), p2.toString());

-      return Paths.get(p2.toString(), p.getFileName().toString());

+      Path lastPartOfPath = p.getFileName();

+      if (null == lastPartOfPath) throw new RuntimeException();

+      return Paths.get(p2.toString(), lastPartOfPath.toString());

     }

     return p;

   }

   

-  private boolean reportDuplicates() {

-    List<Entry<String, List<ConvertedSource>>> nonIdenticals = new ArrayList<>();

-    List<ConvertedSource> onlyIdenticals = new ArrayList<>();

-    for (Entry<String, List<ConvertedSource>> e : classname2multiSources.entrySet()) {

-      List<ConvertedSource> convertedSourcesFor1class = e.getValue();

-      if (convertedSourcesFor1class.size() > 1) {

-        // have multiple non-identical sources for one class

-        nonIdenticals.add(e);

-      } else {

-        ConvertedSource cs = convertedSourcesFor1class.get(0);

-        if (cs.paths.size() > 1) {

-          // have multiple (only) identical sources for one class

-          onlyIdenticals.add(cs);

-        }

-      }

-    }

-    

-    if (nonIdenticals.size() == 0) {

-      if (onlyIdenticals.size() == 0) {

-        System.out.println("There were no duplicates found.");

-      } else {

-        // report identical duplicates

-        System.out.println("Identical duplicates (only):");

-        for (ConvertedSource cs : onlyIdenticals) {

-          for (Path path : cs.paths) {

-            System.out.println("  " + vWithFileSys(path));

-          }

-        }

-      }

-      return true;

-    } else {

-      System.out.println("Report of non-identical duplicates");

-      for (Entry<String, List<ConvertedSource>> nonIdentical : nonIdenticals) {

-        System.out.println("  classname: " + nonIdentical.getKey());

-        int i = 1;

-        for (ConvertedSource cs : nonIdentical.getValue()) {

-          System.out.println("    version " + i);

-          for (Path path : cs.paths) {

-            System.out.println("      " + vWithFileSys(path));

-          }

-          i++;

-        }

-      }

-    }

-    return false;

+  

+  private void logPrint(String msg, Writer bw) throws IOException {

+    System.out.print(msg);

+    bw.write(msg);

+  }

+  

+  private void logPrintNl(String msg, Writer bw) throws IOException {

+    logPrint(msg, bw);

+    logPrint("\n", bw);

   }

   

   /**

+   * prints "There were no xxx" if there are no items.

+   * prints a title, followed by a ================== underneath it

    * 

-   * @param title -

-   * @param fileName -

-   * @param items -

-   * @return true if likely ok

+   * prints a sorted report of two fields.

+   * 

+   * @param title title of report

+   * @param fileName file name to save the report in (as well as print to sysout

+   * @param items the set of items to report on-

+   * @return true if items were empty

    * @throws IOException -

    */

   private <T, U> boolean reportPaths(String title, String fileName, List<? extends Report2<T, U>> items) throws IOException {

@@ -1434,284 +2108,341 @@
 

       sortReport2(sorted);  

       int max = 0;

+      int nbrFirsts = 0;

+      Object prevFirst = null;

       for (Report2<T, U> p : sorted) {

         max = Math.max(max, p.getFirstLength());

+        Comparable<T> first = p.getFirst();

+        if (first != prevFirst) {

+          prevFirst = first;

+          nbrFirsts ++;

+        }

       }

       

+      /** 

+       * Two styles.

+       *   Style 1: where nbrFirst &lt;= 25% nbr: first on separate line, seconds indented

+       *   Style 2: firsts and seconds on same line.

+       */

       int i = 1;

+      boolean style1 = nbrFirsts <= sorted.size() / 4;

+      prevFirst = null;

       for (Report2<T, U> p : sorted) {

-        Object v = p.getSecond();

-        String s = String.format("%5d %-" +max+ "s %s%n", Integer.valueOf(i), p.getFirst(), vWithFileSys(v));

-        bw.write(s);

-        System.out.print(s);

+        if (style1) {

+          

+          if (prevFirst != p.getFirst()) {

+            prevFirst = p.getFirst();

+            logPrintNl(String.format("\n  For: %s", p.getFirst()), bw);

+          } 

+          logPrintNl(String.format("    %5d   %s", Integer.valueOf(i), p.getSecond()), bw);

+        } else {

+          logPrintNl(String.format("%5d %-" +max+ "s %s", Integer.valueOf(i), p.getFirst(), p.getSecond()), bw);

+        }

         i++;

       }

       System.out.println("");

     } // end of try-with-resources

     return false;

   }

-  

-  private String vWithFileSys(Object v) {

-    if (v instanceof Path) {

-      Path path = (Path) v;

-      FileSystem fileSystem = path.getFileSystem();

-      if (fileSystem instanceof com.sun.nio.zipfs.ZipFileSystem) {

-        v = v.toString() + "\t\t " + fileSystem.toString();

-      }

-    }

-    return v.toString();

+    

+  private boolean isZipFs(Object o) {

+    // Surprise! sometimes the o is not an instance of FileSystem but is the zipfs anyways

+    return o.getClass().getName().contains("zipfs");  // java 8 and 9

   }

   

+  /**

+   * Sort the items on first, then second

+   * @param items

+   */

   private <T, U> void sortReport2(List<? extends Report2<T, U>> items) {

     Collections.sort(items, 

         (o1, o2) -> {

-          int r = o1.getFirst().compareTo((T) o2.getFirst());

+          int r = protectedCompare(o1.getFirst(), o2.getFirst());           

           if (r == 0) {

-            r = o1.getSecond().compareTo((U) o2.getSecond());

+            r = protectedCompare(o1.getSecond(), o2.getSecond());

           }

           return r;

         });

   }

+        

+  /**

+   * protect against comparing zip fs with non-zip fs - these are not comparable to each other in IBM Java 8

+   * @return -

+   */

+  private <T> int protectedCompare(Comparable<T> comparable, Comparable<T> comparable2) {

+    //debug

+    try {

+      if (isZipFs(comparable)) {

+        if (isZipFs(comparable2)) {

+          return comparable.compareTo((T) comparable2);  // both zip

+        } else {

+          return 1;

+        }

+      } else {

+        if (isZipFs(comparable2)) {

+          return -1;

+        } else {

+          return comparable.compareTo((T) comparable2);  // both not zip

+        }

+      }

+    } catch (ClassCastException e) {

+      //debug

+      System.out.format("Internal error: c1: %b  c2: %b%n c1: %s%n c2: %s%n", isZipFs(comparable), isZipFs(comparable2), comparable.getClass().getName(), comparable2.getClass().getName());

+      throw e;

+    }

+  }

 

   /**

+   * Called only for top level roots.  Sub containers recurse getCandidates_processFile2.

+   * 

    * Walk the directory tree rooted at root

    *   - descend subdirectories

    *   - descend Jar file

    *     -- descend nested Jar files (!)

    *        by extracting these to a temp dir, and keeping a back reference to where they were extracted from.

    *   

-   * output the paths representing the classes

+   * output the paths representing the classes to migrate:  

+   *      classes having a _Type partner

+   *      excluding things other than .java or .classes, and excluding anything with "$" in the name

    *   - the path includes the "file system".

    * @param root

-   * @return list of Paths to walk

    * @throws IOException

    */

-  private List<Candidate> getCandidates(CommandLineParser clp, String root) {

-    isSkipTypeCheck  = clp.isInArgsList(SKIP_TYPE_CHECK);

-    Path startPath = Paths.get(root);

-    candidates = new ArrayList<>();

+  private void getAndProcessCandidatesInContainer(Container container) {

     

-    try (Stream<Path> stream = Files.walk(startPath, FileVisitOption.FOLLOW_LINKS)) {  // needed to release file handles

+//    current_paths2RootIds = top_paths2RootIds;  // don't do lower, that's called within Jars etc.

+    

+    try (Stream<Path> stream = Files.walk(container.root, FileVisitOption.FOLLOW_LINKS)) {  // needed to release file handles

         stream.forEachOrdered(

-          p -> getCandidates_processFile(p, null));

+            // only puts into the RootIds possible Fqcn (ending in either .class or .java)

+          p -> getCandidates_processFile2(p, container));

     } catch (IOException e) {

       throw new RuntimeException(e);

     }

-    

-    Collections.sort(candidates, pathComparator);

-   

-    // the collection potentially includes inner class files

-    

-    List<Candidate> c = new ArrayList<>();  // candidates

-    final int nbrOfPaths = candidates.size();

-    if (nbrOfPaths == 0) {

-      return c;

+

+    // walk from root container, remove items not JCas candidates

+    // prunes empty rootIds and subContainer nodes

+    removeNonJCas(container);

+

+    if (container.candidates.size() == 0 && 

+        container.subContainers.size() == 0) { // above call might remove all candidates

+      Container parent = container.parent;

+      if (parent != null) {

+//        System.out.println("No Candidates found, removing container: " + container.toString() );

+//        // debug

+//        System.out.println("debug: " + container.rootOrig.toString());

+        parent.subContainers.remove(container);

+      }

+      return;

     }

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

-     

-      // skip files that end with _Type or 

-      //   appear to be inner files: have names with a "$" char

-      candidate = candidates.get(i);

-      String lastPartOfPath = candidate.p.getFileName().toString();

-      if (lastPartOfPath.endsWith(isSource ? "_Type.java" : "_Type.class")) {

-        continue;  // skip the _Type files

-      }

-      

-      if (lastPartOfPath.contains("$")) {

-        continue;  // inner class

-      }

-      

-      if (isSkipTypeCheck) {

-        c.add(candidate);

-      } else {

-        // doing _Type check: only include java files if there's an associated _Type file

-        //   in the sort order, these follow the file without the _Type suffix

-        //   but perhaps there are other names inbetween

-        boolean has_Type = has_Type(candidate, i + 1);  // look for the next _Type file starting at position i + 1

-        if (!has_Type) {

-          continue;  // not a JCas class

+    

+    si(psb).append("Migrating JCas files ");

+    psb.append( container.isJar

+                  ? "in Jar: "

+                  : container.isPear 

+                     ? "in Pear: "

+                     : "from root: ");

+    psb.append(container.rootOrig);

+    

+    indent[0] += 2;

+    si(psb);

+    flush(psb);

+    try {

+      for (Path path : container.candidates) {

+        

+        CommonConverted cc = getSource(path, container);

+        // migrate checks to see if already done, outputs a "." or some other char for the candidate

+        migrate(cc, container, path);

+        

+        //defer any compilation to container level

+  

+        if ((itemCount % 50) == 0) {

+          psb.append(" ").append(itemCount);

+          si(psb);

+          flush(psb);

         }

-        c.add(candidate);  

+        itemCount++;

       }

+      

+      psb.append(" ").append(itemCount - 1);

+      flush(psb);

+  

+      

+      if (isSource) {

+        return;  // done

+      }

+      

+      if (!isSource &&

+          !container.haveDifferentCapitalizedNamesCollidingOnWindows && 

+          javaCompiler != null) {

+        boolean somethingCompiled = compileV3SourcesCommon2(container);

+        if (container.isPear || container.isJar) {

+          if (somethingCompiled) {

+            postProcessPearOrJar(container);

+          }

+        }

+        return;

+      }

+      

+      unableToCompile = true;

+      return;  // unable to do post processing or compiling

+    } finally {

+      indent[0] -= 2;

     }

-    return c;  

+  }

+

+  // removes nonJCas candidates

+  private void removeNonJCas(Container container) {

+    Iterator<Path> it = container.candidates.iterator();

+    while (it.hasNext()) {

+      String candidate = it.next().toString();

+      // remove non JCas classes

+//      //debug

+//      System.out.println("debug, testing to remove: " + candidate);

+//      if (candidate.indexOf("Corrected") >= 0) {

+//        if (!container._Types.contains(candidate)) {

+//          System.out.println("debug dumping _Types map keys to see why ... Corrected.class not there");

+//          System.out.println("debug key is=" + candidate);

+//          System.out.println("keys are:");

+//          int i = 0;

+//          for (String k : container._Types) {

+//            if (i == 4) {

+//              i = 0;

+//              System.out.println("");

+//            }

+//            System.out.print(k + ", ");

+//          }

+//        } else {

+//          System.out.println("debug container._Types did contain " + candidate);

+//        }

+//      }

+      if (!container._Types.contains(candidate)) {

+          it.remove();

+      }

+    }    

   }

   

-  private final static Comparator<Candidate> pathComparator = new Comparator<Candidate>() {

-    @Override

-    public int compare(Candidate o1, Candidate o2) {

-      return o1.p.toString().compareTo(o2.p.toString());

-    }

-  };

-  

-//  // there may be several same-name roots not quite right

-//  //   xxx_Type$1.class

-//  

-//  private void addIfPreviousIsSameName(List<Path> c, int i) {

-//    if (i == 0) return;

-//    String _Type = candidates.get(i).toString();

-////    String prev = r.get(i-1).getPath();

-//    String prefix = _Type.substring(0, _Type.length() - ("_Type." + (isSource ? "java" : "class")).length());

-//    i--;

-//    while (i >= 0) {

-//      String s = candidates.get(i).toString();

-//      if ( ! s.startsWith(prefix)) {

-//        break;

-//      }

-//      if (s.substring(prefix.length()).equals((isSource ? ".java" : ".class"))) {

-//        c.add(candidates.get(i));

-//        break;

-//      }

-//      i--;

-//    }

-//  }

-    

-  

   /**

+   * Called from Stream walker starting at a root or starting at an imbedded Jar or Pear.

+   * 

    * adds all the .java or .class files to the candidates, including _Type if not skipping the _Type check

+   * 

    * Handling embedded jar files

    *   - single level Jar (at the top level of the default file system)

    *     -- handle using an overlayed file system

    *   - embedded Jars within Jars: 

    *     - not supported by Zip File System Provider (it only supports one level)

    *     - handle by extracting to a temp dir, and then using the Zip File System Provider

-   * @param path the path to a .java or .class or .jar or .pear

+   * 

+   * For PEARs, check for and disallow nested PEARs; install the PEAR, set the pear classpath for

+   *   recursive processing with the Pear.

+   *   

+   * For Jar and PEAR files, use local variable + recursive call to update current_paths2RootIds map

+   *   to new one for the Jar / Pear, and then process recursiveloy

+   *    

+   * @param path the path to a .java or .class or .jar or .pear that was walked to

    * @param pearClasspath - a string representing a path to the pear's classpath if there is one, or null

+   * @param container the container for the 

+   *                    - rootIds (which have the JCas candidates) and

+   *                    - subContainers for imbedded Pears and Jars

    */

-  private void getCandidates_processFile(Path path, String pearClasspath) {

-//    System.out.println("debug processing " + path);

-    try {

-//      URI pathUri = path.toUri();

-      String pathString = path.toString();

-      final boolean isPear = pathString.endsWith(".pear");

-      final boolean isJar = pathString.endsWith(".jar");

-            

-      if (isJar || isPear) {  // path.endsWith does not mean this !!

-        if (!path.getFileSystem().equals(FileSystems.getDefault())) {        

-          // embedded Jar: extract to temp

-          Path out = getTempOutputPath(path);

-          Files.copy(path, out, StandardCopyOption.REPLACE_EXISTING);

-//          embeddedJars.add(new PathAndPath(path, out));

-          path = out;

-        }

-        

-        Path start;

-        final String localPearClasspath; 

-        if (isPear) {

-          if (pearClasspath != null) {

-            throw new UIMARuntimeException("Nested PEAR files not supported");

-          }

-          

-          pear_current = new PearOrJar(path);

-          pears.add(pear_current);

-          // add pear classpath info

-          File pearInstallDir = Files.createTempDirectory(getTempDir(), "installedPear").toFile();

-          PackageBrowser ip = PackageInstaller.installPackage(pearInstallDir, path.toFile(), false);

-          localPearClasspath = ip.buildComponentClassPath();

-          String[] children = pearInstallDir.list();

-          if (children == null || children.length != 1) {

-            Misc.internalError();

-          }

-          pearResolveStart = Paths.get(pearInstallDir.getAbsolutePath(), children[0]);

-          

-          start = pearInstallDir.toPath();

-        } else {

-          if (isJar) {

-            PearOrJar jarInfo = new PearOrJar(path);

-            jar_current_stack.push(jarInfo);

-            jars.add(jarInfo);

-          }

-          

-          localPearClasspath = pearClasspath;

-          FileSystem jfs = FileSystems.newFileSystem(Paths.get(path.toUri()), null);

-          start = jfs.getPath("/");

-        }

-        

-        try (Stream<Path> stream = Files.walk(start)) {  // needed to release file handles

-          stream.forEachOrdered(

-            p -> getCandidates_processFile(p, localPearClasspath));

-        }

-        if (isJar) {

-          jar_current_stack.pop();

-        }

-        if (isPear) {

-          pear_current = null;

-        }

-      } else {

-        // is not a .jar or .pear file.  add .java or .class files to initial candidate set

-        //    will be filtered additionally later

-//        System.out.println("debug path ends with java or class " + pathString.endsWith(isSource ? ".java" : ".class") + " " + pathString);

-        if (pathString.endsWith(isSource ? ".java" : ".class")) {

-          candidates.add(new Candidate(path, pearClasspath));

-          if (!isSource && null != pear_current) {

-            // inside a pear, which has been unzipped into pearInstallDir;

-            path2InsidePearOrJarPath.put(path.toString(), pearResolveStart.relativize(path).toString());                

-            pear_current.pathsToCandidateFiles.add(path.toString());           

-          }

-          

-          if (!isSource && jar_current_stack.size() > 0) {

-            // inside a jar, not contained in a pear                

-            jar_current_stack.getFirst().pathsToCandidateFiles.add(path.toString());    

-          }

-        }

-      }

-    } catch (IOException e) {

-      throw new RuntimeException(e);

+  private void getCandidates_processFile2(Path path, Container container) {

+      

+    String pathString = path.toString();

+    final boolean isPear = pathString.endsWith(".pear"); // path.endsWith does not mean this !!

+    final boolean isJar = pathString.endsWith(".jar");

+    

+    if (isPear || isJar) {

+      Container subc = new Container(container, path); 

+      getAndProcessCandidatesInContainer(subc);

+      return;

     }

+    

+    if (pathString.endsWith(isSource ? ".java" : ".class")) {

+      // Skip candidates except .java or .class

+      addToCandidates(path, container);

+    }     

   }

   

   /**

-   * 

-   * @param path used to get the last name from the path

-   * @return a temporary file in the local temp directory that has some name parts from the path's file, and ends in .jar

-   * @throws IOException -

+   * if _Type kind, add artifactId to set kept in current rootIdContainer 

+   * If currently scanning within a PEAR, 

+   *    record 2-way map from unzipped path to internal path inside pear

+   *    Used when doing pear reassembly.

+   *    

+   * If currently scanning within a Jar or a PEAR,

+   *    add unzipped path to list of all subparts for containing Jar or PEAR

+   *    These paths are used as unique ids to things needing to be replaced in the Jar or PEAR,

+   *    when doing re-assembly.  For compiled classes migration, only, since source migration

+   *    doesn't do re-assembly.

+   *               

+   * @param path

+   * @param pearClassPath

    */

-  private Path getTempOutputPath(Path path) throws IOException {

-    Path localTempDir = getTempDir();

-    Path tempFile = Files.createTempFile(localTempDir, path.getFileName().toString(),  ".jar");

-    tempFile.toFile().deleteOnExit();

-    return tempFile;

+  private void addToCandidates(Path path, Container container) {

+    String ps = path.toString();

+    

+    if (ps.endsWith(isSource ? "_Type.java" : "_Type.class")) {

+      container._Types.add(isSource 

+                            ? (ps.substring(0, ps.length() - 10) + ".java")

+                            : (ps.substring(0, ps.length() - 11) + ".class"));

+//      if (container.isJar) {

+//        System.out.println("debug add container._Types " + Paths.get(ps.substring(0, ps.length() - 11)).toString() + ".class".toString() + " for Jar " + container.rootOrig.getFileName().toString());

+//      }

+

+      return;

+    }

+    

+    if (ps.contains("$")) {

+      return; // don't add these kinds of things, they're not JCas classes

+    }

+    

+    //debug

+//    if (container.isJar) {

+//      System.out.println("debug add candidate " + path.toString() + " for Jar " + container.rootOrig.getFileName().toString());

+//    }

+    container.candidates.add(path);

   }

   

-  private Path getTempDir() throws IOException {

+  

+  /**

+   * For Jars inside other Jars, we copy the Jar to a temp spot in the default file system

+   * Extracted Jar is marked delete-on-exit

+   * 

+   * @param path embedded Jar to copy (only the last name is used, in constructing the temp dir)

+   * @return a temporary file in the local temp directory that is a copy of the Jar

+   * @throws IOException -

+   */

+  private static Path getTempOutputPathForJarOrPear(Path path) throws IOException {

+    Path localTempDir = getTempDir();

+    if (path == null ) {

+      throw new IllegalArgumentException();

+    }

+    Path fn = path.getFileName();

+    if (fn == null) {

+      throw new IllegalArgumentException();

+    }

+    Path tempPath = Files.createTempFile(localTempDir, fn.toString(),  "");

+    tempPath.toFile().deleteOnExit();

+    return tempPath;

+  }

+  

+  private static Path getTempDir() throws IOException {

     if (tempDir == null) {

       tempDir = Files.createTempDirectory("migrateJCas");

       tempDir.toFile().deleteOnExit();

     }

     return tempDir;

-  } 

-  

-  private boolean has_Type(Candidate cand, int start) {

-    if (start >= candidates.size()) {

-      return false;

-    }

-

-    String sc = cand.p.toString();

-    String sc_minus_suffix = sc.substring(0,  sc.length() - ( isSource ? ".java".length() : ".class".length())); 

-    String sc_Type = sc_minus_suffix + ( isSource ? "_Type.java" : "_Type.class");

-    // a string which sorts beyond the candidate + a suffix of "_"

-    String s_end = sc_minus_suffix + (char) (((int)'_') + 1);

-    for (Candidate c : candidates.subList(start,  candidates.size())) {

-      String s = c.p.toString();

-      if (s_end.compareTo(s) < 0) {

-        return false;  // not found, we're already beyond where it would be found

-      }

-      if (s.equals(sc_Type)) {

-        return true;

-      }

-    }

-    return false;

-  }

-  

+  }   

   

   private static final CommandLineParser createCmdLineParser() {

     CommandLineParser parser = new CommandLineParser();

     parser.addParameter(SOURCE_FILE_ROOTS, true);

     parser.addParameter(CLASS_FILE_ROOTS, true);

     parser.addParameter(OUTPUT_DIRECTORY, true);

-    parser.addParameter(SKIP_TYPE_CHECK, false);

+//    parser.addParameter(SKIP_TYPE_CHECK, false);

     parser.addParameter(MIGRATE_CLASSPATH, true);

-    parser.addParameter(CLASSES, true);

+//    parser.addParameter(CLASSES, true);

     return parser;

   }

 

@@ -1726,8 +2457,14 @@
       System.err.println();

       return false;

     }

+    

+    if (!clp.isInArgsList(SOURCE_FILE_ROOTS) && !clp.isInArgsList(CLASS_FILE_ROOTS)) {

+      System.err.println("Neither sources file roots nor classes file roots parameters specified; please specify just one.");

+      return false;

+    }

+    

     if (clp.isInArgsList(SOURCE_FILE_ROOTS) && clp.isInArgsList(CLASS_FILE_ROOTS)) {

-      System.err.println("both sources file roots and classess file roots parameters specified; please specify just one.");

+      System.err.println("both sources file roots and classes file roots parameters specified; please specify just one.");

       return false;

     }

     

@@ -1736,42 +2473,66 @@
       if (!outputDirectory.endsWith("/")) {

         outputDirectory = outputDirectory + "/";

       }

-      outDirConverted = outputDirectory + "converted/";

-      outDirSkipped = outputDirectory + "not-converted/";

-      outDirLog = outputDirectory + "logs/";

     } else {

-      System.err.println("-outputDirectory is a required parameter, must be a path to a writable file directory.");

-      return false;

+      try {

+        outputDirectory = Files.createTempDirectory("migrateJCasOutput").toString() + "/";

+      } catch (IOException e) {

+        e.printStackTrace();

+        throw new RuntimeException(e);

+      }

     }

+    outDirConverted = outputDirectory + "converted/";

+    outDirSkipped = outputDirectory + "not-converted/";

+    outDirLog = outputDirectory + "logs/";

+

     

     if (clp.isInArgsList(MIGRATE_CLASSPATH)) {

       migrateClasspath = clp.getParamArgument(MIGRATE_CLASSPATH);

+    } else {

+      if (clp.isInArgsList(CLASS_FILE_ROOTS)) {

+        System.err.println("WARNING: classes file roots is specified, but the\n"

+                         + "       migrateClasspath parameter is missing\n");

+      }

     }

     

-    if (clp.isInArgsList(CLASSES)) {

-      individualClasses = clp.getParamArgument(CLASSES);

-    }

+//    if (clp.isInArgsList(CLASSES)) {

+//      individualClasses = clp.getParamArgument(CLASSES);

+//    }

     return true;

   }

   

+  // called to decompile a string of bytes.

+  //   - first get the class name (fully qualified) 

+  //     and skip decompiling if already decompiled this class

+  //     for this pearClasspath

+  //     - this handles multiple class definitions, insuring

+  //       only one decompile happens per pearClasspath (including null)

+  /**

+   * Caller does any caching to avoid this method.

+   * 

+   * @param b bytecode to decompile

+   * @param pearClasspath to prepend to the classpath

+   * @return

+   */

   private String decompile(byte[] b, String pearClasspath) {

+    badClassName = false;

+    String classNameWithSlashes = Misc.classNameFromByteCode(b);

+    packageAndClassNameSlash = classNameWithSlashes;

     ClassLoader cl = getClassLoader(pearClasspath);

+    

     UimaDecompiler ud = new UimaDecompiler(cl, null);

-    return ud.decompile(b);

+

+    if (classNameWithSlashes == null || classNameWithSlashes.length() < 2) {

+      System.err.println("Failed to extract class name from binary code, "

+          + "name found was \"" + ((classNameWithSlashes == null) ? "null" : classNameWithSlashes) 

+          + "\"\n  byte array was:");

+      System.err.println(Misc.dumpByteArray(b, 2000));

+      badClassName = true;

+    }

+

+    return ud.decompileToString(classNameWithSlashes, b);

   }

-  

-  private String decompile(String classname) {

-    ClassLoader cl = getClassLoader(null);

-    UimaDecompiler ud = new UimaDecompiler(cl, null);

-    return ud.decompileToString(classname);

-  }

-  

-//  private String getFullyQualifiedClassNameWithSlashes(byte[] b) {

-//    ClassLoader cl = getClassLoader();

-//    UimaDecompiler ud = new UimaDecompiler(cl, null);

-//    return ud.extractClassNameSlashes(b);    

-//  }

-  

+    

   /**

    * The classloader to use in decompiling, if it is provided, is one that delegates first

    * to the parent.  This may need fixing for PEARs

@@ -1780,9 +2541,9 @@
   private ClassLoader getClassLoader(String pearClasspath) {

     if (null == pearClasspath) {

       if (null == cachedMigrateClassLoader) {

-        cachedMigrateClassLoader = (migrateClasspath == null) 

+        cachedMigrateClassLoader = (null == migrateClasspath)

                         ? this.getClass().getClassLoader()

-                        : new URLClassLoader(Misc.classpath2urls(migrateClasspath));

+                        : new UIMAClassLoader(Misc.classpath2urls(migrateClasspath));

       }

       return cachedMigrateClassLoader;

     } else {

@@ -1797,14 +2558,14 @@
   }

   

   private void addImport(String s) {

-    cu.getImports().add(new ImportDeclaration(new NameExpr(s), false, false));

+    cu.getImports().add(new ImportDeclaration(new Name(s), false, false));

   }

   

   private void removeImport(String s) {

     Iterator<ImportDeclaration> it = cu.getImports().iterator();

     while (it.hasNext()) { 

       ImportDeclaration impDcl = it.next();

-      if (impDcl.getName().toString().equals(s)) {

+      if (impDcl.getNameAsString().equals(s)) {

         it.remove();

         break;

       }

@@ -1816,33 +2577,40 @@
    ******************/

   

   private Node replaceInParent(Node n, Expression v) {

-    Node parent = n.getParentNode();

-    if (parent instanceof EnclosedExpr) {

-      ((EnclosedExpr)parent).setInner(v);

-    } else if (parent instanceof MethodCallExpr) { // args in the arg list

-      List<Expression> args = ((MethodCallExpr)parent).getArgs();

-      args.set(args.indexOf(n), v);

-      v.setParentNode(parent);

-    } else if (parent instanceof ExpressionStmt) { 

-      ((ExpressionStmt)parent).setExpression(v);

-    } else if (parent instanceof CastExpr) { 

-      ((CastExpr)parent).setExpr(v);

-    } else if (parent instanceof ReturnStmt) { 

-      ((ReturnStmt)parent).setExpr(v);

-    } else if (parent instanceof AssignExpr) {

-      ((AssignExpr)parent).setValue(v);

-    } else if (parent instanceof VariableDeclarator) {

-      ((VariableDeclarator)parent).setInit(v);      

-    } else if (parent instanceof ObjectCreationExpr) {

-      List<Expression> args = ((ObjectCreationExpr)parent).getArgs();

-      int i = args.indexOf(n);

-      if (i < 0) throw new RuntimeException();

-      args.set(i, v);      

-   } else {

-      System.out.println(parent.getClass().getName());

-      throw new RuntimeException();

+    Optional<Node> maybeParent = n.getParentNode();

+    if (maybeParent.isPresent()) {

+      Node parent = n.getParentNode().get();

+      if (parent instanceof EnclosedExpr) {

+        ((EnclosedExpr)parent).setInner(v);

+      } else if (parent instanceof MethodCallExpr) { // args in the arg list

+        List<Expression> args = ((MethodCallExpr)parent).getArguments();

+        args.set(args.indexOf(n), v);

+        v.setParentNode(parent);

+      } else if (parent instanceof ExpressionStmt) { 

+        ((ExpressionStmt)parent).setExpression(v);

+      } else if (parent instanceof CastExpr) { 

+        ((CastExpr)parent).setExpression(v);

+      } else if (parent instanceof ReturnStmt) { 

+        ((ReturnStmt)parent).setExpression(v);

+      } else if (parent instanceof AssignExpr) {

+        ((AssignExpr)parent).setValue(v);

+      } else if (parent instanceof VariableDeclarator) {

+        ((VariableDeclarator)parent).setInitializer(v);      

+      } else if (parent instanceof ObjectCreationExpr) {

+        List<Expression> args = ((ObjectCreationExpr)parent).getArguments();

+        int i = args.indexOf(n);

+        if (i < 0) throw new RuntimeException();

+        args.set(i, v);      

+      } else {

+        System.out.println(parent.getClass().getName());

+        throw new RuntimeException();

+      }

+      return v;

     }

-    return v;

+    System.out.println("internal error replacing in parent: no parent for node: " + n.getClass().getName());

+    System.out.println("   node: " + n.toString());

+    System.out.println("   expression replacing: " + v.toString());

+    throw new RuntimeException();

   }

     

   /**

@@ -1854,12 +2622,12 @@
   private void setParameter(List<Parameter> ps, int i, String t, String name) {

     Parameter p = ps.get(i);

     p.setType(new ClassOrInterfaceType(t));

-    p.setId(new VariableDeclaratorId(name));

+    p.setName(new SimpleName(name));

   }

   

-  private int findConstructor(List<BodyDeclaration> classMembers) {

+  private int findConstructor(NodeList<BodyDeclaration<?>> classMembers) {

     int i = 0;

-    for (BodyDeclaration bd : classMembers) {

+    for (BodyDeclaration<?> bd : classMembers) {

       if (bd instanceof ConstructorDeclaration) {

         return i;

       }

@@ -1868,28 +2636,34 @@
     return -1;

   }

   

-  private boolean hasTypeFields(List<BodyDeclaration> members) {

+  private boolean hasTypeFields(NodeList<BodyDeclaration<?>> members) {

     boolean hasType = false;

     boolean hasTypeId = false;

-    for (BodyDeclaration bd : members) {

+    for (BodyDeclaration<?> bd : members) {

       if (bd instanceof FieldDeclaration) {

         FieldDeclaration f = (FieldDeclaration)bd;

-        int m = f.getModifiers();

-        if (Modifier.isPublic(m) &&

-            Modifier.isStatic(m) &&

-            Modifier.isFinal(m) &&

-            getTypeName(f.getType()).equals("int")) {

+        EnumSet<Modifier> m = f.getModifiers();

+        if (m.contains(Modifier.PUBLIC) &&

+            m.contains(Modifier.STATIC) &&

+            m.contains(Modifier.FINAL) 

+//            &&

+//            getTypeName(f.getType()).equals("int")

+            ) {

           List<VariableDeclarator> vds = f.getVariables();

           for (VariableDeclarator vd : vds) {

-            String n = vd.getId().getName();

-            if (n.equals("type")) hasType = true;

-            if (n.equals("typeIndexID")) hasTypeId = true;

-            if (hasTypeId && hasType) break;

+            if (vd.getType().equals(intType)) {

+              String n = vd.getNameAsString();

+              if (n.equals("type")) hasType = true;

+              if (n.equals("typeIndexID")) hasTypeId = true;

+              if (hasTypeId && hasType) {

+                return true;

+              }

+            }

           }

         }

       }

     } // end of for

-    return hasTypeId && hasType;

+    return false;

   }

   

   /**

@@ -1904,13 +2678,13 @@
    * Sets fields hasV2Constructors, hasV3Constructors

    * @param members

    */

-  private void setHasJCasConstructors(List<BodyDeclaration> members) {

+  private void setHasJCasConstructors(NodeList<BodyDeclaration<?>> members) {

     boolean has0ArgConstructor = false;

     boolean has1ArgJCasConstructor = false;

     boolean has2ArgJCasConstructorV2 = false;

     boolean has2ArgJCasConstructorV3 = false;

     

-    for (BodyDeclaration bd : members) {

+    for (BodyDeclaration<?> bd : members) {

       if (bd instanceof ConstructorDeclaration) {

         List<Parameter> ps = ((ConstructorDeclaration)bd).getParameters();

         if (ps.size() == 0) has0ArgConstructor = true;

@@ -1938,15 +2712,15 @@
   }

   

   private String getTypeName(Type t) {

-    if (t instanceof ReferenceType) {

-      t = ((ReferenceType)t).getType();

-    }

+//    if (t instanceof ReferenceType) {

+//      t = ((ReferenceType<?>)t).getType();

+//    }

     

     if (t instanceof PrimitiveType) {

       return ((PrimitiveType)t).toString(); 

     }

     if (t instanceof ClassOrInterfaceType) {

-      return ((ClassOrInterfaceType)t).getName();

+      return ((ClassOrInterfaceType)t).getNameAsString();

     }

     Misc.internalError(); return null;

   }

@@ -1959,10 +2733,10 @@
   private String getName(Expression e) {

     e = getUnenclosedExpr(e);

     if (e instanceof NameExpr) {

-      return ((NameExpr)e).getName();

+      return ((NameExpr)e).getNameAsString();

     }

     if (e instanceof FieldAccessExpr) {

-      return ((FieldAccessExpr)e).getField();

+      return ((FieldAccessExpr)e).getNameAsString();

     }

     return null;

   }

@@ -1975,26 +2749,40 @@
    * 

    * @param n type being declared

    */

-  private void updateClassName(TypeDeclaration n) {

-    if (n.getParentNode() instanceof CompilationUnit) {

-      className = n.getName();

+  private void updateClassName(TypeDeclaration<?> n) {

+    Optional<Node> pnode = n.getParentNode();

+    Node node;

+    if (pnode.isPresent() && 

+        (node = pnode.get()) instanceof CompilationUnit) {

+      CompilationUnit cu2 = (CompilationUnit) node;

+      className = cu2.getType(0).getNameAsString();

       String packageAndClassName = 

           (className.contains(".")) 

             ? className 

             : packageName + '.' + className;

       packageAndClassNameSlash = packageAndClassName.replace('.', '/');

+//      assert current_cc.fqcn_slash == null;  // for decompiling, already set

+      assert (current_cc.fqcn_slash != null) ? current_cc.fqcn_slash.equals(packageAndClassNameSlash) : true;

+      current_cc.fqcn_slash = packageAndClassNameSlash;

       

       TypeImpl ti = TypeSystemImpl.staticTsi.getType(Misc.javaClassName2UimaTypeName(packageAndClassName));

       if (null != ti) {

         // is a built-in type

-        ClassnameAndPath p = new ClassnameAndPath(packageAndClassNameSlash, candidate.p);

-        skippedBuiltins.add(p);

-        v3 = false;   // skip further processing of this class

+//        ContainerAndPath p = new ContainerAndPath(

+//            current_path,

+//            current_container,packageAndClassNameSlash, 

+//            current_cc., 

+//            current_cc.pearClasspath);

+        skippedBuiltins.add(new PathContainerAndReason(current_path, current_container, "built-in"));

+        isBuiltinJCas = true;

+        isConvert2v3 = false;

         return;  

+      } else {

+        VariableDeclarator vd_typename = new VariableDeclarator(

+            stringType, "_TypeName", new StringLiteralExpr(packageAndClassName));

+        fi_fields.add(new FieldDeclaration(public_static_final, vd_typename));

       }

 

-      c2ps.add(new ClassnameAndPath(packageAndClassNameSlash, candidate.p));

-      path2classname.put(candidate.p.toString(), packageAndClassNameSlash);

       return;

     }

     return;

@@ -2010,7 +2798,7 @@
   

   private Expression getUnenclosedExpr(Expression e) {

     while (e instanceof EnclosedExpr) {

-      e = ((EnclosedExpr)e).getInner();

+      e = ((EnclosedExpr)e).getInner().get();

     }

     return e;

   }

@@ -2022,7 +2810,7 @@
    */

   private Statement getStmtFromStmt(Statement stmt) {

     while (stmt instanceof BlockStmt) {

-      List<Statement> stmts = ((BlockStmt) stmt).getStmts();

+      NodeList<Statement> stmts = ((BlockStmt) stmt).getStatements();

       if (stmts.size() == 1) {

         stmt = stmts.get(0);

         continue;

@@ -2034,7 +2822,13 @@
   

   private void addCastExpr(Statement stmt, Type castType) {

     ReturnStmt rstmt = (ReturnStmt) stmt;

-    rstmt.setExpr(new CastExpr(castType, rstmt.getExpr()));

+    Optional<Expression> o_expr = rstmt.getExpression(); 

+    Expression expr = o_expr.isPresent() ? o_expr.get() : null;

+    CastExpr ce = new CastExpr(castType, expr);

+    rstmt.setExpression(ce);  // removes the parent link from expr

+    if (expr != null) {

+      expr.setParentNode(ce); // restore it

+    }

   }

   

   /********************

@@ -2045,33 +2839,33 @@
     reportMigrateFailed("Constructor is incorrect, " + msg);

   }

       

-  private void reportParseException() {

-    reportMigrateFailed("Unparsable Java");

-  }

+//  private void reportParseException() {

+//    reportMigrateFailed("Unparsable Java");

+//  }

   

   private void migrationFailed(String reason) {

-    failedMigration.add(new PathAndReason(candidate.p, reason));

-    v3 = false;    

+    failedMigration.add(new PathContainerAndReason(current_path, current_container, reason));

+    isConvert2v3 = false;    

   }

   

   private void reportMigrateFailed(String m) {

-    System.out.format("Skipping this file due to error: %s, path: %s%n", m, candidate);

+    System.out.format("Skipping this file due to error: %s, path: %s%n", m, current_path);

     migrationFailed(m);

   }

   

   private void reportV2Class() {

-    v2JCasFiles.add(candidate.p);

-    v2 = true;

+//    v2JCasFiles.add(current_path);

+    isV2JCas = true;

   }

   

   private void reportV3Class() {

-    v3JCasFiles.add(candidate.p);

-    v3 = true;

+//    v3JCasFiles.add(current_path);

+    isConvert2v3 = true;

   }

   

   private void reportNotJCasClass(String reason) {

-    nonJCasFiles.add(new PathAndReason(candidate.p, reason));

-    v3 = false;

+    nonJCasFiles.add(new PathContainerAndReason(current_path, current_container, reason));

+    isConvert2v3 = false;

   }

   

   private void reportNotJCasClassMissingTypeFields() {

@@ -2079,11 +2873,12 @@
   }

   

   private void reportDeletedCheckModified(String m) {

-    deletedCheckModified.add(new PathAndReason(candidate.p, m));

+    deletedCheckModified.add(new PathContainerAndReason(current_path, current_container, m));

   }

   

   private void reportMismatchedFeatureName(String m) {

-    manualInspection.add(new PathAndReason(candidate.p, "This getter/setter name doesn't match internal feature name: " + m));

+    manualInspection.add(new PathContainerAndReason(current_path, current_container, 

+        "This getter/setter name doesn't match internal feature name: " + m));

   }

   

   private void reportUnrecognizedV2Code(String m) {

@@ -2094,44 +2889,42 @@
     pathWorkaround.add(new String1AndString2(orig, modified));

   }

   

-  private void reportPearOrJarClassReplace(String pearOrJar, String classname, String kind) { // pears or jars

-    if (kind.equals("pears")) {

+  private void reportPearOrJarClassReplace(String pearOrJar, String classname, Container kind) { // pears or jars

+    if (kind.isPear) {

       pearClassReplace.add(new String1AndString2(pearOrJar, classname));

     } else {

       jarClassReplace.add(new String1AndString2(pearOrJar, classname));

     }

-  }

+  }  

   

   /***********************************************/

-    

-  private void getBaseOutputPath() {

-    String s = packageAndClassNameSlash;

-    int i = 0;

-    while (!usedPackageAndClassNames.add(s)) {

-      i = i + 1;

-      s = packageAndClassNameSlash + "_dupid_" + i;

-    }

-    packageAndClassNameSlash_i = i;

+  /**

+   * Output directory for source and migrated files

+   * Consisting of converted/skipped, v2/v3, a+cc.id, slashified classname      

+   * @param cc -

+   * @param isV2 -

+   * @param wasConverted -

+   * @return converted/skipped, v2/v3, a+cc.id, slashified classname      

+   */

+  private String getBaseOutputPath(CommonConverted cc, boolean isV2, boolean wasConverted) {

+    StringBuilder sb = new StringBuilder();

+    sb.append(wasConverted ? outDirConverted : outDirSkipped);

+    sb.append(isV2 ? "v2/" : "v3/");

+    sb.append("a").append(cc.getId()).append('/');

+    sb.append(cc.fqcn_slash).append(".java");

+    return sb.toString();

+  }  

+  

+  private void writeV2Orig(CommonConverted cc, boolean wasConverted) throws IOException {

+    String base = getBaseOutputPath(cc, true, wasConverted);  // adds numeric suffix if dupls

+    FileUtils.writeToFile(makePath(base), cc.v2Source);

   }

   

-  private String getBaseOutputPath(boolean wasConverted, boolean isV2) {

-    return (wasConverted ? outDirConverted : outDirSkipped) + (isV2 ? "v2/" : "v3/") 

-        + ((packageAndClassNameSlash_i > 0) 

-             ? (Integer.toString(packageAndClassNameSlash_i) + "/") 

-             : "")

-        + packageAndClassNameSlash 

-        + ".java";

-  }

-  

-  private void writeV2Orig(String data, boolean wasConverted) throws IOException {

-    String base = getBaseOutputPath(wasConverted, true);  // adds numeric suffix if dupls

-    FileUtils.writeToFile(makePath(base), data);

-  }

-  

-  private void writeV3(String data) throws IOException {

-    String base = getBaseOutputPath(true, false);  // adds numeric suffix if dupls

-    data = fixImplementsBug(data);

-    FileUtils.writeToFile(makePath(base), data);

+  private void writeV3(CommonConverted cc) throws IOException {

+    String base = getBaseOutputPath(cc, false, true); 

+    cc.v3SourcePath = makePath(base);

+    String data = fixImplementsBug(cc.v3Source);

+    FileUtils.writeToFile(cc.v3SourcePath, data);

   }

   

   private void printUsage() {

@@ -2139,60 +2932,20 @@
         "Usage: java org.apache.uima.migratev3.jcas.MigrateJCas \n"

         + "  [-sourcesRoots <One-or-more-directories-or-jars-separated-by-Path-separator>]\n"

         + "  [-classesRoots <One-or-more-directories-or-jars-or-pears-separated-by-Path-separator>]\n"

-        + "  [-classes <one-or-more-fully-qualified-class-names-separated-by-Path-separator]\n"

-        + "            example:  -classes mypkg.foo:pkg2.bar\n"

-        + "  [-outputDirectory a-writable-directory-path (required)\n"

-        + "  [-migrateClasspath a-class-path to use in decompiling, used if -classesRoots is specified\n"

+        + "  [-outputDirectory a-writable-directory-path (optional)\n"

+        + "     if omitted, a temporary directory is used\n"

+        + "  [-migrateClasspath a-class-path to use in decompiling, when -classesRoots is specified\n"

         + "                     also used when compiling the migrated classes.\n"

-        + "                     PEAR processing augments this with the PEAR's classpath information               "

-        + "  [-skipTypeCheck if specified, skips validing a found item by looking for the corresponding _Type file"

         + "  NOTE: either -sourcesRoots or -classesRoots is required, but only one may be specified.\n"

         + "  NOTE: classesRoots are scanned for JCas classes, which are then decompiled, and the results processed like sourcesRoots\n"

-        + "        The decompiling requires that the classes being scanned be on the migrateClasspath when this is invoked.\n"

-        + "  NOTE: -outputDirectory is required\n");

+       );

   }

 

   private static final Pattern implementsEmpty = Pattern.compile("implements  \\{");

   private String fixImplementsBug(String data) {

     return implementsEmpty.matcher(data).replaceAll("{");

   }

-  

-//  /**

-//   * Called after class is migrated

-//   * Given a path to a class (source or class file), 

-//   * return the URL to the class as found in the classpath.

-//   *   This returns the "first" one found in the classpath, in the case of duplicates.

-//   * @param path

-//   * @return the location of the class in the class path

-//   */

-//  private URL getPathForClass(Path path) {

-//    return (null == packageAndClassNameSlash) 

-//             ? null 

-//             : migrateClassLoader.getResource(packageAndClassNameSlash + ".class");

-//  }

-  

-  /**

-   * prepare to migrate one class

-   */

-  private String  prepare(Candidate c) {

-    candidate = c;

-    packageName = null;

-    className = null;

-    packageAndClassNameSlash = null;

-    cu = null;

-    return getSource(c);

-  }

-  

-  private String prepareIndividual(String classname) {

-    candidate = new Candidate(Paths.get(classname)); // a pseudo path

-    packageName = null;

-    className = null;

-    packageAndClassNameSlash = null;

-    cu = null;

-    return decompile(classname); // always look up in classpath

-                                 // to decompile individual source - put in sourcesRoots

-  }

-  

+       

   /*********************************************************************

    * Reporting classes

    *********************************************************************/

@@ -2202,66 +2955,27 @@
     public abstract Comparable<U> getSecond();  

     abstract int getFirstLength();

   }

-  

-  private static class PathAndReason extends Report2<Path, String> {

-    Path path;

-    String reason;

-    PathAndReason(Path path, String reason) {

-      this.path = path;

+ 

+  private static class PathContainerAndReason extends Report2<ContainerAndPath, String> {

+    final ContainerAndPath cap;

+    final String reason;

+    PathContainerAndReason(ContainerAndPath cap, String reason) {

+      this.cap = cap;

       this.reason = reason;

     }

+    

+    PathContainerAndReason(Path path, Container container, String reason) {

+      this(new ContainerAndPath(path, container), reason);

+    }

+    

     @Override

-    public Comparable<Path> getFirst() { return path; }

+    public Comparable<ContainerAndPath> getFirst() { return cap; }

     @Override

     public Comparable<String> getSecond() { return reason; }

     @Override

-    int getFirstLength() { return path.toString().length(); }

+    int getFirstLength() { return cap.toString().length(); }

   }

-  

-  private static class ClassnameAndPath extends Report2<String, Path> {

-    String classname;

-    Path path;

-    ClassnameAndPath(String classname, Path path) {

-      this.classname = classname;

-      this.path = path;

-    }

-    @Override

-    public Comparable<String> getFirst() { return classname; }

-    @Override

-    public Comparable<Path> getSecond() { return path; }

-    @Override

-    int getFirstLength() { return classname.length(); }

-    @Override

-    public int hashCode() {

-      final int prime = 31;

-      int result = 1;

-      result = prime * result + ((classname == null) ? 0 : classname.hashCode());

-      result = prime * result + ((path == null) ? 0 : path.hashCode());

-      return result;

-    }

-    @Override

-    public boolean equals(Object obj) {

-      if (this == obj)

-        return true;

-      if (obj == null)

-        return false;

-      if (!(obj instanceof ClassnameAndPath))

-        return false;

-      ClassnameAndPath other = (ClassnameAndPath) obj;

-      if (classname == null) {

-        if (other.classname != null)

-          return false;

-      } else if (!classname.equals(other.classname))

-        return false;

-      if (path == null) {

-        if (other.path != null)

-          return false;

-      } else if (!path.equals(other.path))

-        return false;

-      return true;

-    }

-  }

-  

+    

   private static class String1AndString2 extends Report2<String, String> {

     String s1;

     String s2;

@@ -2276,5 +2990,570 @@
     @Override

     int getFirstLength() { return s1.toString().length(); }

   }

+  

+  private static void withIOX(Runnable_withException r) {

+    try {

+      r.run();

+    } catch (Exception e) {

+      throw new UIMARuntimeException(e);

+    }

+  }

+  

+  private int findFirstCharDifferent(String s1, String s2) {

+    int s1l = s1.length();

+    int s2l = s2.length();

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

+      if (i == s1l || i == s2l) {

+        return i;

+      }

+      if (s1.charAt(i) != s2.charAt(i)) {

+        return i;

+      }

+    }

+  }

+//  private String drop_Type(String s) {

+//    return s.substring(0, isSource ? "_Type.java".length() 

+//                                     : "_Type.class".length()) + 

+//          (isSource ? ".java" : ".class");  

+//  }

+

+///*****************

+//* Root-id

+//*****************/

+//private static int nextRootId = 1;

+//

+///***********************************************************************

+//* Root-id - this is the path part up to the start of the package name.

+//*   - it is relative to container

+//*   - has the collection of artifacts that might be candidates, having this rootId

+//*   - has the collection of _Type things having this rootId

+//*   - "null" path is OK - means package name starts immediately

+//* There is no Root-id for path ending in Jar or PEAR - these created containers instead

+//***********************************************************************/

+//private static class RootId {

+// final int id = nextRootId++;   

+// /**

+//  * The path relative to the the container (if any) (= Jar or Pear)

+//  *   - for Pears, the path is as if it was not installed, but within the PEAR file

+//  */

+// final Path path;

+// 

+// /** The container holding this RootId */

+// final Container container;

+// /**

+//  * For this rootId, all of the fully qualified classnames that are migration eligible.

+//  *   - not all might be migrated, if upon further inspection they are not JCas class files.

+//  */

+// final Set<Fqcn> fqcns = new HashSet<>();

+// final Set<String> fqcns_ignore_case = new HashSet<>();

+// boolean haveDifferentCapitalizedNamesCollidingOnWindows = false;

+//    

+// RootId(Path path, Container container) {

+//   this.path = path;

+//   this.container = container;

+// }

+//

+// /* (non-Javadoc)

+//  * @see java.lang.Object#toString()

+//  */

+// @Override

+// public String toString() {

+//   return "RootId [id=" 

+//       + id 

+//       + ", path=" 

+//       + path 

+//       + ", container=" 

+//       + container.id 

+//       + ", fqcns="

+//       + Misc.ppList(Misc.setAsList(fqcns)) 

+//       + ", fqcns_Type="

+//       + Misc.ppList(Misc.setAsList(fqcns_Type)) 

+//       + "]";

+// }

+// 

+// void add(Fqcn fqcn) {

+//   boolean wasNotPresent = fqcns.add(fqcn);

+//   boolean lc = fqcns_ignore_case.add(fqcn.fqcn_dots.toLowerCase());

+//   if (!lc && wasNotPresent) {

+//     haveDifferentCapitalizedNamesCollidingOnWindows = true;

+//   }

+// }

+// 

+// boolean hasMatching_Type(Fqcn fqcn) {

+//   

+// }

+//}

+///**

+//* Called from Stream walker starting at a root or starting at an imbedded Jar or Pear.

+//* 

+//* adds all the .java or .class files to the candidates, including _Type if not skipping the _Type check

+//* Handling embedded jar files

+//*   - single level Jar (at the top level of the default file system)

+//*     -- handle using an overlayed file system

+//*   - embedded Jars within Jars: 

+//*     - not supported by Zip File System Provider (it only supports one level)

+//*     - handle by extracting to a temp dir, and then using the Zip File System Provider

+//* @param path the path to a .java or .class or .jar or .pear

+//* @param pearClasspath - a string representing a path to the pear's classpath if there is one, or null

+//*/

+//private void getCandidates_processFile(Path path, String pearClasspath) {

+//// if (path.toString().contains("commons-httpclient-3.1.jar"))

+////   System.out.println("Debug: " + path.toString());

+//// System.out.println("debug processing " + path);

+// try {

+////   URI pathUri = path.toUri();

+//   String pathString = path.toString();

+//   final boolean isPear = pathString.endsWith(".pear"); // path.endsWith does not mean this !!

+//   final boolean isJar = pathString.endsWith(".jar");

+//         

+//   if (isJar || isPear) {  

+//     if (!path.getFileSystem().equals(FileSystems.getDefault())) {        

+//       // embedded Pear or Jar: extract to temp

+//       Path out = getTempOutputPathForJar(path);

+//       Files.copy(path, out, StandardCopyOption.REPLACE_EXISTING);

+////       embeddedJars.add(new PathAndPath(path, out));

+//       path = out;   // path points to pear or jar

+//     }

+//     

+//     Path start;

+//     final String localPearClasspath; 

+//     if (isPear) {

+//       if (pearClasspath != null) {

+//         throw new UIMARuntimeException("Nested PEAR files not supported");

+//       }

+//       

+////       pear_current = new PearOrJar(path);

+////       pears.add(pear_current);

+//       // add pear classpath info

+//       File pearInstallDir = Files.createTempDirectory(getTempDir(), "installedPear").toFile();

+//       PackageBrowser ip = PackageInstaller.installPackage(pearInstallDir, path.toFile(), false);

+//       localPearClasspath = ip.buildComponentClassPath();

+//       String[] children = pearInstallDir.list();

+//       if (children == null || children.length != 1) {

+//         Misc.internalError();

+//       }

+//       pearResolveStart = Paths.get(pearInstallDir.getAbsolutePath(), children[0]);

+//       

+//       start = pearInstallDir.toPath();

+//     } else {

+//       if (isJar) {

+//         PearOrJar jarInfo = new PearOrJar(path);

+//         pear_or_jar_current_stack.push(jarInfo);

+//         jars.add(jarInfo);

+//       }

+//       

+//       localPearClasspath = pearClasspath;

+//       FileSystem jfs = FileSystems.newFileSystem(Paths.get(path.toUri()), null);

+//       start = jfs.getPath("/");

+//     }

+//     

+//     try (Stream<Path> stream = Files.walk(start)) {  // needed to release file handles

+//       stream.forEachOrdered(

+//         p -> getCandidates_processFile(p, localPearClasspath));

+//     }

+//     if (isJar) {

+//       pear_or_jar_current_stack.pop();

+//     }

+//     if (isPear) {

+//       pear_current = null;

+//     }

+//   } else {

+//     // is not a .jar or .pear file.  add .java or .class files to initial candidate set

+//     //    will be filtered additionally later

+////     System.out.println("debug path ends with java or class " + pathString.endsWith(isSource ? ".java" : ".class") + " " + pathString);

+//     if (pathString.endsWith(isSource ? ".java" : ".class")) {

+//       candidates.add(new Candidate(path, pearClasspath));

+//       if (!isSource && null != pear_current) {

+//         // inside a pear, which has been unzipped into pearInstallDir;

+//         path2InsidePearOrJarPath.put(path.toString(), pearResolveStart.relativize(path).toString());                

+//         pear_current.pathsToCandidateFiles.add(path.toString());           

+//       }

+//       

+//       if (!isSource && pear_or_jar_current_stack.size() > 0) {

+//         // inside a jar, not contained in a pear                

+//         pear_or_jar_current_stack.getFirst().pathsToCandidateFiles.add(path.toString());    

+//       }

+//     }

+//   }

+// } catch (IOException e) {

+//   throw new RuntimeException(e);

+// }

+//}

+//private void postProcessPearsOrJars(String kind, List<PearOrJar> pearsOrJars, List<String1AndString2> classReplace) {  // pears or jars

+//try {

+//  Path outDir = Paths.get(outputDirectory, kind);

+//  FileUtils.deleteRecursive(outDir.toFile());

+//  Files.createDirectories(outDir);

+//} catch (IOException e) {

+//  throw new RuntimeException(e);

+//}

+//

+//// pearsOrJars may have entries with 0 candidate paths.  This happens when we scan them

+//// but find nothing to convert.  

+//// eliminate these.

+//

+//Iterator<PearOrJar> it = pearsOrJars.iterator();

+//while (it.hasNext()) {

+//  PearOrJar poj = it.next();

+//  if (poj.pathsToCandidateFiles.size() == 0) {

+//    it.remove();

+//  } else {

+////    //debug

+////    if (poj.pathToPearOrJar.toString().contains("commons-httpclient-3.1")) {

+////      System.err.println("debug found converted things inside commons-httpclient");;

+////      for (String x : poj.pathsToCandidateFiles) {

+////        System.err.println(x);

+////      }

+////      System.err.println("");

+////    }

+//  }

+//}

+//

+//it = pearsOrJars.iterator();

+//while (it.hasNext()) {

+//  PearOrJar poj = it.next();

+//  if (poj.pathsToCandidateFiles.size() == 0) {

+//    System.err.print("debug failed to remove unconverted Jar");

+//  }

+//}

+//

+//if (pearsOrJars.size() == 0) {

+//  System.out.format("No .class files were replaced in %s.%n", kind);

+//} else {

+//  System.out.format("replacing .class files in %,d %s%n", pearsOrJars.size(), kind);

+//  for (PearOrJar p : pearsOrJars) {

+//    pearOrJarPostProcessing(p, kind);

+//  }

+//  try {

+//    reportPaths("Reports of updated " + kind, kind + "FileUpdates.txt", classReplace);

+//   

+//  } catch (IOException e) {

+//    throw new RuntimeException(e);

+//  }

+//}

+//

+//}

+///**

+//* When running the compiler to compile v3 sources, we need a classpath that at a minimum

+//* includes uimaj-core.  The strategy is to use the invoker of this tool's classpath as

+//* specified from the application class loader

+//* @return true if no errors

+//*/

+//private boolean compileV3SourcesCommon(List<ClassnameAndPath> items, String msg, String pearClasspath) {

+// 

+// if (items.size() == 0) {

+//   return true;

+// }

+// System.out.format("Compiling %,d classes %s -- This may take a while!%n", c2ps.size(), msg);

+// StandardJavaFileManager fileManager = javaCompiler.getStandardFileManager(null, null, Charset.forName("UTF-8"));

+// 

+// List<String> cus = items.stream()

+//                         .map(c -> outDirConverted + "v3/" + c.classname + ".java")

+//                         .collect(Collectors.toList());

+// 

+// Iterable<String> compilationUnitStrings = cus;

+//

+// Iterable<? extends JavaFileObject> compilationUnits = 

+//     fileManager.getJavaFileObjectsFromStrings(compilationUnitStrings);

+// 

+// // specify where the output classes go

+// String classesBaseDir = outDirConverted + "v3-classes";

+// try {

+//   Files.createDirectories(Paths.get(classesBaseDir));

+// } catch (IOException e) {

+//   throw new UIMARuntimeException(e);

+// }

+// // specify the classpath

+// String classpath = getCompileClassPath(pearClasspath);

+// Iterable<String> options = Arrays.asList("-d", classesBaseDir,

+//                                          "-classpath", classpath);

+// return javaCompiler.getTask(null, fileManager, null, options, null, compilationUnits).call();    

+//}

+///**

+//* Called after class is migrated

+//* Given a path to a class (source or class file), 

+//* return the URL to the class as found in the classpath.

+//*   This returns the "first" one found in the classpath, in the case of duplicates.

+//* @param path

+//* @return the location of the class in the class path

+//*/

+//private URL getPathForClass(Path path) {

+// return (null == packageAndClassNameSlash) 

+//          ? null 

+//          : migrateClassLoader.getResource(packageAndClassNameSlash + ".class");

+//}

+//private void getBaseOutputPath() {

+//String s = packageAndClassNameSlash;

+//int i = 0;

+//while (!usedPackageAndClassNames.add(s)) {

+//  i = i + 1;

+//  s = packageAndClassNameSlash + "_dupid_" + i;

+//}

+//packageAndClassNameSlash_i = i;

+//}

+//private String prepareIndividual(String classname) {

+//candidate = new Candidate(Paths.get(classname)); // a pseudo path

+//packageName = null;

+//className = null;

+//packageAndClassNameSlash = null;

+//cu = null;

+//return decompile(classname); // always look up in classpath

+//                             // to decompile individual source - put in sourcesRoots

+//}

+//if (!isSource)  {  // skip this recording if source

+//if (null != pear_current) {

+//  // inside a pear, which has been unzipped into a temporary pearInstallDir;

+//  // we don't want that temporary dir to be part of the path.

+//  path2InsidePearOrJarPath.put(path.toString(), pearResolveStart.relativize(path).toString());                

+//  pear_current.pathsToCandidateFiles.add(path.toString());           

+//}

+//

+//if (!isSource && pear_or_jar_current_stack.size() > 0) {

+//  // inside a jar, not contained in a pear                

+//  pear_or_jar_current_stack.getFirst().pathsToCandidateFiles.add(path.toString());    

+//}

+//}

+//}

+///**

+//* For a given candidate, use its path:

+//*   switch the ...java to ..._Type.java, or ...class to ..._Type.class

+//*   look thru all the candidates

+//* @param cand

+//* @param start

+//* @return

+//*/

+//private boolean has_Type(Candidate cand, int start) {

+// if (start >= candidates.size()) {

+//   return false;

+// }

+//

+// String sc = cand.p.toString();

+// String sc_minus_suffix = sc.substring(0,  sc.length() - ( isSource ? ".java".length() : ".class".length())); 

+// String sc_Type = sc_minus_suffix + ( isSource ? "_Type.java" : "_Type.class");

+// // a string which sorts beyond the candidate + a suffix of "_"

+// String s_end = sc_minus_suffix + (char) (((int)'_') + 1);

+// for (Candidate c : candidates.subList(start,  candidates.size())) {

+//   String s = c.p.toString();

+//   if (s_end.compareTo(s) < 0) {

+//     return false;  // not found, we're already beyond where it would be found

+//   }

+//   if (s.equals(sc_Type)) {

+//     return true;

+//   }

+// }

+// return false;

+//}

+//private final static Comparator<Candidate> pathComparator = new Comparator<Candidate>() {

+//@Override

+//public int compare(Candidate o1, Candidate o2) {

+//  return o1.p.toString().compareTo(o2.p.toString());

+//}

+//};

+

+//// there may be several same-name roots not quite right

+////   xxx_Type$1.class

+//

+//private void addIfPreviousIsSameName(List<Path> c, int i) {

+//if (i == 0) return;

+//String _Type = candidates.get(i).toString();

+////String prev = r.get(i-1).getPath();

+//String prefix = _Type.substring(0, _Type.length() - ("_Type." + (isSource ? "java" : "class")).length());

+//i--;

+//while (i >= 0) {

+//  String s = candidates.get(i).toString();

+//  if ( ! s.startsWith(prefix)) {

+//    break;

+//  }

+//  if (s.substring(prefix.length()).equals((isSource ? ".java" : ".class"))) {

+//    c.add(candidates.get(i));

+//    break;

+//  }

+//  i--;

+//}

+//}

+

+  

+//

+//for (int i = 0; i < pearOrJar.pathsToCandidateFiles.size(); i++) {

+//  String candidatePath = pearOrJar.pathsToCandidateFiles.get(i);

+//  String path_in_v3_classes = isPear

+//                                ? getPath_in_v3_classes(candidatePath)

+//                                : candidatePath;

+//

+//  Path src = Paths.get(outputDirectory, "converted/v3-classes", path_in_v3_classes 

+//      + (isPear ? ".class" : ""));

+//  Path tgt = pfs.getPath(

+//      "/", 

+//      isPear 

+//        ? path2InsidePearOrJarPath.get(candidatePath) // needs to be bin/org/... etc

+//        : candidatePath);  // needs to be org/... etc

+//  if (Files.exists(src)) {

+//    Files.copy(src, tgt, StandardCopyOption.REPLACE_EXISTING);

+//    reportPearOrJarClassReplace(pearOrJarCopy.toString(), path_in_v3_classes, kind);

+//  }

+//}

+

+///** for compiled mode, do recompiling and reassembly of Jars and Pears */

+//

+//private boolean compileAndReassemble(CommonConverted cc, Container container, Path path) {

+//  boolean noErrors = true;

+//  if (javaCompiler != null) {

+//    if (container.haveDifferentCapitalizedNamesCollidingOnWindows) {

+//      System.out.println("Skipping compiling / reassembly because class " + container.toString() + " has multiple names differing only in capitalization, please resolve first.");

+//    } else {

+//      

+//      

+//      noErrors = compileV3PearSources(container, path);

+//      noErrors = noErrors && compileV3NonPearSources(container, path);

+//      

+//      postProcessPearsOrJars("jars" , jars ,  jarClassReplace);

+//      postProcessPearsOrJars("pears", pears, pearClassReplace);

+//    

+////  

+////    try {

+////      Path pearOutDir = Paths.get(outputDirectory, "pears");

+////      FileUtils.deleteRecursive(pearOutDir.toFile());

+////      Files.createDirectories(pearOutDir);

+////    } catch (IOException e) {

+////      throw new RuntimeException(e);

+////    }

+////      

+////    System.out.format("replacing .class files in %,d PEARs%n", pears.size());

+////    for (PearOrJar p : pears) {

+////      pearOrJarPostProcessing(p);

+////    }

+////    try {

+////      reportPaths("Reports of updated Pears", "pearFileUpdates.txt", pearClassReplace);

+////    } catch (IOException e) {

+////      throw new RuntimeException(e);

+////    }

+//    }

+//  }

+//  

+//  return noErrors;

+//}

+

+///**

+//* @return true if no errors

+//*/

+//private boolean compileV3PearSources() {

+// boolean noError = true;

+// Map<String, List<ClassnameAndPath>> p2c = c2ps.stream()

+//   .filter(c -> c.pearClasspath != null)

+//   .collect(Collectors.groupingBy(c -> c.pearClasspath));

+// 

+// List<Entry<String, List<ClassnameAndPath>>> ea = p2c.entrySet().stream()

+//         .sorted(Comparator.comparing(Entry::getKey)) //(e1, e2) -> e1.getKey().compareTo(e2.getKey())

+//         .collect(Collectors.toList());

+//

+// for (Entry<String, List<ClassnameAndPath>> e : ea) {

+//   noError = noError && compileV3SourcesCommon(e.getValue(), "for Pear " + e.getKey(), e.getKey() );

+// }

+// return noError;

+//}

+//

+///**

+//* @return true if no errors

+//*/

+//private boolean compileV3NonPearSources() {

+// 

+// List<ClassnameAndPath> cnps = c2ps.stream()

+//                                   .filter(c -> c.pearClasspath == null)

+//                                   .collect(Collectors.toList());

+// 

+// return compileV3SourcesCommon(cnps, "(non PEAR)", null);

+//}

+

+///**

+//* @param pathInPear a complete path to a class inside an (installed) pear

+//* @return the part starting after the top node of the install dir

+//*/

+//private String getPath_in_v3_classes(String pathInPear) { 

+// return path2classname.get(pathInPear);  

+//}

+  

+//private boolean reportDuplicates() throws IOException {

+//List<List<CommonConverted>> nonIdenticals = new ArrayList<>();

+//List<CommonConverted> onlyIdenticals = new ArrayList<>();

+//

+//classname2multiSources.forEach(

+//      (classname, ccs) -> {

+//        if (ccs.size() > 1) {

+//          nonIdenticals.add(ccs);

+//        } else {

+//          CommonConverted cc = ccs.get(0);

+//          if (cc.containersAndV2Paths.size() > 1) 

+//            onlyIdenticals.add(cc);  // the same item in multiple containers and/or paths

+//        }

+//      }

+//    );

+//

+//if (nonIdenticals.size() == 0) {

+//  if (onlyIdenticals.size() == 0) {

+//    System.out.println("There were no duplicates found.");

+//  } else {

+//    // report identical duplicates

+//    try (BufferedWriter bw = Files.newBufferedWriter(makePath(outDirLog + "identical_duplicates.txt"), StandardOpenOption.CREATE)) {

+//      logPrintNl("Report of Identical duplicates:", bw);

+//      for (CommonConverted cc : onlyIdenticals) {

+//        int i = 0;

+//        logPrintNl("Class: " + cc.fqcn_slash, bw);

+//        for (ContainerAndPath cp : cc.containersAndV2Paths) {

+//          logPrintNl("  " + (++i) + " " + cp, bw);

+//        }

+//        logPrintNl("", bw);

+//      }

+//    }

+//  }

+//  return true;

+//} 

+//

+//// non-identicals, print out all of them

+//try (BufferedWriter bw = Files.newBufferedWriter(makePath(outDirLog + "nonIdentical_duplicates.txt"), StandardOpenOption.CREATE)) {

+//  logPrintNl("Report of non-identical duplicates", bw);

+//  for (List<CommonConverted> nonIdentical : nonIdenticals) {

+//    String fqcn = nonIdentical.get(0).fqcn_slash;

+//    logPrintNl("  classname: " + fqcn, bw);

+//    int i = 1;

+//    // for each cc, and within each cc, for each containerAndPath

+//    for (CommonConverted cc : nonIdentical) {

+////      logPrintNl("    version " + i, bw);

+//      assert fqcn.equals(cc.fqcn_slash);

+//      int j = 1;

+//      boolean isSame = cc.containersAndV2Paths.size() > 1;

+//      boolean isFirstTime = true;

+//      for (ContainerAndPath cp : cc.containersAndV2Paths) {

+//        String first = isSame && isFirstTime 

+//                        ? "      same: "

+//                        : isSame 

+//                           ? "            "

+//                           : "      ";

+//        isFirstTime = false;

+//        logPrintNl(first + i + "." + (j++) + " " + cp, bw);

+//      }

+//      indent[0] -= 6;

+////      logPrintNl("", bw);

+//      i++;

+//    }

+////    logPrintNl("", bw);

+//  }

+//}

+//return false;

+//}

+  

+//private static class PathAndReason extends Report2<Path, String> {

+//Path path;

+//String reason;

+//PathAndReason(Path path, String reason) {

+//  this.path = path;

+//  this.reason = reason;

+//}

+//@Override

+//public Comparable<Path> getFirst() { return path; }

+//@Override

+//public Comparable<String> getSecond() { return reason; }

+//@Override

+//int getFirstLength() { return path.toString().length(); }

+//}

 

 }

diff --git a/uimaj-v3migration-jcas/src/test/run_configuration/UIMA Run V3 migrate JCas from classes roots test.launch b/uimaj-v3migration-jcas/src/test/run_configuration/UIMA Run V3 migrate JCas from classes roots test.launch
new file mode 100644
index 0000000..278eb69
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/run_configuration/UIMA Run V3 migrate JCas from classes roots test.launch
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one

+   or more contributor license agreements.  See the NOTICE file

+   distributed with this work for additional information

+   regarding copyright ownership.  The ASF licenses this file

+   to you under the Apache License, Version 2.0 (the

+   "License"); you may not use this file except in compliance

+   with the License.  You may obtain a copy of the License at

+

+     http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing,

+   software distributed under the License is distributed on an

+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+   KIND, either express or implied.  See the License for the

+   specific language governing permissions and limitations

+   under the License.    

+-->

+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">

+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">

+<listEntry value="/uimaj-v3migration-jcas/src/main/java/org/apache/uima/migratev3/jcas/MigrateJCas.java"/>

+</listAttribute>

+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">

+<listEntry value="1"/>

+</listAttribute>

+<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.m2e.launchconfig.classpathProvider"/>

+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.apache.uima.migratev3.jcas.MigrateJCas"/>

+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-classesRoots ${project_loc:/uimaj-v3migration-jcas}/src/test/v2_jcas_compiled&#13;&#10;-migrateClasspath ${project_loc:/uimaj-v3migration-jcas}/src/test/v2_jcas_compiled"/>

+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="uimaj-v3migration-jcas"/>

+<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>

+</launchConfiguration>

diff --git a/uimaj-v3migration-jcas/src/test/run_configuration/UIMA Run V3 migrate JCas from sources roots test.launch b/uimaj-v3migration-jcas/src/test/run_configuration/UIMA Run V3 migrate JCas from sources roots test.launch
new file mode 100644
index 0000000..c984065
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/run_configuration/UIMA Run V3 migrate JCas from sources roots test.launch
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one

+   or more contributor license agreements.  See the NOTICE file

+   distributed with this work for additional information

+   regarding copyright ownership.  The ASF licenses this file

+   to you under the Apache License, Version 2.0 (the

+   "License"); you may not use this file except in compliance

+   with the License.  You may obtain a copy of the License at

+

+     http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing,

+   software distributed under the License is distributed on an

+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+   KIND, either express or implied.  See the License for the

+   specific language governing permissions and limitations

+   under the License.    

+-->

+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">

+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">

+<listEntry value="/uimaj-v3migration-jcas/src/main/java/org/apache/uima/migratev3/jcas/MigrateJCas.java"/>

+</listAttribute>

+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">

+<listEntry value="1"/>

+</listAttribute>

+<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.m2e.launchconfig.classpathProvider"/>

+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.apache.uima.migratev3.jcas.MigrateJCas"/>

+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-sourcesRoots ${project_loc:/uimaj-v3migration-jcas}/src/test/v2_jcas_sources"/>

+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="uimaj-examples"/>

+<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>

+</launchConfiguration>

diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/example/PersonTitle.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/example/PersonTitle.class
new file mode 100644
index 0000000..026e91c
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/example/PersonTitle.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/example/PersonTitle_Type$1.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/example/PersonTitle_Type$1.class
new file mode 100644
index 0000000..269c21f
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/example/PersonTitle_Type$1.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/example/PersonTitle_Type.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/example/PersonTitle_Type.class
new file mode 100644
index 0000000..dd6bb70
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/example/PersonTitle_Type.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/SourceDocumentInformation.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/SourceDocumentInformation.class
new file mode 100644
index 0000000..8817ec5
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/SourceDocumentInformation.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/SourceDocumentInformation.xml b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/SourceDocumentInformation.xml
new file mode 100644
index 0000000..2b4cff4
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/SourceDocumentInformation.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+	<!--
+	 ***************************************************************
+	 * Licensed to the Apache Software Foundation (ASF) under one
+	 * or more contributor license agreements.  See the NOTICE file
+	 * distributed with this work for additional information
+	 * regarding copyright ownership.  The ASF licenses this file
+	 * to you under the Apache License, Version 2.0 (the
+	 * "License"); you may not use this file except in compliance
+	 * with the License.  You may obtain a copy of the License at
+         *
+	 *   http://www.apache.org/licenses/LICENSE-2.0
+	 * 
+	 * Unless required by applicable law or agreed to in writing,
+	 * software distributed under the License is distributed on an
+	 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	 * KIND, either express or implied.  See the License for the
+	 * specific language governing permissions and limitations
+	 * under the License.
+	 ***************************************************************
+   -->
+   
+<typeSystemDescription xmlns="http://uima.apache.org/resourceSpecifier">
+	<name>org.apache.uima.examples.SourceDocumentInformation</name>
+	<description>Defines a type for storing information about the original source document from which the current CAS was initialized</description>
+	<version>1.0</version>
+	<vendor>The Apache Software Foundation</vendor>
+	<types>
+		<typeDescription>
+			<name>org.apache.uima.examples.SourceDocumentInformation</name>
+			<description>Stores detailed information about the original source document from which the current CAS was initialized. All information (like size) refers to the source document and not to the document in the CAS which may be converted and filtered by a CAS Initializer. For example this information will be written to the Semantic Search index so that the original document contents can be retrieved by queries.</description>
+			<supertypeName>uima.tcas.Annotation</supertypeName>
+			<features>
+				<featureDescription>
+					<name>uri</name>
+					<description>URI of document. (For example, file:///MyDirectory/myFile.txt for a simple file or http://incubator.apache.org/uima/index.html for content from a web source.)</description>
+					<rangeTypeName>uima.cas.String</rangeTypeName>
+				</featureDescription>
+				<featureDescription>
+					<name>offsetInSource</name>
+					<description>Byte offset of the start of document content within original source file or other input source. Only used if the CAS document was retrieved from an source where one physical source file contained several conceptual documents. Zero otherwise.</description>
+					<rangeTypeName>uima.cas.Integer</rangeTypeName>
+				</featureDescription>
+				<featureDescription>
+					<name>documentSize</name>
+					<description>Size of original document in bytes before processing by CAS Initializer. Either absolute file size of size within file or other source.</description>
+					<rangeTypeName>uima.cas.Integer</rangeTypeName>
+				</featureDescription>
+				<featureDescription>
+				  <name>lastSegment</name>
+				  <description>For a CAS that represents a segment of a larger source document, this flag indicates whether this CAS is the final segment of the source document.  This is useful for downstream components that want to take some action after having seen all of the segments of a particular source document. </description>
+			      <rangeTypeName>uima.cas.Boolean</rangeTypeName>
+			    </featureDescription>				
+			</features>
+		</typeDescription>
+	</types>
+</typeSystemDescription>
\ No newline at end of file
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/SourceDocumentInformation_Type$1.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/SourceDocumentInformation_Type$1.class
new file mode 100644
index 0000000..cecae45
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/SourceDocumentInformation_Type$1.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/SourceDocumentInformation_Type.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/SourceDocumentInformation_Type.class
new file mode 100644
index 0000000..3980992
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/SourceDocumentInformation_Type.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/AdvancedFixedFlowController$FixedFlowObject.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/AdvancedFixedFlowController$FixedFlowObject.class
new file mode 100644
index 0000000..532d364
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/AdvancedFixedFlowController$FixedFlowObject.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/AdvancedFixedFlowController.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/AdvancedFixedFlowController.class
new file mode 100644
index 0000000..a6a2556
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/AdvancedFixedFlowController.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController$WhiteboardFlow.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController$WhiteboardFlow.class
new file mode 100644
index 0000000..b68ca7f
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController$WhiteboardFlow.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController.class
new file mode 100644
index 0000000..4bef6e5
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController2$1.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController2$1.class
new file mode 100644
index 0000000..e82c4be
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController2$1.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController2$ComponentInfo.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController2$ComponentInfo.class
new file mode 100644
index 0000000..28dce89
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController2$ComponentInfo.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController2$WhiteboardFlow.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController2$WhiteboardFlow.class
new file mode 100644
index 0000000..6069ab311a
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController2$WhiteboardFlow.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController2.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController2.class
new file mode 100644
index 0000000..c88439b
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/flow/WhiteboardFlowController2.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Sentence.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Sentence.class
new file mode 100644
index 0000000..14ad35d
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Sentence.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Sentence_Type$1.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Sentence_Type$1.class
new file mode 100644
index 0000000..4af5408
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Sentence_Type$1.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Sentence_Type.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Sentence_Type.class
new file mode 100644
index 0000000..6ca5ef3
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Sentence_Type.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/SimpleTokenAndSentenceAnnotator$1.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/SimpleTokenAndSentenceAnnotator$1.class
new file mode 100644
index 0000000..02bef9b
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/SimpleTokenAndSentenceAnnotator$1.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/SimpleTokenAndSentenceAnnotator$2.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/SimpleTokenAndSentenceAnnotator$2.class
new file mode 100644
index 0000000..f4f1637
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/SimpleTokenAndSentenceAnnotator$2.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/SimpleTokenAndSentenceAnnotator$Maker.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/SimpleTokenAndSentenceAnnotator$Maker.class
new file mode 100644
index 0000000..d431f40
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/SimpleTokenAndSentenceAnnotator$Maker.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/SimpleTokenAndSentenceAnnotator.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/SimpleTokenAndSentenceAnnotator.class
new file mode 100644
index 0000000..d606ae6
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/SimpleTokenAndSentenceAnnotator.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Token.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Token.class
new file mode 100644
index 0000000..a2f1e91
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Token.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Token_Type$1.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Token_Type$1.class
new file mode 100644
index 0000000..2159a7d
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Token_Type$1.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Token_Type.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Token_Type.class
new file mode 100644
index 0000000..78a58c4
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/examples/tokenizer/Token_Type.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/jcas/cas/AnnotationBase.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/jcas/cas/AnnotationBase.class
new file mode 100644
index 0000000..4d15ae0
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/jcas/cas/AnnotationBase.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/jcas/cas/AnnotationBase_Type.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/jcas/cas/AnnotationBase_Type.class
new file mode 100644
index 0000000..ae5fbbb
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/jcas/cas/AnnotationBase_Type.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/jcas/cas/TOP.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/jcas/cas/TOP.class
new file mode 100644
index 0000000..a3d5166
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/jcas/cas/TOP.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/jcas/cas/TOP_Type.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/jcas/cas/TOP_Type.class
new file mode 100644
index 0000000..c8ad7ff
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/jcas/cas/TOP_Type.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateAnnot.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateAnnot.class
new file mode 100644
index 0000000..d988f5c
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateAnnot.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateAnnot_Type$1.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateAnnot_Type$1.class
new file mode 100644
index 0000000..372026d
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateAnnot_Type$1.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateAnnot_Type.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateAnnot_Type.class
new file mode 100644
index 0000000..a57c175
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateAnnot_Type.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateTimeAnnot.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateTimeAnnot.class
new file mode 100644
index 0000000..c66efb9
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateTimeAnnot.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateTimeAnnot_Type$1.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateTimeAnnot_Type$1.class
new file mode 100644
index 0000000..332c0e7
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateTimeAnnot_Type$1.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateTimeAnnot_Type.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateTimeAnnot_Type.class
new file mode 100644
index 0000000..ad622a3
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/DateTimeAnnot_Type.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/Meeting.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/Meeting.class
new file mode 100644
index 0000000..599b2bf
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/Meeting.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/Meeting_Type$1.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/Meeting_Type$1.class
new file mode 100644
index 0000000..3202e89
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/Meeting_Type$1.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/Meeting_Type.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/Meeting_Type.class
new file mode 100644
index 0000000..36d1708
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/Meeting_Type.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/RoomNumber.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/RoomNumber.class
new file mode 100644
index 0000000..4ea7eea
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/RoomNumber.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/RoomNumber_Type$1.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/RoomNumber_Type$1.class
new file mode 100644
index 0000000..fb1ef40
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/RoomNumber_Type$1.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/RoomNumber_Type.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/RoomNumber_Type.class
new file mode 100644
index 0000000..59958fa
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/RoomNumber_Type.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/SentenceAnnot.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/SentenceAnnot.class
new file mode 100644
index 0000000..2972353
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/SentenceAnnot.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/SentenceAnnot_Type$1.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/SentenceAnnot_Type$1.class
new file mode 100644
index 0000000..dfcc7c2
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/SentenceAnnot_Type$1.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/SentenceAnnot_Type.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/SentenceAnnot_Type.class
new file mode 100644
index 0000000..0a086c1
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/SentenceAnnot_Type.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/TimeAnnot.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/TimeAnnot.class
new file mode 100644
index 0000000..9769fb5
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/TimeAnnot.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/TimeAnnot_Type$1.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/TimeAnnot_Type$1.class
new file mode 100644
index 0000000..5d727b7
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/TimeAnnot_Type$1.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/TimeAnnot_Type.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/TimeAnnot_Type.class
new file mode 100644
index 0000000..f339938
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/TimeAnnot_Type.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaAcronym.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaAcronym.class
new file mode 100644
index 0000000..41b2869
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaAcronym.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaAcronym_Type$1.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaAcronym_Type$1.class
new file mode 100644
index 0000000..5a5e6f3
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaAcronym_Type$1.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaAcronym_Type.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaAcronym_Type.class
new file mode 100644
index 0000000..35576f8
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaAcronym_Type.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaMeeting.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaMeeting.class
new file mode 100644
index 0000000..90874e0
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaMeeting.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaMeeting_Type$1.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaMeeting_Type$1.class
new file mode 100644
index 0000000..2811467
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaMeeting_Type$1.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaMeeting_Type.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaMeeting_Type.class
new file mode 100644
index 0000000..e00dd2c
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/UimaMeeting_Type.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/WordAnnot.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/WordAnnot.class
new file mode 100644
index 0000000..4313e45
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/WordAnnot.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/WordAnnot_Type$1.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/WordAnnot_Type$1.class
new file mode 100644
index 0000000..b6a730a
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/WordAnnot_Type$1.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/WordAnnot_Type.class b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/WordAnnot_Type.class
new file mode 100644
index 0000000..7d47658
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_compiled/org/apache/uima/tutorial/WordAnnot_Type.class
Binary files differ
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/example/PersonTitle.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/example/PersonTitle.java
new file mode 100644
index 0000000..1a1c604
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/example/PersonTitle.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package example;
+
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.cas.TOP_Type;
+import org.apache.uima.jcas.tcas.Annotation;
+
+/**
+ * A Personal Title. Updated by JCasGen Mon May 23 17:48:43 EDT 2005 XML source:
+ * c:\a\eclipse\301jxe\jedii_examples\descriptors\analysis_engine\NamesAndPersonTitles_TAE.xml
+ * 
+ * @generated
+ */
+public class PersonTitle extends Annotation {
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int typeIndexID = JCasRegistry.register(PersonTitle.class);
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int type = typeIndexID;
+
+  /** @generated */
+  public int getTypeIndexID() {
+    return typeIndexID;
+  }
+
+  /**
+   * Never called. Disable default constructor
+   * 
+   * @generated
+   */
+  protected PersonTitle() {
+  }
+
+  /**
+   * Internal - constructor used by generator
+   * 
+   * @generated
+   */
+  public PersonTitle(int addr, TOP_Type type) {
+    super(addr, type);
+    readObject();
+  }
+
+  /** @generated */
+  public PersonTitle(JCas jcas) {
+    super(jcas);
+    readObject();
+  }
+
+  public PersonTitle(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }
+
+  /**
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->
+   * 
+   * @generated modifiable
+   */
+  private void readObject() {
+  }
+
+  // *--------------*
+  // * Feature: Kind
+
+  /**
+   * getter for Kind - gets The kind of title - Civilian, Military, or Government.
+   * 
+   * @generated
+   */
+  public String getKind() {
+    if (PersonTitle_Type.featOkTst && ((PersonTitle_Type) jcasType).casFeat_Kind == null)
+      this.jcasType.jcas.throwFeatMissing("Kind", "example.PersonTitle");
+    return jcasType.ll_cas.ll_getStringValue(addr, ((PersonTitle_Type) jcasType).casFeatCode_Kind);
+  }
+
+  /**
+   * setter for Kind - sets The kind of title - Civilian, Military, or Government.
+   * 
+   * @generated
+   */
+  public void setKind(String v) {
+    if (PersonTitle_Type.featOkTst && ((PersonTitle_Type) jcasType).casFeat_Kind == null)
+      this.jcasType.jcas.throwFeatMissing("Kind", "example.PersonTitle");
+    jcasType.ll_cas.ll_setStringValue(addr, ((PersonTitle_Type) jcasType).casFeatCode_Kind, v);
+  }
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/example/PersonTitle_Type.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/example/PersonTitle_Type.java
new file mode 100644
index 0000000..3777eb5
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/example/PersonTitle_Type.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package example;
+
+import org.apache.uima.cas.Feature;
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.FSGenerator;
+import org.apache.uima.cas.impl.FeatureImpl;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.tcas.Annotation_Type;
+
+/**
+ * A Personal Title. Updated by JCasGen Mon May 23 17:48:43 EDT 2005
+ * 
+ * @generated
+ */
+public class PersonTitle_Type extends Annotation_Type {
+  /** @generated */
+  protected FSGenerator getFSGenerator() {
+    return fsGenerator;
+  }
+
+  /** @generated */
+  private final FSGenerator fsGenerator = new FSGenerator() {
+    public FeatureStructure createFS(int addr, CASImpl cas) {
+      if (instanceOf_Type.useExistingInstance) {
+        // Return eq fs instance if already created
+        FeatureStructure fs = instanceOf_Type.jcas.getJfsFromCaddr(addr);
+        if (null == fs) {
+          fs = new PersonTitle(addr, instanceOf_Type);
+          instanceOf_Type.jcas.putJfsFromCaddr(addr, fs);
+          return fs;
+        }
+        return fs;
+      } else
+        return new PersonTitle(addr, instanceOf_Type);
+    }
+  };
+
+  /** @generated */
+  public final static int typeIndexID = PersonTitle.typeIndexID;
+
+  /**
+   * @generated
+   * @modifiable
+   */
+  public final static boolean featOkTst = JCasRegistry.getFeatOkTst("example.PersonTitle");
+
+  /** @generated */
+  final Feature casFeat_Kind;
+
+  /** @generated */
+  final int casFeatCode_Kind;
+
+  /** @generated */
+  public String getKind(int addr) {
+    if (featOkTst && casFeat_Kind == null)
+      this.jcas.throwFeatMissing("Kind", "example.PersonTitle");
+    return ll_cas.ll_getStringValue(addr, casFeatCode_Kind);
+  }
+
+  /** @generated */
+  public void setKind(int addr, String v) {
+    if (featOkTst && casFeat_Kind == null)
+      this.jcas.throwFeatMissing("Kind", "example.PersonTitle");
+    ll_cas.ll_setStringValue(addr, casFeatCode_Kind, v);
+  }
+
+  /**
+   * initialize variables to correspond with Cas Type and Features
+   * 
+   * @generated
+   */
+  public PersonTitle_Type(JCas jcas, Type casType) {
+    super(jcas, casType);
+    casImpl.getFSClassRegistry().addGeneratorForType((TypeImpl) this.casType, getFSGenerator());
+
+    casFeat_Kind = jcas.getRequiredFeatureDE(casType, "Kind", "example.PersonTitleKind", featOkTst);
+    casFeatCode_Kind = (null == casFeat_Kind) ? JCas.INVALID_FEATURE_CODE
+            : ((FeatureImpl) casFeat_Kind).getCode();
+
+  }
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/examples/tokenizer/Sentence.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/examples/tokenizer/Sentence.java
new file mode 100644
index 0000000..b9a815a
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/examples/tokenizer/Sentence.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.examples.tokenizer;
+
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.cas.TOP_Type;
+import org.apache.uima.jcas.tcas.Annotation;
+
+public class Sentence extends Annotation {
+
+  public final static int typeIndexID = JCasRegistry.register(Sentence.class);
+
+  public final static int type = typeIndexID;
+
+  public int getTypeIndexID() {
+    return typeIndexID;
+  }
+
+  // Never called. Disable default constructor
+  protected Sentence() {
+  }
+
+  /** Internal - Constructor used by generator */
+  public Sentence(int addr, TOP_Type type) {
+    super(addr, type);
+  }
+
+  public Sentence(JCas jcas) {
+    super(jcas);
+  }
+
+  public Sentence(JCas jcas, int start, int end) {
+    super(jcas, start, end);
+  }
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/examples/tokenizer/Sentence_Type.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/examples/tokenizer/Sentence_Type.java
new file mode 100644
index 0000000..fc2c2e5
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/examples/tokenizer/Sentence_Type.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.examples.tokenizer;
+
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.FSGenerator;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.tcas.Annotation_Type;
+
+public class Sentence_Type extends Annotation_Type {
+  protected FSGenerator getFSGenerator() {
+    return fsGenerator;
+  }
+
+  private final FSGenerator fsGenerator = new FSGenerator() {
+    public FeatureStructure createFS(int addr, CASImpl cas) {
+      if (instanceOf_Type.useExistingInstance) {
+        // Return eq fs instance if already created
+        FeatureStructure fs = instanceOf_Type.jcas.getJfsFromCaddr(addr);
+        if (null == fs) {
+          fs = new Sentence(addr, instanceOf_Type);
+          instanceOf_Type.jcas.putJfsFromCaddr(addr, fs);
+          return fs;
+        }
+        return fs;
+      } else
+        return new Sentence(addr, instanceOf_Type);
+    }
+  };
+
+  public final static int typeIndexID = Sentence.typeIndexID;
+
+  public final static boolean featOkTst = JCasRegistry.getFeatOkTst("org.apache.uima_examples.tokenizer.Sentence");
+
+  // * initialize variables to correspond with Cas Type and Features
+  public Sentence_Type(JCas jcas, Type casType) {
+    super(jcas, casType);
+    casImpl.getFSClassRegistry().addGeneratorForType((TypeImpl) this.casType, getFSGenerator());
+
+  }
+
+  protected Sentence_Type() { // block default new operator
+    throw new RuntimeException("Internal Error-this constructor should never be called.");
+  }
+
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/examples/tokenizer/SimpleTokenAndSentenceAnnotator.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/examples/tokenizer/SimpleTokenAndSentenceAnnotator.java
new file mode 100644
index 0000000..2122036
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/examples/tokenizer/SimpleTokenAndSentenceAnnotator.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.examples.tokenizer;
+
+import java.text.BreakIterator;
+import java.text.ParsePosition;
+import java.util.Locale;
+
+import org.apache.uima.analysis_component.JCasAnnotator_ImplBase;
+import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.tcas.Annotation;
+
+/**
+ * An example annotator that annotates Tokens and Sentences.
+ */
+public class SimpleTokenAndSentenceAnnotator extends JCasAnnotator_ImplBase {
+
+  static abstract class Maker {
+    abstract Annotation newAnnotation(JCas jcas, int start, int end);
+  }
+
+  JCas jcas;
+
+  String input;
+
+  ParsePosition pp = new ParsePosition(0);
+
+  // ****************************************
+  // * Static vars holding break iterators
+  // ****************************************
+  static final BreakIterator sentenceBreak = BreakIterator.getSentenceInstance(Locale.US);
+
+  static final BreakIterator wordBreak = BreakIterator.getWordInstance(Locale.US);
+
+  // *********************************************
+  // * function pointers for new instances *
+  // *********************************************
+  static final Maker sentenceAnnotationMaker = new Maker() {
+    Annotation newAnnotation(JCas jcas, int start, int end) {
+      return new Sentence(jcas, start, end);
+    }
+  };
+
+  static final Maker tokenAnnotationMaker = new Maker() {
+    Annotation newAnnotation(JCas jcas, int start, int end) {
+      return new Token(jcas, start, end);
+    }
+  };
+
+  // *************************************************************
+  // * process *
+  // *************************************************************
+  public void process(JCas aJCas) throws AnalysisEngineProcessException {
+    jcas = aJCas;
+    input = jcas.getDocumentText();
+
+    // Create Annotations
+    makeAnnotations(sentenceAnnotationMaker, sentenceBreak);
+    makeAnnotations(tokenAnnotationMaker, wordBreak);
+  }
+
+  // *************************************************************
+  // * Helper Methods *
+  // *************************************************************
+  void makeAnnotations(Maker m, BreakIterator b) {
+    b.setText(input);
+    for (int end = b.next(), start = b.first(); end != BreakIterator.DONE; start = end, end = b
+            .next()) {
+      // eliminate all-whitespace tokens
+      boolean isWhitespace = true;
+      for (int i = start; i < end; i++) {
+        if (!Character.isWhitespace(input.charAt(i))) {
+          isWhitespace = false;
+          break;
+        }
+      }
+      if (!isWhitespace) {
+        m.newAnnotation(jcas, start, end).addToIndexes();
+      }
+    }
+  }
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/examples/tokenizer/Token.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/examples/tokenizer/Token.java
new file mode 100644
index 0000000..d9b65ce
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/examples/tokenizer/Token.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.examples.tokenizer;
+
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.cas.TOP_Type;
+import org.apache.uima.jcas.tcas.Annotation;
+
+public class Token extends Annotation {
+
+  public final static int typeIndexID = JCasRegistry.register(Token.class);
+
+  public final static int type = typeIndexID;
+
+  public int getTypeIndexID() {
+    return typeIndexID;
+  }
+
+  // Never called. Disable default constructor
+  protected Token() {
+  }
+
+  /** Internal - Constructor used by generator */
+  public Token(int addr, TOP_Type type) {
+    super(addr, type);
+  }
+
+  public Token(JCas jcas) {
+    super(jcas);
+  }
+
+  public Token(JCas jcas, int start, int end) {
+    super(jcas, start, end);
+  }
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/examples/tokenizer/Token_Type.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/examples/tokenizer/Token_Type.java
new file mode 100644
index 0000000..23a29aa
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/examples/tokenizer/Token_Type.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.examples.tokenizer;
+
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.FSGenerator;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.tcas.Annotation_Type;
+
+public class Token_Type extends Annotation_Type {
+  protected FSGenerator getFSGenerator() {
+    return fsGenerator;
+  }
+
+  private final FSGenerator fsGenerator = new FSGenerator() {
+    public FeatureStructure createFS(int addr, CASImpl cas) {
+      if (instanceOf_Type.useExistingInstance) {
+        // Return eq fs instance if already created
+        FeatureStructure fs = instanceOf_Type.jcas.getJfsFromCaddr(addr);
+        if (null == fs) {
+          fs = new Token(addr, instanceOf_Type);
+          instanceOf_Type.jcas.putJfsFromCaddr(addr, fs);
+          return fs;
+        }
+        return fs;
+      } else
+        return new Token(addr, instanceOf_Type);
+    }
+  };
+
+  public final static int typeIndexID = Token.typeIndexID;
+
+  public final static boolean featOkTst = JCasRegistry.getFeatOkTst("org.apache.uima_examples.tokenizer.Token");
+
+  // * initialize variables to correspond with Cas Type and Features
+  public Token_Type(JCas jcas, Type casType) {
+    super(jcas, casType);
+    casImpl.getFSClassRegistry().addGeneratorForType((TypeImpl) this.casType, getFSGenerator());
+
+  }
+
+  protected Token_Type() { // block default new operator
+    throw new RuntimeException("Internal Error-this constructor should never be called.");
+  }
+
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/DateAnnot.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/DateAnnot.java
new file mode 100644
index 0000000..ba99dba
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/DateAnnot.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.cas.TOP_Type;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004 XML source: C:/Program
+ * Files/apache/uima/examples/descriptors/tutorial/ex6/TutorialTypeSystem.xml
+ * 
+ * @generated
+ */
+public class DateAnnot extends DateTimeAnnot {
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int typeIndexID = JCasRegistry.register(DateAnnot.class);
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int type = typeIndexID;
+
+  /** @generated */
+  public int getTypeIndexID() {
+    return typeIndexID;
+  }
+
+  /**
+   * Never called. Disable default constructor
+   * 
+   * @generated
+   */
+  protected DateAnnot() {
+  }
+
+  /**
+   * Internal - constructor used by generator
+   * 
+   * @generated
+   */
+  public DateAnnot(int addr, TOP_Type type) {
+    super(addr, type);
+    readObject();
+  }
+
+  /** @generated */
+  public DateAnnot(JCas jcas) {
+    super(jcas);
+    readObject();
+  }
+
+  public DateAnnot(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }
+
+  /**
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->
+   * 
+   * @generated modifiable
+   */
+  private void readObject() {
+  }
+
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/DateAnnot_Type.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/DateAnnot_Type.java
new file mode 100644
index 0000000..b5320ea
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/DateAnnot_Type.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.FSGenerator;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004
+ * 
+ * @generated
+ */
+public class DateAnnot_Type extends DateTimeAnnot_Type {
+  /** @generated */
+  protected FSGenerator getFSGenerator() {
+    return fsGenerator;
+  }
+
+  /** @generated */
+  private final FSGenerator fsGenerator = new FSGenerator() {
+    public FeatureStructure createFS(int addr, CASImpl cas) {
+      if (instanceOf_Type.useExistingInstance) {
+        // Return eq fs instance if already created
+        FeatureStructure fs = instanceOf_Type.jcas.getJfsFromCaddr(addr);
+        if (null == fs) {
+          fs = new DateAnnot(addr, instanceOf_Type);
+          instanceOf_Type.jcas.putJfsFromCaddr(addr, fs);
+          return fs;
+        }
+        return fs;
+      } else
+        return new DateAnnot(addr, instanceOf_Type);
+    }
+  };
+
+  /** @generated */
+  public final static int typeIndexID = DateAnnot.typeIndexID;
+
+  /**
+   * @generated
+   * @modifiable
+   */
+  public final static boolean featOkTst = JCasRegistry.getFeatOkTst("org.apache.uima.tutorial.DateAnnot");
+
+  /**
+   * initialize variables to correspond with Cas Type and Features
+   * 
+   * @generated
+   */
+  public DateAnnot_Type(JCas jcas, Type casType) {
+    super(jcas, casType);
+    casImpl.getFSClassRegistry().addGeneratorForType((TypeImpl) this.casType, getFSGenerator());
+
+  }
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/DateTimeAnnot.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/DateTimeAnnot.java
new file mode 100644
index 0000000..19114b6
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/DateTimeAnnot.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.cas.TOP_Type;
+import org.apache.uima.jcas.tcas.Annotation;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004 XML source: C:/Program
+ * Files/apache/uima/examples/descriptors/tutorial/ex6/TutorialTypeSystem.xml
+ * 
+ * @generated
+ */
+public class DateTimeAnnot extends Annotation {
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int typeIndexID = JCasRegistry.register(DateTimeAnnot.class);
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int type = typeIndexID;
+
+  /** @generated */
+  public int getTypeIndexID() {
+    return typeIndexID;
+  }
+
+  /**
+   * Never called. Disable default constructor
+   * 
+   * @generated
+   */
+  protected DateTimeAnnot() {
+  }
+
+  /**
+   * Internal - constructor used by generator
+   * 
+   * @generated
+   */
+  public DateTimeAnnot(int addr, TOP_Type type) {
+    super(addr, type);
+    readObject();
+  }
+
+  /** @generated */
+  public DateTimeAnnot(JCas jcas) {
+    super(jcas);
+    readObject();
+  }
+
+  public DateTimeAnnot(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }
+
+  /**
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->
+   * 
+   * @generated modifiable
+   */
+  private void readObject() {
+  }
+
+  // *--------------*
+  // * Feature: shortDateString
+
+  /**
+   * getter for shortDateString - gets
+   * 
+   * @generated
+   */
+  public String getShortDateString() {
+    if (DateTimeAnnot_Type.featOkTst
+            && ((DateTimeAnnot_Type) jcasType).casFeat_shortDateString == null)
+      this.jcasType.jcas.throwFeatMissing("shortDateString", "org.apache.uima.tutorial.DateTimeAnnot");
+    return jcasType.ll_cas.ll_getStringValue(addr,
+            ((DateTimeAnnot_Type) jcasType).casFeatCode_shortDateString);
+  }
+
+  /**
+   * setter for shortDateString - sets
+   * 
+   * @generated
+   */
+  public void setShortDateString(String v) {
+    if (DateTimeAnnot_Type.featOkTst
+            && ((DateTimeAnnot_Type) jcasType).casFeat_shortDateString == null)
+      this.jcasType.jcas.throwFeatMissing("shortDateString", "org.apache.uima.tutorial.DateTimeAnnot");
+    jcasType.ll_cas.ll_setStringValue(addr,
+            ((DateTimeAnnot_Type) jcasType).casFeatCode_shortDateString, v);
+  }
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/DateTimeAnnot_Type.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/DateTimeAnnot_Type.java
new file mode 100644
index 0000000..5c762eb
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/DateTimeAnnot_Type.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.cas.Feature;
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.FSGenerator;
+import org.apache.uima.cas.impl.FeatureImpl;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.tcas.Annotation_Type;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004
+ * 
+ * @generated
+ */
+public class DateTimeAnnot_Type extends Annotation_Type {
+  /** @generated */
+  protected FSGenerator getFSGenerator() {
+    return fsGenerator;
+  }
+
+  /** @generated */
+  private final FSGenerator fsGenerator = new FSGenerator() {
+    public FeatureStructure createFS(int addr, CASImpl cas) {
+      if (instanceOf_Type.useExistingInstance) {
+        // Return eq fs instance if already created
+        FeatureStructure fs = instanceOf_Type.jcas.getJfsFromCaddr(addr);
+        if (null == fs) {
+          fs = new DateTimeAnnot(addr, instanceOf_Type);
+          instanceOf_Type.jcas.putJfsFromCaddr(addr, fs);
+          return fs;
+        }
+        return fs;
+      } else
+        return new DateTimeAnnot(addr, instanceOf_Type);
+    }
+  };
+
+  /** @generated */
+  public final static int typeIndexID = DateTimeAnnot.typeIndexID;
+
+  /**
+   * @generated
+   * @modifiable
+   */
+  public final static boolean featOkTst = JCasRegistry.getFeatOkTst("org.apache.uima.tutorial.DateTimeAnnot");
+
+  /** @generated */
+  final Feature casFeat_shortDateString;
+
+  /** @generated */
+  final int casFeatCode_shortDateString;
+
+  /** @generated */
+  public String getShortDateString(int addr) {
+    if (featOkTst && casFeat_shortDateString == null)
+      this.jcas.throwFeatMissing("shortDateString", "org.apache.uima.tutorial.DateTimeAnnot");
+    return ll_cas.ll_getStringValue(addr, casFeatCode_shortDateString);
+  }
+
+  /** @generated */
+  public void setShortDateString(int addr, String v) {
+    if (featOkTst && casFeat_shortDateString == null)
+      this.jcas.throwFeatMissing("shortDateString", "org.apache.uima.tutorial.DateTimeAnnot");
+    ll_cas.ll_setStringValue(addr, casFeatCode_shortDateString, v);
+  }
+
+  /**
+   * initialize variables to correspond with Cas Type and Features
+   * 
+   * @generated
+   */
+  public DateTimeAnnot_Type(JCas jcas, Type casType) {
+    super(jcas, casType);
+    casImpl.getFSClassRegistry().addGeneratorForType((TypeImpl) this.casType, getFSGenerator());
+
+    casFeat_shortDateString = jcas.getRequiredFeatureDE(casType, "shortDateString",
+            "uima.cas.String", featOkTst);
+    casFeatCode_shortDateString = (null == casFeat_shortDateString) ? JCas.INVALID_FEATURE_CODE
+            : ((FeatureImpl) casFeat_shortDateString).getCode();
+
+  }
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/Meeting.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/Meeting.java
new file mode 100644
index 0000000..051500a
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/Meeting.java
@@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.cas.TOP_Type;
+import org.apache.uima.jcas.tcas.Annotation;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004 XML source: C:/Program
+ * Files/apache/uima/examples/descriptors/tutorial/ex6/TutorialTypeSystem.xml
+ * 
+ * @generated
+ */
+public class Meeting extends Annotation {
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int typeIndexID = JCasRegistry.register(Meeting.class);
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int type = typeIndexID;
+
+  /** @generated */
+  public int getTypeIndexID() {
+    return typeIndexID;
+  }
+
+  /**
+   * Never called. Disable default constructor
+   * 
+   * @generated
+   */
+  protected Meeting() {
+  }
+
+  /**
+   * Internal - constructor used by generator
+   * 
+   * @generated
+   */
+  public Meeting(int addr, TOP_Type type) {
+    super(addr, type);
+    readObject();
+  }
+
+  /** @generated */
+  public Meeting(JCas jcas) {
+    super(jcas);
+    readObject();
+  }
+
+  public Meeting(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }
+
+  /**
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->
+   * 
+   * @generated modifiable
+   */
+  private void readObject() {
+  }
+
+  // *--------------*
+  // * Feature: room
+
+  /**
+   * getter for room - gets
+   * 
+   * @generated
+   */
+  public RoomNumber getRoom() {
+    if (Meeting_Type.featOkTst && ((Meeting_Type) jcasType).casFeat_room == null)
+      this.jcasType.jcas.throwFeatMissing("room", "org.apache.uima.tutorial.Meeting");
+    return (RoomNumber) (jcasType.ll_cas.ll_getFSForRef(jcasType.ll_cas.ll_getRefValue(addr,
+            ((Meeting_Type) jcasType).casFeatCode_room)));
+  }
+
+  /**
+   * setter for room - sets
+   * 
+   * @generated
+   */
+  public void setRoom(RoomNumber v) {
+    if (Meeting_Type.featOkTst && ((Meeting_Type) jcasType).casFeat_room == null)
+      this.jcasType.jcas.throwFeatMissing("room", "org.apache.uima.tutorial.Meeting");
+    jcasType.ll_cas.ll_setRefValue(addr, ((Meeting_Type) jcasType).casFeatCode_room,
+            jcasType.ll_cas.ll_getFSRef(v));
+  }
+
+  // *--------------*
+  // * Feature: date
+
+  /**
+   * getter for date - gets
+   * 
+   * @generated
+   */
+  public DateAnnot getDate() {
+    if (Meeting_Type.featOkTst && ((Meeting_Type) jcasType).casFeat_date == null)
+      this.jcasType.jcas.throwFeatMissing("date", "org.apache.uima.tutorial.Meeting");
+    return (DateAnnot) (jcasType.ll_cas.ll_getFSForRef(jcasType.ll_cas.ll_getRefValue(addr,
+            ((Meeting_Type) jcasType).casFeatCode_date)));
+  }
+
+  /**
+   * setter for date - sets
+   * 
+   * @generated
+   */
+  public void setDate(DateAnnot v) {
+    if (Meeting_Type.featOkTst && ((Meeting_Type) jcasType).casFeat_date == null)
+      this.jcasType.jcas.throwFeatMissing("date", "org.apache.uima.tutorial.Meeting");
+    jcasType.ll_cas.ll_setRefValue(addr, ((Meeting_Type) jcasType).casFeatCode_date,
+            jcasType.ll_cas.ll_getFSRef(v));
+  }
+
+  // *--------------*
+  // * Feature: startTime
+
+  /**
+   * getter for startTime - gets
+   * 
+   * @generated
+   */
+  public TimeAnnot getStartTime() {
+    if (Meeting_Type.featOkTst && ((Meeting_Type) jcasType).casFeat_startTime == null)
+      this.jcasType.jcas.throwFeatMissing("startTime", "org.apache.uima.tutorial.Meeting");
+    return (TimeAnnot) (jcasType.ll_cas.ll_getFSForRef(jcasType.ll_cas.ll_getRefValue(addr,
+            ((Meeting_Type) jcasType).casFeatCode_startTime)));
+  }
+
+  /**
+   * setter for startTime - sets
+   * 
+   * @generated
+   */
+  public void setStartTime(TimeAnnot v) {
+    if (Meeting_Type.featOkTst && ((Meeting_Type) jcasType).casFeat_startTime == null)
+      this.jcasType.jcas.throwFeatMissing("startTime", "org.apache.uima.tutorial.Meeting");
+    jcasType.ll_cas.ll_setRefValue(addr, ((Meeting_Type) jcasType).casFeatCode_startTime,
+            jcasType.ll_cas.ll_getFSRef(v));
+  }
+
+  // *--------------*
+  // * Feature: endTime
+
+  /**
+   * getter for endTime - gets
+   * 
+   * @generated
+   */
+  public TimeAnnot getEndTime() {
+    if (Meeting_Type.featOkTst && ((Meeting_Type) jcasType).casFeat_endTime == null)
+      this.jcasType.jcas.throwFeatMissing("endTime", "org.apache.uima.tutorial.Meeting");
+    return (TimeAnnot) (jcasType.ll_cas.ll_getFSForRef(jcasType.ll_cas.ll_getRefValue(addr,
+            ((Meeting_Type) jcasType).casFeatCode_endTime)));
+  }
+
+  /**
+   * setter for endTime - sets
+   * 
+   * @generated
+   */
+  public void setEndTime(TimeAnnot v) {
+    if (Meeting_Type.featOkTst && ((Meeting_Type) jcasType).casFeat_endTime == null)
+      this.jcasType.jcas.throwFeatMissing("endTime", "org.apache.uima.tutorial.Meeting");
+    jcasType.ll_cas.ll_setRefValue(addr, ((Meeting_Type) jcasType).casFeatCode_endTime,
+            jcasType.ll_cas.ll_getFSRef(v));
+  }
+
+  /** Custom constructor taking all parameters */
+  public Meeting(JCas jcas, int start, int end, RoomNumber room, DateAnnot date,
+          TimeAnnot startTime, TimeAnnot endTime) {
+    this(jcas, start, end);
+    setRoom(room);
+    setDate(date);
+    setStartTime(startTime);
+    setEndTime(endTime);
+  }
+
+  public String toString() {
+    return "Meeting in " + getRoom().getCoveredText() + " on " + getDate().getCoveredText() + ", "
+            + getStartTime().getCoveredText() + " - " + getEndTime().getCoveredText();
+  }
+
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/Meeting_Type.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/Meeting_Type.java
new file mode 100644
index 0000000..0fe6d08
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/Meeting_Type.java
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.cas.Feature;
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.FSGenerator;
+import org.apache.uima.cas.impl.FeatureImpl;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.tcas.Annotation_Type;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004
+ * 
+ * @generated
+ */
+public class Meeting_Type extends Annotation_Type {
+  /** @generated */
+  protected FSGenerator getFSGenerator() {
+    return fsGenerator;
+  }
+
+  /** @generated */
+  private final FSGenerator fsGenerator = new FSGenerator() {
+    public FeatureStructure createFS(int addr, CASImpl cas) {
+      if (instanceOf_Type.useExistingInstance) {
+        // Return eq fs instance if already created
+        FeatureStructure fs = instanceOf_Type.jcas.getJfsFromCaddr(addr);
+        if (null == fs) {
+          fs = new Meeting(addr, instanceOf_Type);
+          instanceOf_Type.jcas.putJfsFromCaddr(addr, fs);
+          return fs;
+        }
+        return fs;
+      } else
+        return new Meeting(addr, instanceOf_Type);
+    }
+  };
+
+  /** @generated */
+  public final static int typeIndexID = Meeting.typeIndexID;
+
+  /**
+   * @generated
+   * @modifiable
+   */
+  public final static boolean featOkTst = JCasRegistry.getFeatOkTst("org.apache.uima.tutorial.Meeting");
+
+  /** @generated */
+  final Feature casFeat_room;
+
+  /** @generated */
+  final int casFeatCode_room;
+
+  /** @generated */
+  public int getRoom(int addr) {
+    if (featOkTst && casFeat_room == null)
+      this.jcas.throwFeatMissing("room", "org.apache.uima.tutorial.Meeting");
+    return ll_cas.ll_getRefValue(addr, casFeatCode_room);
+  }
+
+  /** @generated */
+  public void setRoom(int addr, int v) {
+    if (featOkTst && casFeat_room == null)
+      this.jcas.throwFeatMissing("room", "org.apache.uima.tutorial.Meeting");
+    ll_cas.ll_setRefValue(addr, casFeatCode_room, v);
+  }
+
+  /** @generated */
+  final Feature casFeat_date;
+
+  /** @generated */
+  final int casFeatCode_date;
+
+  /** @generated */
+  public int getDate(int addr) {
+    if (featOkTst && casFeat_date == null)
+      this.jcas.throwFeatMissing("date", "org.apache.uima.tutorial.Meeting");
+    return ll_cas.ll_getRefValue(addr, casFeatCode_date);
+  }
+
+  /** @generated */
+  public void setDate(int addr, int v) {
+    if (featOkTst && casFeat_date == null)
+      this.jcas.throwFeatMissing("date", "org.apache.uima.tutorial.Meeting");
+    ll_cas.ll_setRefValue(addr, casFeatCode_date, v);
+  }
+
+  /** @generated */
+  final Feature casFeat_startTime;
+
+  /** @generated */
+  final int casFeatCode_startTime;
+
+  /** @generated */
+  public int getStartTime(int addr) {
+    if (featOkTst && casFeat_startTime == null)
+      this.jcas.throwFeatMissing("startTime", "org.apache.uima.tutorial.Meeting");
+    return ll_cas.ll_getRefValue(addr, casFeatCode_startTime);
+  }
+
+  /** @generated */
+  public void setStartTime(int addr, int v) {
+    if (featOkTst && casFeat_startTime == null)
+      this.jcas.throwFeatMissing("startTime", "org.apache.uima.tutorial.Meeting");
+    ll_cas.ll_setRefValue(addr, casFeatCode_startTime, v);
+  }
+
+  /** @generated */
+  final Feature casFeat_endTime;
+
+  /** @generated */
+  final int casFeatCode_endTime;
+
+  /** @generated */
+  public int getEndTime(int addr) {
+    if (featOkTst && casFeat_endTime == null)
+      this.jcas.throwFeatMissing("endTime", "org.apache.uima.tutorial.Meeting");
+    return ll_cas.ll_getRefValue(addr, casFeatCode_endTime);
+  }
+
+  /** @generated */
+  public void setEndTime(int addr, int v) {
+    if (featOkTst && casFeat_endTime == null)
+      this.jcas.throwFeatMissing("endTime", "org.apache.uima.tutorial.Meeting");
+    ll_cas.ll_setRefValue(addr, casFeatCode_endTime, v);
+  }
+
+  /**
+   * initialize variables to correspond with Cas Type and Features
+   * 
+   * @generated
+   */
+  public Meeting_Type(JCas jcas, Type casType) {
+    super(jcas, casType);
+    casImpl.getFSClassRegistry().addGeneratorForType((TypeImpl) this.casType, getFSGenerator());
+
+    casFeat_room = jcas.getRequiredFeatureDE(casType, "room",
+            "org.apache.uima.tutorial.RoomNumber", featOkTst);
+    casFeatCode_room = (null == casFeat_room) ? JCas.INVALID_FEATURE_CODE
+            : ((FeatureImpl) casFeat_room).getCode();
+
+    casFeat_date = jcas.getRequiredFeatureDE(casType, "date", "org.apache.uima.tutorial.DateAnnot",
+            featOkTst);
+    casFeatCode_date = (null == casFeat_date) ? JCas.INVALID_FEATURE_CODE
+            : ((FeatureImpl) casFeat_date).getCode();
+
+    casFeat_startTime = jcas.getRequiredFeatureDE(casType, "startTime",
+            "org.apache.uima.tutorial.TimeAnnot", featOkTst);
+    casFeatCode_startTime = (null == casFeat_startTime) ? JCas.INVALID_FEATURE_CODE
+            : ((FeatureImpl) casFeat_startTime).getCode();
+
+    casFeat_endTime = jcas.getRequiredFeatureDE(casType, "endTime",
+            "org.apache.uima.tutorial.TimeAnnot", featOkTst);
+    casFeatCode_endTime = (null == casFeat_endTime) ? JCas.INVALID_FEATURE_CODE
+            : ((FeatureImpl) casFeat_endTime).getCode();
+
+  }
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/RoomNumber.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/RoomNumber.java
new file mode 100644
index 0000000..2ace78c
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/RoomNumber.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.cas.TOP_Type;
+import org.apache.uima.jcas.tcas.Annotation;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:37 EST 2004 XML source: C:/Program
+ * Files/apache/uima/examples/descriptors/tutorial/ex6/TutorialTypeSystem.xml
+ * 
+ * @generated
+ */
+public class RoomNumber extends Annotation {
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int typeIndexID = JCasRegistry.register(RoomNumber.class);
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int type = typeIndexID;
+
+  /** @generated */
+  public int getTypeIndexID() {
+    return typeIndexID;
+  }
+
+  /**
+   * Never called. Disable default constructor
+   * 
+   * @generated
+   */
+  protected RoomNumber() {
+  }
+
+  /**
+   * Internal - constructor used by generator
+   * 
+   * @generated
+   */
+  public RoomNumber(int addr, TOP_Type type) {
+    super(addr, type);
+    readObject();
+  }
+
+  /** @generated */
+  public RoomNumber(JCas jcas) {
+    super(jcas);
+    readObject();
+  }
+
+  public RoomNumber(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }
+
+  /**
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->
+   * 
+   * @generated modifiable
+   */
+  private void readObject() {
+  }
+
+  // *--------------*
+  // * Feature: building
+
+  /**
+   * getter for building - gets Building containing this room
+   * 
+   * @generated
+   */
+  public String getBuilding() {
+    if (RoomNumber_Type.featOkTst && ((RoomNumber_Type) jcasType).casFeat_building == null)
+      this.jcasType.jcas.throwFeatMissing("building", "org.apache.uima.tutorial.RoomNumber");
+    return jcasType.ll_cas.ll_getStringValue(addr,
+            ((RoomNumber_Type) jcasType).casFeatCode_building);
+  }
+
+  /**
+   * setter for building - sets Building containing this room
+   * 
+   * @generated
+   */
+  public void setBuilding(String v) {
+    if (RoomNumber_Type.featOkTst && ((RoomNumber_Type) jcasType).casFeat_building == null)
+      this.jcasType.jcas.throwFeatMissing("building", "org.apache.uima.tutorial.RoomNumber");
+    jcasType.ll_cas.ll_setStringValue(addr, ((RoomNumber_Type) jcasType).casFeatCode_building, v);
+  }
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/RoomNumber_Type.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/RoomNumber_Type.java
new file mode 100644
index 0000000..f8a897e
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/RoomNumber_Type.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.cas.Feature;
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.FSGenerator;
+import org.apache.uima.cas.impl.FeatureImpl;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.tcas.Annotation_Type;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:37 EST 2004
+ * 
+ * @generated
+ */
+public class RoomNumber_Type extends Annotation_Type {
+  /** @generated */
+  protected FSGenerator getFSGenerator() {
+    return fsGenerator;
+  }
+
+  /** @generated */
+  private final FSGenerator fsGenerator = new FSGenerator() {
+    public FeatureStructure createFS(int addr, CASImpl cas) {
+      if (instanceOf_Type.useExistingInstance) {
+        // Return eq fs instance if already created
+        FeatureStructure fs = instanceOf_Type.jcas.getJfsFromCaddr(addr);
+        if (null == fs) {
+          fs = new RoomNumber(addr, instanceOf_Type);
+          instanceOf_Type.jcas.putJfsFromCaddr(addr, fs);
+          return fs;
+        }
+        return fs;
+      } else
+        return new RoomNumber(addr, instanceOf_Type);
+    }
+  };
+
+  /** @generated */
+  public final static int typeIndexID = RoomNumber.typeIndexID;
+
+  /**
+   * @generated
+   * @modifiable
+   */
+  public final static boolean featOkTst = JCasRegistry.getFeatOkTst("org.apache.uima.tutorial.RoomNumber");
+
+  /** @generated */
+  final Feature casFeat_building;
+
+  /** @generated */
+  final int casFeatCode_building;
+
+  /** @generated */
+  public String getBuilding(int addr) {
+    if (featOkTst && casFeat_building == null)
+      this.jcas.throwFeatMissing("building", "org.apache.uima.tutorial.RoomNumber");
+    return ll_cas.ll_getStringValue(addr, casFeatCode_building);
+  }
+
+  /** @generated */
+  public void setBuilding(int addr, String v) {
+    if (featOkTst && casFeat_building == null)
+      this.jcas.throwFeatMissing("building", "org.apache.uima.tutorial.RoomNumber");
+    ll_cas.ll_setStringValue(addr, casFeatCode_building, v);
+  }
+
+  /**
+   * initialize variables to correspond with Cas Type and Features
+   * 
+   * @generated
+   */
+  public RoomNumber_Type(JCas jcas, Type casType) {
+    super(jcas, casType);
+    casImpl.getFSClassRegistry().addGeneratorForType((TypeImpl) this.casType, getFSGenerator());
+
+    casFeat_building = jcas.getRequiredFeatureDE(casType, "building", "uima.cas.String", featOkTst);
+    casFeatCode_building = (null == casFeat_building) ? JCas.INVALID_FEATURE_CODE
+            : ((FeatureImpl) casFeat_building).getCode();
+
+  }
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/SentenceAnnot.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/SentenceAnnot.java
new file mode 100644
index 0000000..1dc5ee6
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/SentenceAnnot.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.cas.TOP_Type;
+import org.apache.uima.jcas.tcas.Annotation;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:37 EST 2004 XML source: C:/Program
+ * Files/apache/uima/examples/descriptors/tutorial/ex6/TutorialTypeSystem.xml
+ * 
+ * @generated
+ */
+public class SentenceAnnot extends Annotation {
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int typeIndexID = JCasRegistry.register(SentenceAnnot.class);
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int type = typeIndexID;
+
+  /** @generated */
+  public int getTypeIndexID() {
+    return typeIndexID;
+  }
+
+  /**
+   * Never called. Disable default constructor
+   * 
+   * @generated
+   */
+  protected SentenceAnnot() {
+  }
+
+  /**
+   * Internal - constructor used by generator
+   * 
+   * @generated
+   */
+  public SentenceAnnot(int addr, TOP_Type type) {
+    super(addr, type);
+    readObject();
+  }
+
+  /** @generated */
+  public SentenceAnnot(JCas jcas) {
+    super(jcas);
+    readObject();
+  }
+
+  public SentenceAnnot(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }
+
+  /**
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->
+   * 
+   * @generated modifiable
+   */
+  private void readObject() {
+  }
+
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/SentenceAnnot_Type.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/SentenceAnnot_Type.java
new file mode 100644
index 0000000..09f5bab
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/SentenceAnnot_Type.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.FSGenerator;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.tcas.Annotation_Type;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:37 EST 2004
+ * 
+ * @generated
+ */
+public class SentenceAnnot_Type extends Annotation_Type {
+  /** @generated */
+  protected FSGenerator getFSGenerator() {
+    return fsGenerator;
+  }
+
+  /** @generated */
+  private final FSGenerator fsGenerator = new FSGenerator() {
+    public FeatureStructure createFS(int addr, CASImpl cas) {
+      if (instanceOf_Type.useExistingInstance) {
+        // Return eq fs instance if already created
+        FeatureStructure fs = instanceOf_Type.jcas.getJfsFromCaddr(addr);
+        if (null == fs) {
+          fs = new SentenceAnnot(addr, instanceOf_Type);
+          instanceOf_Type.jcas.putJfsFromCaddr(addr, fs);
+          return fs;
+        }
+        return fs;
+      } else
+        return new SentenceAnnot(addr, instanceOf_Type);
+    }
+  };
+
+  /** @generated */
+  public final static int typeIndexID = SentenceAnnot.typeIndexID;
+
+  /**
+   * @generated
+   * @modifiable
+   */
+  public final static boolean featOkTst = JCasRegistry.getFeatOkTst("org.apache.uima.tutorial.SentenceAnnot");
+
+  /**
+   * initialize variables to correspond with Cas Type and Features
+   * 
+   * @generated
+   */
+  public SentenceAnnot_Type(JCas jcas, Type casType) {
+    super(jcas, casType);
+    casImpl.getFSClassRegistry().addGeneratorForType((TypeImpl) this.casType, getFSGenerator());
+
+  }
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/TimeAnnot.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/TimeAnnot.java
new file mode 100644
index 0000000..5778487
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/TimeAnnot.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.cas.TOP_Type;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004 XML source: C:/Program
+ * Files/apache/uima/examples/descriptors/tutorial/ex6/TutorialTypeSystem.xml
+ * 
+ * @generated
+ */
+public class TimeAnnot extends DateTimeAnnot {
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int typeIndexID = JCasRegistry.register(TimeAnnot.class);
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int type = typeIndexID;
+
+  /** @generated */
+  public int getTypeIndexID() {
+    return typeIndexID;
+  }
+
+  /**
+   * Never called. Disable default constructor
+   * 
+   * @generated
+   */
+  protected TimeAnnot() {
+  }
+
+  /**
+   * Internal - constructor used by generator
+   * 
+   * @generated
+   */
+  public TimeAnnot(int addr, TOP_Type type) {
+    super(addr, type);
+    readObject();
+  }
+
+  /** @generated */
+  public TimeAnnot(JCas jcas) {
+    super(jcas);
+    readObject();
+  }
+
+  public TimeAnnot(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }
+
+  /**
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->
+   * 
+   * @generated modifiable
+   */
+  private void readObject() {
+  }
+
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/TimeAnnot_Type.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/TimeAnnot_Type.java
new file mode 100644
index 0000000..3d94a05
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/TimeAnnot_Type.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.FSGenerator;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004
+ * 
+ * @generated
+ */
+public class TimeAnnot_Type extends DateTimeAnnot_Type {
+  /** @generated */
+  protected FSGenerator getFSGenerator() {
+    return fsGenerator;
+  }
+
+  /** @generated */
+  private final FSGenerator fsGenerator = new FSGenerator() {
+    public FeatureStructure createFS(int addr, CASImpl cas) {
+      if (instanceOf_Type.useExistingInstance) {
+        // Return eq fs instance if already created
+        FeatureStructure fs = instanceOf_Type.jcas.getJfsFromCaddr(addr);
+        if (null == fs) {
+          fs = new TimeAnnot(addr, instanceOf_Type);
+          instanceOf_Type.jcas.putJfsFromCaddr(addr, fs);
+          return fs;
+        }
+        return fs;
+      } else
+        return new TimeAnnot(addr, instanceOf_Type);
+    }
+  };
+
+  /** @generated */
+  public final static int typeIndexID = TimeAnnot.typeIndexID;
+
+  /**
+   * @generated
+   * @modifiable
+   */
+  public final static boolean featOkTst = JCasRegistry.getFeatOkTst("org.apache.uima.tutorial.TimeAnnot");
+
+  /**
+   * initialize variables to correspond with Cas Type and Features
+   * 
+   * @generated
+   */
+  public TimeAnnot_Type(JCas jcas, Type casType) {
+    super(jcas, casType);
+    casImpl.getFSClassRegistry().addGeneratorForType((TypeImpl) this.casType, getFSGenerator());
+
+  }
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/UimaAcronym.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/UimaAcronym.java
new file mode 100644
index 0000000..9f8adcf
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/UimaAcronym.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.cas.TOP_Type;
+import org.apache.uima.jcas.tcas.Annotation;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004 XML source: C:/Program
+ * Files/apache/uima/examples/descriptors/tutorial/ex6/TutorialTypeSystem.xml
+ * 
+ * @generated
+ */
+public class UimaAcronym extends Annotation {
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int typeIndexID = JCasRegistry.register(UimaAcronym.class);
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int type = typeIndexID;
+
+  /** @generated */
+  public int getTypeIndexID() {
+    return typeIndexID;
+  }
+
+  /**
+   * Never called. Disable default constructor
+   * 
+   * @generated
+   */
+  protected UimaAcronym() {
+  }
+
+  /**
+   * Internal - constructor used by generator
+   * 
+   * @generated
+   */
+  public UimaAcronym(int addr, TOP_Type type) {
+    super(addr, type);
+    readObject();
+  }
+
+  /** @generated */
+  public UimaAcronym(JCas jcas) {
+    super(jcas);
+    readObject();
+  }
+
+  public UimaAcronym(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }
+
+  /**
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->
+   * 
+   * @generated modifiable
+   */
+  private void readObject() {
+  }
+
+  // *--------------*
+  // * Feature: expandedForm
+
+  /**
+   * getter for expandedForm - gets
+   * 
+   * @generated
+   */
+  public String getExpandedForm() {
+    if (UimaAcronym_Type.featOkTst && ((UimaAcronym_Type) jcasType).casFeat_expandedForm == null)
+      this.jcasType.jcas.throwFeatMissing("expandedForm", "org.apache.uima.tutorial.UimaAcronym");
+    return jcasType.ll_cas.ll_getStringValue(addr,
+            ((UimaAcronym_Type) jcasType).casFeatCode_expandedForm);
+  }
+
+  /**
+   * setter for expandedForm - sets
+   * 
+   * @generated
+   */
+  public void setExpandedForm(String v) {
+    if (UimaAcronym_Type.featOkTst && ((UimaAcronym_Type) jcasType).casFeat_expandedForm == null)
+      this.jcasType.jcas.throwFeatMissing("expandedForm", "org.apache.uima.tutorial.UimaAcronym");
+    jcasType.ll_cas.ll_setStringValue(addr, ((UimaAcronym_Type) jcasType).casFeatCode_expandedForm,
+            v);
+  }
+
+  /** Custom constructor taking all parameters */
+  public UimaAcronym(JCas jcas, int start, int end, String expandedForm) {
+    super(jcas, start, end);
+    setExpandedForm(expandedForm);
+  }
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/UimaAcronym_Type.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/UimaAcronym_Type.java
new file mode 100644
index 0000000..4d38d22
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/UimaAcronym_Type.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.cas.Feature;
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.FSGenerator;
+import org.apache.uima.cas.impl.FeatureImpl;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.tcas.Annotation_Type;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004
+ * 
+ * @generated
+ */
+public class UimaAcronym_Type extends Annotation_Type {
+  /** @generated */
+  protected FSGenerator getFSGenerator() {
+    return fsGenerator;
+  }
+
+  /** @generated */
+  private final FSGenerator fsGenerator = new FSGenerator() {
+    public FeatureStructure createFS(int addr, CASImpl cas) {
+      if (instanceOf_Type.useExistingInstance) {
+        // Return eq fs instance if already created
+        FeatureStructure fs = instanceOf_Type.jcas.getJfsFromCaddr(addr);
+        if (null == fs) {
+          fs = new UimaAcronym(addr, instanceOf_Type);
+          instanceOf_Type.jcas.putJfsFromCaddr(addr, fs);
+          return fs;
+        }
+        return fs;
+      } else
+        return new UimaAcronym(addr, instanceOf_Type);
+    }
+  };
+
+  /** @generated */
+  public final static int typeIndexID = UimaAcronym.typeIndexID;
+
+  /**
+   * @generated
+   * @modifiable
+   */
+  public final static boolean featOkTst = JCasRegistry.getFeatOkTst("org.apache.uima.tutorial.UimaAcronym");
+
+  /** @generated */
+  final Feature casFeat_expandedForm;
+
+  /** @generated */
+  final int casFeatCode_expandedForm;
+
+  /** @generated */
+  public String getExpandedForm(int addr) {
+    if (featOkTst && casFeat_expandedForm == null)
+      this.jcas.throwFeatMissing("expandedForm", "org.apache.uima.tutorial.UimaAcronym");
+    return ll_cas.ll_getStringValue(addr, casFeatCode_expandedForm);
+  }
+
+  /** @generated */
+  public void setExpandedForm(int addr, String v) {
+    if (featOkTst && casFeat_expandedForm == null)
+      this.jcas.throwFeatMissing("expandedForm", "org.apache.uima.tutorial.UimaAcronym");
+    ll_cas.ll_setStringValue(addr, casFeatCode_expandedForm, v);
+  }
+
+  /**
+   * initialize variables to correspond with Cas Type and Features
+   * 
+   * @generated
+   */
+  public UimaAcronym_Type(JCas jcas, Type casType) {
+    super(jcas, casType);
+    casImpl.getFSClassRegistry().addGeneratorForType((TypeImpl) this.casType, getFSGenerator());
+
+    casFeat_expandedForm = jcas.getRequiredFeatureDE(casType, "expandedForm", "uima.cas.String",
+            featOkTst);
+    casFeatCode_expandedForm = (null == casFeat_expandedForm) ? JCas.INVALID_FEATURE_CODE
+            : ((FeatureImpl) casFeat_expandedForm).getCode();
+
+  }
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/UimaMeeting.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/UimaMeeting.java
new file mode 100644
index 0000000..3643724
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/UimaMeeting.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.cas.TOP_Type;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004 XML source: C:/Program
+ * Files/apache/uima/examples/descriptors/tutorial/ex6/TutorialTypeSystem.xml
+ * 
+ * @generated
+ */
+public class UimaMeeting extends Meeting {
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int typeIndexID = JCasRegistry.register(UimaMeeting.class);
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int type = typeIndexID;
+
+  /** @generated */
+  public int getTypeIndexID() {
+    return typeIndexID;
+  }
+
+  /**
+   * Never called. Disable default constructor
+   * 
+   * @generated
+   */
+  protected UimaMeeting() {
+  }
+
+  /**
+   * Internal - constructor used by generator
+   * 
+   * @generated
+   */
+  public UimaMeeting(int addr, TOP_Type type) {
+    super(addr, type);
+    readObject();
+  }
+
+  /** @generated */
+  public UimaMeeting(JCas jcas) {
+    super(jcas);
+    readObject();
+  }
+
+  public UimaMeeting(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }
+
+  /**
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->
+   * 
+   * @generated modifiable
+   */
+  private void readObject() {
+  }
+
+  /** Custom constructor taking all parameters */
+  public UimaMeeting(JCas jcas, int start, int end, RoomNumber room, DateAnnot date,
+          TimeAnnot startTime, TimeAnnot endTime) {
+    super(jcas, start, end, room, date, startTime, endTime);
+  }
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/UimaMeeting_Type.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/UimaMeeting_Type.java
new file mode 100644
index 0000000..a59cd1f
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/UimaMeeting_Type.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.FSGenerator;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004
+ * 
+ * @generated
+ */
+public class UimaMeeting_Type extends Meeting_Type {
+  /** @generated */
+  protected FSGenerator getFSGenerator() {
+    return fsGenerator;
+  }
+
+  /** @generated */
+  private final FSGenerator fsGenerator = new FSGenerator() {
+    public FeatureStructure createFS(int addr, CASImpl cas) {
+      if (instanceOf_Type.useExistingInstance) {
+        // Return eq fs instance if already created
+        FeatureStructure fs = instanceOf_Type.jcas.getJfsFromCaddr(addr);
+        if (null == fs) {
+          fs = new UimaMeeting(addr, instanceOf_Type);
+          instanceOf_Type.jcas.putJfsFromCaddr(addr, fs);
+          return fs;
+        }
+        return fs;
+      } else
+        return new UimaMeeting(addr, instanceOf_Type);
+    }
+  };
+
+  /** @generated */
+  public final static int typeIndexID = UimaMeeting.typeIndexID;
+
+  /**
+   * @generated
+   * @modifiable
+   */
+  public final static boolean featOkTst = JCasRegistry.getFeatOkTst("org.apache.uima.tutorial.UimaMeeting");
+
+  /**
+   * initialize variables to correspond with Cas Type and Features
+   * 
+   * @generated
+   */
+  public UimaMeeting_Type(JCas jcas, Type casType) {
+    super(jcas, casType);
+    casImpl.getFSClassRegistry().addGeneratorForType((TypeImpl) this.casType, getFSGenerator());
+
+  }
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/WordAnnot.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/WordAnnot.java
new file mode 100644
index 0000000..1abb8f7
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/WordAnnot.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.cas.TOP_Type;
+import org.apache.uima.jcas.tcas.Annotation;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004 XML source: C:/Program
+ * Files/apache/uima/examples/descriptors/tutorial/ex6/TutorialTypeSystem.xml
+ * 
+ * @generated
+ */
+public class WordAnnot extends Annotation {
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int typeIndexID = JCasRegistry.register(WordAnnot.class);
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int type = typeIndexID;
+
+  /** @generated */
+  public int getTypeIndexID() {
+    return typeIndexID;
+  }
+
+  /**
+   * Never called. Disable default constructor
+   * 
+   * @generated
+   */
+  protected WordAnnot() {
+  }
+
+  /**
+   * Internal - constructor used by generator
+   * 
+   * @generated
+   */
+  public WordAnnot(int addr, TOP_Type type) {
+    super(addr, type);
+    readObject();
+  }
+
+  /** @generated */
+  public WordAnnot(JCas jcas) {
+    super(jcas);
+    readObject();
+  }
+
+  public WordAnnot(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }
+
+  /**
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->
+   * 
+   * @generated modifiable
+   */
+  private void readObject() {
+  }
+
+}
diff --git a/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/WordAnnot_Type.java b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/WordAnnot_Type.java
new file mode 100644
index 0000000..60092b2
--- /dev/null
+++ b/uimaj-v3migration-jcas/src/test/v2_jcas_sources/org/apache/uima/tutorial/WordAnnot_Type.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.uima.tutorial;
+
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.FSGenerator;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.tcas.Annotation_Type;
+
+/**
+ * Updated by JCasGen Mon Nov 29 15:02:38 EST 2004
+ * 
+ * @generated
+ */
+public class WordAnnot_Type extends Annotation_Type {
+  /** @generated */
+  protected FSGenerator getFSGenerator() {
+    return fsGenerator;
+  }
+
+  /** @generated */
+  private final FSGenerator fsGenerator = new FSGenerator() {
+    public FeatureStructure createFS(int addr, CASImpl cas) {
+      if (instanceOf_Type.useExistingInstance) {
+        // Return eq fs instance if already created
+        FeatureStructure fs = instanceOf_Type.jcas.getJfsFromCaddr(addr);
+        if (null == fs) {
+          fs = new WordAnnot(addr, instanceOf_Type);
+          instanceOf_Type.jcas.putJfsFromCaddr(addr, fs);
+          return fs;
+        }
+        return fs;
+      } else
+        return new WordAnnot(addr, instanceOf_Type);
+    }
+  };
+
+  /** @generated */
+  public final static int typeIndexID = WordAnnot.typeIndexID;
+
+  /**
+   * @generated
+   * @modifiable
+   */
+  public final static boolean featOkTst = JCasRegistry.getFeatOkTst("org.apache.uima.tutorial.WordAnnot");
+
+  /**
+   * initialize variables to correspond with Cas Type and Features
+   * 
+   * @generated
+   */
+  public WordAnnot_Type(JCas jcas, Type casType) {
+    super(jcas, casType);
+    casImpl.getFSClassRegistry().addGeneratorForType((TypeImpl) this.casType, getFSGenerator());
+
+  }
+}
diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSListIteratorImpl.java b/unused-saved/src/org/apache/uima/cas/impl/FSListIteratorImpl.java
similarity index 99%
rename from uimaj-core/src/main/java/org/apache/uima/cas/impl/FSListIteratorImpl.java
rename to unused-saved/src/org/apache/uima/cas/impl/FSListIteratorImpl.java
index cffacb8..ed9e1e3 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSListIteratorImpl.java
+++ b/unused-saved/src/org/apache/uima/cas/impl/FSListIteratorImpl.java
@@ -1,161 +1,161 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.uima.cas.impl;
-
-import java.util.ListIterator;
-import java.util.NoSuchElementException;
-
-import org.apache.uima.cas.FSIterator;
-import org.apache.uima.cas.FeatureStructure;
-
-/**
- * Class comment for FSListIteratorImpl.java goes here.
- * 
- * 
- */
-class FSListIteratorImpl<T extends FeatureStructure> implements ListIterator<T> {
-
-  // Keep two pointers: one for the next element, and one for the previous
-  // one. The two pointers are always moved in lockstep. Watch for border
-  // conditions where only one of the pointers is valid.
-  private FSIterator<T> forward;
-
-  private FSIterator<T> back;
-
-  public FSListIteratorImpl(FSIterator<T> it) {
-    super();
-    this.forward = it;
-    this.back = it.copy();
-    it.moveToPrevious();
-  }
-
-  /**
-   * @see ListIterator#hasNext()
-   */
-  public boolean hasNext() {
-    return this.forward.isValid();
-  }
-
-  /**
-   * @see ListIterator#hasPrevious()
-   */
-  public boolean hasPrevious() {
-    return this.back.isValid();
-  }
-
-  /**
-   * Move the iterator so that the next call to {@link #previous() previous()} will return the first
-   * element in the index (for a non-empty index).
-   */
-  public void moveToEnd() {
-    // Move the back pointer to point at the last element.
-    this.back.moveToLast();
-    // Move the forward pointer past the end.
-    this.forward.moveToLast();
-    this.forward.moveToNext();
-  }
-
-  /**
-   * Move the iterator so that the next call to {@link #next() next()} will return the first element
-   * in the index (for a non-empty index).
-   */
-  public void moveToStart() {
-    // Move the forward pointer to the start.
-    this.forward.moveToFirst();
-    // Move the back pointer past the start.
-    this.back.moveToFirst();
-    this.back.moveToPrevious();
-  }
-
-  /**
-   * @see ListIterator#next()
-   */
-  public T next() throws NoSuchElementException {
-    // Throw exception if forward pointer is invalid.
-    if (!this.forward.isValid()) {
-      throw new NoSuchElementException();
-    }
-    // Move the forward pointer.
-    this.forward.moveToNext();
-    // Move the backward pointer. Need to check if it's valid.
-    if (this.back.isValid()) {
-      this.back.moveToNext();
-    } else {
-      // This is guaranteed to yield a valid pointer, since otherwise, the
-      // forward pointer couldn't have been valid.
-      this.back.moveToFirst();
-    }
-    // The back pointer is now pointing at the current forward element.
-    return this.back.get();
-  }
-
-  /**
-   * @see ListIterator#previous()
-   */
-  public T previous() throws NoSuchElementException {
-    // See comments for next().
-    if (!this.back.isValid()) {
-      throw new NoSuchElementException();
-    }
-    this.back.moveToPrevious();
-    if (this.forward.isValid()) {
-      this.forward.moveToPrevious();
-    } else {
-      this.forward.moveToLast();
-    }
-    return this.forward.get();
-  }
-
-  /**
-   * @see java.util.ListIterator#add(Object)
-   */
-  public void add(T o) {
-    throw new UnsupportedOperationException();
-  }
-
-  /**
-   * @see java.util.ListIterator#nextIndex()
-   */
-  public int nextIndex() {
-    throw new UnsupportedOperationException();
-  }
-
-  /**
-   * @see java.util.ListIterator#previousIndex()
-   */
-  public int previousIndex() {
-    throw new UnsupportedOperationException();
-  }
-
-  /**
-   * @see java.util.Iterator#remove()
-   */
-  public void remove() {
-    throw new UnsupportedOperationException();
-  }
-
-  /**
-   * @see java.util.ListIterator#set(T)
-   */
-  public void set(T o) {
-    throw new UnsupportedOperationException();
-  }
-
-}
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.cas.impl;

+

+import java.util.ListIterator;

+import java.util.NoSuchElementException;

+

+import org.apache.uima.cas.FSIterator;

+import org.apache.uima.cas.FeatureStructure;

+

+/**

+ * Class comment for FSListIteratorImpl.java goes here.

+ * 

+ * 

+ */

+class FSListIteratorImpl<T extends FeatureStructure> implements ListIterator<T> {

+

+  // Keep two pointers: one for the next element, and one for the previous

+  // one. The two pointers are always moved in lockstep. Watch for border

+  // conditions where only one of the pointers is valid.

+  private FSIterator<T> forward;

+

+  private FSIterator<T> back;

+

+  public FSListIteratorImpl(FSIterator<T> it) {

+    super();

+    this.forward = it;

+    this.back = it.copy();

+    it.moveToPrevious();

+  }

+

+  /**

+   * @see ListIterator#hasNext()

+   */

+  public boolean hasNext() {

+    return this.forward.isValid();

+  }

+

+  /**

+   * @see ListIterator#hasPrevious()

+   */

+  public boolean hasPrevious() {

+    return this.back.isValid();

+  }

+

+  /**

+   * Move the iterator so that the next call to {@link #previous() previous()} will return the first

+   * element in the index (for a non-empty index).

+   */

+  public void moveToEnd() {

+    // Move the back pointer to point at the last element.

+    this.back.moveToLast();

+    // Move the forward pointer past the end.

+    this.forward.moveToLast();

+    this.forward.moveToNext();

+  }

+

+  /**

+   * Move the iterator so that the next call to {@link #next() next()} will return the first element

+   * in the index (for a non-empty index).

+   */

+  public void moveToStart() {

+    // Move the forward pointer to the start.

+    this.forward.moveToFirst();

+    // Move the back pointer past the start.

+    this.back.moveToFirst();

+    this.back.moveToPrevious();

+  }

+

+  /**

+   * @see ListIterator#next()

+   */

+  public T next() throws NoSuchElementException {

+    // Throw exception if forward pointer is invalid.

+    if (!this.forward.isValid()) {

+      throw new NoSuchElementException();

+    }

+    // Move the forward pointer.

+    this.forward.moveToNext();

+    // Move the backward pointer. Need to check if it's valid.

+    if (this.back.isValid()) {

+      this.back.moveToNext();

+    } else {

+      // This is guaranteed to yield a valid pointer, since otherwise, the

+      // forward pointer couldn't have been valid.

+      this.back.moveToFirst();

+    }

+    // The back pointer is now pointing at the current forward element.

+    return this.back.get();

+  }

+

+  /**

+   * @see ListIterator#previous()

+   */

+  public T previous() throws NoSuchElementException {

+    // See comments for next().

+    if (!this.back.isValid()) {

+      throw new NoSuchElementException();

+    }

+    this.back.moveToPrevious();

+    if (this.forward.isValid()) {

+      this.forward.moveToPrevious();

+    } else {

+      this.forward.moveToLast();

+    }

+    return this.forward.get();

+  }

+

+  /**

+   * @see java.util.ListIterator#add(Object)

+   */

+  public void add(T o) {

+    throw new UnsupportedOperationException();

+  }

+

+  /**

+   * @see java.util.ListIterator#nextIndex()

+   */

+  public int nextIndex() {

+    throw new UnsupportedOperationException();

+  }

+

+  /**

+   * @see java.util.ListIterator#previousIndex()

+   */

+  public int previousIndex() {

+    throw new UnsupportedOperationException();

+  }

+

+  /**

+   * @see java.util.Iterator#remove()

+   */

+  public void remove() {

+    throw new UnsupportedOperationException();

+  }

+

+  /**

+   * @see java.util.ListIterator#set(T)

+   */

+  public void set(T o) {

+    throw new UnsupportedOperationException();

+  }

+

+}

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSRBTIndex.java b/unused-saved/src/org/apache/uima/cas/impl/FSRBTIndex.java
similarity index 99%
rename from uimaj-core/src/main/java/org/apache/uima/cas/impl/FSRBTIndex.java
rename to unused-saved/src/org/apache/uima/cas/impl/FSRBTIndex.java
index 80e1d8d..1fda498 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSRBTIndex.java
+++ b/unused-saved/src/org/apache/uima/cas/impl/FSRBTIndex.java
@@ -1,151 +1,151 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-//package org.apache.uima.cas.impl;
-//
-//import org.apache.uima.cas.FeatureStructure;
-//import org.apache.uima.cas.Type;
-//import org.apache.uima.cas.admin.FSIndexComparator;
-//import org.apache.uima.internal.util.ComparableIntIterator;
-//import org.apache.uima.internal.util.ComparableIntPointerIterator;
-//import org.apache.uima.internal.util.IntComparator;
-//import org.apache.uima.internal.util.IntPointerIterator;
-//import org.apache.uima.internal.util.IntVector;
-//import org.apache.uima.internal.util.rb_trees.CompIntArrayRBT;
-//
-///**
-// * Class comment for FSRBTIndex.java goes here.
-// * 
-// * 
-// */
-//// TODO: may not be used - no refs to it on 6-2006
-//class FSRBTIndex<T extends FeatureStructure> extends FSLeafIndexImpl<T> {
-//
-//  private CompIntArrayRBT tree;
-//
-//  /**
-//   * Constructor for FSRBTIndex.
-//   * 
-//   * @param cas
-//   */
-//  public FSRBTIndex(CASImpl cas, Type type, int indexType) {
-//    super(cas, type, indexType);
-//    // We can only initialize the tree after we got the comparator.
-//    this.tree = null;
-//  }
-//
-//  boolean init(FSIndexComparator comp) {
-//    boolean rc = super.init(comp);
-//    this.tree = new CompIntArrayRBT(this);
-//    return rc;
-//  }
-//
-//  public void flush() {
-//    this.tree.flush();
-//  }
-//
-//  /**
-//   * @see org.apache.uima.cas.impl.FSLeafIndexImpl#insert(int)
-//   */
-//  boolean insert(int fs) {
-//    this.tree.insertKeyWithDups(fs);
-//    return true;
-//  }
-//
-//  public IntPointerIterator refIterator() {
-//    return this.tree.pointerIterator();
-//  }
-//
-//  ComparableIntIterator refIterator(IntComparator comp) {
-//    return this.tree.iterator(comp);
-//  }
-//
-//  public ComparableIntPointerIterator pointerIterator(IntComparator comp,
-//          int[] detectIllegalIndexUpdates, int typeCode) {
-//    return this.tree.pointerIterator(comp, detectIllegalIndexUpdates, typeCode);
-//  }
-//
-//  /**
-//   * @see org.apache.uima.cas.impl.FSLeafIndexImpl#refIterator(int)
-//   */
-//  protected IntPointerIterator refIterator(int fsCode) {
-//    return this.tree.pointerIterator(fsCode);
-//  }
-//
-//  /**
-//   * @see org.apache.uima.cas.FSIndex#contains(FeatureStructure)
-//   */
-//  public boolean contains(FeatureStructure fs) {
-//    return this.tree.containsKey(((FeatureStructureImpl) fs).getAddress());
-//  }
-//
-//  public FeatureStructure find(FeatureStructure fs) {
-//    final FeatureStructureImpl fsi = (FeatureStructureImpl) fs;
-//    final int resultAddr = this.tree.getKeyForNode(this.tree.findKey(fsi.getAddress()));
-//    if (resultAddr > 0) {
-//      return fsi.getCASImpl().createFS(resultAddr);
-//    }
-//    return null;
-//  }
-//
-//  /**
-//   * @see org.apache.uima.cas.FSIndex#size()
-//   */
-//  public int size() {
-//    return this.tree.size();
-//  }
-//
-//  /**
-//   * @see org.apache.uima.cas.impl.FSLeafIndexImpl#deleteFS(org.apache.uima.cas.FeatureStructure)
-//   */
-//  public void deleteFS(FeatureStructure fs) {
-//    final int addr = ((FeatureStructureImpl) fs).getAddress();
-//    this.tree.deleteKey(addr);
-//  }
-//
-//  /*
-//   * (non-Javadoc)
-//   * 
-//   * @see org.apache.uima.cas.impl.LowLevelIndex#ll_iterator()
-//   */
-//  public LowLevelIterator ll_iterator() {
-//    return new LowLevelIteratorWrapper(this.tree.pointerIterator(), this);
-//  }
-//
-//  /*
-//   * (non-Javadoc)
-//   * 
-//   * @see org.apache.uima.cas.impl.FSLeafIndexImpl#remove(int)
-//   */
-//  @Override
-//  boolean remove(int fs) {
-//    return this.tree.deleteKey(fs);
-//  }
-//
-//  @Override
-//  boolean insert(int fs, int count) {
-//    throw new UnsupportedOperationException();
-//  }
-//
-//  @Override
-//  protected void bulkAddTo(IntVector v) {
-//    throw new UnsupportedOperationException();
-//  }
-//
-//}
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+//package org.apache.uima.cas.impl;

+//

+//import org.apache.uima.cas.FeatureStructure;

+//import org.apache.uima.cas.Type;

+//import org.apache.uima.cas.admin.FSIndexComparator;

+//import org.apache.uima.internal.util.ComparableIntIterator;

+//import org.apache.uima.internal.util.ComparableIntPointerIterator;

+//import org.apache.uima.internal.util.IntComparator;

+//import org.apache.uima.internal.util.IntPointerIterator;

+//import org.apache.uima.internal.util.IntVector;

+//import org.apache.uima.internal.util.rb_trees.CompIntArrayRBT;

+//

+///**

+// * Class comment for FSRBTIndex.java goes here.

+// * 

+// * 

+// */

+//// TODO: may not be used - no refs to it on 6-2006

+//class FSRBTIndex<T extends FeatureStructure> extends FSLeafIndexImpl<T> {

+//

+//  private CompIntArrayRBT tree;

+//

+//  /**

+//   * Constructor for FSRBTIndex.

+//   * 

+//   * @param cas

+//   */

+//  public FSRBTIndex(CASImpl cas, Type type, int indexType) {

+//    super(cas, type, indexType);

+//    // We can only initialize the tree after we got the comparator.

+//    this.tree = null;

+//  }

+//

+//  boolean init(FSIndexComparator comp) {

+//    boolean rc = super.init(comp);

+//    this.tree = new CompIntArrayRBT(this);

+//    return rc;

+//  }

+//

+//  public void flush() {

+//    this.tree.flush();

+//  }

+//

+//  /**

+//   * @see org.apache.uima.cas.impl.FSLeafIndexImpl#insert(int)

+//   */

+//  boolean insert(int fs) {

+//    this.tree.insertKeyWithDups(fs);

+//    return true;

+//  }

+//

+//  public IntPointerIterator refIterator() {

+//    return this.tree.pointerIterator();

+//  }

+//

+//  ComparableIntIterator refIterator(IntComparator comp) {

+//    return this.tree.iterator(comp);

+//  }

+//

+//  public ComparableIntPointerIterator pointerIterator(IntComparator comp,

+//          int[] detectIllegalIndexUpdates, int typeCode) {

+//    return this.tree.pointerIterator(comp, detectIllegalIndexUpdates, typeCode);

+//  }

+//

+//  /**

+//   * @see org.apache.uima.cas.impl.FSLeafIndexImpl#refIterator(int)

+//   */

+//  protected IntPointerIterator refIterator(int fsCode) {

+//    return this.tree.pointerIterator(fsCode);

+//  }

+//

+//  /**

+//   * @see org.apache.uima.cas.FSIndex#contains(FeatureStructure)

+//   */

+//  public boolean contains(FeatureStructure fs) {

+//    return this.tree.containsKey(((FeatureStructureImpl) fs).getAddress());

+//  }

+//

+//  public FeatureStructure find(FeatureStructure fs) {

+//    final FeatureStructureImpl fsi = (FeatureStructureImpl) fs;

+//    final int resultAddr = this.tree.getKeyForNode(this.tree.findKey(fsi.getAddress()));

+//    if (resultAddr > 0) {

+//      return fsi.getCASImpl().createFS(resultAddr);

+//    }

+//    return null;

+//  }

+//

+//  /**

+//   * @see org.apache.uima.cas.FSIndex#size()

+//   */

+//  public int size() {

+//    return this.tree.size();

+//  }

+//

+//  /**

+//   * @see org.apache.uima.cas.impl.FSLeafIndexImpl#deleteFS(org.apache.uima.cas.FeatureStructure)

+//   */

+//  public void deleteFS(FeatureStructure fs) {

+//    final int addr = ((FeatureStructureImpl) fs).getAddress();

+//    this.tree.deleteKey(addr);

+//  }

+//

+//  /*

+//   * (non-Javadoc)

+//   * 

+//   * @see org.apache.uima.cas.impl.LowLevelIndex#ll_iterator()

+//   */

+//  public LowLevelIterator ll_iterator() {

+//    return new LowLevelIteratorWrapper(this.tree.pointerIterator(), this);

+//  }

+//

+//  /*

+//   * (non-Javadoc)

+//   * 

+//   * @see org.apache.uima.cas.impl.FSLeafIndexImpl#remove(int)

+//   */

+//  @Override

+//  boolean remove(int fs) {

+//    return this.tree.deleteKey(fs);

+//  }

+//

+//  @Override

+//  boolean insert(int fs, int count) {

+//    throw new UnsupportedOperationException();

+//  }

+//

+//  @Override

+//  protected void bulkAddTo(IntVector v) {

+//    throw new UnsupportedOperationException();

+//  }

+//

+//}

diff --git a/unused-saved/src/org/apache/uima/cas/impl/FsIndex_aggr.java b/unused-saved/src/org/apache/uima/cas/impl/FsIndex_aggr.java
new file mode 100644
index 0000000..08af34c
--- /dev/null
+++ b/unused-saved/src/org/apache/uima/cas/impl/FsIndex_aggr.java
@@ -0,0 +1,233 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ * 

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.uima.cas.impl;

+

+import java.util.ArrayList;

+import java.util.Arrays;

+import java.util.Comparator;

+import java.util.stream.Stream;

+

+import org.apache.uima.cas.FSIndex;

+import org.apache.uima.cas.FeatureStructure;

+import org.apache.uima.cas.Type;

+import org.apache.uima.cas.admin.FSIndexComparator;

+import org.apache.uima.jcas.cas.TOP;

+

+/**

+ * FsIndex_aggr supports iterators over various aggregations of other iterators involving multiple indexes

+ *   examples: iterate over all views

+ *             iterate over all FSs in a view

+ *             iterate over an index + all of its sub-indexes (iicp)

+ * 

+ * compareTo() is delegatedbased on types and the comparator of the index.

+ * 

+ * T is the Java cover class of the top type (root) in the index set

+ * 

+ * Also includes a lazily initialized reference to a corresponding FSIndexFlat instance.

+ * 

+ * This class is package private to share with FSIndexFlat

+ * For Internal Use

+ */  

+class FsIndex_aggr<T extends FeatureStructure> 

+          implements Comparator<FeatureStructure>,

+                     LowLevelIndex<T> {

+

+//  private final static boolean DEBUG = false;

+

+//  final FSIndexRepositoryImpl fsIndexRepositoryImpl;

+  

+  /**

+   * A list of indexes that make up the aggregate 

+   * 

+   * This is set up lazily on first need, to avoid extra work when won't be accessed

+   */

+  final private LowLevelIndex<T>[] indexes;

+      

+  FsIndex_aggr(LowLevelIndex<T>[] indexes) {

+    this.indexes = indexes;    

+  }

+

+  @Override

+  public String toString() {

+    StringBuilder sb = new StringBuilder(this.getClass().getSimpleName()).append(", indexes=");

+    for (FSIndex idx : indexes) {

+      sb.append("\n   ").append(idx.toString());

+    }

+    return sb.toString();

+  }

+  

+  /**

+   * Two iicps are equal if and only if:

+   *   - the types they index are the same, and

+   *   - the comparators are equal, and

+   *   - the indexing stragtegy (bag/set/sorted) are the same

+   * Used when creating the index iterator cache to select from the

+   *   set of all instances of these the one that goes with the same index definition

+   * Used by CasComplete serialization to merge multiple index names referring to the same index  

+   */

+  @Override

+  public boolean equals(Object o) {

+    if (!(o instanceof FsIndex_aggr)) {

+      return false;

+    }

+    final FsIndex_aggr<?> idx = (FsIndex_aggr<?>) o;

+    return Arrays.equals(indexes, idx.indexes);

+  }

+

+// Implement a hashCode; 

+// previously tried just throwing an exception, but if the hashCode method throws, 

+//   then the Eclipse debugger fails to show the object saying 

+//   com.sun.jdi.InvocationException occurred invoking method. 

+  @Override

+  public int hashCode() {

+    return Arrays.hashCode(indexes);

+  }

+

+  

+  /**

+   * 

+   * @return the sum of the sizes of the indexes of the type + all subtypes

+   */

+  @Override

+  public int size() {

+    int size = 0;

+    for (LowLevelIndex<T> idx : indexes) {

+      size += idx.size();

+    }

+    return size;

+  }

+  

+  @Override

+  public int ll_maxAnnotSpan() {

+    int span = -1;

+    for (LowLevelIndex<T> idx : indexes) {

+      span = Math.max(span,  idx.ll_maxAnnotSpan());

+    }

+    return span;

+  }

+  

+  public boolean isEmpty() {

+    for (LowLevelIndex<T> idx : indexes) {

+      if (idx.size() > 0) {

+        return false;

+      }

+    } 

+    return true;

+  }

+  

+  /**

+   * A faster version of size() when there are lots indexes

+   * 

+   * Guess by adding the sizes of up to the first 3 type/subtypes, 

+   * then add 1 more for each subtype in addition.

+   * 

+   * @return a guess at the size, done quickly

+   */

+  int guessedSize() {

+    final int len = indexes.length;

+    final int lim = Math.min(3, len);

+    int size = 0;

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

+      size += indexes[i].size();

+    }

+    size += len - lim;

+    return size;

+  }

+     

+  @Override

+  public int getIndexingStrategy() {

+    throw new UnsupportedOperationException();

+  }

+

+  /* (non-Javadoc)

+   * @see org.apache.uima.cas.impl.LowLevelIndex#getComparator()

+   */

+  @Override

+  public Comparator<TOP> getComparator() {

+    throw new UnsupportedOperationException();

+  }

+

+  @Override

+  public FSIndexComparator getComparatorForIndexSpecs() {

+    throw new UnsupportedOperationException();

+  }

+  

+  @Override

+  public int compare(FeatureStructure fs1, FeatureStructure fs2) {

+    throw new UnsupportedOperationException();

+  }

+    

+  @Override

+  public boolean contains(FeatureStructure fs) {

+    return find(fs) != null;

+  }

+

+  @Override

+  public T find(FeatureStructure fs) {    

+    for (LowLevelIndex<T> idx : indexes) {

+     T result = idx.find(fs);

+      if (result != null) {

+        return result;

+      }

+    }

+    return null;

+  }

+

+  @Override

+  public Type getType() {

+    throw new UnsupportedOperationException();

+  }

+  

+  int getTypeCode() {

+    throw new UnsupportedOperationException();

+  }

+

+  @Override

+  public CASImpl getCasImpl() {

+    return indexes[0].getCasImpl();

+  }

+  

+  @Override

+  public LowLevelIterator<T> iterator() {  

+    throw new UnsupportedOperationException();

+  } 

+  

+  public LowLevelIterator<T> iteratorUnordered() {

+    throw new UnsupportedOperationException();

+  }

+

+  @Override

+  public LowLevelIterator<T> ll_iterator(boolean ambiguous) {

+    throw new UnsupportedOperationException();

+  }

+     

+  @Override

+  public FSIndex<T> withSnapshotIterators() {

+    throw new UnsupportedOperationException();

+  }

+

+  /**

+   * @return a stream of FSIndex_singletype, for all non-empty indexes

+   */

+  public Stream<LowLevelIndex<T>> streamNonEmptyIndexes() {

+    return Arrays.stream(indexes).filter(idx -> idx.size() > 0);

+  }

+    

+}

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_set_sorted.java b/unused-saved/src/org/apache/uima/cas/impl/FsIterator_set_sorted.java
similarity index 87%
copy from uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_set_sorted.java
copy to unused-saved/src/org/apache/uima/cas/impl/FsIterator_set_sorted.java
index a09eb30..10f07f5 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_set_sorted.java
+++ b/unused-saved/src/org/apache/uima/cas/impl/FsIterator_set_sorted.java
@@ -27,9 +27,15 @@
 import org.apache.uima.cas.FSIterator;

 import org.apache.uima.cas.FeatureStructure;

 import org.apache.uima.internal.util.CopyOnWriteOrderedFsSet_array;

+import org.apache.uima.internal.util.Misc;

 import org.apache.uima.jcas.cas.TOP;

 

 /**

+ * NOTE: This class is no longer used; instead, the callers which created instances of this class now 

+ * create instances of OrderedFsSort_array.LL_iterator.

+ * 

+ * 

+ * 

  * @param <T> the type of FSs being returned from the iterator, supplied by the calling context

  */

 class FsIterator_set_sorted<T extends FeatureStructure> extends FsIterator_singletype<T> {

@@ -61,6 +67,7 @@
     super(ti, comp);

     this.fsSetSortIndex = fsSetSortIndex;

     moveToFirst();

+    Misc.internalError();  // class superseded

   }

 

   @Override

@@ -71,7 +78,7 @@
 //    fsSetSortIndex.maybeProcessBulkAdds();

     this.navSet = (NavigableSet<TOP>) fsSetSortIndex.getNonNullCow();

     iterator = (Iterator<T>) navSet.iterator();  // in case iterator was reverse, etc.

-    resetConcurrentModification(); // follow create of iterator, which, in turn, does any pending batch processing

+//    resetConcurrentModification(); // follow create of iterator, which, in turn, does any pending batch processing

     isGoingForward = true;

     isCurrentElementFromLastGet = false;

   }

@@ -81,18 +88,10 @@
 //    fsSetSortIndex.maybeProcessBulkAdds();

     this.navSet = (NavigableSet<TOP>) fsSetSortIndex.getNonNullCow();

     iterator =  (Iterator<T>) navSet.descendingIterator();

-    resetConcurrentModification(); // follow create of iterator, which, in turn, does any pending batch processing

+//    resetConcurrentModification(); // follow create of iterator, which, in turn, does any pending batch processing

     isGoingForward = false;

     isCurrentElementFromLastGet = false;

   }

-

-  @Override

-  public void moveToNext() {

-    if (!isValid()) {

-      return;

-    }

-    moveToNextNvc();

-  }

   

   @Override

   public void moveToNextNvc() { 

@@ -117,16 +116,6 @@
     }

   }

 

-

-  @Override

-  public void moveToPrevious() {

-    if (!isValid()) {

-      return;

-    }

-    

-    moveToPreviousNvc();

-  }

-  

   @Override

   public void moveToPreviousNvc() {

     if (!isGoingForward) {

@@ -151,25 +140,12 @@
   }

 

   @Override

-  public T get() {

-    if (!isValid()) {

-      throw new NoSuchElementException();

-    }

-    if (!isCurrentElementFromLastGet) {      

-      currentElement = iterator.next();

-      isCurrentElementFromLastGet = true;

-    }

-    maybeTraceCowUsingCopy(fsSetSortIndex, (CopyOnWriteIndexPart) navSet); 

-    return currentElement;

-  }

-

-  @Override

   public T getNvc() {

     if (!isCurrentElementFromLastGet) {

-      maybeTraceCowUsingCopy(fsSetSortIndex, (CopyOnWriteIndexPart) navSet);

       currentElement = iterator.next();

       isCurrentElementFromLastGet = true;

     }

+    maybeTraceCowUsingCopy(fsSetSortIndex, (CopyOnWriteIndexPart) navSet);

     return currentElement;

   }

 

@@ -229,7 +205,7 @@
     }

     

     iterator = (Iterator<T>) navSet.tailSet(elementBefore, false).iterator();

-    resetConcurrentModification(); // follow create of iterator, which, in turn, does any pending batch processing

+//    resetConcurrentModification(); // follow create of iterator, which, in turn, does any pending batch processing

     return;

   }

     

@@ -251,10 +227,10 @@
     return fsSetSortIndex;

   }

   

-  @Override

-  protected int getModificationCountFromIndex() {

-    return ((CopyOnWriteOrderedFsSet_array)navSet).getModificationCount();

-  }

+//  @Override

+//  protected int getModificationCountFromIndex() {

+//    return ((CopyOnWriteOrderedFsSet_array)navSet).getModificationCount();

+//  }

   

   /* (non-Javadoc)

    * @see org.apache.uima.cas.impl.LowLevelIterator#isIndexesHaveBeenUpdated()

@@ -264,5 +240,25 @@
     return navSet != fsSetSortIndex.getCopyOnWriteIndexPart();

   }

 

+  @Override

+  public boolean maybeReinitIterator() {

+    throw Misc.internalError();  // not yet done

+  }

+

+  @Override

+  public void moveToFirstNoReinit() {

+    Misc.internalError();  // not yet done

+  }

+

+  @Override

+  public void moveToLastNoReinit() {

+    Misc.internalError();  // not yet done

+  }

+

+  @Override

+  public void moveToNoReinit(FeatureStructure fs) {

+    Misc.internalError();  // not yet done

+  }

+

 }

 

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_set_sorted.java b/unused-saved/src/org/apache/uima/cas/impl/FsIterator_set_sorted_navset_version.java
similarity index 93%
rename from uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_set_sorted.java
rename to unused-saved/src/org/apache/uima/cas/impl/FsIterator_set_sorted_navset_version.java
index a09eb30..f560bc4 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_set_sorted.java
+++ b/unused-saved/src/org/apache/uima/cas/impl/FsIterator_set_sorted_navset_version.java
@@ -27,12 +27,13 @@
 import org.apache.uima.cas.FSIterator;

 import org.apache.uima.cas.FeatureStructure;

 import org.apache.uima.internal.util.CopyOnWriteOrderedFsSet_array;

+import org.apache.uima.internal.util.Misc;

 import org.apache.uima.jcas.cas.TOP;

 

 /**

  * @param <T> the type of FSs being returned from the iterator, supplied by the calling context

  */

-class FsIterator_set_sorted<T extends FeatureStructure> extends FsIterator_singletype<T> {

+class FsIterator_set_sorted_navset_version<T extends FeatureStructure> extends FsIterator_singletype<T> {

 

   // We use TOP instead of T because the 

   // signature of getting a "matching" element limits the type to the declared type, and 

@@ -57,10 +58,11 @@
 

   private Iterator<T> iterator; // changes according to direction, starting point, etc.

   

-  FsIterator_set_sorted(FsIndex_set_sorted<T> fsSetSortIndex, TypeImpl ti, Comparator<FeatureStructure> comp) {

+  FsIterator_set_sorted_navset_version(FsIndex_set_sorted<T> fsSetSortIndex, TypeImpl ti, Comparator<FeatureStructure> comp) {

     super(ti, comp);

     this.fsSetSortIndex = fsSetSortIndex;

     moveToFirst();

+    Misc.internalError();

   }

 

   @Override

@@ -166,10 +168,10 @@
   @Override

   public T getNvc() {

     if (!isCurrentElementFromLastGet) {

-      maybeTraceCowUsingCopy(fsSetSortIndex, (CopyOnWriteIndexPart) navSet);

       currentElement = iterator.next();

       isCurrentElementFromLastGet = true;

     }

+    maybeTraceCowUsingCopy(fsSetSortIndex, (CopyOnWriteIndexPart) navSet);

     return currentElement;

   }

 

@@ -177,8 +179,8 @@
    * @see org.apache.uima.internal.util.IntPointerIterator#copy()

    */

   @Override

-  public FsIterator_set_sorted<T> copy() {

-    return new FsIterator_set_sorted<T>(this.fsSetSortIndex, ti, this.comparator);

+  public FsIterator_set_sorted_navset_version<T> copy() {

+    return new FsIterator_set_sorted_navset_version<T>(this.fsSetSortIndex, ti, this.comparator);

   }

 

   /**

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_subtypes.java b/unused-saved/src/org/apache/uima/cas/impl/FsIterator_subtypes.java
similarity index 88%
rename from uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_subtypes.java
rename to unused-saved/src/org/apache/uima/cas/impl/FsIterator_subtypes.java
index 57c292a..e052518 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FsIterator_subtypes.java
+++ b/unused-saved/src/org/apache/uima/cas/impl/FsIterator_subtypes.java
@@ -19,19 +19,16 @@
 

 package org.apache.uima.cas.impl;

 

-import java.util.NoSuchElementException;

-

-import org.apache.uima.cas.FSIterator;

 import org.apache.uima.cas.FeatureStructure;

-import org.apache.uima.jcas.cas.TOP;

 

 

-public abstract class FsIterator_subtypes<T extends FeatureStructure> implements LowLevelIterator<T> {

+public abstract class FsIterator_subtypes<T extends FeatureStructure> extends FsIterator_multiple_indexes<T> {

 

   // The IICP

   final protected FsIndex_iicp<T> iicp;

  

   public FsIterator_subtypes(FsIndex_iicp<T> iicp) {

+    super(iicp.getIterators());

     this.iicp = iicp;

   } 

   

@@ -54,7 +51,7 @@
     TypeImpl type = (TypeImpl) this.ll_getIndex().getType();

     StringBuilder sb = new StringBuilder(this.getClass().getSimpleName()).append(":").append(System.identityHashCode(this));

     sb.append(" over Type: ").append(type.getName()).append(":").append(type.getCode());

-    sb.append(", size: ").append(this.ll_indexSize());

+    sb.append(", index size: ").append(this.ll_indexSize());

     return sb.toString();

   }

   

diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl_javaObject.java b/unused-saved/src/org/apache/uima/cas/impl/FsIterator_subtypes_list_unused.java
similarity index 68%
rename from uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl_javaObject.java
rename to unused-saved/src/org/apache/uima/cas/impl/FsIterator_subtypes_list_unused.java
index 47c1228..c7b852f 100644
--- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl_javaObject.java
+++ b/unused-saved/src/org/apache/uima/cas/impl/FsIterator_subtypes_list_unused.java
@@ -19,16 +19,16 @@
 

 package org.apache.uima.cas.impl;

 

-/**

- * A version of TypeImpl for types that are JavaObject types

- * Note: these are non-creatable (as FeatureStructures), but they may be the

- * values of Feature slots.

- *

- */

-public class TypeImpl_javaObject extends TypeImpl_primitive {

-  

-  public TypeImpl_javaObject(String name, TypeSystemImpl tsi, TypeImpl supertype, Class<?> javaClass) {

-    super(name, tsi, supertype, javaClass);

+import java.util.ArrayList;

+

+import org.apache.uima.cas.FSIterator;

+import org.apache.uima.cas.FeatureStructure;

+

+public abstract class FsIterator_subtypes_list_unused <T extends FeatureStructure>  extends FsIterator_multiple_indexes<T> {

+ 

+  public FsIterator_subtypes_list_unused(FsIndex_iicp<T> iicp) {

+    super(iicp.getIterators());

   }

   

+  

 }