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

gate.Factory 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!
/*
 *  Factory.java
 *
 *  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).
 *
 *  Hamish Cunningham, 25/May/2000
 *
 *  $Id: Factory.java 20037 2017-02-01 06:17:21Z markagreenwood $
 */

package gate;

import gate.annotation.ImmutableAnnotationSetImpl;
import gate.creole.AbstractProcessingResource;
import gate.creole.AbstractResource;
import gate.creole.AnnotationSchema;
import gate.creole.ConditionalController;
import gate.creole.CustomDuplication;
import gate.creole.ParameterException;
import gate.creole.ParameterList;
import gate.creole.Plugin;
import gate.creole.ResourceData;
import gate.creole.ResourceInstantiationException;
import gate.event.CreoleEvent;
import gate.event.CreoleListener;
import gate.persist.PersistenceException;
import gate.persist.SerialDataStore;
import gate.util.Out;
import gate.util.SimpleFeatureMapImpl;
import gate.util.Strings;

import java.io.Serializable;
import java.net.URI;
import java.net.URL;
import java.util.Collection;
import java.util.EventListener;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Provides static methods for the creation of Resources.
 */
public abstract class Factory {
  /** Debug flag */
  private static final boolean DEBUG = false;

  private static final boolean DEBUG_DUPLICATION = false;

  private static final Logger log = LoggerFactory.getLogger(Factory.class);

  /** An object to source events from. */
  private static CreoleProxy creoleProxy;

  /**
   * Create an instance of a resource using default parameter values.
   * 
   * @see #createResource(String,FeatureMap)
   */
  public static Resource createResource(String resourceClassName)
          throws ResourceInstantiationException {
    // get the resource metadata
    ResourceData resData = Gate.getCreoleRegister().get(resourceClassName);
    if(resData == null) {
      Set plugins = Gate.getPlugins(resourceClassName);

      StringBuilder msg = new StringBuilder();
      msg.append("Couldn't get resource data for ").append(resourceClassName)
              .append(".\n\n");

      if(plugins.isEmpty()) {
        msg.append("You may need first to load the plugin that contains your resource.\n");
        msg.append("For example, to create a gate.creole.tokeniser.DefaultTokeniser\n");
        msg.append("you need first to load the ANNIE plugin.\n\n");
      } else if(plugins.size() == 1) {
        msg.append(resourceClassName).append(" can be found in the ")
                .append(plugins.iterator().next().getName())
                .append(" plugin\n\n");
      } else {
        msg.append(resourceClassName).append(
                " can be found in the following plugins\n   ");
        for(Plugin dInfo : plugins) {
          msg.append(dInfo.getName()).append(", ");
        }

        msg.setLength(msg.length() - 2);
        msg.append("\n\n");
      }

      msg.append("Go to the menu File->Manage CREOLE plugins or use the method\n");
      msg.append("\"registerPlugin\" on Gate.getCreoleRegister()");

      throw new ResourceInstantiationException(msg.toString());
    }

    // get the parameter list and default values
    ParameterList paramList = resData.getParameterList();
    FeatureMap parameterValues = null;
    try {
      parameterValues = paramList.getInitimeDefaults();
    } catch(ParameterException e) {
      throw new ResourceInstantiationException(
              "Couldn't get default parameters for " + resourceClassName + ": "
                      + e);
    }

    return createResource(resourceClassName, parameterValues);
  } // createResource(resClassName)

  /**
   * Create an instance of a resource, and return it. Callers of this
   * method are responsible for querying the resource's parameter lists,
   * putting together a set that is complete apart from runtime
   * parameters, and passing a feature map containing these parameter
   * settings.
   *
   * @param resourceClassName the name of the class implementing the
   *          resource.
   * @param parameterValues the feature map containing intialisation
   *          time parameterValues for the resource.
   * @return an instantiated resource.
   */
  public static Resource createResource(String resourceClassName,
          FeatureMap parameterValues) throws ResourceInstantiationException {
    return createResource(resourceClassName, parameterValues, null, null);
  } // createResource(resClassName, paramVals, listeners)

