1   /*
2    *  AbstractResource.java
3    *
4    *  Copyright (c) 1998-2001, 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: AbstractResource.java,v 1.12 2002/02/26 10:30:07 valyt Exp $
14   */
15  
16  package gate.creole;
17  
18  import java.util.*;
19  import java.io.*;
20  import java.beans.*;
21  import java.lang.reflect.*;
22  
23  
24  import gate.*;
25  import gate.util.*;
26  
27  
28  /** A convenience implementation of Resource with some default code.
29    */
30  abstract public class AbstractResource
31  extends AbstractFeatureBearer implements Resource, Serializable
32  {
33    static final long serialVersionUID = -9196293927841163321L;
34  
35    /** Initialise this resource, and return it. */
36    public Resource init() throws ResourceInstantiationException {
37      return this;
38    } // init()
39  
40      /** Sets the name of this resource*/
41    public void setName(String name){
42      this.name = name;
43    }
44  
45    /** Returns the name of this resource*/
46    public String getName(){
47      return name;
48    }
49  
50    protected String name;
51    /**
52     * releases the memory allocated to this resource
53     */
54    public void cleanup(){
55    }
56  
57    //Parameters utility methods
58    /**
59     * Gets the value of a parameter for a resource.
60     * @param resource the resource from which the parameter value will be
61     * obtained
62     * @param paramaterName the name of the parameter
63     * @return the current value of the parameter
64     */
65    public static Object getParameterValue(Resource resource,
66                                           String paramaterName)
67                  throws ResourceInstantiationException{
68      // get the beaninfo for the resource bean, excluding data about Object
69      BeanInfo resBeanInf = null;
70      try {
71        resBeanInf = Introspector.getBeanInfo(resource.getClass(), Object.class);
72      } catch(Exception e) {
73        throw new ResourceInstantiationException(
74          "Couldn't get bean info for resource " + resource.getClass().getName()
75          + Strings.getNl() + "Introspector exception was: " + e
76        );
77      }
78      PropertyDescriptor[] properties = resBeanInf.getPropertyDescriptors();
79  
80      //find the property we're interested on
81      if(properties == null){
82        throw new ResourceInstantiationException(
83          "Couldn't get properties info for resource " +
84          resource.getClass().getName());
85      }
86      boolean done = false;
87      int i = 0;
88      Object value = null;
89      while(!done && i < properties.length){
90        PropertyDescriptor prop = properties[i];
91        if(prop.getName().equals(paramaterName)){
92          Method getMethod = prop.getReadMethod();
93          if(getMethod == null){
94            throw new ResourceInstantiationException(
95              "Couldn't get read accessor method for parameter " + paramaterName +
96              " in " + resource.getClass().getName());
97          }
98          // call the get method with the parameter value
99          Object[] args = new Object[0];
100         try {
101           value = getMethod.invoke(resource, args);
102         } catch(Exception e) {
103           throw new ResourceInstantiationException(
104             "couldn't invoke get method: " + e
105           );
106         }
107         done = true;
108       }//if(prop.getName().equals(paramaterName))
109       i++;
110     }//while(!done && i < properties.length)
111     if(done) return value;
112     else throw new ResourceInstantiationException(
113             "Couldn't find parameter named " + paramaterName +
114             " in " + resource.getClass().getName());
115   }
116 
117   /**
118    * Sets the value for a specified parameter for a resource.
119    *
120    * @param resource the resource for which the parameter value will be set
121    * @param paramaterName the name for the parameteer
122    * @param parameterValue the value the parameter will receive
123    */
124   public static void setParameterValue(Resource resource, BeanInfo resBeanInf,
125                                        String paramaterName,
126                                        Object parameterValue)
127               throws ResourceInstantiationException{
128     PropertyDescriptor[] properties = resBeanInf.getPropertyDescriptors();
129     //find the property we're interested on
130     if(properties == null){
131       throw new ResourceInstantiationException(
132         "Couldn't get properties info for resource " +
133         resource.getClass().getName());
134     }
135     boolean done = false;
136     int i = 0;
137     while(!done && i < properties.length){
138       PropertyDescriptor prop = properties[i];
139       if(prop.getName().equals(paramaterName)){
140         Method setMethod = prop.getWriteMethod();
141         if(setMethod == null){
142           throw new ResourceInstantiationException(
143             "Couldn't get write accessor method for parameter " +
144             paramaterName + " in " + resource.getClass().getName());
145         }
146 
147         // convert the parameter to the right type eg String -> URL
148         if(parameterValue != null){
149           Class propertyType = prop.getPropertyType();
150           Class paramType = parameterValue.getClass();
151           try {
152             if(!propertyType.isAssignableFrom(paramType)) {
153               parameterValue =
154                 propertyType.getConstructor(
155                   new Class[]{paramType}
156                 ).newInstance( new Object[]{parameterValue} );
157             }
158           } catch(Exception e) {
159             throw new ResourceInstantiationException(
160               "Error converting " + parameterValue.getClass() +
161               " to " + propertyType + ": " + e.toString()
162             );
163           }
164         }//if(parameterValue != null)
165 
166         // call the set method with the parameter value
167         Object[] args = new Object[1];
168         args[0] = parameterValue;
169         try {
170           setMethod.invoke(resource, args);
171         } catch(Exception e) {
172           e.printStackTrace(Err.getPrintWriter());
173           throw new ResourceInstantiationException(
174             "couldn't invoke set method for " + paramaterName +
175             " on " + resource.getClass().getName() + ": " + e);
176         }
177         done = true;
178       }//if(prop.getName().equals(paramaterName))
179       i++;
180     }//while(!done && i < properties.length)
181     if(!done) throw new ResourceInstantiationException(
182                           "Couldn't find parameter named " + paramaterName +
183                           " in " + resource.getClass().getName());
184   }//public void setParameterValue(String paramaterName, Object parameterValue)
185 
186 
187   /**
188    * Sets the values for more parameters for a resource in one step.
189    *
190    * @param parameters a feature map that has paramete names as keys and
191    * parameter values as values.
192    */
193   public static void setParameterValues(Resource resource,
194                                         FeatureMap parameters)
195               throws ResourceInstantiationException{
196     // get the beaninfo for the resource bean, excluding data about Object
197     BeanInfo resBeanInf = null;
198     try {
199       resBeanInf = Introspector.getBeanInfo(resource.getClass(), Object.class);
200     } catch(Exception e) {
201       throw new ResourceInstantiationException(
202         "Couldn't get bean info for resource " + resource.getClass().getName()
203         + Strings.getNl() + "Introspector exception was: " + e
204       );
205     }
206 
207     Iterator parnameIter = parameters.keySet().iterator();
208     while(parnameIter.hasNext()){
209       String parName = (String)parnameIter.next();
210       setParameterValue(resource, resBeanInf, parName, parameters.get(parName));
211     }
212   }
213 
214 
215   /**
216    * Adds listeners to a resource.
217    * @param listeners The listeners to be registered with the resource. A
218    * {@link java.util.Map} that maps from fully qualified class name (as a
219    * string) to listener (of the type declared by the key).
220    * @param resource the resource that listeners will be registered to.
221    */
222   public static void setResourceListeners(Resource resource, Map listeners)
223   throws
224     IntrospectionException, InvocationTargetException,
225     IllegalAccessException, GateException
226   {
227     // get the beaninfo for the resource bean, excluding data about Object
228     BeanInfo resBeanInfo = Introspector.getBeanInfo(
229       resource.getClass(), Object.class
230     );
231 
232     // get all the events the bean can fire
233     EventSetDescriptor[] events = resBeanInfo.getEventSetDescriptors();
234 
235     // add the listeners
236     if (events != null) {
237       EventSetDescriptor event;
238       for(int i = 0; i < events.length; i++) {
239         event = events[i];
240 
241         // did we get such a listener?
242         Object listener =
243           listeners.get(event.getListenerType().getName());
244         if(listener != null) {
245           Method addListener = event.getAddListenerMethod();
246 
247           // call the set method with the parameter value
248           Object[] args = new Object[1];
249           args[0] = listener;
250           addListener.invoke(resource, args);
251         }
252       } // for each event
253     }   // if events != null
254   } // setResourceListeners()
255 
256   /**
257    * Removes listeners from a resource.
258    * @param listeners The listeners to be removed from the resource. A
259    * {@link java.util.Map} that maps from fully qualified class name
260    * (as a string) to listener (of the type declared by the key).
261    * @param resource the resource that listeners will be removed from.
262    */
263   public static void removeResourceListeners(Resource resource, Map listeners)
264                      throws IntrospectionException, InvocationTargetException,
265                             IllegalAccessException, GateException{
266 
267     // get the beaninfo for the resource bean, excluding data about Object
268     BeanInfo resBeanInfo = Introspector.getBeanInfo(
269       resource.getClass(), Object.class
270     );
271 
272     // get all the events the bean can fire
273     EventSetDescriptor[] events = resBeanInfo.getEventSetDescriptors();
274 
275     //remove the listeners
276     if(events != null) {
277       EventSetDescriptor event;
278       for(int i = 0; i < events.length; i++) {
279         event = events[i];
280 
281         // did we get such a listener?
282         Object listener =
283           listeners.get(event.getListenerType().getName());
284         if(listener != null) {
285           Method removeListener = event.getRemoveListenerMethod();
286 
287           // call the set method with the parameter value
288           Object[] args = new Object[1];
289           args[0] = listener;
290           removeListener.invoke(resource, args);
291         }
292       } // for each event
293     }   // if events != null
294   } // removeResourceListeners()
295 
296   /**
297    * Checks whether the provided {@link Resource} has values for all the
298    * required parameters from the provided list of parameters.
299    *
300    * @param resource the resource being checked
301    * @param paramters is a {@link List} of {@link List} of {@link Parameter}
302    * representing a list of parameter disjunctions (e.g. the one returned by
303    * {@link ParameterList#getRuntimeParameters()}).
304    * @return <tt>true</tt> if all the required parameters have non null values,
305    * <tt>false</tt> otherwise.
306    * @throw {@link ResourceInstantiationException} if problems occur while
307    * inspecting the parameters for the resource. These will normally be
308    * introspection problems and are usually caused by the lack of a parameter
309    * or of the read accessor for a parameter.
310    */
311   public static boolean checkParameterValues(Resource resource,
312                                              List parameters)
313                 throws ResourceInstantiationException{
314     Iterator disIter = parameters.iterator();
315     while(disIter.hasNext()){
316       List disjunction = (List)disIter.next();
317       boolean required = !((Parameter)disjunction.get(0)).isOptional();
318       if(required){
319         //at least one parameter in the disjunction must have a value
320         boolean valueSet = false;
321         Iterator parIter = disjunction.iterator();
322         while(!valueSet && parIter.hasNext()){
323           Parameter par = (Parameter)parIter.next();
324           valueSet = (resource.getParameterValue(par.getName()) != null);
325         }
326         if(!valueSet) return false;
327       }
328     }
329     return true;
330   }
331 
332 
333 
334   /**
335    * Gets the value of a parameter of this resource.
336    * @param paramaterName the name of the parameter
337    * @return the current value of the parameter
338    */
339   public Object getParameterValue(String paramaterName)
340                 throws ResourceInstantiationException{
341     return getParameterValue(this, paramaterName);
342   }
343 
344   /**
345    * Sets the value for a specified parameter for this resource.
346    *
347    * @param paramaterName the name for the parameter
348    * @param parameterValue the value the parameter will receive
349    */
350   public void setParameterValue(String paramaterName, Object parameterValue)
351               throws ResourceInstantiationException{
352     // get the beaninfo for the resource bean, excluding data about Object
353     BeanInfo resBeanInf = null;
354     try {
355       resBeanInf = Introspector.getBeanInfo(this.getClass(), Object.class);
356     } catch(Exception e) {
357       throw new ResourceInstantiationException(
358         "Couldn't get bean info for resource " + this.getClass().getName()
359         + Strings.getNl() + "Introspector exception was: " + e
360       );
361     }
362     setParameterValue(this, resBeanInf, paramaterName, parameterValue);
363   }
364 
365   /**
366    * Sets the values for more parameters for this resource in one step.
367    *
368    * @param parameters a feature map that has paramete names as keys and
369    * parameter values as values.
370    */
371   public void setParameterValues(FeatureMap parameters)
372               throws ResourceInstantiationException{
373     setParameterValues(this, parameters);
374   }
375 
376 
377 } // class AbstractResource
378