001: package org.objectweb.celtix.bus.handlers;
002:
003: import java.util.ArrayList;
004: import java.util.Collections;
005: import java.util.List;
006: import java.util.logging.Level;
007: import java.util.logging.Logger;
008:
009: import javax.xml.ws.ProtocolException;
010: import javax.xml.ws.handler.Handler;
011: import javax.xml.ws.handler.LogicalHandler;
012: import javax.xml.ws.handler.MessageContext;
013:
014: import org.objectweb.celtix.bus.context.LogicalMessageContextImpl;
015: import org.objectweb.celtix.bus.context.StreamMessageContextImpl;
016: import org.objectweb.celtix.common.logging.LogUtils;
017: import org.objectweb.celtix.context.InputStreamMessageContext;
018: import org.objectweb.celtix.context.ObjectMessageContext;
019: import org.objectweb.celtix.context.OutputStreamMessageContext;
020: import org.objectweb.celtix.context.WebServiceContextImpl;
021: import org.objectweb.celtix.handlers.HandlerInvoker;
022: import org.objectweb.celtix.handlers.StreamHandler;
023:
024: /**
025: * invoke invoke the handlers in a registered handler chain
026: *
027: */
028: public class HandlerChainInvoker implements HandlerInvoker {
029:
030: private static final Logger LOG = LogUtils
031: .getL7dLogger(HandlerChainInvoker.class);
032:
033: private final List<Handler> protocolHandlers = new ArrayList<Handler>();
034: private List<LogicalHandler> logicalHandlers = new ArrayList<LogicalHandler>();
035: private final List<StreamHandler> streamHandlers = new ArrayList<StreamHandler>();
036: private final List<Handler> invokedHandlers = new ArrayList<Handler>();
037: private final List<Handler> closeHandlers = new ArrayList<Handler>();
038:
039: private boolean outbound;
040: private boolean responseExpected = true;
041: private boolean faultExpected;
042: private boolean handlerProcessingAborted;
043: private boolean closed;
044:
045: public HandlerChainInvoker(List<Handler> hc) {
046: this (hc, true);
047: }
048:
049: public HandlerChainInvoker(List<Handler> hc, boolean isOutbound) {
050: if (LOG.isLoggable(Level.FINE)) {
051: LOG.log(Level.FINE, "invoker for chain size: "
052: + (hc != null ? hc.size() : 0));
053: }
054:
055: if (hc != null) {
056: for (Handler h : hc) {
057: if (h instanceof LogicalHandler) {
058: logicalHandlers.add((LogicalHandler) h);
059: } else if (h instanceof StreamHandler) {
060: streamHandlers.add((StreamHandler) h);
061: } else {
062: protocolHandlers.add(h);
063: }
064: }
065: }
066: outbound = isOutbound;
067: }
068:
069: public boolean invokeLogicalHandlers(boolean requestor,
070: ObjectMessageContext objectCtx) {
071: objectCtx.setRequestorRole(requestor);
072: objectCtx.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY,
073: isOutbound());
074: LogicalMessageContextImpl logicalContext = new LogicalMessageContextImpl(
075: objectCtx);
076: return invokeHandlerChain(logicalHandlers, logicalContext);
077:
078: }
079:
080: public boolean invokeProtocolHandlers(boolean requestor,
081: MessageContext bindingContext) {
082: bindingContext
083: .put(ObjectMessageContext.REQUESTOR_ROLE_PROPERTY,
084: requestor);
085: bindingContext.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY,
086: isOutbound());
087:
088: return invokeHandlerChain(protocolHandlers, bindingContext);
089: }
090:
091: public boolean invokeStreamHandlers(InputStreamMessageContext ctx) {
092: StreamMessageContextImpl sctx = new StreamMessageContextImpl(
093: ctx);
094: sctx.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY,
095: this .outbound);
096: // return invokeHandlerChain(streamHandlers, new StreamMessageContextImpl(ctx));
097: return invokeHandlerChain(streamHandlers, sctx);
098: }
099:
100: public boolean invokeStreamHandlers(OutputStreamMessageContext ctx) {
101: StreamMessageContextImpl sctx = new StreamMessageContextImpl(
102: ctx);
103: sctx.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY,
104: this .outbound);
105: return invokeHandlerChain(streamHandlers, sctx);
106: }
107:
108: public void closeHandlers() {
109: //nothing to do
110: }
111:
112: public void setResponseExpected(boolean expected) {
113: responseExpected = expected;
114: }
115:
116: public boolean isResponseExpected() {
117: return responseExpected;
118: }
119:
120: public boolean isOutbound() {
121: return outbound;
122: }
123:
124: public boolean isInbound() {
125: return !outbound;
126: }
127:
128: public void setInbound() {
129: outbound = false;
130: }
131:
132: public void setOutbound() {
133: outbound = true;
134: }
135:
136: public boolean faultRaised(MessageContext context) {
137: return (null != context && null != context
138: .get(ObjectMessageContext.METHOD_FAULT))
139: || faultExpected;
140: }
141:
142: public void setFault(boolean fe) {
143: faultExpected = fe;
144: }
145:
146: /** Invoke handlers at the end of an MEP calling close on each.
147: * The handlers must be invoked in the reverse order that they
148: * appear in the handler chain. On the server side this will not
149: * be the reverse order in which they were invoked so use the
150: * handler chain directly and not simply the invokedHandler list.
151: */
152: public void mepComplete(MessageContext context) {
153: if (LOG.isLoggable(Level.FINE)) {
154: LOG.log(Level.FINE,
155: "closing protocol handlers - handler count:"
156: + invokedHandlers.size());
157: }
158: invokeClose(protocolHandlers, context);
159: invokeClose(logicalHandlers, context);
160: invokeClose(streamHandlers, context);
161: }
162:
163: /** Indicates that the invoker is closed. When closed, only @see
164: * #mepComplete may be called. The invoker will become closed if
165: * during a invocation of handlers, a handler throws a runtime
166: * exception that is not a protocol exception and no futher
167: * handler or message processing is possible.
168: *
169: */
170: public boolean isClosed() {
171: return closed;
172: }
173:
174: /**
175: * Allows an the logical handler chain for one invoker to be used
176: * as an alternate chain for another.
177: *
178: * @param invoker the invoker encalsulting the alternate logical handler
179: * chain
180: */
181: public void adoptLogicalHandlers(HandlerInvoker invoker) {
182: logicalHandlers = ((HandlerChainInvoker) invoker)
183: .getLogicalHandlers();
184: }
185:
186: List getInvokedHandlers() {
187: return Collections.unmodifiableList(invokedHandlers);
188: }
189:
190: public List<LogicalHandler> getLogicalHandlers() {
191: return logicalHandlers;
192: }
193:
194: List<Handler> getProtocolHandlers() {
195: return protocolHandlers;
196: }
197:
198: List<? extends Handler> getStreamHandlers() {
199: return streamHandlers;
200: }
201:
202: private <T extends Handler> void invokeClose(List<T> handlers,
203: MessageContext context) {
204: handlers = reverseHandlerChain(handlers);
205: for (Handler h : handlers) {
206: if (closeHandlers.contains(h)) {
207: h.close(context);
208: }
209: }
210: }
211:
212: private boolean invokeHandlerChain(
213: List<? extends Handler> handlerChain, MessageContext ctx) {
214: if (handlerChain.isEmpty()) {
215: LOG.log(Level.FINEST, "no handlers registered");
216: return true;
217: }
218:
219: if (isClosed()) {
220: return false;
221: }
222:
223: if (LOG.isLoggable(Level.FINE)) {
224: LOG.log(Level.FINE, "invoking handlers, direction: "
225: + (outbound ? "outbound" : "inbound"));
226: }
227: setMessageOutboundProperty(ctx);
228:
229: if (!outbound) {
230: handlerChain = reverseHandlerChain(handlerChain);
231: }
232:
233: boolean continueProcessing = true;
234:
235: WebServiceContextImpl.setMessageContext(ctx);
236:
237: if (!faultRaised(ctx)) {
238: continueProcessing = invokeHandleMessage(handlerChain, ctx);
239: } else {
240: continueProcessing = invokeHandleFault(handlerChain, ctx);
241: }
242:
243: if (!continueProcessing) {
244: // stop processing handlers, change direction and return
245: // control to the bindng. Then the binding will invoke on
246: // the next set on handlers and they will be processing in
247: // the correct direction. It would be good refactor it
248: // and control all of the processing here.
249: changeMessageDirection(ctx);
250: handlerProcessingAborted = true;
251: }
252: return continueProcessing;
253: }
254:
255: @SuppressWarnings("unchecked")
256: private boolean invokeHandleFault(
257: List<? extends Handler> handlerChain, MessageContext ctx) {
258:
259: boolean continueProcessing = true;
260:
261: try {
262: for (Handler<MessageContext> h : handlerChain) {
263: if (invokeThisHandler(h)) {
264: closeHandlers.add(h);
265: continueProcessing = h.handleFault(ctx);
266: }
267: if (!continueProcessing) {
268: break;
269: }
270: markHandlerInvoked(h);
271: }
272: } catch (RuntimeException e) {
273: LOG.log(Level.WARNING, "HANDLER_RAISED_RUNTIME_EXCEPTION",
274: e);
275: continueProcessing = false;
276: closed = true;
277: }
278: return continueProcessing;
279: }
280:
281: @SuppressWarnings("unchecked")
282: private boolean invokeHandleMessage(
283: List<? extends Handler> handlerChain, MessageContext ctx) {
284:
285: boolean continueProcessing = true;
286: try {
287: for (Handler h : handlerChain) {
288: if (invokeThisHandler(h)) {
289: closeHandlers.add(h);
290: continueProcessing = h.handleMessage(ctx);
291: }
292: if (!continueProcessing) {
293: break;
294: }
295: markHandlerInvoked(h);
296: }
297: } catch (ProtocolException e) {
298: LOG.log(Level.FINE, "handleMessage raised exception", e);
299: continueProcessing = false;
300: setFault(ctx, e);
301: } catch (RuntimeException e) {
302: LOG.log(Level.WARNING, "HANDLER_RAISED_RUNTIME_EXCEPTION",
303: e);
304: continueProcessing = false;
305: closed = true;
306: }
307: return continueProcessing;
308: }
309:
310: private boolean invokeThisHandler(Handler h) {
311: boolean ret = true;
312: // when handler processing has been aborted, only invoked on
313: // previously invoked handlers
314: //
315: if (handlerProcessingAborted) {
316: ret = invokedHandlers.contains(h);
317: }
318: if (ret && LOG.isLoggable(Level.FINE)) {
319: LOG.log(Level.FINE, "invoking handler of type "
320: + h.getClass().getName());
321: }
322: return ret;
323: }
324:
325: private void markHandlerInvoked(Handler h) {
326: if (!invokedHandlers.contains(h)) {
327: invokedHandlers.add(h);
328: }
329: }
330:
331: private void changeMessageDirection(MessageContext context) {
332: outbound = !outbound;
333: setMessageOutboundProperty(context);
334: context.put(ObjectMessageContext.MESSAGE_INPUT, Boolean.TRUE);
335: }
336:
337: private void setMessageOutboundProperty(MessageContext context) {
338: context.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY,
339: this .outbound);
340: }
341:
342: private <T extends Handler> List<T> reverseHandlerChain(
343: List<T> handlerChain) {
344: List<T> reversedHandlerChain = new ArrayList<T>();
345: reversedHandlerChain.addAll(handlerChain);
346: Collections.reverse(reversedHandlerChain);
347: return reversedHandlerChain;
348: }
349:
350: protected final void setFault(MessageContext context, Exception ex) {
351: context.put(ObjectMessageContext.METHOD_FAULT, ex);
352: context.setScope(ObjectMessageContext.METHOD_FAULT,
353: MessageContext.Scope.HANDLER);
354: }
355: }
|