1   /*
2    *  Parameter.java
3    *
4    *  Copyright (c) 1998-2004, The University of Sheffield.
5    *
6    *  This file is part of GATE (see http://gate.ac.uk/), and is free
7    *  software, licenced under the GNU Library General Public License,
8    *  Version 2, June 1991 (in the distribution as file licence.html,
9    *  and also available at http://gate.ac.uk/gate/licence.html).
10   *
11   *  Hamish Cunningham, 15/Oct/2000
12   *
13   *  $Id: Parameter.java,v 1.22 2004/07/21 17:10:03 akshay Exp $
14   */
15  
16  package gate.creole;
17  
18  import java.io.Serializable;
19  import java.net.MalformedURLException;
20  import java.net.URL;
21  import java.util.*;
22  
23  import gate.Gate;
24  import gate.util.*;
25  
26  
27  /** Models a resource parameter.
28    */
29  public class Parameter implements Serializable
30  {
31    /**
32     * Constructor
33     * @param baseUrl the URL to the creole.xml file that defines the resource 
34     * this parameter belongs to. This will be used a context when deriving 
35     * default values for the parameters of type URL.
36     */
37    public Parameter(URL baseUrl){
38      this.baseURL = baseUrl;
39    }
40    
41    /** The type name of the parameter */
42    String typeName;
43  
44    /** Set the type name for this parameter */
45    public void setTypeName(String typeName) { this.typeName = typeName; }
46  
47    /** Get the type name for this parameter */
48    public String getTypeName() { return typeName; }
49  
50    /** Is the parameter optional? */
51    boolean optional = false;
52  
53    /** Set optionality of this parameter */
54    public void setOptional(boolean optional) { this.optional = optional; }
55  
56    /** Is the parameter optional? */
57    public boolean isOptional() { return optional; }
58  
59    /** The name of the item's class. If the parameter is a collection then
60      * we need  to know the class of its items in order to create them the
61      * way we want.
62      */
63    String itemClassName = null;
64  
65    /** A set of strings representing suffixes for URL params*/
66    Set suffixes = null;
67  
68    /** Calculate and return the default value for this parameter */
69    public Object calculateDefaultValue() throws ParameterException {
70      // if there's no default string and this is a builtin type, return null
71      if(
72        defaultValueString == null && typeName != null &&
73        typeName.startsWith("java.")
74      )
75        return null;
76  
77      return calculateValueFromString(defaultValueString);
78    } // calculateDefaultValue()
79  
80    /** Calculate and return the value for this parameter starting from a String
81     */
82    public Object calculateValueFromString(String stringValue)
83    throws ParameterException {
84      //if we have no string we can't construct a value
85      Object value = null;
86  
87      // get the Class for the parameter via Class.forName or CREOLE register
88      Class paramClass = getParameterClass();
89  
90  
91      // Test if the paramClass is a collection and if it is, try to
92      // construct the param as a collection of items specified in the
93      // default string value...
94      if (Collection.class.isAssignableFrom(paramClass) &&
95          (!paramClass.isInterface())){
96        // Create an collection object belonging to paramClass
97        Collection colection = null;
98        try{
99          colection = (Collection)paramClass.getConstructor(new Class[]{}).
100                                   newInstance(new Object[]{});
101       } catch(Exception ex){
102           throw new ParameterException("Could not construct an object of type "
103             + typeName + " for param " + name +
104             "\nProblem was: " + ex.toString());
105       }// End try
106       // If an itemClassName was specified then try to create objects belonging
107       // to this class and add them to the collection. Otherwise add the
108       // string tokens to the collection.
109       if(itemClassName == null){
110         // Read the tokens from the default value and try to create items
111         // belonging to the itemClassName
112         StringTokenizer strTokenizer = new StringTokenizer(
113                                                       defaultValueString,";");
114         while(strTokenizer.hasMoreTokens()){
115           String itemStringValue = strTokenizer.nextToken();
116           colection.add(itemStringValue);
117         }// End while
118       }else{
119         Class itemClass = null;
120         try{
121           itemClass = Gate.getClassLoader().loadClass(itemClassName);
122         }catch(ClassNotFoundException e){
123           throw new ParameterException("Could not construct a class object for "
124             + itemClassName + " for param "+ name +
125             ", with type name="+ typeName);
126         }// End try
127         // Read the tokens from the default value and try to create items
128         // belonging to the itemClassName
129         StringTokenizer strTokenizer = new StringTokenizer(
130                                                       defaultValueString,";");
131         while(strTokenizer.hasMoreTokens()){
132           // Read a string item and construct an object belonging to
133           // itemClassName
134           String itemStringValue = strTokenizer.nextToken();
135           Object itemValue = null;
136           try{
137             itemValue = itemClass.getConstructor(new Class[]{String.class}).
138                                   newInstance(new Object[]{itemStringValue});
139           }catch(Exception e){
140             throw new ParameterException("Could not create an object of " +
141             itemClassName + " for param name "+ name + ", with type name ="+
142             typeName);
143           }// End try
144           // Add the item value object to the collection
145           colection.add(itemValue);
146         }// End while
147       }// End if(itemClassName == null)
148       return colection;
149     }// End if (Collection.class.isAssignableFrom(paramClass))
150     // java builtin types
151     if(typeName.startsWith("java.")) {
152       if(typeName.equals("java.lang.Boolean"))
153         value = Boolean.valueOf(stringValue);
154       else if(typeName.equals("java.lang.Long"))
155         value = Long.valueOf(stringValue);
156       else if(typeName.equals("java.lang.Integer"))
157         value = Integer.valueOf(stringValue);
158       else if(typeName.equals("java.lang.String"))
159         value = stringValue;
160       else if(typeName.equals("java.lang.Double"))
161         value = Double.valueOf(stringValue);
162       else if(typeName.equals("java.lang.Float"))
163         value = Float.valueOf(stringValue);
164       else if(typeName.equals("java.net.URL"))
165         try{
166           value = new URL(baseURL, stringValue);
167         }catch(MalformedURLException mue){
168           value = null;
169         }
170       else{
171         //try to construct a new value from the string using a constructor
172         // e.g. for URLs
173         try{
174           if(!paramClass.isAssignableFrom(String.class)){
175             value = paramClass.getConstructor(new Class[]{String.class}).
176                          newInstance(new Object[]{stringValue});
177           }
178         }catch(Exception e){
179           throw new ParameterException("Unsupported parameter type " + typeName);
180         }
181       }
182     } else {
183       // non java types
184       if(resData == null)
185         resData = (ResourceData) Gate.getCreoleRegister().get(typeName);
186       if(resData == null){
187         //unknown type
188         return null;
189       }
190 
191       WeakBumpyStack instantiations = resData.getInstantiations();
192       if(! instantiations.isEmpty()) value = instantiations.peek();
193     }
194 
195     return value;
196   } // calculateValueFromString()
197 
198 
199   /** The resource data that this parameter is part of. */
200   protected ResourceData resData;
201 
202   /** Get the default value for this parameter. If the value is
203     * currently null it will try and calculate a value.
204     * @see #calculateDefaultValue()
205     */
206   public Object getDefaultValue() throws ParameterException {
207     return calculateDefaultValue();
208   } // getDefaultValue
209 
210   /** Default value string (unprocessed, from the metadata)
211     * for the parameter
212     */
213   String defaultValueString;
214 
215   /** Set the default value string (from the metadata)
216     * for the parameter
217     */
218   public void setDefaultValueString(String defaultValueString) {
219     this.defaultValueString = defaultValueString;
220   } // setDefaultValueString
221 
222   /** Get the default value string (unprocessed, from the metadata)
223     * for the parameter
224     */
225   public String getDefaultValueString() { return defaultValueString; }
226 
227   /** Comment for the parameter */
228   String comment;
229 
230   /** Set the comment for this parameter */
231   public void setComment(String comment) { this.comment = comment; }
232 
233   /** Get the comment for this parameter */
234   public String getComment() { return comment; }
235 
236   /** Name for the parameter */
237   String name;
238 
239   /** Set the name for this parameter */
240   public void setName(String name) { this.name = name; }
241 
242   /** Get the name for this parameter */
243   public String getName() { return name; }
244 
245   /** Get the suffixes atached with this param. If it's null then there are
246    *  no suffices attached with it
247    */
248   public Set getSuffixes(){ return suffixes;}
249 
250   /** Is this a run-time parameter? */
251   boolean runtime = false;
252 
253   /**
254    * The URL to the creole.xml file that defines the resource this parameter 
255    * belongs to. It is used for deriving default values for parameters of type
256    * {@link URL}.
257    */
258   protected URL baseURL;
259   /** Set runtime status of this parameter */
260   public void setRuntime(boolean runtime) { this.runtime = runtime; }
261 
262   /** Is the parameter runtime? */
263   public boolean isRuntime() { return runtime; }
264 
265   /** The Class for the parameter type */
266   protected Class paramClass;
267 
268   /** Find the class for this parameter type. */
269   protected Class getParameterClass() throws ParameterException
270   {
271     // get java builtin classes via class; else look in the register
272     try {
273       ResourceData resData = (ResourceData)
274                              Gate.getCreoleRegister().get(typeName);
275       if(resData == null){
276         paramClass = Gate.getClassLoader().loadClass(typeName);
277       }else{
278         paramClass = resData.getResourceClass();
279       }
280 
281 //      if(typeName.startsWith("java."))
282 //          paramClass = Class.forName(typeName);
283 //      else {
284 //        ResourceData resData =
285 //          (ResourceData) Gate.getCreoleRegister().get(typeName);
286 //        if(resData == null)
287 //          throw new ParameterException(
288 //            "No resource data for " + typeName + " in Parameter/getParamClz"
289 //          );
290 //        paramClass = resData.getResourceClass();
291 //      }
292     } catch(ClassNotFoundException e) {
293       throw new ParameterException(
294         "Couldn't find class " + typeName + ": " + Strings.getNl() + e
295       );
296     }
297 
298     if(paramClass == null)
299       throw new ParameterException("Couldn't find class " + typeName);
300 
301     return paramClass;
302   } // getParameterClass
303 
304   /** String representation */
305   public String toString() {
306     try{
307       return "Parameter: name="+ name+ "; valueString=" + typeName +
308              "; optional=" + optional +
309              "; defaultValueString=" + defaultValueString +
310              "; defaultValue=" + getDefaultValue() + "; comment=" +
311              comment + "; runtime=" + runtime +
312              "; itemClassName=" + itemClassName +
313              "; suffixes=" + suffixes;
314     }catch(ParameterException pe){
315       throw new GateRuntimeException(pe.toString());
316     }
317   }
318 
319   /**
320    * If this parameter is a List type this will return the type of the items
321    * in the list. If the type is <tt>null</tt> String will be assumed.
322    */
323   public String getItemClassName() {
324     return itemClassName;
325   } // toString()
326 } // class Parameter
327