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: package com.sun.xml.ws.handler;
037:
038: import com.sun.xml.ws.api.WSBinding;
039:
040: import javax.xml.ws.ProtocolException;
041: import javax.xml.ws.handler.Handler;
042: import javax.xml.ws.handler.MessageContext;
043: import java.util.ArrayList;
044: import java.util.List;
045: import java.util.logging.Level;
046: import java.util.logging.Logger;
047:
048: /**
049: * @author WS Development Team
050: */
051: abstract class HandlerProcessor<C extends MessageUpdatableContext> {
052:
053: boolean isClient;
054: static final Logger logger = Logger
055: .getLogger(com.sun.xml.ws.util.Constants.LoggingDomain
056: + ".handler");
057:
058: // need request or response for Handle interface
059: public enum RequestOrResponse {
060: REQUEST, RESPONSE
061: }
062:
063: public enum Direction {
064: OUTBOUND, INBOUND
065: }
066:
067: private List<? extends Handler> handlers; // may be logical/soap mixed
068:
069: WSBinding binding;
070: private int index = -1;
071: private HandlerTube owner;
072:
073: /**
074: * The handlers that are passed in will be sorted into
075: * logical and soap handlers. During this sorting, the
076: * understood headers are also obtained from any soap
077: * handlers.
078: *
079: * @param chain A list of handler objects, which can
080: * be protocol or logical handlers.
081: */
082: protected HandlerProcessor(HandlerTube owner, WSBinding binding,
083: List<? extends Handler> chain) {
084: this .owner = owner;
085: if (chain == null) { // should only happen in testing
086: chain = new ArrayList<Handler>();
087: }
088: handlers = chain;
089: this .binding = binding;
090: }
091:
092: /**
093: * Gives index of the handler in the chain to know what handlers in the chain
094: * are invoked
095: */
096: int getIndex() {
097: return index;
098: }
099:
100: /**
101: * This is called when a handler returns false or throws a RuntimeException
102: */
103: void setIndex(int i) {
104: index = i;
105: }
106:
107: /**
108: * TODO: Just putting thoughts,
109: * Current contract: This is Called during Request Processing.
110: * return true, if all handlers in the chain return true
111: * Current Pipe can call nextPipe.process();
112: * return false, One of the handlers has returned false or thrown a
113: * RuntimeException. Remedy Actions taken:
114: * 1) In this case, The processor will setIndex()to track what
115: * handlers are invoked until that point.
116: * 2) Previously invoked handlers are again invoked (handleMessage()
117: * or handleFault()) to take remedy action.
118: * CurrentPipe should NOT call nextPipe.process()
119: * While closing handlers, check getIndex() to get the invoked
120: * handlers.
121: * @throws RuntimeException this happens when a RuntimeException occurs during
122: * handleMessage during Request processing or
123: * during remedy action 2)
124: * CurrentPipe should NOT call nextPipe.process() and throw the
125: * exception to the previous Pipe
126: * While closing handlers, check getIndex() to get the invoked
127: * handlers.
128: */
129: public boolean callHandlersRequest(Direction direction, C context,
130: boolean responseExpected) {
131: setDirection(direction, context);
132: boolean result;
133: // call handlers
134: try {
135: if (direction == Direction.OUTBOUND) {
136: result = callHandleMessage(context, 0,
137: handlers.size() - 1);
138: } else {
139: result = callHandleMessage(context,
140: handlers.size() - 1, 0);
141: }
142: } catch (ProtocolException pe) {
143: logger.log(Level.FINER, "exception in handler chain", pe);
144: if (responseExpected) {
145: //insert fault message if its not a fault message
146: insertFaultMessage(context, pe);
147: // reverse direction
148: reverseDirection(direction, context);
149: //Set handleFault so that cousinTube is aware of fault
150: setHandleFaultProperty();
151: // call handle fault
152: if (direction == Direction.OUTBOUND) {
153: callHandleFault(context, getIndex() - 1, 0);
154: } else {
155: callHandleFault(context, getIndex() + 1, handlers
156: .size() - 1);
157: }
158: return false;
159: }
160: throw pe;
161: } catch (RuntimeException re) {
162: logger.log(Level.FINER, "exception in handler chain", re);
163: throw re;
164: }
165:
166: if (!result) {
167: if (responseExpected) {
168: // reverse direction
169: reverseDirection(direction, context);
170: // call handle message
171: if (direction == Direction.OUTBOUND) {
172: callHandleMessageReverse(context, getIndex() - 1, 0);
173: } else {
174: callHandleMessageReverse(context, getIndex() + 1,
175: handlers.size() - 1);
176: }
177: } else {
178: // Set handleFalse so that cousinTube is aware of false processing
179: // Oneway, dispatch the message
180: // cousinTube should n't call handleMessage() anymore.
181: setHandleFalseProperty();
182: }
183: return false;
184: }
185:
186: return result;
187: }
188:
189: /**
190: * TODO: Just putting thoughts,
191: * Current contract: This is Called during Response Processing.
192: * Runs all handlers until handle returns false or throws a RuntimeException
193: * CurrentPipe should close all the handlers in the chain.
194: * throw RuntimeException, this happens when a RuntimeException occurs during
195: * normal Response processing or remedy action 2) taken
196: * during callHandlersRequest().
197: * CurrentPipe should close all the handlers in the chain. *
198: */
199: public void callHandlersResponse(Direction direction, C context,
200: boolean isFault) {
201: setDirection(direction, context);
202: try {
203: if (isFault) {
204: // call handleFault on handlers
205: if (direction == Direction.OUTBOUND) {
206: callHandleFault(context, 0, handlers.size() - 1);
207: } else {
208: callHandleFault(context, handlers.size() - 1, 0);
209: }
210: } else {
211: // call handleMessage on handlers
212: if (direction == Direction.OUTBOUND) {
213: callHandleMessageReverse(context, 0, handlers
214: .size() - 1);
215: } else {
216: callHandleMessageReverse(context,
217: handlers.size() - 1, 0);
218: }
219: }
220: } catch (RuntimeException re) {
221: logger.log(Level.FINER, "exception in handler chain", re);
222: throw re;
223: }
224: }
225:
226: /**
227: * Reverses the Message Direction.
228: * MessageContext.MESSAGE_OUTBOUND_PROPERTY is changed.
229: */
230: private void reverseDirection(Direction origDirection, C context) {
231: if (origDirection == Direction.OUTBOUND) {
232: context
233: .put(MessageContext.MESSAGE_OUTBOUND_PROPERTY,
234: false);
235: } else {
236: context.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, true);
237: }
238: }
239:
240: /**
241: * Sets the Message Direction.
242: * MessageContext.MESSAGE_OUTBOUND_PROPERTY is changed.
243: */
244: private void setDirection(Direction direction, C context) {
245: if (direction == Direction.OUTBOUND) {
246: context.put(MessageContext.MESSAGE_OUTBOUND_PROPERTY, true);
247: } else {
248: context
249: .put(MessageContext.MESSAGE_OUTBOUND_PROPERTY,
250: false);
251: }
252: }
253:
254: /**
255: * When this property is set HandlerPipes can call handleFault() on the
256: * message
257: */
258: private void setHandleFaultProperty() {
259: owner.setHandleFault();
260: }
261:
262: /**
263: * When this property is set HandlerPipes will not call
264: * handleMessage() during Response processing.
265: */
266: private void setHandleFalseProperty() {
267: owner.setHandleFalse();
268: }
269:
270: /**
271: * When a ProtocolException is thrown, this is called.
272: * If it's XML/HTTP Binding, clear the the message
273: * If its SOAP/HTTP Binding, put right SOAP Fault version
274: */
275: abstract void insertFaultMessage(C context,
276: ProtocolException exception);
277:
278: /*
279: * Calls handleMessage on the handlers. Indices are
280: * inclusive. Exceptions get passed up the chain, and an
281: * exception or return of 'false' ends processing.
282: */
283: private boolean callHandleMessage(C context, int start, int end) {
284: /* Do we need this check?
285: if (handlers.isEmpty() ||
286: start == -1 ||
287: start == handlers.size()) {
288: return false;
289: }
290: */
291: int i = start;
292: try {
293: if (start > end) {
294: while (i >= end) {
295: if (!handlers.get(i).handleMessage(context)) {
296: setIndex(i);
297: return false;
298: }
299: i--;
300: }
301: } else {
302: while (i <= end) {
303: if (!handlers.get(i).handleMessage(context)) {
304: setIndex(i);
305: return false;
306: }
307: i++;
308: }
309: }
310: } catch (RuntimeException e) {
311: setIndex(i);
312: throw e;
313: }
314: return true;
315: }
316:
317: /*
318: * Calls handleMessage on the handlers. Indices are
319: * inclusive. Exceptions get passed up the chain, and an
320: * exception (or)
321: * return of 'false' calls addHandleFalseProperty(context) and
322: * ends processing.
323: * setIndex() is not called.
324: *
325: */
326: private boolean callHandleMessageReverse(C context, int start,
327: int end) {
328:
329: if (handlers.isEmpty() || start == -1
330: || start == handlers.size()) {
331: return false;
332: }
333:
334: int i = start;
335:
336: if (start > end) {
337: while (i >= end) {
338: if (!handlers.get(i).handleMessage(context)) {
339: // Set handleFalse so that cousinTube is aware of false processing
340: setHandleFalseProperty();
341: return false;
342: }
343: i--;
344: }
345: } else {
346: while (i <= end) {
347: if (!handlers.get(i).handleMessage(context)) {
348: // Set handleFalse so that cousinTube is aware of false processing
349: setHandleFalseProperty();
350: return false;
351: }
352: i++;
353: }
354: }
355: return true;
356: }
357:
358: /*
359: * Calls handleFault on the handlers. Indices are
360: * inclusive. Exceptions get passed up the chain, and an
361: * exception or return of 'false' ends processing.
362: */
363:
364: private boolean callHandleFault(C context, int start, int end) {
365:
366: if (handlers.isEmpty() || start == -1
367: || start == handlers.size()) {
368: return false;
369: }
370:
371: int i = start;
372: if (start > end) {
373: try {
374: while (i >= end) {
375: if (!handlers.get(i).handleFault(context)) {
376: return false;
377: }
378: i--;
379: }
380: } catch (RuntimeException re) {
381: logger.log(Level.FINER, "exception in handler chain",
382: re);
383: throw re;
384: }
385: } else {
386: try {
387: while (i <= end) {
388: if (!handlers.get(i).handleFault(context)) {
389: return false;
390: }
391: i++;
392: }
393: } catch (RuntimeException re) {
394: logger.log(Level.FINER, "exception in handler chain",
395: re);
396: throw re;
397: }
398: }
399: return true;
400: }
401:
402: /**
403: * Calls close on the handlers from the starting
404: * index through the ending index (inclusive). Made indices
405: * inclusive to allow both directions more easily.
406: */
407: void closeHandlers(MessageContext context, int start, int end) {
408: if (handlers.isEmpty() || start == -1) {
409: return;
410: }
411: if (start > end) {
412: for (int i = start; i >= end; i--) {
413: try {
414: handlers.get(i).close(context);
415: } catch (RuntimeException re) {
416: logger.log(Level.INFO,
417: "Exception ignored during close", re);
418: }
419: }
420: } else {
421: for (int i = start; i <= end; i++) {
422: try {
423: handlers.get(i).close(context);
424: } catch (RuntimeException re) {
425: logger.log(Level.INFO,
426: "Exception ignored during close", re);
427: }
428: }
429: }
430: }
431: }
|