Source code: org/embl/ebi/escience/scufl/SoaplabProcessor.java
1 /**
2 * This file is a component of the Taverna project,
3 * and is licensed under the GNU LGPL.
4 * Copyright Tom Oinn, EMBL-EBI
5 */
6 package org.embl.ebi.escience.scufl;
7
8 import javax.xml.namespace.QName;
9 import org.apache.axis.client.Call;
10 import org.apache.axis.client.Service;
11
12 // Utility Imports
13 import java.util.ArrayList;
14 import java.util.Map;
15
16 // Network Imports
17 import java.net.MalformedURLException;
18 import java.net.URL;
19
20 import org.embl.ebi.escience.scufl.DuplicatePortNameException;
21 import org.embl.ebi.escience.scufl.DuplicateProcessorNameException;
22 import org.embl.ebi.escience.scufl.InputPort;
23 import org.embl.ebi.escience.scufl.OutputPort;
24 import org.embl.ebi.escience.scufl.Port;
25 import org.embl.ebi.escience.scufl.PortCreationException;
26 import org.embl.ebi.escience.scufl.Processor;
27 import org.embl.ebi.escience.scufl.ProcessorCreationException;
28 import org.embl.ebi.escience.scufl.ScuflModel;
29 import org.embl.ebi.escience.scufl.ScuflModelEvent;
30 import java.lang.NullPointerException;
31 import java.lang.Object;
32 import java.lang.String;
33
34
35
36 /**
37 * A processor based on the Soaplab web service
38 * around the EMBOSS tools. This processor
39 * implementation will contact Soaplab in order
40 * to find the list of extant ports at creation
41 * time. It is therefore important when creating
42 * an instance of this class that the creating
43 * thread should be able to make an HTTP connection
44 * to the supplied endpoint.
45 * @author Tom Oinn
46 */
47 public class SoaplabProcessor extends Processor implements java.io.Serializable {
48
49 private URL endpoint = null;
50
51 /**
52 * Construct a new processor with the given model and
53 * name, delegates to the superclass.
54 */
55 public SoaplabProcessor(ScuflModel model, String name, String endpoint)
56 throws ProcessorCreationException,
57 DuplicateProcessorNameException {
58 super(model, name);
59 // Set the endpoint, this then populates the ports appropriately
60 // from the returned parameters of the soap call.
61 try {
62 setEndpoint(endpoint);
63 }
64 catch (MalformedURLException mue) {
65 throw new ProcessorCreationException("The supplied endpoint url was malformed, endpoint was specified as '"+endpoint+"'");
66 }
67 }
68
69 /**
70 * Set the endpoint for this soaplab processor
71 */
72 void setEndpoint(String specifier)
73 throws MalformedURLException,
74 ProcessorCreationException {
75 URL new_endpoint = new URL(specifier);
76 if (this.endpoint!=null) {
77 if (this.endpoint.equals(new_endpoint)==false) {
78 fireModelEvent(new ScuflModelEvent(this, "Service endpoint changed to '"+specifier+"'"));
79 }
80 else {
81 // Do nothing if the endpoint was the same as before
82 return;
83 }
84 }
85 else {
86 fireModelEvent(new ScuflModelEvent(this, "Service endpoint set to '"+specifier+"'"));
87 }
88 this.endpoint = new_endpoint;
89 try {
90 generatePorts();
91 getDescriptionText();
92 }
93 catch (PortCreationException pce) {
94 throw new ProcessorCreationException("Exception when trying to create ports from Soaplab endpoint : "+pce.getMessage());
95 }
96 catch (DuplicatePortNameException dpne) {
97 throw new ProcessorCreationException("Exception when trying to create ports from Soaplab endpoint : "+dpne.getMessage());
98 }
99 }
100
101 /**
102 * Use the endpoint data to set the description field
103 */
104 public void getDescriptionText()
105 throws ProcessorCreationException {
106 try {
107 Call call = (Call)new Service().createCall();
108 call.setTargetEndpointAddress(this.endpoint.toString());
109 call.setOperationName(new QName("getAnalysisType"));
110 Map info = (Map)call.invoke(new Object[0]);
111 // Get the description element from the map
112 String description = (String)info.get("description");
113 if (description != null) {
114 setDescription(description);
115 }
116 }
117 catch (javax.xml.rpc.ServiceException se) {
118 throw new ProcessorCreationException("Unable to create a new call to connect to soaplab, error was : "+se.getMessage());
119 }
120 catch (java.rmi.RemoteException re) {
121 throw new ProcessorCreationException("Unable to call the get description method : "+re.getMessage());
122 }
123 }
124
125 /**
126 * Use the endpoint data to create new ports and attach them to
127 * the processor. Interogates Soaplab for names of input and
128 * output parameters, and additionally for their syntactic types,
129 * as we might as well keep that information while we have it.
130 */
131 public void generatePorts()
132 throws ProcessorCreationException,
133 PortCreationException,
134 DuplicatePortNameException {
135 // Wipe the existing port declarations
136 ports = new ArrayList();
137 try {
138
139 // Do web service type stuff[tm]
140 Call call = (Call)new Service().createCall();
141 call.setTargetEndpointAddress(this.endpoint.toString());
142
143 // Get inputs
144 call.setOperationName(new QName("getInputSpec"));
145 Map inputs[] = (Map[])call.invoke(new Object[0]);
146 // Iterate over the inputs
147 for (int i = 0; i<inputs.length; i++) {
148 Map input_spec = inputs[i];
149 String input_name = (String)input_spec.get("name");
150 String input_type = ((String)(input_spec.get("type"))).toLowerCase();
151 // Could get other properties such as defaults here
152 // but at the moment we've got nowhere to put them
153 // so we don't bother.
154 Port new_port = new InputPort(this, input_name);
155 new_port.setSyntacticType(input_type);
156 this.addPort(new_port);
157 }
158
159 // Get outputs
160 call = (Call)new Service().createCall();
161 call.setTargetEndpointAddress(this.endpoint.toString());
162 call.setOperationName(new QName("getResultSpec"));
163 Map[] results = (Map[])call.invoke(new Object[0]);
164 // Iterate over the outputs
165 for (int i = 0; i<results.length; i++) {
166 Map output_spec = results[i];
167 String output_name = (String)output_spec.get("name");
168 String output_type = ((String)(output_spec.get("type"))).toLowerCase();
169 // Check to see whether the output is either report or detailed_status, in
170 // which cases we ignore it, this is soaplab metadata rather than application
171 // data.
172 if ((!output_name.equalsIgnoreCase("detailed_status"))
173 && (!output_name.equalsIgnoreCase("report"))) {
174 Port new_port = new OutputPort(this, output_name);
175 new_port.setSyntacticType(output_type);
176 this.addPort(new_port);
177 }
178 }
179
180 }
181 catch (javax.xml.rpc.ServiceException se) {
182 throw new ProcessorCreationException("Unable to create a new call to connect to soaplab, error was : "+se.getMessage());
183 }
184 catch (java.rmi.RemoteException re) {
185 throw new ProcessorCreationException("Unable to call the get spec method : "+re.getMessage());
186 }
187 catch (NullPointerException npe) {
188 // If we had a null pointer exception, go around again - this is a bug somewhere between axis and soaplab
189 // that occasionally causes NPEs to happen in the first call or two to a given soaplab installation. It also
190 // manifests in the Talisman soaplab clients.
191 generatePorts();
192 }
193 }
194
195 /**
196 * Get the URL for this endpoint
197 */
198 public URL getEndpoint() {
199 return this.endpoint;
200 }
201
202
203 }