001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.xml.ws.client.sei;
038:
039: import com.sun.xml.bind.api.AccessorException;
040: import com.sun.xml.bind.api.Bridge;
041: import com.sun.xml.bind.api.CompositeStructure;
042: import com.sun.xml.bind.api.RawAccessor;
043: import com.sun.xml.ws.api.SOAPVersion;
044: import com.sun.xml.ws.api.message.Message;
045: import com.sun.xml.ws.api.message.Messages;
046: import com.sun.xml.ws.message.jaxb.JAXBMessage;
047: import com.sun.xml.ws.model.ParameterImpl;
048: import com.sun.xml.ws.model.WrapperParameter;
049:
050: import javax.xml.bind.JAXBException;
051: import javax.xml.namespace.QName;
052: import javax.xml.ws.Holder;
053: import javax.xml.ws.WebServiceException;
054: import java.util.List;
055:
056: /**
057: * Builds a JAXB object that represents the payload.
058: *
059: * @see MessageFiller
060: * @author Kohsuke Kawaguchi
061: */
062: abstract class BodyBuilder {
063: abstract Message createMessage(Object[] methodArgs);
064:
065: static final BodyBuilder EMPTY_SOAP11 = new Empty(
066: SOAPVersion.SOAP_11);
067: static final BodyBuilder EMPTY_SOAP12 = new Empty(
068: SOAPVersion.SOAP_12);
069:
070: private static final class Empty extends BodyBuilder {
071: private final SOAPVersion soapVersion;
072:
073: public Empty(SOAPVersion soapVersion) {
074: this .soapVersion = soapVersion;
075: }
076:
077: Message createMessage(Object[] methodArgs) {
078: return Messages.createEmpty(soapVersion);
079: }
080: }
081:
082: /**
083: * Base class for those {@link BodyBuilder}s that build a {@link Message}
084: * from JAXB objects.
085: */
086: private static abstract class JAXB extends BodyBuilder {
087: /**
088: * This object determines the binding of the object returned
089: * from {@link #build(Object[])}.
090: */
091: private final Bridge bridge;
092: private final SOAPVersion soapVersion;
093:
094: protected JAXB(Bridge bridge, SOAPVersion soapVersion) {
095: assert bridge != null;
096: this .bridge = bridge;
097: this .soapVersion = soapVersion;
098: }
099:
100: final Message createMessage(Object[] methodArgs) {
101: return JAXBMessage.create(bridge, build(methodArgs),
102: soapVersion);
103: }
104:
105: /**
106: * Builds a JAXB object that becomes the payload.
107: */
108: abstract Object build(Object[] methodArgs);
109: }
110:
111: /**
112: * Used to create a payload JAXB object just by taking
113: * one of the parameters.
114: */
115: final static class Bare extends JAXB {
116: /**
117: * The index of the method invocation parameters that goes into the payload.
118: */
119: private final int methodPos;
120:
121: private final ValueGetter getter;
122:
123: /**
124: * Creates a {@link BodyBuilder} from a bare parameter.
125: */
126: Bare(ParameterImpl p, SOAPVersion soapVersion,
127: ValueGetter getter) {
128: super (p.getBridge(), soapVersion);
129: this .methodPos = p.getIndex();
130: this .getter = getter;
131: }
132:
133: /**
134: * Picks up an object from the method arguments and uses it.
135: */
136: Object build(Object[] methodArgs) {
137: return getter.get(methodArgs[methodPos]);
138: }
139: }
140:
141: /**
142: * Used to handle a 'wrapper' style request.
143: * Common part of rpc/lit and doc/lit.
144: */
145: abstract static class Wrapped extends JAXB {
146:
147: /**
148: * Where in the method argument list do they come from?
149: */
150: protected final int[] indices;
151:
152: /**
153: * Abstracts away the {@link Holder} handling when touching method arguments.
154: */
155: protected final ValueGetter[] getters;
156:
157: protected Wrapped(WrapperParameter wp, SOAPVersion soapVersion,
158: ValueGetterFactory getter) {
159: super (wp.getBridge(), soapVersion);
160:
161: List<ParameterImpl> children = wp.getWrapperChildren();
162:
163: indices = new int[children.size()];
164: getters = new ValueGetter[children.size()];
165: for (int i = 0; i < indices.length; i++) {
166: ParameterImpl p = children.get(i);
167: indices[i] = p.getIndex();
168: getters[i] = getter.get(p);
169: }
170: }
171: }
172:
173: /**
174: * Used to create a payload JAXB object by wrapping
175: * multiple parameters into one "wrapper bean".
176: */
177: final static class DocLit extends Wrapped {
178: /**
179: * How does each wrapped parameter binds to XML?
180: */
181: private final RawAccessor[] accessors;
182:
183: /**
184: * Wrapper bean.
185: */
186: private final Class wrapper;
187:
188: /**
189: * Creates a {@link BodyBuilder} from a {@link WrapperParameter}.
190: */
191: DocLit(WrapperParameter wp, SOAPVersion soapVersion,
192: ValueGetterFactory getter) {
193: super (wp, soapVersion, getter);
194:
195: wrapper = (Class) wp.getBridge().getTypeReference().type;
196:
197: List<ParameterImpl> children = wp.getWrapperChildren();
198:
199: accessors = new RawAccessor[children.size()];
200: for (int i = 0; i < accessors.length; i++) {
201: ParameterImpl p = children.get(i);
202: QName name = p.getName();
203: try {
204: accessors[i] = p.getOwner().getJAXBContext()
205: .getElementPropertyAccessor(wrapper,
206: name.getNamespaceURI(),
207: name.getLocalPart());
208: } catch (JAXBException e) {
209: throw new WebServiceException( // TODO: i18n
210: wrapper
211: + " do not have a property of the name "
212: + name, e);
213: }
214: }
215:
216: }
217:
218: /**
219: * Packs a bunch of arguments into a {@link CompositeStructure}.
220: */
221: Object build(Object[] methodArgs) {
222: try {
223: Object bean = wrapper.newInstance();
224:
225: // fill in wrapped parameters from methodArgs
226: for (int i = indices.length - 1; i >= 0; i--) {
227: accessors[i].set(bean, getters[i]
228: .get(methodArgs[indices[i]]));
229: }
230:
231: return bean;
232: } catch (InstantiationException e) {
233: // this is irrecoverable
234: Error x = new InstantiationError(e.getMessage());
235: x.initCause(e);
236: throw x;
237: } catch (IllegalAccessException e) {
238: // this is irrecoverable
239: Error x = new IllegalAccessError(e.getMessage());
240: x.initCause(e);
241: throw x;
242: } catch (AccessorException e) {
243: // this can happen when the set method throw a checked exception or something like that
244: throw new WebServiceException(e); // TODO:i18n
245: }
246: }
247: }
248:
249: /**
250: * Used to create a payload JAXB object by wrapping
251: * multiple parameters into a {@link CompositeStructure}.
252: *
253: * <p>
254: * This is used for rpc/lit, as we don't have a wrapper bean for it.
255: * (TODO: Why don't we have a wrapper bean for this, when doc/lit does!?)
256: */
257: final static class RpcLit extends Wrapped {
258: /**
259: * How does each wrapped parameter binds to XML?
260: */
261: private final Bridge[] parameterBridges;
262:
263: /**
264: * List of Parameters packed in the body.
265: * Only used for error diagnostics.
266: */
267: private final List<ParameterImpl> children;
268:
269: /**
270: * Creates a {@link BodyBuilder} from a {@link WrapperParameter}.
271: */
272: RpcLit(WrapperParameter wp, SOAPVersion soapVersion,
273: ValueGetterFactory getter) {
274: super (wp, soapVersion, getter);
275: // we'll use CompositeStructure to pack requests
276: assert wp.getTypeReference().type == CompositeStructure.class;
277:
278: this .children = wp.getWrapperChildren();
279:
280: parameterBridges = new Bridge[children.size()];
281: for (int i = 0; i < parameterBridges.length; i++)
282: parameterBridges[i] = children.get(i).getBridge();
283: }
284:
285: /**
286: * Packs a bunch of arguments intoa {@link CompositeStructure}.
287: */
288: CompositeStructure build(Object[] methodArgs) {
289: CompositeStructure cs = new CompositeStructure();
290: cs.bridges = parameterBridges;
291: cs.values = new Object[parameterBridges.length];
292:
293: // fill in wrapped parameters from methodArgs
294: for (int i = indices.length - 1; i >= 0; i--) {
295: Object arg = getters[i].get(methodArgs[indices[i]]);
296: if (arg == null) {
297: throw new WebServiceException(
298: "Method Parameter: "
299: + children.get(i).getName()
300: + " cannot be null. This is BP 1.1 R2211 violation.");
301: }
302: cs.values[i] = arg;
303: }
304:
305: return cs;
306: }
307: }
308: }
|