KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > soap > skeleton > AbstractAction


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.soap.skeleton;
31
32 import com.caucho.jaxb.JAXBContextImpl;
33 import com.caucho.jaxb.skeleton.Property;
34
35 import com.caucho.soap.wsdl.SOAPOperation;
36 import com.caucho.soap.wsdl.WSDLBindingOperation;
37 import com.caucho.soap.wsdl.WSDLBindingOperationMessage;
38 import com.caucho.soap.wsdl.WSDLMessage;
39 import com.caucho.soap.wsdl.WSDLOperation;
40 import com.caucho.soap.wsdl.WSDLOperationFault;
41 import com.caucho.util.L10N;
42
43 import javax.jws.WebMethod;
44 import javax.jws.WebParam;
45 import javax.xml.bind.JAXBException;
46 import javax.xml.bind.Marshaller;
47 import javax.xml.bind.Unmarshaller;
48 import javax.xml.namespace.QName JavaDoc;
49 import javax.xml.stream.XMLInputFactory;
50 import javax.xml.stream.XMLOutputFactory;
51 import javax.xml.stream.XMLStreamException;
52 import javax.xml.stream.XMLStreamReader;
53 import javax.xml.stream.XMLStreamWriter;
54 import javax.xml.ws.Holder;
55 import javax.xml.ws.WebServiceException;
56 import java.io.IOException JavaDoc;
57 import java.io.InputStream JavaDoc;
58 import java.io.OutputStream JavaDoc;
59 import java.lang.reflect.Method JavaDoc;
60 import java.lang.reflect.ParameterizedType JavaDoc;
61 import java.lang.reflect.Type JavaDoc;
62 import java.net.HttpURLConnection JavaDoc;
63 import java.net.MalformedURLException JavaDoc;
64 import java.net.URL JavaDoc;
65 import java.net.URLConnection JavaDoc;
66 import java.util.ArrayList JavaDoc;
67 import java.util.LinkedHashMap JavaDoc;
68 import java.util.Map JavaDoc;
69 import java.util.logging.Logger JavaDoc;
70
71 /**
72  * Invokes a SOAP request on a Java POJO method
73  */

