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

gate.creole.Parameter 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!
/*
 *  Parameter.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, 15/Oct/2000
 *
 *  $Id: Parameter.java 20035 2017-02-01 03:01:32Z markagreenwood $
 */

package gate.creole;

import gate.Factory;
import gate.FeatureMap;
import gate.Gate;
import gate.Resource;
import gate.util.GateRuntimeException;
import gate.util.Strings;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.SortedSet;
import java.util.StringTokenizer;
import java.util.TreeSet;


/** Models a resource parameter.
  */
public class Parameter implements Serializable
{
  private static final long serialVersionUID = 6611664706992065985L;

  /**
   * Construct a new Parameter for a resource in a given plugin.
   * @param plugin the plugin that defines the resource 
   * this parameter belongs to. This will be used as context when deriving 
   * default values for the parameters of type URL oe ResourceReference.
   */  
  public Parameter(Plugin plugin) {
    this.plugin = plugin;
  }
  
  /** The type name of the parameter */
  String typeName;

  /** Set the type name for this parameter */
  public void setTypeName(String typeName) { this.typeName = typeName; }

  /** Get the type name for this parameter */
  public String getTypeName() { return typeName; }

  /** Is the parameter optional? */
  boolean optional = false;

  /** Set optionality of this parameter */
  public void setOptional(boolean optional) { this.optional = optional; }

  /** Is the parameter optional? */
  public boolean isOptional() { return optional; }

  /** The name of the item's class. If the parameter is a collection then
    * we need  to know the class of its items in order to create them the
    * way we want.
    */
  String itemClassName = null;

  /** A set of strings representing suffixes for URL params*/
  Set suffixes = null;
  
  /**
   * Map giving concrete classes that should be used for a parameter
   * whose declared type is an interface.  This substitution allows a
   * resource to specify a parameter of type, e.g. java.util.List,
   * and give it a default value in creole.xml.  The runtime class of
   * the default value will be taken from this map.
   * 
   * Note that for this to work, it must be the case that for every
   * key k in this map,
   * 
   * k.isAssignableFrom(substituteClasses.get(k))
   */
   static Map, Class> substituteClasses = 
    new HashMap, Class>();
  
  static {
    substituteClasses.put(Collection.class, ArrayList.class);
    substituteClasses.put(List.class, ArrayList.class);
    substituteClasses.put(Set.class, HashSet.class);
    substituteClasses.put(SortedSet.class, TreeSet.class);
    substituteClasses.put(Queue.class, LinkedList.class);
  }

  /** Calculate and return the default value for this parameter */
  public Object calculateDefaultValue() throws ParameterException {
    // if there's no default string and this is a builtin type, return null
    if(
      defaultValueString == null && typeName != null &&
      typeName.startsWith("java.")
    )
      return null;

    return calculateValueFromString(defaultValueString);
  } // calculateDefaultValue()

