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.handler;
038:
039: import com.sun.istack.Nullable;
040: import com.sun.xml.ws.api.message.Packet;
041: import com.sun.xml.ws.api.model.wsdl.WSDLPort;
042: import com.sun.xml.ws.api.pipe.*;
043: import com.sun.xml.ws.api.pipe.helper.AbstractFilterTubeImpl;
044:
045: import javax.xml.ws.handler.MessageContext;
046: import javax.xml.ws.handler.Handler;
047: import java.util.List;
048:
049: /**
050: * @author WS Development team
051: */
052:
053: public abstract class HandlerTube extends AbstractFilterTubeImpl {
054: /**
055: * handle hold reference to other Tube for inter-tube communication
056: */
057: HandlerTube cousinTube;
058: protected List<Handler> handlers;
059: HandlerProcessor processor;
060: boolean remedyActionTaken = false;
061: private final @Nullable
062: WSDLPort port;
063: // flag used to decide whether to call close on cousinTube
064: boolean requestProcessingSucessful = false;
065:
066: // TODO: For closing in Exceptions this is needed
067: // This is used for creating MessageContext in #close
068: Packet packet;
069:
070: public HandlerTube(Tube next, WSDLPort port) {
071: super (next);
072: this .port = port;
073: }
074:
075: public HandlerTube(Tube next, HandlerTube cousinTube) {
076: super (next);
077: this .cousinTube = cousinTube;
078: if (cousinTube != null) {
079: this .port = cousinTube.port;
080: } else {
081: this .port = null;
082: }
083: }
084:
085: /**
086: * Copy constructor for {@link Tube#copy(TubeCloner)}.
087: */
088: protected HandlerTube(HandlerTube that, TubeCloner cloner) {
089: super (that, cloner);
090: if (that.cousinTube != null) {
091: this .cousinTube = cloner.copy(that.cousinTube);
092: }
093: this .port = that.port;
094: }
095:
096: @Override
097: public NextAction processRequest(Packet request) {
098: this .packet = request;
099: setupExchange();
100: // This check is done to cover handler returning false in Oneway request
101: if (isHandleFalse()) {
102: // Cousin HandlerTube returned false during Oneway Request processing.
103: // Don't call handlers and dispatch the message.
104: remedyActionTaken = true;
105: return doInvoke(super .next, packet);
106: }
107:
108: // This is done here instead of the constructor, since User can change
109: // the roles and handlerchain after a stub/proxy is created.
110: setUpProcessor();
111:
112: MessageUpdatableContext context = getContext(packet);
113: boolean isOneWay = checkOneWay(packet);
114: try {
115: if (!isHandlerChainEmpty()) {
116: // Call handlers on Request
117: boolean handlerResult = callHandlersOnRequest(context,
118: isOneWay);
119: //Update Packet with user modifications
120: context.updatePacket();
121: // two-way case where no message is sent
122: if (!isOneWay && !handlerResult) {
123: return doReturnWith(packet);
124: }
125: }
126: requestProcessingSucessful = true;
127: // Call next Tube
128: return doInvoke(super .next, packet);
129: } catch (RuntimeException re) {
130: if (isOneWay) {
131: //Eat the exception, its already logged and close the transportBackChannel
132: if (packet.transportBackChannel != null) {
133: packet.transportBackChannel.close();
134: }
135: packet.setMessage(null);
136: return doReturnWith(packet);
137: } else
138: throw re;
139: } finally {
140: if (!requestProcessingSucessful) {
141: initiateClosing(context.getMessageContext());
142: }
143: }
144:
145: }
146:
147: @Override
148: public NextAction processResponse(Packet response) {
149: this .packet = response;
150: MessageUpdatableContext context = getContext(packet);
151: try {
152: if (isHandleFalse() || (packet.getMessage() == null)) {
153: // Cousin HandlerTube returned false during Response processing.
154: // or it is oneway request
155: // or handler chain is empty
156: // Don't call handlers.
157: return doReturnWith(packet);
158: }
159: boolean isFault = isHandleFault(packet);
160: if (!isHandlerChainEmpty()) {
161: // Call handlers on Response
162: callHandlersOnResponse(context, isFault);
163: }
164: } finally {
165: initiateClosing(context.getMessageContext());
166: }
167: //Update Packet with user modifications
168: context.updatePacket();
169:
170: return doReturnWith(packet);
171:
172: }
173:
174: @Override
175: public NextAction processException(Throwable t) {
176: try {
177: return doThrow(t);
178: } finally {
179: MessageUpdatableContext context = getContext(packet);
180: initiateClosing(context.getMessageContext());
181: /* TODO revisit: commented this out as the modified packet is no longer used
182: In future if the message is propagated even when an exception
183: occurs, then uncomment context.updatePacket();
184: */
185: //Update Packet with user modifications
186: //context.updatePacket();
187:
188: }
189: }
190:
191: /**
192: * Must be overridden by HandlerTube that drives other handler tubes for processing a message.
193: * On Client-side: ClientLogicalHandlerTube drives the Handler Processing.
194: * On Server-side: In case SOAP Binding, ServerMessageHandlerTube drives the Handler Processing.
195: * In case XML/HTTP Binding, ServerLogicalHandlerTube drives the Handler Processing.
196: *
197: *
198: * If its a top HandlerTube, should override by calling #close(MessaggeContext);
199: *
200: */
201:
202: protected void initiateClosing(MessageContext mc) {
203: // Do nothing
204:
205: }
206:
207: /**
208: * Calls close on previously invoked handlers.
209: * Also, Cleans up any state left over in the Tube instance from the current
210: * invocation, as Tube instances can be reused after the completion of MEP.
211: *
212: * On Client, SOAPHandlers are closed first and then LogicalHandlers
213: * On Server, LogicalHandlers are closed first and then SOAPHandlers
214: */
215: final public void close(MessageContext msgContext) {
216: //assuming cousinTube is called if requestProcessingSucessful is true
217: if (requestProcessingSucessful) {
218: if (cousinTube != null) {
219: cousinTube.close(msgContext);
220: }
221:
222: }
223: if (processor != null)
224: closeHandlers(msgContext);
225:
226: // Clean up the exchange for next invocation.
227: exchange = null;
228: requestProcessingSucessful = false;
229:
230: }
231:
232: /**
233: * On Client, Override by calling #closeClientHandlers(MessageContext mc)
234: * On Server, Override by calling #closeServerHandlers(MessageContext mc)
235: * The difference is the order in which they are closed.
236: * @param mc
237: */
238: abstract void closeHandlers(MessageContext mc);
239:
240: /**
241: * Called by close(MessageContext mc) in a Client Handlertube
242: */
243: protected void closeClientsideHandlers(MessageContext msgContext) {
244: if (processor == null)
245: return;
246: if (remedyActionTaken) {
247: //Close only invoked handlers in the chain
248:
249: //CLIENT-SIDE
250: processor
251: .closeHandlers(msgContext, processor.getIndex(), 0);
252: processor.setIndex(-1);
253: //reset remedyActionTaken
254: remedyActionTaken = false;
255: } else {
256: //Close all handlers in the chain
257:
258: //CLIENT-SIDE
259: processor.closeHandlers(msgContext, handlers.size() - 1, 0);
260:
261: }
262: }
263:
264: /**
265: * Called by close(MessageContext mc) in a Server Handlertube
266: */
267: protected void closeServersideHandlers(MessageContext msgContext) {
268: if (processor == null)
269: return;
270: if (remedyActionTaken) {
271: //Close only invoked handlers in the chain
272:
273: //SERVER-SIDE
274: processor.closeHandlers(msgContext, processor.getIndex(),
275: handlers.size() - 1);
276: processor.setIndex(-1);
277: //reset remedyActionTaken
278: remedyActionTaken = false;
279: } else {
280: //Close all handlers in the chain
281:
282: //SERVER-SIDE
283: processor.closeHandlers(msgContext, 0, handlers.size() - 1);
284:
285: }
286: }
287:
288: abstract void callHandlersOnResponse(
289: MessageUpdatableContext context, boolean handleFault);
290:
291: abstract boolean callHandlersOnRequest(
292: MessageUpdatableContext context, boolean oneWay);
293:
294: private boolean checkOneWay(Packet packet) {
295: if (port != null) {
296: /* we can determine this value from WSDL */
297: return packet.getMessage().isOneWay(port);
298: } else {
299: /*
300: otherwise use this value as an approximation, since this carries
301: the appliation's intention --- whether it was invokeOneway vs invoke,etc.
302: */
303: return !(packet.expectReply != null && packet.expectReply);
304: }
305: }
306:
307: abstract void setUpProcessor();
308:
309: final public boolean isHandlerChainEmpty() {
310: return handlers.isEmpty();
311: }
312:
313: abstract MessageUpdatableContext getContext(Packet p);
314:
315: private boolean isHandleFault(Packet packet) {
316: if (cousinTube != null) {
317: return exchange.isHandleFault();
318: } else {
319: boolean isFault = packet.getMessage().isFault();
320: exchange.setHandleFault(isFault);
321: return isFault;
322: }
323: }
324:
325: final void setHandleFault() {
326: exchange.setHandleFault(true);
327: }
328:
329: private boolean isHandleFalse() {
330: return exchange.isHandleFalse();
331: }
332:
333: final void setHandleFalse() {
334: exchange.setHandleFalse();
335: }
336:
337: private void setupExchange() {
338: if (exchange == null) {
339: exchange = new HandlerTubeExchange();
340: if (cousinTube != null) {
341: cousinTube.exchange = exchange;
342: }
343: } else {
344: if (cousinTube != null) {
345: cousinTube.exchange = exchange;
346: }
347:
348: }
349: }
350:
351: private HandlerTubeExchange exchange;
352:
353: /**
354: * This class is used primarily to exchange information or status between
355: * LogicalHandlerTube and SOAPHandlerTube
356: */
357: static final class HandlerTubeExchange {
358: private boolean handleFalse;
359: private boolean handleFault;
360:
361: boolean isHandleFault() {
362: return handleFault;
363: }
364:
365: void setHandleFault(boolean isFault) {
366: this .handleFault = isFault;
367: }
368:
369: public boolean isHandleFalse() {
370: return handleFalse;
371: }
372:
373: void setHandleFalse() {
374: this .handleFalse = true;
375: }
376: }
377:
378: }
|