1   /*
2    *  Parameter.java
3    *
4    *  Copyright (c) 1998-2005, 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.24 2006/03/17 12:42:12 ian_roberts 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 - for numeric types, we don't attempt to parse an
151     // empty string value, but just leave value as null
152     if(typeName.startsWith("java.")) {
153       if(typeName.equals("java.lang.Boolean"))
154         value = Boolean.valueOf(stringValue);
155       else if(typeName.equals("java.lang.Long")) {
156         if(stringValue != null && !stringValue.equals("")) {
157           value = Long.valueOf(stringValue);
158         }
159       }
160       else if(typeName.equals("java.lang.Integer")) {
161         if(stringValue != null && !stringValue.equals("")) {
162           value = Integer.valueOf(stringValue);
163         }
164       }
165       else if(typeName.equals("java.lang.String"))
166         value = stringValue;
167       else if(typeName.equals("java.lang.Double")) {
168         if(stringValue != null && !stringValue.equals("")) {
169           value = Double.valueOf(stringValue);
170         }
171       }
172       else if(typeName.equals("java.lang.Float")) {
173         if(stringValue != null && !stringValue.equals("")) {
174           value = Float.valueOf(stringValue);
175         }
176       }
177       else if(typeName.equals("java.net.URL"))
178         try{
179           value = new URL(baseURL, stringValue);
180         }catch(MalformedURLException mue){
181           value = null;
182         }
183       else{
184         //try to construct a new value from the string using a constructor
185         // e.g. for URLs
186         try{
187           if(!paramClass.isAssignableFrom(String.class)){
188             value = paramClass.getConstructor(new Class[]{String.class}).
189                          newInstance(new Object[]{stringValue});
190           }
191         }catch(Exception e){
192           throw new ParameterException("Unsupported parameter type " + typeName);
193         }
194       }
195     } else {
196       // non java types
197       if(resData == null)
198         resData = (ResourceData) Gate.getCreoleRegister().get(typeName);
199       if(resData == null){
200         //unknown type
201         return null;
202       }
203 
204       WeakBumpyStack instantiations = resData.getInstantiations();
205       if(! instantiations.isEmpty()) value = instantiations.peek();
206     }
207 
208     return value;
209   } // calculateValueFromString()
210 
211 
212   /** The resource data that this parameter is part of. */
213   protected ResourceData resData;
214 
215   /** Get the default value for this parameter. If the value is
216     * currently null it will try and calculate a value.
217     * @see #calculateDefaultValue()
218     */
219   public Object getDefaultValue() throws ParameterException {
220     return calculateDefaultValue();
221   } // getDefaultValue
222 
223   /** Default value string (unprocessed, from the metadata)
224     * for the parameter
225     */
226   String defaultValueString;
227 
228   /** Set the default value string (from the metadata)
229     * for the parameter
230     */
231   public void setDefaultValueString(String defaultValueString) {
232     this.defaultValueString = defaultValueString;
233   } // setDefaultValueString
234 
235   /** Get the default value string (unprocessed, from the metadata)
236     * for the parameter
237     */
238   public String getDefaultValueString() { return defaultValueString; }
239 
240   /** Comment for the parameter */
241   String comment;
242 
243   /** Set the comment for this parameter */
244   public void setComment(String comment) { this.comment = comment; }
245 
246   /** Get the comment for this parameter */
247   public String getComment() { return comment; }
248 
249   /** Name for the parameter */
250   String name;
251 
252   /** Set the name for this parameter */
253   public void setName(String name) { this.name = name; }
254 
255   /** Get the name for this parameter */
256   public String getName() { return name; }
257 
258   /** Get the suffixes atached with this param. If it's null then there are
259    *  no suffices attached with it
260    */
261   public Set getSuffixes(){ return suffixes;}
262 
263   /** Is this a run-time parameter? */
264   boolean runtime = false;
265 
266   /**
267    * The URL to the creole.xml file that defines the resource this parameter 
268    * belongs to. It is used for deriving default values for parameters of type
269    * {@link URL}.
270    */
271   protected URL baseURL;
272   /** Set runtime status of this parameter */
273   public void setRuntime(boolean runtime) { this.runtime = runtime; }
274 
275   /** Is the parameter runtime? */
276   public boolean isRuntime() { return runtime; }
277 
278   /** The Class for the parameter type */
279   protected Class paramClass;
280 
281   /** Find the class for this parameter type. */
282   protected Class getParameterClass() throws ParameterException
283   {
284     // get java builtin classes via class; else look in the register
285     try {
286       ResourceData resData = (ResourceData)
287                              Gate.getCreoleRegister().get(typeName);
288       if(resData == null){
289         paramClass = Gate.getClassLoader().loadClass(typeName);
290       }else{
291         paramClass = resData.getResourceClass();
292       }
293 
294 //      if(typeName.startsWith("java."))
295 //          paramClass = Class.forName(typeName);
296 //      else {
297 //        ResourceData resData =
298 //          (ResourceData) Gate.getCreoleRegister().get(typeName);
299 //        if(resData == null)
300 //          throw new ParameterException(
301 //            "No resource data for " + typeName + " in Parameter/getParamClz"
302 //          );
303 //        paramClass = resData.getResourceClass();
304 //      }
305     } catch(ClassNotFoundException e) {
306       throw new ParameterException(
307         "Couldn't find class " + typeName + ": " + Strings.getNl() + e
308       );
309     }
310 
311     if(paramClass == null)
312       throw new ParameterException("Couldn't find class " + typeName);
313 
314     return paramClass;
315   } // getParameterClass
316 
317   /** String representation */
318   public String toString() {
319     try{
320       return "Parameter: name="+ name+ "; valueString=" + typeName +
321              "; optional=" + optional +
322              "; defaultValueString=" + defaultValueString +
323              "; defaultValue=" + getDefaultValue() + "; comment=" +
324              comment + "; runtime=" + runtime +
325              "; itemClassName=" + itemClassName +
326              "; suffixes=" + suffixes;
327     }catch(ParameterException pe){
328       throw new GateRuntimeException(pe.toString());
329     }
330   }
331 
332   /**
333    * If this parameter is a List type this will return the type of the items
334    * in the list. If the type is <tt>null</tt> String will be assumed.
335    */
336   public String getItemClassName() {
337     return itemClassName;
338   } // toString()
339 } // class Parameter
340