/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Emil Ong, Scott Ferguson */ package com.caucho.soap.skeleton; import com.caucho.jaxb.JAXBContextImpl; import com.caucho.jaxb.JAXBUtil; import com.caucho.jaxb.property.Property; import com.caucho.jaxb.property.AttachmentProperty; import com.caucho.soap.jaxws.HandlerChainInvoker; import static com.caucho.soap.wsdl.WSDLConstants.*; import com.caucho.soap.wsdl.WSDLBinding; import com.caucho.soap.wsdl.WSDLBindingOperation; import com.caucho.soap.wsdl.WSDLDefinitions; import com.caucho.soap.wsdl.WSDLParser; import com.caucho.soap.wsdl.WSDLPortType; import com.caucho.util.Attachment; import com.caucho.util.AttachmentReader; import com.caucho.util.L10N; import javax.activation.DataHandler; import javax.jws.Oneway; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import static javax.xml.XMLConstants.*; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.namespace.QName; import javax.xml.soap.MessageFactory; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPFault; import javax.xml.soap.SOAPMessage; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.ws.Holder; import javax.xml.ws.WebServiceException; import static javax.xml.ws.handler.MessageContext.*; import javax.xml.ws.soap.SOAPFaultException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; /** * Invokes a SOAP request on a Java POJO method */ public abstract class AbstractAction { private final static Logger log = Logger.getLogger(AbstractAction.class.getName()); private static final L10N L = new L10N(AbstractAction.class); private static final HashMap<Method,String> _methodNames = new HashMap<Method,String>(); protected static final String XML_SCHEMA_PREFIX = "xsd"; protected static final String TARGET_NAMESPACE_PREFIX = "m"; protected static final String SOAP_ENCODING_STYLE = "http://schemas.xmlsoap.org/soap/encoding/"; public final static String SOAP_ENVELOPE_PREFIX = "soapenv"; public final static String SOAP_ENVELOPE = "http://schemas.xmlsoap.org/soap/envelope/"; protected static XMLOutputFactory _xmlOutputFactory; protected static XMLInputFactory _xmlInputFactory = XMLInputFactory.newInstance(); protected static MessageFactory _messageFactory; protected static SOAPMessage _soapMessage; protected final Method _method; protected final int _arity; protected boolean _isOneway; protected String _responseName; protected String _operationName; protected String _portName; protected String _inputName; protected QName _requestName; protected QName _resultName; protected final HashMap<String,ParameterMarshal> _bodyArguments = new HashMap<String,ParameterMarshal>(); protected final ParameterMarshal[] _bodyArgs; protected final HashMap<String,ParameterMarshal> _headerArguments = new HashMap<String,ParameterMarshal>(); protected final ParameterMarshal[] _headerArgs; protected final HashMap<String,ParameterMarshal> _attachmentArguments = new HashMap<String,ParameterMarshal>(); protected final ParameterMarshal[] _attachmentArgs; protected final ParameterMarshal _returnMarshal; protected final boolean _headerReturn; protected final HashMap<Class,ParameterMarshal> _faults = new HashMap<Class,ParameterMarshal>(); protected final HashMap<QName,ParameterMarshal> _faultNames = new HashMap<QName,ParameterMarshal>(); protected int _attachmentInputs; protected int _headerInputs; protected int _bodyInputs; protected int _attachmentOutputs; protected int _headerOutputs; protected int _bodyOutputs; protected final JAXBContextImpl _jaxbContext; protected final String _targetNamespace; protected final String _soapAction; protected WSDLDefinitions _wsdl; protected WSDLBindingOperation _bindingOperation; protected static XMLOutputFactory getXMLOutputFactory() { if (_xmlOutputFactory == null) { _xmlOutputFactory = XMLOutputFactory.newInstance(); _xmlOutputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, Boolean.TRUE); } return _xmlOutputFactory; } protected static SOAPFault createSOAPFault() throws SOAPException { if (_messageFactory == null) _messageFactory = MessageFactory.newInstance(); // XXX protocol if (_soapMessage == null) _soapMessage = _messageFactory.createMessage(); _soapMessage.getSOAPBody().removeContents(); return _soapMessage.getSOAPBody().addFault(); } protected AbstractAction(Method method, Method eiMethod, JAXBContextImpl jaxbContext, String targetNamespace, WSDLDefinitions wsdl, Marshaller marshaller, Unmarshaller unmarshaller) throws JAXBException, WebServiceException { _method = method; _arity = _method.getParameterTypes().length; _jaxbContext = jaxbContext; _targetNamespace = targetNamespace; // XXX introspect this from the method _isOneway = (method.getAnnotation(Oneway.class) != null); // set the names for the input/output messages, portType/operation, and // binding/operation. _operationName = getWebMethodName(method, eiMethod); _portName = getPortName(method, eiMethod); _inputName = _operationName; _responseName = _operationName + "Response"; _soapAction = getSOAPAction(method, eiMethod); // // Arguments // _wsdl = wsdl; if (_wsdl != null) { for (WSDLBinding binding : _wsdl.getBindings()) { WSDLPortType portType = binding.getPortType(); if (portType != null && portType.getName().equals(_portName)) { for (WSDLBindingOperation operation : binding.getOperations()) { if (operation.getName().equals(_operationName)) { _bindingOperation = operation; break; } } } } } Class[] params = method.getParameterTypes(); Type[] genericParams = method.getGenericParameterTypes(); Annotation[][] paramAnn = method.getParameterAnnotations(); Annotation[][] eiParamAnn = null; if (eiMethod != null) eiParamAnn = eiMethod.getParameterAnnotations(); ArrayList<ParameterMarshal> attachmentList = new ArrayList<ParameterMarshal>(); ArrayList<ParameterMarshal> headerList = new ArrayList<ParameterMarshal>(); ArrayList<ParameterMarshal> bodyList = new ArrayList<ParameterMarshal>(); for (int i = 0; i < params.length; i++) { boolean isHeader = false; boolean isAttachment = false; String localName = "arg" + i; // As per JAX-WS spec QName name = null; WebParam.Mode mode = WebParam.Mode.IN; WebParam webParam = null; for (Annotation ann : paramAnn[i]) { if (ann instanceof WebParam) { webParam = (WebParam) ann; break; } } if (webParam == null && eiParamAnn != null) { for (Annotation ann : eiParamAnn[i]) { if (ann instanceof WebParam) { webParam = (WebParam) ann; break; } } } if (webParam != null) { if (! "".equals(webParam.name())) localName = webParam.name(); if ("".equals(webParam.targetNamespace())) name = new QName(localName); else name = new QName(webParam.targetNamespace(), localName); if (params[i].equals(Holder.class)) { mode = webParam.mode(); if (_isOneway) { throw new WebServiceException(L.l("Method {0} annotated with @Oneway, but contains output argument", method.getName())); } } isHeader = webParam.header(); if (! isHeader) isAttachment = isAttachment(webParam); } else if (params[i].equals(Holder.class)) { mode = WebParam.Mode.INOUT; } if (name == null) name = new QName(localName); Type type = JAXBUtil.getActualParameterType(genericParams[i]); Property property = _jaxbContext.createProperty(type, true); ParameterMarshal pMarshal = ParameterMarshal.create(i, property, name, mode, marshaller, unmarshaller); if (isHeader) { if (pMarshal instanceof InParameterMarshal) _headerInputs++; else if (pMarshal instanceof OutParameterMarshal) _headerOutputs++; else { _headerInputs++; _headerOutputs++; } headerList.add(pMarshal); _headerArguments.put(localName, pMarshal); } else if (isAttachment) { if (! (property instanceof AttachmentProperty)) throw new WebServiceException(L.l("Argument {0} of method {1} is of type {2}: Attachment argument types must map to base64Binary", i, method.getName(), params[i])); if (pMarshal instanceof InParameterMarshal) _attachmentInputs++; else if (pMarshal instanceof OutParameterMarshal) _attachmentOutputs++; else { _attachmentInputs++; _attachmentOutputs++; } attachmentList.add(pMarshal); _attachmentArguments.put(localName, pMarshal); } else { if (pMarshal instanceof InParameterMarshal) _bodyInputs++; else if (pMarshal instanceof OutParameterMarshal) _bodyOutputs++; else { _bodyInputs++; _bodyOutputs++; } bodyList.add(pMarshal); _bodyArguments.put(localName, pMarshal); } } _attachmentArgs = new ParameterMarshal[attachmentList.size()]; attachmentList.toArray(_attachmentArgs); _headerArgs = new ParameterMarshal[headerList.size()]; headerList.toArray(_headerArgs); _bodyArgs = new ParameterMarshal[bodyList.size()]; bodyList.toArray(_bodyArgs); // // Return type // if (! Void.TYPE.equals(method.getReturnType())) { if (_isOneway) throw new WebServiceException(L.l("Method {0} annotated with @Oneway, but has non-void return", method.getName())); Property property = _jaxbContext.createProperty(method.getGenericReturnType()); WebResult webResult = method.getAnnotation(WebResult.class); if (webResult == null && eiMethod != null) webResult = eiMethod.getAnnotation(WebResult.class); if (webResult != null) { _headerReturn = webResult.header(); String localName = webResult.name(); if ("".equals(localName)) localName = "return"; if ("".equals(webResult.targetNamespace())) _resultName = new QName(localName); else _resultName = new QName(webResult.targetNamespace(), localName); } else { _headerReturn = false; _resultName = new QName("return"); // XXX namespace? } _returnMarshal = ParameterMarshal.create(0, property, _resultName, WebParam.Mode.OUT, marshaller, unmarshaller); _bodyOutputs++; if (_headerReturn) _headerOutputs++; } else { _headerReturn = false; _returnMarshal = null; } // // Exceptions // Class[] exceptions = method.getExceptionTypes(); for (Class exception : exceptions) { QName faultName = new QName(targetNamespace, exception.getSimpleName(), TARGET_NAMESPACE_PREFIX); // XXX check for generated exception classes versus raw exceptions // i.e. things like getFaultInfo() Property property = jaxbContext.createProperty(exception); ParameterMarshal marshal = ParameterMarshal.create(0, property, faultName, WebParam.Mode.OUT, marshaller, unmarshaller); _faults.put(exception, marshal); _faultNames.put(faultName, marshal); } } public static AbstractAction createAction(Method method, JAXBContextImpl jaxbContext, String targetNamespace, WSDLDefinitions wsdl, Marshaller marshaller, Unmarshaller unmarshaller) throws JAXBException, WebServiceException { // There are three valid modes in JAX-WS: // // 1. Document wrapped -- all the parameters and return values // are encapsulated in a single encoded object (i.e. the document). // This is selected by // SOAPBinding.style() == DOCUMENT // SOAPBinding.use() == LITERAL // SOAPBinding.parameterStyle() == WRAPPED // // 2. Document bare -- the method must have at most one input and // one output parameter. No wrapper objects are created. // This is selected by // SOAPBinding.style() == DOCUMENT // SOAPBinding.use() == LITERAL // SOAPBinding.parameterStyle() == BARE // // 3. RPC style -- parameters and return values are mapped to // wsdl:parts. This is selected by: // SOAPBinding.style() == RPC // SOAPBinding.use() == LITERAL // SOAPBinding.parameterStyle() == WRAPPED // // It seems that "use" is never ENCODED in JAX-WS and is not allowed // by WS-I, so we don't allow it either. // // Check for the SOAPBinding annotation... // look at the declaring class and method first Class cl = method.getDeclaringClass(); Method eiMethod = null; SOAPBinding soapBinding = (SOAPBinding) cl.getAnnotation(SOAPBinding.class); if (method.isAnnotationPresent(SOAPBinding.class)) soapBinding = method.getAnnotation(SOAPBinding.class); if (soapBinding == null) { // Then look at the endpoint interface, if available WebService webService = (WebService) cl.getAnnotation(WebService.class); if (webService != null) { if (! "".equals(webService.endpointInterface())) { try { ClassLoader loader = cl.getClassLoader(); Class endpointInterface = loader.loadClass(webService.endpointInterface()); soapBinding = (SOAPBinding) endpointInterface.getAnnotation(SOAPBinding.class); eiMethod = endpointInterface.getMethod(method.getName(), method.getParameterTypes()); if (eiMethod.isAnnotationPresent(SOAPBinding.class)) soapBinding = eiMethod.getAnnotation(SOAPBinding.class); } catch (ClassNotFoundException e) { throw new WebServiceException(L.l("Endpoint interface {0} not found", webService.endpointInterface()), e); } catch (NoSuchMethodException e) { // We don't care if the method isn't defined in the interface } } } } // Document wrapped is the default for methods w/o a @SOAPBinding if (soapBinding == null) return new DocumentWrappedAction(method, eiMethod, jaxbContext, targetNamespace, wsdl, marshaller, unmarshaller); if (soapBinding.use() == SOAPBinding.Use.ENCODED) throw new UnsupportedOperationException(L.l("SOAP encoded style is not supported by JAX-WS")); if (soapBinding.style() == SOAPBinding.Style.DOCUMENT) { if (soapBinding.parameterStyle() == SOAPBinding.ParameterStyle.WRAPPED) return new DocumentWrappedAction(method, eiMethod, jaxbContext, targetNamespace, wsdl, marshaller, unmarshaller); else { return new DocumentBareAction(method, eiMethod, jaxbContext, targetNamespace, wsdl, marshaller, unmarshaller); } } else { if (soapBinding.parameterStyle() != SOAPBinding.ParameterStyle.WRAPPED) throw new UnsupportedOperationException(L.l("SOAP RPC bare style not supported")); return new RpcAction(method, eiMethod, jaxbContext, targetNamespace, wsdl, marshaller, unmarshaller); } } protected boolean isAttachment(WebParam webParam) { return webParam.name().startsWith("attach"); } /** * Client-side invocation. */ public Object invoke(String url, Object[] args, HandlerChainInvoker handlerChain) throws IOException, XMLStreamException, MalformedURLException, JAXBException, Throwable { XMLStreamReader in = null; URL urlObject = new URL(url); URLConnection connection = urlObject.openConnection(); // XXX HTTPS if (! (connection instanceof HttpURLConnection)) return null; HttpURLConnection httpConnection = (HttpURLConnection) connection; try { // // Send the request // httpConnection.setRequestMethod("POST"); httpConnection.setDoInput(true); httpConnection.setDoOutput(true); // XXX: Does this change for multipart/attachments? httpConnection.setRequestProperty("Content-type", "text/xml"); OutputStream httpOut = null; XMLStreamWriter out = null; DOMResult dom = null; UUID uuid = UUID.randomUUID(); if (_attachmentInputs > 0) { // note that we have to add the request property (header) before // we get the output stream httpConnection.addRequestProperty("Content-Type", "multipart/related; " + "type=\"text/xml\"; " + "boundary=\"uuid:" + uuid + "\""); httpOut = httpConnection.getOutputStream(); PrintWriter writer = new PrintWriter(httpOut); writer.print("--uuid:" + uuid + "\r\n"); writer.print("Content-Type: text/xml\r\n"); writer.print("\r\n"); writer.flush(); } else httpOut = httpConnection.getOutputStream(); if (handlerChain != null) { dom = new DOMResult(); out = getXMLOutputFactory().createXMLStreamWriter(dom); } else { out = getXMLOutputFactory().createXMLStreamWriter(httpOut); } writeRequest(out, args); out.flush(); if (_attachmentInputs > 0) { httpOut.write("\r\n".getBytes()); writeAttachments(httpOut, uuid, args); } if (handlerChain != null) { Source source = new DOMSource(dom.getNode()); if (! handlerChain.invokeClientOutbound(source, httpOut)) { source = handlerChain.getSource(); in = _xmlInputFactory.createXMLStreamReader(source); return readResponse(in, args); } } // // Parse the response // httpConnection.getResponseCode(); InputStream is = httpConnection.getInputStream(); if (handlerChain != null) is = handlerChain.invokeClientInbound(httpConnection); String contentType = httpConnection.getHeaderField("Content-Type"); if (contentType != null && contentType.startsWith("multipart/related")) { String[] tokens = contentType.split(";"); String boundary = null; for (int i = 0; i < tokens.length; i++) { int start = tokens[i].indexOf("boundary="); if (start >= 0) { boundary = tokens[i].substring(start + "boundary=".length() + 1, tokens[i].lastIndexOf('"')); break; } } if (boundary == null) return null; // XXX throw something about malformed response } in = _xmlInputFactory.createXMLStreamReader(is); if (httpConnection.getResponseCode() != 200) return null; // XXX more meaningful error if (_isOneway) return null; return readResponse(in, args); } finally { if (httpConnection != null) httpConnection.disconnect(); } } protected void writeRequest(XMLStreamWriter out, Object []args) throws IOException, XMLStreamException, JAXBException { out.writeStartDocument("UTF-8", "1.0"); out.writeStartElement(Skeleton.SOAP_ENVELOPE_PREFIX, "Envelope", Skeleton.SOAP_ENVELOPE); out.writeNamespace(Skeleton.SOAP_ENVELOPE_PREFIX, Skeleton.SOAP_ENVELOPE); out.writeStartElement(Skeleton.SOAP_ENVELOPE_PREFIX, "Header", Skeleton.SOAP_ENVELOPE); for (ParameterMarshal marshal : _headerArguments.values()) marshal.serializeCall(out, args); out.writeEndElement(); // Header out.writeStartElement(Skeleton.SOAP_ENVELOPE_PREFIX, "Body", Skeleton.SOAP_ENVELOPE); writeMethodInvocation(out, args); out.writeEndElement(); // Body out.writeEndElement(); // Envelope } protected void writeAttachments(OutputStream out, UUID uuid, Object[] args) throws IOException { PrintWriter writer = new PrintWriter(out); for (int i = 0; i < _attachmentArgs.length; i++) _attachmentArgs[i].serializeCall(writer, out, uuid, args); } abstract protected void writeMethodInvocation(XMLStreamWriter out, Object []args) throws IOException, XMLStreamException, JAXBException; abstract protected Object readResponse(XMLStreamReader in, Object []args) throws IOException, XMLStreamException, JAXBException, Throwable; /** * Invokes the request for a call. */ public int invoke(Object service, XMLStreamReader header, XMLStreamReader in, XMLStreamWriter out, List<Attachment> attachments) throws IOException, XMLStreamException, Throwable { // We're starting out at the point in the input stream where the // method name is listed (with the arguments as children) and the // point in the output stream where the results are to be written. Object[] args = readMethodInvocation(header, in); readAttachments(attachments, args); Object value = null; try { value = _method.invoke(service, args); } catch (IllegalAccessException e) { throw new Throwable(e); } catch (IllegalArgumentException e) { throw new Throwable(e); } catch (InvocationTargetException e) { writeFault(out, e.getCause()); return 500; } if (! _isOneway) { if (_headerOutputs > 0) { out.writeStartElement(SOAP_ENVELOPE_PREFIX, "Header", SOAP_ENVELOPE); if (_returnMarshal != null && _headerReturn) _returnMarshal.serializeReply(out, value); for (int i = 0; i < _headerArgs.length; i++) _headerArgs[i].serializeReply(out, args); out.writeEndElement(); // Header } } // services/1318: We always need a body even if it is oneway out.writeStartElement(SOAP_ENVELOPE_PREFIX, "Body", SOAP_ENVELOPE); if (! _isOneway) writeResponse(out, value, args); out.writeEndElement(); // Body return 200; } protected void readHeaders(XMLStreamReader header, Object[] args) throws IOException, XMLStreamException, JAXBException { for (int i = 0; i < _headerArgs.length; i++) _headerArgs[i].prepareArgument(args); if (header != null) { header.nextTag(); while (header.getEventType() == header.START_ELEMENT) { ParameterMarshal arg = _headerArguments.get(header.getLocalName()); if (arg == null) { if (log.isLoggable(Level.FINER)) log.finer(L.l("Unknown header argument: {0}", header.getName())); // skip this subtree int depth = 1; while (depth > 0) { switch (header.nextTag()) { case XMLStreamReader.START_ELEMENT: depth++; break; case XMLStreamReader.END_ELEMENT: depth--; break; } } } else { arg.deserializeCall(header, args); } } } } protected void readAttachments(List<Attachment> attachments, Object[] args) throws IOException, XMLStreamException, JAXBException { for (int i = 0; i < _attachmentArgs.length; i++) { if (_attachmentArgs[i] instanceof OutParameterMarshal) continue; _attachmentArgs[i].prepareArgument(args); if (attachments != null) { if (i < attachments.size()) _attachmentArgs[i].deserializeCall(attachments.get(i), args); else log.fine(L.l("Received unexpected attachment")); } } } // reads the method invocation and returns the arguments abstract protected Object[] readMethodInvocation(XMLStreamReader header, XMLStreamReader in) throws IOException, XMLStreamException, JAXBException; abstract protected void writeResponse(XMLStreamWriter out, Object value, Object[] args) throws IOException, XMLStreamException, JAXBException; protected void writeFault(XMLStreamWriter out, Throwable fault) throws IOException, XMLStreamException, JAXBException { out.writeStartElement(SOAP_ENVELOPE_PREFIX, "Body", SOAP_ENVELOPE); out.writeStartElement(Skeleton.SOAP_ENVELOPE_PREFIX, "Fault", Skeleton.SOAP_ENVELOPE); out.writeStartElement("faultcode"); out.writeCharacters(Skeleton.SOAP_ENVELOPE_PREFIX + ":Server"); out.writeEndElement(); // faultcode // // Marshal this exception as a fault. // // faults must have exactly the same class as declared on the method, // otherwise we emit an internal server error. // XXX This may not be behavior required by the standard and we may // be able to improve here by casting as a superclass. ParameterMarshal faultMarshal = _faults.get(fault.getClass()); if (faultMarshal == null) { out.writeStartElement("faultstring"); out.writeCharacters(L.l("Internal server error")); out.writeEndElement(); // faultstring } else { out.writeStartElement("faultstring"); out.writeCharacters(fault.getMessage()); out.writeEndElement(); // faultstring out.writeStartElement("detail"); faultMarshal.serializeReply(out, fault); out.writeEndElement(); // detail } out.writeEndElement(); // Fault out.writeEndElement(); // Body } protected Throwable readFault(XMLStreamReader in) throws IOException, XMLStreamException, JAXBException, SOAPException { Throwable fault = null; String message = null; String actor = null; SOAPFault soapFault = createSOAPFault(); while (in.nextTag() == XMLStreamReader.START_ELEMENT) { if ("faultcode".equals(in.getLocalName())) { if (in.next() == XMLStreamReader.CHARACTERS) { String code = in.getText(); int colon = code.indexOf(':'); if (colon >= 0) code = code.substring(colon + 1); if ("Server".equalsIgnoreCase(code)) { // XXX Do anything with this? } else if ("Client".equalsIgnoreCase(code)) { // XXX Do anything with this? } else if ("VersionMismatch".equalsIgnoreCase(code)) { // XXX Do anything with this? } else if ("MustUnderstand".equalsIgnoreCase(code)) { // XXX Do anything with this? } soapFault.setFaultCode(code); } while (in.nextTag() != XMLStreamReader.END_ELEMENT) {} } else if ("faultstring".equals(in.getLocalName())) { if (in.next() == XMLStreamReader.CHARACTERS) message = in.getText(); soapFault.setFaultString(message); while (in.nextTag() != XMLStreamReader.END_ELEMENT) {} } else if ("faultactor".equals(in.getLocalName())) { if (in.next() == XMLStreamReader.CHARACTERS) actor = in.getText(); soapFault.setFaultActor(actor); while (in.nextTag() != XMLStreamReader.END_ELEMENT) {} } else if ("detail".equals(in.getLocalName())) { if (in.nextTag() == XMLStreamReader.START_ELEMENT) { ParameterMarshal faultMarshal = _faultNames.get(in.getName()); if (faultMarshal != null) fault = (Exception) faultMarshal.deserializeReply(in, fault); } } } if (fault == null) fault = new SOAPFaultException(soapFault); return fault; } public boolean hasHeaderInput() { return false; } public int getArity() { return _arity; } public String getInputName() { return _inputName; } public static String getWebMethodName(Method method) { String methodName = _methodNames.get(method); if (methodName == null) { Method eiMethod = getEIMethod(method); methodName = getWebMethodName(method, eiMethod); _methodNames.put(method, methodName); } return methodName; } public static String getWebMethodName(Method method, Method eiMethod) { String name = method.getName(); WebMethod webMethod = method.getAnnotation(WebMethod.class); if (webMethod == null && eiMethod != null) webMethod = eiMethod.getAnnotation(WebMethod.class); if (webMethod != null && ! "".equals(webMethod.operationName())) name = webMethod.operationName(); return name; } public static String getPortName(Method method, Method eiMethod) { Class cl = method.getDeclaringClass(); WebService webService = (WebService) cl.getAnnotation(WebService.class); if (webService == null && eiMethod != null) { cl = eiMethod.getDeclaringClass(); webService = (WebService) cl.getAnnotation(WebService.class); } if (webService != null && ! "".equals(webService.portName())) return webService.portName(); return null; } public static String getSOAPAction(Method method, Method eiMethod) { String action = ""; WebMethod webMethod = method.getAnnotation(WebMethod.class); if (webMethod == null && eiMethod != null) webMethod = eiMethod.getAnnotation(WebMethod.class); if (webMethod != null) action = webMethod.action(); return action; } public static Method getEIMethod(Method method) { try { Class cl = method.getDeclaringClass(); WebService webService = (WebService) cl.getAnnotation(WebService.class); if (webService != null) { if (! "".equals(webService.endpointInterface())) { ClassLoader loader = cl.getClassLoader(); Class endpointInterface = loader.loadClass(webService.endpointInterface()); return endpointInterface.getMethod(method.getName(), method.getParameterTypes()); } } } catch (ClassNotFoundException e) { } catch (NoSuchMethodException e) { } return null; } public abstract void writeWSDLMessages(XMLStreamWriter out, String soapNamespaceURI) throws XMLStreamException; public abstract void writeSchema(XMLStreamWriter out, String namespace, JAXBContextImpl context) throws XMLStreamException, WebServiceException; public abstract void writeWSDLBindingOperation(XMLStreamWriter out, String soapNamespaceURI) throws XMLStreamException; public abstract void writeWSDLOperation(XMLStreamWriter out, String soapNamespaceURI) throws XMLStreamException; }