All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gate.creole.AbstractController Maven / Gradle / Ivy

Go to download

GATE - general achitecture for text engineering - is open source software capable of solving almost any text processing problem. This artifact enables you to embed the core GATE Embedded with its essential dependencies. You will able to use the GATE Embedded API and load and store GATE XML documents. This artifact is the perfect dependency for CREOLE plugins or for applications that need to customize the GATE dependencies due to confict with their own dependencies or for lower footprint.

The newest version!
/*
 *  Copyright (c) 1995-2012, The University of Sheffield. See the file
 *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
 *
 *  This file is part of GATE (see http://gate.ac.uk/), and is free
 *  software, licenced under the GNU Library General Public License,
 *  Version 2, June 1991 (in the distribution as file licence.html,
 *  and also available at http://gate.ac.uk/gate/licence.html).
 *
 *  Valentin Tablan 27 Sep 2001
 *
 *  $I$
 */
package gate.creole;

import gate.Controller;
import gate.Gate;
import gate.ProcessingResource;
import gate.Resource;
import gate.creole.metadata.CreoleResource;
import gate.event.ControllerEvent;
import gate.event.ControllerListener;
import gate.event.ProgressListener;
import gate.event.StatusListener;
import gate.util.Benchmark;
import gate.util.Benchmarkable;

import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

