View Javadoc
1   /*
2    * Copyright (c) 1997, 2012, 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.client.sei;
27  
28  import com.sun.xml.internal.ws.api.SOAPVersion;
29  import com.sun.xml.internal.ws.api.message.Message;
30  import com.sun.xml.internal.ws.api.message.Messages;
31  import com.sun.xml.internal.ws.message.jaxb.JAXBMessage;
32  import com.sun.xml.internal.ws.model.ParameterImpl;
33  import com.sun.xml.internal.ws.model.WrapperParameter;
34  import com.sun.xml.internal.ws.spi.db.BindingContext;
35  import com.sun.xml.internal.ws.spi.db.XMLBridge;
36  import com.sun.xml.internal.ws.spi.db.PropertyAccessor;
37  import com.sun.xml.internal.ws.spi.db.WrapperComposite;
38  
39  import javax.xml.bind.JAXBException;
40  import javax.xml.namespace.QName;
41  import javax.xml.ws.Holder;
42  import javax.xml.ws.WebServiceException;
43  import java.util.List;
44  
45  /**
46   * Builds a JAXB object that represents the payload.
47   *
48   * @see MessageFiller
49   * @author Kohsuke Kawaguchi
50   */
51  abstract class BodyBuilder {
52      abstract Message createMessage(Object[] methodArgs);
53  
54      static final BodyBuilder EMPTY_SOAP11 = new Empty(SOAPVersion.SOAP_11);
55      static final BodyBuilder EMPTY_SOAP12 = new Empty(SOAPVersion.SOAP_12);
56  
57      private static final class Empty extends BodyBuilder {
58          private final SOAPVersion soapVersion;
59  
60          public Empty(SOAPVersion soapVersion) {
61              this.soapVersion = soapVersion;
62          }
63  
64          Message createMessage(Object[] methodArgs) {
65              return Messages.createEmpty(soapVersion);
66          }
67      }
68  
69      /**
70       * Base class for those {@link BodyBuilder}s that build a {@link Message}
71       * from JAXB objects.
72       */
73      private static abstract class JAXB extends BodyBuilder {
74          /**
75           * This object determines the binding of the object returned
76           * from {@link #build(Object[])}.
77           */
78          private final XMLBridge bridge;
79          private final SOAPVersion soapVersion;
80  
81          protected JAXB(XMLBridge bridge, SOAPVersion soapVersion) {
82              assert bridge!=null;
83              this.bridge = bridge;
84              this.soapVersion = soapVersion;
85          }
86  
87          final Message createMessage(Object[] methodArgs) {
88              return JAXBMessage.create( bridge, build(methodArgs), soapVersion );
89          }
90  
91          /**
92           * Builds a JAXB object that becomes the payload.
93           */
94          abstract Object build(Object[] methodArgs);
95      }
96  
97      /**
98       * Used to create a payload JAXB object just by taking
99       * one of the parameters.
100      */
101     final static class Bare extends JAXB {
102         /**
103          * The index of the method invocation parameters that goes into the payload.
104          */
105         private final int methodPos;
106 
107         private final ValueGetter getter;
108 
109         /**
110          * Creates a {@link BodyBuilder} from a bare parameter.
111          */
112         Bare(ParameterImpl p, SOAPVersion soapVersion, ValueGetter getter) {
113             super(p.getXMLBridge(), soapVersion);
114             this.methodPos = p.getIndex();
115             this.getter = getter;
116         }
117 
118         /**
119          * Picks up an object from the method arguments and uses it.
120          */
121         Object build(Object[] methodArgs) {
122             return getter.get(methodArgs[methodPos]);
123         }
124     }
125 
126 
127     /**
128      * Used to handle a 'wrapper' style request.
129      * Common part of rpc/lit and doc/lit.
130      */
131     abstract static class Wrapped extends JAXB {
132 
133         /**
134          * Where in the method argument list do they come from?
135          */
136         protected final int[] indices;
137 
138         /**
139          * Abstracts away the {@link Holder} handling when touching method arguments.
140          */
141         protected final ValueGetter[] getters;
142 
143         /**
144          * How does each wrapped parameter binds to XML?
145          */
146         protected XMLBridge[] parameterBridges;
147 
148         /**
149          * List of Parameters packed in the body.
150          * Only used for error diagnostics.
151          */
152         protected List<ParameterImpl> children;
153 
154         protected Wrapped(WrapperParameter wp, SOAPVersion soapVersion, ValueGetterFactory getter) {
155             super(wp.getXMLBridge(), soapVersion);
156             children = wp.getWrapperChildren();
157             indices = new int[children.size()];
158             getters = new ValueGetter[children.size()];
159             for( int i=0; i<indices.length; i++ ) {
160                 ParameterImpl p = children.get(i);
161                 indices[i] = p.getIndex();
162                 getters[i] = getter.get(p);
163             }
164         }
165 
166         /**
167          * Packs a bunch of arguments into a {@link WrapperComposite}.
168          */
169         protected WrapperComposite buildWrapperComposite(Object[] methodArgs) {
170             WrapperComposite cs = new WrapperComposite();
171             cs.bridges = parameterBridges;
172             cs.values = new Object[parameterBridges.length];
173 
174             // fill in wrapped parameters from methodArgs
175             for( int i=indices.length-1; i>=0; i-- ) {
176                 Object arg = getters[i].get(methodArgs[indices[i]]);
177                 if(arg==null) {
178                     throw new WebServiceException("Method Parameter: "+
179                         children.get(i).getName()+" cannot be null. This is BP 1.1 R2211 violation.");
180                 }
181                 cs.values[i] = arg;
182             }
183 
184             return cs;
185         }
186     }
187 
188     /**
189      * Used to create a payload JAXB object by wrapping
190      * multiple parameters into one "wrapper bean".
191      */
192     final static class DocLit extends Wrapped {
193         /**
194          * How does each wrapped parameter binds to XML?
195          */
196         private final PropertyAccessor[] accessors;
197 
198         /**
199          * Wrapper bean.
200          */
201         private final Class wrapper;
202 
203         /**
204          * Needed to get wrapper instantiation method.
205          */
206         private BindingContext bindingContext;
207         private boolean dynamicWrapper;
208 
209         /**
210          * Creates a {@link BodyBuilder} from a {@link WrapperParameter}.
211          */
212         DocLit(WrapperParameter wp, SOAPVersion soapVersion, ValueGetterFactory getter) {
213             super(wp, soapVersion, getter);
214             bindingContext = wp.getOwner().getBindingContext();
215             wrapper = (Class)wp.getXMLBridge().getTypeInfo().type;
216             dynamicWrapper = WrapperComposite.class.equals(wrapper);
217             parameterBridges = new XMLBridge[children.size()];
218             accessors = new PropertyAccessor[children.size()];
219             for( int i=0; i<accessors.length; i++ ) {
220                 ParameterImpl p = children.get(i);
221                 QName name = p.getName();
222                 if (dynamicWrapper) {
223                     parameterBridges[i] = children.get(i).getInlinedRepeatedElementBridge();
224                     if (parameterBridges[i] == null) parameterBridges[i] = children.get(i).getXMLBridge();
225                 } else {
226                     try {
227                         accessors[i] = p.getOwner().getBindingContext().getElementPropertyAccessor(
228                             wrapper, name.getNamespaceURI(), name.getLocalPart() );
229                     } catch (JAXBException e) {
230                         throw new WebServiceException(  // TODO: i18n
231                             wrapper+" do not have a property of the name "+name,e);
232                     }
233                 }
234             }
235 
236         }
237 
238         /**
239          * Packs a bunch of arguments into a {@link WrapperComposite}.
240          */
241         Object build(Object[] methodArgs) {
242             if (dynamicWrapper) return buildWrapperComposite(methodArgs);
243             try {
244                 //Object bean = wrapper.newInstance();
245                 Object bean = bindingContext.newWrapperInstace(wrapper);
246 
247                 // fill in wrapped parameters from methodArgs
248                 for( int i=indices.length-1; i>=0; i-- ) {
249                     accessors[i].set(bean,getters[i].get(methodArgs[indices[i]]));
250                 }
251 
252                 return bean;
253             } catch (InstantiationException e) {
254                 // this is irrecoverable
255                 Error x = new InstantiationError(e.getMessage());
256                 x.initCause(e);
257                 throw x;
258             } catch (IllegalAccessException e) {
259                 // this is irrecoverable
260                 Error x = new IllegalAccessError(e.getMessage());
261                 x.initCause(e);
262                 throw x;
263             } catch (com.sun.xml.internal.ws.spi.db.DatabindingException e) {
264                 // this can happen when the set method throw a checked exception or something like that
265                 throw new WebServiceException(e);    // TODO:i18n
266             }
267         }
268     }
269 
270 
271     /**
272      * Used to create a payload JAXB object by wrapping
273      * multiple parameters into a {@link WrapperComposite}.
274      *
275      * <p>
276      * This is used for rpc/lit, as we don't have a wrapper bean for it.
277      * (TODO: Why don't we have a wrapper bean for this, when doc/lit does!?)
278      */
279     final static class RpcLit extends Wrapped {
280 
281         /**
282          * Creates a {@link BodyBuilder} from a {@link WrapperParameter}.
283          */
284         RpcLit(WrapperParameter wp, SOAPVersion soapVersion, ValueGetterFactory getter) {
285             super(wp, soapVersion, getter);
286             // we'll use CompositeStructure to pack requests
287             assert wp.getTypeInfo().type==WrapperComposite.class;
288 
289             parameterBridges = new XMLBridge[children.size()];
290             for( int i=0; i<parameterBridges.length; i++ )
291                 parameterBridges[i] = children.get(i).getXMLBridge();
292         }
293 
294         Object build(Object[] methodArgs) {
295             return buildWrapperComposite(methodArgs);
296         }
297     }
298 }