  /**
   * Create an instance of a resource, and return it. Callers of this
   * method are responsible for querying the resource's parameter lists,
   * putting together a set that is complete apart from runtime
   * parameters, and passing a feature map containing these parameter
   * settings.
   *
   * @param resourceClassName the name of the class implementing the
   *          resource.
   * @param parameterValues the feature map containing intialisation
   *          time parameterValues for the resource.
   * @param features the features for the new resource
   * @return an instantiated resource.
   */
  public static Resource createResource(String resourceClassName,
          FeatureMap parameterValues, FeatureMap features)
          throws ResourceInstantiationException {
    return createResource(resourceClassName, parameterValues, features, null);
  }

  /**
   * Create an instance of a resource, and return it. Callers of this
   * method are responsible for querying the resource's parameter lists,
   * putting together a set that is complete apart from runtime
   * parameters, and passing a feature map containing these parameter
   * settings.
   *
   * In the case of ProcessingResources they will have their runtime
   * parameters initialised to their default values.
   *
   * @param resourceClassName the name of the class implementing the
   *          resource.
   * @param parameterValues the feature map containing intialisation
   *          time parameterValues for the resource.
   * @param features the features for the new resource or null to not
   *          assign any (new) features.
   * @param resourceName the name to be given to the resource or null to
   *          assign a default name.
   * @return an instantiated resource.
   */
  public static Resource createResource(String resourceClassName,
          FeatureMap parameterValues, FeatureMap features, String resourceName)
          throws ResourceInstantiationException {
    // get the resource metadata
    ResourceData resData = Gate.getCreoleRegister().get(resourceClassName);
    if(resData == null) {
      Set plugins = Gate.getPlugins(resourceClassName);

      StringBuilder msg = new StringBuilder();
      msg.append("Couldn't get resource data for ").append(resourceClassName)
              .append(".\n\n");

      if(plugins.isEmpty()) {
        msg.append("You may need first to load the plugin that contains your resource.\n");
        msg.append("For example, to create a gate.creole.tokeniser.DefaultTokeniser\n");
        msg.append("you need first to load the ANNIE plugin.\n\n");
      } else if(plugins.size() == 1) {
        msg.append(resourceClassName).append(" can be found in the ")
                .append(plugins.iterator().next().getName())
                .append(" plugin\n\n");
      } else {
        msg.append(resourceClassName).append(
                " can be found in the following plugins\n   ");
        for(Plugin dInfo : plugins) {
          msg.append(dInfo.getName()).append(", ");
        }

        msg.setLength(msg.length() - 2);
        msg.append("\n\n");
      }

      msg.append("Go to the menu File->Manage CREOLE plugins or use the method\n");
      msg.append("Gate.getCreoleRegister().registerPlugin(plugin).");

      throw new ResourceInstantiationException(msg.toString());
    }
    // get the default implementation class
    Class resClass = null;
    try {
      resClass = resData.getResourceClass();
    } catch(ClassNotFoundException e) {
      throw new ResourceInstantiationException(
              "Couldn't get resource class from the resource data:"
                      + Strings.getNl() + e);
    }

    // create a pointer for the resource
    Resource res = null;

    // if the object is an LR and it should come from a DS then create
    // that way
    DataStore dataStore;
    if(LanguageResource.class.isAssignableFrom(resClass)
            && ((dataStore =
                    (DataStore)parameterValues
                            .get(DataStore.DATASTORE_FEATURE_NAME)) != null)) {
      // ask the datastore to create our object
      if(dataStore instanceof SerialDataStore) {
        // SDS doesn't need a wrapper class; just check for
        // serialisability
        if(!Serializable.class.isAssignableFrom(resClass))
          throw new ResourceInstantiationException(
                  "Resource cannot be (de-)serialized: " + resClass.getName());
      }

      // get the datastore instance id and retrieve the resource
      Object instanceId = parameterValues.get(DataStore.LR_ID_FEATURE_NAME);
      if(instanceId == null)
        throw new ResourceInstantiationException("No instance id for "
                + resClass);
      try {
        res = dataStore.getLr(resClass.getName(), instanceId);
      } catch(PersistenceException pe) {
        throw new ResourceInstantiationException("Bad read from DB: " + pe);
      } catch(SecurityException se) {
        throw new ResourceInstantiationException("Insufficient permissions: "
                + se);
      }
      resData.addInstantiation(res);
      if(features != null) {
        if(res.getFeatures() == null) {
          res.setFeatures(newFeatureMap());
        }
        res.getFeatures().putAll(features);
      }

      // set the name
      if(res.getName() == null) {
        res.setName(resourceName == null ? resData.getName() + "_"
                + Gate.genSym() : resourceName);
      }

      // fire the event
      creoleProxy.fireResourceLoaded(new CreoleEvent(res,
              CreoleEvent.RESOURCE_LOADED));

      return res;
    }

    // The resource is not a persistent LR; use a constructor

    // create an object using the resource's default constructor
    try {
      if(DEBUG) Out.prln("Creating resource " + resClass.getName());
      res = resClass.newInstance();
    } catch(IllegalAccessException e) {
      throw new ResourceInstantiationException(
              "Couldn't create resource instance, access denied: " + e);
    } catch(InstantiationException e) {
      throw new ResourceInstantiationException(
              "Couldn't create resource instance due to newInstance() failure: "
                      + e);
    }

    if(LanguageResource.class.isAssignableFrom(resClass)) {
      // type-specific stuff for LRs
      if(DEBUG) Out.prln(resClass.getName() + " is a LR");
    } else if(ProcessingResource.class.isAssignableFrom(resClass)) {
      // type-specific stuff for PRs
      if(DEBUG) Out.prln(resClass.getName() + " is a PR");
      // set the runtime parameters to their defaults
      try {
        FeatureMap parameters = newFeatureMap();
        parameters.putAll(resData.getParameterList().getRuntimeDefaults());
        res.setParameterValues(parameters);
      } catch(ParameterException pe) {
        throw new ResourceInstantiationException(
                "Could not set the runtime parameters "
                        + "to their default values for: "
                        + res.getClass().getName() + " :\n" + pe.toString());
      }
      // type-specific stuff for VRs
    } else if(VisualResource.class.isAssignableFrom(resClass)) {
      if(DEBUG) Out.prln(resClass.getName() + " is a VR");
    } else if(Controller.class.isAssignableFrom(resClass)) {
      // type specific stuff for Controllers
      if(DEBUG) Out.prln(resClass.getName() + " is a Controller");
    }

    // set the parameterValues of the resource
    try {
      FeatureMap parameters = newFeatureMap();
      // put the defaults
      parameters.putAll(resData.getParameterList().getInitimeDefaults());
      // overwrite the defaults with the user provided values
      parameters.putAll(parameterValues);
      res.setParameterValues(parameters);
    } catch(ParameterException pe) {
      throw new ResourceInstantiationException(
              "Could not set the init parameters for: "
                      + res.getClass().getName() + " :\n" + pe.toString());
    }

    // set the name
    // if we have an explicitly provided name, use that, otherwise
    // generate a
    // suitable name if the resource doesn't already have one
    if(resourceName != null && resourceName.trim().length() > 0) {
      res.setName(resourceName);
    } else if(res.getName() == null) {
      // no name provided, and the resource doesn't have a name already
      // (e.g. calculated in init())
      // -> let's try and find a reasonable one
      try {
        // first try to get a filename from the various parameters
        URL sourceUrl = null;
        if(res instanceof SimpleDocument) {
          sourceUrl = ((SimpleDocument)res).getSourceUrl();
        } else if(res instanceof AnnotationSchema) {
          sourceUrl = ((AnnotationSchema)res).getXmlFileUrl().toURL();
        } else if(res.getClass().getName()
                .startsWith("gate.creole.ontology.owlim.")) {
          // get the name for the OWLIM2 ontology LR
          java.lang.reflect.Method m = resClass.getMethod("getRdfXmlURL");
          sourceUrl = (java.net.URL)m.invoke(res);
          if(sourceUrl == null) {
            m = resClass.getMethod("getN3URL");
            sourceUrl = (java.net.URL)m.invoke(res);
          }
          if(sourceUrl == null) {
            m = resClass.getMethod("getNtriplesURL");
            sourceUrl = (java.net.URL)m.invoke(res);
          }
          if(sourceUrl == null) {
            m = resClass.getMethod("getTurtleURL");
            sourceUrl = (java.net.URL)m.invoke(res);
          }
        } else if(res.getClass().getName()
                .startsWith("gate.creole.ontology.impl.")) {
          java.lang.reflect.Method m = resClass.getMethod("getSourceURL");
          sourceUrl = (java.net.URL)m.invoke(res);
        }
        if(sourceUrl != null) {
          URI sourceURI = sourceUrl.toURI();
          resourceName = sourceURI.getPath();
          if(resourceName == null ||
             resourceName.length() == 0 ||
             resourceName.equals("/")) {
            // this URI has no path -> use the whole string
            resourceName = sourceURI.toString();
          } else {
            // there is a significant path value -> get the last element
            resourceName = resourceName.trim();
            int lastSlash = resourceName.lastIndexOf('/');
            if(lastSlash >= 0) {
              String subStr = resourceName.substring(lastSlash + 1);
              if(subStr.trim().length() > 0) resourceName = subStr;
            }
          }
        }
      } catch(RuntimeException t) {
        // even runtime exceptions are safe to ignore at this point
      } catch(Exception t) {
        // there were problems while trying to guess a name
        // we can safely ignore them
      } finally {
        // make sure there is a name provided, whatever happened
        if(resourceName == null || resourceName.trim().length() == 0) {
          resourceName = resData.getName();
        }
      }
      resourceName += "_" + Gate.genSym();
      res.setName(resourceName);
    } // else if(res.getName() == null)
    // if res.getName() != null, leave it as it is

    Map listeners =
            new HashMap(gate.Gate.getListeners());
    // set the listeners if any
    if(!listeners.isEmpty()) {
      try {
        if(DEBUG) Out.prln("Setting the listeners for  " + res.toString());
        AbstractResource.setResourceListeners(res, listeners);
      } catch(Exception e) {
        if(DEBUG) Out.prln("Failed to set listeners for " + res.toString());
        throw new ResourceInstantiationException("Parameterisation failure" + e);
      }
    }

    try {
      // if the features of the resource have not been explicitly set,
      // set them to the features of the resource data
      if(res.getFeatures() == null || res.getFeatures().isEmpty()) {
        FeatureMap fm = newFeatureMap();
        fm.putAll(resData.getFeatures());
        res.setFeatures(fm);
      }
      // add the features specified by the user
      if(features != null) res.getFeatures().putAll(features);

      // initialise the resource
      if(DEBUG) Out.prln("Initialising resource " + res.toString());
      res = res.init();

    } finally {
      // remove the listeners if any
      if(!listeners.isEmpty()) {
        try {
          if(DEBUG) Out.prln("Removing the listeners for  " + res.toString());
          AbstractResource.removeResourceListeners(res, listeners);
        } catch(Exception e) {
          if(DEBUG)
            Out.prln("Failed to remove the listeners for " + res.toString());
          throw new ResourceInstantiationException("Parameterisation failure" + e);
        }
      }
    }
    // record the instantiation on the resource data's stack
    resData.addInstantiation(res);
    // fire the event
    creoleProxy.fireResourceLoaded(new CreoleEvent(res,
            CreoleEvent.RESOURCE_LOADED));
    return res;
  } // create(resourceClassName, parameterValues, features, listeners)