@CreoleResource(icon = "application")
public abstract class AbstractController extends AbstractResource 
       implements Controller, ProcessingResource, Benchmarkable {

  private static final long serialVersionUID = 6466829205468662382L;

  /**
   * Benchmark ID of this resource.
   */
  protected String benchmarkID;

  /**
   * Shared featureMap
   */
  protected Map benchmarkFeatures = new HashMap();

  // executable code
  /**
   * Execute this controller. This implementation takes care of informing any
   * {@link ControllerAwarePR}s of the start and end of execution, and
   * delegates to the {@link #executeImpl()} method to do the real work.
   * Subclasses should override {@link #executeImpl()} rather than this method.
   */
  @Override
  public void execute() throws ExecutionException {

    // inform ControllerAware PRs that execution has started, if automatic callbacks are enabled
    if(controllerCallbacksEnabled) { 
      invokeControllerExecutionStarted();
    }
    Throwable thrown = null;
    try {
      if(Benchmark.isBenchmarkingEnabled()) {
        // write a start marker to the benchmark log for this
        // controller as a whole
        Benchmark.startPoint(getBenchmarkId());
      }
      // do the real work
      this.executeImpl();
    }
    catch(Throwable t) {
      thrown = t;
    }
    finally {
      if(thrown == null) {
        // successfully completed
        if(controllerCallbacksEnabled) {
          invokeControllerExecutionFinished();
        }
      }
      else {
        // aborted
        if(controllerCallbacksEnabled) {
          invokeControllerExecutionAborted(thrown);
        }

        // rethrow the aborting exception or error
        if(thrown instanceof Error) {
          throw (Error)thrown;
        }
        else if(thrown instanceof RuntimeException) {
          throw (RuntimeException)thrown;
        }
        else if(thrown instanceof ExecutionException) {
          throw (ExecutionException)thrown;
        }
        else {
          // we have a checked exception that isn't one executeImpl can
          // throw. This shouldn't be possible, but just in case...
          throw new UndeclaredThrowableException(thrown);
        }
      }
    }

  }

  /**
   * Get the set of PRs from this controller that implement
   * {@link ControllerAwarePR}. If there are no such PRs in this controller, an
   * empty set is returned. This implementation simply filters the collection
   * returned by {@link Controller#getPRs()}, override this method if your
   * subclass admits a more efficient implementation.
   */
  protected Set getControllerAwarePRs() {
    Set returnSet = null;
    for(Object pr : getPRs()) {
      if(pr instanceof ControllerAwarePR) {
        if(returnSet == null) {
          returnSet = new HashSet();
        }
        returnSet.add((ControllerAwarePR)pr);
      }
    }

    if(returnSet == null) {
      // optimization - don't waste time creating a new set in the most
      // common case where there are no Controller aware PRs
      return Collections.emptySet();
    }
    else {
      return returnSet;
    }
  }

  /**
   * Executes the PRs in this controller, according to the execution strategy of
   * the particular controller type (simple pipeline, parallel execution,
   * once-per-document in a corpus, etc.). Subclasses should override this
   * method, allowing the default {@link #execute()} method to handle sending
   * notifications to controller aware PRs.
   */
  protected void executeImpl() throws ExecutionException {
    throw new ExecutionException("Controller " + getClass()
      + " hasn't overriden the executeImpl() method");
  }

  /** Initialise this resource, and return it. */
  @Override
  public Resource init() throws ResourceInstantiationException {
    return this;
  }

  /* (non-Javadoc)
   * @see gate.ProcessingResource#reInit()
   */
  @Override
  public void reInit() throws ResourceInstantiationException {
    init();
  }

  /** Clears the internal data of the resource, when it gets released * */
  @Override
  public void cleanup() {
  }

  /**
   * Populates this controller from a collection of {@link ProcessingResource}s
   * (optional operation).
   * 
   * Controllers that are serializable must implement this method needed by GATE
   * to restore their contents.
   * 
   * @throws UnsupportedOperationException
   *           if the setPRs method is not supported by this
   *           controller.
   */
  @Override
  public void setPRs(Collection PRs) {
  }

  /**
   * Notifies all the PRs in this controller that they should stop their
   * execution as soon as possible.
   */
  @Override
  public synchronized void interrupt() {
    interrupted = true;
    Iterator prIter = getPRs().iterator();
    while(prIter.hasNext()) {
      prIter.next().interrupt();
    }
  }

  @Override
  public synchronized boolean isInterrupted() {
    return interrupted;
  }

  // events code
  /**
   * Removes a {@link gate.event.StatusListener} from the list of listeners for
   * this processing resource
   */
  public synchronized void removeStatusListener(StatusListener l) {
    if(statusListeners != null && statusListeners.contains(l)) {
      @SuppressWarnings("unchecked")
      Vector v = (Vector)statusListeners.clone();
      v.removeElement(l);
      statusListeners = v;
    }
  }

  /**
   * Adds a {@link gate.event.StatusListener} to the list of listeners for this
   * processing resource
   */
  public synchronized void addStatusListener(StatusListener l) {
    @SuppressWarnings("unchecked")
    Vector v =
      statusListeners == null ? new Vector(2) : (Vector)statusListeners.clone();
    if(!v.contains(l)) {
      v.addElement(l);
      statusListeners = v;
    }
  }

  /**
   * Notifies all the {@link gate.event.StatusListener}s of a change of status.
   * 
   * @param e
   *          the message describing the status change
   */
  protected void fireStatusChanged(String e) {
    if(statusListeners != null) {
      Vector listeners = statusListeners;
      int count = listeners.size();
      for(int i = 0; i < count; i++) {
        listeners.elementAt(i).statusChanged(e);
      }
    }
  }

  /**
   * Adds a {@link gate.event.ProgressListener} to the list of listeners for
   * this processing resource.
   */
  public synchronized void addProgressListener(ProgressListener l) {
    @SuppressWarnings("unchecked")
    Vector v =
      progressListeners == null ? new Vector(2) : (Vector)progressListeners
        .clone();
    if(!v.contains(l)) {
      v.addElement(l);
      progressListeners = v;
    }
  }

  /**
   * Removes a {@link gate.event.ProgressListener} from the list of listeners
   * for this processing resource.
   */
  public synchronized void removeProgressListener(ProgressListener l) {
    if(progressListeners != null && progressListeners.contains(l)) {
      @SuppressWarnings("unchecked")
      Vector v = (Vector)progressListeners.clone();
      v.removeElement(l);
      progressListeners = v;
    }
  }

  /**
   * Notifies all the {@link gate.event.ProgressListener}s of a progress change
   * event.
   * 
   * @param e
   *          the new value of execution completion
   */
  protected void fireProgressChanged(int e) {
    if(progressListeners != null) {
      Vector listeners = progressListeners;
      int count = listeners.size();
      for(int i = 0; i < count; i++) {
        listeners.elementAt(i).progressChanged(e);
      }
    }
  }

  /**
   * Notifies all the {@link gate.event.ProgressListener}s of a progress
   * finished.
   */
  protected void fireProcessFinished() {
    if(progressListeners != null) {
      Vector listeners = progressListeners;
      int count = listeners.size();
      for(int i = 0; i < count; i++) {
        listeners.elementAt(i).processFinished();
      }
    }
  }

  /**
   * A progress listener used to convert a 0..100 interval into a smaller one
   */
  protected class IntervalProgressListener implements ProgressListener {
    public IntervalProgressListener(int start, int end) {
      this.start = start;
      this.end = end;
    }

    @Override
    public void progressChanged(int i) {
      fireProgressChanged(start + (end - start) * i / 100);
    }

    @Override
    public void processFinished() {
      fireProgressChanged(end);
    }

    int start;
    int end;
  }// CustomProgressListener

  /**
   * A simple status listener used to forward the events upstream.
   */
  protected class InternalStatusListener implements StatusListener {
    @Override
    public void statusChanged(String message) {
      fireStatusChanged(message);
    }
  }

  /**
   * Checks whether all the contained PRs have all the required runtime
   * parameters set.
   * 
   * @return a {@link List} of {@link ProcessingResource}s that have required
   *         parameters with null values if they exist null
   *         otherwise.
   * @throws ResourceInstantiationException
   *           if problems occur while inspecting the parameters for one of the
   *           resources. These will normally be introspection problems and are
   *           usually caused by the lack of a parameter or of the read accessor
   *           for a parameter.
   */
  public List getOffendingPocessingResources()
    throws ResourceInstantiationException {
    // take all the contained PRs
    List badPRs = new ArrayList(getPRs());
    // remove the ones that no parameters problems
    Iterator prIter = getPRs().iterator();
    while(prIter.hasNext()) {
      ProcessingResource pr = prIter.next();
      ResourceData rData =
        Gate.getCreoleRegister().get(pr.getClass().getName());
      if(AbstractResource.checkParameterValues(pr, rData.getParameterList()
        .getRuntimeParameters())) {
        badPRs.remove(pr);
      }
    }
    return badPRs.isEmpty() ? null : badPRs;
  }

  public synchronized void removeControllerListener(ControllerListener l) {
    if(controllerListeners != null && controllerListeners.contains(l)) {
      @SuppressWarnings("unchecked")
      Vector v = (Vector)controllerListeners.clone();
      v.removeElement(l);
      controllerListeners = v;
    }
  }

  public synchronized void addControllerListener(ControllerListener l) {
    @SuppressWarnings("unchecked")
    Vector v =
      controllerListeners == null ? new Vector(2) : (Vector)controllerListeners
        .clone();
    if(!v.contains(l)) {
      v.addElement(l);
      controllerListeners = v;
    }
  }

  /**
   * The list of {@link gate.event.StatusListener}s registered with this
   * resource
   */
  private transient Vector statusListeners;

  /**
   * The list of {@link gate.event.ProgressListener}s registered with this
   * resource
   */
  private transient Vector progressListeners;

  /**
   * The list of {@link gate.event.ControllerListener}s registered with this
   * resource
   */
  private transient Vector controllerListeners;

  protected boolean interrupted = false;

  protected void fireResourceAdded(ControllerEvent e) {
    if(controllerListeners != null) {
      Vector listeners = controllerListeners;
      int count = listeners.size();
      for(int i = 0; i < count; i++) {
        listeners.elementAt(i).resourceAdded(e);
      }
    }
  }

  protected void fireResourceRemoved(ControllerEvent e) {
    if(controllerListeners != null) {
      Vector listeners = controllerListeners;
      int count = listeners.size();
      for(int i = 0; i < count; i++) {
        listeners.elementAt(i).resourceRemoved(e);
      }
    }
  }
  
  /**
   * Sets the benchmark ID of this controller.
   */
  @Override
  public void setBenchmarkId(String benchmarkID) {
    this.benchmarkID = benchmarkID;
  }

  /**
   * Returns the benchmark ID of this controller.
   */
  @Override
  public String getBenchmarkId() {
    if(benchmarkID == null) {
      benchmarkID = getName().replaceAll("[ ]+", "_");
    }
    return benchmarkID;
  }
  
   /**
   * Invoke the controllerExecutionStarted method on this controller and all nested PRs and controllers. 
   * This method is intended to be used after if the automatic invocation of the controller
   * callback methods has been disabled with a call setControllerCallbackEnabled(false).  Normally
   * the callback methods are automatically invoked at the start and end of execute().  
   * @throws ExecutionException 
   */
  public void invokeControllerExecutionStarted() throws ExecutionException {
    for (ControllerAwarePR pr : getControllerAwarePRs()) {
      pr.controllerExecutionStarted(this);
    }
  }

   /**
   * Invoke the controllerExecutionFinished method on this controller and all nested PRs and controllers. 
   * This method is intended to be used after if the automatic invocation of the controller
   * callback methods has been disabled with a call setControllerCallbackEnabled(false).  Normally
   * the callback methods are automatically invoked at the start and end of execute().  
   * @throws ExecutionException 
   */
  public void invokeControllerExecutionFinished() throws ExecutionException {
    for (ControllerAwarePR pr : getControllerAwarePRs()) {
      pr.controllerExecutionFinished(this);
    }
  }
  
   /**
   * Invoke the controllerExecutionAborted method on this controller and all nested PRs and controllers. 
   * This method is intended to be used after if the automatic invocation of the controller
   * callback methods has been disabled with a call setControllerCallbackEnabled(false).  Normally
   * the callback methods are automatically invoked at the start and end of execute().  
   * @throws ExecutionException 
   */
  public void invokeControllerExecutionAborted(Throwable thrown) throws ExecutionException {
    for (ControllerAwarePR pr : getControllerAwarePRs()) {
      pr.controllerExecutionAborted(this, thrown);
    }
  }
    
  protected boolean controllerCallbacksEnabled = true;  
  /**
   * Enable or disable the automatic invocation of the controller callbacks. 
   * By default, the controller calls the controllerExecutionStarted method of each controllerAwarePR
   * at the start of execute(), the controllerExecutionFinished method of each controllerAwarePR
   * at the end of execute() or the controllerExecutionAborted method of each controllerAwarePR if
   * there was an exception during execute(). If this method is called with the parameter false
   * before execute() is called, then those controllerAwarePR methods will not get called automatically.
   * In that case they can invoked deliberately using the invokeControllerExecutionStarted(), 
   * invokeControllerExecutionFinished() and controllerExecutionAborted() methods.
   * 
   * @param flag a boolean indicating if the callbacks should be enabled (true) or disabled (false)
   */
  public void setControllerCallbacksEnabled(boolean flag) {
    controllerCallbacksEnabled = flag;
  }
    
    
  
  
  
  
  
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy