1/* 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.xml.internal.ws.handler; 27 28import com.sun.istack.internal.Nullable; 29import com.sun.xml.internal.ws.api.WSBinding; 30import com.sun.xml.internal.ws.api.message.Packet; 31import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort; 32import com.sun.xml.internal.ws.api.pipe.*; 33import com.sun.xml.internal.ws.api.pipe.helper.AbstractFilterTubeImpl; 34import com.sun.xml.internal.ws.binding.BindingImpl; 35import com.sun.xml.internal.ws.client.HandlerConfiguration; 36 37import javax.xml.ws.handler.MessageContext; 38import javax.xml.ws.handler.Handler; 39import java.util.List; 40 41/** 42 * @author WS Development team 43 */ 44 45public abstract class HandlerTube extends AbstractFilterTubeImpl { 46 /** 47 * handle hold reference to other Tube for inter-tube communication 48 */ 49 HandlerTube cousinTube; 50 protected List<Handler> handlers; 51 HandlerProcessor processor; 52 boolean remedyActionTaken = false; 53 protected final @Nullable WSDLPort port; 54 // flag used to decide whether to call close on cousinTube 55 boolean requestProcessingSucessful = false; 56 private WSBinding binding; 57 private HandlerConfiguration hc; 58 59 public HandlerTube(Tube next, WSDLPort port, WSBinding binding) { 60 super(next); 61 this.port = port; 62 this.binding = binding; 63 } 64 65 public HandlerTube(Tube next, HandlerTube cousinTube, WSBinding binding) { 66 super(next); 67 this.cousinTube = cousinTube; 68 this.binding = binding; 69 if(cousinTube != null) { 70 this.port = cousinTube.port; 71 } else { 72 this.port = null; 73 } 74 } 75 76 /** 77 * Copy constructor for {@link Tube#copy(TubeCloner)}. 78 */ 79 protected HandlerTube(HandlerTube that, TubeCloner cloner) { 80 super(that,cloner); 81 if(that.cousinTube != null) { 82 this.cousinTube = cloner.copy(that.cousinTube); 83 } 84 this.port = that.port; 85 this.binding = that.binding; 86 } 87 88 protected WSBinding getBinding() { 89 return binding; 90 } 91 92 @Override 93 public NextAction processRequest(Packet request) { 94 setupExchange(); 95 // This check is done to cover handler returning false in Oneway request 96 if (isHandleFalse()) { 97 // Cousin HandlerTube returned false during Oneway Request processing. 98 // Don't call handlers and dispatch the message. 99 remedyActionTaken = true; 100 return doInvoke(super.next, request); 101 } 102 103 // This is done here instead of the constructor, since User can change 104 // the roles and handlerchain after a stub/proxy is created. 105 setUpProcessorInternal(); 106 107 MessageUpdatableContext context = getContext(request); 108 boolean isOneWay = checkOneWay(request); 109 try { 110 if (!isHandlerChainEmpty()) { 111 // Call handlers on Request 112 boolean handlerResult = callHandlersOnRequest(context, isOneWay); 113 //Update Packet with user modifications 114 context.updatePacket(); 115 // two-way case where no message is sent 116 if (!isOneWay && !handlerResult) { 117 return doReturnWith(request); 118 } 119 } 120 requestProcessingSucessful = true; 121 // Call next Tube 122 return doInvoke(super.next, request); 123 } catch (RuntimeException re) { 124 if(isOneWay) { 125 //Eat the exception, its already logged and close the transportBackChannel 126 if(request.transportBackChannel != null ) { 127 request.transportBackChannel.close(); 128 } 129 request.setMessage(null); 130 return doReturnWith(request); 131 } else 132 throw re; 133 } finally { 134 if(!requestProcessingSucessful) { 135 initiateClosing(context.getMessageContext()); 136 } 137 } 138 139 } 140 141 @Override 142 public NextAction processResponse(Packet response) { 143 setupExchange(); 144 MessageUpdatableContext context = getContext(response); 145 try { 146 if (isHandleFalse() || (response.getMessage() == null)) { 147 // Cousin HandlerTube returned false during Response processing. 148 // or it is oneway request 149 // or handler chain is empty 150 // Don't call handlers. 151 return doReturnWith(response); 152 } 153 154 setUpProcessorInternal(); 155 156 boolean isFault = isHandleFault(response); 157 if (!isHandlerChainEmpty()) { 158 // Call handlers on Response 159 callHandlersOnResponse(context, isFault); 160 } 161 } finally { 162 initiateClosing(context.getMessageContext()); 163 } 164 //Update Packet with user modifications 165 context.updatePacket(); 166 167 return doReturnWith(response); 168 169 } 170 171 @Override 172 public NextAction processException(Throwable t) { 173 try { 174 return doThrow(t); 175 } finally { 176 Packet packet = Fiber.current().getPacket(); 177 MessageUpdatableContext context = getContext(packet); 178 initiateClosing(context.getMessageContext()); 179 /* TODO revisit: commented this out as the modified packet is no longer used 180 In future if the message is propagated even when an exception 181 occurs, then uncomment context.updatePacket(); 182 */ 183 //Update Packet with user modifications 184 //context.updatePacket(); 185 186 187 } 188 } 189 190 /** 191 * Must be overridden by HandlerTube that drives other handler tubes for processing a message. 192 * On Client-side: ClientLogicalHandlerTube drives the Handler Processing. 193 * On Server-side: In case SOAP Binding, ServerMessageHandlerTube drives the Handler Processing. 194 * In case XML/HTTP Binding, ServerLogicalHandlerTube drives the Handler Processing. 195 * 196 * 197 * If its a top HandlerTube, should override by calling #close(MessaggeContext); 198 * 199 */ 200 201 protected void initiateClosing(MessageContext mc) { 202 // Do nothing 203 204 } 205 206 /** 207 * Calls close on previously invoked handlers. 208 * Also, Cleans up any state left over in the Tube instance from the current 209 * invocation, as Tube instances can be reused after the completion of MEP. 210 * 211 * On Client, SOAPHandlers are closed first and then LogicalHandlers 212 * On Server, LogicalHandlers are closed first and then SOAPHandlers 213 */ 214 final public void close(MessageContext msgContext) { 215 //assuming cousinTube is called if requestProcessingSucessful is true 216 if (requestProcessingSucessful) { 217 if (cousinTube != null) { 218 cousinTube.close(msgContext); 219 } 220 221 } 222 if (processor != null) 223 closeHandlers(msgContext); 224 225 // Clean up the exchange for next invocation. 226 exchange = null; 227 requestProcessingSucessful = false; 228 229 } 230 231 /** 232 * On Client, Override by calling #closeClientHandlers(MessageContext mc) 233 * On Server, Override by calling #closeServerHandlers(MessageContext mc) 234 * The difference is the order in which they are closed. 235 * @param mc 236 */ 237 abstract void closeHandlers(MessageContext mc); 238 239 /** 240 * Called by close(MessageContext mc) in a Client Handlertube 241 */ 242 protected void closeClientsideHandlers(MessageContext msgContext) { 243 if (processor == null) 244 return; 245 if (remedyActionTaken) { 246 //Close only invoked handlers in the chain 247 248 //CLIENT-SIDE 249 processor.closeHandlers(msgContext, processor.getIndex(), 0); 250 processor.setIndex(-1); 251 //reset remedyActionTaken 252 remedyActionTaken = false; 253 } else { 254 //Close all handlers in the chain 255 256 //CLIENT-SIDE 257 processor.closeHandlers(msgContext, handlers.size() - 1, 0); 258 259 } 260 } 261 262 /** 263 * Called by close(MessageContext mc) in a Server Handlertube 264 */ 265 protected void closeServersideHandlers(MessageContext msgContext) { 266 if (processor == null) 267 return; 268 if (remedyActionTaken) { 269 //Close only invoked handlers in the chain 270 271 //SERVER-SIDE 272 processor.closeHandlers(msgContext, processor.getIndex(), handlers.size() - 1); 273 processor.setIndex(-1); 274 //reset remedyActionTaken 275 remedyActionTaken = false; 276 } else { 277 //Close all handlers in the chain 278 279 //SERVER-SIDE 280 processor.closeHandlers(msgContext, 0, handlers.size() - 1); 281 282 } 283 } 284 285 abstract void callHandlersOnResponse(MessageUpdatableContext context, boolean handleFault); 286 287 abstract boolean callHandlersOnRequest(MessageUpdatableContext context, boolean oneWay); 288 289 private boolean checkOneWay(Packet packet) { 290 if (port != null) { 291 /* we can determine this value from WSDL */ 292 return packet.getMessage().isOneWay(port); 293 } else { 294 /* 295 otherwise use this value as an approximation, since this carries 296 the application's intention --- whether it was invokeOneway vs invoke,etc. 297 */ 298 return !(packet.expectReply != null && packet.expectReply); 299 } 300 } 301 302 private void setUpProcessorInternal() { 303 HandlerConfiguration hc = ((BindingImpl) binding).getHandlerConfig(); 304 if (hc != this.hc) 305 resetProcessor(); 306 this.hc = hc; 307 308 setUpProcessor(); 309 } 310 311 abstract void setUpProcessor(); 312 313 protected void resetProcessor() { 314 handlers = null; 315 } 316 317 final public boolean isHandlerChainEmpty() { 318 return handlers.isEmpty(); 319 } 320 abstract MessageUpdatableContext getContext(Packet p); 321 322 private boolean isHandleFault(Packet packet) { 323 if (cousinTube != null) { 324 return exchange.isHandleFault(); 325 } else { 326 boolean isFault = packet.getMessage().isFault(); 327 exchange.setHandleFault(isFault); 328 return isFault; 329 } 330 } 331 332 final void setHandleFault() { 333 exchange.setHandleFault(true); 334 } 335 336 private boolean isHandleFalse() { 337 return exchange.isHandleFalse(); 338 } 339 340 final void setHandleFalse() { 341 exchange.setHandleFalse(); 342 } 343 344 private void setupExchange() { 345 if(exchange == null) { 346 exchange = new HandlerTubeExchange(); 347 if(cousinTube != null) { 348 cousinTube.exchange = exchange; 349 } 350 } else { 351 if(cousinTube != null) { 352 cousinTube.exchange = exchange; 353 } 354 355 } 356 } 357 private HandlerTubeExchange exchange; 358 359 /** 360 * This class is used primarily to exchange information or status between 361 * LogicalHandlerTube and SOAPHandlerTube 362 */ 363 static final class HandlerTubeExchange { 364 private boolean handleFalse; 365 private boolean handleFault; 366 367 boolean isHandleFault() { 368 return handleFault; 369 } 370 371 void setHandleFault(boolean isFault) { 372 this.handleFault = isFault; 373 } 374 375 public boolean isHandleFalse() { 376 return handleFalse; 377 } 378 379 void setHandleFalse() { 380 this.handleFalse = true; 381 } 382 } 383 384} 385