  /**
   * Delete an instance of a resource. This involves removing it from
   * the stack of instantiations maintained by this resource type's
   * resource data. Deletion does not guarantee that the resource will
   * become a candidate for garbage collection, just that the GATE
   * framework is no longer holding references to the resource.
   *
   * @param resource the resource to be deleted.
   */
  public static void deleteResource(Resource resource) {
    ResourceData rd =
            Gate.getCreoleRegister().get(resource.getClass().getName());
    if(rd != null && rd.removeInstantiation(resource)) {
      creoleProxy.fireResourceUnloaded(new CreoleEvent(resource,
              CreoleEvent.RESOURCE_UNLOADED));
      resource.cleanup();
    }
  } // deleteResource

  /** Create a new transient Corpus. */
  public static Corpus newCorpus(String name)
          throws ResourceInstantiationException {
    return (Corpus)createResource("gate.corpora.CorpusImpl", newFeatureMap(),
            newFeatureMap(), name);
  } // newCorpus

  /** Create a new transient Document from a URL. */
  public static Document newDocument(URL sourceUrl)
          throws ResourceInstantiationException {
    FeatureMap parameterValues = newFeatureMap();
    parameterValues.put(Document.DOCUMENT_URL_PARAMETER_NAME, sourceUrl);
    return (Document)createResource("gate.corpora.DocumentImpl",
            parameterValues);
  } // newDocument(URL)

