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