package edu.stanford.nlp.pipeline; import java.util.Map; import edu.stanford.nlp.util.Generics; /** * An object for keeping track of Annotators. Typical use is to allow multiple * pipelines to share any Annotators in common. * * For example, if multiple pipelines exist, and they both need a * ParserAnnotator, it would be bad to load two such Annotators into memory. * Instead, an AnnotatorPool will only create one Annotator and allow both * pipelines to share it. * * @author bethard */ public class AnnotatorPool { private final Map<String, Annotator> annotators; private final Map<String, AnnotatorFactory> factories; /** * Create an empty AnnotatorPool. */ public AnnotatorPool() { this.annotators = Generics.newHashMap(); this.factories = Generics.newHashMap(); } /** * Register an Annotator that can be created by the pool. * * Note that factories are used here so that many possible annotators can * be defined within the AnnotatorPool, but an Annotator is only created * when one is actually needed. * * @param name The name to be associated with the Annotator. * @param factory A factory that creates an instance of the desired Annotator. * @return true if a new annotator was created; false if we reuse an existing one */ public boolean register(String name, AnnotatorFactory factory) { boolean newAnnotator = false; if (this.factories.containsKey(name)) { AnnotatorFactory oldFactory = this.factories.get(name); String oldSig = oldFactory.signature(); String newSig = factory.signature(); if(! oldSig.equals(newSig)) { // the new annotator uses different properties so we need to update! // TODO: this printout should be logged instead of going to stderr. we need to standardize logging // System.err.println("Replacing old annotator \"" + name + "\" with signature [" // + oldSig + "] with new annotator with signature [" + newSig + "]"); this.factories.put(name, factory); newAnnotator = true; // delete the existing annotator; we'll create one with the new props on demand // removing the annotator like this will not affect any // existing pipelines which use the old annotator, but if // those are all gone, then the old annotator will be garbage // collected and memory will be freed up annotators.remove(name); } // nothing to do if an annotator with same name and signature already exists } else { this.factories.put(name, factory); } return newAnnotator; } /** * Retrieve an Annotator from the pool. If the named Annotator has not yet * been requested, it will be created. Otherwise, the existing instance of * the Annotator will be returned. * * @param name The annotator to retrieve from the pool * @return The annotator * @throws IllegalArgumentException If the annotator cannot be created */ public synchronized Annotator get(String name) { if (!this.annotators.containsKey(name)) { AnnotatorFactory factory = this.factories.get(name); if (factory == null) { throw new IllegalArgumentException("No annotator named " + name); } this.annotators.put(name, factory.create()); } return this.annotators.get(name); } }