  /** Create a new transient Document from a URL and an encoding. */
  public static Document newDocument(URL sourceUrl, String encoding)
          throws ResourceInstantiationException {
    FeatureMap parameterValues = newFeatureMap();
    parameterValues.put(Document.DOCUMENT_URL_PARAMETER_NAME, sourceUrl);
    parameterValues.put(Document.DOCUMENT_ENCODING_PARAMETER_NAME, encoding);
    return (Document)createResource("gate.corpora.DocumentImpl",
            parameterValues);
  } // newDocument(URL)

  /** Create a new transient textual Document from a string. */
  public static Document newDocument(String content)
          throws ResourceInstantiationException {
    FeatureMap params = newFeatureMap();
    params.put(Document.DOCUMENT_STRING_CONTENT_PARAMETER_NAME, content);
    Document doc =
            (Document)createResource("gate.corpora.DocumentImpl", params);
    /*
     * // laziness: should fit this into createResource by adding a new
     * // document parameter, but haven't time right now...
     * doc.setContent(new DocumentContentImpl(content));
     */
    // various classes are in the habit of assuming that a document
    // inevitably has a source URL... so give it a dummy one
    /*
     * try { doc.setSourceUrl(new URL("http://localhost/")); }
     * catch(MalformedURLException e) { throw new
     * ResourceInstantiationException(
     * "Couldn't create dummy URL in newDocument(String): " + e ); }
     */
    doc.setSourceUrl(null);
    return doc;
  } // newDocument(String)

