Merge pull request #122 from apache/UIMA-6270-Add-selectOverlapping-to-JCasUtil

[UIMA-6270] Add selectOverlapping to (J)CasUtil
diff --git a/Jenkinsfile b/Jenkinsfile
index f7c905b..5bd0abc 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -16,7 +16,10 @@
 // under the License.
   
 pipeline {
-  agent any
+  agent {
+    label '!Windows'
+  }
+
   tools { 
     maven 'Maven (latest)' 
     jdk 'JDK 1.8 (latest)' 
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/factory/FsIndexFactory.java b/uimafit-core/src/main/java/org/apache/uima/fit/factory/FsIndexFactory.java
index a8fa976..10827f4 100644
--- a/uimafit-core/src/main/java/org/apache/uima/fit/factory/FsIndexFactory.java
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/factory/FsIndexFactory.java
@@ -30,6 +30,7 @@
 
 import org.apache.uima.fit.descriptor.FsIndex;
 import org.apache.uima.fit.descriptor.FsIndexKey;
+import org.apache.uima.fit.internal.ClassLoaderUtils;
 import org.apache.uima.fit.internal.MetaDataType;
 import org.apache.uima.resource.ResourceInitializationException;
 import org.apache.uima.resource.metadata.FsIndexCollection;
@@ -44,13 +45,12 @@
 import org.apache.uima.util.XMLInputSource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.util.ClassUtils;
 
 /**
  */
 public final class FsIndexFactory {
-  private static Logger LOG = LoggerFactory.getLogger(FsIndexFactory.class); 
-  
+  private static Logger LOG = LoggerFactory.getLogger(FsIndexFactory.class);
+
   /**
    * Comparator that orders FeatureStructures according to the standard order of their key features.
    * For integer and float values, this is the standard linear order, and for strings it is
@@ -262,7 +262,7 @@
    *           if the index collection could not be assembled
    */
   public static FsIndexCollection createFsIndexCollection() throws ResourceInitializationException {
-    ClassLoader cl = ClassUtils.getDefaultClassLoader();
+    ClassLoader cl = ClassLoaderUtils.findClassloader();
     FsIndexCollection aggFsIdxCol = fsIndexCollectionsByClassloader.get(cl);
     if (aggFsIdxCol == null) {
       synchronized (CREATE_LOCK) {
@@ -301,7 +301,7 @@
    */
   public static String[] scanIndexDescriptors() throws ResourceInitializationException {
     synchronized (SCAN_LOCK) {
-      ClassLoader cl = ClassUtils.getDefaultClassLoader();
+      ClassLoader cl = ClassLoaderUtils.findClassloader();
       String[] indexLocations = fsIndexLocationsByClassloader.get(cl);
       if (indexLocations == null) {
         indexLocations = scanDescriptors(MetaDataType.FS_INDEX);
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/factory/TypePrioritiesFactory.java b/uimafit-core/src/main/java/org/apache/uima/fit/factory/TypePrioritiesFactory.java
index 2073441..4c83f45 100644
--- a/uimafit-core/src/main/java/org/apache/uima/fit/factory/TypePrioritiesFactory.java
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/factory/TypePrioritiesFactory.java
@@ -27,6 +27,7 @@
 import java.util.List;
 import java.util.WeakHashMap;
 
+import org.apache.uima.fit.internal.ClassLoaderUtils;
 import org.apache.uima.fit.internal.MetaDataType;
 import org.apache.uima.fit.internal.ResourceManagerFactory;
 import org.apache.uima.jcas.cas.TOP;
@@ -40,11 +41,10 @@
 import org.apache.uima.util.XMLInputSource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.util.ClassUtils;
 
 public final class TypePrioritiesFactory {
   private static final Logger LOG = LoggerFactory.getLogger(TypePrioritiesFactory.class);
-    
+
   private static final Object SCAN_LOCK = new Object();
 
   private static final Object CREATE_LOCK = new Object();
@@ -76,7 +76,7 @@
       if (!TOP.class.isAssignableFrom(prioritizedTypes[i])) {
         throw new IllegalArgumentException("[" + prioritizedTypes[i] + "] is not a JCas type");
       }
-      
+
       String typeName = prioritizedTypes[i].getName();
       if (typeName.startsWith(UIMA_BUILTIN_JCAS_PREFIX)) {
         typeName = "uima." + typeName.substring(UIMA_BUILTIN_JCAS_PREFIX.length());
@@ -114,7 +114,7 @@
    *           if the collected type priorities cannot be merged.
    */
   public static TypePriorities createTypePriorities() throws ResourceInitializationException {
-    ClassLoader cl = ClassUtils.getDefaultClassLoader();
+    ClassLoader cl = ClassLoaderUtils.findClassloader();
     TypePriorities aggTypePriorities = typePrioritiesByClassloader.get(cl);
     if (aggTypePriorities == null) {
       synchronized (CREATE_LOCK) {
@@ -153,7 +153,7 @@
    */
   public static String[] scanTypePrioritiesDescriptors() throws ResourceInitializationException {
     synchronized (SCAN_LOCK) {
-      ClassLoader cl = ClassUtils.getDefaultClassLoader();
+      ClassLoader cl = ClassLoaderUtils.findClassloader();
       String[] typePrioritesLocations = typePrioritesLocationsByClassloader.get(cl);
       if (typePrioritesLocations == null) {
         typePrioritesLocations = scanDescriptors(MetaDataType.TYPE_PRIORITIES);
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/factory/TypeSystemDescriptionFactory.java b/uimafit-core/src/main/java/org/apache/uima/fit/factory/TypeSystemDescriptionFactory.java
index dc05a40..0c1af58 100644
--- a/uimafit-core/src/main/java/org/apache/uima/fit/factory/TypeSystemDescriptionFactory.java
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/factory/TypeSystemDescriptionFactory.java
@@ -27,6 +27,7 @@
 import java.util.List;
 import java.util.WeakHashMap;
 
+import org.apache.uima.fit.internal.ClassLoaderUtils;
 import org.apache.uima.fit.internal.MetaDataType;
 import org.apache.uima.fit.internal.ResourceManagerFactory;
 import org.apache.uima.resource.ResourceInitializationException;
@@ -39,11 +40,10 @@
 import org.apache.uima.util.XMLInputSource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.util.ClassUtils;
 
 public final class TypeSystemDescriptionFactory {
   private static final Logger LOG = LoggerFactory.getLogger(TypeSystemDescriptionFactory.class);
-  
+
   private static final Object SCAN_LOCK = new Object();
 
   private static final Object CREATE_LOCK = new Object();
@@ -113,7 +113,7 @@
    */
   public static TypeSystemDescription createTypeSystemDescription()
           throws ResourceInitializationException {
-    ClassLoader cl = ClassUtils.getDefaultClassLoader();
+    ClassLoader cl = ClassLoaderUtils.findClassloader();
     TypeSystemDescription tsd = typeDescriptorByClassloader.get(cl);
     if (tsd == null) {
       synchronized (CREATE_LOCK) {
@@ -149,7 +149,7 @@
    */
   public static String[] scanTypeDescriptors() throws ResourceInitializationException {
     synchronized (SCAN_LOCK) {
-      ClassLoader cl = ClassUtils.getDefaultClassLoader();
+      ClassLoader cl = ClassLoaderUtils.findClassloader();
       String[] typeDescriptorLocations = typeDescriptorLocationsByClassloader.get(cl);
       if (typeDescriptorLocations == null) {
         typeDescriptorLocations = scanDescriptors(MetaDataType.TYPE_SYSTEM);
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/factory/initializable/InitializableFactory.java b/uimafit-core/src/main/java/org/apache/uima/fit/factory/initializable/InitializableFactory.java
index e0c54e6..535782d 100644
--- a/uimafit-core/src/main/java/org/apache/uima/fit/factory/initializable/InitializableFactory.java
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/factory/initializable/InitializableFactory.java
@@ -6,9 +6,9 @@
  * 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
@@ -19,11 +19,12 @@
 package org.apache.uima.fit.factory.initializable;
 
 import org.apache.uima.UimaContext;
+import org.apache.uima.fit.internal.ClassLoaderUtils;
 import org.apache.uima.resource.ResourceInitializationException;
 
 /**
  * Please see {@link Initializable} for a description of how this class is intended to be used.
- * 
+ *
  * @see Initializable
  */
 public final class InitializableFactory {
@@ -35,7 +36,7 @@
    * Provides a way to create an instance of T. If the class specified by className implements
    * {@link Initializable}, then the UimaContext provided here will be passed to its initialize
    * method.
-   * 
+   *
    * @param <T>
    *          the interface type
    * @param context
@@ -50,7 +51,14 @@
    */
   public static <T> T create(UimaContext context, String className, Class<T> superClass)
           throws ResourceInitializationException {
-    Class<? extends T> cls = getClass(className, superClass);
+    Class<? extends T> cls;
+    try {
+      ClassLoader cl = ClassLoaderUtils.findClassloader(context);
+      cls = Class.forName(className, true, cl).asSubclass(superClass);
+    } catch (Exception e) {
+      throw new ResourceInitializationException(new IllegalStateException("classname = "
+              + className + " superClass = " + superClass.getName(), e));
+    }
     return create(context, cls);
   }
 
@@ -68,7 +76,8 @@
   public static <T> Class<? extends T> getClass(String className, Class<T> superClass)
           throws ResourceInitializationException {
     try {
-      return Class.forName(className).asSubclass(superClass);
+      ClassLoader cl = ClassLoaderUtils.findClassloader();
+      return Class.forName(className, true, cl).asSubclass(superClass);
     } catch (Exception e) {
       throw new ResourceInitializationException(new IllegalStateException("classname = "
               + className + " superClass = " + superClass.getName(), e));
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/internal/ClassLoaderUtils.java b/uimafit-core/src/main/java/org/apache/uima/fit/internal/ClassLoaderUtils.java
new file mode 100644
index 0000000..f498264
--- /dev/null
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/internal/ClassLoaderUtils.java
@@ -0,0 +1,123 @@
+/*
+ * 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.fit.internal;
+
+import org.apache.uima.UimaContext;
+import org.apache.uima.UimaContextAdmin;
+import org.apache.uima.UimaContextHolder;
+import org.apache.uima.resource.ResourceManager;
+import org.springframework.util.ClassUtils;
+
+/**
+ * INTERNAL API - Helper functions to obtain a suitable classloader.
+ */
+public final class ClassLoaderUtils {
+  private ClassLoaderUtils() {
+    // No instances
+  }
+
+  /**
+   * Looks up a suitable classloader in the following order:
+   * <ol>
+   * <li>The {@link UimaContext} in the {@link UimaContextHolder} of the current thread(if any)</li>
+   * <li>The current thread-context classloader (if any)</li>
+   * <li>The classloader through which uimaFIT (i.e. this class) was loaded.</li>
+   * <li>For backwards compatibility then delegates to {@link ClassUtils#getDefaultClassLoader()}</li>
+   * </ol>
+   *
+   * @return a classloader or {@code null} if no suitable classloader could be found.
+   */
+  public static ClassLoader findClassloader() {
+    ClassLoader uimaThreadContextClassLoader = getExtensionClassloader(
+            UimaContextHolder.getContext());
+    if (uimaThreadContextClassLoader != null) {
+      return uimaThreadContextClassLoader;
+    }
+
+    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+    if (contextClassLoader != null) {
+      return contextClassLoader;
+    }
+
+    ClassLoader uimaFITClassLoader = ClassLoaderUtils.class.getClassLoader();
+    if (uimaFITClassLoader != null) {
+      return uimaFITClassLoader;
+    }
+
+    return ClassUtils.getDefaultClassLoader();
+  }
+
+  /**
+   * Looks up a suitable classloader in the following order:
+   * <ol>
+   * <li>The extension classloader of the given {@link ResourceManager}</li>
+   * <li>See {@link #findClassloader()}</li>
+   * </ol>
+   *
+   * @return a classloader or {@code null} if no suitable classloader could be found.
+   */
+  public static ClassLoader findClassloader(ResourceManager aResMgr) {
+    ClassLoader resourceManagerExtensionClassloader = getExtensionClassloader(aResMgr);
+    if (resourceManagerExtensionClassloader != null) {
+      return resourceManagerExtensionClassloader;
+    }
+
+    return findClassloader();
+  }
+
+  /**
+   * Looks up a suitable classloader in the following order:
+   * <ol>
+   * <li>The extension classloader of the {@link ResourceManager} associated with the given
+   * {@link UimaContext} (if any)</li>
+   * <li>See {@link #findClassloader(ResourceManager)}</li>
+   * </ol>
+   *
+   * @return a classloader or {@code null} if no suitable classloader could be found.
+   */
+  public static ClassLoader findClassloader(UimaContext aContext) {
+    ClassLoader uimaContextExtensionClassloader = getExtensionClassloader(aContext);
+    if (uimaContextExtensionClassloader != null) {
+      return uimaContextExtensionClassloader;
+    }
+
+    return findClassloader((ResourceManager) null);
+  }
+
+  private static ClassLoader getExtensionClassloader(UimaContext aContext) {
+    if (aContext instanceof UimaContextAdmin) {
+      return getExtensionClassloader(((UimaContextAdmin) aContext).getResourceManager());
+    }
+
+    return null;
+  }
+
+  private static ClassLoader getExtensionClassloader(ResourceManager aResMgr) {
+    if (aResMgr == null) {
+      return null;
+    }
+
+    ClassLoader cl = aResMgr.getExtensionClassLoader();
+    if (cl != null) {
+      return aResMgr.getExtensionClassLoader();
+    }
+
+    return null;
+  }
+}
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/internal/ResourceManagerFactory.java b/uimafit-core/src/main/java/org/apache/uima/fit/internal/ResourceManagerFactory.java
index 656e4bb..11e1f59 100644
--- a/uimafit-core/src/main/java/org/apache/uima/fit/internal/ResourceManagerFactory.java
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/internal/ResourceManagerFactory.java
@@ -6,9 +6,9 @@
  * 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
@@ -18,8 +18,6 @@
  */
 package org.apache.uima.fit.internal;
 
-import java.net.MalformedURLException;
-
 import org.apache.uima.UIMAFramework;
 import org.apache.uima.UimaContext;
 import org.apache.uima.UimaContextAdmin;
@@ -28,25 +26,23 @@
 import org.apache.uima.resource.ResourceInitializationException;
 import org.apache.uima.resource.ResourceManager;
 import org.apache.uima.resource.impl.ResourceManager_impl;
-import org.springframework.util.ClassUtils;
 
 /**
  * INTERNAL API - Helper functions for dealing with resource managers and classloading
- * 
- * This API is experimental and is very likely to be removed or changed in future versions. 
+ *
+ * This API is experimental and is very likely to be removed or changed in future versions.
  */
 public class ResourceManagerFactory {
   private static ResourceManagerCreator resourceManagerCreator = new DefaultResourceManagerCreator();
-  
+
   private ResourceManagerFactory() {
     // No instances
   }
 
-  public static ResourceManager newResourceManager() throws ResourceInitializationException
-  {
+  public static ResourceManager newResourceManager() throws ResourceInitializationException {
     return resourceManagerCreator.newResourceManager();
   }
-  
+
   /**
    * Mind that returning a singleton resource manager from {@link ResourceManagerFactory} is
    * generally a bad idea because it gets destroyed on a regular basis. For this reason, it is
@@ -57,15 +53,15 @@
           ResourceManagerCreator resourceManagerCreator) {
     ResourceManagerFactory.resourceManagerCreator = resourceManagerCreator;
   }
-  
+
   public static ResourceManagerCreator getResourceManagerCreator() {
     return resourceManagerCreator;
   }
-  
-  public static interface ResourceManagerCreator {
+
+  public interface ResourceManagerCreator {
     ResourceManager newResourceManager() throws ResourceInitializationException;
   }
-  
+
   public static class DefaultResourceManagerCreator implements ResourceManagerCreator {
     @Override
     public ResourceManager newResourceManager() throws ResourceInitializationException {
@@ -77,41 +73,34 @@
         // See https://issues.apache.org/jira/browse/UIMA-5056
         return ((UimaContextAdmin) activeContext).getResourceManager();
       }
-      else {
-        // If there is no UIMA context, then we create a new resource manager
-        // UIMA core still does not fall back to the context classloader in all cases.
-        // This was the default behavior until uimaFIT 2.2.0.
-        ResourceManager resMgr;
-        if (Thread.currentThread().getContextClassLoader() != null) {
-          // If the context classloader is set, then we want the resource manager to fallb
-          // back to it. However, it may not reliably do that that unless we explictly pass
-          // null here. See. UIMA-6239.
-          resMgr = new ResourceManager_impl(null);
-        }
-        else {
-          resMgr = UIMAFramework.newDefaultResourceManager();
-        }
-        
-        // Since UIMA Core version 2.10.3 and 3.0.1 the thread context classloader is taken
-        // into account by the core framework. Thus, we no longer have to explicitly set a
-        // classloader these or more recent versions. (cf. UIMA-5802)
-        short maj = UimaVersion.getMajorVersion();
-        short min = UimaVersion.getMinorVersion();
-        short rev = UimaVersion.getBuildRevision();
-        boolean uimaCoreIgnoresContextClassloader = 
-                (maj == 2 && (min < 10 || (min == 10 && rev < 3))) || // version < 2.10.3
-                (maj == 3 && ((min == 0 && rev < 1)));                // version < 3.0.1
-        if (uimaCoreIgnoresContextClassloader) {
-          try {
-            resMgr.setExtensionClassPath(ClassUtils.getDefaultClassLoader(), "", true);
-          }
-          catch (MalformedURLException e) {
-            throw new ResourceInitializationException(e);
-          }
-        }
-        
-        return resMgr;
+
+      // If there is no UIMA context, then we create a new resource manager
+      // UIMA core still does not fall back to the context classloader in all cases.
+      // This was the default behavior until uimaFIT 2.2.0.
+      ResourceManager resMgr;
+      if (Thread.currentThread().getContextClassLoader() != null) {
+        // If the context classloader is set, then we want the resource manager to fallb
+        // back to it. However, it may not reliably do that that unless we explictly pass
+        // null here. See. UIMA-6239.
+        resMgr = new ResourceManager_impl(null);
+      } else {
+        resMgr = UIMAFramework.newDefaultResourceManager();
       }
+
+      // Since UIMA Core version 2.10.3 and 3.0.1 the thread context classloader is taken
+      // into account by the core framework. Thus, we no longer have to explicitly set a
+      // classloader these or more recent versions. (cf. UIMA-5802)
+      short maj = UimaVersion.getMajorVersion();
+      short min = UimaVersion.getMinorVersion();
+      short rev = UimaVersion.getBuildRevision();
+      boolean uimaCoreIgnoresContextClassloader = 
+              (maj == 2 && (min < 10 || (min == 10 && rev < 3))) || // version < 2.10.3
+              (maj == 3 && ((min == 0 && rev < 1)));                // version < 3.0.1
+      if (uimaCoreIgnoresContextClassloader) {
+        resMgr.setExtensionClassLoader(ClassLoaderUtils.findClassloader(), true);
+      }
+
+      return resMgr;
     }
   }
 }