Merge branch 'master' into fix/JLL/use_https_to_resolve_dependencies
diff --git a/NOTICE b/NOTICE
index 77fe8bf..74e0eb5 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,5 +1,5 @@
 Apache UIMA uimaFIT
-Copyright 2013-2019 The Apache Software Foundation
+Copyright 2013-2020 The Apache Software Foundation
 
 Copyright 2009-2012 Regents of the University of Colorado.
 All rights reserved.
diff --git a/README b/README
index 90fd2ec..a83f923 100644
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
 
-      Apache uimaFIT (TM) v3.0.0
+      Apache uimaFIT (TM) v3.1.0
       --------------------------
 
 
@@ -37,20 +37,20 @@
      SimplePipeline.runPipeline(reader, ae1, ..., aeN, consumer1, ... consumerN)
 
 
-What's New in 3.0.0
+What's New in 3.1.0
 -------------------
 
-uimaFIT 3.0.0 is a major release because it upgrades uimaFIT to UIMA v3. Upgrading to the new version 
+uimaFIT 3.1.0 is a major release because it upgrades uimaFIT to UIMA v3. Upgrading to the new version 
 may require minor adjustments to the code depending on uimaFIT.
 
 A full list of issues addressed in this release can be found on the Apache issue tracker:
 
-  https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12310570&version=12332458
+  https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12310570&version=12343882
 
 Supported Platforms
 -------------------
 
-uimaFIT requires Java 1.8 or higher, UIMA 3.0.2 or higher, and the Spring Framework 4.3.22 or higher.
+uimaFIT requires Java 1.8 or higher, UIMA 3.1.1 or higher, and the Spring Framework 4.3.26 or higher.
 
 
 Availability
@@ -67,7 +67,7 @@
   <dependency>
     <groupId>org.apache.uima</groupId>
     <artifactId>uimafit-core</artifactId>
-    <version>3.0.0</version>
+    <version>3.1.0</version>
   </dependency>
 
 
diff --git a/pom.xml b/pom.xml
index 2a27a51..1c2e855 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,11 +28,11 @@
   <parent>
     <groupId>org.apache.uima</groupId>
     <artifactId>uimafit-parent</artifactId>
-    <version>3.0.1-SNAPSHOT</version>
+    <version>3.1.0-SNAPSHOT</version>
     <relativePath>uimafit-parent</relativePath>
   </parent>
   <properties>
-    <jiraVersion>3.0.0uimaFIT</jiraVersion>
+    <jiraVersion>3.1.0uimaFIT</jiraVersion>
   </properties>
   <scm>
     <connection>scm:git:git://github.com/apache/uima-uimafit</connection>
@@ -51,12 +51,12 @@
     <dependency>
       <groupId>org.apache.uima</groupId>
       <artifactId>uimafit-core</artifactId>
-      <version>3.0.1-SNAPSHOT</version>
+      <version>3.1.0-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.apache.uima</groupId>
       <artifactId>uimafit-cpe</artifactId>
-      <version>3.0.1-SNAPSHOT</version>
+      <version>3.1.0-SNAPSHOT</version>
     </dependency>
   </dependencies>
   <build>
diff --git a/src/main/dist-bin/LICENSE b/src/main/dist-bin/LICENSE
index 5516c5a..df56428 100644
--- a/src/main/dist-bin/LICENSE
+++ b/src/main/dist-bin/LICENSE
@@ -203,9 +203,9 @@
 
 =======================================================================
 
-SPRING FRAMEWORK 4.3.22.RELEASE SUBCOMPONENTS:
+SPRING FRAMEWORK 4.3.26.RELEASE SUBCOMPONENTS:
 
-Spring Framework 4.3.22.RELEASE includes a number of subcomponents
+Spring Framework 4.3.26.RELEASE includes a number of subcomponents
 with separate copyright notices and license terms. The product that
 includes this file does not necessarily use all the open source
 subcomponents referred to below. Your use of the source
@@ -213,7 +213,7 @@
 conditions of the following licenses.
 
 
->>> ASM 4.0 (org.ow2.asm:asm:4.0, org.ow2.asm:asm-commons:4.0):
+>>> ASM 6.0 (org.ow2.asm:asm:6.0, org.ow2.asm:asm-commons:6.0):
 
 Copyright (c) 2000-2011 INRIA, France Telecom
 All rights reserved.
@@ -245,36 +245,39 @@
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 THE POSSIBILITY OF SUCH DAMAGE.
 
-Copyright (c) 1999-2009, OW2 Consortium <http://www.ow2.org/>
+Copyright (c) 1999-2009, OW2 Consortium <https://www.ow2.org/>
 
 
->>> CGLIB 3.0 (cglib:cglib:3.0):
+>>> CGLIB 3.2.6 (cglib:cglib:3.2.6):
 
 Per the LICENSE file in the CGLIB JAR distribution downloaded from
-http://sourceforge.net/projects/cglib/files/cglib3/3.0/cglib-3.0.jar/download,
-CGLIB 3.0 is licensed under the Apache License, version 2.0, the text of which
-is included above.
+https://github.com/cglib/cglib/releases/download/RELEASE_3_2_6/cglib-3.2.6.jar,
+CGLIB 3.2.6 is licensed under the Apache License, version 2.0, the text of
+which is included above.
 
 
-=======================================================================
+>>> Objenesis 2.6 (org.objenesis:objenesis:2.6):
 
-To the extent any open source subcomponents are licensed under the EPL and/or
+Per the LICENSE file in the Objenesis ZIP distribution downloaded from
+http://objenesis.org/download.html, Objenesis 2.6 is licensed under the
+Apache License, version 2.0, the text of which is included above.
+
+
+===============================================================================
+
+To the extent any open source components are licensed under the EPL and/or
 other similar licenses that require the source code and/or modifications to
 source code to be made available (as would be noted above), you may obtain a
 copy of the source code corresponding to the binaries for such open source
 components and modifications thereto, if any, (the "Source Files"), by
-downloading the Source Files from http://www.springsource.org/download, or by
-sending a request, with your name and address to:
+downloading the Source Files from https://spring.io/projects, Pivotal's website
+at https://network.pivotal.io/open-source, or by sending a request, with your
+name and address to: Pivotal Software, Inc., 875 Howard Street, 5th floor, San
+Francisco, CA 94103, Attention: General Counsel. All such requests should
+clearly specify: OPEN SOURCE FILES REQUEST, Attention General Counsel. Pivotal
+can mail a copy of the Source Files to you on a CD or equivalent physical
+medium.
 
-    Pivotal, Inc., 875 Howard St,
-    San Francisco, CA 94103
-    United States of America
-
-or email info@pivotal.io.  All such requests should clearly specify:
-
-    OPEN SOURCE FILES REQUEST
-    Attention General Counsel
-
-Pivotal shall mail a copy of the Source Files to you on a CD or equivalent
-physical medium. This offer to obtain a copy of the Source Files is valid for
-three years from the date you acquired this Software product.
+This offer to obtain a copy of the Source Files is valid for three years from
+the date you acquired this Software product. Alternatively, the Source Files
+may accompany the Software.
diff --git a/src/main/dist-bin/NOTICE b/src/main/dist-bin/NOTICE
index a661f84..b0cfc2a 100644
--- a/src/main/dist-bin/NOTICE
+++ b/src/main/dist-bin/NOTICE
@@ -1,12 +1,15 @@
+----------------------------------------------------------------
+
 Apache UIMA uimaFIT
-Copyright 2012-2019 The Apache Software Foundation
+Copyright 2012-2020 The Apache Software Foundation
 
 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
 
+----------------------------------------------------------------
 
 Apache UIMA uimaFIT - Core
-Copyright 2013-2019 The Apache Software Foundation
+Copyright 2013-2020 The Apache Software Foundation
 
 Copyright 2009-2012 Regents of the University of Colorado.
 All rights reserved.
@@ -15,16 +18,18 @@
 Technische Universität Darmstadt.
 All rights reserved.
 
+----------------------------------------------------------------
 
 Apache UIMA uimaFIT - Collection Processing Engine support
 Apache UIMA uimaFIT - Legacy uimaFIT support
-Copyright 2012-2019 The Apache Software Foundation
+Copyright 2012-2020 The Apache Software Foundation
 
+----------------------------------------------------------------
 
-Apache UIMA Base: uimaj-core
-Apache UIMA Base: jVinci: Vinci Transport Library
-Apache UIMA Base: uimaj-adapter-vinci: Vinci Adapter
-Apache UIMA Base: uimaj-cpe: Collection Processing Engine
+Apache UIMA Base 3.0.2: uimaj-core
+Apache UIMA Base 3.0.2: jVinci: Vinci Transport Library
+Apache UIMA Base 3.0.2: uimaj-adapter-vinci: Vinci Adapter
+Apache UIMA Base 3.0.2: uimaj-cpe: Collection Processing Engine
 Copyright 2006-2019 The Apache Software Foundation
 
 Portions of Apache UIMA were originally developed by
@@ -34,21 +39,25 @@
 "IBM UIMA License Agreement".
 Copyright (c) 2003, 2006 IBM Corporation.
 
+----------------------------------------------------------------
 
-Apache Commons IO
+Apache Commons IO 2.6
 Copyright 2002-2017 The Apache Software Foundation
 
+----------------------------------------------------------------
 
-Apache Commons Lang
+Apache Commons Lang 3.8.1
 Copyright 2001-2018 The Apache Software Foundation
 
+----------------------------------------------------------------
 
-Commons Logging
+Commons Logging 1.2
 Copyright 2003-2014 The Apache Software Foundation
   
+----------------------------------------------------------------
   
-Spring Framework 4.3.22.RELEASE
-Copyright (c) 2002-2019 Pivotal, Inc.
+Spring Framework 4.3.26.RELEASE
+Copyright (c) 2002-2020 Pivotal, Inc.
 
 This product is licensed to you under the Apache License, Version 2.0
 (the "License"). You may not use this product except in compliance with
@@ -59,6 +68,7 @@
 these subcomponents is subject to the terms and conditions of the
 subcomponent's license, as noted in the license.txt file.
 
+----------------------------------------------------------------
 
 AnnotationLiteral.java
 
diff --git a/uimafit-benchmark/pom.xml b/uimafit-benchmark/pom.xml
index 6c13ea0..c2ed513 100644
--- a/uimafit-benchmark/pom.xml
+++ b/uimafit-benchmark/pom.xml
@@ -27,7 +27,7 @@
   <parent>
     <groupId>org.apache.uima</groupId>
     <artifactId>uimafit-parent</artifactId>
