| /* |
| * 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.resource.impl; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| |
| import org.apache.uima.UIMAFramework; |
| import org.apache.uima.UIMA_IllegalStateException; |
| import org.apache.uima.analysis_engine.impl.AnalysisEngineImplBase; |
| import org.apache.uima.analysis_engine.impl.PearAnalysisEngineWrapper; |
| import org.apache.uima.internal.util.Class_TCCL; |
| import org.apache.uima.internal.util.UIMAClassLoader; |
| import org.apache.uima.resource.CasManager; |
| import org.apache.uima.resource.DataResource; |
| import org.apache.uima.resource.ExternalResourceDependency; |
| import org.apache.uima.resource.ExternalResourceDescription; |
| import org.apache.uima.resource.FileResourceSpecifier; |
| import org.apache.uima.resource.ParameterizedDataResource; |
| import org.apache.uima.resource.RelativePathResolver; |
| import org.apache.uima.resource.Resource; |
| import org.apache.uima.resource.ResourceAccessException; |
| import org.apache.uima.resource.ResourceInitializationException; |
| import org.apache.uima.resource.ResourceManager; |
| import org.apache.uima.resource.ResourceSpecifier; |
| import org.apache.uima.resource.SharedResourceObject; |
| import org.apache.uima.resource.metadata.ExternalResourceBinding; |
| import org.apache.uima.resource.metadata.ResourceManagerConfiguration; |
| import org.apache.uima.util.Level; |
| import org.apache.uima.util.XMLizable; |
| |
| /** |
| * Reference implementation of {@link org.apache.uima.resource.ResourceManager}. |
| * |
| * |
| */ |
| public class ResourceManager_impl implements ResourceManager { |
| |
| /** |
| * Ties an External Resource instance to |
| * - its description |
| * -- name |
| * -- textual description |
| * -- a ResourceSpecifier describing how to create it |
| * -- (optional) the String name of the Java class that implements the resource) |
| * - its defining UIMA Context |
| * |
| * These are used to validate multiple declarations, and to get |
| * a resource to tie it to a binding |
| */ |
| static protected class ResourceRegistration { // make protected https://issues.apache.org/jira/browse/UIMA-2102 |
| /** |
| * For ParameterizedDataResources or DataResources, is the implementation object, which is |
| * an arbitrary Java class implementing SharedDataResource (which has the "load" method) |
| * |
| * If the external resource specification omitted the implementation class, a default FileResource |
| */ |
| Object resource; |
| |
| ExternalResourceDescription description; |
| |
| String definingContext; |
| |
| public ResourceRegistration(Object resourceOrImplementation, ExternalResourceDescription description, |
| String definingContext) { |
| this.resource = resourceOrImplementation; |
| this.description = description; |
| this.definingContext = definingContext; |
| } |
| } |
| |
| /** |
| * resource bundle for log messages |
| */ |
| protected static final String LOG_RESOURCE_BUNDLE = "org.apache.uima.impl.log_messages"; |
| |
| protected static final Class<Resource> EMPTY_RESOURCE_CLASS = Resource.class; |
| |
| private AtomicBoolean isDestroyed = new AtomicBoolean(false); |
| /** |
| * a monitor lock for synchronizing get/set of casManager ref |
| */ |
| private final Object casManagerMonitor = new Object(); |
| |
| /** |
| * Object used for resolving relative paths. This is built by parsing the data path. |
| */ |
| private final RelativePathResolver mRelativePathResolver; |
| |
| /** |
| * Map from qualified key names (declared in resource dependency XML) to |
| * either DataResource objects or SharedResourceObjects that impl Resource. |
| * |
| * This map is many to one (multiple keys may refer to the same Resource object) |
| * |
| * Can't be concurrentMap because it (currently) depends on storing nulls |
| * |
| * Keeping the Map's 2nd argument as Object, although it could be Resource, |
| * for backwards compatibility |
| */ |
| final protected Map<String, Object> mResourceMap; |
| |
| /** |
| * Internal map from resource names (declared in resource declaration XML) to ResourceRegistration |
| * objects. |
| * Uses: for detecting if multiple declarations are made for the same resource name |
| * .values() for list of all resources that have been registered |
| * |
| * This is a one-to-one map. |
| */ |
| final protected Map<String, ResourceRegistration> mInternalResourceRegistrationMap; |
| |
| /** |
| * Map from String keys to Class objects. For ParameterizedResources only, stores the |
| * implementation class (not a Resource) corresponding to each resource name. |
| * |
| * These class objects may or may not be Resource instances. |
| * They may be arbitrary classes, except that they must implement SharedResourceObject. |
| * |
| * This is a many to one map; many keys may refer to the same class |
| * |
| * key = aQualifiedContextName + the key name in an external resource binding |
| */ |
| final protected Map<String, Class<?>> mParameterizedResourceImplClassMap; |
| |
| /** |
| * Internal map from resource names (declared in resource declaration XML) to Class objects |
| * for parameterized Resource. |
| * |
| * These class objects may or may not be Resource instances. |
| * They may be arbitrary classes, except that they must implement SharedResourceObject. |
| * |
| * These are "customized" when referenced, by |
| * parameter strings (such as language, for a Dictionary resource). Used |
| * internally during resource initialization. |
| * |
| * key = external resource declared name. |
| */ |
| final protected Map<String, Class<?>> mInternalParameterizedResourceImplClassMap; |
| |
| /** |
| * Map from ParameterizedResourceKey to SharedResourceObject or DataResource instances. |
| * |
| * Note: SharedResourceObjects are not "Resource" instances, but rather arbitrary Java classes that |
| * are the "implementations" of Resources. The only requirement on these Java classes is |
| * that they implement SharedResourceObject interface. |
| * |
| * This map is for ParameterizedResources only, and |
| * stores the SharedResourceObjects or DataResource objects that have already been instantiated and loaded. |
| */ |
| final protected Map<List<Object>, Object> mParameterizedResourceInstanceMap; |
| |
| /** |
| * UIMA extension ClassLoader. ClassLoader is created if an extension classpath is specified at |
| * the ResourceManager |
| * |
| * volatile might be better than synch sets/gets |
| */ |
| private volatile UIMAClassLoader uimaCL = null; |
| |
| /** CasManager - manages creation and pooling of CASes. */ |
| // volatile to support double-checked locking idiom |
| protected volatile CasManager mCasManager = null; |
| |
| /** |
| * Cache of imported descriptors, so that parsed objects can be reused if the |
| * same URL is imported more than once. |
| * |
| * All callers of this synchronize on the importCache object before doing a |
| * get |
| * ... |
| * put |
| * sequence |
| * |
| * Use Case where synchronization is needed: |
| * running multiple instances on multiple threads, sharing a common resource manager, |
| * the initialization that merges typePriorities happens lazily, when using Cas Multipliers, |
| * and occurs when the first getCas call happens on a thread. Although these calls |
| * are synchronized among themselves, any other use of this map that might occur |
| * simultaneously is not. |
| */ |
| // leaving this as a synchronizedMap - for backwards compatibility |
| // internal users do sync around get/set pairs anyways, but can't rely on |
| // what external users do |
| // Because internal users do a sync, only one thread at a time is using this |
| // (for internal calls) anyways, so there's no advantage to the extra overhead |
| // of making this a ConcurrentHashMap (March 2014) |
| private Map<String, XMLizable> importCache = Collections.synchronizedMap(new HashMap<String,XMLizable>()); |
| |
| /** |
| * Cache of imported descriptor URLs from which the parsed objects in importCache |
| * were created, so that these URLs are not re-parsed if the same URL is imported again. |
| */ |
| private Map<String, Set<String>> importUrlsCache = Collections.synchronizedMap(new HashMap<String,Set<String>>()); |
| |
| /** |
| * Creates a new <code>ResourceManager_impl</code>. |
| */ |
| public ResourceManager_impl() { |
| mResourceMap = Collections.synchronizedMap(new HashMap<String, Object>()); |
| mInternalResourceRegistrationMap = new ConcurrentHashMap<String, ResourceRegistration>(); |
| mParameterizedResourceImplClassMap = new ConcurrentHashMap<String, Class<?>>(); |
| mInternalParameterizedResourceImplClassMap = new ConcurrentHashMap<String, Class<?>>(); |
| mParameterizedResourceInstanceMap = new ConcurrentHashMap<List<Object>, Object>(); |
| mRelativePathResolver = new RelativePathResolver_impl(); |
| } |
| |
| /** |
| * Creates a new <code>ResourceManager_impl</code> with a custom ClassLoader to use for locating |
| * resources. |
| * @param aClassLoader - |
| */ |
| public ResourceManager_impl(ClassLoader aClassLoader) { |
| mResourceMap = Collections.synchronizedMap(new HashMap<String, Object>()); |
| mInternalResourceRegistrationMap = new ConcurrentHashMap<String, ResourceRegistration>(); |
| mParameterizedResourceImplClassMap = new ConcurrentHashMap<String, Class<?>>(); |
| mInternalParameterizedResourceImplClassMap = new ConcurrentHashMap<String, Class<?>>(); |
| mParameterizedResourceInstanceMap = new ConcurrentHashMap<List<Object>, Object>(); |
| mRelativePathResolver = new RelativePathResolver_impl(aClassLoader); |
| } |
| |
| /* |
| * Version for Pear wrapper |
| */ |
| public ResourceManager_impl( |
| Map<String, Object> resourceMap, |
| Map<String, ResourceRegistration> internalResourceRegistrationMap, |
| Map<String, Class<?>> parameterizedResourceImplClassMap, |
| Map<String, Class<?>> internalParameterizedResourceImplClassMap, |
| Map<List<Object>, Object> parameterizedResourceInstanceMap) { |
| mResourceMap = resourceMap; |
| mInternalResourceRegistrationMap = internalResourceRegistrationMap; |
| mParameterizedResourceImplClassMap = parameterizedResourceImplClassMap; |
| mInternalParameterizedResourceImplClassMap = internalParameterizedResourceImplClassMap; |
| mParameterizedResourceInstanceMap = parameterizedResourceInstanceMap; |
| mRelativePathResolver = new RelativePathResolver_impl(); |
| } |
| |
| public ResourceManager_impl copy() { |
| ResourceManager_impl rm = new ResourceManager_impl( |
| this.mResourceMap, |
| this.mInternalResourceRegistrationMap, |
| this.mParameterizedResourceImplClassMap, |
| this.mInternalParameterizedResourceImplClassMap, |
| this.mParameterizedResourceInstanceMap |
| ); |
| // non-final fields init |
| rm.uimaCL = this.uimaCL; |
| rm.importCache = this.importCache; |
| rm.importUrlsCache = this.importUrlsCache; |
| return rm; |
| } |
| |
| |
| /** |
| * Support reusing UIMA Class Loader instances to speed up |
| * things including the Component Description Editor when |
| * obtaining info from CustomResourceSpecifiers |
| * https://issues.apache.org/jira/browse/UIMA-1722 |
| * @param uimaCL - |
| * @param resolveResource - |
| */ |
| public synchronized void setExtensionClassPath(UIMAClassLoader uimaCL, boolean resolveResource) { |
| this.uimaCL = uimaCL; |
| |
| if (resolveResource) { |
| // set UIMA extension ClassLoader also to resolve resources |
| getRelativePathResolver().setPathResolverClassLoader(uimaCL); |
| } |
| } |
| |
| /** |
| |
| /** |
| * @see org.apache.uima.resource.ResourceManager#setExtensionClassPath(java.lang.String, boolean) |
| */ |
| @Override |
| public synchronized void setExtensionClassPath(String classpath, boolean resolveResource) |
| throws MalformedURLException { |
| // create UIMA extension ClassLoader with the given classpath |
| uimaCL = new UIMAClassLoader(classpath, Class_TCCL.get_parent_cl()); |
| |
| if (resolveResource) { |
| // set UIMA extension ClassLoader also to resolve resources |
| getRelativePathResolver().setPathResolverClassLoader(uimaCL); |
| } |
| } |
| |
| /** |
| * @see org.apache.uima.resource.ResourceManager#setExtensionClassPath(ClassLoader,java.lang.String, |
| * boolean) |
| */ |
| @Override |
| public synchronized void setExtensionClassPath(ClassLoader parent, String classpath, boolean resolveResource) |
| throws MalformedURLException { |
| // create UIMA extension ClassLoader with the given classpath |
| uimaCL = new UIMAClassLoader(classpath, parent); |
| |
| if (resolveResource) { |
| // set UIMA extension ClassLoader also to resolve resources |
| getRelativePathResolver().setPathResolverClassLoader(uimaCL); |
| } |
| } |
| |
| /** |
| * @see org.apache.uima.resource.ResourceManager#getExtensionClassLoader() |
| */ |
| @Override |
| public ClassLoader getExtensionClassLoader() { |
| return uimaCL; |
| } |
| |
| /** |
| * @see org.apache.uima.resource.ResourceManager#getDataPath() |
| */ |
| @Override |
| public String getDataPath() { |
| return getRelativePathResolver().getDataPath(); |
| } |
| |
| /** |
| * @see org.apache.uima.resource.ResourceManager#setDataPath(String) |
| */ |
| @Override |
| public void setDataPath(String aPath) throws MalformedURLException { |
| getRelativePathResolver().setDataPath(aPath); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.resource.ResourceManager#resolveRelativePath(java.lang.String) |
| */ |
| @Override |
| public URL resolveRelativePath(String aRelativePath) throws MalformedURLException { |
| URL relativeUrl; |
| try { |
| relativeUrl = new URL(aRelativePath); |
| } catch (MalformedURLException e) { |
| relativeUrl = new URL("file", "", aRelativePath); |
| } |
| return getRelativePathResolver().resolveRelativePath(relativeUrl); |
| } |
| |
| private void checkDestroyed() { |
| if (isDestroyed.get()) { |
| throw new IllegalStateException("ResourceManager is destroyed"); |
| } |
| } |
| |
| /** |
| * @see org.apache.uima.resource.ResourceManager#getResource(String) |
| */ |
| @Override |
| public Object getResource(String aName) throws ResourceAccessException { |
| checkDestroyed(); |
| Object r = mResourceMap.get(aName); |
| // if this is a ParameterizedDataResource, it is an error |
| if (r instanceof ParameterizedDataResource) { |
| throw new ResourceAccessException(ResourceAccessException.PARAMETERS_REQUIRED, |
| new Object[] { aName }); |
| } |
| return r; |
| } |
| |
| /** |
| * @see org.apache.uima.resource.ResourceManager#getResource(java.lang.String, java.lang.String[]) |
| */ |
| @Override |
| public Object getResource(String aName, String[] aParams) throws ResourceAccessException { |
| /* Multi-core design |
| * This may be called by user code sharing the same Resource Manager, and / or the same |
| * uima context object. |
| * Do double-checked idiom to avoid locking where resource is already available, loaded |
| */ |
| checkDestroyed(); |
| Object r = mResourceMap.get(aName); |
| |
| // if no resource found, return null |
| if (r == null) { |
| return null; |
| } |
| // if not a ParameterizedDataResource, it is an error |
| if (!(r instanceof ParameterizedDataResource)) { |
| throw new ResourceAccessException(ResourceAccessException.PARAMETERS_NOT_ALLOWED, |
| new Object[] { aName }); |
| } |
| ParameterizedDataResource pdr = (ParameterizedDataResource) r; |
| |
| // get a particular DataResource instance for the specified parameters |
| DataResource dr; |
| try { |
| dr = pdr.getDataResource(aParams); |
| } catch (ResourceInitializationException e) { |
| throw new ResourceAccessException(e); |
| } |
| |
| // see if we've already encountered this DataResource under this resource name |
| List<Object> nameAndResource = new ArrayList<Object>(2); |
| nameAndResource.add(aName); |
| nameAndResource.add(dr); |
| Object resourceInstance = mParameterizedResourceInstanceMap.get(nameAndResource); |
| if (resourceInstance != null) { |
| return resourceInstance; |
| } |
| synchronized(mParameterizedResourceInstanceMap) { |
| // double-check idiom |
| resourceInstance = mParameterizedResourceInstanceMap.get(nameAndResource); |
| if (resourceInstance != null) { |
| return resourceInstance; |
| } |
| // We haven't encountered this before. See if we need to instantiate a |
| // SharedResourceObject |
| Class<?> sharedResourceObjectClass = mParameterizedResourceImplClassMap.get(aName); |
| if (sharedResourceObjectClass != EMPTY_RESOURCE_CLASS) { |
| try { |
| SharedResourceObject sro = (SharedResourceObject) sharedResourceObjectClass.newInstance(); |
| sro.load(dr); |
| mParameterizedResourceInstanceMap.put(nameAndResource, sro); |
| return sro; |
| } catch (InstantiationException e) { |
| throw new ResourceAccessException(e); |
| } catch (IllegalAccessException e) { |
| throw new ResourceAccessException(e); |
| } catch (ResourceInitializationException e) { |
| throw new ResourceAccessException(e); |
| } |
| } else |
| // no impl. class - just return the DataResource |
| { |
| mParameterizedResourceInstanceMap.put(nameAndResource, dr); |
| return dr; |
| } |
| } |
| } |
| |
| /** |
| * @see org.apache.uima.resource.ResourceManager#getResourceClass(java.lang.String) |
| */ |
| @Override |
| @SuppressWarnings("unchecked") |
| public Class<?> getResourceClass(String aName) { |
| checkDestroyed(); |
| Object r = mResourceMap.get(aName); |
| if (r == null) // no such resource |
| { |
| return null; |
| } |
| |
| // if this is a ParameterizedDataResource, look up its class |
| if (r instanceof ParameterizedDataResource) { |
| Class<?> customResourceClass = mParameterizedResourceImplClassMap.get(aName); |
| if (customResourceClass == EMPTY_RESOURCE_CLASS) { |
| // return the default class |
| return DataResource_impl.class; |
| } |
| return customResourceClass; |
| } else { |
| // return r's Class |
| // could be, for |
| return (Class<? extends Resource>) r.getClass(); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.resource.ResourceManager#getResourceAsStream(java.lang.String, |
| * java.lang.String[]) |
| */ |
| @Override |
| public InputStream getResourceAsStream(String aKey, String[] aParams) |
| throws ResourceAccessException { |
| return getResourceAsStreamCommon(getResource(aKey, aParams)); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.resource.ResourceManager#getResourceAsStream(java.lang.String) |
| */ |
| @Override |
| public InputStream getResourceAsStream(String aKey) throws ResourceAccessException { |
| return getResourceAsStreamCommon(getResource(aKey)); |
| } |
| |
| private InputStream getResourceAsStreamCommon(Object resource) throws ResourceAccessException { |
| checkDestroyed(); |
| try { |
| if (resource != null && resource instanceof DataResource) { |
| return ((DataResource) resource).getInputStream(); |
| } else { |
| return null; |
| } |
| } catch (IOException e) { |
| throw new ResourceAccessException(e); |
| } |
| } |
| |
| private URL getResourceAsStreamCommonUrl(Object resource) { |
| if (resource != null && resource instanceof DataResource) { |
| return ((DataResource) resource).getUrl(); |
| } else { |
| return null; |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.resource.ResourceManager#getResourceURL(java.lang.String, |
| * java.lang.String[]) |
| */ |
| @Override |
| public URL getResourceURL(String aKey, String[] aParams) throws ResourceAccessException { |
| return getResourceAsStreamCommonUrl(getResource(aKey, aParams)); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.resource.ResourceManager#getResourceURL(java.lang.String) |
| */ |
| @Override |
| public URL getResourceURL(String aKey) throws ResourceAccessException { |
| return getResourceAsStreamCommonUrl(getResource(aKey)); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * This method is called during Resource Initialization, |
| * - only for resources which are "local", that is, instances of ResourceCreationSpecifier |
| * - and therefore might have external resource declarations |
| * |
| * Compare with resolveAndValidateResourceDependencies, called for resource binding resolution. |
| * |
| * @see ResourceManager#initializeExternalResources(ResourceManagerConfiguration, String, Map<String, Object>) |
| */ |
| @Override |
| public synchronized void initializeExternalResources(ResourceManagerConfiguration aConfiguration, |
| String aQualifiedContextName, Map<String, Object> aAdditionalParams) |
| throws ResourceInitializationException { |
| // register resources |
| checkDestroyed(); |
| |
| // set up aAdditionalParams to have this resource manager if not already set |
| // so that External Resource instances created from this use this creating/owning |
| // resource manager as the value returned from their getResourceManager call |
| // see https://issues.apache.org/jira/browse/UIMA-5148 |
| if (null == aAdditionalParams) { |
| aAdditionalParams = new HashMap<String, Object>(); |
| } |
| if (!aAdditionalParams.containsKey(Resource.PARAM_RESOURCE_MANAGER)) { |
| aAdditionalParams.put(Resource.PARAM_RESOURCE_MANAGER, this); |
| } |
| |
| // set up aAdditionalParams to have this resource manager if not already set |
| // so that External Resource instances created from this use this creating/owning |
| // UIMA Context so that getResourceManager works |
| // see https://issues.apache.org/jira/browse/UIMA-5153 |
| |
| ExternalResourceDescription[] resources = aConfiguration.getExternalResources(); |
| for (int i = 0; i < resources.length; i++) { |
| String name = resources[i].getName(); |
| |
| // check for existing resource registration under this name |
| ResourceRegistration registration = mInternalResourceRegistrationMap.get(name); |
| if (registration == null) { |
| registerResource(name, resources[i], aQualifiedContextName, aAdditionalParams); |
| } else { |
| // log a message if the resource definitions are not identical |
| if (!registration.description.equals(resources[i])) { |
| // if the resource was overridden in an enclosing aggregate, use an INFO level message. |
| // if not (e.g. sibling annotators declare the same resource name), it's a WARNING. |
| if (aQualifiedContextName.startsWith(registration.definingContext)) { |
| UIMAFramework.getLogger().logrb(Level.CONFIG, ResourceManager_impl.class.getName(), |
| "initializeExternalResources", LOG_RESOURCE_BUNDLE, |
| "UIMA_overridden_resource__CONFIG", |
| new Object[] { name, aQualifiedContextName, registration.definingContext}); |
| } else { |
| UIMAFramework.getLogger().logrb(Level.WARNING, ResourceManager_impl.class.getName(), |
| "initializeExternalResources", LOG_RESOURCE_BUNDLE, |
| "UIMA_duplicate_resource_name__WARNING", |
| new Object[] { name, registration.definingContext, aQualifiedContextName}); |
| } |
| } |
| } |
| } |
| // apply bindings |
| ExternalResourceBinding[] bindings = aConfiguration.getExternalResourceBindings(); |
| for (int i = 0; i < bindings.length; i++) { |
| ResourceRegistration registration = mInternalResourceRegistrationMap |
| .get(bindings[i].getResourceName()); |
| if (registration == null) { |
| throw new ResourceInitializationException( |
| ResourceInitializationException.UNKNOWN_RESOURCE_NAME, new Object[] { |
| bindings[i].getResourceName(), bindings[i].getSourceUrlString() }); |
| } |
| mResourceMap.put(aQualifiedContextName + bindings[i].getKey(), registration.resource); |
| // record the link from key to resource class (for parameterized resources only) |
| Class<?> impl = mInternalParameterizedResourceImplClassMap.get(bindings[i].getResourceName()); |
| mParameterizedResourceImplClassMap.put(aQualifiedContextName + bindings[i].getKey(), |
| (impl == null) ? EMPTY_RESOURCE_CLASS : impl); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * Called during resource initialization, when the resource has external resource bindings, |
| * to resolve those bindings |
| * |
| * @see ResourceManager#resolveAndValidateResourceDependencies(ExternalResourceDependency[], String) |
| * |
| * Multi-threaded. Partial avoidance of re-resolving, but if a resource fails to resolve, it will be |
| * reattempted on every call |
| */ |
| @Override |
| public synchronized void resolveAndValidateResourceDependencies(ExternalResourceDependency[] aDependencies, |
| String aQualifiedContextName) throws ResourceInitializationException { |
| checkDestroyed(); |
| for (int i = 0; i < aDependencies.length; i++) { |
| // get resource |
| String qname = aQualifiedContextName + aDependencies[i].getKey(); |
| Object resourceImpl = mResourceMap.get(qname); // may or may not implement Resource, may implement SharedResourceObject |
| |
| if (resourceImpl == null) { |
| // no resource found |
| // try to look up in classpath/datapath |
| URL relativeUrl; |
| try { |
| relativeUrl = new URL("file", "", aDependencies[i].getKey()); |
| } catch (MalformedURLException e) { |
| throw new ResourceInitializationException(e); |
| } |
| URL absUrl = getRelativePathResolver().resolveRelativePath(relativeUrl); |
| if (absUrl != null) { |
| // found - create a DataResource object and store it in the mResourceMap |
| FileResourceSpecifier spec = new FileResourceSpecifier_impl(); |
| spec.setFileUrl(absUrl.toString()); |
| // produces an instance of DataResourceImpl |
| resourceImpl = UIMAFramework.produceResource(spec, null); |
| mResourceMap.put(qname, resourceImpl); |
| } |
| } |
| |
| if (resourceImpl == null) { // still no resource found - throw exception if required |
| |
| if (!aDependencies[i].isOptional()) { |
| throw new ResourceInitializationException( |
| ResourceInitializationException.RESOURCE_DEPENDENCY_NOT_SATISFIED, new Object[] { |
| aDependencies[i].getKey(), aDependencies[i].getSourceUrlString() }); |
| } |
| |
| } else { // resource not null |
| |
| // make sure resource exists and implements the correct interface |
| try { |
| String name = aDependencies[i].getInterfaceName(); |
| if (name != null && name.length() > 0) { |
| Class<?> theInterface = loadUserClass(name); |
| |
| Class<?> resourceClass = getResourceClass(qname); |
| if (!theInterface.isAssignableFrom(resourceClass)) { |
| throw new ResourceInitializationException( |
| ResourceInitializationException.RESOURCE_DOES_NOT_IMPLEMENT_INTERFACE, |
| new Object[] { qname, aDependencies[i].getInterfaceName(), |
| aDependencies[i].getSourceUrlString() }); |
| } |
| } |
| } catch (ClassNotFoundException e) { |
| throw new ResourceInitializationException( |
| ResourceInitializationException.CLASS_NOT_FOUND, new Object[] { |
| aDependencies[i].getInterfaceName(), aDependencies[i].getSourceUrlString() }); |
| } |
| } |
| |
| } |
| } |
| |
| /** |
| * Instantiates a resource and inserts it in the internal resource map. |
| */ |
| private void registerResource(String aName, ExternalResourceDescription aResourceDescription, |
| String aDefiningContext, Map<String, Object> aResourceInitParams) throws ResourceInitializationException { |
| // add the relative path resolver to the resource init. params |
| Map<String, Object> initParams = (aResourceInitParams == null) ? new HashMap<String, Object>() : new HashMap<String, Object>( |
| aResourceInitParams); |
| initParams.put(DataResource.PARAM_RELATIVE_PATH_RESOLVER, getRelativePathResolver()); |
| |
| // determine if verification mode is on. If so, we don't want to load the resource data |
| boolean verificationMode = initParams.containsKey(AnalysisEngineImplBase.PARAM_VERIFICATION_MODE); |
| |
| // create the initial resource using the resource factory |
| Resource r = UIMAFramework.produceResource(aResourceDescription.getResourceSpecifier(), |
| initParams); |
| |
| // load implementation class (if any) and ensure that it implements |
| // SharedResourceObject |
| String implementationName = aResourceDescription.getImplementationName(); |
| Class<?> implClass = null; // might or might not impl Resource |
| Object implInstance = r; // what will be registered, might be the Resource, or its implementation |
| if (implementationName != null && implementationName.length() > 0) { |
| try { |
| implClass = loadUserClass(implementationName); |
| } catch (ClassNotFoundException e) { |
| throw new ResourceInitializationException(ResourceInitializationException.CLASS_NOT_FOUND, |
| new Object[] { implementationName, aResourceDescription.getSourceUrlString() }, e); |
| } |
| |
| if (!SharedResourceObject.class.isAssignableFrom(implClass)) { |
| throw new ResourceInitializationException( |
| ResourceInitializationException.NOT_A_SHARED_RESOURCE_OBJECT, new Object[] { |
| implementationName, aResourceDescription.getSourceUrlString() }); |
| } |
| } |
| |
| // is this a DataResource? |
| if (r instanceof DataResource) { |
| // instantiate and load the resource object if there is one |
| if (implClass != null) { |
| try { |
| SharedResourceObject sro = (SharedResourceObject) implClass.newInstance(); |
| if (!verificationMode) { |
| sro.load((DataResource) r); |
| } |
| implInstance = sro; // so the implementation is registered, for DataResources |
| } catch (InstantiationException e) { |
| throw new ResourceInitializationException( |
| ResourceInitializationException.COULD_NOT_INSTANTIATE, new Object[] { |
| implClass.getName(), aResourceDescription.getSourceUrlString() }, e); |
| } catch (IllegalAccessException e) { |
| throw new ResourceInitializationException( |
| ResourceInitializationException.COULD_NOT_INSTANTIATE, new Object[] { |
| implClass.getName(), aResourceDescription.getSourceUrlString() }, e); |
| } |
| } |
| } |
| // is it a ParameterizedDataResource? |
| else if (r instanceof ParameterizedDataResource) { |
| // we can't load the SharedResourceObject now, but we need to remember |
| // which class it is for later when we get a request with parameters |
| mInternalParameterizedResourceImplClassMap.put(aName, (null == implClass) ? EMPTY_RESOURCE_CLASS : implClass); |
| } else { |
| // it is some other type of Resource |
| // it is an error to specify an implementation class in this case |
| if (implClass != null) { |
| throw new ResourceInitializationException( |
| ResourceInitializationException.NOT_A_DATA_RESOURCE, new Object[] { |
| implClass.getName(), aName, r.getClass().getName(), |
| aResourceDescription.getSourceUrlString() }); |
| } |
| } |
| |
| // put resource or its implementation (for DataResources) in internal map for later retrieval |
| ResourceRegistration registration = new ResourceRegistration(implInstance, aResourceDescription, |
| aDefiningContext); |
| mInternalResourceRegistrationMap.put(aName, registration); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.uima.resource.ResourceManager#getCasManager() |
| */ |
| @Override |
| public CasManager getCasManager() { |
| //Optimization for case where mCasManager already created |
| // Some sync contention was observed - this makes it less. UIMA-4012 |
| if(mCasManager != null) { |
| return mCasManager; |
| } |
| synchronized(casManagerMonitor) { |
| if (mCasManager == null) { |
| mCasManager = new CasManager_impl(this); |
| } |
| return mCasManager; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.uima.resource.ResourceManager#setCasManager(org.apache.uima.resource.CasManager) |
| */ |
| @Override |
| public void setCasManager(CasManager aCasManager) { |
| synchronized(casManagerMonitor) { |
| if (mCasManager == null) { |
| mCasManager = aCasManager; |
| } |
| else { |
| throw new UIMA_IllegalStateException( |
| UIMA_IllegalStateException.CANNOT_SET_CAS_MANAGER, new Object[0]); |
| } |
| } |
| } |
| |
| // This method overridden by subclass for pear wrapper |
| protected RelativePathResolver getRelativePathResolver() { |
| return mRelativePathResolver; |
| } |
| |
| @Override |
| public Map<String, XMLizable> getImportCache() { |
| return importCache; |
| } |
| |
| public Map<String, Set<String>> getImportUrlsCache() { |
| return importUrlsCache; |
| } |
| |
| @Override |
| public <N> Class<N> loadUserClass(String name) throws ClassNotFoundException { |
| return Class_TCCL.forName(name, this, true); |
| } |
| |
| public static Class<?> loadUserClass(String name, ResourceManager rm) throws ClassNotFoundException { |
| return Class_TCCL.forName(name, rm, true); |
| } |
| |
| public static Class<?> loadUserClassOrThrow(String name, ResourceManager rm, ResourceSpecifier aSpecifier) |
| throws ResourceInitializationException { |
| try { |
| return Class_TCCL.forName(name, rm, true); |
| } catch (ClassNotFoundException e) { |
| throw new ResourceInitializationException( |
| ResourceInitializationException.CLASS_NOT_FOUND, new Object[] { name, |
| aSpecifier.getSourceUrlString() }, e); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.uima.resource.ResourceManager#destroy() |
| */ |
| @Override |
| public void destroy() { |
| boolean alreadyDestroyed = isDestroyed.getAndSet(true); |
| if (alreadyDestroyed) { |
| return; |
| } |
| |
| for (ResourceRegistration rr : mInternalResourceRegistrationMap.values()) { |
| if (rr.resource instanceof Resource) { |
| ((Resource)rr.resource).destroy(); |
| } |
| } |
| |
| for (Object r : mParameterizedResourceInstanceMap.values()) { |
| if (r instanceof Resource) { |
| ((Resource)r).destroy(); |
| } |
| } |
| |
| if (uimaCL != null) { |
| try { |
| uimaCL.close(); |
| } catch (IOException e) { |
| UIMAFramework.getLogger().logrb(Level.WARNING, ResourceManager_impl.class.getName(), |
| "destroy", LOG_RESOURCE_BUNDLE, "UIMA_Classloader_close_exception", e); |
| } |
| } |
| |
| // https://issues.apache.org/jira/browse/UIMA-5935 |
| Map<ResourceManager, Map<PearAnalysisEngineWrapper.StringPair, ResourceManager>> cachedResourceManagers = |
| PearAnalysisEngineWrapper.getCachedResourceManagers(); |
| synchronized(cachedResourceManagers) { |
| Map<PearAnalysisEngineWrapper.StringPair, ResourceManager> c1 = cachedResourceManagers.get(this); |
| if (c1 != null) { |
| for (ResourceManager rm : c1.values()) { |
| rm.destroy(); |
| } |
| } |
| } |
| |
| // not clearing mResourcMap, mInternalResourceRegistrationMap, mParameterizedResourceImplClassMap, |
| // mInternalParameterizedResourceImplClassMap, mParameterizedResourceInstanceMap |
| // because these could be shared with other resource managers |
| // not clearing importCache, importUrlsCache - might be in used by other Resource Managers (shared) |
| |
| |
| // no destroy of caspool at this time |
| |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.uima.resource.ResourceManager#getExternalResources() |
| */ |
| @Override |
| public List<Object> getExternalResources() { |
| |
| List<Object> rs = new ArrayList<>(); |
| for (ResourceRegistration r : mInternalResourceRegistrationMap.values()) { |
| if (!(r instanceof ParameterizedDataResource)) { |
| rs.add(r.resource); |
| } |
| } |
| |
| for (Object r : mParameterizedResourceInstanceMap.values()) { |
| rs.add(r); |
| } |
| |
| return rs; |
| } |
| |
| |
| |
| |
| |
| } |