  /**
   * Utility method to create an immutable annotation set. If the
   * provided collection of annotations is
   * null, the newly created set will
   * be empty.
   * 
   * @param document the document this set belongs to.
   * @param annotations the set of annotations that should be contained
   *          in the returned {@link AnnotationSet}.
   * @return an {@link AnnotationSet} that throws exceptions on all
   *         attempts to modify it.
   */
  public static AnnotationSet createImmutableAnnotationSet(Document document,
          Collection annotations) {
    return new ImmutableAnnotationSetImpl(document, annotations);
  }

  /**
   * 

* Create a duplicate of the given resource. A duplicate is a * an independent copy of the resource that has the same name and the * same behaviour. It does not necessarily have the same * concrete class as the original, but if the original resource * implements any of the following interfaces then the duplicate can * be assumed to implement the same ones: *

*
    *
  • {@link ProcessingResource}
  • *
  • {@link LanguageAnalyser}
  • *
  • {@link Controller}
  • *
  • {@link CorpusController}
  • *
  • {@link ConditionalController}
  • *
  • {@code Gazetteer}
  • *
  • {@link LanguageResource}
  • *
  • {@link gate.creole.ontology.Ontology}
  • *
  • {@link Document}
  • *
  • {@link Corpus}
  • *
*

* The default duplication algorithm simply calls * {@link #createResource(String, FeatureMap, FeatureMap, String) * createResource} with the type and name of the original resource, * and with parameters and features which are copies of those from the * original resource, but any Resource values in the maps will * themselves be duplicated. A context is passed around all the * duplicate calls that stem from the same call to this method so that * if the same resource is referred to in different places, the same * duplicate can be used in the corresponding places in the duplicated * object graph. *

*

* This default behaviour is sufficient for most resource types (and * is roughly the equivalent of saving the resource's state using the * persistence manager and then reloading it), but individual resource * classes can override it by implementing the * {@link CustomDuplication} interface. This may be necessary for * semantic reasons (e.g. controllers need to recursively duplicate * the PRs they contain), or desirable for performance or memory * consumption reasons (e.g. the behaviour of a DefaultGazetteer can * be duplicated by a SharedDefaultGazetteer that shares the internal * data structures). *

* * @param res the resource to duplicate * @return an independent duplicate copy of the resource * @throws ResourceInstantiationException if an exception occurs while * constructing the duplicate. */ public static Resource duplicate(Resource res) throws ResourceInstantiationException { DuplicationContext ctx = new DuplicationContext(); try { return duplicate(res, ctx); } finally { // de-activate the context ctx.active = false; } } private static long dupIndex = 0; /** * Create a duplicate of the given resource, using the provided * context. This method is intended for use by resources that * implement the {@link CustomDuplication} interface when they need to * duplicate their child resources. Calls made to this method outside * the scope of such a {@link CustomDuplication#duplicate * CustomDuplication.duplicate} call will fail with a runtime * exception. * * @see #duplicate(Resource) * @param res the resource to duplicate * @param ctx the current context as passed to the * {@link CustomDuplication#duplicate} method. * @return the duplicated resource * @throws ResourceInstantiationException if an error occurs while * constructing the duplicate. */ public static Resource duplicate(Resource res, DuplicationContext ctx) throws ResourceInstantiationException { long myDupIndex = -1, startTime = -1; if(DEBUG_DUPLICATION) { myDupIndex = dupIndex++; log.debug(myDupIndex + ": Duplicating \"" + ((res == null) ? "null" : res.getName()) + "\" (a " + ((res == null) ? "null" : res.getClass().getName()) + ")"); startTime = System.currentTimeMillis(); } try { checkDuplicationContext(ctx); // check for null if(res == null) { return null; } // check if we've seen this resource before else if(ctx.knownResources.containsKey(res)) { if(DEBUG_DUPLICATION) { log.debug(myDupIndex + ": Resource already duplicated in context"); } return ctx.knownResources.get(res); } else { // create the duplicate Resource newRes = null; if(res instanceof CustomDuplication) { // use custom duplicate if available newRes = ((CustomDuplication)res).duplicate(ctx); } else { newRes = defaultDuplicate(res, ctx); } // remember this duplicate in the context ctx.knownResources.put(res, newRes); return newRes; } } finally { if(DEBUG_DUPLICATION) { log.debug(myDupIndex + ": Duplication took " + (System.currentTimeMillis() - startTime) + " ms"); } } } /** * Implementation of the default duplication algorithm described in * the comment for {@link #duplicate(Resource)}. This method is public * for the benefit of resources that implement * {@link CustomDuplication} but only need to do some post-processing * after the default duplication algorithm; they can call this method * to obtain an initial duplicate and then post-process it before * returning. If they need to duplicate child resources they should * call {@link #duplicate(Resource, DuplicationContext)} in the normal * way. Calls to this method made outside the context of a * {@link CustomDuplication#duplicate CustomDuplication.duplicate} * call will fail with a runtime exception. * * @param res the resource to duplicate * @param ctx the current context * @return a duplicate of the given resource, constructed using the * default algorithm. In particular, if res * implements {@link CustomDuplication} its own duplicate * method will not be called. * @throws ResourceInstantiationException if an error occurs while * duplicating the given resource. */ public static Resource defaultDuplicate(Resource res, DuplicationContext ctx) throws ResourceInstantiationException { checkDuplicationContext(ctx); String className = res.getClass().getName(); ResourceData resData = Gate.getCreoleRegister().get(className); if(resData == null) { throw new ResourceInstantiationException( "Could not find CREOLE data for " + className); } String resName = res.getName(); FeatureMap newResFeatures = duplicate(res.getFeatures(), ctx); // init parameters FeatureMap initParams = AbstractResource.getInitParameterValues(res); // remove parameters that are also sharable properties for(String propName : resData.getSharableProperties()) { initParams.remove(propName); } // duplicate any Resources in the params map (excluding sharable // ones) initParams = duplicate(initParams, ctx); // add sharable properties to the params map (unduplicated). Some of // these // may be registered parameters but others may not be. for(String propName : resData.getSharableProperties()) { initParams.put(propName, res.getParameterValue(propName)); } // create the new resource Resource newResource = createResource(className, initParams, newResFeatures, resName); if(newResource instanceof ProcessingResource) { // runtime params FeatureMap runtimeParams = AbstractProcessingResource.getRuntimeParameterValues(res); // remove parameters that are also sharable properties for(String propName : resData.getSharableProperties()) { runtimeParams.remove(propName); } // duplicate any Resources in the params map (excluding sharable // ones) runtimeParams = duplicate(runtimeParams, ctx); // do not need to add sharable properties here, they have already // been injected by createResource newResource.setParameterValues(runtimeParams); } return newResource; } /** * Construct a feature map that is a copy of the one provided except * that any {@link Resource} values in the map are replaced by their * duplicates. This method is public for the benefit of resources that * implement {@link CustomDuplication} and will fail if called outside * of a {@link CustomDuplication#duplicate * CustomDuplication.duplicate} implementation. * * @param fm the feature map to duplicate * @param ctx the current context * @return a duplicate feature map * @throws ResourceInstantiationException if an error occurs while * duplicating any Resource in the feature map. */ public static FeatureMap duplicate(FeatureMap fm, DuplicationContext ctx) throws ResourceInstantiationException { checkDuplicationContext(ctx); FeatureMap newFM = Factory.newFeatureMap(); for(Map.Entry entry : fm.entrySet()) { Object value = entry.getValue(); if(value instanceof Resource) { value = duplicate((Resource)value, ctx); } newFM.put(entry.getKey(), value); } return newFM; } /** * Opaque memo object passed to {@link CustomDuplication#duplicate * CustomDuplication.duplicate} methods to encapsulate the state of * the current duplication run. If the duplicate method itself needs * to duplicate any objects it should pass this context back to * {@link #duplicate(Resource,DuplicationContext)}. */ public static class DuplicationContext { IdentityHashMap knownResources = new IdentityHashMap(); /** * Whether this duplication context is part of an active duplicate * call. */ boolean active = true; /** * Overridden to ensure no public constructor. */ DuplicationContext() { } } /** * Throws an exception if the specified duplication context is null or * not active. This is to ensure that the Factory helper methods that * take a DuplicationContext parameter can only be called in the * context of a {@link #duplicate(Resource)} call. * * @param ctx the context to check. * @throws NullPointerException if the provided context is null. * @throws IllegalStateException if the provided context is not * active. */ protected static void checkDuplicationContext(DuplicationContext ctx) { if(ctx == null) { throw new NullPointerException("No DuplicationContext provided"); } if(!ctx.active) { throw new IllegalStateException( new Throwable().getStackTrace()[1].getMethodName() + " helper method called outside an active duplicate call"); } } /** Create a new FeatureMap. */ public static FeatureMap newFeatureMap() { return new SimpleFeatureMapImpl(); } // newFeatureMap /** Open an existing DataStore. */ public static DataStore openDataStore(String dataStoreClassName, String storageUrl) throws PersistenceException { DataStore ds = instantiateDataStore(dataStoreClassName, storageUrl); ds.open(); if(Gate.getDataStoreRegister().add(ds)) creoleProxy.fireDatastoreOpened(new CreoleEvent(ds, CreoleEvent.DATASTORE_OPENED)); return ds; } // openDataStore() /** * Create a new DataStore and open it. NOTE: for some data * stores creation is an system administrator task; in such cases this * method will throw an UnsupportedOperationException. */ public static DataStore createDataStore(String dataStoreClassName, String storageUrl) throws PersistenceException, UnsupportedOperationException { DataStore ds = instantiateDataStore(dataStoreClassName, storageUrl); ds.create(); ds.open(); if(Gate.getDataStoreRegister().add(ds)) creoleProxy.fireDatastoreCreated(new CreoleEvent(ds, CreoleEvent.DATASTORE_CREATED)); return ds; } // createDataStore() /** Instantiate a DataStore (not open or created). */ protected static DataStore instantiateDataStore(String dataStoreClassName, String storageUrl) throws PersistenceException { DataStore godfreyTheDataStore = null; try { godfreyTheDataStore = (DataStore)Gate.getClassLoader().loadClass(dataStoreClassName) .newInstance(); } catch(Exception e) { throw new PersistenceException("Couldn't create DS class: " + e); } godfreyTheDataStore.setStorageUrl(storageUrl); return godfreyTheDataStore; } // instantiateDS(dataStoreClassName, storageURL) /** Add a listener */ public static synchronized void addCreoleListener(CreoleListener l) { creoleProxy.addCreoleListener(l); } // addCreoleListener(CreoleListener) /** Static initialiser to set up the CreoleProxy event source object */ static { creoleProxy = new CreoleProxy(); } // static initialiser } // abstract Factory /** * Factory is basically a collection of static methods but events need * to have as source an object and not a class. The CreolProxy class * addresses this issue acting as source for all events fired by the * Factory class. */ class CreoleProxy { public synchronized void removeCreoleListener(CreoleListener l) { if(creoleListeners != null && creoleListeners.contains(l)) { @SuppressWarnings("unchecked") Vector v = (Vector)creoleListeners.clone(); v.removeElement(l); creoleListeners = v; }// if }// removeCreoleListener(CreoleListener l) public synchronized void addCreoleListener(CreoleListener l) { @SuppressWarnings("unchecked") Vector v = creoleListeners == null ? new Vector(2) : (Vector)creoleListeners.clone(); if(!v.contains(l)) { v.addElement(l); creoleListeners = v; }// if }// addCreoleListener(CreoleListener l) protected void fireResourceLoaded(CreoleEvent e) { if(creoleListeners != null) { int count = creoleListeners.size(); for(int i = 0; i < count; i++) { creoleListeners.elementAt(i).resourceLoaded(e); }// for }// if }// fireResourceLoaded(CreoleEvent e) protected void fireResourceUnloaded(CreoleEvent e) { if(creoleListeners != null) { int count = creoleListeners.size(); for(int i = 0; i < count; i++) { creoleListeners.elementAt(i).resourceUnloaded(e); }// for }// if }// fireResourceUnloaded(CreoleEvent e) protected void fireDatastoreOpened(CreoleEvent e) { if(creoleListeners != null) { int count = creoleListeners.size(); for(int i = 0; i < count; i++) { creoleListeners.elementAt(i).datastoreOpened(e); }// for }// if }// fireDatastoreOpened(CreoleEvent e) protected void fireDatastoreCreated(CreoleEvent e) { if(creoleListeners != null) { int count = creoleListeners.size(); for(int i = 0; i < count; i++) { creoleListeners.elementAt(i).datastoreCreated(e); }// for }// if }// fireDatastoreCreated(CreoleEvent e) protected void fireDatastoreClosed(CreoleEvent e) { if(creoleListeners != null) { int count = creoleListeners.size(); for(int i = 0; i < count; i++) { creoleListeners.elementAt(i).datastoreClosed(e); }// for }// if }// fireDatastoreClosed(CreoleEvent e) private transient Vector creoleListeners; }// class CreoleProxy




© 2015 - 2025 Weber Informatics LLC | Privacy Policy