001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.jaxws.handler;
019:
020: import java.util.ArrayList;
021: import java.util.Collections;
022: import java.util.List;
023: import java.util.logging.Level;
024: import java.util.logging.Logger;
025:
026: import javax.xml.namespace.QName;
027: import javax.xml.soap.MessageFactory;
028: import javax.xml.soap.SOAPBody;
029: import javax.xml.soap.SOAPConstants;
030: import javax.xml.soap.SOAPException;
031: import javax.xml.soap.SOAPFault;
032: import javax.xml.soap.SOAPMessage;
033: import javax.xml.stream.XMLStreamReader;
034: import javax.xml.transform.Source;
035: import javax.xml.ws.ProtocolException;
036: import javax.xml.ws.handler.Handler;
037: import javax.xml.ws.handler.LogicalHandler;
038: import javax.xml.ws.handler.LogicalMessageContext;
039: import javax.xml.ws.handler.MessageContext;
040: import javax.xml.ws.soap.SOAPFaultException;
041:
042: import org.w3c.dom.Node;
043:
044: import org.apache.cxf.binding.soap.SoapFault;
045: import org.apache.cxf.binding.soap.SoapMessage;
046: import org.apache.cxf.common.logging.LogUtils;
047: import org.apache.cxf.interceptor.Fault;
048: import org.apache.cxf.jaxws.context.WebServiceContextImpl;
049: import org.apache.cxf.jaxws.context.WrappedMessageContext;
050: import org.apache.cxf.message.Message;
051:
052: /**
053: * invoke the handlers in a registered handler chain
054: */
055: public class HandlerChainInvoker {
056:
057: private static final Logger LOG = LogUtils
058: .getL7dLogger(HandlerChainInvoker.class);
059:
060: private final List<Handler> protocolHandlers = new ArrayList<Handler>();
061: private List<LogicalHandler> logicalHandlers = new ArrayList<LogicalHandler>();
062:
063: private final List<Handler> invokedHandlers = new ArrayList<Handler>();
064: private final List<Handler> closeHandlers = new ArrayList<Handler>();
065:
066: private boolean outbound;
067: private boolean isRequestor;
068: private boolean responseExpected = true;
069: private boolean faultExpected;
070: private boolean closed;
071: private boolean messageDirectionReversed;
072: private Exception fault;
073: private MessageContext logicalMessageContext;
074: private MessageContext protocolMessageContext;
075:
076: public HandlerChainInvoker(List<Handler> hc) {
077: this (hc, true);
078: }
079:
080: public HandlerChainInvoker(List<Handler> hc, boolean isOutbound) {
081: if (LOG.isLoggable(Level.FINE)) {
082: LOG.log(Level.FINE, "invoker for chain size: "
083: + (hc != null ? hc.size() : 0));
084: }
085:
086: if (hc != null) {
087: for (Handler h : hc) {
088: if (h instanceof LogicalHandler) {
089: logicalHandlers.add((LogicalHandler) h);
090: } else {
091: protocolHandlers.add(h);
092: }
093: }
094: }
095: outbound = isOutbound;
096: }
097:
098: public List<LogicalHandler> getLogicalHandlers() {
099: return logicalHandlers;
100: }
101:
102: public List<Handler> getProtocolHandlers() {
103: return protocolHandlers;
104: }
105:
106: public MessageContext getLogicalMessageContext() {
107: return logicalMessageContext;
108: }
109:
110: public void setLogicalMessageContext(MessageContext mc) {
111: logicalMessageContext = mc;
112: }
113:
114: public MessageContext getProtocolMessageContext() {
115: return protocolMessageContext;
116: }
117:
118: public void setProtocolMessageContext(MessageContext mc) {
119: protocolMessageContext = mc;
120: }
121:
122: public boolean invokeLogicalHandlers(boolean requestor,
123: LogicalMessageContext context) {
124: context.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY,
125: isOutbound());
126: return invokeHandlerChain(logicalHandlers, context);
127: }
128:
129: public boolean invokeLogicalHandlersHandleFault(boolean requestor,
130: LogicalMessageContext context) {
131: context.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY,
132: isOutbound());
133: return invokeHandlerChainHandleFault(logicalHandlers, context);
134: }
135:
136: public boolean invokeProtocolHandlers(boolean requestor,
137: MessageContext context) {
138: context.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY,
139: isOutbound());
140:
141: return invokeHandlerChain(protocolHandlers, context);
142: }
143:
144: public boolean invokeProtocolHandlersHandleFault(boolean requestor,
145: MessageContext context) {
146: context.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY,
147: isOutbound());
148:
149: return invokeHandlerChainHandleFault(protocolHandlers, context);
150: }
151:
152: public void setResponseExpected(boolean expected) {
153: responseExpected = expected;
154: }
155:
156: public boolean isResponseExpected() {
157: return responseExpected;
158: }
159:
160: public boolean isOutbound() {
161: return outbound;
162: }
163:
164: public boolean isInbound() {
165: return !outbound;
166: }
167:
168: /**
169: * We need HandlerChainInvoker behaves differently on the client and server
170: * side. For the client side, as there is no inbound faultChain, we need to call
171: * handleFault and close within HandlerChainInvoker directly.
172: */
173: public boolean isRequestor() {
174: return isRequestor;
175: }
176:
177: public void setRequestor(boolean requestor) {
178: isRequestor = requestor;
179: }
180:
181: public void setInbound() {
182: outbound = false;
183: }
184:
185: public void setOutbound() {
186: outbound = true;
187: }
188:
189: public boolean faultRaised() {
190: return null != fault || faultExpected;
191: }
192:
193: public Exception getFault() {
194: return fault;
195: }
196:
197: public void setFault(boolean fe) {
198: faultExpected = fe;
199: }
200:
201: /**
202: * Invoke handlers at the end of an MEP calling close on each. The handlers
203: * must be invoked in the reverse order that they appear in the handler
204: * chain. On the server side this will not be the reverse order in which
205: * they were invoked so use the handler chain directly and not simply the
206: * invokedHandler list.
207: */
208: public void mepComplete(Message message) {
209: if (LOG.isLoggable(Level.FINE)) {
210: LOG.log(Level.FINE,
211: "closing protocol handlers - handler count:"
212: + invokedHandlers.size());
213: }
214:
215: if (isClosed()) {
216: return;
217: }
218:
219: invokeReversedClose();
220: }
221:
222: /**
223: * Indicates that the invoker is closed. When closed, only
224: * @see #mepComplete may be called. The invoker will become closed if during
225: * a invocation of handlers, a handler throws a runtime exception that
226: * is not a protocol exception and no futher handler or message
227: * processing is possible.
228: */
229: public boolean isClosed() {
230: return closed;
231: }
232:
233: /**
234: * Allows an the logical handler chain for one invoker to be used as an
235: * alternate chain for another.
236: *
237: * @param invoker the invoker encalsulting the alternate logical handler
238: * chain
239: */
240: public void adoptLogicalHandlers(HandlerChainInvoker invoker) {
241: logicalHandlers = invoker.getLogicalHandlers();
242: }
243:
244: List getInvokedHandlers() {
245: return Collections.unmodifiableList(invokedHandlers);
246: }
247:
248: private boolean invokeHandlerChain(
249: List<? extends Handler> handlerChain, MessageContext ctx) {
250: if (handlerChain.isEmpty()) {
251: LOG.log(Level.FINEST, "no handlers registered");
252: return true;
253: }
254:
255: if (isClosed()) {
256: return false;
257: }
258:
259: if (LOG.isLoggable(Level.FINE)) {
260: LOG.log(Level.FINE, "invoking handlers, direction: "
261: + (outbound ? "outbound" : "inbound"));
262: }
263: setMessageOutboundProperty(ctx);
264:
265: if (!outbound) {
266: handlerChain = reverseHandlerChain(handlerChain);
267: }
268:
269: boolean continueProcessing = true;
270: WebServiceContextImpl.setMessageContext(ctx);
271: continueProcessing = invokeHandleMessage(handlerChain, ctx);
272:
273: return continueProcessing;
274: }
275:
276: /*
277: * REVISIT: the logic of current implemetation is if the exception is thrown
278: * from previous handlers, we only invoke handleFault if it is
279: * ProtocolException (per spec), if the exception is thrown from other
280: * places other than handlers, we always invoke handleFault.
281: */
282: private boolean invokeHandlerChainHandleFault(
283: List<? extends Handler> handlerChain, MessageContext ctx) {
284: if (handlerChain.isEmpty()) {
285: LOG.log(Level.FINEST, "no handlers registered");
286: return true;
287: }
288:
289: if (isClosed()) {
290: return false;
291: }
292:
293: //The fault is raised from previous handlers, in this case, we only invoke handleFault
294: //if the fault is a ProtocolException
295: if (fault != null && !(fault instanceof ProtocolException)) {
296: return true;
297: }
298:
299: if (LOG.isLoggable(Level.FINE)) {
300: LOG.log(Level.FINE, "invoking handlers, direction: "
301: + (outbound ? "outbound" : "inbound"));
302: }
303: setMessageOutboundProperty(ctx);
304:
305: if (!outbound) {
306: handlerChain = reverseHandlerChain(handlerChain);
307: }
308:
309: boolean continueProcessing = true;
310: WebServiceContextImpl.setMessageContext(ctx);
311: continueProcessing = invokeHandleFault(handlerChain, ctx);
312:
313: return continueProcessing;
314: }
315:
316: @SuppressWarnings("unchecked")
317: private boolean invokeHandleFault(
318: List<? extends Handler> handlerChain, MessageContext ctx) {
319: boolean continueProcessing = true;
320:
321: try {
322: for (Handler h : handlerChain) {
323: if (invokeThisHandler(h)) {
324: closeHandlers.add(h);
325: markHandlerInvoked(h);
326: continueProcessing = h.handleFault(ctx);
327: }
328: if (!continueProcessing) {
329: break;
330: }
331:
332: }
333: } catch (RuntimeException e) {
334: LOG.log(Level.WARNING, "HANDLER_RAISED_RUNTIME_EXCEPTION",
335: e);
336: continueProcessing = false;
337: throw e;
338: }
339: return continueProcessing;
340: }
341:
342: @SuppressWarnings("unchecked")
343: private boolean invokeHandleMessage(
344: List<? extends Handler> handlerChain, MessageContext ctx) {
345: boolean continueProcessing = true;
346: try {
347: for (Handler h : handlerChain) {
348: if (invokeThisHandler(h)) {
349: closeHandlers.add(h);
350: markHandlerInvoked(h);
351: continueProcessing = h.handleMessage(ctx);
352: }
353: if (!continueProcessing) {
354: if (responseExpected) {
355: changeMessageDirection(ctx);
356: messageDirectionReversed = true;
357: }
358:
359: break;
360: }
361: }
362: } catch (ProtocolException e) {
363: LOG.log(Level.FINE, "handleMessage raised exception", e);
364:
365: if (responseExpected) {
366: changeMessageDirection(ctx);
367: messageDirectionReversed = true;
368: }
369:
370: //special case for client side, this is because we do nothing in client fault
371: //observer, we have to call handleFault and close here.
372: if (isRequestor()) {
373: if (responseExpected) {
374: setFaultMessage(ctx, e);
375: invokeReversedHandleFault(ctx);
376: } else {
377: invokeReversedClose();
378: }
379: }
380:
381: continueProcessing = false;
382: setFault(e);
383: throw e;
384: } catch (RuntimeException e) {
385: LOG.log(Level.WARNING, "HANDLER_RAISED_RUNTIME_EXCEPTION",
386: e);
387:
388: if (responseExpected) {
389: changeMessageDirection(ctx);
390: messageDirectionReversed = true;
391: }
392:
393: //special case for client side, this is because we do nothing in client fault
394: //observer, we have to call close here.
395: if (isRequestor()) {
396: invokeReversedClose();
397: }
398:
399: continueProcessing = false;
400: setFault(e);
401: throw e;
402: }
403: return continueProcessing;
404: }
405:
406: /*
407: * When the message direction is reversed, if the message is not already a
408: * fault message then it is replaced with a fault message
409: */
410: private void setFaultMessage(MessageContext mc, Exception exception) {
411: Message msg = ((WrappedMessageContext) mc).getWrappedMessage();
412: msg.setContent(Exception.class, exception);
413: msg.removeContent(XMLStreamReader.class);
414: msg.removeContent(Source.class);
415:
416: try {
417: SOAPMessage soapMessage = null;
418:
419: if (!(msg instanceof SoapMessage)
420: || ((SoapMessage) msg).getVersion().getVersion() <= 1.11d) {
421: soapMessage = MessageFactory.newInstance(
422: SOAPConstants.SOAP_1_1_PROTOCOL)
423: .createMessage();
424: } else {
425: soapMessage = MessageFactory.newInstance(
426: SOAPConstants.SOAP_1_2_PROTOCOL)
427: .createMessage();
428: }
429: msg.setContent(SOAPMessage.class, soapMessage);
430:
431: SOAPBody body = soapMessage.getSOAPBody();
432: SOAPFault soapFault = body.addFault();
433:
434: if (exception instanceof SOAPFaultException) {
435: SOAPFaultException sf = (SOAPFaultException) exception;
436: soapFault
437: .setFaultString(sf.getFault().getFaultString());
438: soapFault.setFaultCode(sf.getFault().getFaultCode());
439: soapFault.setFaultActor(sf.getFault().getFaultActor());
440: Node nd = soapMessage.getSOAPPart()
441: .importNode(
442: sf.getFault().getDetail()
443: .getFirstChild(), true);
444: soapFault.addDetail().appendChild(nd);
445: } else if (exception instanceof Fault) {
446: SoapFault sf = SoapFault.createFault((Fault) exception,
447: ((SoapMessage) msg).getVersion());
448: soapFault.setFaultString(sf.getReason());
449: soapFault.setFaultCode(sf.getFaultCode());
450: Node nd = soapMessage.getSOAPPart().importNode(
451: sf.getOrCreateDetail(), true);
452: soapFault.addDetail().appendChild(nd);
453: } else {
454: soapFault.setFaultCode(new QName(
455: "http://cxf.apache.org/faultcode",
456: "HandlerFault"));
457: soapFault.setFaultString(exception.getMessage());
458: }
459: } catch (SOAPException e) {
460: e.printStackTrace();
461: // do nothing
462: }
463: }
464:
465: @SuppressWarnings("unchecked")
466: private boolean invokeReversedHandleFault(MessageContext ctx) {
467: boolean continueProcessing = true;
468:
469: try {
470: int index = invokedHandlers.size() - 2;
471: while (index >= 0 && continueProcessing) {
472: Handler h = invokedHandlers.get(index);
473: if (h instanceof LogicalHandler) {
474: continueProcessing = h
475: .handleFault(logicalMessageContext);
476: } else {
477: continueProcessing = h
478: .handleFault(protocolMessageContext);
479: }
480:
481: if (!continueProcessing) {
482: invokeReversedClose();
483: break;
484: }
485: index--;
486: }
487: } catch (RuntimeException e) {
488: LOG.log(Level.WARNING, "HANDLER_RAISED_RUNTIME_EXCEPTION",
489: e);
490: invokeReversedClose();
491: continueProcessing = false;
492: closed = true;
493:
494: throw e;
495: }
496: invokeReversedClose();
497: return continueProcessing;
498: }
499:
500: /*
501: * close is called on each previously invoked handler in the chain, the
502: * close method is only called on handlers that were previously invoked via
503: * either handleMessage or handleFault
504: */
505: private void invokeReversedClose() {
506: int index = invokedHandlers.size() - 1;
507: while (index >= 0) {
508: Handler handler = invokedHandlers.get(index);
509: if (handler instanceof LogicalHandler) {
510: handler.close(logicalMessageContext);
511: } else {
512: handler.close(protocolMessageContext);
513: }
514: invokedHandlers.remove(index);
515: index--;
516: }
517: closed = true;
518: }
519:
520: private boolean invokeThisHandler(Handler h) {
521: boolean ret = true;
522: // when handler processing has been aborted, only invoke on
523: // previously invoked handlers
524: //Only invoke the next handler (take the reversed direction into account)
525: if (messageDirectionReversed) {
526: ret = invokedHandlers.contains(h)
527: && !isTheLastInvokedHandler(h);
528: }
529:
530: if (ret && LOG.isLoggable(Level.FINE)) {
531: LOG.log(Level.FINE, "invoking handler of type "
532: + h.getClass().getName());
533: }
534: return ret;
535: }
536:
537: private boolean isTheLastInvokedHandler(Handler h) {
538: return invokedHandlers.contains(h)
539: && invokedHandlers.indexOf(h) == (invokedHandlers
540: .size() - 1);
541: }
542:
543: private void markHandlerInvoked(Handler h) {
544: if (!invokedHandlers.contains(h)) {
545: invokedHandlers.add(h);
546: }
547: }
548:
549: private void changeMessageDirection(MessageContext context) {
550: outbound = !outbound;
551: setMessageOutboundProperty(context);
552: }
553:
554: private void setMessageOutboundProperty(MessageContext context) {
555: context.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY,
556: this .outbound);
557: if (logicalMessageContext != null) {
558: logicalMessageContext.put(
559: MessageContext.MESSAGE_OUTBOUND_PROPERTY,
560: this .outbound);
561: }
562: if (protocolMessageContext != null) {
563: protocolMessageContext.put(
564: MessageContext.MESSAGE_OUTBOUND_PROPERTY,
565: this .outbound);
566: }
567: }
568:
569: private <T extends Handler> List<T> reverseHandlerChain(
570: List<T> handlerChain) {
571: List<T> reversedHandlerChain = new ArrayList<T>();
572: reversedHandlerChain.addAll(handlerChain);
573: Collections.reverse(reversedHandlerChain);
574: return reversedHandlerChain;
575: }
576:
577: protected final void setFault(Exception ex) {
578: fault = ex;
579: }
580: }
|