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.11 2001/11/12 18:54:50 kalina 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           throw new ResourceInstantiationException(
173             "couldn't invoke set method for " + paramaterName +
174             " on " + resource.getClass().getName() + ": " + e);
175         }
176         done = true;
177       }//if(prop.getName().equals(paramaterName))
178       i++;
179     }//while(!done && i < properties.length)
180     if(!done) throw new ResourceInstantiationException(
181                           "Couldn't find parameter named " + paramaterName +
182                           " in " + resource.getClass().getName());
183   }//public void setParameterValue(String paramaterName, Object parameterValue)
184 
185 
186   /**
187    * Sets the values for more parameters for a resource in one step.
188    *
189    * @param parameters a feature map that has paramete names as keys and
190    * parameter values as values.
191    */
192   public static void setParameterValues(Resource resource,
193                                         FeatureMap parameters)
194               throws ResourceInstantiationException{
195     // get the beaninfo for the resource bean, excluding data about Object
196     BeanInfo resBeanInf = null;
197     try {
198       resBeanInf = Introspector.getBeanInfo(resource.getClass(), Object.class);
199     } catch(Exception e) {
200       throw new ResourceInstantiationException(
201         "Couldn't get bean info for resource " + resource.getClass().getName()
202         + Strings.getNl() + "Introspector exception was: " + e
203       );
204     }
205 
206     Iterator parnameIter = parameters.keySet().iterator();
207     while(parnameIter.hasNext()){
208       String parName = (String)parnameIter.next();
209       setParameterValue(resource, resBeanInf, parName, parameters.get(parName));
210     }
211   }
212 
213 
214   /**
215    * Adds listeners to a resource.
216    * @param listeners The listeners to be registered with the resource. A
217    * {@link java.util.Map} that maps from fully qualified class name (as a
218    * string) to listener (of the type declared by the key).
219    * @param resource the resource that listeners will be registered to.
220    */
221   public static void setResourceListeners(Resource resource, Map listeners)
222   throws
223     IntrospectionException, InvocationTargetException,
224     IllegalAccessException, GateException
225   {
226     // get the beaninfo for the resource bean, excluding data about Object
227     BeanInfo resBeanInfo = Introspector.getBeanInfo(
228       resource.getClass(), Object.class
229     );
230 
231     // get all the events the bean can fire
232     EventSetDescriptor[] events = resBeanInfo.getEventSetDescriptors();
233 
234     // add the listeners
235     if (events != null) {
236       EventSetDescriptor event;
237       for(int i = 0; i < events.length; i++) {
238         event = events[i];
239 
240         // did we get such a listener?
241         Object listener =
242           listeners.get(event.getListenerType().getName());
243         if(listener != null) {
244           Method addListener = event.getAddListenerMethod();
245 
246           // call the set method with the parameter value
247           Object[] args = new Object[1];
248           args[0] = listener;
249           addListener.invoke(resource, args);
250         }
251       } // for each event
252     }   // if events != null
253   } // setResourceListeners()
254 
255   /**
256    * Removes listeners from a resource.
257    * @param listeners The listeners to be removed from the resource. A
258    * {@link java.util.Map} that maps from fully qualified class name
259    * (as a string) to listener (of the type declared by the key).
260    * @param resource the resource that listeners will be removed from.
261    */
262   public static void removeResourceListeners(Resource resource, Map listeners)
263                      throws IntrospectionException, InvocationTargetException,
264                             IllegalAccessException, GateException{
265 
266     // get the beaninfo for the resource bean, excluding data about Object
267     BeanInfo resBeanInfo = Introspector.getBeanInfo(
268       resource.getClass(), Object.class
269     );
270 
271     // get all the events the bean can fire
272     EventSetDescriptor[] events = resBeanInfo.getEventSetDescriptors();
273 
274     //remove the listeners
275     if(events != null) {
276       EventSetDescriptor event;
277       for(int i = 0; i < events.length; i++) {
278         event = events[i];
279 
280         // did we get such a listener?
281         Object listener =
282           listeners.get(event.getListenerType().getName());
283         if(listener != null) {
284           Method removeListener = event.getRemoveListenerMethod();
285 
286           // call the set method with the parameter value
287           Object[] args = new Object[1];
288           args[0] = listener;
289           removeListener.invoke(resource, args);
290         }
291       } // for each event
292     }   // if events != null
293   } // removeResourceListeners()
294 
295   /**
296    * Checks whether the provided {@link Resource} has values for all the
297    * required parameters from the provided list of parameters.
298    *
299    * @param resource the resource being checked
300    * @param paramters is a {@link List} of {@link List} of {@link Parameter}
301    * representing a list of parameter disjunctions (e.g. the one returned by
302    * {@link ParameterList#getRuntimeParameters()}).
303    * @return <tt>true</tt> if all the required parameters have non null values,
304    * <tt>false</tt> otherwise.
305    * @throw {@link ResourceInstantiationException} if problems occur while
306    * inspecting the parameters for the resource. These will normally be
307    * introspection problems and are usually caused by the lack of a parameter
308    * or of the read accessor for a parameter.
309    */
310   public static boolean checkParameterValues(Resource resource,
311                                              List parameters)
312                 throws ResourceInstantiationException{
313     Iterator disIter = parameters.iterator();
314     while(disIter.hasNext()){
315       List disjunction = (List)disIter.next();
316       boolean required = !((Parameter)disjunction.get(0)).isOptional();
317       if(required){
318         //at least one parameter in the disjunction must have a value
319         boolean valueSet = false;
320         Iterator parIter = disjunction.iterator();
321         while(!valueSet && parIter.hasNext()){
322           Parameter par = (Parameter)parIter.next();
323           valueSet = (resource.getParameterValue(par.getName()) != null);
324         }
325         if(!valueSet) return false;
326       }
327     }
328     return true;
329   }
330 
331 
332 
333   /**
334    * Gets the value of a parameter of this resource.
335    * @param paramaterName the name of the parameter
336    * @return the current value of the parameter
337    */
338   public Object getParameterValue(String paramaterName)
339                 throws ResourceInstantiationException{
340     return getParameterValue(this, paramaterName);
341   }
342 
343   /**
344    * Sets the value for a specified parameter for this resource.
345    *
346    * @param paramaterName the name for the parameter
347    * @param parameterValue the value the parameter will receive
348    */
349   public void setParameterValue(String paramaterName, Object parameterValue)
350               throws ResourceInstantiationException{
351     // get the beaninfo for the resource bean, excluding data about Object
352     BeanInfo resBeanInf = null;
353     try {
354       resBeanInf = Introspector.getBeanInfo(this.getClass(), Object.class);
355     } catch(Exception e) {
356       throw new ResourceInstantiationException(
357         "Couldn't get bean info for resource " + this.getClass().getName()
358         + Strings.getNl() + "Introspector exception was: " + e
359       );
360     }
361     setParameterValue(this, resBeanInf, paramaterName, parameterValue);
362   }
363 
364   /**
365    * Sets the values for more parameters for this resource in one step.
366    *
367    * @param parameters a feature map that has paramete names as keys and
368    * parameter values as values.
369    */
370   public void setParameterValues(FeatureMap parameters)
371               throws ResourceInstantiationException{
372     setParameterValues(this, parameters);
373   }
374 
375 
376 } // class AbstractResource
377