1
2
3
4
5
6
7
8
9 package bexee.axis;
10
11 import java.util.HashMap;
12 import java.util.Iterator;
13 import java.util.Map;
14 import java.util.Vector;
15
16 import javax.wsdl.Definition;
17 import javax.wsdl.WSDLException;
18 import javax.wsdl.factory.WSDLFactory;
19 import javax.wsdl.xml.WSDLWriter;
20 import javax.xml.namespace.QName;
21 import javax.xml.soap.SOAPException;
22
23 import org.apache.axis.AxisFault;
24 import org.apache.axis.Message;
25 import org.apache.axis.MessageContext;
26 import org.apache.axis.description.OperationDesc;
27 import org.apache.axis.description.ServiceDesc;
28 import org.apache.axis.handlers.soap.SOAPService;
29 import org.apache.axis.message.RPCElement;
30 import org.apache.axis.message.RPCParam;
31 import org.apache.axis.message.SOAPEnvelope;
32 import org.apache.axis.providers.BasicProvider;
33 import org.w3c.dom.Document;
34 import org.w3c.dom.Element;
35 import org.xml.sax.SAXException;
36
37 import bexee.core.BexeeMessage;
38 import bexee.core.Dispatcher;
39 import bexee.core.DispatcherException;
40 import bexee.dao.BPELProcessDAO;
41 import bexee.dao.DAOException;
42 import bexee.dao.DAOFactory;
43 import bexee.model.process.BPELProcess;
44 import bexee.wsdl.WSDLBindingFactory;
45 import bexee.wsdl.extensions.partnerlinktype.PartnerLinkTypeExtensionRegistry;
46
47 /***
48 * This is the Axis provider (also commonly called pivot handler) used by all
49 * deployed BPEL process web services.
50 * <p>
51 * This provider takes the incoming SOAP message, performs a number of checks
52 * (e.g. verifying whether the requested operation can actually be performed by
53 * our <code>ProcessController</code>), puts all the necessary information
54 * into a new <code>BexeeMessage</code> and dispatches it to
55 * <code>Dispatcher</code>.
56 * <p>
57 * As soon as the provider receives the result back from the dispatcher, it will
58 * create a new SOAP response and hand it back to the Axis response flow, from
59 * where it will eventually be sent back to the client that invoked the service.
60 *
61 * @version $Revision: 1.1 $, $Date: 2004/12/15 14:18:15 $
62 * @author Patric Fornasier
63 * @author Pawel Kowalski
64 */
65 public class BexeeProvider extends BasicProvider {
66
67 /***
68 * The default URL for services
69 */
70 private static final String DEFAULT_SERVICES_URL = "http://localhost/bexee/services/";
71
72 public void initServiceDesc(SOAPService service, MessageContext msgContext)
73 throws AxisFault {
74
75 }
76
77 /***
78 * Creates a <code>BexeeMessage</code> from an incoming SOAP message and
79 * passes it to the {@link Dispatcher}from where it will be dispatched to
80 * the {@link bexee.core.ProcessController}.
81 * <p>
82 * Once the processing is completed, the result from the {@link Dispatcher}
83 * is taken and put back into a SOAP message and passed back into the Axis
84 * response flow.
85 * <p>
86 * Right now and Object of type {@link Element}is passed back into the
87 * response flow, because we don't generate Java objects from complex XML
88 * types.
89 * <p>
90 * TODO: This class needs some work, especially the message type stuff
91 * (possible improvements: code generation from wsdl, serializing and
92 * deserializing into Java objects)
93 */
94 public void invoke(MessageContext ctx) throws AxisFault {
95
96 RPCElement body = null;
97 String operation = null;
98
99
100 String service = ctx.getTargetService();
101 SOAPEnvelope reqEnv = ctx.getRequestMessage().getSOAPEnvelope();
102 ServiceDesc serviceDesc = ctx.getService().getServiceDescription();
103 OperationDesc operationDesc = ctx.getOperation();
104
105
106 Vector bodies = reqEnv.getBodyElements();
107 for (int i = 0; body == null && i < bodies.size(); i++) {
108 if (bodies.get(i) instanceof RPCElement) {
109 body = (RPCElement) bodies.get(i);
110 }
111 }
112
113
114 if (body == null) {
115 throw new AxisFault("No RPCElement found in SOAP message");
116 }
117
118
119 if (operationDesc == null) {
120 QName qname = new QName(body.getNamespaceURI(), body.getName());
121 operationDesc = serviceDesc.getOperationByElementQName(qname);
122 }
123
124
125 if (operationDesc == null) {
126 throw new AxisFault("No such operation");
127 }
128
129
130 Vector params = null;
131 try {
132 params = body.getParams();
133 } catch (SAXException e) {
134 throw new AxisFault("Possible cause: too many parameters", e);
135 }
136
137
138 if (operationDesc.getNumParams() > params.size()) {
139 throw new AxisFault("Wrong number of parameters passed in");
140 }
141
142
143
144
145 operation = body.getMethodName();
146
147
148 BexeeMessage message = createBexeeMessage(service, operation, params);
149 Object result;
150 try {
151 result = dispatch(message);
152 } catch (DispatcherException e) {
153 throw new AxisFault("Unable to dispatch message", e);
154 }
155
156 RPCElement resBody = new RPCElement(operation + "Response");
157 resBody.setPrefix(body.getPrefix());
158 resBody.setNamespaceURI(body.getNamespaceURI());
159 try {
160 resBody.setEncodingStyle(ctx.getEncodingStyle());
161 } catch (SOAPException e) {
162 throw AxisFault.makeFault(e);
163 }
164
165
166 RPCParam param = new RPCParam(operationDesc.getReturnQName(), result);
167 resBody.addParam(param);
168
169
170 SOAPEnvelope resEnv = new SOAPEnvelope();
171 resEnv.setSoapConstants(ctx.getSOAPConstants());
172 resEnv.setSchemaVersion(ctx.getSchemaVersion());
173
174
175 resEnv.addBodyElement(resBody);
176
177
178 ctx.setResponseMessage(new Message(resEnv));
179 }
180
181 /***
182 * Gets WSDL associated with requested BPEL process from DAO and adds
183 * binding information on the fly.
184 * <p>
185 * If the target service endpoint URL can not be determined, a constant
186 * value with the default services root is assumed.
187 */
188 public void generateWSDL(MessageContext ctx) throws AxisFault {
189
190
191 Document doc = null;
192
193
194 String url = getLocationURL(ctx);
195
196
197 BPELProcessDAO dao = DAOFactory.getInstance().createBPELProcessDAO();
198 BPELProcess process;
199 String name = getServiceName(ctx);
200 try {
201 process = dao.find(name);
202 } catch (DAOException e) {
203 throw new AxisFault("Error trying to find process", e);
204 }
205
206 if (process == null) {
207 throw new AxisFault("No process " + name + " found");
208 }
209
210 Definition wsdlAbstract = process.getWSDL();
211
212 try {
213
214 WSDLBindingFactory bindingFactory = new WSDLBindingFactory();
215 Definition wsdl = bindingFactory.addBinding(wsdlAbstract, url);
216
217
218 WSDLWriter writer = WSDLFactory.newInstance().newWSDLWriter();
219 wsdl.setExtensionRegistry(new PartnerLinkTypeExtensionRegistry());
220 doc = writer.getDocument(wsdl);
221 } catch (WSDLException e) {
222 throw AxisFault.makeFault(e);
223 }
224
225
226 ctx.setProperty("WSDL", doc);
227 }
228
229 /***
230 * Gets the service location URL.
231 *
232 * @return a <code>String</code>
233 */
234 protected String getLocationURL(MessageContext ctx) {
235
236 String url = ctx.getStrProp(MessageContext.WSDLGEN_SERV_LOC_URL);
237
238
239 if (url == null) {
240 url = ctx.getService().getServiceDescription().getEndpointURL();
241 }
242
243
244 if (url == null) {
245 url = ctx.getStrProp(MessageContext.TRANS_URL);
246 }
247
248
249 if (url == null) {
250 url = DEFAULT_SERVICES_URL + getServiceName(ctx);
251 }
252
253 return url;
254 }
255
256 protected String getServiceName(MessageContext ctx) {
257 String name = ctx.getService().getServiceDescription().getName();
258 return name;
259 }
260
261 /***
262 * Helper method to create the <code>BexeeMessage</code>
263 */
264 protected BexeeMessage createBexeeMessage(String service, String operation,
265 Vector params) throws AxisFault {
266
267 BexeeMessage message = new BexeeMessage();
268
269
270 Map parts = new HashMap();
271 for (Iterator iter = params.iterator(); iter.hasNext();) {
272 RPCParam rpcParam = (RPCParam) iter.next();
273
274
275 Object value = rpcParam.getObjectValue();
276
277
278
279 String name = rpcParam.getParamDesc().getName();
280
281
282 parts.put(name, value);
283 }
284
285
286 message.setService(service);
287 message.setOperation(operation);
288 message.setParts(parts);
289
290 return message;
291 }
292
293 /***
294 * Call dispatcher to kick off the process controller and return result
295 *
296 * @return the result from the {@link Dispatcher}
297 */
298 protected Object dispatch(BexeeMessage message) throws DispatcherException {
299
300 Dispatcher dispatcher = new Dispatcher(message);
301 return dispatcher.dispatch();
302 }
303
304 }