74 public abstract class AbstractAction {
75   private final static Logger JavaDoc log =
76     Logger.getLogger(AbstractAction.class.getName());
77   private static final L10N L = new L10N(AbstractAction.class);
78
79   private static final String JavaDoc TARGET_NAMESPACE_PREFIX = "tns";
80   protected static final String JavaDoc SOAP_ENCODING_STYLE
81     = "http://schemas.xmlsoap.org/soap/encoding/";
82
83   protected final XMLOutputFactory _xmlOutputFactory
84     = XMLOutputFactory.newInstance();
85   protected final XMLInputFactory _xmlInputFactory
86     = XMLInputFactory.newInstance();
87
88   protected final Method _method;
89   protected final int _arity;
90
91   protected String JavaDoc _responseName;
92   protected String JavaDoc _operationName;
93   protected QName JavaDoc _requestName;
94   protected QName JavaDoc _resultName;
95
96   // XXX: add array for efficiency
97
protected final LinkedHashMap JavaDoc<String JavaDoc,ParameterMarshal> _bodyArguments
98     = new LinkedHashMap JavaDoc<String JavaDoc,ParameterMarshal>();
99   protected ParameterMarshal[] _bodyArgs;
100
101   protected final LinkedHashMap JavaDoc<String JavaDoc,ParameterMarshal> _headerArguments
102     = new LinkedHashMap JavaDoc<String JavaDoc,ParameterMarshal>();
103
104   protected ParameterMarshal _retMarshal;
105
106   protected int _headerOutputs;
107   protected int _bodyOutputs;
108
109   protected final JAXBContextImpl _jaxbContext;
110   protected final String JavaDoc _targetNamespace;
111
112   //
113
// WSDL Constructs
114
//
115

116   protected final WSDLMessage _inputMessage = new WSDLMessage();
117   protected final WSDLMessage _outputMessage = new WSDLMessage();
118   protected final ArrayList JavaDoc<WSDLMessage> _faultMessages
119     = new ArrayList JavaDoc<WSDLMessage>();
120
121   protected final WSDLOperation _wsdlOperation = new WSDLOperation();
122   protected final ArrayList JavaDoc<WSDLOperationFault> _wsdlFaults
123     = new ArrayList JavaDoc<WSDLOperationFault>();
124
125   protected final WSDLBindingOperation _wsdlBindingOperation
126     = new WSDLBindingOperation();
127
128   protected AbstractAction(Method method, JAXBContextImpl jaxbContext,
129                            String JavaDoc targetNamespace)
130     throws JAXBException, WebServiceException
131   {
132     _method = method;
133     _arity = _method.getParameterTypes().length;
134     _jaxbContext = jaxbContext;
135     _targetNamespace = targetNamespace; // XXX introspect this from the method
136

137     // set the names for the input/output messages, portType/operation, and
138
// binding/operation.
139
_operationName = getWebMethodName(method);
140     _responseName = _operationName + "Response";
141
142       _inputMessage.setName(_operationName);
143     _outputMessage.setName(_responseName);
144
145     _wsdlOperation.setName(_operationName);
146     _wsdlBindingOperation.setName(_operationName);
147
148     // initialize the binding operation
149

150     _wsdlBindingOperation.setInput(new WSDLBindingOperationMessage());
151     _wsdlBindingOperation.setOutput(new WSDLBindingOperationMessage());
152
153     // SOAP action (URI where SOAP messages are sent)
154
SOAPOperation soapOperation = new SOAPOperation();
155     soapOperation.setSoapAction(""); // XXX
156
_wsdlBindingOperation.addAny(soapOperation);
157   }
158
159   public static AbstractAction createAction(Method method,
160                                             JAXBContextImpl jaxbContext,
161                                             String JavaDoc targetNamespace,
162                                             Marshaller marshaller,
163                                             Unmarshaller unmarshaller)
164     throws JAXBException, WebServiceException
165   {
166     // There are three valid modes in JAX-WS:
167
//
168
// 1. Document wrapped -- all the parameters and return values
169
// are encapsulated in a single encoded object (i.e. the document).
170
// This is selected by
171
// javax.jws.soap.SOAPBinding.style() == DOCUMENT
172
// javax.jws.soap.SOAPBinding.use() == LITERAL
173
// javax.jws.soap.SOAPBinding.parameterStyle() == WRAPPED
174
//
175
// 2. Document bare -- the method must have at most one input and
176
// one output parameter. No wrapper objects are created.
177
// This is selected by
178
// javax.jws.soap.SOAPBinding.style() == DOCUMENT
179
// javax.jws.soap.SOAPBinding.use() == LITERAL
180
// javax.jws.soap.SOAPBinding.parameterStyle() == BARE
181
//
182
// 3. RPC style -- parameters and return values are mapped to
183
// wsdl:parts. This is selected by:
184
// javax.jws.soap.SOAPBinding.style() == RPC
185
// javax.jws.soap.SOAPBinding.use() == LITERAL
186
// javax.jws.soap.SOAPBinding.parameterStyle() == WRAPPED
187
//
188
// It seems that "use" is never ENCODED in JAX-WS and is not allowed
189
// by WS-I, so we don't allow it either.
190
//
191

192     Class JavaDoc cl = method.getDeclaringClass();
193     javax.jws.soap.SOAPBinding soapBinding = null;
194
195     if (cl.isAnnotationPresent(javax.jws.soap.SOAPBinding.class)) {
196       soapBinding = (javax.jws.soap.SOAPBinding)
197                     cl.getAnnotation(javax.jws.soap.SOAPBinding.class);
198     }
199     
200     if (method.isAnnotationPresent(javax.jws.soap.SOAPBinding.class)) {
201       soapBinding = (javax.jws.soap.SOAPBinding)
202                     method.getAnnotation(javax.jws.soap.SOAPBinding.class);
203     }
204
205     // Document wrapped is the default for methods w/o a @SOAPBinding
206
if (soapBinding == null)
207       return new DocumentWrappedAction(method, jaxbContext, targetNamespace,
208                                        marshaller, unmarshaller);
209
210     if (soapBinding.use() == javax.jws.soap.SOAPBinding.Use.ENCODED)
211       throw new UnsupportedOperationException JavaDoc(L.l("SOAP encoded style is not supported by JAX-WS"));
212
213     if (soapBinding.style() == javax.jws.soap.SOAPBinding.Style.DOCUMENT) {
214       if (soapBinding.parameterStyle() ==
215           javax.jws.soap.SOAPBinding.ParameterStyle.WRAPPED)
216         return new DocumentWrappedAction(method, jaxbContext, targetNamespace,
217                                          marshaller, unmarshaller);
218       else {
219         return new DocumentBareAction(method, jaxbContext, targetNamespace,
220                                       marshaller, unmarshaller);
221       }
222     }
223     else {
224       if (soapBinding.parameterStyle() !=
225           javax.jws.soap.SOAPBinding.ParameterStyle.WRAPPED)
226         throw new UnsupportedOperationException JavaDoc(L.l("SOAP RPC bare style not supported"));
227
228       return new RpcAction(method, jaxbContext, targetNamespace,
229                            marshaller, unmarshaller);
230     }
231   }
232
233   /**
234    * Client-side invocation.
235    */

236   public Object JavaDoc invoke(String JavaDoc url, Object JavaDoc[] args)
237     throws IOException JavaDoc, XMLStreamException, MalformedURLException JavaDoc, JAXBException
238   {
239     URL JavaDoc urlObject = new URL JavaDoc(url);
240     URLConnection JavaDoc connection = urlObject.openConnection();
241
242     // XXX HTTPS
243
if (! (connection instanceof HttpURLConnection JavaDoc))
244       return null;
245
246     HttpURLConnection JavaDoc httpConnection = (HttpURLConnection JavaDoc) connection;
247
248     try {
249       //
250
// Send the request
251
//
252

253       httpConnection.setRequestMethod("POST");
254       httpConnection.setDoInput(true);
255       httpConnection.setDoOutput(true);
256
257       OutputStream JavaDoc httpOut = httpConnection.getOutputStream();
258       XMLStreamWriter out = _xmlOutputFactory.createXMLStreamWriter(httpOut);
259
260       writeRequest(out, args);
261       out.flush();
262
263       //
264
// Parse the response
265
//
266

267       if (httpConnection.getResponseCode() != 200)
268         return null; // XXX more meaningful error
269

270       InputStream JavaDoc httpIn = httpConnection.getInputStream();
271       XMLStreamReader in = _xmlInputFactory.createXMLStreamReader(httpIn);
272
273       Object JavaDoc ret = readResponse(in, args);
274
275       return ret;
276     }
277     finally {
278       if (httpConnection != null)
279         httpConnection.disconnect();
280     }
281   }
282
283   protected void writeRequest(XMLStreamWriter out, Object JavaDoc []args)
284     throws IOException JavaDoc, XMLStreamException, JAXBException
285   {
286     out.writeStartDocument();
287     out.writeStartElement(Skeleton.SOAP_ENVELOPE_PREFIX,
288                           "Envelope",
289                           Skeleton.SOAP_ENVELOPE);
290     out.writeNamespace(Skeleton.SOAP_ENVELOPE_PREFIX, Skeleton.SOAP_ENVELOPE);
291
292     out.writeStartElement(Skeleton.SOAP_ENVELOPE_PREFIX,
293                           "Header",
294                           Skeleton.SOAP_ENVELOPE);
295
296     for (ParameterMarshal marshal : _headerArguments.values())
297       marshal.serializeCall(out, args);
298
299     out.writeEndElement(); // Header
300

301     out.writeStartElement(Skeleton.SOAP_ENVELOPE_PREFIX,
302                           "Body",
303                           Skeleton.SOAP_ENVELOPE);
304
305     out.writeStartElement(TARGET_NAMESPACE_PREFIX,
306                           _operationName,
307                           _targetNamespace);
308     out.writeNamespace(TARGET_NAMESPACE_PREFIX,
309                        _targetNamespace);
310
311     for (int i = 0; i < _bodyArgs.length; i++)
312       _bodyArgs[i].serializeCall(out, args);
313
314     out.writeEndElement(); // name
315

316     out.writeEndElement(); // Body
317
out.writeEndElement(); // Envelope
318
}
319
320   protected Object JavaDoc readResponse(XMLStreamReader in, Object JavaDoc []args)
321     throws IOException JavaDoc, XMLStreamException, JAXBException
322   {
323     Object JavaDoc ret = null;
324
325     in.nextTag();
326
327     if (! "Envelope".equals(in.getName().getLocalPart()))
328       throw new IOException JavaDoc("expected Envelope at " + in.getName());
329
330     // Header
331
if (_headerOutputs > 0) {
332       in.nextTag();
333
334       if (! "Header".equals(in.getName().getLocalPart()))
335         throw new IOException JavaDoc("expected <Header>");
336
337       for (int i = 0; i < _headerOutputs; i++) {
338         String JavaDoc tagName = in.getLocalName();
339
340         ParameterMarshal marshal = _headerArguments.get(tagName);
341
342         if (marshal == null)
343           throw new IOException JavaDoc(L.l("Unknown output in header <{0}>", tagName));
344
345         Object JavaDoc value = marshal.deserializeReply(in);
346
347         if (marshal.getArg() < 0)
348           ret = value;
349         else
350           ((Holder) args[marshal.getArg()]).value = value;
351
352         if (i + 1 < _headerOutputs)
353           in.nextTag();
354       }
355
356       if (in.nextTag() != in.END_ELEMENT)
357         throw new IOException JavaDoc("expected </Header>");
358     }
359
360     // Body is manditory
361
in.nextTag();
362     if (! "Body".equals(in.getName().getLocalPart()))
363       throw new IOException JavaDoc("expected Body");
364
365     // Body
366
if (_bodyOutputs > 0) {
367       for (int i = 0; i < _headerOutputs; i++) {
368         String JavaDoc tagName = in.getLocalName();
369
370         ParameterMarshal marshal = _headerArguments.get(tagName);
371
372         if (marshal == null)
373           throw new IOException JavaDoc(L.l("Unknown output in header <{0}>", tagName));
374
375         Object JavaDoc value = marshal.deserializeReply(in);
376
377         if (marshal._arg < 0)
378           ret = value;
379         else
380           ((Holder) args[marshal.getArg()]).value = value;
381
382         if (i + 1 < _headerOutputs)
383           in.nextTag();
384       }
385     }
386
387     if (in.nextTag() != in.END_ELEMENT)
388       throw new IOException JavaDoc(L.l("expected </Body> at <{0}>",
389             in.getName().getLocalPart()));
390
391
392     if (in.nextTag() != in.END_ELEMENT)
393       throw new IOException JavaDoc(L.l("expected </Envelope> at {0}",
394             in.getName().getLocalPart()));
395
396     return ret;
397   }
398
399   /**
400    * Invokes the request for a call.
401    */

402   public void invoke(Object JavaDoc service, XMLStreamReader in, XMLStreamWriter out)
403     throws IOException JavaDoc, XMLStreamException, Throwable JavaDoc
404   {
405   }
406
407   /**
408    * returns the WSDLMessage for the input of this method.
409    */

410   public WSDLMessage getInputMessage()
411   {
412     return _inputMessage;
413   }
414
415   /**
416    * returns the WSDLMessage for the output of this method.
417    */

418   public WSDLMessage getOutputMessage()
419   {
420     return _outputMessage;
421   }
422
423   public WSDLOperation getOperation()
424   {
425     return _wsdlOperation;
426   }
427
428   public WSDLBindingOperation getBindingOperation()
429   {
430     return _wsdlBindingOperation;
431   }
432
433   public boolean hasHeaderInput()
434   {
435     return false;
436   }
437
438   public int getArity()
439   {
440     return _arity;
441   }
442
443   protected static Class JavaDoc getHolderValueType(Type JavaDoc holder)
444   {
445     // XXX Generics and arrays
446
Type JavaDoc holderParams[] = ((ParameterizedType JavaDoc) holder).getActualTypeArguments();
447     return (Class JavaDoc) holderParams[0];
448   }
449
450   public static String JavaDoc getWebMethodName(Method method)
451   {
452     String JavaDoc name = method.getName();
453
454     WebMethod webMethod = (WebMethod) method.getAnnotation(WebMethod.class);
455
456     if (webMethod != null && ! "".equals(webMethod.operationName()))
457       name = webMethod.operationName();
458     
459     return name;
460   }
461 }
462
Popular Tags