src/share/jaxws_classes/com/sun/xml/internal/ws/client/sei/ResponseBuilder.java

Sat, 07 Nov 2020 10:30:02 +0800

author
aoqi
date
Sat, 07 Nov 2020 10:30:02 +0800
changeset 1921
7166269ef0f1
parent 637
9c07ef4934dd
permissions
-rw-r--r--

Added tag mips-jdk8u275-b01 for changeset fdbe50121f48

     1 /*
     2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.xml.internal.ws.client.sei;
    28 import com.sun.xml.internal.ws.api.SOAPVersion;
    29 import com.sun.xml.internal.ws.api.message.Attachment;
    30 import com.sun.xml.internal.ws.api.message.AttachmentSet;
    31 import com.sun.xml.internal.ws.api.message.Message;
    32 import com.sun.xml.internal.ws.api.model.ParameterBinding;
    33 import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory;
    34 import com.sun.xml.internal.ws.message.AttachmentUnmarshallerImpl;
    35 import com.sun.xml.internal.ws.model.ParameterImpl;
    36 import com.sun.xml.internal.ws.model.WrapperParameter;
    37 import com.sun.xml.internal.ws.resources.ServerMessages;
    38 import com.sun.xml.internal.ws.spi.db.RepeatedElementBridge;
    39 import com.sun.xml.internal.ws.spi.db.XMLBridge;
    40 import com.sun.xml.internal.ws.spi.db.DatabindingException;
    41 import com.sun.xml.internal.ws.spi.db.PropertyAccessor;
    42 import com.sun.xml.internal.ws.spi.db.WrapperComposite;
    43 import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil;
    44 import com.sun.xml.internal.ws.encoding.StringDataContentHandler;
    45 import com.sun.xml.internal.ws.encoding.DataHandlerDataSource;
    47 import javax.activation.DataHandler;
    48 import javax.imageio.ImageIO;
    49 import javax.xml.bind.JAXBException;
    50 import javax.xml.namespace.QName;
    51 import javax.xml.soap.SOAPException;
    52 import javax.xml.soap.SOAPFault;
    53 import javax.xml.stream.XMLStreamException;
    54 import javax.xml.stream.XMLStreamReader;
    55 import javax.xml.stream.XMLStreamConstants;
    56 import javax.xml.transform.Source;
    57 import javax.xml.ws.Holder;
    58 import javax.xml.ws.WebServiceException;
    59 import javax.xml.ws.soap.SOAPFaultException;
    60 import java.awt.Image;
    61 import java.io.IOException;
    62 import java.io.InputStream;
    63 import java.io.UnsupportedEncodingException;
    64 import java.lang.reflect.Type;
    65 import java.util.ArrayList;
    66 import java.util.Collection;
    67 import java.util.HashMap;
    68 import java.util.Iterator;
    69 import java.util.List;
    70 import java.util.Map;
    72 /**
    73  * Reads a response {@link Message}, disassembles it, and moves obtained Java values
    74  * to the expected places.
    75  *
    76  * @author Kohsuke Kawaguchi
    77  * @author Jitendra Kotamraju
    78  */
    79 public abstract class ResponseBuilder {
    80     /**
    81      * Reads a response {@link Message}, disassembles it, and moves obtained Java values
    82      * to the expected places.
    83      *
    84      * @param reply
    85      *      The reply {@link Message} to be de-composed.
    86      * @param args
    87      *      The Java arguments given to the SEI method invocation.
    88      *      Some parts of the reply message may be set to {@link Holder}s in the arguments.
    89      * @return
    90      *      If a part of the reply message is returned as a return value from
    91      *      the SEI method, this method returns that value. Otherwise null.
    92      * @throws JAXBException
    93      *      if there's an error during unmarshalling the reply message.
    94      * @throws XMLStreamException
    95      *      if there's an error during unmarshalling the reply message.
    96      */
    97     public abstract Object readResponse(Message reply, Object[] args) throws JAXBException, XMLStreamException;
    99     static final class WrappedPartBuilder {
   100         private final XMLBridge bridge;
   101         private final ValueSetter setter;
   102         public WrappedPartBuilder(XMLBridge bridge, ValueSetter setter) {
   103             this.bridge = bridge;
   104             this.setter = setter;
   105         }
   106         final Object readResponse(Object[] args, XMLStreamReader r, AttachmentSet att) throws JAXBException {
   107             Object obj;
   108             AttachmentUnmarshallerImpl au = (att != null)?new AttachmentUnmarshallerImpl(att):null;
   109             if (bridge instanceof RepeatedElementBridge) {
   110                 RepeatedElementBridge rbridge = (RepeatedElementBridge)bridge;
   111                 ArrayList list = new ArrayList();
   112                 QName name = r.getName();
   113                 while (r.getEventType()==XMLStreamReader.START_ELEMENT && name.equals(r.getName())) {
   114                     list.add(rbridge.unmarshal(r, au));
   115                     XMLStreamReaderUtil.toNextTag(r, name);
   116                 }
   117                 obj = rbridge.collectionHandler().convert(list);
   118             } else {
   119                 obj = bridge.unmarshal(r, au);
   120             }
   121             return setter.put(obj,args);
   122         }
   123     }
   124     /**
   125      * {@link ResponseBuilder.PartBuilder} keyed by the element name (inside the wrapper element.)
   126      */
   127     protected Map<QName,WrappedPartBuilder> wrappedParts = null;
   128     protected QName wrapperName;
   130     protected Object readWrappedResponse(Message msg, Object[] args) throws JAXBException, XMLStreamException {
   131         Object retVal = null;
   133         if (!msg.hasPayload()) {
   134             throw new WebServiceException("No payload. Expecting payload with "+wrapperName+" element");
   135         }
   136         XMLStreamReader reader = msg.readPayload();
   137         XMLStreamReaderUtil.verifyTag(reader,wrapperName);
   138         reader.nextTag();
   140         while(reader.getEventType()==XMLStreamReader.START_ELEMENT) {
   141             // TODO: QName has a performance issue
   142             WrappedPartBuilder part = wrappedParts.get(reader.getName());
   143             if(part==null) {
   144                 // no corresponding part found. ignore
   145                 XMLStreamReaderUtil.skipElement(reader);
   146                 reader.nextTag();
   147             } else {
   148                 Object o = part.readResponse(args,reader, msg.getAttachments());
   149                 // there's only at most one ResponseBuilder that returns a value.
   150                 if(o!=null) {
   151                     assert retVal==null;
   152                     retVal = o;
   153                 }
   154             }
   155             // skip any whitespace
   156             if (reader.getEventType() != XMLStreamConstants.START_ELEMENT &&
   157                     reader.getEventType() != XMLStreamConstants.END_ELEMENT) {
   158                 XMLStreamReaderUtil.nextElementContent(reader);
   159             }
   160         }
   162         // we are done with the body
   163         reader.close();
   164         XMLStreamReaderFactory.recycle(reader);
   166         return retVal;
   167     }
   169     static final class None extends ResponseBuilder {
   170         private None(){
   171         }
   172         @Override
   173         public Object readResponse(Message msg, Object[] args) {
   174             msg.consume();
   175             return null;
   176         }
   177     }
   179     /**
   180      * The singleton instance that produces null return value.
   181      * Used for operations that doesn't have any output.
   182      */
   183     public final static ResponseBuilder NONE = new None();
   185     /**
   186      * Returns the 'uninitialized' value for the given type.
   187      *
   188      * <p>
   189      * For primitive types, it's '0', and for reference types, it's null.
   190      */
   191     @SuppressWarnings("element-type-mismatch")
   192     public static Object getVMUninitializedValue(Type type) {
   193         // if this map returns null, that means the 'type' is a reference type,
   194         // in which case 'null' is the correct null value, so this code is correct.
   195         return primitiveUninitializedValues.get(type);
   196     }
   198     private static final Map<Class,Object> primitiveUninitializedValues = new HashMap<Class, Object>();
   200     static {
   201         Map<Class, Object> m = primitiveUninitializedValues;
   202         m.put(int.class,(int)0);
   203         m.put(char.class,(char)0);
   204         m.put(byte.class,(byte)0);
   205         m.put(short.class,(short)0);
   206         m.put(long.class,(long)0);
   207         m.put(float.class,(float)0);
   208         m.put(double.class,(double)0);
   209     }
   211     /**
   212      * {@link ResponseBuilder} that sets the VM uninitialized value to the type.
   213      */
   214     public static final class NullSetter extends ResponseBuilder {
   215         private final ValueSetter setter;
   216         private final Object nullValue;
   218         public NullSetter(ValueSetter setter, Object nullValue){
   219             assert setter!=null;
   220             this.nullValue = nullValue;
   221             this.setter = setter;
   222         }
   223         @Override
   224         public Object readResponse(Message msg, Object[] args) {
   225             return setter.put(nullValue, args);
   226         }
   227     }
   229     /**
   230      * {@link ResponseBuilder} that is a composition of multiple
   231      * {@link ResponseBuilder}s.
   232      *
   233      * <p>
   234      * Sometimes we need to look at multiple parts of the reply message
   235      * (say, two header params, one body param, and three attachments, etc.)
   236      * and that's when this object is used to combine multiple {@link ResponseBuilder}s
   237      * (that each responsible for handling one part).
   238      *
   239      * <p>
   240      * The model guarantees that only at most one {@link ResponseBuilder} will
   241      * return a value as a return value (and everything else has to go to
   242      * {@link Holder}s.)
   243      */
   244     public static final class Composite extends ResponseBuilder {
   245         private final ResponseBuilder[] builders;
   247         public Composite(ResponseBuilder... builders) {
   248             this.builders = builders;
   249         }
   251         public Composite(Collection<? extends ResponseBuilder> builders) {
   252             this(builders.toArray(new ResponseBuilder[builders.size()]));
   253         }
   255         @Override
   256         public Object readResponse(Message msg, Object[] args) throws JAXBException, XMLStreamException {
   257             Object retVal = null;
   258             for (ResponseBuilder builder : builders) {
   259                 Object r = builder.readResponse(msg,args);
   260                 // there's only at most one ResponseBuilder that returns a value.
   261                 if(r!=null) {
   262                     assert retVal==null;
   263                     retVal = r;
   264                 }
   265             }
   266             return retVal;
   267         }
   268     }
   270     /**
   271      * Reads an Attachment into a Java parameter.
   272      */
   273     public static abstract class AttachmentBuilder extends ResponseBuilder {
   274         protected final ValueSetter setter;
   275         protected final ParameterImpl param;
   276         private final String pname;
   277         private final String pname1;
   279         AttachmentBuilder(ParameterImpl param, ValueSetter setter) {
   280             this.setter = setter;
   281             this.param = param;
   282             this.pname = param.getPartName();
   283             this.pname1 = "<"+pname;
   284         }
   286         /**
   287          * Creates an AttachmentBuilder based on the parameter type
   288          *
   289          * @param param
   290          *      runtime Parameter that abstracts the annotated java parameter
   291          * @param setter
   292          *      specifies how the obtained value is set into the argument. Takes
   293          *      care of Holder arguments.
   294          */
   295         public static ResponseBuilder createAttachmentBuilder(ParameterImpl param, ValueSetter setter) {
   296             Class type = (Class)param.getTypeInfo().type;
   297             if (DataHandler.class.isAssignableFrom(type)) {
   298                 return new DataHandlerBuilder(param, setter);
   299             } else if (byte[].class==type) {
   300                 return new ByteArrayBuilder(param, setter);
   301             } else if(Source.class.isAssignableFrom(type)) {
   302                 return new SourceBuilder(param, setter);
   303             } else if(Image.class.isAssignableFrom(type)) {
   304                 return new ImageBuilder(param, setter);
   305             } else if(InputStream.class==type) {
   306                 return new InputStreamBuilder(param, setter);
   307             } else if(isXMLMimeType(param.getBinding().getMimeType())) {
   308                 return new JAXBBuilder(param, setter);
   309             } else if(String.class.isAssignableFrom(type)) {
   310                 return new StringBuilder(param, setter);
   311             } else {
   312                 throw new UnsupportedOperationException("Unexpected Attachment type ="+type);
   313             }
   314         }
   316         @Override
   317         public Object readResponse(Message msg, Object[] args) throws JAXBException, XMLStreamException {
   318             // TODO not to loop
   319             for (Attachment att : msg.getAttachments()) {
   320                 String part = getWSDLPartName(att);
   321                 if (part == null) {
   322                     continue;
   323                 }
   324                 if(part.equals(pname) || part.equals(pname1)){
   325                     return mapAttachment(att, args);
   326                 }
   327             }
   328             return null;
   329         }
   331         abstract Object mapAttachment(Attachment att, Object[] args) throws JAXBException;
   332     }
   334     private static final class DataHandlerBuilder extends AttachmentBuilder {
   335         DataHandlerBuilder(ParameterImpl param, ValueSetter setter) {
   336             super(param, setter);
   337         }
   339         @Override
   340         Object mapAttachment(Attachment att, Object[] args) {
   341             return setter.put(att.asDataHandler(), args);
   342         }
   343     }
   345     private static final class StringBuilder extends AttachmentBuilder {
   346         StringBuilder(ParameterImpl param, ValueSetter setter) {
   347             super(param, setter);
   348         }
   350         @Override
   351         Object mapAttachment(Attachment att, Object[] args) {
   352             att.getContentType();
   353             StringDataContentHandler sdh = new StringDataContentHandler();
   354             try {
   355                 String str = (String)sdh.getContent(new DataHandlerDataSource(att.asDataHandler()));
   356                 return setter.put(str, args);
   357             } catch(Exception e) {
   358                 throw new WebServiceException(e);
   359             }
   361         }
   362     }
   364     private static final class ByteArrayBuilder extends AttachmentBuilder {
   365         ByteArrayBuilder(ParameterImpl param, ValueSetter setter) {
   366             super(param, setter);
   367         }
   369         @Override
   370         Object mapAttachment(Attachment att, Object[] args) {
   371             return setter.put(att.asByteArray(), args);
   372         }
   373     }
   375     private static final class SourceBuilder extends AttachmentBuilder {
   376         SourceBuilder(ParameterImpl param, ValueSetter setter) {
   377             super(param, setter);
   378         }
   380         @Override
   381         Object mapAttachment(Attachment att, Object[] args) {
   382             return setter.put(att.asSource(), args);
   383         }
   384     }
   386     private static final class ImageBuilder extends AttachmentBuilder {
   387         ImageBuilder(ParameterImpl param, ValueSetter setter) {
   388             super(param, setter);
   389         }
   391         @Override
   392         Object mapAttachment(Attachment att, Object[] args) {
   393             Image image;
   394             InputStream is = null;
   395             try {
   396                 is = att.asInputStream();
   397                 image = ImageIO.read(is);
   398             } catch(IOException ioe) {
   399                 throw new WebServiceException(ioe);
   400             } finally {
   401                 if (is != null) {
   402                     try {
   403                         is.close();
   404                     } catch(IOException ioe) {
   405                         throw new WebServiceException(ioe);
   406                     }
   407                 }
   408             }
   409             return setter.put(image, args);
   410         }
   411     }
   413     private static final class InputStreamBuilder extends AttachmentBuilder {
   414         InputStreamBuilder(ParameterImpl param, ValueSetter setter) {
   415             super(param, setter);
   416         }
   418         @Override
   419         Object mapAttachment(Attachment att, Object[] args) {
   420             return setter.put(att.asInputStream(), args);
   421         }
   422     }
   424     private static final class JAXBBuilder extends AttachmentBuilder {
   425         JAXBBuilder(ParameterImpl param, ValueSetter setter) {
   426             super(param, setter);
   427         }
   429         @Override
   430         Object mapAttachment(Attachment att, Object[] args) throws JAXBException {
   431             Object obj = param.getXMLBridge().unmarshal(att.asInputStream());
   432             return setter.put(obj, args);
   433         }
   434     }
   436     /**
   437      * Gets the WSDL part name of this attachment.
   438      *
   439      * <p>
   440      * According to WSI AP 1.0
   441      * <PRE>
   442      * 3.8 Value-space of Content-Id Header
   443      *   Definition: content-id part encoding
   444      *   The "content-id part encoding" consists of the concatenation of:
   445      * 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:
   446      *     o Each disallowed character is converted to UTF-8 as one or more bytes.
   447      *     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).
   448      *     o The original character is replaced by the resulting character sequence.
   449      * The character '=' (0x3D).
   450      * A globally unique value such as a UUID.
   451      * The character '@' (0x40).
   452      * A valid domain name under the authority of the entity constructing the message.
   453      * </PRE>
   454      *
   455      * So a wsdl:part fooPart will be encoded as:
   456      *      <fooPart=somereallybignumberlikeauuid@example.com>
   457      *
   458      * @return null
   459      *      if the parsing fails.
   460      */
   461     @SuppressWarnings("FinalStaticMethod")
   462     public static final String getWSDLPartName(com.sun.xml.internal.ws.api.message.Attachment att){
   463         String cId = att.getContentId();
   465         int index = cId.lastIndexOf('@', cId.length());
   466         if(index == -1){
   467             return null;
   468         }
   469         String localPart = cId.substring(0, index);
   470         index = localPart.lastIndexOf('=', localPart.length());
   471         if(index == -1){
   472             return null;
   473         }
   474         try {
   475             return java.net.URLDecoder.decode(localPart.substring(0, index), "UTF-8");
   476         } catch (UnsupportedEncodingException e) {
   477             throw new WebServiceException(e);
   478         }
   479     }
   482     /**
   483      * Reads a header into a JAXB object.
   484      */
   485     public static final class Header extends ResponseBuilder {
   486         private final XMLBridge<?> bridge;
   487         private final ValueSetter setter;
   488         private final QName headerName;
   489         private final SOAPVersion soapVersion;
   491         /**
   492          * @param soapVersion
   493          *      SOAP1.1 or 1.2
   494          * @param name
   495          *      The name of the header element.
   496          * @param bridge
   497          *      specifies how to unmarshal a header into a JAXB object.
   498          * @param setter
   499          *      specifies how the obtained value is returned to the client.
   500          */
   501         public Header(SOAPVersion soapVersion, QName name, XMLBridge<?> bridge, ValueSetter setter) {
   502             this.soapVersion = soapVersion;
   503             this.headerName = name;
   504             this.bridge = bridge;
   505             this.setter = setter;
   506         }
   508         public Header(SOAPVersion soapVersion, ParameterImpl param, ValueSetter setter) {
   509             this(soapVersion,
   510                 param.getTypeInfo().tagName,
   511                 param.getXMLBridge(),
   512                 setter);
   513             assert param.getOutBinding()== ParameterBinding.HEADER;
   514         }
   516         private SOAPFaultException createDuplicateHeaderException() {
   517             try {
   518                 SOAPFault fault = soapVersion.getSOAPFactory().createFault();
   519                 fault.setFaultCode(soapVersion.faultCodeServer);
   520                 fault.setFaultString(ServerMessages.DUPLICATE_PORT_KNOWN_HEADER(headerName));
   521                 return new SOAPFaultException(fault);
   522             } catch(SOAPException e) {
   523                 throw new WebServiceException(e);
   524             }
   525         }
   527         @Override
   528         public Object readResponse(Message msg, Object[] args) throws JAXBException {
   529             com.sun.xml.internal.ws.api.message.Header header = null;
   530             Iterator<com.sun.xml.internal.ws.api.message.Header> it =
   531                 msg.getHeaders().getHeaders(headerName,true);
   532             if (it.hasNext()) {
   533                 header = it.next();
   534                 if (it.hasNext()) {
   535                     throw createDuplicateHeaderException();
   536                 }
   537             }
   539             if(header!=null)
   540                 return setter.put( header.readAsJAXB(bridge), args );
   541             else
   542                 // header not found.
   543                 return null;
   544         }
   545     }
   547     /**
   548      * Reads the whole payload into a single JAXB bean.
   549      */
   550     public static final class Body extends ResponseBuilder {
   551         private final XMLBridge<?> bridge;
   552         private final ValueSetter setter;
   554         /**
   555          * @param bridge
   556          *      specifies how to unmarshal the payload into a JAXB object.
   557          * @param setter
   558          *      specifies how the obtained value is returned to the client.
   559          */
   560         public Body(XMLBridge<?> bridge, ValueSetter setter) {
   561             this.bridge = bridge;
   562             this.setter = setter;
   563         }
   565         @Override
   566         public Object readResponse(Message msg, Object[] args) throws JAXBException {
   567             return setter.put( msg.readPayloadAsJAXB(bridge), args );
   568         }
   569     }
   571     /**
   572      * Treats a payload as multiple parts wrapped into one element,
   573      * and processes all such wrapped parts.
   574      */
   575     public static final class DocLit extends ResponseBuilder {
   576         /**
   577          * {@link PartBuilder} keyed by the element name (inside the wrapper element.)
   578          */
   579         private final PartBuilder[] parts;
   581         private final XMLBridge wrapper;
   583         private boolean dynamicWrapper;
   585         public DocLit(WrapperParameter wp, ValueSetterFactory setterFactory) {
   586             wrapperName = wp.getName();
   587             wrapper = wp.getXMLBridge();
   588             Class wrapperType = (Class) wrapper.getTypeInfo().type;
   589             dynamicWrapper = WrapperComposite.class.equals(wrapperType);
   591             List<PartBuilder> tempParts = new ArrayList<PartBuilder>();
   593             List<ParameterImpl> children = wp.getWrapperChildren();
   594             for (ParameterImpl p : children) {
   595                 if(p.isIN())
   596                     continue;
   597                 QName name = p.getName();
   598                 if (dynamicWrapper) {
   599                     if (wrappedParts == null) wrappedParts = new HashMap<QName,WrappedPartBuilder>();
   600                     XMLBridge xmlBridge = p.getInlinedRepeatedElementBridge();
   601                     if (xmlBridge == null) xmlBridge = p.getXMLBridge();
   602                     wrappedParts.put( p.getName(), new WrappedPartBuilder(xmlBridge, setterFactory.get(p)));
   603                 } else {
   604                     try {
   605                         tempParts.add(new PartBuilder(
   606                                     wp.getOwner().getBindingContext().getElementPropertyAccessor(
   607                                         wrapperType,
   608                                         name.getNamespaceURI(),
   609                                         p.getName().getLocalPart()),
   610                                     setterFactory.get(p)
   611                                 ));
   612                         // wrapper parameter itself always bind to body, and
   613                         // so do all its children
   614                         assert p.getBinding()== ParameterBinding.BODY;
   615                     } catch (JAXBException e) {
   616                         throw new WebServiceException(  // TODO: i18n
   617                             wrapperType+" do not have a property of the name "+name,e);
   618                     }
   619                 }
   620             }
   621             this.parts = tempParts.toArray(new PartBuilder[tempParts.size()]);
   622         }
   624         @Override
   625         public Object readResponse(Message msg, Object[] args) throws JAXBException, XMLStreamException {
   626             if (dynamicWrapper) return readWrappedResponse(msg, args);
   627             Object retVal = null;
   629             if (parts.length>0) {
   630                 if (!msg.hasPayload()) {
   631                     throw new WebServiceException("No payload. Expecting payload with "+wrapperName+" element");
   632                 }
   633                 XMLStreamReader reader = msg.readPayload();
   634                 XMLStreamReaderUtil.verifyTag(reader,wrapperName);
   635                 Object wrapperBean = wrapper.unmarshal(reader, (msg.getAttachments() != null) ?
   636                     new AttachmentUnmarshallerImpl(msg.getAttachments()): null);
   638                 try {
   639                     for (PartBuilder part : parts) {
   640                         Object o = part.readResponse(args,wrapperBean);
   641                         // there's only at most one ResponseBuilder that returns a value.
   642                         // TODO: reorder parts so that the return value comes at the end.
   643                         if(o!=null) {
   644                             assert retVal==null;
   645                             retVal = o;
   646                         }
   647                     }
   648                 } catch (DatabindingException e) {
   649                     // this can happen when the set method throw a checked exception or something like that
   650                     throw new WebServiceException(e);    // TODO:i18n
   651                 }
   653                 // we are done with the body
   654                 reader.close();
   655                 XMLStreamReaderFactory.recycle(reader);
   656             } else {
   657                 msg.consume();
   658             }
   660             return retVal;
   661         }
   663         /**
   664          * Unmarshals each wrapped part into a JAXB object and moves it
   665          * to the expected place.
   666          */
   667         static final class PartBuilder {
   668             private final PropertyAccessor accessor;
   669             private final ValueSetter setter;
   671             /**
   672              * @param accessor
   673              *      specifies which portion of the wrapper bean to obtain the value from.
   674              * @param setter
   675              *      specifies how the obtained value is returned to the client.
   676              */
   677             public PartBuilder(PropertyAccessor accessor, ValueSetter setter) {
   678                 this.accessor = accessor;
   679                 this.setter = setter;
   680                 assert accessor!=null && setter!=null;
   681             }
   683             final Object readResponse( Object[] args, Object wrapperBean ) {
   684                 Object obj = accessor.get(wrapperBean);
   685                 return setter.put(obj,args);
   686             }
   689         }
   690     }
   692     /**
   693      * Treats a payload as multiple parts wrapped into one element,
   694      * and processes all such wrapped parts.
   695      */
   696     public static final class RpcLit extends ResponseBuilder {
   697         public RpcLit(WrapperParameter wp, ValueSetterFactory setterFactory) {
   698             assert wp.getTypeInfo().type== WrapperComposite.class;
   699             wrapperName = wp.getName();
   700             wrappedParts = new HashMap<QName,WrappedPartBuilder>();
   701             List<ParameterImpl> children = wp.getWrapperChildren();
   702             for (ParameterImpl p : children) {
   703                 wrappedParts.put( p.getName(), new WrappedPartBuilder(
   704                     p.getXMLBridge(), setterFactory.get(p)
   705                 ));
   706                 // wrapper parameter itself always bind to body, and
   707                 // so do all its children
   708                 assert p.getBinding()== ParameterBinding.BODY;
   709             }
   710         }
   712         @Override
   713         public Object readResponse(Message msg, Object[] args) throws JAXBException, XMLStreamException {
   714             return readWrappedResponse(msg, args);
   715         }
   716     }
   718     private static boolean isXMLMimeType(String mimeType){
   719         return mimeType.equals("text/xml") || mimeType.equals("application/xml");
   720     }
   721 }

mercurial