View Javadoc

1   /*$Id: ApplicationDescription.java,v 1.7 2004/11/08 18:05:15 jdt Exp $
2    * Created on 09-Mar-2004
3    *
4    * Copyright (C) AstroGrid. All rights reserved.
5    *
6    * This software is published under the terms of the AstroGrid 
7    * Software License version 1.2, a copy of which has been included 
8    * with this distribution in the LICENSE.txt file.  
9    *
10  **/
11  package org.astrogrid.portal.workflow.intf;
12  
13  import org.astrogrid.applications.beans.v1.ApplicationBase;
14  import org.astrogrid.applications.beans.v1.Interface;
15  import org.astrogrid.applications.beans.v1.InterfacesType;
16  import org.astrogrid.applications.beans.v1.ParameterRef;
17  import org.astrogrid.applications.beans.v1.Parameters;
18  import org.astrogrid.applications.beans.v1.parameters.BaseParameterDefinition;
19  import org.astrogrid.applications.beans.v1.parameters.ParameterValue;
20  import org.astrogrid.common.bean.BaseBean;
21  import org.astrogrid.workflow.beans.v1.Input;
22  import org.astrogrid.workflow.beans.v1.Output;
23  import org.astrogrid.workflow.beans.v1.Tool;
24  
25  import org.exolab.castor.types.AnyNode;
26  import org.exolab.castor.xml.ValidationException;
27  import org.w3c.dom.Element;
28  
29  import java.util.HashMap;
30  import java.util.Iterator;
31  import java.util.Map;
32  
33  /*** Description of an application 
34   * <p>
35   * This class provides access to the descriptor of an application - by wrapping a {@link org.astrogrid.applications.beans.v1.ApplicationBase} object.
36   * <ul>
37   * <li>{@link #getInterfaces}
38   * <li>{@link #getName}
39   * <li>{@link #getParameters}
40   * </ul>
41   * 
42   * <p>
43   * It also provides methods to create a new workflow {@link org.astrogrid.workflow.beans.v1.Tool} object that can be used to call the application this class describes
44   * <ul>
45   * <li>{@link #createToolFromDefaultInterface}
46   * <li>{@link #createToolFromInterface}
47   * </ul>
48   * 
49  * <p>
50  * ParameterValues can be added to a <tt>Tool</tt> by hand, with the assistance of these methods:
51  * <ul>
52  * <li>{@link c#reateValueFromDefinition}
53  * <li>{@link #getDefinitionForValue}
54  * <li>{@link #getReferenceForValue}
55  * <li>{@link #getDefinitionForReference}
56  * </ul>
57  * 
58  * <p>
59  * Finally, a Tool object can be checked that it conforms to the application description by calling the {@link #validate} method
60   * @author Noel Winstanley nw@jb.man.ac.uk 09-Mar-2004
61   * @modified Noel Winstanley - add method and constructor to access original DOM.
62   *
63   */
64  public class ApplicationDescription  {
65      /*** Construct a new ApplicationDescription
66       * 
67       */
68      public ApplicationDescription(ApplicationBase app) {
69          this(app,null);
70  
71      }
72      
73      /***
74       *  Construct a new ApplicationDescription
75       * @param app the application base object
76       * @param voDesc the defining registry entry - i.e. a vodescrption.
77       */
78      public ApplicationDescription(ApplicationBase app, Element voDesc) {
79          this.app = app;
80          this.paramMap = populateParamMap(app);
81          this.voDesc = voDesc;
82      }
83      
84      private final ApplicationBase app;
85      private final Map paramMap;
86      private final Element voDesc;
87      
88      private final Map populateParamMap(ApplicationBase app){
89          Map m = new HashMap();
90          Parameters params = app.getParameters();
91          for (int i = 0; i < params.getParameterCount(); i++) {
92              BaseParameterDefinition param = params.getParameter(i);
93              m.put(param.getName(),param);
94          }
95          return m;
96      }
97      
98      /***  interfaces contain a bunch of 'ParameterRef' objects, that reference 'BaseParameterDefinitions' that are defined elsewhere, and give the type, user interface
99       * description, etc of the paramter. This method will get a definition for a parameter reference
100      * @param parameterRef the reference to look up
101      * @return the associated parameter definition.
102      * @throws IllegalArgumentException when asked to find definition for a reference that is not in the application description.
103      */ 
104     public BaseParameterDefinition getDefinitionForReference(ParameterRef parameterRef) throws IllegalArgumentException {
105         BaseParameterDefinition result = (BaseParameterDefinition)paramMap.get(parameterRef.getRef());
106         if (result == null) {
107             throw new IllegalArgumentException("ParameterRef " + parameterRef.getRef() + " not found in this application description");
108         }
109         return result;
110     }
111     
112     /*** find the parameter reference assocuated with a parameter value in a particular interface*/
113     public ParameterRef getReferenceForValue(ParameterValue paramVal, Interface intf) throws IllegalArgumentException {
114         ParameterRef[] refs = intf.getInput().getPref();
115         String name = paramVal.getName();     
116         if (name == null || name.trim().length() == 0) {
117             throw new IllegalArgumentException("Empty name in this parameter value");
118         }
119         for (int i = 0; i < refs.length; i++) {
120             if (refs[i].getRef().equals(name)) {
121                 return refs[i];  
122             }          
123         }
124         // hmm, wasn't an input. try outputs..
125         refs = intf.getOutput().getPref();
126         for (int i = 0; i < refs.length; i++) {
127             if (refs[i].getRef().equals(name)) {
128                 return refs[i];
129             }            
130         }
131         // not found. we throw.
132         throw new IllegalArgumentException("ParameterValue " + paramVal.getName() + "not found in this interface");        
133     }
134     
135     /*** convenience method to get a parameter definition for a parameter value.
136      * <p>
137      * equivalent to <tt> getDefinitionForReference(getReferenceForValue(p,i))</tt>
138      * @param paramVal
139      * @param intf
140      * @return
141      * @throws IllegalArgumentException
142      */
143     public BaseParameterDefinition getDefinitionForValue(ParameterValue paramVal, Interface intf) throws IllegalArgumentException {
144         return getDefinitionForReference(getReferenceForValue(paramVal,intf));
145     }
146     
147     
148     /*** from a definition of a parameter, create a new, initialized parameter value.
149      * 
150      * @param defn definition of the parameter
151      * @return a parameter value with name, type initialized. if <tt>defn</tt> provides a defaultValue, this is set as <tt>content</tt>
152      * @todo check this still works.
153      */
154     public ParameterValue createValueFromDefinition(BaseParameterDefinition defn) {
155         ParameterValue paramVal = new ParameterValue();
156         paramVal.setName(defn.getName());
157         Object o= defn.getDefaultValue();
158         if (o != null) { // work around here.. - extension schema, so there's a hole, where an anynode appears. orsomething.
159             if (o instanceof AnyNode) {
160                 AnyNode any = (AnyNode)o;
161                 paramVal.setValue(any.getStringValue());
162             } else {
163                paramVal.setValue(o.toString());
164             }
165         } else {
166             paramVal.setValue(""); // necessary - as value field must be present for document to be schema-valid.
167         }
168         return paramVal;
169     }
170     
171     
172     /*** construct a new, initialized tool from the default (first) interface in the application descriptor */
173     public Tool createToolFromDefaultInterface() {
174         return createToolFromInterface(app.getInterfaces().get_interface(0));
175     }
176     
177     
178     /*** construct a new, initialized tool from an interface in this application descriptor
179      * @param intf the interface to create a tool instance from 
180      * @return a populated tool object
181      * @throws IllegalArgumentException if the interface does not belong to this application description.*/
182     public Tool createToolFromInterface(Interface intf) throws IllegalArgumentException {
183         Tool t = new Tool();
184         t.setInterface(intf.getName());
185         t.setName(app.getName());
186         Input input = new Input();
187         Output output = new Output();
188         t.setInput(input);
189         t.setOutput(output);        
190         // populate inputs - pity these can't be the same class.
191         ParameterRef[] parameterRefs = intf.getInput().getPref();
192         for (int i = 0; i < parameterRefs.length; i++) {
193             ParameterRef paramRef = parameterRefs[i];
194             BaseParameterDefinition paramDef = getDefinitionForReference(paramRef);
195             ParameterValue paramVal = createValueFromDefinition(paramDef);
196             input.addParameter(paramVal);
197         }
198         // do the same for outputs
199         parameterRefs = intf.getOutput().getPref();
200         for (int i = 0; i < parameterRefs.length; i++) {
201             ParameterRef paramRef = parameterRefs[i];
202             BaseParameterDefinition paramDef = getDefinitionForReference(paramRef);
203             ParameterValue paramVal = createValueFromDefinition(paramDef);
204             output.addParameter(paramVal);
205         }
206         
207         return t;
208     }
209     
210     /*** verify that a tool object matches what is expected by the application (as defined by this descriptor)
211      * <p>
212      * at moment, checks against information in the application description. in future, could access web services to resolve ucds, or check url parameters, etc. 
213      */
214     public void validate(Tool t) throws ToolValidationException{
215         // check tool structure 
216         try {
217             t.validate();
218         } catch (ValidationException e) {
219             throw new ToolValidationException(e);
220         }
221         // so now we know that all required fields are there, etc. 
222         Interface[] intfs = getInterfaces().get_interface();
223         Interface intf = null;
224         for (int i = 0; i < intfs.length; i++) {
225             if (intfs[i].getName().equals(t.getInterface())) {
226                 intf = intfs[i];
227             }            
228         }
229         if (intf == null) {
230             throw new ToolValidationException("Interface " + t.getInterface() + " not found"); 
231         }
232         // now need to check each parameter, against its interface, and the definition itself.
233         ParameterRef[] refs = intf.getInput().getPref();
234         BaseBean searchRoot = t.getInput();
235         for (int i =0; i < refs.length; i++) {
236             validateReference(refs[i],searchRoot);
237         }
238         // now the outputs
239         refs = intf.getOutput().getPref();
240         searchRoot = t.getOutput();
241         for (int i =0; i < refs.length; i++) {
242             validateReference(refs[i],searchRoot);
243         }                      
244     }
245     
246     private void validateReference(ParameterRef reference,BaseBean searchRoot) throws ToolValidationException {
247         Iterator results = searchRoot.findXPathIterator("/parameter[name = '" + reference.getRef() + "']");
248         try {
249             BaseParameterDefinition paramDef = getDefinitionForReference(reference);
250             int occurenceCount = 0;
251             while( results.hasNext()) {
252                 occurenceCount ++;
253                 ParameterValue val = (ParameterValue)results.next();
254                 
255             }
256            
257             
258             if (occurenceCount < reference.getMinoccurs() || 
259                     (reference.getMaxoccurs() != 0 ?occurenceCount > reference.getMaxoccurs():false)) {
260                 throw new ToolValidationException("Parameter " + reference.getRef() + " occurs " + occurenceCount 
261                     + ". Should occur between " + reference.getMinoccurs() + " and " + reference.getMaxoccurs() + " times");
262             }
263          
264         } catch (IllegalArgumentException e) {
265             throw new ToolValidationException(e);
266         }        
267     }
268     
269  
270     /***
271      * @see org.astrogrid.applications.beans.v1.ApplicationBase#getInterfaces()
272      */
273     public InterfacesType getInterfaces() {
274         return app.getInterfaces();
275     }
276 
277     /***
278      * @see org.astrogrid.applications.beans.v1.ApplicationBase#getName()
279      */
280     public String getName() {
281         return app.getName();
282     }
283 
284     /***
285      * @see org.astrogrid.applications.beans.v1.ApplicationBase#getParameters()
286      */
287     public Parameters getParameters() {
288         return app.getParameters();
289     }
290     
291     /*** access the xml of the original registry entry that defines this Application  
292      * @return dom of registry entry. may be null; if not, root element will be <tt>&lt;VODescription&gt;</tt>
293      * 
294      * @author Noel Winstanley nw@jb.man.ac.uk 28-Oct-2004
295      *
296      */
297     public Element getOriginalVODescription() {
298         return voDesc;
299     }
300 
301 }
302 
303 
304 /* 
305 $Log: ApplicationDescription.java,v $
306 Revision 1.7  2004/11/08 18:05:15  jdt
307 Merges from branch nww-bz#590
308 
309 Revision 1.6.20.1  2004/10/28 14:53:50  nw
310 added method getOriginalVODescription() to ApplicationDescription,
311 adjusted RegistryApplicationRegistry to populate this field.
312 
313 Revision 1.6  2004/09/10 18:28:53  pah
314 update the cardinality testing to deal with unlimited max properly
315 
316 Revision 1.5  2004/07/01 11:23:14  nw
317 removed 'setType' - as parameterValue nolonger has this atrribute.
318 part of cea componentization refactoring
319 
320 Revision 1.4  2004/03/17 00:31:51  nw
321 updated to always populate 'value' field of 'parameter' -
322 necessary to make the object model schema-valid
323 
324 Revision 1.3  2004/03/12 14:53:09  nw
325 bugfix for default parameters
326 
327 Revision 1.2  2004/03/11 13:53:36  nw
328 merged in branch bz#236 - implementation of interfaces
329 
330 Revision 1.1.2.2  2004/03/11 13:36:46  nw
331 tidied up interfaces, documented
332 
333 Revision 1.1.2.1  2004/03/09 17:42:50  nw
334 getting there..
335 
336 Revision 1.1  2004/03/09 15:31:21  nw
337 represents the initerface to an application
338  
339 */