  /** Calculate and return the value for this parameter starting from a String
   */
  @SuppressWarnings({"unchecked", "rawtypes"})
  public Object calculateValueFromString(String stringValue)
  throws ParameterException {
    //if we have no string we can't construct a value
    Object value = null;

    // get the Class for the parameter via Class.forName or CREOLE register
    Class paramClass = getParameterClass();
    if(substituteClasses.containsKey(paramClass)) {
      paramClass = substituteClasses.get(paramClass);
    }


    // Test if the paramClass is a collection and if it is, try to
    // construct the param as a collection of items specified in the
    // default string value.  If paramClass is an interface type we
    // look up its substitute concrete type in the map
    // collectionSubstituteClasses and create a value of that type.
    if (Collection.class.isAssignableFrom(paramClass) &&
            !paramClass.isInterface()){
      // Create an collection object belonging to paramClass
      Collection colection = null;
      try{
        colection = paramClass.asSubclass(Collection.class).getConstructor(new Class[]{}).
                                  newInstance(new Object[]{});
      } catch(Exception ex){
          throw new ParameterException("Could not construct an object of type "
            + typeName + " for param " + name +
            "\nProblem was: " + ex.toString());
      }// End try
      // If an itemClassName was specified then try to create objects belonging
      // to this class and add them to the collection. Otherwise add the
      // string tokens to the collection.
      if(itemClassName == null){
        // Read the tokens from the default value and try to create items
        // belonging to the itemClassName
        StringTokenizer strTokenizer = new StringTokenizer(
                                                      stringValue,";");
        while(strTokenizer.hasMoreTokens()){
          String itemStringValue = strTokenizer.nextToken();
          ((Collection)colection).add(itemStringValue);
        }// End while
      }else{
        Class itemClass = null;
        try{
          itemClass = Gate.getClassLoader().loadClass(itemClassName);
        }catch(ClassNotFoundException e){
          throw new ParameterException("Could not construct a class object for "
            + itemClassName + " for param "+ name +
            ", with type name="+ typeName);
        }// End try
        // Read the tokens from the default value and try to create items
        // belonging to the itemClassName
        StringTokenizer strTokenizer = new StringTokenizer(
                                                      stringValue,";");
        while(strTokenizer.hasMoreTokens()){
          // Read a string item and construct an object belonging to
          // itemClassName
          String itemStringValue = strTokenizer.nextToken();
          Object itemValue = null;
          try{
            itemValue = itemClass.getConstructor(new Class[]{String.class}).
                                  newInstance(new Object[]{itemStringValue});
          }catch(Exception e){
            throw new ParameterException("Could not create an object of " +
            itemClassName + " for param name "+ name + ", with type name ="+
            typeName);
          }// End try
          // Add the item value object to the collection
          ((Collection)colection).add(itemValue);
        }// End while
      }// End if(itemClassName == null)
      return colection;
    }// End if (Collection.class.isAssignableFrom(paramClass))
    
    if(FeatureMap.class.isAssignableFrom(paramClass)) {
      // a null string value means a null FeatureMap
      if(stringValue == null) return null;
      FeatureMap fm = null;
      // if the type is an interface type (not a concrete implementation)
      // then just create a normal feature map using the factory
      if(paramClass.isInterface()) {
        fm = Factory.newFeatureMap();
      }
      else {
        try{
          fm = paramClass.asSubclass(FeatureMap.class).getConstructor(new Class[]{}).
                                    newInstance(new Object[]{});
        } catch(InstantiationException | IllegalAccessException
            | IllegalArgumentException | InvocationTargetException
            | NoSuchMethodException | SecurityException e) {
          
          throw new ParameterException("Could not construct an object of type "
              + typeName + " for param " + name +
              "\nProblem was: " + e.toString());
        }
      }
      
      // Read the tokens from the default value and try to create items
      // belonging to the itemClassName
      StringTokenizer strTokenizer = new StringTokenizer(
                                                    stringValue,";");
      while(strTokenizer.hasMoreTokens()) {
        String keyAndValue = strTokenizer.nextToken();
        int indexOfEquals = keyAndValue.indexOf('=');
        if(indexOfEquals == -1) {
          throw new ParameterException("Error parsing string \""
                  + stringValue + "\" for parameter " + name + " of type "
                  + typeName + ". Value string must be of the form "
                  + "name1=value1;name2=value2;...");
        }
        String featName = keyAndValue.substring(0, indexOfEquals);
        String featValue = keyAndValue.substring(indexOfEquals + 1);
        fm.put(featName, featValue);
      }
      
      return fm;
    }
    
    // Java 5.0 enum types
    if(paramClass.isEnum()) {
      if(stringValue == null) {
        value = null;
      }
      else {
        try {
          value = Enum.valueOf(paramClass.asSubclass(Enum.class), stringValue);
        }
        catch(IllegalArgumentException e) {
          throw new ParameterException("Invalid enum constant name "
              + stringValue + " for type " + typeName);
        }
      }
    }
    else if (typeName.equals("gate.creole.ResourceReference")) {
      if (stringValue != null && !stringValue.equals("")) {
        try {
          value = new ResourceReference(plugin, stringValue);
        } catch(URISyntaxException e) {
          throw new ParameterException("Malformed ResourceReference parameter value: "+stringValue,e);
        }
      }
    }
    // java builtin types - for numeric types, we don't attempt to parse an
    // empty string value, but just leave value as null
    else if(typeName.startsWith("java.")) {
      if(typeName.equals("java.lang.Boolean"))
        value = Boolean.valueOf(stringValue);
      else if(typeName.equals("java.lang.Long")) {
        if(stringValue != null && !stringValue.equals("")) {
          value = Long.valueOf(stringValue);
        }
      }
      else if(typeName.equals("java.lang.Integer")) {
        if(stringValue != null && !stringValue.equals("")) {
          value = Integer.valueOf(stringValue);
        }
      }
      else if(typeName.equals("java.lang.String"))
        value = stringValue;
      else if(typeName.equals("java.lang.Double")) {
        if(stringValue != null && !stringValue.equals("")) {
          value = Double.valueOf(stringValue);
        }
      }
      else if(typeName.equals("java.lang.Float")) {
        if(stringValue != null && !stringValue.equals("")) {
          value = Float.valueOf(stringValue);
        }
      }
      else if(typeName.equals("java.net.URL")) {
        try{
          if(stringValue != null && !stringValue.equals("")) {
            value = new URL(plugin.getBaseURL(), stringValue);
          }
        }catch(MalformedURLException mue){
          //value = null;
          throw new ParameterException("Malformed URL parameter value: "+stringValue,mue);
        }
      }
      else{
        //try to construct a new value from the string using a constructor
        // e.g. for URLs
        try{
          if(!paramClass.isAssignableFrom(String.class)){
            value = paramClass.getConstructor(new Class[]{String.class}).
                         newInstance(new Object[]{stringValue});
          }
        }catch(Exception e){
          throw new ParameterException("Unsupported parameter type " + typeName);
        }
      }
    } else {
      // non java types
      // null string value means null target value
      if(stringValue != null) {
        // otherwise, if it's a GATE resource type pick the first registered instance 
        if(resData == null)
          resData = Gate.getCreoleRegister().get(typeName);
        if(resData == null){
          //unknown type
          return null;
        }
  
        List instantiations = resData.getInstantiations();
        if(! instantiations.isEmpty()) value = instantiations.get(0);
      }
    }

    return value;
  } // calculateValueFromString()


