Merge pull request #123 from apache/bugfix/UIMA-6275-InitializableFactory-is-not-smart-enough-to-find-a-suitable-classloader
[UIMA-6275] InitializableFactory is not smart enough to find a suitable classloader
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 bfc7923..a210ef7 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
@@ -31,6 +31,7 @@
import org.apache.commons.logging.LogFactory;
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;
@@ -43,7 +44,6 @@
import org.apache.uima.resource.metadata.impl.Import_impl;
import org.apache.uima.util.InvalidXMLException;
import org.apache.uima.util.XMLInputSource;
-import org.springframework.util.ClassUtils;
/**
*/
@@ -259,7 +259,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) {
@@ -275,7 +275,7 @@
throw new ResourceInitializationException(e);
} catch (InvalidXMLException e) {
LogFactory.getLog(FsIndexFactory.class)
- .warn("[" + location + "] is not a index descriptor file. Ignoring.", e);
+ .warn("[" + location + "] is not a index descriptor file. Ignoring.", e);
}
}
@@ -299,7 +299,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 1759bc9..c79abaa 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
@@ -28,6 +28,7 @@
import java.util.WeakHashMap;
import org.apache.commons.logging.LogFactory;
+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;
@@ -38,7 +39,6 @@
import org.apache.uima.util.CasCreationUtils;
import org.apache.uima.util.InvalidXMLException;
import org.apache.uima.util.XMLInputSource;
-import org.springframework.util.ClassUtils;
public final class TypePrioritiesFactory {
private static final Object SCAN_LOCK = new Object();
@@ -105,7 +105,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) {
@@ -117,7 +117,7 @@
typePriorities.resolveImports();
typePrioritiesList.add(typePriorities);
LogFactory.getLog(TypePrioritiesFactory.class)
- .debug("Detected type priorities at [" + location + "]");
+ .debug("Detected type priorities at [" + location + "]");
} catch (IOException e) {
throw new ResourceInitializationException(e);
} catch (InvalidXMLException e) {
@@ -146,7 +146,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 ab3e9f8..dd2a246 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
@@ -28,6 +28,7 @@
import java.util.WeakHashMap;
import org.apache.commons.logging.LogFactory;
+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;
@@ -38,7 +39,6 @@
import org.apache.uima.resource.metadata.impl.TypeSystemDescription_impl;
import org.apache.uima.util.InvalidXMLException;
import org.apache.uima.util.XMLInputSource;
-import org.springframework.util.ClassUtils;
public final class TypeSystemDescriptionFactory {
private static final Object SCAN_LOCK = new Object();
@@ -110,7 +110,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) {
@@ -120,12 +120,12 @@
XMLInputSource xmlInputType1 = new XMLInputSource(location);
tsdList.add(getXMLParser().parseTypeSystemDescription(xmlInputType1));
LogFactory.getLog(TypeSystemDescription.class)
- .debug("Detected type system at [" + location + "]");
+ .debug("Detected type system at [" + location + "]");
} catch (IOException e) {
throw new ResourceInitializationException(e);
} catch (InvalidXMLException e) {
LogFactory.getLog(TypeSystemDescription.class)
- .warn("[" + location + "] is not a type file. Ignoring.", e);
+ .warn("[" + location + "] is not a type file. Ignoring.", e);
}
}
@@ -148,7 +148,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..906538a 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..2dc3671
--- /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 #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 #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 5bf34fa..e3e40b1 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
@@ -28,16 +28,15 @@
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
}
@@ -46,7 +45,7 @@
{
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 +56,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 {
@@ -78,37 +77,35 @@
// 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) {
- resMgr.setExtensionClassPath(ClassUtils.getDefaultClassLoader(), "", true);
- }
-
- 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.setExtensionClassPath(ClassloaderUtils.findClassloader(), "", true);
+ }
+
+ return resMgr;
}
catch (MalformedURLException e) {
throw new ResourceInitializationException(e);