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
26package com.sun.xml.internal.ws.server.sei;
27
28import com.sun.xml.internal.ws.api.SOAPVersion;
29import com.sun.xml.internal.ws.api.message.Attachment;
30import com.sun.xml.internal.ws.api.message.AttachmentSet;
31import com.sun.xml.internal.ws.api.message.Message;
32import com.sun.xml.internal.ws.api.model.ParameterBinding;
33import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory;
34import com.sun.xml.internal.ws.message.AttachmentUnmarshallerImpl;
35import com.sun.xml.internal.ws.model.ParameterImpl;
36import com.sun.xml.internal.ws.model.WrapperParameter;
37import com.sun.xml.internal.ws.resources.ServerMessages;
38import com.sun.xml.internal.ws.spi.db.RepeatedElementBridge;
39import com.sun.xml.internal.ws.spi.db.XMLBridge;
40import com.sun.xml.internal.ws.spi.db.DatabindingException;
41import com.sun.xml.internal.ws.spi.db.PropertyAccessor;
42import com.sun.xml.internal.ws.spi.db.WrapperComposite;
43import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil;
44import com.sun.xml.internal.ws.encoding.StringDataContentHandler;
45import com.sun.xml.internal.ws.encoding.DataHandlerDataSource;
46
47import javax.activation.DataHandler;
48import javax.imageio.ImageIO;
49import javax.jws.WebParam.Mode;
50import javax.xml.bind.JAXBException;
51import javax.xml.namespace.QName;
52import javax.xml.soap.SOAPException;
53import javax.xml.soap.SOAPFault;
54import javax.xml.stream.XMLStreamException;
55import javax.xml.stream.XMLStreamReader;
56import javax.xml.transform.Source;
57import javax.xml.ws.Holder;
58import javax.xml.ws.WebServiceException;
59import javax.xml.ws.soap.SOAPFaultException;
60import java.awt.Image;
61import java.io.IOException;
62import java.io.InputStream;
63import java.io.UnsupportedEncodingException;
64import java.lang.reflect.Type;
65import java.util.ArrayList;
66import java.util.Collection;
67import java.util.HashMap;
68import java.util.Iterator;
69import java.util.List;
70import 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 */
78public 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}
693