| /* |
| * 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.Date; |
| import java.util.Vector; |
| |
| import org.apache.uima.UIMAFramework; |
| import org.apache.uima.analysis_engine.AnalysisEngine; |
| import org.apache.uima.analysis_engine.TextAnalysisEngine; |
| import org.apache.uima.cas.CASException; |
| import org.apache.uima.jcas.JCas; |
| import org.apache.uima.resource.ResourceInitializationException; |
| import org.apache.uima.resource.metadata.ProcessingResourceMetaData; |
| |
| /** |
| * This class represents a simple pool of {@link JCas} instances. This is useful for multithreaded |
| * applications, where there is a need for multiple CASes to be processed simultaneously. Because |
| * JCas creation is expensive, it is a good idea to create a pool of reusable JCas instances at |
| * initialization time, rather than creating a new JCas each time one is needed. |
| * <p> |
| * Clients check-out JCas instances from the pool using the {@link #getJCas()} method and check-in |
| * JCas instances using the {@link #releaseJCas(JCas)} method. |
| * |
| * |
| * |
| */ |
| public class JCasPool { |
| |
| private Vector mAllInstances = new Vector(); |
| |
| private Vector mFreeInstances = new Vector(); |
| |
| private int mNumInstances; |
| |
| /** |
| * resource bundle for log messages |
| */ |
| private static final String LOG_RESOURCE_BUNDLE = "org.apache.uima.impl.log_messages"; |
| |
| /** |
| * current class |
| */ |
| private static final Class CLASS_NAME = JCasPool.class; |
| |
| /** |
| * Creates a new JCasPool |
| * |
| * @param aNumInstances |
| * the number of JCas instances in the pool |
| * @param aTextAnalysisEngine |
| * the TAE that will create the JCas instances and which will later be used to process |
| * them |
| * |
| * @throws ResourceInitializationException |
| * if the JCas instances could not be created |
| * |
| * @deprecated As of v2.0, TextAnalysisEngine has been deprecated. Use |
| * {@link #JCasPool(int, AnalysisEngine)} instead. |
| */ |
| public JCasPool(int aNumInstances, TextAnalysisEngine aTextAnalysisEngine) |
| throws ResourceInitializationException { |
| mNumInstances = aNumInstances; |
| |
| fillPool(aTextAnalysisEngine.getAnalysisEngineMetaData()); |
| } |
| |
| /** |
| * Creates a new JCasPool |
| * |
| * @param aNumInstances |
| * the number of JCas instances in the pool |
| * @param aAnalysisEngine |
| * the AE that will create the JCas instances and which will later be used to process |
| * them |
| * |
| * @throws ResourceInitializationException |
| * if the JCas instances could not be created |
| */ |
| public JCasPool(int aNumInstances, AnalysisEngine aAnalysisEngine) |
| throws ResourceInitializationException { |
| mNumInstances = aNumInstances; |
| |
| fillPool(aAnalysisEngine.getAnalysisEngineMetaData()); |
| } |
| |
| /** |
| * Creates a new JCasPool |
| * |
| * @param aNumInstances |
| * the number of JCas 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 JCasPool(int aNumInstances, ProcessingResourceMetaData aMetaData) |
| throws ResourceInitializationException { |
| mNumInstances = aNumInstances; |
| |
| fillPool(aMetaData); |
| } |
| |
| /** |
| * Checks out a JCas from the pool. |
| * |
| * @return a JCas 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 JCas getJCas() { |
| if (!mFreeInstances.isEmpty()) { |
| return (JCas) mFreeInstances.remove(0); |
| } else { |
| // no instances available |
| return null; |
| } |
| } |
| |
| /** |
| * Checks in a JCas to the pool. This automatically calls the {@link JCas#reset()} method, to |
| * ensure that when the JCas 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 aJCas |
| * the JCas to release |
| */ |
| public synchronized void releaseJCas(JCas aJCas) { |
| // make sure this CAS actually belongs to this pool and is checked out |
| if (!mAllInstances.contains(aJCas) || mFreeInstances.contains(aJCas)) { |
| UIMAFramework.getLogger(CLASS_NAME).logrb(Level.WARNING, CLASS_NAME.getName(), "releaseJCas", |
| LOG_RESOURCE_BUNDLE, "UIMA_return_jcas_to_pool__WARNING"); |
| } else { |
| // reset CAS |
| aJCas.reset(); |
| // Add the CAS to the end of the free instances List |
| mFreeInstances.add(aJCas); |
| } |
| |
| // Notify any threads waiting on this object |
| notifyAll(); |
| } |
| |
| /** |
| * Checks out a JCas 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 JCas instance. Returns <code>null</code> if none are available within the specified |
| * timeout period. |
| */ |
| public synchronized JCas getJCas(long aTimeout) { |
| long startTime = new Date().getTime(); |
| JCas cas; |
| while ((cas = getJCas()) == null) { |
| try { |
| wait(aTimeout); |
| } catch (InterruptedException e) { |
| } |
| if (aTimeout > 0 && (new Date().getTime() - startTime) >= aTimeout) { |
| // Timeout has expired |
| return null; |
| } |
| } |
| return cas; |
| } |
| |
| /** |
| * Gets the size of this pool (the total number of JCas instances that it can hold). |
| * |
| * @return the size of this pool |
| */ |
| public int getSize() { |
| return mNumInstances; |
| } |
| |
| /** |
| * Utility method used in the constructor to fill the pool with CAS instances. |
| * |
| * @param aMetaData |
| * metadata including the type sytsem for the CASes |
| * |
| * @throws ResourceInitializationException |
| * if the Resource instances could not be created |
| */ |
| protected void fillPool(ProcessingResourceMetaData aMetaData) |
| throws ResourceInitializationException { |
| // fill the pool |
| ArrayList mdList = new ArrayList(); |
| mdList.add(aMetaData); |
| for (int i = 0; i < mNumInstances; i++) { |
| JCas c; |
| try { |
| c = CasCreationUtils.createCas(mdList).getJCas(); |
| } catch (CASException e) { |
| throw new ResourceInitializationException(e); |
| } |
| mAllInstances.add(c); |
| mFreeInstances.add(c); |
| } |
| } |
| |
| protected Vector getAllInstances() { |
| return mAllInstances; |
| } |
| |
| protected Vector getFreeInstances() { |
| return mFreeInstances; |
| } |
| } |