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.server.sei;
038:
039: import com.sun.xml.ws.api.SOAPVersion;
040: import com.sun.xml.ws.api.WSBinding;
041: import com.sun.xml.ws.api.message.Message;
042: import com.sun.xml.ws.api.message.Packet;
043: import com.sun.xml.ws.api.model.SEIModel;
044: import com.sun.xml.ws.encoding.soap.DeserializationException;
045: import com.sun.xml.ws.fault.SOAPFaultBuilder;
046: import com.sun.xml.ws.message.jaxb.JAXBMessage;
047: import com.sun.xml.ws.model.JavaMethodImpl;
048: import com.sun.xml.ws.model.ParameterImpl;
049: import com.sun.xml.ws.model.WrapperParameter;
050:
051: import javax.jws.WebParam.Mode;
052: import javax.xml.bind.JAXBException;
053: import javax.xml.stream.XMLStreamException;
054: import javax.xml.ws.Holder;
055: import java.lang.reflect.InvocationTargetException;
056: import java.lang.reflect.Method;
057: import java.util.ArrayList;
058: import java.util.List;
059: import java.util.logging.Level;
060: import java.util.logging.Logger;
061:
062: /**
063: *
064: * <p>
065: * This class mainly performs the following two tasks:
066: * <ol>
067: * <li>Takes a {@link Message] that represents a request,
068: * and extracts the arguments (and updates {@link Holder}s.)
069: * <li>Accepts return value and {@link Holder} arguments for a Java method,
070: * and creates {@link JAXBMessage} that represents a response message.
071: * </ol>
072: *
073: * <h2>Creating {@link JAXBMessage}</h2>
074: * <p>
075: * At the construction time, we prepare {@link EndpointArgumentsBuilder} that knows how to create endpoint {@link Method}
076: * invocation arguments.
077: * we also prepare {@link EndpointResponseMessageBuilder} and {@link MessageFiller}s
078: * that know how to move arguments into a {@link Message}.
079: * Some arguments go to the payload, some go to headers, still others go to attachments.
080: *
081: * @author Jitendra Kotamraju
082: */
083: final class EndpointMethodHandler {
084:
085: private final SOAPVersion soapVersion;
086: private final Method method;
087: private final int noOfArgs;
088: private final JavaMethodImpl javaMethodModel;
089:
090: private final Boolean isOneWay;
091:
092: // Converts {@link Message} --> Object[]
093: private final EndpointArgumentsBuilder argumentsBuilder;
094:
095: // these objects together create a response message from method parameters
096: private final EndpointResponseMessageBuilder bodyBuilder;
097: private final MessageFiller[] outFillers;
098:
099: private final SEIInvokerTube owner;
100:
101: public EndpointMethodHandler(SEIInvokerTube owner,
102: JavaMethodImpl method, WSBinding binding) {
103: this .owner = owner;
104: this .soapVersion = binding.getSOAPVersion();
105: this .method = method.getMethod();
106: this .javaMethodModel = method;
107: argumentsBuilder = createArgumentsBuilder();
108: List<MessageFiller> fillers = new ArrayList<MessageFiller>();
109: bodyBuilder = createResponseMessageBuilder(fillers);
110: this .outFillers = fillers.toArray(new MessageFiller[fillers
111: .size()]);
112: this .isOneWay = method.getMEP().isOneWay();
113: this .noOfArgs = this .method.getParameterTypes().length;
114: }
115:
116: /**
117: * It builds EndpointArgumentsBuilder which converts request {@link Message} to endpoint method's invocation
118: * arguments Object[]
119: *
120: * @return EndpointArgumentsBuilder
121: */
122: private EndpointArgumentsBuilder createArgumentsBuilder() {
123: EndpointArgumentsBuilder argsBuilder;
124: List<ParameterImpl> rp = javaMethodModel.getRequestParameters();
125: List<EndpointArgumentsBuilder> builders = new ArrayList<EndpointArgumentsBuilder>();
126:
127: for (ParameterImpl param : rp) {
128: EndpointValueSetter setter = EndpointValueSetter.get(param);
129: switch (param.getInBinding().kind) {
130: case BODY:
131: if (param.isWrapperStyle()) {
132: if (param.getParent().getBinding().isRpcLit())
133: builders
134: .add(new EndpointArgumentsBuilder.RpcLit(
135: (WrapperParameter) param));
136: else
137: builders
138: .add(new EndpointArgumentsBuilder.DocLit(
139: (WrapperParameter) param,
140: Mode.OUT));
141: } else {
142: builders.add(new EndpointArgumentsBuilder.Body(
143: param.getBridge(), setter));
144: }
145: break;
146: case HEADER:
147: builders.add(new EndpointArgumentsBuilder.Header(
148: soapVersion, param, setter));
149: break;
150: case ATTACHMENT:
151: builders.add(EndpointArgumentsBuilder.AttachmentBuilder
152: .createAttachmentBuilder(param, setter));
153: break;
154: case UNBOUND:
155: builders.add(new EndpointArgumentsBuilder.NullSetter(
156: setter, EndpointArgumentsBuilder
157: .getVMUninitializedValue(param
158: .getTypeReference().type)));
159: break;
160: default:
161: throw new AssertionError();
162: }
163: }
164:
165: // creates {@link Holder} arguments for OUT parameters
166: List<ParameterImpl> resp = javaMethodModel
167: .getResponseParameters();
168: for (ParameterImpl param : resp) {
169: if (param.isWrapperStyle()) {
170: WrapperParameter wp = (WrapperParameter) param;
171: List<ParameterImpl> children = wp.getWrapperChildren();
172: for (ParameterImpl p : children) {
173: if (p.isOUT() && p.getIndex() != -1) {
174: EndpointValueSetter setter = EndpointValueSetter
175: .get(p);
176: builders
177: .add(new EndpointArgumentsBuilder.NullSetter(
178: setter, null));
179: }
180: }
181: } else if (param.isOUT() && param.getIndex() != -1) {
182: EndpointValueSetter setter = EndpointValueSetter
183: .get(param);
184: builders.add(new EndpointArgumentsBuilder.NullSetter(
185: setter, null));
186: }
187: }
188:
189: switch (builders.size()) {
190: case 0:
191: argsBuilder = EndpointArgumentsBuilder.NONE;
192: break;
193: case 1:
194: argsBuilder = builders.get(0);
195: break;
196: default:
197: argsBuilder = new EndpointArgumentsBuilder.Composite(
198: builders);
199: }
200: return argsBuilder;
201: }
202:
203: /**
204: * prepare objects for creating response {@link Message}
205: */
206: private EndpointResponseMessageBuilder createResponseMessageBuilder(
207: List<MessageFiller> fillers) {
208:
209: EndpointResponseMessageBuilder bodyBuilder = null;
210: List<ParameterImpl> rp = javaMethodModel
211: .getResponseParameters();
212:
213: for (ParameterImpl param : rp) {
214: ValueGetter getter = ValueGetter.get(param);
215:
216: switch (param.getOutBinding().kind) {
217: case BODY:
218: if (param.isWrapperStyle()) {
219: if (param.getParent().getBinding().isRpcLit()) {
220: bodyBuilder = new EndpointResponseMessageBuilder.RpcLit(
221: (WrapperParameter) param, soapVersion);
222: } else {
223: bodyBuilder = new EndpointResponseMessageBuilder.DocLit(
224: (WrapperParameter) param, soapVersion);
225: }
226: } else {
227: bodyBuilder = new EndpointResponseMessageBuilder.Bare(
228: param, soapVersion);
229: }
230: break;
231: case HEADER:
232: fillers.add(new MessageFiller.Header(param.getIndex(),
233: param.getBridge(), getter));
234: break;
235: case ATTACHMENT:
236: fillers.add(MessageFiller.AttachmentFiller
237: .createAttachmentFiller(param, getter));
238: break;
239: case UNBOUND:
240: break;
241: default:
242: throw new AssertionError(); // impossible
243: }
244: }
245:
246: if (bodyBuilder == null) {
247: // no parameter binds to body. we create an empty message
248: switch (soapVersion) {
249: case SOAP_11:
250: bodyBuilder = EndpointResponseMessageBuilder.EMPTY_SOAP11;
251: break;
252: case SOAP_12:
253: bodyBuilder = EndpointResponseMessageBuilder.EMPTY_SOAP12;
254: break;
255: default:
256: throw new AssertionError();
257: }
258: }
259: return bodyBuilder;
260: }
261:
262: public Packet invoke(Packet req) {
263: Message reqMsg = req.getMessage();
264: Object[] args = new Object[noOfArgs];
265: try {
266: argumentsBuilder.readRequest(reqMsg, args);
267: } catch (JAXBException e) {
268: throw new DeserializationException(
269: "failed.to.read.response", e);
270: } catch (XMLStreamException e) {
271: throw new DeserializationException(
272: "failed.to.read.response", e);
273: }
274: // Some transports(like HTTP) may want to send response before envoking endpoint method
275: // Doing this here so that after closing the response stream, cannot read
276: // request from some transports(light weight http server)
277: if (isOneWay && req.transportBackChannel != null) {
278: req.transportBackChannel.close();
279: }
280: Message responseMessage;
281: try {
282: Object ret = owner.getInvoker(req)
283: .invoke(req, method, args);
284: responseMessage = isOneWay ? null : createResponseMessage(
285: args, ret);
286: } catch (InvocationTargetException e) {
287: Throwable cause = e.getCause();
288:
289: if (!(cause instanceof RuntimeException)
290: && cause instanceof Exception) {
291: // Service specific exception
292: LOGGER.log(Level.INFO, cause.getMessage(), cause);
293: responseMessage = SOAPFaultBuilder
294: .createSOAPFaultMessage(soapVersion,
295: javaMethodModel
296: .getCheckedException(cause
297: .getClass()), cause);
298: } else {
299: LOGGER.log(Level.SEVERE, cause.getMessage(), cause);
300: responseMessage = SOAPFaultBuilder
301: .createSOAPFaultMessage(soapVersion, null,
302: cause);
303: }
304: } catch (Exception e) {
305: LOGGER.log(Level.SEVERE, e.getMessage(), e);
306: responseMessage = SOAPFaultBuilder.createSOAPFaultMessage(
307: soapVersion, null, e);
308: }
309: return req.createServerResponse(responseMessage, req.endpoint
310: .getPort(), javaMethodModel.getOwner(), req.endpoint
311: .getBinding());
312: }
313:
314: /**
315: * Creates a response {@link JAXBMessage} from method arguments, return value
316: *
317: * @return response message
318: */
319: private Message createResponseMessage(Object[] args,
320: Object returnValue) {
321: Message msg = bodyBuilder.createMessage(args, returnValue);
322:
323: for (MessageFiller filler : outFillers)
324: filler.fillIn(args, returnValue, msg);
325:
326: return msg;
327: }
328:
329: private static final Logger LOGGER = Logger
330: .getLogger(EndpointMethodHandler.class.getName());
331: }
|