/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.uima.util; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; import org.apache.uima.ResourceFactory; import org.apache.uima.UIMAFramework; import org.apache.uima.resource.Resource; import org.apache.uima.resource.ResourceInitializationException; import org.apache.uima.resource.ResourceSpecifier; /** * A simple implementation of a {@link org.apache.uima.ResourceFactory}. This implementation * maintains a Map between the {@link ResourceSpecifier} sub-interface name (e.g. * <code>AnalysisEngineDescription</code>) and the class name of the resource to be constructed * from specifiers of that type. * <p> * UIMA developers who introduce new types of {@link Resource}s or {@link ResourceSpecifier}s may * create an instance of this class and use the {@link #addMapping(Class,Class)} method to register * a mapping between the ResourceSpecifier interface and the Class of the Resource that is to be * constructed from it. The <code>SimpleResourceFactory</code> should then be registered with the * framework by calling * <code>{@link UIMAFramework#getResourceFactory()}.{@link org.apache.uima.CompositeResourceFactory#registerFactory(Class,ResourceFactory) registerFactory(Class,ResourceFactory)};</code> * * */ public class SimpleResourceFactory implements ResourceFactory { /** * resource bundle for log messages */ private static final String LOG_RESOURCE_BUNDLE = "org.apache.uima.impl.log_messages"; /** * current class */ private static final Class<SimpleResourceFactory> CLASS_NAME = SimpleResourceFactory.class; /** * Map from ResourceSpecifier Class to List of Resource Classes. Resource initialization is * attempted in reverse order through this List, so more recently registered classes are tried * first. */ protected Map<Class<? extends ResourceSpecifier>, List<Class<? extends Resource>>> mClassMap = Collections.synchronizedMap(new HashMap<Class<? extends ResourceSpecifier>, List<Class<? extends Resource>>>()); /** * Produces an appropriate <code>Resource</code> instance from a <code>ResourceSpecifier</code>. * * @param aResourceClass * the interface of the resource to be produced. This is intended to be a standard UIMA * interface such as <code>TextAnalysisEngine</code> or <code>ASB</code>. * @param aSpecifier * an object that specifies how to acquire an instance of a <code>Resource</code>. * @param aAdditionalParams * a Map containing additional parameters to pass to the * {@link Resource#initialize(ResourceSpecifier,Map)} method. May be <code>null</code> * if there are no parameters. * * @return a <code>Resource</code> instance. Returns <code>null</code> if this factory does * not know how to create a Resource from the <code>ResourceSpecifier</code> provided. * * @throws ResourceInitializationException * if a failure occurred during production of the resource * * @see org.apache.uima.ResourceFactory#produceResource(Class, ResourceSpecifier,Map) */ public Resource produceResource(Class<? extends Resource> aResourceClass, ResourceSpecifier aSpecifier, Map<String, Object> aAdditionalParams) throws ResourceInitializationException { ResourceInitializationException lastException = null; // get all interfaces implemented by aSpecifier Class<?>[] interfaces = aSpecifier.getClass().getInterfaces(); // look up class mapping List<Class<? extends Resource>> resourceClasses = null; for (int i = 0; i < interfaces.length; i++) { resourceClasses = mClassMap.get(interfaces[i]); if (resourceClasses != null) break; } if (resourceClasses != null) { // iterate backwards through the elements of the list, so that // we attempt to initialize the most recently registered Resource // classes first ListIterator<Class<? extends Resource>> i = resourceClasses.listIterator(resourceClasses.size()); while (i.hasPrevious()) { Class<? extends Resource> currentClass = i.previous(); ResourceInitializationException currentException = null; try { // check to see if this is a subclass of aResourceClass if (aResourceClass.isAssignableFrom(currentClass)) { // instantiate this Resource Class Resource resource = currentClass.newInstance(); // attempt to initialize it UIMAFramework.getLogger(CLASS_NAME).logrb(Level.CONFIG, CLASS_NAME.getName(), "produceResource", LOG_RESOURCE_BUNDLE, "UIMA_trying_resource_class__CONFIG", currentClass.getName()); if (resource.initialize(aSpecifier, aAdditionalParams)) { // success! return resource; } } } // if an exception occurs, log it but do not throw it... yet catch (IllegalAccessException e) { currentException = new ResourceInitializationException( ResourceInitializationException.COULD_NOT_INSTANTIATE, new Object[] { currentClass.getName(), aSpecifier.getSourceUrlString() }, e); } catch (InstantiationException e) { currentException = new ResourceInitializationException( ResourceInitializationException.COULD_NOT_INSTANTIATE, new Object[] { currentClass.getName(), aSpecifier.getSourceUrlString() }, e); } catch (Throwable t) { currentException = new ResourceInitializationException( ResourceInitializationException.ERROR_INITIALIZING_FROM_DESCRIPTOR, new Object[] { currentClass.getName(), aSpecifier.getSourceUrlString() }, t); } finally { if (currentException != null) { currentException.fillInStackTrace(); // UIMAFramework.getLogger().logException(currentException); // store this exception lastException = currentException; } } // try again } } // No resource could be created. If an exception occurred, // throw it. Otherwise, return null. if (lastException != null) { throw lastException; } else { return null; } } /** * Configures this <code>SimpleResourceFactory</code> by adding a new mapping between a * <code>ResourceSpecifier</code> class and a <code>Resource</code> class. * * @param aSpecifierInterface * the subinterface of <code>ResourceSpecifier</code>. * @param aResourceClass * a subclass of <code>Resource</code> that is to be instantiated from resource * specifiers of the given class. */ public void addMapping(Class<? extends ResourceSpecifier> aSpecifierInterface, Class<? extends Resource> aResourceClass) { List<Class<? extends Resource>> mappingList = mClassMap.get(aSpecifierInterface); if (mappingList == null) { // No mapping exists. Create a new list and put it in the map. mappingList = new ArrayList<Class<? extends Resource>>(); mClassMap.put(aSpecifierInterface, mappingList); } // add the new Resource Class to the end of the mapping list mappingList.add(aResourceClass); } /** * Configures this <code>SimpleResourceFactory</code> by adding a new mapping between a * <code>ResourceSpecifier</code> class and a <code>Resource</code> class. * * @param aSpecifierInterfaceName * name of the subinterface of <code>ResourceSpecifier</code>. * @param aResourceClassName * the name of a subclass of <code>Resource</code> that is to be instantiated from * resource specifiers of the given class. */ @SuppressWarnings("unchecked") public void addMapping(String aSpecifierInterfaceName, String aResourceClassName) throws ClassNotFoundException { addMapping((Class<? extends ResourceSpecifier>) Class.forName(aSpecifierInterfaceName), (Class<? extends Resource>) Class.forName(aResourceClassName)); } }