View Javadoc
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   */
25  
26  package com.sun.xml.internal.ws.server.sei;
27  
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;
46  
47  import javax.activation.DataHandler;
48  import javax.imageio.ImageIO;
49  import javax.jws.WebParam.Mode;
50  import javax.xml.bind.JAXBException;
51  import javax.xml.namespace.QName;
52  import javax.xml.soap.SOAPException;
53  import javax.xml.soap.SOAPFault;
54  import javax.xml.stream.XMLStreamException;
55  import javax.xml.stream.XMLStreamReader;
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;
71  
72  /**
73   * Reads a request {@link Message}, disassembles it, and moves obtained Java values
74   * to the expected places.
75   *
76   * @author Jitendra Kotamraju
77   */
78  public abstract class EndpointArgumentsBuilder {
79      /**
80       * Reads a request {@link Message}, disassembles it, and moves obtained
81       * Java values to the expected places.
82       *
83       * @param request
84       *      The request {@link Message} to be de-composed.
85       * @param args
86       *      The Java arguments given to the SEI method invocation.
87       *      Some parts of the reply message may be set to {@link Holder}s in the arguments.
88       * @throws JAXBException
89       *      if there's an error during unmarshalling the request message.
90       * @throws XMLStreamException
91       *      if there's an error during unmarshalling the request message.
92       */
93      public abstract void readRequest(Message request, Object[] args)
94          throws JAXBException, XMLStreamException;
95  
96      static final class None extends EndpointArgumentsBuilder {
97          private None(){
98          }
99          @Override
100         public void readRequest(Message msg, Object[] args) {
101             msg.consume();
102         }
103     }
104 
105     /**
106      * The singleton instance that produces null return value.
107      * Used for operations that doesn't have any output.
108      */
109     public final static EndpointArgumentsBuilder NONE = new None();
110 
111     /**
112      * Returns the 'uninitialized' value for the given type.
113      *
114      * <p>
115      * For primitive types, it's '0', and for reference types, it's null.
116      */
117     @SuppressWarnings("element-type-mismatch")
118     public static Object getVMUninitializedValue(Type type) {
119         // if this map returns null, that means the 'type' is a reference type,
120         // in which case 'null' is the correct null value, so this code is correct.
121         return primitiveUninitializedValues.get(type);
122     }
123 
124     private static final Map<Class,Object> primitiveUninitializedValues = new HashMap<Class, Object>();
125 
126     static {
127         Map<Class, Object> m = primitiveUninitializedValues;
128         m.put(int.class,(int)0);
129         m.put(char.class,(char)0);
130         m.put(byte.class,(byte)0);
131         m.put(short.class,(short)0);
132         m.put(long.class,(long)0);
133         m.put(float.class,(float)0);
134         m.put(double.class,(double)0);
135     }
136 
137     protected QName wrapperName;
138 
139     static final class WrappedPartBuilder {
140         private final XMLBridge bridge;
141         private final EndpointValueSetter setter;
142 
143         /**
144          * @param bridge
145          *      specifies how the part is unmarshalled.
146          * @param setter
147          *      specifies how the obtained value is returned to the endpoint.
148          */
149         public WrappedPartBuilder(XMLBridge bridge, EndpointValueSetter setter) {
150             this.bridge = bridge;
151             this.setter = setter;
152         }
153 
154         void readRequest( Object[] args, XMLStreamReader r, AttachmentSet att) throws JAXBException {
155             Object obj = null;
156             AttachmentUnmarshallerImpl au = (att != null)?new AttachmentUnmarshallerImpl(att):null;
157             if (bridge instanceof RepeatedElementBridge) {
158                 RepeatedElementBridge rbridge = (RepeatedElementBridge)bridge;
159                 ArrayList list = new ArrayList();
160                 QName name = r.getName();
161                 while (r.getEventType()==XMLStreamReader.START_ELEMENT && name.equals(r.getName())) {
162                     list.add(rbridge.unmarshal(r, au));
163                     XMLStreamReaderUtil.toNextTag(r, name);
164                 }
165                 obj = rbridge.collectionHandler().convert(list);
166             } else {
167                 obj = bridge.unmarshal(r, au);
168             }
169             setter.put(obj,args);
170         }
171     }
172 
173     protected Map<QName,WrappedPartBuilder> wrappedParts = null;
174 
175     protected void readWrappedRequest(Message msg, Object[] args) throws JAXBException, XMLStreamException {
176         if (!msg.hasPayload()) {
177             throw new WebServiceException("No payload. Expecting payload with "+wrapperName+" element");
178         }
179         XMLStreamReader reader = msg.readPayload();
180         XMLStreamReaderUtil.verifyTag(reader,wrapperName);
181         reader.nextTag();
182         while(reader.getEventType()==XMLStreamReader.START_ELEMENT) {
183             // TODO: QName has a performance issue
184             QName name = reader.getName();
185             WrappedPartBuilder part = wrappedParts.get(name);
186             if(part==null) {
187                 // no corresponding part found. ignore
188                 XMLStreamReaderUtil.skipElement(reader);
189                 reader.nextTag();
190             } else {
191                 part.readRequest(args,reader, msg.getAttachments());
192             }
193             XMLStreamReaderUtil.toNextTag(reader, name);
194         }
195 
196         // we are done with the body
197         reader.close();
198         XMLStreamReaderFactory.recycle(reader);
199     }
200 
201     /**
202      * {@link EndpointArgumentsBuilder} that sets the VM uninitialized value to the type.
203      */
204     public static final class NullSetter extends EndpointArgumentsBuilder {
205         private final EndpointValueSetter setter;
206         private final Object nullValue;
207 
208         public NullSetter(EndpointValueSetter setter, Object nullValue){
209             assert setter!=null;
210             this.nullValue = nullValue;
211             this.setter = setter;
212         }
213         public void readRequest(Message msg, Object[] args) {
214             setter.put(nullValue, args);
215         }
216     }
217 
218     /**
219      * {@link EndpointArgumentsBuilder} that is a composition of multiple
220      * {@link EndpointArgumentsBuilder}s.
221      *
222      * <p>
223      * Sometimes we need to look at multiple parts of the reply message
224      * (say, two header params, one body param, and three attachments, etc.)
225      * and that's when this object is used to combine multiple {@link EndpointArgumentsBuilder}s
226      * (that each responsible for handling one part).
227      *
228      * <p>
229      * The model guarantees that only at most one {@link EndpointArgumentsBuilder} will
230      * return a value as a return value (and everything else has to go to
231      * {@link Holder}s.)
232      */
233     public static final class Composite extends EndpointArgumentsBuilder {
234         private final EndpointArgumentsBuilder[] builders;
235 
236         public Composite(EndpointArgumentsBuilder... builders) {
237             this.builders = builders;
238         }
239 
240         public Composite(Collection<? extends EndpointArgumentsBuilder> builders) {
241             this(builders.toArray(new EndpointArgumentsBuilder[builders.size()]));
242         }
243 
244         public void readRequest(Message msg, Object[] args) throws JAXBException, XMLStreamException {
245             for (EndpointArgumentsBuilder builder : builders) {
246                 builder.readRequest(msg,args);
247             }
248         }
249     }
250 
251 
252     /**
253      * Reads an Attachment into a Java parameter.
254      */
255     public static abstract class AttachmentBuilder extends EndpointArgumentsBuilder {
256         protected final EndpointValueSetter setter;
257         protected final ParameterImpl param;
258         protected final String pname;
259         protected final String pname1;
260 
261         AttachmentBuilder(ParameterImpl param, EndpointValueSetter setter) {
262             this.setter = setter;
263             this.param = param;
264             this.pname = param.getPartName();
265             this.pname1 = "<"+pname;
266         }
267 
268         /**
269          * Creates an AttachmentBuilder based on the parameter type
270          *
271          * @param param
272          *      runtime Parameter that abstracts the annotated java parameter
273          * @param setter
274          *      specifies how the obtained value is set into the argument. Takes
275          *      care of Holder arguments.
276          */
277         public static EndpointArgumentsBuilder createAttachmentBuilder(ParameterImpl param, EndpointValueSetter setter) {
278             Class type = (Class)param.getTypeInfo().type;
279             if (DataHandler.class.isAssignableFrom(type)) {
280                 return new DataHandlerBuilder(param, setter);
281             } else if (byte[].class==type) {
282                 return new ByteArrayBuilder(param, setter);
283             } else if(Source.class.isAssignableFrom(type)) {
284                 return new SourceBuilder(param, setter);
285             } else if(Image.class.isAssignableFrom(type)) {
286                 return new ImageBuilder(param, setter);
287             } else if(InputStream.class==type) {
288                 return new InputStreamBuilder(param, setter);
289             } else if(isXMLMimeType(param.getBinding().getMimeType())) {
290                 return new JAXBBuilder(param, setter);
291             } else if(String.class.isAssignableFrom(type)) {
292                 return new StringBuilder(param, setter);
293             } else {
294                 throw new UnsupportedOperationException("Unknown Type="+type+" Attachment is not mapped.");
295             }
296         }
297 
298         public void readRequest(Message msg, Object[] args) throws JAXBException, XMLStreamException {
299             boolean foundAttachment = false;
300             // TODO not to loop
301             for (Attachment att : msg.getAttachments()) {
302                 String part = getWSDLPartName(att);
303                 if (part == null) {
304                     continue;
305                 }
306                 if(part.equals(pname) || part.equals(pname1)){
307                     foundAttachment = true;
308                     mapAttachment(att, args);
309                     break;
310                 }
311             }
312             if (!foundAttachment) {
313                 throw new WebServiceException("Missing Attachment for "+pname);
314             }
315         }
316 
317         abstract void mapAttachment(Attachment att, Object[] args) throws JAXBException;
318     }
319 
320     private static final class DataHandlerBuilder extends AttachmentBuilder {
321         DataHandlerBuilder(ParameterImpl param, EndpointValueSetter setter) {
322             super(param, setter);
323         }
324 
325         void mapAttachment(Attachment att, Object[] args) {
326             setter.put(att.asDataHandler(), args);
327         }
328     }
329 
330     private static final class ByteArrayBuilder extends AttachmentBuilder {
331         ByteArrayBuilder(ParameterImpl param, EndpointValueSetter setter) {
332             super(param, setter);
333         }
334 
335         void mapAttachment(Attachment att, Object[] args) {
336             setter.put(att.asByteArray(), args);
337         }
338     }
339 
340     private static final class SourceBuilder extends AttachmentBuilder {
341         SourceBuilder(ParameterImpl param, EndpointValueSetter setter) {
342             super(param, setter);
343         }
344 
345         void mapAttachment(Attachment att, Object[] args) {
346             setter.put(att.asSource(), args);
347         }
348     }
349 
350     private static final class ImageBuilder extends AttachmentBuilder {
351         ImageBuilder(ParameterImpl param, EndpointValueSetter setter) {
352             super(param, setter);
353         }
354 
355         void mapAttachment(Attachment att, Object[] args) {
356             Image image;
357             InputStream is = null;
358             try {
359                 is = att.asInputStream();
360                 image = ImageIO.read(is);
361             } catch(IOException ioe) {
362                 throw new WebServiceException(ioe);
363             } finally {
364                 if (is != null) {
365                     try {
366                         is.close();
367                     } catch(IOException ioe) {
368                         throw new WebServiceException(ioe);
369                     }
370                 }
371             }
372             setter.put(image, args);
373         }
374     }
375 
376     private static final class InputStreamBuilder extends AttachmentBuilder {
377         InputStreamBuilder(ParameterImpl param, EndpointValueSetter setter) {
378             super(param, setter);
379         }
380 
381         void mapAttachment(Attachment att, Object[] args) {
382             setter.put(att.asInputStream(), args);
383         }
384     }
385 
386     private static final class JAXBBuilder extends AttachmentBuilder {
387         JAXBBuilder(ParameterImpl param, EndpointValueSetter setter) {
388             super(param, setter);
389         }
390 
391         void mapAttachment(Attachment att, Object[] args) throws JAXBException {
392             Object obj = param.getXMLBridge().unmarshal(att.asInputStream());
393             setter.put(obj, args);
394         }
395     }
396 
397     private static final class StringBuilder extends AttachmentBuilder {
398         StringBuilder(ParameterImpl param, EndpointValueSetter setter) {
399             super(param, setter);
400         }
401 
402         void mapAttachment(Attachment att, Object[] args) {
403             att.getContentType();
404             StringDataContentHandler sdh = new StringDataContentHandler();
405             try {
406                 String str = (String)sdh.getContent(new DataHandlerDataSource(att.asDataHandler()));
407                 setter.put(str, args);
408             } catch(Exception e) {
409                 throw new WebServiceException(e);
410             }
411         }
412     }
413 
414     /**
415      * Gets the WSDL part name of this attachment.
416      *
417      * <p>
418      * According to WSI AP 1.0
419      * <PRE>
420      * 3.8 Value-space of Content-Id Header
421      *   Definition: content-id part encoding
422      *   The "content-id part encoding" consists of the concatenation of:
423      * 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:
424      *     o Each disallowed character is converted to UTF-8 as one or more bytes.
425      *     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).
426      *     o The original character is replaced by the resulting character sequence.
427      * The character '=' (0x3D).
428      * A globally unique value such as a UUID.
429      * The character '@' (0x40).
430      * A valid domain name under the authority of the entity constructing the message.
431      * </PRE>
432      *
433      * So a wsdl:part fooPart will be encoded as:
434      *      <fooPart=somereallybignumberlikeauuid@example.com>
435      *
436      * @return null
437      *      if the parsing fails.
438      */
439     public static final String getWSDLPartName(com.sun.xml.internal.ws.api.message.Attachment att){
440         String cId = att.getContentId();
441 
442         int index = cId.lastIndexOf('@', cId.length());
443         if(index == -1){
444             return null;
445         }
446         String localPart = cId.substring(0, index);
447         index = localPart.lastIndexOf('=', localPart.length());
448         if(index == -1){
449             return null;
450         }
451         try {
452             return java.net.URLDecoder.decode(localPart.substring(0, index), "UTF-8");
453         } catch (UnsupportedEncodingException e) {
454             throw new WebServiceException(e);
455         }
456     }
457 
458 
459 
460 
461     /**
462      * Reads a header into a JAXB object.
463      */
464     public static final class Header extends EndpointArgumentsBuilder {
465         private final XMLBridge<?> bridge;
466         private final EndpointValueSetter setter;
467         private final QName headerName;
468         private final SOAPVersion soapVersion;
469 
470         /**
471          * @param name
472          *      The name of the header element.
473          * @param bridge
474          *      specifies how to unmarshal a header into a JAXB object.
475          * @param setter
476          *      specifies how the obtained value is returned to the client.
477          */
478         public Header(SOAPVersion soapVersion, QName name, XMLBridge<?> bridge, EndpointValueSetter setter) {
479             this.soapVersion = soapVersion;
480             this.headerName = name;
481             this.bridge = bridge;
482             this.setter = setter;
483         }
484 
485         public Header(SOAPVersion soapVersion, ParameterImpl param, EndpointValueSetter setter) {
486             this(
487                 soapVersion,
488                 param.getTypeInfo().tagName,
489                 param.getXMLBridge(),
490                 setter);
491             assert param.getOutBinding()== ParameterBinding.HEADER;
492         }
493 
494         private SOAPFaultException createDuplicateHeaderException() {
495             try {
496                 SOAPFault fault = soapVersion.getSOAPFactory().createFault();
497                 fault.setFaultCode(soapVersion.faultCodeClient);
498                 fault.setFaultString(ServerMessages.DUPLICATE_PORT_KNOWN_HEADER(headerName));
499                 return new SOAPFaultException(fault);
500             } catch(SOAPException e) {
501                 throw new WebServiceException(e);
502             }
503         }
504 
505         public void readRequest(Message msg, Object[] args) throws JAXBException {
506             com.sun.xml.internal.ws.api.message.Header header = null;
507             Iterator<com.sun.xml.internal.ws.api.message.Header> it =
508                 msg.getHeaders().getHeaders(headerName,true);
509             if (it.hasNext()) {
510                 header = it.next();
511                 if (it.hasNext()) {
512                     throw createDuplicateHeaderException();
513                 }
514             }
515 
516             if(header!=null) {
517                 setter.put( header.readAsJAXB(bridge), args );
518             } else {
519                 // header not found.
520             }
521         }
522     }
523 
524     /**
525      * Reads the whole payload into a single JAXB bean.
526      */
527     public static final class Body extends EndpointArgumentsBuilder {
528         private final XMLBridge<?> bridge;
529         private final EndpointValueSetter setter;
530 
531         /**
532          * @param bridge
533          *      specifies how to unmarshal the payload into a JAXB object.
534          * @param setter
535          *      specifies how the obtained value is returned to the client.
536          */
537         public Body(XMLBridge<?> bridge, EndpointValueSetter setter) {
538             this.bridge = bridge;
539             this.setter = setter;
540         }
541 
542         public void readRequest(Message msg, Object[] args) throws JAXBException {
543             setter.put( msg.readPayloadAsJAXB(bridge), args );
544         }
545     }
546 
547     /**
548      * Treats a payload as multiple parts wrapped into one element,
549      * and processes all such wrapped parts.
550      */
551     public static final class DocLit extends EndpointArgumentsBuilder {
552         /**
553          * {@link PartBuilder} keyed by the element name (inside the wrapper element.)
554          */
555         private final PartBuilder[] parts;
556 
557         private final XMLBridge wrapper;
558         private boolean dynamicWrapper;
559 
560         public DocLit(WrapperParameter wp, Mode skipMode) {
561             wrapperName = wp.getName();
562             wrapper = wp.getXMLBridge();
563             Class wrapperType = (Class) wrapper.getTypeInfo().type;
564             dynamicWrapper = WrapperComposite.class.equals(wrapperType);
565             List<PartBuilder> parts = new ArrayList<PartBuilder>();
566             List<ParameterImpl> children = wp.getWrapperChildren();
567             for (ParameterImpl p : children) {
568                 if (p.getMode() == skipMode) {
569                     continue;
570                 }
571                 /*
572                 if(p.isIN())
573                     continue;
574                  */
575                 QName name = p.getName();
576                 try {
577                     if (dynamicWrapper) {
578                         if (wrappedParts == null) wrappedParts = new HashMap<QName,WrappedPartBuilder>();
579                         XMLBridge xmlBridge = p.getInlinedRepeatedElementBridge();
580                         if (xmlBridge == null) xmlBridge = p.getXMLBridge();
581                         wrappedParts.put( p.getName(), new WrappedPartBuilder(xmlBridge, EndpointValueSetter.get(p)));
582                     } else {
583                         parts.add( new PartBuilder(
584                                 wp.getOwner().getBindingContext().getElementPropertyAccessor(
585                                     wrapperType,
586                                     name.getNamespaceURI(),
587                                     p.getName().getLocalPart()),
588                                 EndpointValueSetter.get(p)
589                             ) );
590                     // wrapper parameter itself always bind to body, and
591                     // so do all its children
592                         assert p.getBinding()== ParameterBinding.BODY;
593                     }
594                 } catch (JAXBException e) {
595                     throw new WebServiceException(  // TODO: i18n
596                         wrapperType+" do not have a property of the name "+name,e);
597                 }
598             }
599 
600             this.parts = parts.toArray(new PartBuilder[parts.size()]);
601         }
602 
603         public void readRequest(Message msg, Object[] args) throws JAXBException, XMLStreamException {
604             if (dynamicWrapper) {
605                 readWrappedRequest(msg, args);
606             } else {
607                 if (parts.length>0) {
608                     if (!msg.hasPayload()) {
609                         throw new WebServiceException("No payload. Expecting payload with "+wrapperName+" element");
610                     }
611                     XMLStreamReader reader = msg.readPayload();
612                     XMLStreamReaderUtil.verifyTag(reader, wrapperName);
613                     Object wrapperBean = wrapper.unmarshal(reader, (msg.getAttachments() != null) ?
614                             new AttachmentUnmarshallerImpl(msg.getAttachments()): null);
615 
616                     try {
617                         for (PartBuilder part : parts) {
618                             part.readRequest(args,wrapperBean);
619                         }
620                     } catch (DatabindingException e) {
621                         // this can happen when the set method throw a checked exception or something like that
622                         throw new WebServiceException(e);    // TODO:i18n
623                     }
624 
625                     // we are done with the body
626                     reader.close();
627                     XMLStreamReaderFactory.recycle(reader);
628                 } else {
629                     msg.consume();
630                 }
631             }
632         }
633 
634         /**
635          * Unmarshals each wrapped part into a JAXB object and moves it
636          * to the expected place.
637          */
638         static final class PartBuilder {
639             private final PropertyAccessor accessor;
640             private final EndpointValueSetter setter;
641 
642             /**
643              * @param accessor
644              *      specifies which portion of the wrapper bean to obtain the value from.
645              * @param setter
646              *      specifies how the obtained value is returned to the client.
647              */
648             public PartBuilder(PropertyAccessor accessor, EndpointValueSetter setter) {
649                 this.accessor = accessor;
650                 this.setter = setter;
651                 assert accessor!=null && setter!=null;
652             }
653 
654             final void readRequest( Object[] args, Object wrapperBean ) {
655                 Object obj = accessor.get(wrapperBean);
656                 setter.put(obj,args);
657             }
658 
659 
660         }
661     }
662 
663     /**
664      * Treats a payload as multiple parts wrapped into one element,
665      * and processes all such wrapped parts.
666      */
667     public static final class RpcLit extends EndpointArgumentsBuilder {
668         public RpcLit(WrapperParameter wp) {
669             assert wp.getTypeInfo().type== WrapperComposite.class;
670 
671             wrapperName = wp.getName();
672             wrappedParts = new HashMap<QName,WrappedPartBuilder>();
673             List<ParameterImpl> children = wp.getWrapperChildren();
674             for (ParameterImpl p : children) {
675                 wrappedParts.put( p.getName(), new WrappedPartBuilder(
676                     p.getXMLBridge(), EndpointValueSetter.get(p)
677                 ));
678                 // wrapper parameter itself always bind to body, and
679                 // so do all its children
680                 assert p.getBinding()== ParameterBinding.BODY;
681             }
682         }
683 
684         public void readRequest(Message msg, Object[] args) throws JAXBException, XMLStreamException {
685             readWrappedRequest(msg, args);
686         }
687     }
688 
689     private static boolean isXMLMimeType(String mimeType){
690         return mimeType.equals("text/xml") || mimeType.equals("application/xml");
691     }
692 }