001: package org.objectweb.celtix.bindings;
002:
003: import java.io.IOException;
004: import java.io.OutputStream;
005: import java.lang.reflect.InvocationTargetException;
006: import java.util.logging.Level;
007: import java.util.logging.Logger;
008:
009: import javax.xml.namespace.QName;
010: import javax.xml.ws.WebServiceException;
011: import javax.xml.ws.handler.MessageContext;
012:
013: import org.objectweb.celtix.common.i18n.Message;
014: import org.objectweb.celtix.common.logging.LogUtils;
015: import org.objectweb.celtix.context.InputStreamMessageContext;
016: import org.objectweb.celtix.context.ObjectMessageContext;
017: import org.objectweb.celtix.context.OutputStreamMessageContext;
018: import org.objectweb.celtix.context.WebServiceContextImpl;
019: import org.objectweb.celtix.handlers.HandlerInvoker;
020: import org.objectweb.celtix.transports.ServerTransport;
021:
022: public class ServerRequest {
023:
024: public enum ServerRequestState {
025: STREAM_HANDLERS_INVOKED(1), STREAM_READ(2), PROTOCOL_HANDLERS_INVOKED(
026: 3), UNMARSHALLED(4), LOGICAL_HANDLERS_INVOKED(5), DISPATCHED(
027: 6);
028:
029: private final int val;
030:
031: ServerRequestState(int v) {
032: this .val = v;
033: }
034:
035: public int value() {
036: return val;
037: }
038: }
039:
040: private static final Logger LOG = LogUtils
041: .getL7dLogger(ServerRequest.class);
042:
043: private final AbstractBindingBase binding;
044: private HandlerInvoker handlerInvoker;
045:
046: private InputStreamMessageContext istreamCtx;
047: private MessageContext bindingCtx;
048: private ObjectMessageContext objectCtx;
049: private ServerRequestState state;
050: private boolean isOneway;
051: private boolean isOnewayDetermined;
052:
053: public ServerRequest(AbstractBindingBase b,
054: InputStreamMessageContext i) {
055: binding = b;
056: istreamCtx = i;
057: istreamCtx.put(ObjectMessageContext.MESSAGE_INPUT,
058: Boolean.FALSE);
059: }
060:
061: /**
062: * Used to create a ServerRequest to represent a resent outgoing
063: * message. Hence the state is set up to allow us to proceed directly
064: * to the processOutbound() phase.
065: *
066: * @param b the underlying binding
067: * @param objectContext the object message context
068: */
069: public ServerRequest(AbstractBindingBase b,
070: ObjectMessageContext objectContext) {
071: binding = b;
072: objectCtx = objectContext;
073: handlerInvoker = binding.createHandlerInvoker();
074: state = ServerRequestState.DISPATCHED;
075: }
076:
077: public AbstractBindingBase getBinding() {
078: return binding;
079: }
080:
081: public HandlerInvoker getHandlerInvoker() {
082: return handlerInvoker;
083: }
084:
085: public void setHandlerInvoker(HandlerInvoker h) {
086: handlerInvoker = h;
087: }
088:
089: public MessageContext getBindingCtx() {
090: return bindingCtx;
091: }
092:
093: public ObjectMessageContext getObjectCtx() {
094: return objectCtx;
095: }
096:
097: public ServerRequestState getState() {
098: return state;
099: }
100:
101: public void processInbound() {
102:
103: if (null == handlerInvoker) {
104: handlerInvoker = binding.createHandlerInvoker();
105: }
106: handlerInvoker.setInbound();
107:
108: handlerInvoker.invokeStreamHandlers(istreamCtx);
109: state = ServerRequestState.STREAM_HANDLERS_INVOKED;
110:
111: if (bindingCtx == null) {
112: bindingCtx = binding.getBindingImpl()
113: .createBindingMessageContext(istreamCtx);
114: } else {
115: bindingCtx.putAll(istreamCtx);
116: }
117: bindingCtx.put(ObjectMessageContext.MESSAGE_INPUT,
118: Boolean.FALSE);
119:
120: try {
121: binding.getBindingImpl().read(istreamCtx, bindingCtx);
122: state = ServerRequestState.STREAM_READ;
123: } catch (IOException ex) {
124: LOG.log(Level.SEVERE, "REQUEST_UNREADABLE_MSG", ex);
125: throw new WebServiceException(ex);
126: }
127:
128: boolean continueProcessing = handlerInvoker
129: .invokeProtocolHandlers(isRequestor(), bindingCtx);
130: state = ServerRequestState.PROTOCOL_HANDLERS_INVOKED;
131: if (!continueProcessing) {
132: return;
133: }
134:
135: // store method and operation name in binding context if not already there -
136: // using server binding endpoint callback
137:
138: storeOperationName();
139:
140: if (null == objectCtx) {
141: objectCtx = binding.createObjectContext();
142: initObjectContext(objectCtx);
143: objectCtx.putAll(bindingCtx);
144: }
145:
146: binding.getBindingImpl().unmarshal(bindingCtx, objectCtx,
147: getDataBindingCallback());
148: state = ServerRequestState.UNMARSHALLED;
149: objectCtx.put(OutputStreamMessageContext.ONEWAY_MESSAGE_TF,
150: isOneway());
151:
152: handlerInvoker.invokeLogicalHandlers(isRequestor(), objectCtx);
153:
154: state = ServerRequestState.LOGICAL_HANDLERS_INVOKED;
155: }
156:
157: public void doInvocation() {
158: LOG.fine("doInvocation");
159: QName operationName = (QName) objectCtx
160: .get(MessageContext.WSDL_OPERATION);
161: if (null == operationName) {
162: Message msg = new Message(
163: "CONTEXT_MISSING_OPERATION_NAME_EXC", LOG);
164: LOG.log(Level.SEVERE, msg.toString());
165: objectCtx.setException(new WebServiceException(msg
166: .toString()));
167: return;
168: }
169: if (LOG.isLoggable(Level.FINE)) {
170: LOG.fine("operation name: " + operationName);
171: }
172:
173: ServerDataBindingCallback method = (ServerDataBindingCallback) BindingContextUtils
174: .retrieveDataBindingCallback(objectCtx);
175: if (null == method) {
176: Message msg = new Message("IMPLEMENTOR_MISSING_METHOD_EXC",
177: LOG, operationName);
178: LOG.log(Level.SEVERE, msg.toString());
179: objectCtx.setException(new WebServiceException(msg
180: .toString()));
181: return;
182: }
183: if (LOG.isLoggable(Level.FINE)) {
184: LOG.fine("method: " + method);
185: }
186:
187: try {
188: new WebServiceContextImpl(objectCtx);
189:
190: method.invoke(objectCtx);
191: } catch (WebServiceException wex) {
192: Throwable cause = wex.getCause();
193: if (cause != null) {
194: objectCtx.setException(cause);
195: } else {
196: objectCtx.setException(wex);
197: }
198: } catch (InvocationTargetException ex) {
199: LogUtils.log(LOG, Level.FINE,
200: "IMPLEMENTOR_INVOCATION_EXCEPTION_MSG", ex, method
201: .getOperationName());
202: Throwable cause = ex.getCause();
203: if (cause != null) {
204: objectCtx.setException(cause);
205: } else {
206: objectCtx.setException(ex);
207: }
208: }
209:
210: state = ServerRequestState.DISPATCHED;
211: }
212:
213: public void processOutbound(ServerTransport st,
214: Exception inboundException) {
215: processOutbound(st, inboundException, false);
216: }
217:
218: public void processOutbound(ServerTransport st,
219: Exception inboundException, boolean logicalChainTraversed) {
220: if (LOG.isLoggable(Level.FINE)) {
221: LOG.info("Reverse processing inbound message, exception: "
222: + inboundException);
223: }
224:
225: handlerInvoker.setOutbound();
226:
227: ObjectMessageContext replyObjectCtx = objectCtx;
228: if (null == replyObjectCtx) {
229: replyObjectCtx = binding.createObjectContext();
230: }
231: replyObjectCtx.put(ObjectMessageContext.MESSAGE_INPUT,
232: Boolean.TRUE);
233:
234: if (null != inboundException) {
235: replyObjectCtx.setException(inboundException);
236: }
237:
238: // If protocol handlers were invoked inbound, then also invoke them
239: // outbound - except when message is oneway.
240: // TODO: relax this restriction to allow outbound processing of system
241: // handlers.
242:
243: if (!logicalChainTraversed
244: && state.value() >= ServerRequestState.LOGICAL_HANDLERS_INVOKED
245: .value() && !isOneway()) {
246:
247: // Protocol and runtime exceptions have already been caught by
248: // handler invoker and stored in the object context.
249:
250: handlerInvoker.invokeLogicalHandlers(isRequestor(),
251: replyObjectCtx);
252: }
253:
254: // If on the inbound path we managed to construct a binding message
255: // context use it - otherwise create a new one.
256:
257: MessageContext replyBindingCtx = bindingCtx;
258: if (null == replyBindingCtx) {
259: bindingCtx = binding.getBindingImpl()
260: .createBindingMessageContext(replyObjectCtx);
261: replyBindingCtx = bindingCtx;
262: } else if (null != replyObjectCtx) {
263: replyBindingCtx.putAll(replyObjectCtx);
264: }
265:
266: // The following will only succeed if we have a data binding callback.
267:
268: if (handlerInvoker.faultRaised(replyObjectCtx)) {
269: LOG.fine("Marshalling fault.");
270: marshalFault(replyObjectCtx, replyBindingCtx);
271: } else if (null != replyObjectCtx
272: .get(ObjectMessageContext.MESSAGE_PAYLOAD)
273: || state.value() >= ServerRequestState.DISPATCHED
274: .value()
275: || null != replyObjectCtx
276: .get(ObjectMessageContext.METHOD_RETURN)) {
277: LOG.fine("Marshalling.");
278: marshal(replyObjectCtx, replyBindingCtx);
279: }
280:
281: // If protocol handlers were invoked inbound, then also invoke them
282: // outbound - except when message is oneway.
283: // TODO: relax this restriction to allow outbound processing of system
284: // handlers.
285: // Note we may not be able to find out if the message is oneway (in case where
286: // inbound processing failed while invoking stream handlers).
287:
288: if (state.value() >= ServerRequestState.PROTOCOL_HANDLERS_INVOKED
289: .value()
290: && !isOneway()) {
291:
292: // Protocol and runtime exceptions have already been caught by
293: // handler invoker and stored in binding context
294: // As marshalling took place prior to invoking the
295: // protocol handlers we need to go back and marshal this fault.
296:
297: handlerInvoker.invokeProtocolHandlers(isRequestor(),
298: replyBindingCtx);
299:
300: if (handlerInvoker.faultRaised(replyBindingCtx)
301: && !binding.getBindingImpl().hasFault(
302: replyBindingCtx)) {
303: LOG
304: .fine("Marshalling fault raised by protocol handlers.");
305: replyObjectCtx.setException((Exception) replyBindingCtx
306: .get(ObjectMessageContext.METHOD_FAULT));
307: marshalFault(replyObjectCtx, replyBindingCtx);
308: }
309: }
310:
311: // create an output stream message context
312:
313: binding.getBindingImpl().updateMessageContext(replyBindingCtx);
314:
315: try {
316:
317: OutputStreamMessageContext ostreamCtx = st
318: .createOutputStreamContext(replyBindingCtx);
319: ostreamCtx.setOneWay(isOneway());
320:
321: if (isOneway()) {
322: st.finalPrepareOutputStreamContext(ostreamCtx);
323: } else {
324:
325: if (binding.getBindingImpl().hasFault(replyBindingCtx)) {
326: ostreamCtx.setFault(true);
327: }
328:
329: handlerInvoker.invokeStreamHandlers(ostreamCtx);
330: st.finalPrepareOutputStreamContext(ostreamCtx);
331: binding.getBindingImpl().write(replyBindingCtx,
332: ostreamCtx);
333: OutputStream os = ostreamCtx.getOutputStream();
334: os.flush();
335: }
336:
337: LOG.fine("postDispatch from binding on thread : "
338: + Thread.currentThread());
339: st.postDispatch(replyBindingCtx, ostreamCtx);
340: if (ostreamCtx.getOutputStream() != null) {
341: ostreamCtx.getOutputStream().close();
342: }
343: } catch (IOException ex) {
344: LOG.log(Level.SEVERE, "RESPONSE_UNWRITABLE_MSG", ex);
345: throw new WebServiceException(ex);
346: } finally {
347: complete();
348: }
349: }
350:
351: public void complete() {
352: handlerInvoker.mepComplete(istreamCtx);
353: }
354:
355: public boolean isRequestor() {
356: return false;
357: }
358:
359: public boolean isOneway() {
360: if (!isOnewayDetermined) {
361: isOneway = BindingContextUtils.isOnewayMethod(bindingCtx);
362: }
363: return isOneway;
364: }
365:
366: public void setOneway(boolean oneway) {
367: isOneway = oneway;
368: isOnewayDetermined = true;
369: }
370:
371: public boolean doDispatch() {
372: return state.value() >= ServerRequestState.LOGICAL_HANDLERS_INVOKED
373: .value()
374: && handlerInvoker.isInbound()
375: && objectCtx != null
376: && BindingContextUtils.retrieveDispatch(objectCtx);
377: }
378:
379: protected void storeOperationName() {
380: AbstractServerBinding sb = (AbstractServerBinding) binding;
381: if (bindingCtx.containsKey(MessageContext.WSDL_OPERATION)) {
382: if (LOG.isLoggable(Level.FINE)) {
383: LOG
384: .fine("Determined operation using pre-existing operation name: "
385: + bindingCtx
386: .get(MessageContext.WSDL_OPERATION));
387: }
388: return;
389: }
390:
391: QName operationName = sb.getOperationName(bindingCtx);
392:
393: if (null != operationName) {
394: bindingCtx
395: .put(MessageContext.WSDL_OPERATION, operationName);
396: } else {
397: throw new WebServiceException(
398: "No operation matching message was found");
399: }
400:
401: if (LOG.isLoggable(Level.FINE)) {
402: LOG
403: .fine("Determined operation name using server binding endpoint callback: "
404: + operationName);
405: }
406: }
407:
408: public ServerDataBindingCallback getDataBindingCallback() {
409: ServerDataBindingCallback callback = (ServerDataBindingCallback) BindingContextUtils
410: .retrieveDataBindingCallback(bindingCtx);
411: if (null == callback) {
412: assert null != objectCtx;
413: ServerBindingEndpointCallback sbeCallback = BindingContextUtils
414: .retrieveServerBindingEndpointCallback(bindingCtx);
415: DataBindingCallback.Mode mode = sbeCallback
416: .getServiceMode();
417: callback = sbeCallback.getDataBindingCallback(
418: (QName) bindingCtx
419: .get(MessageContext.WSDL_OPERATION),
420: objectCtx, mode);
421: if (LOG.isLoggable(Level.FINE)) {
422: LOG
423: .fine("Using data binding callback constructed by server endpoint callback: "
424: + callback);
425: }
426: BindingContextUtils.storeDataBindingCallback(bindingCtx,
427: callback);
428: } else if (LOG.isLoggable(Level.FINE)) {
429: LOG.fine("Using data binding callback stored in context.");
430: }
431: return callback;
432: }
433:
434: private void initObjectContext(ObjectMessageContext octx) {
435: getDataBindingCallback().initObjectContext(octx);
436: }
437:
438: private void marshalFault(ObjectMessageContext octx,
439: MessageContext bctx) {
440: DataBindingCallback callback = BindingContextUtils
441: .retrieveDataBindingCallback(bindingCtx);
442: if (null == callback) {
443: ServerBindingEndpointCallback sbeCallback = BindingContextUtils
444: .retrieveServerBindingEndpointCallback(bindingCtx);
445: callback = sbeCallback.getFaultDataBindingCallback(octx);
446: }
447: if (null == callback) {
448: // TODO
449: LOG.log(Level.SEVERE, "NO_DATA_BINDING_CALLBACK");
450: }
451: try {
452: binding.getBindingImpl().marshalFault(octx, bctx, callback);
453: } catch (Exception ex) {
454: LOG.log(Level.SEVERE, "COULD_NOT_MARSHAL_FAULT_MSG", ex);
455: }
456: }
457:
458: private void marshal(ObjectMessageContext octx, MessageContext bctx) {
459: DataBindingCallback callback = getDataBindingCallback();
460: if (null == callback) {
461: // TODO
462: LOG.log(Level.SEVERE, "NO_DATA_BINDING_CALLBACK");
463: } else {
464: try {
465: binding.getBindingImpl().marshal(octx, bctx, callback);
466: } catch (Exception ex) {
467: LOG.log(Level.SEVERE, "COULD_NOT_MARSHAL_MSG", ex);
468: }
469: }
470: }
471:
472: }
|