  /** The resource data that this parameter is part of. */
  protected ResourceData resData;

  /** Get the default value for this parameter. If the value is
    * currently null it will try and calculate a value.
    * @see #calculateDefaultValue()
    */
  public Object getDefaultValue() throws ParameterException {
    return calculateDefaultValue();
  } // getDefaultValue

  /** Default value string (unprocessed, from the metadata)
    * for the parameter
    */
  String defaultValueString;

  /** Set the default value string (from the metadata)
    * for the parameter
    */
  public void setDefaultValueString(String defaultValueString) {
    this.defaultValueString = defaultValueString;
  } // setDefaultValueString

  /** Get the default value string (unprocessed, from the metadata)
    * for the parameter
    */
  public String getDefaultValueString() { return defaultValueString; }

  /** Comment for the parameter */
  String comment;

  /** Set the comment for this parameter */
  public void setComment(String comment) { this.comment = comment; }

  /** Get the comment for this parameter */
  public String getComment() { return comment; }

  /** helpURL for the parameter */
  String helpURL;
  
  /** Set the helpURL for this parameter */
  public void setHelpURL(String helpURL) { this.helpURL = helpURL; }
  
  /** Get the helpURL for this parameter */
  public String getHelpURL() { return helpURL; }
  
  /** Name for the parameter */
  String name;

  /** Set the name for this parameter */
  public void setName(String name) { this.name = name; }

  /** Get the name for this parameter */
  public String getName() { return name; }

  /** Get the suffixes atached with this param. If it's null then there are
   *  no suffices attached with it
   */
  public Set getSuffixes(){ return suffixes;}

  /** Is this a run-time parameter? */
  boolean runtime = false;

  /**
   * The URL to the creole.xml file that defines the resource this parameter 
   * belongs to. It is used for deriving default values for parameters of type
   * {@link URL}.
   */
  //protected URL baseURL;
  
  protected Plugin plugin;
  
  /** Set runtime status of this parameter */
  public void setRuntime(boolean runtime) { this.runtime = runtime; }

  /** Is the parameter runtime? */
  public boolean isRuntime() { return runtime; }

  /** The Class for the parameter type */
  protected Class paramClass;

  /** Find the class for this parameter type. */
  protected Class getParameterClass() throws ParameterException
  {
    // get java builtin classes via class; else look in the register
    try {
      ResourceData resData = Gate.getCreoleRegister().get(typeName);
      if(resData == null){
        paramClass = Gate.getClassLoader().loadClass(typeName);
      }else{
        paramClass = resData.getResourceClass();
      }

//      if(typeName.startsWith("java."))
//          paramClass = Class.forName(typeName);
//      else {
//        ResourceData resData =
//          (ResourceData) Gate.getCreoleRegister().get(typeName);
//        if(resData == null)
//          throw new ParameterException(
//            "No resource data for " + typeName + " in Parameter/getParamClz"
//          );
//        paramClass = resData.getResourceClass();
//      }
    } catch(ClassNotFoundException e) {
      throw new ParameterException(
        "Couldn't find class " + typeName + ": " + Strings.getNl() + e
      );
    }

    if(paramClass == null)
      throw new ParameterException("Couldn't find class " + typeName);

    return paramClass;
  } // getParameterClass

  /** String representation */
  @Override
  public String toString() {
    try{
      return "Parameter: name="+ name+ "; valueString=" + typeName +
             "; optional=" + optional +
             "; defaultValueString=" + defaultValueString +
             "; defaultValue=" + getDefaultValue() + "; comment=" +
             comment + "; helpURL=" +
             helpURL + "; runtime=" + runtime +
             "; itemClassName=" + itemClassName +
             "; suffixes=" + suffixes;
    }catch(ParameterException pe){
      throw new GateRuntimeException(pe.toString());
    }
  }

  /**
   * If this parameter is a List type this will return the type of the items
   * in the list. If the type is null String will be assumed.
   */
  public String getItemClassName() {
    return itemClassName;
  } // toString()
} // class Parameter