001: /*
002: * The Apache Software License, Version 1.1
003: *
004: *
005: * Copyright (c) 2002 The Apache Software Foundation. All rights
006: * reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Apache Software Foundation (http://www.apache.org/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The names "WSIF" and "Apache Software Foundation" must
028: * not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact apache@apache.org.
031: *
032: * 5. Products derived from this software may not be called "Apache",
033: * nor may "Apache" appear in their name, without prior written
034: * permission of the Apache Software Foundation.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: * ====================================================================
049: *
050: * This software consists of voluntary contributions made by many
051: * individuals on behalf of the Apache Software Foundation and was
052: * originally based on software copyright (c) 2001, 2002, International
053: * Business Machines, Inc., http://www.apache.org. For more
054: * information on the Apache Software Foundation, please see
055: * <http://www.apache.org/>.
056: */
057:
058: package org.apache.wsif.providers.soap.soaprmi;
059:
060: import java.io.BufferedWriter;
061: import java.io.IOException;
062: import java.io.Reader;
063: import java.io.StringWriter;
064: import java.io.Writer;
065: import java.net.URL;
066: import java.util.HashMap;
067: import java.util.Iterator;
068: import java.util.List;
069: import java.util.Map;
070: import java.util.Vector;
071:
072: import javax.wsdl.Definition;
073: import javax.wsdl.Input;
074: import javax.wsdl.Operation;
075: import javax.wsdl.Output;
076: import javax.wsdl.Part;
077: import javax.xml.namespace.QName;
078:
079: import org.apache.wsif.WSIFException;
080: import org.apache.wsif.WSIFMessage;
081: import org.apache.wsif.WSIFOperation;
082: import org.apache.wsif.WSIFPort;
083: import org.apache.wsif.base.WSIFDefaultOperation;
084: import org.apache.wsif.logging.Trc;
085: import org.apache.wsif.providers.WSIFDynamicTypeMap;
086: import org.apache.wsif.providers.WSIFDynamicTypeMapping;
087: import soaprmi.mapping.XmlJavaMapping;
088: import soaprmi.mapping.XmlJavaTypeMap;
089: import soaprmi.mapping.XmlMapException;
090: import soaprmi.soap.Soap;
091: import soaprmi.soaprpc.MethodInvoker;
092: import soaprmi.util.HTTPUtils;
093:
094: /**
095: * Provide concrete implementation of WSDL operation with SoapRMI
096: * RPC method invocation.
097: *
098: * @author Alekander Slominski
099: */
100: public class WSIFOperation_SoapRMI extends WSIFDefaultOperation
101: implements WSIFOperation {
102:
103: private static final long serialVersionUID = 1L;
104:
105: protected WSIFPort_SoapRMI portInstance;
106: protected Operation operation;
107: protected Definition definition;
108:
109: // cached information to allow efficinet operation calls
110: protected List partNames;
111: protected String[] names;
112: protected Class[] types;
113: protected String inputEncodingStyle = Soap.SOAP_ENC_NS;
114: protected String inputNamespace;
115:
116: protected String returnName;
117: protected Class returnType;
118: protected String outputEncodingStyle = Soap.SOAP_ENC_NS;
119: protected String actionUri;
120: protected WSIFDynamicTypeMap typeMap;
121: protected XmlJavaMapping soaprmiMapping;
122:
123: /**
124: * Create Apache SOAP operation instance that encapsultes all necessary
125: * information required to create and execute Apache SOAP Call.
126: */
127: public WSIFOperation_SoapRMI(WSIFPort_SoapRMI pi, Operation op,
128: WSIFDynamicTypeMap typeMap) throws WSIFException {
129: this .typeMap = typeMap;
130: setDynamicWSIFPort(pi);
131: setOperation(op);
132: setDefintion(pi.getDefinition());
133: prepare();
134: }
135:
136: /**
137: * Create a new copy of this object. This is not a clone, since
138: * it does not copy the referenced objects as well.
139: */
140: public WSIFOperation_SoapRMI copy() throws WSIFException {
141:
142: WSIFOperation_SoapRMI op = new WSIFOperation_SoapRMI(
143: portInstance, operation, typeMap);
144:
145: op.setSoapActionURI(getSoapActionURI());
146: op.setInputNamespace(getInputNamespace());
147: op.setInputEncodingStyle(getInputEncodingStyle());
148: op.setOutputEncodingStyle(getOutputEncodingStyle());
149: op.setPartNames(getPartNames());
150: op.setReturnName(getReturnName());
151:
152: return op;
153: }
154:
155: /**
156: * This is utility method that when called initializes operation
157: * (including reconstruction of method signature).
158: */
159: private void prepare() throws WSIFException {
160: soaprmiMapping = new XmlJavaMapping();
161: try {
162: XmlJavaMapping defaultMapping = soaprmi.soap.Soap
163: .getDefault().getMapping();
164: soaprmiMapping.connectTo(defaultMapping);
165: // disable SoapRMI auto mapping
166: soaprmiMapping.setDefaultStructNsPrefix(null);
167:
168: for (Iterator i = typeMap.iterator(); i.hasNext();) {
169: WSIFDynamicTypeMapping mapping = (WSIFDynamicTypeMapping) i
170: .next();
171:
172: // map SOAPStruct into namespace:http://soapinterop.org/ : SOAPStruct
173: soaprmiMapping.mapStruct(
174: "http://schemas.xmlsoap.org/soap/encoding/",
175: mapping.getXmlType().getNamespaceURI(), mapping
176: .getXmlType().getLocalPart(), mapping
177: .getJavaType());
178:
179: }
180: } catch (XmlMapException ex) {
181: throw new WSIFException("Could not initialize mapping.", ex);
182: }
183:
184: // first determine list of arguments
185: Input input = operation.getInput();
186: if (input != null) {
187: List parts;
188: if (partNames != null) {
189: parts = new Vector();
190: for (Iterator i = partNames.iterator(); i.hasNext();) {
191: String partName = (String) i.next();
192: Part part = input.getMessage().getPart(partName);
193: if (part == null) {
194: throw new WSIFException("no input part named "
195: + partName + " for bining operation "
196: + getName());
197: }
198: parts.add(part);
199: }
200: } else {
201: parts = input.getMessage().getOrderedParts(null);
202: }
203: int count = parts.size();
204: names = new String[count];
205: types = new Class[count];
206:
207: // get parts in correct order
208: for (int i = 0; i < count; ++i) {
209: Part part = (Part) parts.get(i);
210: names[i] = part.getName();
211: QName partType = part.getTypeName();
212: if (partType == null) {
213: throw new WSIFException("part " + names[i]
214: + " must have type name declared");
215: }
216: try {
217: XmlJavaTypeMap typeMap = soaprmiMapping
218: .queryTypeMap(inputEncodingStyle, partType
219: .getNamespaceURI(), partType
220: .getLocalPart());
221: types[i] = typeMap.javaClass();
222: } catch (XmlMapException ex) {
223: throw new WSIFException(
224: "Could not determine local java type for "
225: + partType.getNamespaceURI() + ":"
226: + partType.getLocalPart(), ex);
227: }
228:
229: }
230: } else {
231: names = new String[0];
232: types = new Class[0];
233: }
234:
235: // now prepare return value
236: Output output = operation.getOutput();
237: if (output != null) {
238: Part returnPart = null;
239: if (returnName != null) {
240: returnPart = output.getMessage().getPart(returnName);
241: if (returnPart == null) {
242: throw new WSIFException("no output part named "
243: + returnName + " for bining operation "
244: + getName());
245: }
246: } else {
247: List parts = output.getMessage().getOrderedParts(null);
248: if (parts.size() > 0) {
249: returnPart = (Part) parts.get(0);
250: returnName = returnPart.getName();
251: }
252: }
253: if (returnPart != null) {
254: QName partType = returnPart.getTypeName();
255: try {
256: XmlJavaTypeMap typeMap = soaprmiMapping
257: .queryTypeMap(outputEncodingStyle, partType
258: .getNamespaceURI(), partType
259: .getLocalPart());
260: returnType = typeMap.javaClass();
261: } catch (XmlMapException ex) {
262: throw new WSIFException(
263: "Could not determine local java type for "
264: + partType.getNamespaceURI() + ":"
265: + partType.getLocalPart(), ex);
266: }
267: } else {
268: returnType = Void.TYPE;
269: }
270: }
271:
272: }
273:
274: public boolean executeRequestResponseOperation(WSIFMessage input,
275: WSIFMessage output, WSIFMessage fault) throws WSIFException {
276: return invokeRequestResponseOperation(input, output, fault);
277: }
278:
279: public void executeInputOnlyOperation(WSIFMessage input)
280: throws WSIFException {
281: invokeInputOnlyOperation(input);
282: }
283:
284: /**
285: * Invoke RPC operation using ApacheSOAP
286: */
287: public boolean invokeRequestResponseOperation(WSIFMessage input,
288: WSIFMessage output, WSIFMessage fault) throws WSIFException {
289: if (names == null)
290: prepare();
291:
292: try {
293:
294: // prepare parameters
295:
296: Object[] params = new Object[types.length];
297:
298: Object partInst;
299: for (int i = 0; i < names.length; ++i) {
300: partInst = input.getObjectPart(names[i]);
301: if (partInst == null) {
302: boolean foundInputParameter = false;
303: String paramName = names[i];
304: Iterator partsIterator = input.getPartNames();
305: while (partsIterator.hasNext()) {
306: String partName = (String) partsIterator.next();
307: if (partName == null || paramName == null)
308: break;
309: if (partName.equals(paramName)) {
310: foundInputParameter = true;
311: }
312: }
313: if (!foundInputParameter)
314: throw new WSIFException(
315: "expected input message to have part with name '"
316: + names[i] + "'");
317: }
318: Object value = partInst;
319: // some runtime param validity check
320: if (value != null
321: && !types[i].isPrimitive()
322: && !(types[i]
323: .isAssignableFrom(value.getClass()))) {
324: throw new WSIFException("value " + value
325: + " has unexpected type "
326: + value.getClass() + " instead of "
327: + types[i]);
328: }
329: params[i] = value;
330: }
331:
332: MethodInvoker mi = null; //newCall(m);
333: // prepare this method invoker
334: // try {
335: mi = MethodInvoker.makeMethodInvoker(getInputNamespace(),
336: returnType, getName(), types, names,
337: getSoapActionURI(), soaprmiMapping);
338: // } catch(soaprmi.RemoteException ex) {
339: // throw new WSIFException(
340: // "Could not prepare method invoker for operation "+getName(), ex);
341: // }
342:
343: Map requestHeaders = new HashMap();
344:
345: requestHeaders.put("SOAPAction", getSoapActionURI());
346:
347: StringWriter sw = new StringWriter();
348: Writer writer = new BufferedWriter(sw);
349:
350: String locationUri = portInstance.getLocation();
351:
352: if (Trc.ON)
353: Trc.event(this , "invoking SoapRMI operation "
354: + getName() + " on " + locationUri);
355:
356: mi.sendRequest(params, writer);
357:
358: String requestContent = sw.toString();
359:
360: String httpProxyHost = null;
361: int httpProxyPort = -1;
362:
363: URL url = new URL(locationUri);
364:
365: Reader reader = HTTPUtils.post(url, requestContent,
366: requestHeaders, "text/xml; charset=utf-8",
367: //NOTE putting "" around utf-8 is crashing Tomcat 3.2.1
368: 60 * 1000, //timeout,
369: httpProxyHost, httpProxyPort);
370:
371: Object result = mi.receiveResponse(reader);
372:
373: if (returnType != null) {
374: if (result != null
375: && !returnType.isPrimitive()
376: && !(returnType.isAssignableFrom(result
377: .getClass()))) {
378: throw new WSIFException("return value " + result
379: + " has unexpected type "
380: + result.getClass() + " instead of "
381: + returnType);
382: }
383: output.setObjectPart(returnName, result);
384: }
385:
386: // TOOD keep pool of method invokers - good for performance
387: //returnCallToPool(mi);
388:
389: } catch (IOException ex) {
390: //ex.printStackTrace();
391: throw new WSIFException("IO Exception", ex);
392: } catch (soaprmi.RemoteException ex) {
393: ex.printStackTrace();
394: throw new WSIFException("SoapRMI exception", ex);
395: } catch (soaprmi.soap.SoapException ex) {
396: throw new WSIFException("SOAP exception", ex);
397: } catch (xpp.XmlPullParserException ex) {
398: throw new WSIFException("SOAP exception", ex);
399: }
400:
401: return true;
402: }
403:
404: /**
405: * Invoke only operation are not yet supported.
406: */
407: public void invokeInputOnlyOperation(WSIFMessage input)
408: throws WSIFException {
409: throw new WSIFException("not implemented");
410: }
411:
412: /**
413: * Return name of operation.
414: */
415: public String getName() {
416: return operation.getName();
417: }
418:
419: public String getSoapActionURI() {
420: return actionUri;
421: }
422:
423: public void setSoapActionURI(String value) {
424: actionUri = value;
425: }
426:
427: public String getInputNamespace() {
428: return inputNamespace;
429: }
430:
431: public void setInputNamespace(String value) {
432: inputNamespace = value;
433: }
434:
435: public String getInputEncodingStyle() {
436: return inputEncodingStyle;
437: }
438:
439: public void setInputEncodingStyle(String value) {
440: inputEncodingStyle = value;
441: }
442:
443: public String getOutputEncodingStyle() {
444: return outputEncodingStyle;
445: }
446:
447: public void setOutputEncodingStyle(String value) {
448: outputEncodingStyle = value;
449: }
450:
451: public List getPartNames() {
452: return partNames;
453: }
454:
455: public void setPartNames(List value) {
456: partNames = value;
457: }
458:
459: public String getReturnName() {
460: return returnName;
461: }
462:
463: public void setReturnName(String value) {
464: returnName = value;
465: }
466:
467: // where is WSDL defining this abstract mesage
468: public Operation getOperation() {
469: return operation;
470: }
471:
472: public void setOperation(Operation value) {
473: operation = value;
474: }
475:
476: public Definition getDefinition() {
477: return definition;
478: }
479:
480: public void setDefintion(Definition value) {
481: definition = value;
482: }
483:
484: // WSIF related
485: public WSIFPort_SoapRMI getDynamicWSIFPort() {
486: return portInstance;
487: }
488:
489: public void setDynamicWSIFPort(WSIFPort_SoapRMI value) {
490: portInstance = value;
491: }
492:
493: public WSIFPort getWSIFPort() {
494: Trc.entry(this);
495: Trc.exit(portInstance);
496: return portInstance;
497: }
498:
499: }
|