-    <version>3.0.1-SNAPSHOT</version>
+    <version>3.1.0-SNAPSHOT</version>
     <relativePath>../uimafit-parent</relativePath>
   </parent>
   <properties>
@@ -37,7 +37,7 @@
     <dependency>
       <groupId>org.apache.uima</groupId>
       <artifactId>uimafit-core</artifactId>
-      <version>3.0.1-SNAPSHOT</version>
+      <version>3.1.0-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.apache.uima</groupId>
diff --git a/uimafit-core/pom.xml b/uimafit-core/pom.xml
index 54b3f84..5e980b5 100644
--- a/uimafit-core/pom.xml
+++ b/uimafit-core/pom.xml
@@ -27,7 +27,7 @@
   <parent>
     <groupId>org.apache.uima</groupId>
     <artifactId>uimafit-parent</artifactId>
-    <version>3.0.1-SNAPSHOT</version>
+    <version>3.1.0-SNAPSHOT</version>
     <relativePath>../uimafit-parent</relativePath>
   </parent>
   <dependencies>
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/component/ExternalResourceAware.java b/uimafit-core/src/main/java/org/apache/uima/fit/component/ExternalResourceAware.java
index e5e2e12..f5edff0 100644
--- a/uimafit-core/src/main/java/org/apache/uima/fit/component/ExternalResourceAware.java
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/component/ExternalResourceAware.java
@@ -25,14 +25,12 @@
 /**
  * Allows an external resource to use the {@link ExternalResource} annotation on member variables to
  * gain access to other external resources.
- * 
  */
 public interface ExternalResourceAware {
   /**
-   * Get the name of the resource. This is set by
-   * {@link ExternalResourceFactory#bindResource(org.apache.uima.resource.ResourceCreationSpecifier, String, org.apache.uima.resource.ExternalResourceDescription)
-   * bindExternalResource()} as the parameter {@link ExternalResourceFactory#PARAM_RESOURCE_NAME
-   * PARAM_RESOURCE_NAME}. <br>
+   * Get the name of the resource. This is set by the different variations of
+   * {@link ExternalResourceFactory#bindResourceOnce} which internally call {@code ExternalResourceFactory.bindNestedResources(...)}
+   * to set the parameter {@link ExternalResourceFactory#PARAM_RESOURCE_NAME PARAM_RESOURCE_NAME}.<br>
    * <b>It is mandatory that any resource implementing this interface declares the configuration
    * parameter {@link ExternalResourceFactory#PARAM_RESOURCE_NAME PARAM_RESOURCE_NAME}.</b>
    * 
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/factory/AnalysisEngineFactory.java b/uimafit-core/src/main/java/org/apache/uima/fit/factory/AnalysisEngineFactory.java
index e374551..52058e8 100644
--- a/uimafit-core/src/main/java/org/apache/uima/fit/factory/AnalysisEngineFactory.java
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/factory/AnalysisEngineFactory.java
@@ -25,7 +25,7 @@
 import static org.apache.uima.fit.factory.ConfigurationParameterFactory.createConfigurationData;
 import static org.apache.uima.fit.factory.ConfigurationParameterFactory.ensureParametersComeInPairs;
 import static org.apache.uima.fit.factory.ConfigurationParameterFactory.setParameters;
-import static org.apache.uima.fit.factory.ExternalResourceFactory.bindResource;
+import static org.apache.uima.fit.factory.ExternalResourceFactory.bindResourceOnce;
 import static org.apache.uima.fit.factory.ExternalResourceFactory.createResourceDependencies;
 import static org.apache.uima.fit.factory.FsIndexFactory.createFsIndexCollection;
 import static org.apache.uima.fit.factory.TypePrioritiesFactory.createTypePriorities;
@@ -1362,7 +1362,7 @@
     // Bind External Resources
     if (externalResources != null) {
       for (Entry<String, ExternalResourceDescription> e : externalResources.entrySet()) {
-        bindResource(desc, e.getKey(), e.getValue());
+        bindResourceOnce(desc, e.getKey(), e.getValue());
       }
     }
 
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/factory/CollectionReaderFactory.java b/uimafit-core/src/main/java/org/apache/uima/fit/factory/CollectionReaderFactory.java
index 5913f95..850463c 100644
--- a/uimafit-core/src/main/java/org/apache/uima/fit/factory/CollectionReaderFactory.java
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/factory/CollectionReaderFactory.java
@@ -21,7 +21,7 @@
 import static org.apache.uima.fit.factory.ConfigurationParameterFactory.createConfigurationData;
 import static org.apache.uima.fit.factory.ConfigurationParameterFactory.ensureParametersComeInPairs;
 import static org.apache.uima.fit.factory.ConfigurationParameterFactory.setParameters;
-import static org.apache.uima.fit.factory.ExternalResourceFactory.bindResource;
+import static org.apache.uima.fit.factory.ExternalResourceFactory.bindResourceOnce;
 import static org.apache.uima.fit.factory.ExternalResourceFactory.createResourceDependencies;
 import static org.apache.uima.fit.factory.FsIndexFactory.createFsIndexCollection;
 import static org.apache.uima.fit.factory.ResourceCreationSpecifierFactory.createResourceCreationSpecifier;
@@ -449,8 +449,10 @@
 
   /**
    * A simple factory method for creating a CollectionReaderDescription with a given class, type
-   * system description, and configuration data The type system is detected automatically using
-   * {@link TypeSystemDescriptionFactory#createTypeSystemDescription()}.
+   * system description, and configuration data. The type system is detected automatically using
+   * {@link TypeSystemDescriptionFactory#createTypeSystemDescription()}. Type priorities are
+   * detected automatically using {@link TypePrioritiesFactory#createTypePriorities()}. Indexes are
+   * detected automatically using {@link FsIndexFactory#createFsIndexCollection()}.
    * 
    * @param readerClass
    *          The class of the CollectionReader to be created.
@@ -465,8 +467,11 @@
   public static CollectionReaderDescription createReaderDescription(
           Class<? extends CollectionReader> readerClass, Object... configurationData)
           throws ResourceInitializationException {
-    TypeSystemDescription tsd = createTypeSystemDescription();
-    return createReaderDescription(readerClass, tsd, (TypePriorities) null, configurationData);
+    TypeSystemDescription typeSystem = createTypeSystemDescription();
+    TypePriorities typePriorities = createTypePriorities();
+    FsIndexCollection fsIndexCollection = createFsIndexCollection();
+    return createReaderDescription(readerClass, typeSystem, typePriorities, fsIndexCollection,
+            (Capability[]) null, configurationData);
   }
 
   /**
@@ -845,7 +850,7 @@
     // Bind External Resources
     if (externalResources != null) {
       for (Entry<String, ExternalResourceDescription> e : externalResources.entrySet()) {
-        bindResource(desc, e.getKey(), e.getValue());
+        bindResourceOnce(desc, e.getKey(), e.getValue());
       }
     }
 
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/factory/ExternalResourceFactory.java b/uimafit-core/src/main/java/org/apache/uima/fit/factory/ExternalResourceFactory.java
index d492f57..20b1f5c 100644
--- a/uimafit-core/src/main/java/org/apache/uima/fit/factory/ExternalResourceFactory.java
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/factory/ExternalResourceFactory.java
@@ -21,6 +21,7 @@
 
 import static java.util.Arrays.asList;
 import static java.util.Collections.emptyMap;
+import static org.apache.uima.UIMAFramework.getResourceSpecifierFactory;
 import static org.apache.uima.UIMAFramework.produceResource;
 import static org.apache.uima.fit.factory.ConfigurationParameterFactory.canParameterBeSet;
 import static org.apache.uima.fit.factory.ConfigurationParameterFactory.createConfigurationData;
@@ -39,6 +40,7 @@
 import java.util.concurrent.atomic.AtomicLong;
 
 import org.apache.commons.lang3.ArrayUtils;
+import org.apache.uima.ResourceSpecifierFactory;
 import org.apache.uima.UIMAFramework;
 import org.apache.uima.analysis_engine.AnalysisEngineDescription;
 import org.apache.uima.collection.CollectionReaderDescription;
@@ -63,13 +65,11 @@
 import org.apache.uima.resource.SharedResourceObject;
 import org.apache.uima.resource.impl.ConfigurableDataResourceSpecifier_impl;
 import org.apache.uima.resource.impl.ConfigurableDataResource_impl;
-import org.apache.uima.resource.impl.ExternalResourceDependency_impl;
 import org.apache.uima.resource.impl.ExternalResourceDescription_impl;
 import org.apache.uima.resource.impl.FileResourceSpecifier_impl;
 import org.apache.uima.resource.impl.Parameter_impl;
 import org.apache.uima.resource.metadata.ExternalResourceBinding;
 import org.apache.uima.resource.metadata.ResourceManagerConfiguration;
-import org.apache.uima.resource.metadata.impl.ExternalResourceBinding_impl;
 import org.apache.uima.resource.metadata.impl.ResourceManagerConfiguration_impl;
 import org.apache.uima.resource.metadata.impl.ResourceMetaData_impl;
 import org.apache.uima.util.InvalidXMLException;
@@ -343,7 +343,10 @@
   }
 
   /**
-   * Create an external resource binding.
+   * Create an external resource binding. This is a more convenient method of creating an
+   * {@link ExternalResourceBinding} than calling
+   * {@link ResourceSpecifierFactory#createExternalResourceBinding()} and setting the resource name
+   * and key manually.
    * 
    * @param aKey
    *          the key to bind to.
@@ -353,15 +356,16 @@
    */
   public static ExternalResourceBinding createResourceBinding(final String aKey,
           final String aResourceKey) {
-    ExternalResourceBinding extResBind = new ExternalResourceBinding_impl();
+    ExternalResourceBinding extResBind = getResourceSpecifierFactory()
+            .createExternalResourceBinding();
     extResBind.setResourceName(aResourceKey);
     extResBind.setKey(aKey);
     return extResBind;
   }
 
   /**
-   * Creates an ExternalResourceDependency for a field annotated with
-   * {@link org.apache.uima.fit.descriptor.ExternalResource}.
+   * Creates an {@link ExternalResourceDependency} for a field annotated with
+   * {@link ExternalResource}.
    * 
    * @param field
    *          the field to analyze
@@ -380,10 +384,13 @@
     // Get the type of class/interface a resource has to implement to bind to the annotated field.
     // If no API is set, get it from the annotated field type.
     Class<? extends Resource> api = era.api();
-    // If no api is specified, look at the annotated field
+    
+    // If no API is specified, look at the annotated field
     if (api == Resource.class) {
-      if (Resource.class.isAssignableFrom(field.getType())
-              || SharedResourceObject.class.isAssignableFrom(field.getType())) {
+      if (
+              Resource.class.isAssignableFrom(field.getType()) || 
+              SharedResourceObject.class.isAssignableFrom(field.getType())
+      ) {
         // If no API is set, check if the field type is already a resource type
         api = (Class<? extends Resource>) field.getType();
       } else {
@@ -395,12 +402,14 @@
       }
     }
 
-    return ExternalResourceFactory.createResourceDependency(key, api, !era.mandatory(),
-            era.description());
+    return createResourceDependency(key, api, !era.mandatory(), era.description());
   }
 
   /**
-   * Creates an ExternalResourceDependency for a given key and interface
+   * Creates an ExternalResourceDependency for a given key and interface. This is a more convenient
+   * method of creating an {@link ExternalResourceDependency} than calling
+   * {@link ResourceSpecifierFactory#createExternalResourceDependency()} and setting the fields
+   * manually.
    * 
    * @param aKey
    *          the resource key
@@ -414,7 +423,8 @@
    */
   public static ExternalResourceDependency createResourceDependency(final String aKey,
           final Class<?> aInterface, final boolean aOptional, String aDescription) {
-    ExternalResourceDependency dep = new ExternalResourceDependency_impl();
+    ExternalResourceDependency dep = getResourceSpecifierFactory()
+            .createExternalResourceDependency();
     dep.setInterfaceName(aInterface.getName());
     dep.setKey(aKey);
     dep.setOptional(aOptional);
@@ -520,7 +530,35 @@
 
   /**
    * Scan the given resource specifier for external resource dependencies and whenever a dependency
-   * is encounter that has the specified key, the resource will be bound.
+   * is encountered that has the specified key, the resource will be bound.
+   * <p>
+   * <b>Caveat</b>: If you use this method, you may expect that {@link DataResource#getUrl()} or
+   * {@link DataResource#getUri()} will return the same URL that you have specified here. This is
+   * may <b>NOT</b> be the case. UIMA will internally try to resolve the URL via a
+   * {@link ResourceManager}. If it cannot resolve a remove URL, this mechanism will think it may be
+   * a local file and will return some local path - or it may redirect it to some location as though
+   * fit by the {@link ResourceManager}.
+   * 
+   * @param aDesc
+   *          a description.
+   * @param aKey
+   *          the key to bind to.
+   * @param aUrl
+   *          a URL.
+   * @throws InvalidXMLException
+   *           if import resolution failed
+   * @see FileResourceSpecifier
+   * @deprecated Use {@link #bindResourceUsingUrl(ResourceSpecifier, String, String)}
+   */
+  @Deprecated
+  public static void bindResource(ResourceSpecifier aDesc, String aKey, String aUrl)
+          throws InvalidXMLException {
+    bindResourceUsingUrl(aDesc, aKey, aUrl);
+  }
+  
+  /**
+   * Scan the given resource specifier for external resource dependencies and whenever a dependency
+   * is encountered that has the specified key, the resource will be bound.
    * <p>
    * <b>Caveat</b>: If you use this method, you may expect that {@link DataResource#getUrl()} or
    * {@link DataResource#getUri()} will return the same URL that you have specified here. This is
@@ -539,7 +577,7 @@
    *           if import resolution failed
    * @see FileResourceSpecifier
    */
-  public static void bindResource(ResourceSpecifier aDesc, String aKey, String aUrl)
+  public static void bindResourceUsingUrl(ResourceSpecifier aDesc, String aKey, String aUrl)
           throws InvalidXMLException {
     ExternalResourceDescription extRes = createNamedFileResourceDescription(aKey, aUrl);
     bindResource(aDesc, aKey, extRes);
@@ -597,6 +635,7 @@
   /**
    * Scan the given resource specifier for external resource dependencies and whenever a dependency
    * with a compatible type is found, the resource will be bound.
+   * 
    * @param aDesc
    *          a description.
    * @param aRes
@@ -616,7 +655,7 @@
           throws InvalidXMLException, ClassNotFoundException {
     ExternalResourceDescription extRes = createNamedResourceDescriptionUsingUrl(
             uniqueResourceKey(aRes.getName()), aRes, aUrl, aParams);
-    bind((AnalysisEngineDescription) aDesc, extRes);
+    scanRecursivelyForDependenciesByInterfaceAndBind((AnalysisEngineDescription) aDesc, extRes);
   }
 
   /**
@@ -666,7 +705,7 @@
           throws InvalidXMLException {
     ExternalResourceDescription extRes = createNamedResourceDescriptionUsingUrl(
             uniqueResourceKey(aRes.getName()), aRes, aUrl, aParams);
-    bind((AnalysisEngineDescription) aDesc, aKey, extRes);
+    scanRecursivelyForDependenciesByKeyAndBind((AnalysisEngineDescription) aDesc, aKey, extRes);
   }
 
   /**
@@ -715,7 +754,7 @@
           throws InvalidXMLException, ClassNotFoundException {
     // Dispatch
     if (aDesc instanceof AnalysisEngineDescription) {
-      bind((AnalysisEngineDescription) aDesc, aResDesc);
+      scanRecursivelyForDependenciesByInterfaceAndBind((AnalysisEngineDescription) aDesc, aResDesc);
     }
   }
 
@@ -736,7 +775,7 @@
           ExternalResourceDescription aResDesc) throws InvalidXMLException {
     // Dispatch
     if (aDesc instanceof AnalysisEngineDescription) {
-      bind((AnalysisEngineDescription) aDesc, aKey, aResDesc);
+      scanRecursivelyForDependenciesByKeyAndBind((AnalysisEngineDescription) aDesc, aKey, aResDesc);
     }
   }
 
@@ -903,12 +942,13 @@
    * @param aResDesc
    *          the resource description.
    */
-  private static void bind(AnalysisEngineDescription aDesc, ExternalResourceDescription aResDesc)
+  private static void scanRecursivelyForDependenciesByInterfaceAndBind(
+          AnalysisEngineDescription aDesc, ExternalResourceDescription aResDesc)
           throws InvalidXMLException, ClassNotFoundException {
     // Recursively address delegates
     if (!aDesc.isPrimitive()) {
-      for (Object delegate : aDesc.getDelegateAnalysisEngineSpecifiers().values()) {
-        bindResource((ResourceSpecifier) delegate, aResDesc);
+      for (ResourceSpecifier delegate : aDesc.getDelegateAnalysisEngineSpecifiers().values()) {
+        bindResource(delegate, aResDesc);
       }
     }
 
@@ -923,7 +963,7 @@
       }
 
       if (apiClass.isAssignableFrom(resClass)) {
-        bindResource(aDesc, dep.getKey(), aResDesc);
+        bindResourceOnce(aDesc, dep.getKey(), aResDesc);
       }
     }
   }
@@ -939,25 +979,52 @@
    * @param aResDesc
    *          the resource description.
    */
-  private static void bind(AnalysisEngineDescription aDesc, String aKey,
-          ExternalResourceDescription aResDesc) throws InvalidXMLException {
+  private static void scanRecursivelyForDependenciesByKeyAndBind(AnalysisEngineDescription aDesc,
+          String aKey, ExternalResourceDescription aResDesc) throws InvalidXMLException {
     // Recursively address delegates
     if (!aDesc.isPrimitive()) {
-      for (Object delegate : aDesc.getDelegateAnalysisEngineSpecifiers().values()) {
-        bindResource((ResourceSpecifier) delegate, aKey, aResDesc);
+      for (ResourceSpecifier delegate : aDesc.getDelegateAnalysisEngineSpecifiers().values()) {
+        bindResource(delegate, aKey, aResDesc);
       }
     }
 
     // Bind if necessary
     for (ExternalResourceDependency dep : aDesc.getExternalResourceDependencies()) {
       if (aKey.equals(dep.getKey())) {
-        bindResource(aDesc, aKey, aResDesc);
+        bindResourceOnce(aDesc, aKey, aResDesc);
       }
     }
   }
 
   /**
-   * Create a new external resource binding.
+   * Create a binding for the given external resource in the given resource manager. This method
+   * also scans the given external resource for any nested external resources and creates
+   * bindings for them as well.
+   * 
+   * @param aResMgrCfg
+   *          the resource manager to create the binding in.
+   * @param aBindTo
+   *          what key to bind to.
+   * @param aRes
+   *          the resource that should be bound.
+   * @deprecated Use {@link #bindResourceOnce(ResourceManagerConfiguration, String, ExternalResourceDescription)}
+   */
+  @Deprecated
+  public static void bindResource(ResourceManagerConfiguration aResMgrCfg, String aBindTo,
+          ExternalResourceDescription aRes) {
+    bindResourceOnce(aResMgrCfg, aBindTo, aRes);
+  }
+  
+  /**
+   * Create a binding for the given external resource in the given resource manager. This method
+   * also scans the given external resource for any nested external resources and creates
+   * bindings for them as well.
+   * <p>
+   * <b>NOTE:</b>If you use this method on resource manager configurations of aggregate analysis
+   * engine descriptions because it will <b>not have any effects on the delegate analysis
+   * engines</b> of the aggregate. If you want to recursively bind an external resource to the
+   * delegates in an aggregate engine, use e.g.
+   * {@link #bindResource(ResourceSpecifier, String, ExternalResourceDescription)}.
    * 
    * @param aResMgrCfg
    *          the resource manager to create the binding in.
@@ -966,16 +1033,16 @@
    * @param aRes
    *          the resource that should be bound.
    */
-  public static void bindResource(ResourceManagerConfiguration aResMgrCfg, String aBindTo,
+  public static void bindResourceOnce(ResourceManagerConfiguration aResMgrCfg, String aBindTo,
           ExternalResourceDescription aRes) {
     // Create a map of all bindings
-    Map<String, ExternalResourceBinding> bindings = new HashMap<String, ExternalResourceBinding>();
+    Map<String, ExternalResourceBinding> bindings = new HashMap<>();
     for (ExternalResourceBinding b : aResMgrCfg.getExternalResourceBindings()) {
       bindings.put(b.getKey(), b);
     }
 
     // Create a map of all resources
-    Map<String, ExternalResourceDescription> resources = new HashMap<String, ExternalResourceDescription>();
+    Map<String, ExternalResourceDescription> resources = new HashMap<>();
     for (ExternalResourceDescription r : aResMgrCfg.getExternalResources()) {
       resources.put(r.getName(), r);
     }
@@ -1004,9 +1071,37 @@
    *          what key to bind to.
    * @param aNestedRes
    *          the resource that should be bound.
+   * @deprecated Use {@link #bindResourceOnce(ExternalResourceDescription, String, ExternalResourceDescription)}
    */
+  @Deprecated
   public static void bindResource(ExternalResourceDescription aRes, String aBindTo,
           ExternalResourceDescription aNestedRes) {
+    bindResourceOnce(aRes, aBindTo, aNestedRes);
+  }
+  
+  /**
+   * Create a binding for the given external resource in the given resource. This method also scans
+   * the given external resource for any nested external resources and creates bindings for them as
+   * well.
+   * <p>
+   * <b>NOTE:</b> This method only works on {@link ExtendedExternalResourceDescription_impl}
+   * instances. Any {@link ExternalResourceDescription} instances created with uimaFIT use this
+   * implementation. For reasons of convenience, the method signature uses
+   * {@link ExternalResourceDescription} but will thrown an {@link IllegalArgumentException} if the
+   * wrong implementations are provided.
+   * 
+   * @param aRes
+   *          the resource to bind to
+   * @param aBindTo
+   *          what key to bind to.
+   * @param aNestedRes
+   *          the resource that should be bound.
+   * @throws IllegalArgumentException
+   *           if the given resource description is not an instance of
+   *           {@link ExtendedExternalResourceDescription_impl}.
+   */
+  public static void bindResourceOnce(ExternalResourceDescription aRes, String aBindTo,
+          ExternalResourceDescription aNestedRes) {
     if (!(aRes instanceof ExtendedExternalResourceDescription_impl)) {
       throw new IllegalArgumentException("Nested resources are only supported on instances of ["
               + ExtendedExternalResourceDescription_impl.class.getName() + "] which"
@@ -1038,11 +1133,10 @@
     // Commit everything to the resource manager configuration
     extRes.setExternalResourceBindings(bindings.values());
     extRes.setExternalResources(resources.values());
-
   }
 
   /**
-   * Helper method to recursively bind resources bound to resources.
+   * Helper method to recursively bind resources bound to other resources (a.k.a. nested resources).
    * 
    * @param aRes
    *          resource.
@@ -1095,7 +1189,15 @@
   }
 
   /**
-   * Create a new external resource binding.
+   * Create a binding for the given external resource in the resource manager configuration of the
+   * given resource. If no resource manager configuration exists yet, it will be created. This
+   * method also scans the given external resource for any nested external resources and creates
+   * bindings for them as well.
+   * <p>
+   * <b>NOTE:</b>IF you use this method with aggregate analysis engine descriptions because it will
+   * <b>not have any effects on the delegate analysis engines</b> of the aggregate. If you want to
+   * recursively bind an external resource to the delegates in an aggregate engine, use e.g.
+   * {@link #bindResource(ResourceSpecifier, String, ExternalResourceDescription)}.
    * 
    * @param aDesc
    *          the specifier to create the binding in.
@@ -1104,7 +1206,7 @@
    * @param aRes
    *          the resource that should be bound.
    */
-  public static void bindResource(ResourceCreationSpecifier aDesc, String aBindTo,
+  public static void bindResourceOnce(ResourceCreationSpecifier aDesc, String aBindTo,
           ExternalResourceDescription aRes) {
     ResourceManagerConfiguration resMgrCfg = aDesc.getResourceManagerConfiguration();
     if (resMgrCfg == null) {
@@ -1112,11 +1214,49 @@
       aDesc.setResourceManagerConfiguration(resMgrCfg);
     }
 
-    bindResource(resMgrCfg, aBindTo, aRes);
+    bindResourceOnce(resMgrCfg, aBindTo, aRes);
   }
 
   /**
-   * Create a new external resource binding.
+   * Create a binding for the given external resource in the given resource manager configuration.
+   * This method <b>does not</b> scan the given external resource for any nested external resources
+   * and <b>does not</b> create bindings for them. Use
+   * {@link #bindResourceOnce(ResourceCreationSpecifier, String, ExternalResourceDescription)} if
+   * you wish to bind nested resources as well.
+   * <p>
+   * <b>NOTE:</b>If you use this method on resource manager configurations of aggregate analysis
+   * engine descriptions because it will <b>not have any effects on the delegate analysis
+   * engines</b> of the aggregate. If you want to recursively bind an external resource to the
+   * delegates in an aggregate engine, use e.g.
+   * {@link #bindResource(ResourceSpecifier, String, ExternalResourceDescription)}.
+   * 
+   * @param aResMgrCfg
+   *          the resource manager to create the binding in.
+   * @param aBindTo
+   *          what key to bind to.
+   * @param aRes
+   *          the resource that should be bound.
+   * @deprecated Use
+   *             {@link #bindResourceOnceWithoutNested(ResourceManagerConfiguration, String, String)}.
+   */
+  @Deprecated
+  public static void bindResource(ResourceManagerConfiguration aResMgrCfg, String aBindTo,
+          String aRes) {
+    bindResourceOnceWithoutNested(aResMgrCfg, aBindTo, aRes);
+  }
+
+  /**
+   * Create a binding for the given external resource in the given resource manager configuration.
+   * This method <b>does not</b> scan the given external resource for any nested external resources
+   * and <b>does not</b> create bindings for them. Use
+   * {@link #bindResourceOnce(ResourceCreationSpecifier, String, ExternalResourceDescription)} if
+   * you wish to bind nested resources as well.
+   * <p>
+   * <b>NOTE:</b>If you use this method on resource manager configurations of aggregate analysis
+   * engine descriptions because it will <b>not have any effects on the delegate analysis
+   * engines</b> of the aggregate. If you want to recursively bind an external resource to the
+   * delegates in an aggregate engine, use e.g.
+   * {@link #bindResource(ResourceSpecifier, String, ExternalResourceDescription)}.
    * 
    * @param aResMgrCfg
    *          the resource manager to create the binding in.
@@ -1125,14 +1265,25 @@
    * @param aRes
    *          the resource that should be bound.
    */
-  public static void bindResource(ResourceManagerConfiguration aResMgrCfg, String aBindTo,
-          String aRes) {
+  public static void bindResourceOnceWithoutNested(ResourceManagerConfiguration aResMgrCfg,
+          String aBindTo, String aRes) {
     ExternalResourceBinding extResBind = createResourceBinding(aBindTo, aRes);
     aResMgrCfg.addExternalResourceBinding(extResBind);
   }
-
+  
+  
   /**
-   * Create a new external resource binding.
+   * Create a binding for the given external resource in resource manager configuration of the given
+   * resource creation specified. If no resource manager configuration exists yet, it is created.
+   * This method <b>does not</b> scan the given external resource for any nested external resources
+   * and <b>does not</b> create bindings for them. Use
+   * {@link #bindResourceOnce(ResourceCreationSpecifier, String, ExternalResourceDescription)} if
+   * you wish to bind nested resources as well.
+   * <p>
+   * <b>NOTE:</b>If you use this method on an aggregate analysis engine description, it will <b>not
+   * have any effects on the delegate analysis engines</b> of the aggregate. If you want to
+   * recursively bind an external resource to the delegates in an aggregate engine, use e.g.
+   * {@link #bindResource(ResourceSpecifier, String, ExternalResourceDescription)}.
    * 
    * @param aDesc
    *          the specifier to create the binding in.
@@ -1141,14 +1292,14 @@
    * @param aRes
    *          the resource that should be bound.
    */
-  public static void bindResource(ResourceCreationSpecifier aDesc, String aBindTo, String aRes) {
+  public static void bindResourceOnceWithoutNested(ResourceCreationSpecifier aDesc, String aBindTo, String aRes) {
     ResourceManagerConfiguration resMgrCfg = aDesc.getResourceManagerConfiguration();
     if (resMgrCfg == null) {
       resMgrCfg = new ResourceManagerConfiguration_impl();
       aDesc.setResourceManagerConfiguration(resMgrCfg);
     }
 
-    bindResource(resMgrCfg, aBindTo, aRes);
+    bindResourceOnceWithoutNested(resMgrCfg, aBindTo, aRes);
   }
 
   static String uniqueResourceKey(String aKey) {
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/factory/FlowControllerFactory.java b/uimafit-core/src/main/java/org/apache/uima/fit/factory/FlowControllerFactory.java
index 2d08bcd..9e986a9 100644
--- a/uimafit-core/src/main/java/org/apache/uima/fit/factory/FlowControllerFactory.java
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/factory/FlowControllerFactory.java
@@ -21,7 +21,7 @@
 import static org.apache.uima.fit.factory.ConfigurationParameterFactory.createConfigurationData;
 import static org.apache.uima.fit.factory.ConfigurationParameterFactory.ensureParametersComeInPairs;
 import static org.apache.uima.fit.factory.ConfigurationParameterFactory.setParameters;
-import static org.apache.uima.fit.factory.ExternalResourceFactory.bindResource;
+import static org.apache.uima.fit.factory.ExternalResourceFactory.bindResourceOnce;
 import static org.apache.uima.fit.factory.ExternalResourceFactory.createResourceDependencies;
 
 import java.util.Map;
@@ -130,7 +130,7 @@
     // Bind External Resources
     if (externalResources != null) {
       for (Entry<String, ExternalResourceDescription> e : externalResources.entrySet()) {
-        bindResource(desc, e.getKey(), e.getValue());
+        bindResourceOnce(desc, e.getKey(), e.getValue());
       }
     }
 
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/util/FSCollectionFactory.java b/uimafit-core/src/main/java/org/apache/uima/fit/util/FSCollectionFactory.java
index 67f1d73..40e39a6 100644
--- a/uimafit-core/src/main/java/org/apache/uima/fit/util/FSCollectionFactory.java
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/util/FSCollectionFactory.java
@@ -100,9 +100,7 @@
     if (ts.subsumes(cas.getAnnotationType(), type)) {
       return (List) create(cas.getAnnotationIndex(type));
     } else {
-      Collection<FeatureStructure> result = create(cas.getIndexRepository().getAllIndexedFS(type));
-      return asList(result.toArray(new FeatureStructure[result.size()]));
-      // return (List) cas.select(type).asList(); - This call is still buggy in UIMA 3.0.0
+      return (List) cas.select(type).asList();
     }
   }
 
@@ -133,10 +131,7 @@
    */
   @Deprecated
   public static <T extends AnnotationFS> List<T> create(AnnotationIndex<T> aIndex) {
-    // Was: return new AnnotationIndexAdapter<T>(aIndex);
-    // return aIndex.select().asList(); // That call is still buggy in UIMA 3.0.0
-    Collection<T> result = new AnnotationIndexAdapter<T>(aIndex);
-    return (List) asList(result.toArray());
+    return aIndex.select().asList();
   }
 
   /**
@@ -164,7 +159,7 @@
    */
   @SuppressWarnings({ "unchecked", "rawtypes" })
   public static <T extends TOP> List<T> create(ArrayFS aArray, Class<T> aType) {
-    return (List) create(aArray, CasUtil.getType(aArray.getCAS(), aType));
+    return create(aArray, CasUtil.getType(aArray.getCAS(), aType));
   }
 
   /**
@@ -553,7 +548,7 @@
    * @return a new collection of all feature structures of the given type.
    */
   public static <T extends TOP> Collection<T> create(FSList<T> aList, Class<? extends T> aType) {
-    return (Collection<T>) create(aList, CasUtil.getType(aList.getCAS(), aType));
+    return create(aList, CasUtil.getType(aList.getCAS(), aType));
   }
 
   // Using TOP here because FSList is only available in the JCas.
diff --git a/uimafit-core/src/test/java/org/apache/uima/fit/factory/AnalysisEngineFactoryExternalResourceTest.java b/uimafit-core/src/test/java/org/apache/uima/fit/factory/AnalysisEngineFactoryExternalResourceTest.java
index 4f6808c..5d446be 100644
--- a/uimafit-core/src/test/java/org/apache/uima/fit/factory/AnalysisEngineFactoryExternalResourceTest.java
+++ b/uimafit-core/src/test/java/org/apache/uima/fit/factory/AnalysisEngineFactoryExternalResourceTest.java
@@ -21,8 +21,9 @@
 
 import static org.apache.uima.fit.factory.AnalysisEngineFactory.createEngine;
 import static org.apache.uima.fit.factory.AnalysisEngineFactory.createEngineDescription;
-import static org.apache.uima.fit.factory.ExternalResourceFactory.bindResource;
-import static org.apache.uima.fit.factory.ExternalResourceFactory.*;
+import static org.apache.uima.fit.factory.ExternalResourceFactory.bindResourceOnce;
+import static org.apache.uima.fit.factory.ExternalResourceFactory.createResourceDescription;
+import static org.apache.uima.fit.factory.ExternalResourceFactory.createSharedResourceDescription;
 import static org.junit.Assert.assertNotNull;
 
 import java.io.ByteArrayInputStream;
@@ -188,7 +189,7 @@
     ExternalResourceDescription resDesc = createResourceDescription(
             TestExternalResource2.class, TestExternalResource.PARAM_VALUE,
             TestExternalResource.EXPECTED_VALUE);
-    bindResource(resDesc, TestExternalResource2.PARAM_RESOURCE, resDesc);
+    bindResourceOnce(resDesc, TestExternalResource2.PARAM_RESOURCE, resDesc);
 
     AnalysisEngineDescription aeDesc = saveLoad(createEngineDescription(
             TestAnalysisEngineWithResource.class, TestAnalysisEngineWithResource.PARAM_RESOURCE,
@@ -208,7 +209,7 @@
     ExternalResourceDescription resDesc = createResourceDescription(
             TestExternalResource2.class, TestExternalResource.PARAM_VALUE,
             TestExternalResource.EXPECTED_VALUE);
-    bindResource(resDesc, TestExternalResource2.PARAM_RESOURCE, resDesc);
+    bindResourceOnce(resDesc, TestExternalResource2.PARAM_RESOURCE, resDesc);
 
     AnalysisEngineDescription aeDesc1 = saveLoad(createEngineDescription(
             TestAnalysisEngineWithResource.class, TestAnalysisEngineWithResource.PARAM_RESOURCE,
@@ -309,7 +310,7 @@
             "http://dumm.my", TestSharedResourceObject2.class,
             TestSharedResourceObject2.PARAM_VALUE, TestSharedResourceObject2.EXPECTED_VALUE);
 
-    bindResource(res1, TestSharedResourceObject2.PARAM_RESOURCE, res2);
+    bindResourceOnce(res1, TestSharedResourceObject2.PARAM_RESOURCE, res2);
     
     AnalysisEngineDescription aeDesc =createEngineDescription(
             TestAnalysisEngineWithSharedResourceObject.class,
@@ -329,7 +330,7 @@
     ExternalResourceDescription resDesc = createSharedResourceDescription(
             "http://dumm.my", TestSharedResourceObject2.class,
             TestSharedResourceObject.PARAM_VALUE, TestSharedResourceObject.EXPECTED_VALUE);
-    bindResource(resDesc, TestSharedResourceObject2.PARAM_RESOURCE, resDesc);
+    bindResourceOnce(resDesc, TestSharedResourceObject2.PARAM_RESOURCE, resDesc);
 
     AnalysisEngineDescription aeDesc = saveLoad(createEngineDescription(
             TestAnalysisEngineWithSharedResourceObject.class,
diff --git a/uimafit-core/src/test/java/org/apache/uima/fit/factory/AnalysisEngineFactoryTest.java b/uimafit-core/src/test/java/org/apache/uima/fit/factory/AnalysisEngineFactoryTest.java
index 6cb703a..e5ee069 100644
--- a/uimafit-core/src/test/java/org/apache/uima/fit/factory/AnalysisEngineFactoryTest.java
+++ b/uimafit-core/src/test/java/org/apache/uima/fit/factory/AnalysisEngineFactoryTest.java
@@ -21,6 +21,9 @@
 import static java.util.Arrays.asList;
 import static org.apache.uima.fit.factory.AnalysisEngineFactory.createEngine;
 import static org.apache.uima.fit.factory.AnalysisEngineFactory.createEngineDescription;
+import static org.apache.uima.fit.factory.AnalysisEngineFactory.createEngineFromPath;
+import static org.apache.uima.fit.factory.TypeSystemDescriptionFactory.createTypeSystemDescription;
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -60,6 +63,7 @@
 import org.apache.uima.fit.factory.testAes.SerializationTestAnnotator;
 import org.apache.uima.fit.factory.testAes.ViewNames;
 import org.apache.uima.fit.pipeline.SimplePipeline;
+import org.apache.uima.fit.type.AnalyzedText;
 import org.apache.uima.fit.type.Sentence;
 import org.apache.uima.fit.type.Token;
 import org.apache.uima.fit.util.CasIOUtil;
@@ -70,25 +74,19 @@
 import org.apache.uima.pear.tools.PackageInstaller;
 import org.apache.uima.resource.PearSpecifier;
 import org.apache.uima.resource.ResourceInitializationException;
-import org.apache.uima.resource.ResourceManager;
-import org.apache.uima.resource.ResourceSpecifier;
 import org.apache.uima.resource.metadata.Capability;
 import org.apache.uima.resource.metadata.ConfigurationParameter;
 import org.apache.uima.resource.metadata.ConfigurationParameterDeclarations;
 import org.apache.uima.resource.metadata.ConfigurationParameterSettings;
+import org.apache.uima.resource.metadata.FsIndexDescription;
 import org.apache.uima.resource.metadata.ProcessingResourceMetaData;
 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.util.XMLInputSource;
 import org.custommonkey.xmlunit.XMLAssert;
-import org.custommonkey.xmlunit.XMLUnit;
-import org.junit.Assert;
 import org.junit.Test;
 
-/**
- */
-
 public class AnalysisEngineFactoryTest extends ComponentTestBase {
 
   @Test
@@ -106,8 +104,8 @@
 
   @Test
   public void testCreateAnalysisEngineFromPath() throws UIMAException, IOException {
-    AnalysisEngine engine = AnalysisEngineFactory
-            .createEngineFromPath("src/main/resources/org/apache/uima/fit/component/NoOpAnnotator.xml");
+    AnalysisEngine engine = createEngineFromPath(
+            "src/main/resources/org/apache/uima/fit/component/NoOpAnnotator.xml");
     assertNotNull(engine);
   }
 
@@ -590,4 +588,33 @@
     cas.setDocumentLanguage("en");
     ae.process(cas);
   }
+  
+  @Test
+  public void thatCreateEngineDescriptorAutoDetectionWorks() throws Exception
+  {
+    AnalysisEngineDescription aed = createEngineDescription(NoOpAnnotator.class);
+    
+    TypeSystemDescription tsd = createTypeSystemDescription();
+    assertThat(tsd.getType(Token.class.getName()))
+        .as("Token type auto-detection")
+        .isNotNull();
+    assertThat(tsd.getType(Sentence.class.getName()))
+        .as("Sentence type auto-detection")
+        .isNotNull();
+    assertThat(tsd.getType(AnalyzedText.class.getName()))
+        .as("AnalyzedText type auto-detection")
+        .isNotNull();
+
+    TypePriorityList[] typePrioritiesLists = typePriorities.getPriorityLists();
+    assertThat(typePrioritiesLists.length).isEqualTo(1);
+    assertThat(typePrioritiesLists[0].getTypes())
+        .as("Type priorities auto-detection")
+        .containsExactly(Sentence.class.getName(), AnalyzedText.class.getName(), Token.class.getName());
+
+    FsIndexDescription[] indexes = aed.getAnalysisEngineMetaData().getFsIndexCollection().getFsIndexes();
+    assertThat(indexes.length).isEqualTo(1);
+    assertThat(indexes[0])
+        .extracting(FsIndexDescription::getLabel, FsIndexDescription::getTypeName, FsIndexDescription::getKind)
+        .containsExactly("Automatically Scanned Index", Token.class.getName(), FsIndexDescription.KIND_SORTED);
+  }
 }
diff --git a/uimafit-core/src/test/java/org/apache/uima/fit/factory/CollectionReaderFactoryTest.java b/uimafit-core/src/test/java/org/apache/uima/fit/factory/CollectionReaderFactoryTest.java
index a43eba7..e2f1a73 100644
--- a/uimafit-core/src/test/java/org/apache/uima/fit/factory/CollectionReaderFactoryTest.java
+++ b/uimafit-core/src/test/java/org/apache/uima/fit/factory/CollectionReaderFactoryTest.java
@@ -18,6 +18,11 @@
  */
 package org.apache.uima.fit.factory;
 
+import static org.apache.uima.fit.factory.CollectionReaderFactory.createReader;
+import static org.apache.uima.fit.factory.CollectionReaderFactory.createReaderDescription;
+import static org.apache.uima.fit.factory.CollectionReaderFactory.createReaderFromPath;
+import static org.apache.uima.fit.factory.TypeSystemDescriptionFactory.createTypeSystemDescription;
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
@@ -33,24 +38,26 @@
 import org.apache.uima.fit.descriptor.ResourceMetaData;
 import org.apache.uima.fit.factory.testCrs.SingleFileXReader;
 import org.apache.uima.fit.pipeline.JCasIterator;
+import org.apache.uima.fit.type.AnalyzedText;
+import org.apache.uima.fit.type.Sentence;
 import org.apache.uima.fit.type.Token;
 import org.apache.uima.fit.util.JCasUtil;
 import org.apache.uima.resource.ResourceInitializationException;
+import org.apache.uima.resource.metadata.FsIndexDescription;
+import org.apache.uima.resource.metadata.TypePriorityList;
+import org.apache.uima.resource.metadata.TypeSystemDescription;
 import org.apache.uima.util.Progress;
 import org.junit.Test;
 
-/**
- */
-
 public class CollectionReaderFactoryTest extends ComponentTestBase {
 
   @Test
   public void testCreateCollectionReader() throws UIMAException, IOException {
 
     CollectionReader reader = CollectionReaderFactory.createReader(
-            SingleFileXReader.class, typeSystemDescription, SingleFileXReader.PARAM_FILE_NAME,
-            "src/test/resources/data/docs/test.xmi", SingleFileXReader.PARAM_XML_SCHEME,
-            SingleFileXReader.XMI);
+            SingleFileXReader.class, typeSystemDescription, 
+            SingleFileXReader.PARAM_FILE_NAME, "src/test/resources/data/docs/test.xmi", 
+            SingleFileXReader.PARAM_XML_SCHEME, SingleFileXReader.XMI);
 
     JCasIterator jCasIterator = new JCasIterator(reader, typeSystemDescription);
     jCas = jCasIterator.next();
@@ -61,7 +68,7 @@
     assertEquals("A", token.getPos());
     assertEquals("all", token.getStem());
 
-    reader = CollectionReaderFactory.createReader(
+    reader = createReader(
             "org.apache.uima.fit.factory.testCrs.SingleFileXReader",
             SingleFileXReader.PARAM_FILE_NAME, "src/test/resources/data/docs/test.xmi",
             SingleFileXReader.PARAM_XML_SCHEME, SingleFileXReader.XMI);
@@ -75,7 +82,7 @@
     assertEquals(".", token.getPos());
     assertEquals(".", token.getStem());
 
-    reader = CollectionReaderFactory.createReaderFromPath(
+    reader = createReaderFromPath(
             "src/test/resources/org/apache/uima/fit/factory/testCrs/SingleFileXReader.xml",
             SingleFileXReader.PARAM_FILE_NAME, "src/test/resources/data/docs/test.xmi",
             SingleFileXReader.PARAM_XML_SCHEME, SingleFileXReader.XMI);
@@ -88,7 +95,6 @@
     assertEquals("friends", token.getCoveredText());
     assertEquals("F", token.getPos());
     assertEquals("friend", token.getStem());
-
   }
 
   @Test
@@ -103,6 +109,35 @@
   }
 
   @Test
+  public void thatCreateReaderDescriptorAutoDetectionWorks() throws Exception
+  {
+    CollectionReaderDescription aed = createReaderDescription(TestCR.class);
+    
+    TypeSystemDescription tsd = createTypeSystemDescription();
+    assertThat(tsd.getType(Token.class.getName()))
+        .as("Token type auto-detection")
+        .isNotNull();
+    assertThat(tsd.getType(Sentence.class.getName()))
+        .as("Sentence type auto-detection")
+        .isNotNull();
+    assertThat(tsd.getType(AnalyzedText.class.getName()))
+        .as("AnalyzedText type auto-detection")
+        .isNotNull();
+
+    TypePriorityList[] typePrioritiesLists = typePriorities.getPriorityLists();
+    assertThat(typePrioritiesLists.length).isEqualTo(1);
+    assertThat(typePrioritiesLists[0].getTypes())
+        .as("Type priorities auto-detection")
+        .containsExactly(Sentence.class.getName(), AnalyzedText.class.getName(), Token.class.getName());
+
+    FsIndexDescription[] indexes = aed.getCollectionReaderMetaData().getFsIndexCollection().getFsIndexes();
+    assertThat(indexes.length).isEqualTo(1);
+    assertThat(indexes[0])
+        .extracting(FsIndexDescription::getLabel, FsIndexDescription::getTypeName, FsIndexDescription::getKind)
+        .containsExactly("Automatically Scanned Index", Token.class.getName(), FsIndexDescription.KIND_SORTED);
+  }
+
+  @Test
   public void testResourceMetaData() throws Exception
   {
     CollectionReaderDescription desc = CollectionReaderFactory
@@ -117,6 +152,8 @@
     assertEquals("uimaFIT", meta.getVendor());
   }
 
+  
+  
   @ResourceMetaData(name = "dummy", version = "1.0", description = "Just a dummy", copyright = "ASL 2.0", vendor = "uimaFIT")
   private class TestCR extends CollectionReader_ImplBase {
 
@@ -124,19 +161,23 @@
       // do not instantiate
     }
 
+    @Override
     public void getNext(CAS acas) throws IOException, CollectionException {
       // Not required for test
     }
 
+    @Override
     public void close() throws IOException {
       // Not required for test
     }
 
+    @Override
     public Progress[] getProgress() {
       // Not required for test
       return null;
     }
 
+    @Override
     public boolean hasNext() throws IOException, CollectionException {
       // Not required for test
       return false;
diff --git a/uimafit-core/src/test/java/org/apache/uima/fit/factory/ExternalResourceFactoryTest.java b/uimafit-core/src/test/java/org/apache/uima/fit/factory/ExternalResourceFactoryTest.java
index 90a9c66..6bc7b2f 100644
--- a/uimafit-core/src/test/java/org/apache/uima/fit/factory/ExternalResourceFactoryTest.java
+++ b/uimafit-core/src/test/java/org/apache/uima/fit/factory/ExternalResourceFactoryTest.java
@@ -23,8 +23,12 @@
 import static org.apache.uima.fit.factory.AnalysisEngineFactory.createEngine;
 import static org.apache.uima.fit.factory.AnalysisEngineFactory.createEngineDescription;
 import static org.apache.uima.fit.factory.ExternalResourceFactory.bindResource;
-import static org.apache.uima.fit.factory.ExternalResourceFactory.bindResource;
-import static org.apache.uima.fit.factory.ExternalResourceFactory.*;
+import static org.apache.uima.fit.factory.ExternalResourceFactory.bindResourceOnceWithoutNested;
+import static org.apache.uima.fit.factory.ExternalResourceFactory.createNamedResourceDescription;
+import static org.apache.uima.fit.factory.ExternalResourceFactory.createResourceDescription;
+import static org.apache.uima.fit.factory.ExternalResourceFactory.createSharedResourceDescription;
+import static org.apache.uima.fit.factory.JCasFactory.createJCas;
+import static org.apache.uima.fit.pipeline.SimplePipeline.runPipeline;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -58,6 +62,8 @@
 import org.apache.uima.fit.factory.locator.JndiResourceLocator;
 import org.apache.uima.fit.internal.ResourceManagerFactory;
 import org.apache.uima.fit.pipeline.SimplePipeline;
+import org.apache.uima.fit.type.AnalyzedText;
+import org.apache.uima.fit.util.JCasUtil;
 import org.apache.uima.fit.util.SimpleNamedResourceManager;
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.resource.DataResource;
@@ -167,8 +173,8 @@
     bindResources(desc);
 
     // Bind external resources for DummyAE2 - necessary because autowiring is disabled
-    bindResource(desc, DummyAE2.RES_INJECTED_POJO1, "pojoName1");
-    bindResource(desc, DummyAE2.RES_INJECTED_POJO2, "pojoName2");
+    bindResourceOnceWithoutNested(desc, DummyAE2.RES_INJECTED_POJO1, "pojoName1");
+    bindResourceOnceWithoutNested(desc, DummyAE2.RES_INJECTED_POJO2, "pojoName2");
 
     // Create a custom resource manager that allows to inject any Java object as an external
     // dependency
@@ -349,7 +355,61 @@
     ae.process(ae.newJCas());
     ae.collectionProcessComplete();
   }
-  
+
+  @Test
+  public void testNestedAggregateBinding() throws Exception {
+    ExternalResourceDescription resourceDescription = createSharedResourceDescription("",
+            DummyResource.class);
+
+    AggregateBuilder builder = new AggregateBuilder();
+    builder.add(createEngineDescription(ResourceDependent.class));
+    AnalysisEngineDescription aggregateDescription = builder.createAggregateDescription();
+
+    bindResource(aggregateDescription, DummyResource.RESOURCE_KEY, resourceDescription);
+
+    JCas jCas = createJCas();
+    jCas.setDocumentText("Hello");
+
+    runPipeline(jCas, aggregateDescription);
+    int count = 0;
+    for (AnalyzedText annotation : JCasUtil.select(jCas, AnalyzedText.class)) {
+      assertEquals("World", annotation.getText());
+      count++;
+    }
+
+    assertEquals(1, count);
+  }
+
+  public static class DummyResource implements SharedResourceObject {
+
+    public static final String RESOURCE_KEY = "DummyResource";
+
+    public DummyResource() {
+    }
+
+    @Override
+    public void load(DataResource aData) throws ResourceInitializationException {
+      // Nothing to do
+    }
+
+    public String getText() {
+      return "World";
+    }
+  }
+
+  public static class ResourceDependent extends JCasAnnotator_ImplBase {
+
+      @ExternalResource(key = DummyResource.RESOURCE_KEY)
+      private DummyResource dummyResource;
+
+      @Override
+      public void process(JCas aJCas) throws AnalysisEngineProcessException {
+        // Just marking up that the AE was executed as expected, so that it can be verified.
+        AnalyzedText annotation = new AnalyzedText(aJCas, 0, aJCas.getDocumentText().length());
+        annotation.setText(dummyResource.getText());
+        annotation.addToIndexes();
+      }
+  }
   
   private static void bindResources(AnalysisEngineDescription desc) throws Exception {
     bindResource(desc, ResourceWithAssert.class);
diff --git a/uimafit-core/src/test/java/org/apache/uima/fit/factory/TypePrioritiesFactoryTest.java b/uimafit-core/src/test/java/org/apache/uima/fit/factory/TypePrioritiesFactoryTest.java
index e50a6d7..8d2978a 100644
--- a/uimafit-core/src/test/java/org/apache/uima/fit/factory/TypePrioritiesFactoryTest.java
+++ b/uimafit-core/src/test/java/org/apache/uima/fit/factory/TypePrioritiesFactoryTest.java
@@ -28,6 +28,7 @@
 import org.apache.uima.fit.type.Token;
 import org.apache.uima.jcas.tcas.Annotation;
 import org.apache.uima.resource.metadata.TypePriorities;
+import org.apache.uima.resource.metadata.TypePriorityList;
 import org.apache.uima.util.CasCreationUtils;
 import org.junit.Test;
 
@@ -65,8 +66,10 @@
   public void testAutoDetectTypePriorities() throws Exception {
     TypePriorities prio = createTypePriorities();
 
-    assertThat(prio.getPriorityLists()).hasSize(1);
-    assertThat(prio.getPriorityLists()[0].getTypes()).containsExactly(Sentence.class.getName(),
-            Token.class.getName());
+    TypePriorityList[] typePrioritiesLists = prio.getPriorityLists();
+    assertThat(typePrioritiesLists.length).isEqualTo(1);
+    assertThat(typePrioritiesLists[0].getTypes())
+        .as("Type priorities auto-detection")
+        .containsExactly(Sentence.class.getName(), Token.class.getName());
   }
 }
diff --git a/uimafit-cpe/pom.xml b/uimafit-cpe/pom.xml
index 1a35661..919032a 100644
--- a/uimafit-cpe/pom.xml
+++ b/uimafit-cpe/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.uima</groupId>
     <artifactId>uimafit-parent</artifactId>
-    <version>3.0.1-SNAPSHOT</version>
+    <version>3.1.0-SNAPSHOT</version>
     <relativePath>../uimafit-parent</relativePath>
   </parent>
   <artifactId>uimafit-cpe</artifactId>
@@ -31,7 +31,7 @@
     <dependency>
       <groupId>org.apache.uima</groupId>
       <artifactId>uimafit-core</artifactId>
-      <version>3.0.1-SNAPSHOT</version>
+      <version>3.1.0-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.apache.uima</groupId>
diff --git a/uimafit-cpe/src/main/java/org/apache/uima/fit/cpe/CpeBuilder.java b/uimafit-cpe/src/main/java/org/apache/uima/fit/cpe/CpeBuilder.java
index 1ba8ce4..a0f9c60 100644
--- a/uimafit-cpe/src/main/java/org/apache/uima/fit/cpe/CpeBuilder.java
+++ b/uimafit-cpe/src/main/java/org/apache/uima/fit/cpe/CpeBuilder.java
@@ -25,12 +25,14 @@
 import static org.apache.uima.collection.impl.metadata.cpe.CpeDescriptorFactory.produceDescriptor;
 
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.net.URL;
+import java.nio.file.Files;
 import java.util.Map;
 
+import javax.xml.transform.OutputKeys;
+
 import org.apache.uima.analysis_engine.AnalysisEngineDescription;
 import org.apache.uima.analysis_engine.metadata.FixedFlow;
 import org.apache.uima.collection.CollectionProcessingEngine;
@@ -48,6 +50,8 @@
 import org.apache.uima.resource.ResourceManager;
 import org.apache.uima.resource.ResourceSpecifier;
 import org.apache.uima.util.InvalidXMLException;
+import org.apache.uima.util.XMLSerializer;
+import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
 
 /**
@@ -177,8 +181,14 @@
     File tempDesc = File.createTempFile("desc", ".xml");
     tempDesc.deleteOnExit();
 
-    try (OutputStream os = new FileOutputStream(tempDesc)) {
-      resource.toXML(os);
+    // Write the descriptor using XML 1.1 to allow a wider range of characters for parameter values
+    try (OutputStream os = Files.newOutputStream(tempDesc.toPath())) {
+      XMLSerializer sax2xml = new XMLSerializer(os, true);
+      sax2xml.setOutputProperty(OutputKeys.VERSION, "1.1");
+      ContentHandler contentHandler = sax2xml.getContentHandler();
+      contentHandler.startDocument();
+      resource.toXML(sax2xml.getContentHandler(), true);
+      contentHandler.endDocument();
     }
 
     return tempDesc;
diff --git a/uimafit-cpe/src/main/java/org/apache/uima/fit/cpe/CpePipeline.java b/uimafit-cpe/src/main/java/org/apache/uima/fit/cpe/CpePipeline.java
index 9089937..7cce0b2 100644
--- a/uimafit-cpe/src/main/java/org/apache/uima/fit/cpe/CpePipeline.java
+++ b/uimafit-cpe/src/main/java/org/apache/uima/fit/cpe/CpePipeline.java
@@ -18,6 +18,7 @@
  */
 package org.apache.uima.fit.cpe;
 
+import static java.lang.Runtime.getRuntime;
 import static org.apache.uima.fit.factory.AnalysisEngineFactory.createEngineDescription;
 
 import java.io.IOException;
@@ -36,16 +37,51 @@
 import org.apache.uima.util.InvalidXMLException;
 import org.xml.sax.SAXException;
 
-/**
- */
 public final class CpePipeline {
   private CpePipeline() {
     // No instances
   }
   
   /**
+   * Run the CollectionReader and AnalysisEngines as a multi-threaded pipeline. This call uses
+   * a number of threads equal to the number of available processors (as reported by Java, so 
+   * usually boiling down to cores) minus 1 - minimum of 1.
+   * 
+   * @param readerDesc
+   *          The CollectionReader that loads the documents into the CAS.
+   * @param descs
+   *          Primitive AnalysisEngineDescriptions that process the CAS, in order. If you have a mix
+   *          of primitive and aggregate engines, then please create the AnalysisEngines yourself
+   *          and call the other runPipeline method.
+   * @throws SAXException
+   *           if there was a XML-related problem materializing the component descriptors that are
+   *           referenced from the CPE descriptor
+   * @throws InvalidXMLException
+   *           if there was a XML-related problem materializing the component descriptors that are
+   *           referenced from the CPE descriptor
+   * @throws IOException
+   *           if there was a I/O-related problem materializing the component descriptors that are
+   *           referenced from the CPE descriptor
+   * @throws CpeDescriptorException
+   *           if there was a problem configuring the CPE descriptor
+   * @throws ResourceInitializationException
+   *           if there was a problem initializing or running the CPE.
+   * @throws AnalysisEngineProcessException
+   *           if there was a problem initializing or running the CPE.
+   */
+  public static void runPipeline(final CollectionReaderDescription readerDesc,
+          final AnalysisEngineDescription... descs)
+          throws SAXException, CpeDescriptorException, IOException, ResourceInitializationException,
+          InvalidXMLException, AnalysisEngineProcessException {
+
+    runPipeline(Math.max(1, getRuntime().availableProcessors() - 1), readerDesc, descs);
+  }
+
+  /**
    * Run the CollectionReader and AnalysisEngines as a multi-threaded pipeline.
    * 
+   * @param parallelism
+   *          Number of threads to use when running the analysis engines in the CPE.
    * @param readerDesc
    *          The CollectionReader that loads the documents into the CAS.
    * @param descs
@@ -67,8 +103,8 @@
    * @throws AnalysisEngineProcessException 
    *           if there was a problem running the CPE.
    */
-  public static void runPipeline(final CollectionReaderDescription readerDesc,
-          final AnalysisEngineDescription... descs)
+  public static void runPipeline(final int parallelism,
+          final CollectionReaderDescription readerDesc, final AnalysisEngineDescription... descs)
           throws SAXException, CpeDescriptorException, IOException, ResourceInitializationException,
           InvalidXMLException, AnalysisEngineProcessException {
     // Create AAE
diff --git a/uimafit-docbook/pom.xml b/uimafit-docbook/pom.xml
index dd70617..09327c2 100644
--- a/uimafit-docbook/pom.xml
+++ b/uimafit-docbook/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.uima</groupId>
     <artifactId>uimafit-parent</artifactId>
-    <version>3.0.1-SNAPSHOT</version>
+    <version>3.1.0-SNAPSHOT</version>
     <relativePath>../uimafit-parent</relativePath>
   </parent>
   <artifactId>uimafit-docbook</artifactId>
diff --git a/uimafit-docbook/src/docbook/tools.uimafit.migration.xml b/uimafit-docbook/src/docbook/tools.uimafit.migration.xml
index 9da8ac0..8a3091b 100644
--- a/uimafit-docbook/src/docbook/tools.uimafit.migration.xml
+++ b/uimafit-docbook/src/docbook/tools.uimafit.migration.xml
@@ -20,6 +20,49 @@
   <title>Migration Guide</title>
   <para>This section provides helpful information on incompatible changes between versions.</para>
   <section>
+    <title>Version 3.0.x to 3.1.x</title>
+    <formalpara>
+      <title>Changes to ExternalResourceFactory</title>
+      <para>The renaming of methods in the <literal>ExternalResourceFactory</literal> had
+      unfortunately introduced another name clash between unrelated methods. To fix this
+      clash, the following methods have been renamed from <literal>bindResource</literal> to 
+      <literal>bindResourceOnce</literal>:
+        <itemizedlist>
+          <listitem><para>
+            <literal>void bindResource(ResourceCreationSpecifier aDesc, String aBindTo, ExternalResourceDescription aRes)</literal>
+            was <emphasis role="strong">removed</emphasis> and replaced by
+            <literal>void bindResourceOnce(ResourceCreationSpecifier aDesc, String aBindTo, ExternalResourceDescription aRes)</literal>
+          </para></listitem>
+          <listitem><para>
+            <literal>void bindResource(ExternalResourceDescription aRes, String aBindTo, ExternalResourceDescription aNestedRes)</literal>
+            was deprecated and replaced by
+            <literal>void bindResourceOnce(ExternalResourceDescription aRes, String aBindTo, ExternalResourceDescription aNestedRes)</literal>
+          </para></listitem>
+          <listitem><para>
+            <literal>void bindResource(ResourceManagerConfiguration aResMgrCfg, String aBindTo, ExternalResourceDescription aRes)</literal>
+            was deprecated and replaced by
+            <literal>void bindResourceOnce(ResourceManagerConfiguration aResMgrCfg, String aBindTo, ExternalResourceDescription aRes)</literal>
+          </para></listitem>
+          <listitem><para>
+            <literal>void bindResource(ResourceCreationSpecifier aDesc, String aBindTo, String aRes)</literal>
+            was <emphasis role="strong">removed</emphasis> and replaced by
+            <literal>void bindResourceOnceWithoutNested(ResourceCreationSpecifier aDesc, String aBindTo, String aRes)</literal>
+          </para></listitem>
+          <listitem><para>
+            <literal>void bindResource(ResourceManagerConfiguration aResMgrCfg, String aBindTo, String aRes)</literal>
+            was deprecated and replaced by
+            <literal>void bindResourceOnceWithoutNested(ResourceManagerConfiguration aResMgrCfg, String aBindTo, String aRes)</literal>
+          </para></listitem>
+          <listitem><para>
+            <literal>void bindResource(ResourceSpecifier aDesc, String aKey, String aUrl)</literal>
+            was deprecated and replaced by
+            <literal>void bindResourceUsingUrl(ResourceSpecifier aDesc, String aKey, String aUrl)</literal>
+          </para></listitem>
+        </itemizedlist>
+      </para>
+    </formalpara>
+  </section>
+  <section>
     <title>Version 2.x to 3.x</title>
     <formalpara>
       <title>Legacy support module removed</title>
@@ -55,6 +98,21 @@
       file included in the release.</para>
     </formalpara>
     <formalpara>
+      <title>Changes to ExternalResourceFactory</title>
+      <para>Most methods in the <literal>ExternalResourceFactory</literal> have seen changes to 
+      their names and signature to avoid problematic ambiguities as well as to be shorter. In 
+      general, the <literal>External</literal> component of the method names was either
+      removed or replaced. So most methods called <literal>createExternalResourceDescription</literal>
+      are now called <literal>createResourceDescription</literal>. However, some have also been 
+      given a more specific name and/or a slightly different order of parameters. For example, this
+      method</para>
+      <programlisting>public static ExternalResourceDescription createExternalResourceDescription(
+  Class&lt;? extends SharedResourceObject&gt; aInterface, String aUrl, Object... aParams)</programlisting>
+      <para>was changed to</para>
+      <programlisting>public static ExternalResourceDescription createSharedResourceDescription(
+  String aUrl, Class&lt;? extends SharedResourceObject&gt; aInterface, Object... aParams)</programlisting>
+    </formalpara>
+    <formalpara>
       <title>Changes to logging</title>
       <para>UIMA v3 has is using SLF4J. As a consequence, the <literal>ExtendedLogger</literal>
       which uimaFIT had returned on calls to <literal>getLogger()</literal> has been removed
diff --git a/uimafit-examples/pom.xml b/uimafit-examples/pom.xml
index ca1564a..86d6175 100644
--- a/uimafit-examples/pom.xml
+++ b/uimafit-examples/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.apache.uima</groupId>
     <artifactId>uimafit-parent</artifactId>
-    <version>3.0.1-SNAPSHOT</version>
+    <version>3.1.0-SNAPSHOT</version>
     <relativePath>../uimafit-parent</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -33,7 +33,7 @@
     <dependency>
       <groupId>org.apache.uima</groupId>
       <artifactId>uimafit-core</artifactId>
-      <version>3.0.1-SNAPSHOT</version>
+      <version>3.1.0-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.apache.uima</groupId>
diff --git a/uimafit-maven-plugin/pom.xml b/uimafit-maven-plugin/pom.xml
index 9bc6b41..5a40efe 100644
--- a/uimafit-maven-plugin/pom.xml
+++ b/uimafit-maven-plugin/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>org.apache.uima</groupId>
     <artifactId>uimafit-parent</artifactId>
-    <version>3.0.1-SNAPSHOT</version>
+    <version>3.1.0-SNAPSHOT</version>
     <relativePath>../uimafit-parent</relativePath>
   </parent>
   <artifactId>uimafit-maven-plugin</artifactId>
@@ -58,7 +58,7 @@
     <dependency>
       <groupId>org.apache.uima</groupId>
       <artifactId>uimafit-core</artifactId>
-      <version>3.0.1-SNAPSHOT</version>
+      <version>3.1.0-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.javassist</groupId>
diff --git a/uimafit-parent/pom.xml b/uimafit-parent/pom.xml
index bf6eaca..2f03db4 100644
--- a/uimafit-parent/pom.xml
+++ b/uimafit-parent/pom.xml
@@ -23,17 +23,17 @@
     <groupId>org.apache.uima</groupId>
     <artifactId>parent-pom</artifactId>
     <relativePath />
-    <version>14-SNAPSHOT</version>
+    <version>13</version>
   </parent>
   <artifactId>uimafit-parent</artifactId>
-  <version>3.0.1-SNAPSHOT</version>
+  <version>3.1.0-SNAPSHOT</version>
   <packaging>pom</packaging>
   <name>Apache UIMA uimaFIT - Parent</name>
   <url>${uimaWebsiteUrl}</url>
   <inceptionYear>2012</inceptionYear>
   <properties>
-    <spring.version>4.3.22.RELEASE</spring.version>
-    <uima.version>3.0.2</uima.version>
+    <spring.version>4.3.26.RELEASE</spring.version>
+    <uima.version>3.1.1</uima.version>
     <slf4j.version>1.7.26</slf4j.version>
     <maven.compiler.source>1.8</maven.compiler.source>
     <maven.compiler.target>1.8</maven.compiler.target>
@@ -331,6 +331,42 @@
                     <ignore />
                   </action>
                 </pluginExecution>
+                <!-- *********************************************** -->
+                <!-- The Maven Dev Connector for Eclipse m2e is no   -->
+                <!-- longer maintained. We copy the relevant part    --> 
+                <!-- of the lifecycle mapping for the                -->
+                <!-- maven-plugin-plugin here.                       -->
+                <!--                                                 -->
+                <!-- See https://github.com/ifedorenko/com.ifedorenko.m2e.mavendev/blob/master/com.ifedorenko.m2e.mavendev/lifecycle-mapping-metadata.xml -->
+                <!-- *********************************************** -->
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-plugin-plugin</artifactId>
+                    <versionRange>[3.5.2,)</versionRange>
+                    <goals>
+                      <goal>descriptor</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <execute>
+                      <runOnIncremental>false</runOnIncremental>
+                    </execute>
+                  </action>
+                </pluginExecution>
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-plugin-plugin</artifactId>
+                    <versionRange>[3.5.2,)</versionRange>
+                    <goals>
+                      <goal>helpmojo</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <ignore />
+                  </action>
+                </pluginExecution>
               </pluginExecutions>
             </lifecycleMappingMetadata>
           </configuration>
@@ -338,4 +374,31 @@
       </plugins>
     </pluginManagement>
   </build>
+  
+  <profiles>
+    <profile>
+      <id>enforce-compatibility</id>
+      <activation>
+        <file>
+          <exists>marker-file-identifying-api-compatibility-check</exists>
+        </file>
+      </activation>
+      <build>
+        <plugins>
+          <!-- https://siom79.github.io/japicmp/MavenPlugin.html -->
+          <plugin>
+            <groupId>com.github.siom79.japicmp</groupId>
+            <artifactId>japicmp-maven-plugin</artifactId>
+            <configuration>
+              <parameter>
+                <onlyModified>true</onlyModified>
+                <!-- filter out classes with impl in their package or class name -->
+                <postAnalysisScript>${japicmp.postAnalysisScript}</postAnalysisScript>
+              </parameter>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
 </project>
\ No newline at end of file
diff --git a/uimafit-spring/pom.xml b/uimafit-spring/pom.xml
index 0917125..8dedc56 100644
--- a/uimafit-spring/pom.xml
+++ b/uimafit-spring/pom.xml
@@ -27,7 +27,7 @@
   <parent>
     <groupId>org.apache.uima</groupId>
     <artifactId>uimafit-parent</artifactId>
-    <version>3.0.1-SNAPSHOT</version>
+    <version>3.1.0-SNAPSHOT</version>
     <relativePath>../uimafit-parent</relativePath>
   </parent>
   <dependencies>
@@ -46,7 +46,7 @@
     <dependency>
       <groupId>org.apache.uima</groupId>
       <artifactId>uimafit-core</artifactId>
-      <version>3.0.1-SNAPSHOT</version>
+      <version>3.1.0-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
diff --git a/uimafit-spring/src/test/java/org/apache/uima/fit/spring/SpringContextResourceManagerTest.java b/uimafit-spring/src/test/java/org/apache/uima/fit/spring/SpringContextResourceManagerTest.java
index ba72bf9..aa7c683 100644
--- a/uimafit-spring/src/test/java/org/apache/uima/fit/spring/SpringContextResourceManagerTest.java
+++ b/uimafit-spring/src/test/java/org/apache/uima/fit/spring/SpringContextResourceManagerTest.java
@@ -20,7 +20,7 @@
 package org.apache.uima.fit.spring;
 
 import static org.apache.uima.fit.factory.AnalysisEngineFactory.createEngineDescription;
-import static org.apache.uima.fit.factory.ExternalResourceFactory.bindResource;
+import static org.apache.uima.fit.factory.ExternalResourceFactory.bindResourceOnceWithoutNested;
 import static org.junit.Assert.assertEquals;
 
 import org.apache.uima.UIMAFramework;
@@ -57,7 +57,7 @@
 
     // Create component description
     AnalysisEngineDescription desc = createEngineDescription(MyAnalysisEngine.class);
-    bindResource(desc, "injectedBean", "springBean");
+    bindResourceOnceWithoutNested(desc, "injectedBean", "springBean");
 
     // Instantiate component
     AnalysisEngine ae = UIMAFramework.produceAnalysisEngine(desc, resMgr, null);