aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.xml.internal.ws.server.sei; aoqi@0: aoqi@0: import com.sun.xml.internal.ws.api.SOAPVersion; aoqi@0: import com.sun.xml.internal.ws.api.message.Attachment; aoqi@0: import com.sun.xml.internal.ws.api.message.AttachmentSet; aoqi@0: import com.sun.xml.internal.ws.api.message.Message; aoqi@0: import com.sun.xml.internal.ws.api.model.ParameterBinding; aoqi@0: import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory; aoqi@0: import com.sun.xml.internal.ws.message.AttachmentUnmarshallerImpl; aoqi@0: import com.sun.xml.internal.ws.model.ParameterImpl; aoqi@0: import com.sun.xml.internal.ws.model.WrapperParameter; aoqi@0: import com.sun.xml.internal.ws.resources.ServerMessages; aoqi@0: import com.sun.xml.internal.ws.spi.db.RepeatedElementBridge; aoqi@0: import com.sun.xml.internal.ws.spi.db.XMLBridge; aoqi@0: import com.sun.xml.internal.ws.spi.db.DatabindingException; aoqi@0: import com.sun.xml.internal.ws.spi.db.PropertyAccessor; aoqi@0: import com.sun.xml.internal.ws.spi.db.WrapperComposite; aoqi@0: import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil; aoqi@0: import com.sun.xml.internal.ws.encoding.StringDataContentHandler; aoqi@0: import com.sun.xml.internal.ws.encoding.DataHandlerDataSource; aoqi@0: aoqi@0: import javax.activation.DataHandler; aoqi@0: import javax.imageio.ImageIO; aoqi@0: import javax.jws.WebParam.Mode; aoqi@0: import javax.xml.bind.JAXBException; aoqi@0: import javax.xml.namespace.QName; aoqi@0: import javax.xml.soap.SOAPException; aoqi@0: import javax.xml.soap.SOAPFault; aoqi@0: import javax.xml.stream.XMLStreamException; aoqi@0: import javax.xml.stream.XMLStreamReader; aoqi@0: import javax.xml.transform.Source; aoqi@0: import javax.xml.ws.Holder; aoqi@0: import javax.xml.ws.WebServiceException; aoqi@0: import javax.xml.ws.soap.SOAPFaultException; aoqi@0: import java.awt.Image; aoqi@0: import java.io.IOException; aoqi@0: import java.io.InputStream; aoqi@0: import java.io.UnsupportedEncodingException; aoqi@0: import java.lang.reflect.Type; aoqi@0: import java.util.ArrayList; aoqi@0: import java.util.Collection; aoqi@0: import java.util.HashMap; aoqi@0: import java.util.Iterator; aoqi@0: import java.util.List; aoqi@0: import java.util.Map; aoqi@0: aoqi@0: /** aoqi@0: * Reads a request {@link Message}, disassembles it, and moves obtained Java values aoqi@0: * to the expected places. aoqi@0: * aoqi@0: * @author Jitendra Kotamraju aoqi@0: */ aoqi@0: public abstract class EndpointArgumentsBuilder { aoqi@0: /** aoqi@0: * Reads a request {@link Message}, disassembles it, and moves obtained aoqi@0: * Java values to the expected places. aoqi@0: * aoqi@0: * @param request aoqi@0: * The request {@link Message} to be de-composed. aoqi@0: * @param args aoqi@0: * The Java arguments given to the SEI method invocation. aoqi@0: * Some parts of the reply message may be set to {@link Holder}s in the arguments. aoqi@0: * @throws JAXBException aoqi@0: * if there's an error during unmarshalling the request message. aoqi@0: * @throws XMLStreamException aoqi@0: * if there's an error during unmarshalling the request message. aoqi@0: */ aoqi@0: public abstract void readRequest(Message request, Object[] args) aoqi@0: throws JAXBException, XMLStreamException; aoqi@0: aoqi@0: static final class None extends EndpointArgumentsBuilder { aoqi@0: private None(){ aoqi@0: } aoqi@0: @Override aoqi@0: public void readRequest(Message msg, Object[] args) { aoqi@0: msg.consume(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * The singleton instance that produces null return value. aoqi@0: * Used for operations that doesn't have any output. aoqi@0: */ aoqi@0: public final static EndpointArgumentsBuilder NONE = new None(); aoqi@0: aoqi@0: /** aoqi@0: * Returns the 'uninitialized' value for the given type. aoqi@0: * aoqi@0: *

aoqi@0: * For primitive types, it's '0', and for reference types, it's null. aoqi@0: */ aoqi@0: @SuppressWarnings("element-type-mismatch") aoqi@0: public static Object getVMUninitializedValue(Type type) { aoqi@0: // if this map returns null, that means the 'type' is a reference type, aoqi@0: // in which case 'null' is the correct null value, so this code is correct. aoqi@0: return primitiveUninitializedValues.get(type); aoqi@0: } aoqi@0: aoqi@0: private static final Map primitiveUninitializedValues = new HashMap(); aoqi@0: aoqi@0: static { aoqi@0: Map m = primitiveUninitializedValues; aoqi@0: m.put(int.class,(int)0); aoqi@0: m.put(char.class,(char)0); aoqi@0: m.put(byte.class,(byte)0); aoqi@0: m.put(short.class,(short)0); aoqi@0: m.put(long.class,(long)0); aoqi@0: m.put(float.class,(float)0); aoqi@0: m.put(double.class,(double)0); aoqi@0: } aoqi@0: aoqi@0: protected QName wrapperName; aoqi@0: aoqi@0: static final class WrappedPartBuilder { aoqi@0: private final XMLBridge bridge; aoqi@0: private final EndpointValueSetter setter; aoqi@0: aoqi@0: /** aoqi@0: * @param bridge aoqi@0: * specifies how the part is unmarshalled. aoqi@0: * @param setter aoqi@0: * specifies how the obtained value is returned to the endpoint. aoqi@0: */ aoqi@0: public WrappedPartBuilder(XMLBridge bridge, EndpointValueSetter setter) { aoqi@0: this.bridge = bridge; aoqi@0: this.setter = setter; aoqi@0: } aoqi@0: aoqi@0: void readRequest( Object[] args, XMLStreamReader r, AttachmentSet att) throws JAXBException { aoqi@0: Object obj = null; aoqi@0: AttachmentUnmarshallerImpl au = (att != null)?new AttachmentUnmarshallerImpl(att):null; aoqi@0: if (bridge instanceof RepeatedElementBridge) { aoqi@0: RepeatedElementBridge rbridge = (RepeatedElementBridge)bridge; aoqi@0: ArrayList list = new ArrayList(); aoqi@0: QName name = r.getName(); aoqi@0: while (r.getEventType()==XMLStreamReader.START_ELEMENT && name.equals(r.getName())) { aoqi@0: list.add(rbridge.unmarshal(r, au)); aoqi@0: XMLStreamReaderUtil.toNextTag(r, name); aoqi@0: } aoqi@0: obj = rbridge.collectionHandler().convert(list); aoqi@0: } else { aoqi@0: obj = bridge.unmarshal(r, au); aoqi@0: } aoqi@0: setter.put(obj,args); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: protected Map wrappedParts = null; aoqi@0: aoqi@0: protected void readWrappedRequest(Message msg, Object[] args) throws JAXBException, XMLStreamException { aoqi@0: if (!msg.hasPayload()) { aoqi@0: throw new WebServiceException("No payload. Expecting payload with "+wrapperName+" element"); aoqi@0: } aoqi@0: XMLStreamReader reader = msg.readPayload(); aoqi@0: XMLStreamReaderUtil.verifyTag(reader,wrapperName); aoqi@0: reader.nextTag(); aoqi@0: while(reader.getEventType()==XMLStreamReader.START_ELEMENT) { aoqi@0: // TODO: QName has a performance issue aoqi@0: QName name = reader.getName(); aoqi@0: WrappedPartBuilder part = wrappedParts.get(name); aoqi@0: if(part==null) { aoqi@0: // no corresponding part found. ignore aoqi@0: XMLStreamReaderUtil.skipElement(reader); aoqi@0: reader.nextTag(); aoqi@0: } else { aoqi@0: part.readRequest(args,reader, msg.getAttachments()); aoqi@0: } aoqi@0: XMLStreamReaderUtil.toNextTag(reader, name); aoqi@0: } aoqi@0: aoqi@0: // we are done with the body aoqi@0: reader.close(); aoqi@0: XMLStreamReaderFactory.recycle(reader); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@link EndpointArgumentsBuilder} that sets the VM uninitialized value to the type. aoqi@0: */ aoqi@0: public static final class NullSetter extends EndpointArgumentsBuilder { aoqi@0: private final EndpointValueSetter setter; aoqi@0: private final Object nullValue; aoqi@0: aoqi@0: public NullSetter(EndpointValueSetter setter, Object nullValue){ aoqi@0: assert setter!=null; aoqi@0: this.nullValue = nullValue; aoqi@0: this.setter = setter; aoqi@0: } aoqi@0: public void readRequest(Message msg, Object[] args) { aoqi@0: setter.put(nullValue, args); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * {@link EndpointArgumentsBuilder} that is a composition of multiple aoqi@0: * {@link EndpointArgumentsBuilder}s. aoqi@0: * aoqi@0: *

aoqi@0: * Sometimes we need to look at multiple parts of the reply message aoqi@0: * (say, two header params, one body param, and three attachments, etc.) aoqi@0: * and that's when this object is used to combine multiple {@link EndpointArgumentsBuilder}s aoqi@0: * (that each responsible for handling one part). aoqi@0: * aoqi@0: *

aoqi@0: * The model guarantees that only at most one {@link EndpointArgumentsBuilder} will aoqi@0: * return a value as a return value (and everything else has to go to aoqi@0: * {@link Holder}s.) aoqi@0: */ aoqi@0: public static final class Composite extends EndpointArgumentsBuilder { aoqi@0: private final EndpointArgumentsBuilder[] builders; aoqi@0: aoqi@0: public Composite(EndpointArgumentsBuilder... builders) { aoqi@0: this.builders = builders; aoqi@0: } aoqi@0: aoqi@0: public Composite(Collection builders) { aoqi@0: this(builders.toArray(new EndpointArgumentsBuilder[builders.size()])); aoqi@0: } aoqi@0: aoqi@0: public void readRequest(Message msg, Object[] args) throws JAXBException, XMLStreamException { aoqi@0: for (EndpointArgumentsBuilder builder : builders) { aoqi@0: builder.readRequest(msg,args); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * Reads an Attachment into a Java parameter. aoqi@0: */ aoqi@0: public static abstract class AttachmentBuilder extends EndpointArgumentsBuilder { aoqi@0: protected final EndpointValueSetter setter; aoqi@0: protected final ParameterImpl param; aoqi@0: protected final String pname; aoqi@0: protected final String pname1; aoqi@0: aoqi@0: AttachmentBuilder(ParameterImpl param, EndpointValueSetter setter) { aoqi@0: this.setter = setter; aoqi@0: this.param = param; aoqi@0: this.pname = param.getPartName(); aoqi@0: this.pname1 = "<"+pname; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Creates an AttachmentBuilder based on the parameter type aoqi@0: * aoqi@0: * @param param aoqi@0: * runtime Parameter that abstracts the annotated java parameter aoqi@0: * @param setter aoqi@0: * specifies how the obtained value is set into the argument. Takes aoqi@0: * care of Holder arguments. aoqi@0: */ aoqi@0: public static EndpointArgumentsBuilder createAttachmentBuilder(ParameterImpl param, EndpointValueSetter setter) { aoqi@0: Class type = (Class)param.getTypeInfo().type; aoqi@0: if (DataHandler.class.isAssignableFrom(type)) { aoqi@0: return new DataHandlerBuilder(param, setter); aoqi@0: } else if (byte[].class==type) { aoqi@0: return new ByteArrayBuilder(param, setter); aoqi@0: } else if(Source.class.isAssignableFrom(type)) { aoqi@0: return new SourceBuilder(param, setter); aoqi@0: } else if(Image.class.isAssignableFrom(type)) { aoqi@0: return new ImageBuilder(param, setter); aoqi@0: } else if(InputStream.class==type) { aoqi@0: return new InputStreamBuilder(param, setter); aoqi@0: } else if(isXMLMimeType(param.getBinding().getMimeType())) { aoqi@0: return new JAXBBuilder(param, setter); aoqi@0: } else if(String.class.isAssignableFrom(type)) { aoqi@0: return new StringBuilder(param, setter); aoqi@0: } else { aoqi@0: throw new UnsupportedOperationException("Unknown Type="+type+" Attachment is not mapped."); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public void readRequest(Message msg, Object[] args) throws JAXBException, XMLStreamException { aoqi@0: boolean foundAttachment = false; aoqi@0: // TODO not to loop aoqi@0: for (Attachment att : msg.getAttachments()) { aoqi@0: String part = getWSDLPartName(att); aoqi@0: if (part == null) { aoqi@0: continue; aoqi@0: } aoqi@0: if(part.equals(pname) || part.equals(pname1)){ aoqi@0: foundAttachment = true; aoqi@0: mapAttachment(att, args); aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: if (!foundAttachment) { aoqi@0: throw new WebServiceException("Missing Attachment for "+pname); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: abstract void mapAttachment(Attachment att, Object[] args) throws JAXBException; aoqi@0: } aoqi@0: aoqi@0: private static final class DataHandlerBuilder extends AttachmentBuilder { aoqi@0: DataHandlerBuilder(ParameterImpl param, EndpointValueSetter setter) { aoqi@0: super(param, setter); aoqi@0: } aoqi@0: aoqi@0: void mapAttachment(Attachment att, Object[] args) { aoqi@0: setter.put(att.asDataHandler(), args); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private static final class ByteArrayBuilder extends AttachmentBuilder { aoqi@0: ByteArrayBuilder(ParameterImpl param, EndpointValueSetter setter) { aoqi@0: super(param, setter); aoqi@0: } aoqi@0: aoqi@0: void mapAttachment(Attachment att, Object[] args) { aoqi@0: setter.put(att.asByteArray(), args); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private static final class SourceBuilder extends AttachmentBuilder { aoqi@0: SourceBuilder(ParameterImpl param, EndpointValueSetter setter) { aoqi@0: super(param, setter); aoqi@0: } aoqi@0: aoqi@0: void mapAttachment(Attachment att, Object[] args) { aoqi@0: setter.put(att.asSource(), args); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private static final class ImageBuilder extends AttachmentBuilder { aoqi@0: ImageBuilder(ParameterImpl param, EndpointValueSetter setter) { aoqi@0: super(param, setter); aoqi@0: } aoqi@0: aoqi@0: void mapAttachment(Attachment att, Object[] args) { aoqi@0: Image image; aoqi@0: InputStream is = null; aoqi@0: try { aoqi@0: is = att.asInputStream(); aoqi@0: image = ImageIO.read(is); aoqi@0: } catch(IOException ioe) { aoqi@0: throw new WebServiceException(ioe); aoqi@0: } finally { aoqi@0: if (is != null) { aoqi@0: try { aoqi@0: is.close(); aoqi@0: } catch(IOException ioe) { aoqi@0: throw new WebServiceException(ioe); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: setter.put(image, args); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private static final class InputStreamBuilder extends AttachmentBuilder { aoqi@0: InputStreamBuilder(ParameterImpl param, EndpointValueSetter setter) { aoqi@0: super(param, setter); aoqi@0: } aoqi@0: aoqi@0: void mapAttachment(Attachment att, Object[] args) { aoqi@0: setter.put(att.asInputStream(), args); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private static final class JAXBBuilder extends AttachmentBuilder { aoqi@0: JAXBBuilder(ParameterImpl param, EndpointValueSetter setter) { aoqi@0: super(param, setter); aoqi@0: } aoqi@0: aoqi@0: void mapAttachment(Attachment att, Object[] args) throws JAXBException { aoqi@0: Object obj = param.getXMLBridge().unmarshal(att.asInputStream()); aoqi@0: setter.put(obj, args); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private static final class StringBuilder extends AttachmentBuilder { aoqi@0: StringBuilder(ParameterImpl param, EndpointValueSetter setter) { aoqi@0: super(param, setter); aoqi@0: } aoqi@0: aoqi@0: void mapAttachment(Attachment att, Object[] args) { aoqi@0: att.getContentType(); aoqi@0: StringDataContentHandler sdh = new StringDataContentHandler(); aoqi@0: try { aoqi@0: String str = (String)sdh.getContent(new DataHandlerDataSource(att.asDataHandler())); aoqi@0: setter.put(str, args); aoqi@0: } catch(Exception e) { aoqi@0: throw new WebServiceException(e); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Gets the WSDL part name of this attachment. aoqi@0: * aoqi@0: *

aoqi@0: * According to WSI AP 1.0 aoqi@0: *

aoqi@0:      * 3.8 Value-space of Content-Id Header
aoqi@0:      *   Definition: content-id part encoding
aoqi@0:      *   The "content-id part encoding" consists of the concatenation of:
aoqi@0:      * The value of the name attribute of the wsdl:part element referenced by the mime:content, in which characters disallowed in content-id headers (non-ASCII characters as represented by code points above 0x7F) are escaped as follows:
aoqi@0:      *     o Each disallowed character is converted to UTF-8 as one or more bytes.
aoqi@0:      *     o Any bytes corresponding to a disallowed character are escaped with the URI escaping mechanism (that is, converted to %HH, where HH is the hexadecimal notation of the byte value).
aoqi@0:      *     o The original character is replaced by the resulting character sequence.
aoqi@0:      * The character '=' (0x3D).
aoqi@0:      * A globally unique value such as a UUID.
aoqi@0:      * The character '@' (0x40).
aoqi@0:      * A valid domain name under the authority of the entity constructing the message.
aoqi@0:      * 
aoqi@0: * aoqi@0: * So a wsdl:part fooPart will be encoded as: aoqi@0: * aoqi@0: * aoqi@0: * @return null aoqi@0: * if the parsing fails. aoqi@0: */ aoqi@0: public static final String getWSDLPartName(com.sun.xml.internal.ws.api.message.Attachment att){ aoqi@0: String cId = att.getContentId(); aoqi@0: aoqi@0: int index = cId.lastIndexOf('@', cId.length()); aoqi@0: if(index == -1){ aoqi@0: return null; aoqi@0: } aoqi@0: String localPart = cId.substring(0, index); aoqi@0: index = localPart.lastIndexOf('=', localPart.length()); aoqi@0: if(index == -1){ aoqi@0: return null; aoqi@0: } aoqi@0: try { aoqi@0: return java.net.URLDecoder.decode(localPart.substring(0, index), "UTF-8"); aoqi@0: } catch (UnsupportedEncodingException e) { aoqi@0: throw new WebServiceException(e); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * Reads a header into a JAXB object. aoqi@0: */ aoqi@0: public static final class Header extends EndpointArgumentsBuilder { aoqi@0: private final XMLBridge bridge; aoqi@0: private final EndpointValueSetter setter; aoqi@0: private final QName headerName; aoqi@0: private final SOAPVersion soapVersion; aoqi@0: aoqi@0: /** aoqi@0: * @param name aoqi@0: * The name of the header element. aoqi@0: * @param bridge aoqi@0: * specifies how to unmarshal a header into a JAXB object. aoqi@0: * @param setter aoqi@0: * specifies how the obtained value is returned to the client. aoqi@0: */ aoqi@0: public Header(SOAPVersion soapVersion, QName name, XMLBridge bridge, EndpointValueSetter setter) { aoqi@0: this.soapVersion = soapVersion; aoqi@0: this.headerName = name; aoqi@0: this.bridge = bridge; aoqi@0: this.setter = setter; aoqi@0: } aoqi@0: aoqi@0: public Header(SOAPVersion soapVersion, ParameterImpl param, EndpointValueSetter setter) { aoqi@0: this( aoqi@0: soapVersion, aoqi@0: param.getTypeInfo().tagName, aoqi@0: param.getXMLBridge(), aoqi@0: setter); aoqi@0: assert param.getOutBinding()== ParameterBinding.HEADER; aoqi@0: } aoqi@0: aoqi@0: private SOAPFaultException createDuplicateHeaderException() { aoqi@0: try { aoqi@0: SOAPFault fault = soapVersion.getSOAPFactory().createFault(); aoqi@0: fault.setFaultCode(soapVersion.faultCodeClient); aoqi@0: fault.setFaultString(ServerMessages.DUPLICATE_PORT_KNOWN_HEADER(headerName)); aoqi@0: return new SOAPFaultException(fault); aoqi@0: } catch(SOAPException e) { aoqi@0: throw new WebServiceException(e); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public void readRequest(Message msg, Object[] args) throws JAXBException { aoqi@0: com.sun.xml.internal.ws.api.message.Header header = null; aoqi@0: Iterator it = aoqi@0: msg.getHeaders().getHeaders(headerName,true); aoqi@0: if (it.hasNext()) { aoqi@0: header = it.next(); aoqi@0: if (it.hasNext()) { aoqi@0: throw createDuplicateHeaderException(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if(header!=null) { aoqi@0: setter.put( header.readAsJAXB(bridge), args ); aoqi@0: } else { aoqi@0: // header not found. aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Reads the whole payload into a single JAXB bean. aoqi@0: */ aoqi@0: public static final class Body extends EndpointArgumentsBuilder { aoqi@0: private final XMLBridge bridge; aoqi@0: private final EndpointValueSetter setter; aoqi@0: aoqi@0: /** aoqi@0: * @param bridge aoqi@0: * specifies how to unmarshal the payload into a JAXB object. aoqi@0: * @param setter aoqi@0: * specifies how the obtained value is returned to the client. aoqi@0: */ aoqi@0: public Body(XMLBridge bridge, EndpointValueSetter setter) { aoqi@0: this.bridge = bridge; aoqi@0: this.setter = setter; aoqi@0: } aoqi@0: aoqi@0: public void readRequest(Message msg, Object[] args) throws JAXBException { aoqi@0: setter.put( msg.readPayloadAsJAXB(bridge), args ); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Treats a payload as multiple parts wrapped into one element, aoqi@0: * and processes all such wrapped parts. aoqi@0: */ aoqi@0: public static final class DocLit extends EndpointArgumentsBuilder { aoqi@0: /** aoqi@0: * {@link PartBuilder} keyed by the element name (inside the wrapper element.) aoqi@0: */ aoqi@0: private final PartBuilder[] parts; aoqi@0: aoqi@0: private final XMLBridge wrapper; aoqi@0: private boolean dynamicWrapper; aoqi@0: aoqi@0: public DocLit(WrapperParameter wp, Mode skipMode) { aoqi@0: wrapperName = wp.getName(); aoqi@0: wrapper = wp.getXMLBridge(); aoqi@0: Class wrapperType = (Class) wrapper.getTypeInfo().type; aoqi@0: dynamicWrapper = WrapperComposite.class.equals(wrapperType); aoqi@0: List parts = new ArrayList(); aoqi@0: List children = wp.getWrapperChildren(); aoqi@0: for (ParameterImpl p : children) { aoqi@0: if (p.getMode() == skipMode) { aoqi@0: continue; aoqi@0: } aoqi@0: /* aoqi@0: if(p.isIN()) aoqi@0: continue; aoqi@0: */ aoqi@0: QName name = p.getName(); aoqi@0: try { aoqi@0: if (dynamicWrapper) { aoqi@0: if (wrappedParts == null) wrappedParts = new HashMap(); aoqi@0: XMLBridge xmlBridge = p.getInlinedRepeatedElementBridge(); aoqi@0: if (xmlBridge == null) xmlBridge = p.getXMLBridge(); aoqi@0: wrappedParts.put( p.getName(), new WrappedPartBuilder(xmlBridge, EndpointValueSetter.get(p))); aoqi@0: } else { aoqi@0: parts.add( new PartBuilder( aoqi@0: wp.getOwner().getBindingContext().getElementPropertyAccessor( aoqi@0: wrapperType, aoqi@0: name.getNamespaceURI(), aoqi@0: p.getName().getLocalPart()), aoqi@0: EndpointValueSetter.get(p) aoqi@0: ) ); aoqi@0: // wrapper parameter itself always bind to body, and aoqi@0: // so do all its children aoqi@0: assert p.getBinding()== ParameterBinding.BODY; aoqi@0: } aoqi@0: } catch (JAXBException e) { aoqi@0: throw new WebServiceException( // TODO: i18n aoqi@0: wrapperType+" do not have a property of the name "+name,e); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: this.parts = parts.toArray(new PartBuilder[parts.size()]); aoqi@0: } aoqi@0: aoqi@0: public void readRequest(Message msg, Object[] args) throws JAXBException, XMLStreamException { aoqi@0: if (dynamicWrapper) { aoqi@0: readWrappedRequest(msg, args); aoqi@0: } else { aoqi@0: if (parts.length>0) { aoqi@0: if (!msg.hasPayload()) { aoqi@0: throw new WebServiceException("No payload. Expecting payload with "+wrapperName+" element"); aoqi@0: } aoqi@0: XMLStreamReader reader = msg.readPayload(); aoqi@0: XMLStreamReaderUtil.verifyTag(reader, wrapperName); aoqi@0: Object wrapperBean = wrapper.unmarshal(reader, (msg.getAttachments() != null) ? aoqi@0: new AttachmentUnmarshallerImpl(msg.getAttachments()): null); aoqi@0: aoqi@0: try { aoqi@0: for (PartBuilder part : parts) { aoqi@0: part.readRequest(args,wrapperBean); aoqi@0: } aoqi@0: } catch (DatabindingException e) { aoqi@0: // this can happen when the set method throw a checked exception or something like that aoqi@0: throw new WebServiceException(e); // TODO:i18n aoqi@0: } aoqi@0: aoqi@0: // we are done with the body aoqi@0: reader.close(); aoqi@0: XMLStreamReaderFactory.recycle(reader); aoqi@0: } else { aoqi@0: msg.consume(); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Unmarshals each wrapped part into a JAXB object and moves it aoqi@0: * to the expected place. aoqi@0: */ aoqi@0: static final class PartBuilder { aoqi@0: private final PropertyAccessor accessor; aoqi@0: private final EndpointValueSetter setter; aoqi@0: aoqi@0: /** aoqi@0: * @param accessor aoqi@0: * specifies which portion of the wrapper bean to obtain the value from. aoqi@0: * @param setter aoqi@0: * specifies how the obtained value is returned to the client. aoqi@0: */ aoqi@0: public PartBuilder(PropertyAccessor accessor, EndpointValueSetter setter) { aoqi@0: this.accessor = accessor; aoqi@0: this.setter = setter; aoqi@0: assert accessor!=null && setter!=null; aoqi@0: } aoqi@0: aoqi@0: final void readRequest( Object[] args, Object wrapperBean ) { aoqi@0: Object obj = accessor.get(wrapperBean); aoqi@0: setter.put(obj,args); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Treats a payload as multiple parts wrapped into one element, aoqi@0: * and processes all such wrapped parts. aoqi@0: */ aoqi@0: public static final class RpcLit extends EndpointArgumentsBuilder { aoqi@0: public RpcLit(WrapperParameter wp) { aoqi@0: assert wp.getTypeInfo().type== WrapperComposite.class; aoqi@0: aoqi@0: wrapperName = wp.getName(); aoqi@0: wrappedParts = new HashMap(); aoqi@0: List children = wp.getWrapperChildren(); aoqi@0: for (ParameterImpl p : children) { aoqi@0: wrappedParts.put( p.getName(), new WrappedPartBuilder( aoqi@0: p.getXMLBridge(), EndpointValueSetter.get(p) aoqi@0: )); aoqi@0: // wrapper parameter itself always bind to body, and aoqi@0: // so do all its children aoqi@0: assert p.getBinding()== ParameterBinding.BODY; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public void readRequest(Message msg, Object[] args) throws JAXBException, XMLStreamException { aoqi@0: readWrappedRequest(msg, args); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private static boolean isXMLMimeType(String mimeType){ aoqi@0: return mimeType.equals("text/xml") || mimeType.equals("application/xml"); aoqi@0: } aoqi@0: }