/* * 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.Collection; import java.util.Properties; import java.util.Vector; import org.apache.uima.UIMAFramework; import org.apache.uima.analysis_engine.AnalysisEngine; import org.apache.uima.cas.CAS; import org.apache.uima.cas.impl.CASImpl; import org.apache.uima.resource.CasDefinition; import org.apache.uima.resource.CasManager; import org.apache.uima.resource.ResourceInitializationException; import org.apache.uima.resource.ResourceManager; import org.apache.uima.resource.metadata.ProcessingResourceMetaData; /** * This class represents a simple pool of {@link CAS} instances. This is useful for multithreaded * applications, where there is a need for multiple CASes to be processed simultaneously. Because * CAS creation is expensive, it is a good idea to create a pool of reusable CAS instances at * initialization time, rather than creating a new CAS each time one is needed. * <p> * Clients check-out CAS instances from the pool using the {@link #getCas()} method and check-in CAS * instances using the {@link #releaseCas(CAS)} method. * * * */ public class CasPool { /** * resource bundle for log messages */ private static final String LOG_RESOURCE_BUNDLE = "org.apache.uima.impl.log_messages"; /** * current class */ private static final Class<CasPool> CLASS_NAME = CasPool.class; private Vector<CAS> mAllInstances = new Vector<CAS>(); private Vector<CAS> mFreeInstances = new Vector<CAS>(); private int mNumInstances; /** * Creates a new CasPool * * @param aNumInstances * the number of CAS instances in the pool * @param aCollectionOfProcessingResourceMetaData * a collection of * {@link ProcessingResourceMetaData} objects. * @param aPerformanceTuningSettings * Properties object containing framework performance tuning settings using key names * defined on {@link UIMAFramework} interface * @param aResourceManager * the resource manager to use to resolve import declarations within the metadata * * @throws ResourceInitializationException * if the CAS instances could not be created */ public CasPool(int aNumInstances, Collection<? extends ProcessingResourceMetaData> aCollectionOfProcessingResourceMetaData, Properties aPerformanceTuningSettings, ResourceManager aResourceManager) throws ResourceInitializationException { mNumInstances = aNumInstances; fillPool(aCollectionOfProcessingResourceMetaData, aPerformanceTuningSettings, aResourceManager); } /** * Creates a new CasPool * * @param aNumInstances * the number of CAS instances in the pool * @param aAnalysisEngine * the analysis engine that will create the CAS instances and which will later be used to * process them * * @throws ResourceInitializationException * if the CAS instances could not be created */ public CasPool(int aNumInstances, AnalysisEngine aAnalysisEngine) throws ResourceInitializationException { mNumInstances = aNumInstances; ArrayList<ProcessingResourceMetaData> mdList = new ArrayList<ProcessingResourceMetaData>(); mdList.add((ProcessingResourceMetaData) aAnalysisEngine.getMetaData()); fillPool(mdList, aAnalysisEngine.getPerformanceTuningSettings(), aAnalysisEngine .getResourceManager()); } /** * Creates a new CasPool * * @param aNumInstances * the number of CAS instances in the pool * @param aMetaData * metadata that includes the type system for the CAS * * @throws ResourceInitializationException * if the CAS instances could not be created */ public CasPool(int aNumInstances, ProcessingResourceMetaData aMetaData) throws ResourceInitializationException { mNumInstances = aNumInstances; ArrayList<ProcessingResourceMetaData> mdList = new ArrayList<ProcessingResourceMetaData>(); mdList.add(aMetaData); fillPool(mdList, null, null); } /** * Creates a new CasPool * * @param aNumInstances * the number of CAS instances in the pool * @param aMetaData * metadata that includes the type system for the CAS * * @throws ResourceInitializationException * if the CAS instances could not be created */ public CasPool(int aNumInstances, ProcessingResourceMetaData aMetaData, ResourceManager aResourceManager) throws ResourceInitializationException { mNumInstances = aNumInstances; ArrayList<ProcessingResourceMetaData> mdList = new ArrayList<ProcessingResourceMetaData>(); mdList.add(aMetaData); fillPool(mdList, null, aResourceManager); } /** * Creates a new CasPool. * TODO: do we need this method AND the one that takes a CasManager? * * @param aNumInstances * the number of CAS instances in the pool * @param aCasDefinition * the Cas definition, which includes the type system, type priorities, and indexes for * the CASes in the pool. * @param aPerformanceTuningSettings * Properties object containing framework performance tuning settings using key names * defined on {@link UIMAFramework} interface */ public CasPool(int aNumInstances, CasDefinition aCasDefinition, Properties aPerformanceTuningSettings) throws ResourceInitializationException { mNumInstances = aNumInstances; fillPool(aCasDefinition, aPerformanceTuningSettings); } /** * Creates a new CasPool * * @param aNumInstances * the number of CAS instances in the pool * @param aCasManager * CAS Manager that will be used to create the CAS. The CAS Manager * holds the CAS Definition. Also all CASes created from the same * CAS Manager will share identical TypeSystem objects. * @param aPerformanceTuningSettings * Properties object containing framework performance tuning settings using key names * defined on {@link UIMAFramework} interface */ public CasPool(int aNumInstances, CasManager aCasManager, Properties aPerformanceTuningSettings) throws ResourceInitializationException { mNumInstances = aNumInstances; fillPool(aCasManager, aPerformanceTuningSettings); } /** * Checks out a CAS from the pool. * * @return a CAS instance. Returns <code>null</code> if none are available (in which case the * client may {@link Object#wait()} on this object in order to be notified when an * instance becomes available). */ public synchronized CAS getCas() { if (!mFreeInstances.isEmpty()) { return (CAS) mFreeInstances.remove(0); } else { // no instances available return null; } } /** * Checks in a CAS to the pool. This automatically calls the {@link CAS#reset()} method, to ensure * that when the CAS is later retrieved from the pool it will be ready to use. Also notifies other * Threads that may be waiting for an instance to become available. * * @param aCas * the Cas to release */ public synchronized void releaseCas(CAS aCas) { // note the pool stores references to the InitialView of each CAS CAS cas = aCas.getView(CAS.NAME_DEFAULT_SOFA); // make sure this CAS actually belongs to this pool and is checked out if (!mAllInstances.contains(cas) || mFreeInstances.contains(cas)) { UIMAFramework.getLogger(CLASS_NAME).logrb(Level.WARNING, CLASS_NAME.getName(), "releaseCas", LOG_RESOURCE_BUNDLE, "UIMA_return_cas_to_pool__WARNING"); } else { // restore the ClassLoader and unlock the CAS, since release() can be called // from within a CAS Multiplier. ((CASImpl)cas).restoreClassLoaderUnlockCas(); // reset CAS cas.reset(); // Add the CAS to the end of the free instances List mFreeInstances.add(cas); } // Notify any threads waiting on this object notifyAll(); } /** * Checks out a CAS from the pool. If none is currently available, wait for the specified amount * of time for one to be checked in. * * @param aTimeout * the time to wait in milliseconds. A value of <=0 will wait forever. * * @return a CAS instance. Returns <code>null</code> if none are available within the specified * timeout period. */ public synchronized CAS getCas(long aTimeout) { // long startTime = new Date().getTime(); long startTime = System.currentTimeMillis(); CAS cas; while ((cas = getCas()) == null) { try { wait(aTimeout); } catch (InterruptedException e) { } // if (aTimeout > 0 && (new Date().getTime() - startTime) >= aTimeout) { if (aTimeout > 0 && (System.currentTimeMillis() - startTime) >= aTimeout) { // Timeout has expired return null; } } return cas; } /** * Gets the size of this pool (the total number of CAS instances that it can hold). * * @return the size of this pool */ public int getSize() { return mNumInstances; } /** * Gets the number of CASes currently available in this pool. * @return the numberof available CASes */ public int getNumAvailable() { return getFreeInstances().size(); } /** * @param componentDescriptionsOrMetaData * @param performanceTuningSettings * @param resourceManager */ private void fillPool(Collection<? extends ProcessingResourceMetaData> mdList, Properties performanceTuningSettings, ResourceManager resourceManager) throws ResourceInitializationException { CasDefinition casDef = new CasDefinition(mdList, resourceManager); fillPool(casDef, performanceTuningSettings); } private void fillPool(CasDefinition casDef, Properties performanceTuningSettings) throws ResourceInitializationException { // create first CAS from metadata CAS c0 = CasCreationUtils.createCas(casDef, performanceTuningSettings); // set owner so cas.release() can return it to the pool ((CASImpl) c0).setOwner(casDef.getCasManager()); mAllInstances.add(c0); mFreeInstances.add(c0); // create additional CASes that share same type system for (int i = 1; i < mNumInstances; i++) { CAS c = CasCreationUtils.createCas(casDef, performanceTuningSettings, c0.getTypeSystem()); ((CASImpl) c).setOwner(casDef.getCasManager()); mAllInstances.add(c); mFreeInstances.add(c); } } private void fillPool(CasManager casManager, Properties performanceTuningSettings) throws ResourceInitializationException { // create additional CASes that share same type system for (int i = 0; i < mNumInstances; i++) { CAS c = casManager.createNewCas(performanceTuningSettings); ((CASImpl) c).setOwner(casManager); mAllInstances.add(c); mFreeInstances.add(c); } } protected Vector<CAS> getAllInstances() { return mAllInstances; } protected Vector<CAS> getFreeInstances() { return mFreeInstances; } }