AbstractResource.java
001 /*
002  *  AbstractResource.java
003  *
004  *  Copyright (c) 1995-2010, The University of Sheffield. See the file
005  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
006  *
007  *  This file is part of GATE (see http://gate.ac.uk/), and is free
008  *  software, licenced under the GNU Library General Public License,
009  *  Version 2, June 1991 (in the distribution as file licence.html,
010  *  and also available at http://gate.ac.uk/gate/licence.html).
011  *
012  *  Hamish Cunningham, 15/Oct/2000
013  *
014  *  $Id: AbstractResource.java 12006 2009-12-01 17:24:28Z thomas_heitz $
015  */
016 
017 package gate.creole;
018 
019 import java.beans.*;
020 import java.io.Serializable;
021 import java.lang.reflect.Constructor;
022 import java.lang.reflect.InvocationTargetException;
023 import java.lang.reflect.Method;
024 import java.util.*;
025 
026 import gate.*;
027 import gate.util.*;
028 
029 
030 /** A convenience implementation of Resource with some default code.
031   */
032 abstract public class AbstractResource
033 extends AbstractFeatureBearer implements Resource, Serializable
034 {
035   static final long serialVersionUID = -9196293927841163321L;
036 
037   /** Initialise this resource, and return it. */
038   public Resource init() throws ResourceInstantiationException {
039     return this;
040   // init()
041 
042     /** Sets the name of this resource*/
043   public void setName(String name){
044     this.name = name;
045   }
046 
047   /** Returns the name of this resource*/
048   public String getName(){
049     return name;
050   }
051 
052   protected String name;
053   /**
054    * releases the memory allocated to this resource
055    */
056   public void cleanup(){
057   }
058 
059   //Parameters utility methods
060   /**
061    * Gets the value of a parameter for a resource.
062    @param resource the resource from which the parameter value will be
063    * obtained
064    @param paramaterName the name of the parameter
065    @return the current value of the parameter
066    */
067   public static Object getParameterValue(Resource resource,
068                                          String paramaterName)
069                 throws ResourceInstantiationException{
070     // get the beaninfo for the resource bean, excluding data about Object
071     BeanInfo resBeanInf = null;
072     try {
073       resBeanInf = getBeanInfo(resource.getClass());
074     catch(Exception e) {
075       throw new ResourceInstantiationException(
076         "Couldn't get bean info for resource " + resource.getClass().getName()
077         + Strings.getNl() "Introspector exception was: " + e
078       );
079     }
080     PropertyDescriptor[] properties = resBeanInf.getPropertyDescriptors();
081 
082     //find the property we're interested on
083     if(properties == null){
084       throw new ResourceInstantiationException(
085         "Couldn't get properties info for resource " +
086         resource.getClass().getName());
087     }
088     boolean done = false;
089     int i = 0;
090     Object value = null;
091     while(!done && i < properties.length){
092       PropertyDescriptor prop = properties[i];
093       if(prop.getName().equals(paramaterName)){
094         Method getMethod = prop.getReadMethod();
095         if(getMethod == null){
096           throw new ResourceInstantiationException(
097             "Couldn't get read accessor method for parameter " + paramaterName +
098             " in " + resource.getClass().getName());
099         }
100         // call the get method with the parameter value
101         Object[] args = new Object[0];
102         try {
103           value = getMethod.invoke(resource, args);
104         catch(Exception e) {
105           throw new ResourceInstantiationException(
106             "couldn't invoke get method: " + e
107           );
108         }
109         done = true;
110       }//if(prop.getName().equals(paramaterName))
111       i++;
112     }//while(!done && i < properties.length)
113     if(donereturn value;
114     else throw new ResourceInstantiationException(
115             "Couldn't find parameter named " + paramaterName +
116             " in " + resource.getClass().getName());
117   }
118 
119   /**
120    * Sets the value for a specified parameter for a resource.
121    *
122    @param resource the resource for which the parameter value will be set
123    @param paramaterName the name for the parameter
124    @param parameterValue the value the parameter will receive
125    */
126   public static void setParameterValue(Resource resource, BeanInfo resBeanInf,
127                                        String paramaterName,
128                                        Object parameterValue)
129               throws ResourceInstantiationException{
130     PropertyDescriptor[] properties = resBeanInf.getPropertyDescriptors();
131     //find the property we're interested on
132     if(properties == null){
133       throw new ResourceInstantiationException(
134         "Couldn't get properties info for resource " +
135         resource.getClass().getName());
136     }
137     boolean done = false;
138     int i = 0;
139     while(!done && i < properties.length){
140       PropertyDescriptor prop = properties[i];
141       if(prop.getName().equals(paramaterName)){
142         Method setMethod = prop.getWriteMethod();
143         if(setMethod == null){
144           throw new ResourceInstantiationException(
145             "Couldn't get write accessor method for parameter " +
146             paramaterName + " in " + resource.getClass().getName());
147         }
148 
149         // convert the parameter to the right type eg String -> URL
150         if(parameterValue != null){
151           Class propertyType = prop.getPropertyType();
152           Class typeToCreate = propertyType;
153           if(Parameter.substituteClasses.containsKey(propertyType)) {
154             typeToCreate = Parameter.substituteClasses.get(propertyType);
155           }
156           Class paramType = parameterValue.getClass();
157           if(!propertyType.isAssignableFrom(paramType)) {
158             try {
159               Constructor mostSpecificConstructor =
160                 Tools.getMostSpecificConstructor(typeToCreate, paramType);
161               parameterValue = mostSpecificConstructor
162                  .newInstancenew Object[]{parameterValue} );
163             catch(Exception e) {
164               //this didn't work; if the parameter value is String
165               //try to use the Parameter implementation for finding the 
166               //value
167               if(String.class.isAssignableFrom(paramType)){
168                 ResourceData rData = (ResourceData)Gate.getCreoleRegister().
169                   get(resource.getClass().getName());
170                 ParameterList pList = rData.getParameterList();
171                 Parameter param = null;
172                 Iterator disjIter = pList.getInitimeParameters().iterator();
173                 while(param == null && disjIter.hasNext()){
174                   Iterator paramIter = ((List)disjIter.next()).iterator();
175                   while(param == null && paramIter.hasNext()){
176                     Parameter aParam = (Parameter)paramIter.next();
177                     if(aParam.getName().equals(paramaterName)) param = aParam; 
178                   }
179                 }
180                 disjIter = pList.getRuntimeParameters().iterator();
181                 while(param == null && disjIter.hasNext()){
182                   Iterator paramIter = ((List)disjIter.next()).iterator();
183                   while(param == null && paramIter.hasNext()){
184                     Parameter aParam = (Parameter)paramIter.next();
185                     if(aParam.getName().equals(paramaterName)) param = aParam; 
186                   }
187                 }
188                 if(param != null){
189                   try{
190                     parameterValue = param.calculateValueFromString(
191                             (String)parameterValue);
192                   }catch(ParameterException pe){
193                     throw new ResourceInstantiationException(pe);
194                   }
195                 }else{
196                   //this should never happen
197                   throw new LuckyException("Unknown parameter " + paramaterName +
198                           " for resource " + resource.getClass().getName() 
199                           "!");
200                 }
201               }else{
202                 throw new ResourceInstantiationException(
203                   "Error converting " + parameterValue.getClass() +
204                   " to " + propertyType + ": " + e.toString()
205                 );
206               }
207             }
208           }
209         }//if(parameterValue != null)
210 
211         // call the set method with the parameter value
212         Object[] args = new Object[1];
213         args[0= parameterValue;
214         try {
215           setMethod.invoke(resource, args);
216         catch(Exception e) {
217           e.printStackTrace(Err.getPrintWriter());
218           throw new ResourceInstantiationException(
219             "couldn't invoke set method for " + paramaterName +
220             " on " + resource.getClass().getName() ": " + e);
221         }
222         done = true;
223       }//if(prop.getName().equals(paramaterName))
224       i++;
225     }//while(!done && i < properties.length)
226     if(!donethrow new ResourceInstantiationException(
227                           "Couldn't find parameter named " + paramaterName +
228                           " in " + resource.getClass().getName());
229   }//public void setParameterValue(String paramaterName, Object parameterValue)
230 
231 
232   /**
233    * Sets the values for more parameters for a resource in one step.
234    *
235    @param parameters a feature map that has paramete names as keys and
236    * parameter values as values.
237    */
238   public static void setParameterValues(Resource resource,
239                                         FeatureMap parameters)
240               throws ResourceInstantiationException{
241     // get the beaninfo for the resource bean, excluding data about Object
242     BeanInfo resBeanInf = null;
243     try {
244       resBeanInf = getBeanInfo(resource.getClass());
245     catch(Exception e) {
246       throw new ResourceInstantiationException(
247         "Couldn't get bean info for resource " + resource.getClass().getName()
248         + Strings.getNl() "Introspector exception was: " + e
249       );
250     }
251 
252     Iterator parnameIter = parameters.keySet().iterator();
253     while(parnameIter.hasNext()){
254       String parName = (String)parnameIter.next();
255       setParameterValue(resource, resBeanInf, parName, parameters.get(parName));
256     }
257   }
258 
259 
260   /**
261    * Adds listeners to a resource.
262    @param listeners The listeners to be registered with the resource. A
263    {@link java.util.Map} that maps from fully qualified class name (as a
264    * string) to listener (of the type declared by the key).
265    @param resource the resource that listeners will be registered to.
266    */
267   public static void setResourceListeners(Resource resource, Map listeners)
268   throws
269     IntrospectionException, InvocationTargetException,
270     IllegalAccessException, GateException
271   {
272     // get the beaninfo for the resource bean, excluding data about Object
273     BeanInfo resBeanInfo = getBeanInfo(resource.getClass());
274 
275     // get all the events the bean can fire
276     EventSetDescriptor[] events = resBeanInfo.getEventSetDescriptors();
277 
278     // add the listeners
279     if (events != null) {
280       EventSetDescriptor event;
281       for(int i = 0; i < events.length; i++) {
282         event = events[i];
283 
284         // did we get such a listener?
285         Object listener =
286           listeners.get(event.getListenerType().getName());
287         if(listener != null) {
288           Method addListener = event.getAddListenerMethod();
289 
290           // call the set method with the parameter value
291           Object[] args = new Object[1];
292           args[0= listener;
293           addListener.invoke(resource, args);
294         }
295       // for each event
296     }   // if events != null
297   // setResourceListeners()
298 
299   /**
300    * Removes listeners from a resource.
301    @param listeners The listeners to be removed from the resource. A
302    {@link java.util.Map} that maps from fully qualified class name
303    * (as a string) to listener (of the type declared by the key).
304    @param resource the resource that listeners will be removed from.
305    */
306   public static void removeResourceListeners(Resource resource, Map listeners)
307                      throws IntrospectionException, InvocationTargetException,
308                             IllegalAccessException, GateException{
309 
310     // get the beaninfo for the resource bean, excluding data about Object
311     BeanInfo resBeanInfo = getBeanInfo(resource.getClass());
312 
313     // get all the events the bean can fire
314     EventSetDescriptor[] events = resBeanInfo.getEventSetDescriptors();
315 
316     //remove the listeners
317     if(events != null) {
318       EventSetDescriptor event;
319       for(int i = 0; i < events.length; i++) {
320         event = events[i];
321 
322         // did we get such a listener?
323         Object listener =
324           listeners.get(event.getListenerType().getName());
325         if(listener != null) {
326           Method removeListener = event.getRemoveListenerMethod();
327 
328           // call the set method with the parameter value
329           Object[] args = new Object[1];
330           args[0= listener;
331           removeListener.invoke(resource, args);
332         }
333       // for each event
334     }   // if events != null
335   // removeResourceListeners()
336 
337   /**
338    * Checks whether the provided {@link Resource} has values for all the
339    * required parameters from the provided list of parameters.
340    *
341    @param resource the resource being checked
342    @param parameters is a {@link List} of {@link List} of {@link Parameter}
343    * representing a list of parameter disjunctions (e.g. the one returned by
344    {@link ParameterList#getRuntimeParameters()}).
345    @return <tt>true</tt> if all the required parameters have non null values,
346    <tt>false</tt> otherwise.
347    @throws {@link ResourceInstantiationException} if problems occur while
348    * inspecting the parameters for the resource. These will normally be
349    * introspection problems and are usually caused by the lack of a parameter
350    * or of the read accessor for a parameter.
351    */
352   public static boolean checkParameterValues(Resource resource,
353                                              List parameters)
354                 throws ResourceInstantiationException{
355     Iterator disIter = parameters.iterator();
356     while(disIter.hasNext()){
357       List disjunction = (List)disIter.next();
358       boolean required = !((Parameter)disjunction.get(0)).isOptional();
359       if(required){
360         //at least one parameter in the disjunction must have a value
361         boolean valueSet = false;
362         Iterator parIter = disjunction.iterator();
363         while(!valueSet && parIter.hasNext()){
364           Parameter par = (Parameter)parIter.next();
365           valueSet = (resource.getParameterValue(par.getName()) != null);
366         }
367         if(!valueSetreturn false;
368       }
369     }
370     return true;
371   }
372 
373 
374 
375   /**
376    * Gets the value of a parameter of this resource.
377    @param paramaterName the name of the parameter
378    @return the current value of the parameter
379    */
380   public Object getParameterValue(String paramaterName)
381                 throws ResourceInstantiationException{
382     return getParameterValue(this, paramaterName);
383   }
384 
385   /**
386    * Sets the value for a specified parameter for this resource.
387    *
388    @param paramaterName the name for the parameter
389    @param parameterValue the value the parameter will receive
390    */
391   public void setParameterValue(String paramaterName, Object parameterValue)
392               throws ResourceInstantiationException{
393     // get the beaninfo for the resource bean, excluding data about Object
394     BeanInfo resBeanInf = null;
395     try {
396       resBeanInf = getBeanInfo(this.getClass());
397     catch(Exception e) {
398       throw new ResourceInstantiationException(
399         "Couldn't get bean info for resource " this.getClass().getName()
400         + Strings.getNl() "Introspector exception was: " + e
401       );
402     }
403     setParameterValue(this, resBeanInf, paramaterName, parameterValue);
404   }
405 
406   /**
407    * Sets the values for more parameters for this resource in one step.
408    *
409    @param parameters a feature map that has paramete names as keys and
410    * parameter values as values.
411    */
412   public void setParameterValues(FeatureMap parameters)
413               throws ResourceInstantiationException{
414     setParameterValues(this, parameters);
415   }
416 
417   private static int beanCount = 0;
418   private static Hashtable beanInfoCache = new Hashtable();
419 
420   public static BeanInfo getBeanInfo (Class cthrows IntrospectionException
421   {
422     beanCount = beanCount + 1;
423     BeanInfo r = ((BeanInfobeanInfoCache.get(c));
424     if (r == null) {
425       r = Introspector.getBeanInfo(c, Object.class);
426       beanInfoCache.put(c, r);
427     }
428     return r;
429   }
430 
431 // class AbstractResource