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 26 package com.sun.xml.internal.ws.api.message; 27 28 import com.oracle.webservices.internal.api.message.ContentType; 29 import com.oracle.webservices.internal.api.message.PropertySet; 30 import com.sun.istack.internal.NotNull; 31 import com.sun.istack.internal.Nullable; 32 import com.sun.xml.internal.bind.marshaller.SAX2DOMEx; 33 import com.sun.xml.internal.ws.addressing.WsaPropertyBag; 34 import com.sun.xml.internal.ws.addressing.WsaServerTube; 35 import com.sun.xml.internal.ws.addressing.WsaTubeHelper; 36 import com.sun.xml.internal.ws.api.Component; 37 import com.sun.xml.internal.ws.api.EndpointAddress; 38 import com.sun.xml.internal.ws.api.SOAPVersion; 39 import com.sun.xml.internal.ws.api.WSBinding; 40 import com.sun.xml.internal.ws.api.addressing.AddressingVersion; 41 import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; 42 import com.sun.xml.internal.ws.api.model.JavaMethod; 43 import com.sun.xml.internal.ws.api.model.SEIModel; 44 import com.sun.xml.internal.ws.api.model.WSDLOperationMapping; 45 import com.sun.xml.internal.ws.api.model.wsdl.WSDLOperation; 46 import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort; 47 import com.sun.xml.internal.ws.api.pipe.Codec; 48 import com.sun.xml.internal.ws.api.pipe.Tube; 49 import com.sun.xml.internal.ws.api.server.Adapter; 50 import com.sun.xml.internal.ws.api.server.TransportBackChannel; 51 import com.sun.xml.internal.ws.api.server.WSEndpoint; 52 import com.sun.xml.internal.ws.api.server.WebServiceContextDelegate; 53 import com.sun.xml.internal.ws.api.streaming.XMLStreamWriterFactory; 54 import com.sun.xml.internal.ws.client.*; 55 import com.sun.xml.internal.ws.developer.JAXWSProperties; 56 import com.sun.xml.internal.ws.encoding.MtomCodec; 57 import com.sun.xml.internal.ws.message.RelatesToHeader; 58 import com.sun.xml.internal.ws.message.StringHeader; 59 import com.sun.xml.internal.ws.util.DOMUtil; 60 import com.sun.xml.internal.ws.util.xml.XmlUtil; 61 import com.sun.xml.internal.ws.wsdl.DispatchException; 62 import com.sun.xml.internal.ws.wsdl.OperationDispatcher; 63 import com.sun.xml.internal.ws.resources.AddressingMessages; 64 65 66 import org.w3c.dom.Document; 67 import org.w3c.dom.Element; 68 import org.xml.sax.SAXException; 69 70 import javax.xml.namespace.QName; 71 import javax.xml.soap.SOAPException; 72 import javax.xml.soap.SOAPMessage; 73 import javax.xml.stream.XMLStreamWriter; 74 import javax.xml.stream.XMLStreamException; 75 import javax.xml.ws.BindingProvider; 76 import javax.xml.ws.Dispatch; 77 import javax.xml.ws.WebServiceContext; 78 import javax.xml.ws.WebServiceException; 79 import javax.xml.ws.handler.LogicalMessageContext; 80 import javax.xml.ws.handler.MessageContext; 81 import javax.xml.ws.handler.soap.SOAPMessageContext; 82 import javax.xml.ws.soap.MTOMFeature; 83 84 import java.util.*; 85 import java.util.logging.Logger; 86 import java.io.ByteArrayOutputStream; 87 import java.io.IOException; 88 import java.io.OutputStream; 89 import java.nio.channels.WritableByteChannel; 90 91 /** 92 * Represents a container of a {@link Message}. 93 * 94 * <h2>What is a {@link Packet}?</h2> 95 * <p> 96 * A packet can be thought of as a frame/envelope/package that wraps 97 * a {@link Message}. A packet keeps track of optional metadata (properties) 98 * about a {@link Message} that doesn't go across the wire. 99 * This roughly corresponds to {@link MessageContext} in the JAX-WS API. 100 * 101 * <p> 102 * Usually a packet contains a {@link Message} in it, but sometimes 103 * (such as for a reply of an one-way operation), a packet may 104 * float around without a {@link Message} in it. 105 * 106 * 107 * <a name="properties"></a> 108 * <h2>Properties</h2> 109 * <p> 110 * Information frequently used inside the JAX-WS RI 111 * is stored in the strongly-typed fields. Other information is stored 112 * in terms of a generic {@link Map} (see 113 * {@link #invocationProperties}.) 114 * 115 * <p> 116 * Some properties need to be retained between request and response, 117 * some don't. For strongly typed fields, this characteristic is 118 * statically known for each of them, and propagation happens accordingly. 119 * For generic information stored in {@link Map}, {@link #invocationProperties} 120 * stores per-invocation scope information (which carries over to 121 * the response.) 122 * 123 * <p> 124 * This object is used as the backing store of {@link MessageContext}, and 125 * {@link LogicalMessageContext} and {@link SOAPMessageContext} will 126 * be delegating to this object for storing/retrieving values. 127 * 128 * 129 * <h3>Relationship to request/response context</h3> 130 * <p> 131 * {@link BindingProvider#getRequestContext() Request context} is used to 132 * seed the initial values of {@link Packet}. 133 * Some of those values go to strongly-typed fields, and others go to 134 * {@link #invocationProperties}, as they need to be retained in the reply message. 135 * 136 * <p> 137 * Similarly, {@link BindingProvider#getResponseContext() response context} 138 * is constructed from {@link Packet} (or rather it's just a view of {@link Packet}.) 139 * by using properties from {@link #invocationProperties}, 140 * modulo properties named explicitly in {@link #getHandlerScopePropertyNames(boolean)}. 141 * IOW, properties added to {@link #invocationProperties} 142 * are exposed to the response context by default. 143 * 144 * 145 * 146 * <h3>TODO</h3> 147 * <ol> 148 * <li>this class needs to be cloneable since Message is copiable. 149 * <li>The three live views aren't implemented correctly. It will be 150 * more work to do so, although I'm sure it's possible. 151 * <li>{@link PropertySet.Property} annotation is to make it easy 152 * for {@link MessageContext} to export properties on this object, 153 * but it probably needs some clean up. 154 * </ol> 155 * 156 * @author Kohsuke Kawaguchi 157 */ 158 public final class Packet 159 // Packet must continue to extend/implement deprecated interfaces until downstream 160 // usage is updated. 161 extends com.oracle.webservices.internal.api.message.BaseDistributedPropertySet 162 implements com.oracle.webservices.internal.api.message.MessageContext, MessageMetadata { 163 164 /** 165 * Creates a {@link Packet} that wraps a given {@link Message}. 166 * 167 * <p> 168 * This method should be only used to create a fresh {@link Packet}. 169 * To create a {@link Packet} for a reply, use {@link #createResponse(Message)}. 170 * 171 * @param request 172 * The request {@link Message}. Can be null. 173 */ 174 public Packet(Message request) { 175 this(); 176 this.message = request; 177 if (message != null) message.setMessageMedadata(this); 178 } 179 180 /** 181 * Creates an empty {@link Packet} that doesn't have any {@link Message}. 182 */ 183 public Packet() { 184 this.invocationProperties = new HashMap<String, Object>(); 185 } 186 187 /** 188 * Used by {@link #createResponse(Message)} and {@link #copy(boolean)}. 189 */ 190 private Packet(Packet that) { 191 relatePackets(that, true); 192 this.invocationProperties = that.invocationProperties; 193 } 194 195 /** 196 * Creates a copy of this {@link Packet}. 197 * 198 * @param copyMessage determines whether the {@link Message} from the original {@link Packet} should be copied as 199 * well, or not. If the value is {@code false}, the {@link Message} in the copy of the {@link Packet} is {@code null}. 200 * @return copy of the original packet 201 */ 202 public Packet copy(boolean copyMessage) { 203 // the copy constructor is originally designed for creating a response packet, 204 // but so far the implementation is usable for this purpose as well, so calling the copy constructor 205 // to avoid code dupliation. 206 Packet copy = new Packet(this); 207 if (copyMessage && this.message != null) { 208 copy.message = this.message.copy(); 209 } 210 if (copy.message != null) copy.message.setMessageMedadata(copy); 211 return copy; 212 } 213 214 private Message message; 215 216 /** 217 * Gets the last {@link Message} set through {@link #setMessage(Message)}. 218 * 219 * @return may null. See the class javadoc for when it's null. 220 */ 221 public Message getMessage() { 222 if (message != null && !(message instanceof MessageWrapper)) { 223 message = new MessageWrapper(this, message); 224 } 225 return message; 226 } 227 228 public Message getInternalMessage() { 229 return (message instanceof MessageWrapper)? ((MessageWrapper)message).delegate : message; 230 } 231 232 public WSBinding getBinding() { 233 if (endpoint != null) { 234 return endpoint.getBinding(); 235 } 236 if (proxy != null) { 237 return (WSBinding) proxy.getBinding(); 238 } 239 return null; 240 } 241 /** 242 * Sets a {@link Message} to this packet. 243 * 244 * @param message Can be null. 245 */ 246 public void setMessage(Message message) { 247 this.message = message; 248 if (message != null) this.message.setMessageMedadata(this); 249 } 250 251 private WSDLOperationMapping wsdlOperationMapping = null; 252 253 private QName wsdlOperation; 254 255 /** 256 * Returns the QName of the wsdl operation associated with this packet. 257 * <p/> 258 * Information such as Payload QName, wsa:Action header, SOAPAction HTTP header are used depending on the features 259 * enabled on the particular port. 260 * 261 * @return null if there is no WSDL model or 262 * runtime cannot uniquely identify the wsdl operation from the information in the packet. 263 */ 264 @Property(MessageContext.WSDL_OPERATION) 265 public final 266 @Nullable 267 QName getWSDLOperation() { 268 if (wsdlOperation != null) return wsdlOperation; 269 if ( wsdlOperationMapping == null) wsdlOperationMapping = getWSDLOperationMapping(); 270 if ( wsdlOperationMapping != null ) wsdlOperation = wsdlOperationMapping.getOperationName(); 271 return wsdlOperation; 272 } 273 274 public WSDLOperationMapping getWSDLOperationMapping() { 275 if (wsdlOperationMapping != null) return wsdlOperationMapping; 276 OperationDispatcher opDispatcher = null; 277 if (endpoint != null) { 278 opDispatcher = endpoint.getOperationDispatcher(); 279 } else if (proxy != null) { 280 opDispatcher = ((Stub) proxy).getOperationDispatcher(); 281 } 282 //OpDispatcher is null when there is no WSDLModel 283 if (opDispatcher != null) { 284 try { 285 wsdlOperationMapping = opDispatcher.getWSDLOperationMapping(this); 286 } catch (DispatchException e) { 287 //Ignore, this might be a protocol message which may not have a wsdl operation 288 //LOGGER.info("Cannot resolve wsdl operation that this Packet is targeted for."); 289 } 290 } 291 return wsdlOperationMapping; 292 } 293 294 /** 295 * Set the wsdl operation to avoid lookup from other data. 296 * This is useful in SEI based clients, where the WSDL operation can be known 297 * from the associated {@link JavaMethod} 298 * 299 * @param wsdlOp QName 300 */ 301 public void setWSDLOperation(QName wsdlOp) { 302 this.wsdlOperation = wsdlOp; 303 } 304 305 /** 306 * True if this message came from a transport (IOW inbound), 307 * and in paricular from a "secure" transport. A transport 308 * needs to set this flag appropriately. 309 * 310 * <p> 311 * This is a requirement from the security team. 312 */ 313 // TODO: expose this as a property 314 public boolean wasTransportSecure; 315 316 /** 317 * Inbound transport headers are captured in a transport neutral way. 318 * Transports are expected to fill this data after creating a Packet. 319 * <p> 320 * {@link SOAPMessage#getMimeHeaders()} would return these headers. 321 */ 322 public static final String INBOUND_TRANSPORT_HEADERS = "com.sun.xml.internal.ws.api.message.packet.inbound.transport.headers"; 323 324 /** 325 * Outbound transport headers are captured in a transport neutral way. 326 * 327 * <p> 328 * Transports may choose to ignore certain headers that interfere with 329 * its correct operation, such as 330 * <tt>Content-Type</tt> and <tt>Content-Length</tt>. 331 */ 332 public static final String OUTBOUND_TRANSPORT_HEADERS = "com.sun.xml.internal.ws.api.message.packet.outbound.transport.headers"; 333 334 /** 335 * 336 */ 337 public static final String HA_INFO = "com.sun.xml.internal.ws.api.message.packet.hainfo"; 338 339 340 /** 341 * This property holds the snapshot of HandlerConfiguration 342 * at the time of invocation. 343 * This property is used by MUPipe and HandlerPipe implementations. 344 */ 345 @Property(BindingProviderProperties.JAXWS_HANDLER_CONFIG) 346 public HandlerConfiguration handlerConfig; 347 348 /** 349 * If a message originates from a proxy stub that implements 350 * a port interface, this field is set to point to that object. 351 * 352 * TODO: who's using this property? 353 */ 354 @Property(BindingProviderProperties.JAXWS_CLIENT_HANDLE_PROPERTY) 355 public BindingProvider proxy; 356 357 /** 358 * Determines if the governing {@link Adapter} or {@link com.sun.xml.internal.ws.api.pipe.Fiber.CompletionCallback} 359 * will handle delivering response messages targeted at non-anonymous endpoint 360 * addresses. Prior to the introduction of this flag 361 * the {@link WsaServerTube} would deliver non-anonymous responses. 362 */ 363 public boolean isAdapterDeliversNonAnonymousResponse; 364 365 /** 366 * During invocation of a client Stub or Dispatch a Packet is 367 * created then the Stub's RequestContext is copied into the 368 * Packet. On certain internal cases the Packet is created 369 * *before* the invocation. In those cases we want the contents 370 * of the Packet to take precedence when ever any key/value pairs 371 * collide : if the Packet contains a value for a key use it, 372 * otherwise copy as usual from Stub. 373 */ 374 public boolean packetTakesPriorityOverRequestContext = false; 375 376 /** 377 * The endpoint address to which this message is sent to. 378 * 379 * <p> 380 * The JAX-WS spec allows this to be changed for each message, 381 * so it's designed to be a property. 382 * 383 * <p> 384 * Must not be null for a request message on the client. Otherwise 385 * it's null. 386 */ 387 public EndpointAddress endpointAddress; 388 389 /** 390 * @deprecated 391 * The programatic acccess should be done via 392 * {@link #endpointAddress}. This is for JAX-WS client applications 393 * that access this property via {@link BindingProvider#ENDPOINT_ADDRESS_PROPERTY}. 394 */ 395 @Property(BindingProvider.ENDPOINT_ADDRESS_PROPERTY) 396 public String getEndPointAddressString() { 397 if (endpointAddress == null) { 398 return null; 399 } else { 400 return endpointAddress.toString(); 401 } 402 } 403 404 public void setEndPointAddressString(String s) { 405 if (s == null) { 406 this.endpointAddress = null; 407 } else { 408 this.endpointAddress = EndpointAddress.create(s); 409 } 410 } 411 412 /** 413 * The value of {@link ContentNegotiation#PROPERTY} 414 * property. 415 * <p/> 416 * This property is used only on the client side. 417 */ 418 public ContentNegotiation contentNegotiation; 419 420 @Property(ContentNegotiation.PROPERTY) 421 public String getContentNegotiationString() { 422 return (contentNegotiation != null) ? contentNegotiation.toString() : null; 423 } 424 425 public void setContentNegotiationString(String s) { 426 if (s == null) { 427 contentNegotiation = null; 428 } else { 429 try { 430 contentNegotiation = ContentNegotiation.valueOf(s); 431 } catch (IllegalArgumentException e) { 432 // If the value is not recognized default to none 433 contentNegotiation = ContentNegotiation.none; 434 } 435 } 436 } 437 438 /** 439 * Gives a list of Reference Parameters in the Message 440 * <p> 441 * Headers which have attribute wsa:IsReferenceParameter="true" 442 * This is not cached as one may reset the Message. 443 *<p> 444 */ 445 @Property(MessageContext.REFERENCE_PARAMETERS) 446 public 447 @NotNull 448 List<Element> getReferenceParameters() { 449 Message msg = getMessage(); 450 List<Element> refParams = new ArrayList<Element>(); 451 if (msg == null) { 452 return refParams; 453 } 454 MessageHeaders hl = msg.getHeaders(); 455 for (Header h : hl.asList()) { 456 String attr = h.getAttribute(AddressingVersion.W3C.nsUri, "IsReferenceParameter"); 457 if (attr != null && (attr.equals("true") || attr.equals("1"))) { 458 Document d = DOMUtil.createDom(); 459 SAX2DOMEx s2d = new SAX2DOMEx(d); 460 try { 461 h.writeTo(s2d, XmlUtil.DRACONIAN_ERROR_HANDLER); 462 refParams.add((Element) d.getLastChild()); 463 } catch (SAXException e) { 464 throw new WebServiceException(e); 465 } 466 /* 467 DOMResult result = new DOMResult(d); 468 XMLDOMWriterImpl domwriter = new XMLDOMWriterImpl(result); 469 try { 470 h.writeTo(domwriter); 471 refParams.add((Element) result.getNode().getLastChild()); 472 } catch (XMLStreamException e) { 473 throw new WebServiceException(e); 474 } 475 */ 476 } 477 } 478 return refParams; 479 } 480 481 /** 482 * This method is for exposing header list through {@link PropertySet#get(Object)}, 483 * for user applications, and should never be invoked directly from within the JAX-WS RI. 484 */ 485 @Property(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY) 486 /*package*/ MessageHeaders getHeaderList() { 487 Message msg = getMessage(); 488 if (msg == null) { 489 return null; 490 } 491 return msg.getHeaders(); 492 } 493 494 /** 495 * The list of MIME types that are acceptable to a receiver 496 * of an outbound message. 497 * 498 * This property is used only on the server side. 499 * 500 * <p>The representation shall be that specified by the HTTP Accept 501 * request-header field. 502 * 503 * <p>The list of content types will be obtained from the transport 504 * meta-data of a inbound message in a request/response message exchange. 505 * Hence this property will be set by the service-side transport pipe. 506 */ 507 public String acceptableMimeTypes; 508 509 /** 510 * When non-null, this object is consulted to 511 * implement {@link WebServiceContext} methods 512 * exposed to the user application. 513 * 514 * Used only on the server side. 515 * 516 * <p> 517 * This property is set from the parameter 518 * of {@link WSEndpoint.PipeHead#process}. 519 */ 520 public WebServiceContextDelegate webServiceContextDelegate; 521 522 /** 523 * Used only on the server side so that the transport 524 * can close the connection early. 525 * 526 * <p> 527 * This field can be null. While a message is being processed, 528 * this field can be set explicitly to null, to prevent 529 * future pipes from closing a transport (see {@link #keepTransportBackChannelOpen()}) 530 * 531 * <p> 532 * This property is set from the parameter 533 * of {@link WSEndpoint.PipeHead#process}. 534 */ 535 public 536 @Nullable 537 TransportBackChannel transportBackChannel; 538 539 /** 540 * Keeps the transport back channel open (by seeting {@link #transportBackChannel} to null.) 541 * 542 * @return 543 * The previous value of {@link #transportBackChannel}. 544 */ 545 public TransportBackChannel keepTransportBackChannelOpen() { 546 TransportBackChannel r = transportBackChannel; 547 transportBackChannel = null; 548 return r; 549 } 550 551 /** 552 * The governing owner of this packet. On the service-side this is the {@link Adapter} and on the client it is the {@link Stub}. 553 * 554 */ 555 public Component component; 556 557 /** 558 * The governing {@link WSEndpoint} in which this message is floating. 559 * 560 * <p> 561 * This property is set if and only if this is on the server side. 562 */ 563 @Property(JAXWSProperties.WSENDPOINT) 564 public WSEndpoint endpoint; 565 566 /** 567 * The value of the SOAPAction header associated with the message. 568 * 569 * <p> 570 * For outgoing messages, the transport may sends out this value. 571 * If this field is null, the transport may choose to send <tt>""</tt> 572 * (quoted empty string.) 573 * 574 * For incoming messages, the transport will set this field. 575 * If the incoming message did not contain the SOAPAction header, 576 * the transport sets this field to null. 577 * 578 * <p> 579 * If the value is non-null, it must be always in the quoted form. 580 * The value can be null. 581 * 582 * <p> 583 * Note that the way the transport sends this value out depends on 584 * transport and SOAP version. 585 * <p/> 586 * For HTTP transport and SOAP 1.1, BP requires that SOAPAction 587 * header is present (See {@BP R2744} and {@BP R2745}.) For SOAP 1.2, 588 * this is moved to the parameter of the "application/soap+xml". 589 */ 590 @Property(BindingProvider.SOAPACTION_URI_PROPERTY) 591 public String soapAction; 592 593 /** 594 * A hint indicating that whether a transport should expect 595 * a reply back from the server. 596 * 597 * <p> 598 * This property is used on the client-side for 599 * outbound messages, so that a pipeline 600 * can communicate to the terminal (or intermediate) {@link Tube}s 601 * about this knowledge. 602 * 603 * <p> 604 * This property <b>MUST NOT</b> be used by 2-way transports 605 * that have the transport back channel. Those transports 606 * must always check a reply coming through the transport back 607 * channel regardless of this value, and act accordingly. 608 * (This is because the expectation of the client and 609 * that of the server can be different, for example because 610 * of a bug in user's configuration.) 611 * 612 * <p> 613 * This property is for one-way transports, and more 614 * specifically for the coordinator that correlates sent requests 615 * and incoming replies, to decide whether to block 616 * until a response is received. 617 * 618 * <p> 619 * Also note that this property is related to 620 * {@link WSDLOperation#isOneWay()} but not the same thing. 621 * In fact in general, they are completely orthogonal. 622 * 623 * For example, the calling application can choose to invoke 624 * {@link Dispatch#invoke(Object)} or {@link Dispatch#invokeOneWay(Object)} 625 * with an operation (which determines the value of this property), 626 * regardless of whether WSDL actually says it's one way or not. 627 * So these two booleans can take any combinations. 628 * 629 * 630 * <p> 631 * When this property is {@link Boolean#FALSE}, it means that 632 * the pipeline does not expect a reply from a server (and therefore 633 * the correlator should not block for a reply message 634 * -- if such a reply does arrive, it can be just ignored.) 635 * 636 * <p> 637 * When this property is {@link Boolean#TRUE}, it means that 638 * the pipeline expects a reply from a server (and therefore 639 * the correlator should block to see if a reply message is received, 640 * 641 * <p> 642 * This property is always set to {@link Boolean#TRUE} or 643 * {@link Boolean#FALSE} when used on the request message 644 * on the client side. 645 * No other {@link Boolean} instances are allowed. 646 * <p> 647 * 648 * In all other situations, this property is null. 649 * 650 */ 651 @Property(BindingProviderProperties.ONE_WAY_OPERATION) 652 public Boolean expectReply; 653 654 655 /** 656 * This property will be removed in a near future. 657 * 658 * <p> 659 * A part of what this flag represented moved to 660 * {@link #expectReply} and the other part was moved 661 * to {@link Message#isOneWay(WSDLPort)}. Please update 662 * your code soon, or risk breaking your build!! 663 */ 664 @Deprecated 665 public Boolean isOneWay; 666 667 /** 668 * Indicates whether is invoking a synchronous pattern. If true, no 669 * async client programming model (e.g. AsyncResponse or AsyncHandler) 670 * were used to make the request that created this packet. 671 */ 672 public Boolean isSynchronousMEP; 673 674 /** 675 * Indicates whether a non-null AsyncHandler was given at the point of 676 * making the request that created this packet. This flag can be used 677 * by Tube implementations to decide how to react when isSynchronousMEP 678 * is false. If true, the client gave a non-null AsyncHandler instance 679 * at the point of request, and will be expecting a response on that 680 * handler when this request has been processed. 681 */ 682 public Boolean nonNullAsyncHandlerGiven; 683 684 /** 685 * USE-CASE: 686 * WS-AT is enabled, but there is no WSDL available. 687 * If Packet.isRequestReplyMEP() is Boolean.TRUE then WS-AT should 688 * add the TX context. 689 * 690 * This value is exposed to users via facades at higher abstraction layers. 691 * The user should NEVER use Packet directly. 692 * This value should ONLY be set by users. 693 */ 694 private Boolean isRequestReplyMEP; 695 public Boolean isRequestReplyMEP() { return isRequestReplyMEP; } 696 public void setRequestReplyMEP(final Boolean x) { isRequestReplyMEP = x; } 697 698 /** 699 * Lazily created set of handler-scope property names. 700 * 701 * <p> 702 * We expect that this is only used when handlers are present 703 * and they explicitly set some handler-scope values. 704 * 705 * @see #getHandlerScopePropertyNames(boolean) 706 */ 707 private Set<String> handlerScopePropertyNames; 708 709 /** 710 * Bag to capture properties that are available for the whole 711 * message invocation (namely on both requests and responses.) 712 * 713 * <p> 714 * These properties are copied from a request to a response. 715 * This is where we keep properties that are set by handlers. 716 * 717 * <p> 718 * See <a href="#properties">class javadoc</a> for more discussion. 719 * 720 * @see #getHandlerScopePropertyNames(boolean) 721 */ 722 public final Map<String, Object> invocationProperties; 723 724 /** 725 * Gets a {@link Set} that stores handler-scope properties. 726 * 727 * <p> 728 * These properties will not be exposed to the response context. 729 * Consequently, if a {@link Tube} wishes to hide a property 730 * to {@link ResponseContext}, it needs to add the property name 731 * to this set. 732 * 733 * @param readOnly 734 * Return true if the caller only intends to read the value of this set. 735 * Internally, the {@link Set} is allocated lazily, and this flag helps 736 * optimizing the strategy. 737 * 738 * @return 739 * always non-null, possibly empty set that stores property names. 740 */ 741 public final Set<String> getHandlerScopePropertyNames(boolean readOnly) { 742 Set<String> o = this.handlerScopePropertyNames; 743 if (o == null) { 744 if (readOnly) { 745 return Collections.emptySet(); 746 } 747 o = new HashSet<String>(); 748 this.handlerScopePropertyNames = o; 749 } 750 return o; 751 } 752 753 /** 754 * This method no longer works. 755 * 756 * @deprecated 757 * Use {@link #getHandlerScopePropertyNames(boolean)}. 758 * To be removed once Tango components are updated. 759 */ 760 public final Set<String> getApplicationScopePropertyNames(boolean readOnly) { 761 assert false; 762 return new HashSet<String>(); 763 } 764 765 /** 766 * Creates a response {@link Packet} from a request packet ({@code this}). 767 * 768 * <p> 769 * When a {@link Packet} for a reply is created, some properties need to be 770 * copied over from a request to a response, and this method handles it correctly. 771 * 772 * @deprecated 773 * Use createClientResponse(Message) for client side and 774 * createServerResponse(Message, String) for server side response 775 * creation. 776 * 777 * @param msg 778 * The {@link Message} that represents a reply. Can be null. 779 */ 780 @Deprecated 781 public Packet createResponse(Message msg) { 782 Packet response = new Packet(this); 783 response.setMessage(msg); 784 return response; 785 } 786 787 /** 788 * Creates a response {@link Packet} from a request packet ({@code this}). 789 * 790 * <p> 791 * When a {@link Packet} for a reply is created, some properties need to be 792 * copied over from a request to a response, and this method handles it correctly. 793 * 794 * @param msg 795 * The {@link Message} that represents a reply. Can be null. 796 */ 797 public Packet createClientResponse(Message msg) { 798 Packet response = new Packet(this); 799 response.setMessage(msg); 800 finishCreateRelateClientResponse(response); 801 return response; 802 } 803 804 /** 805 * For use cases that start with an existing Packet. 806 */ 807 public Packet relateClientResponse(final Packet response) { 808 response.relatePackets(this, true); 809 finishCreateRelateClientResponse(response); 810 return response; 811 } 812 813 private void finishCreateRelateClientResponse(final Packet response) { 814 response.soapAction = null; // de-initializing 815 response.setState(State.ClientResponse); 816 } 817 818 /** 819 * Creates a server-side response {@link Packet} from a request 820 * packet ({@code this}). If WS-Addressing is enabled, a default Action 821 * Message Addressing Property is obtained using <code>wsdlPort</code> {@link WSDLPort} 822 * and <code>binding</code> {@link WSBinding}. 823 * <p><p> 824 * This method should be called to create application response messages 825 * since they are associated with a {@link WSBinding} and {@link WSDLPort}. 826 * For creating protocol messages that require a non-default Action, use 827 * {@link #createServerResponse(Message, com.sun.xml.internal.ws.api.addressing.AddressingVersion, com.sun.xml.internal.ws.api.SOAPVersion, String)}. 828 * 829 * @param responseMessage The {@link Message} that represents a reply. Can be null. 830 * @param wsdlPort The response WSDL port. 831 * @param binding The response Binding. Cannot be null. 832 * @return response packet 833 */ 834 public Packet createServerResponse(@Nullable Message responseMessage, @Nullable WSDLPort wsdlPort, @Nullable SEIModel seiModel, @NotNull WSBinding binding) { 835 Packet r = createClientResponse(responseMessage); 836 return relateServerResponse(r, wsdlPort, seiModel, binding); 837 } 838 839 /** 840 * Copy all properties from ({@code this}) packet into a input {@link Packet} 841 * @param response packet 842 */ 843 public void copyPropertiesTo(@Nullable Packet response){ 844 relatePackets(response, false); 845 } 846 847 848 /** 849 * A common method to make members related between input packet and this packet 850 * 851 * @param packet 852 * @param isCopy 'true' means copying all properties from input packet; 853 * 'false' means copying all properties from this packet to input packet. 854 */ 855 private void relatePackets(@Nullable Packet packet, boolean isCopy) 856 { 857 Packet request; 858 Packet response; 859 860 if (!isCopy) { //is relate 861 request = this; 862 response = packet; 863 864 // processing specific properties 865 response.soapAction = null; 866 response.invocationProperties.putAll(request.invocationProperties); 867 if (this.getState().equals(State.ServerRequest)) { 868 response.setState(State.ServerResponse); 869 } 870 } else { //is copy constructor 871 request = packet; 872 response = this; 873 874 // processing specific properties 875 response.soapAction = request.soapAction; 876 response.setState(request.getState()); 877 } 878 879 request.copySatelliteInto(response); 880 response.isAdapterDeliversNonAnonymousResponse = request.isAdapterDeliversNonAnonymousResponse; 881 response.handlerConfig = request.handlerConfig; 882 response.handlerScopePropertyNames = request.handlerScopePropertyNames; 883 response.contentNegotiation = request.contentNegotiation; 884 response.wasTransportSecure = request.wasTransportSecure; 885 response.transportBackChannel = request.transportBackChannel; 886 response.endpointAddress = request.endpointAddress; 887 response.wsdlOperation = request.wsdlOperation; 888 response.wsdlOperationMapping = request.wsdlOperationMapping; 889 response.acceptableMimeTypes = request.acceptableMimeTypes; 890 response.endpoint = request.endpoint; 891 response.proxy = request.proxy; 892 response.webServiceContextDelegate = request.webServiceContextDelegate; 893 response.expectReply = request.expectReply; 894 response.component = request.component; 895 response.mtomAcceptable = request.mtomAcceptable; 896 response.mtomRequest = request.mtomRequest; 897 // copy other properties that need to be copied. is there any? 898 } 899 900 901 public Packet relateServerResponse(@Nullable Packet r, @Nullable WSDLPort wsdlPort, @Nullable SEIModel seiModel, @NotNull WSBinding binding) { 902 relatePackets(r, false); 903 r.setState(State.ServerResponse); 904 AddressingVersion av = binding.getAddressingVersion(); 905 // populate WS-A headers only if WS-A is enabled 906 if (av == null) { 907 return r; 908 } 909 910 if (getMessage() == null) { 911 return r; 912 } 913 914 //populate WS-A headers only if the request has addressing headers 915 String inputAction = AddressingUtils.getAction(getMessage().getHeaders(), av, binding.getSOAPVersion()); 916 if (inputAction == null) { 917 return r; 918 } 919 // if one-way, then dont populate any WS-A headers 920 if (r.getMessage() == null || (wsdlPort != null && getMessage().isOneWay(wsdlPort))) { 921 return r; 922 } 923 924 // otherwise populate WS-Addressing headers 925 populateAddressingHeaders(binding, r, wsdlPort, seiModel); 926 return r; 927 } 928 929 /** 930 * Creates a server-side response {@link Packet} from a request 931 * packet ({@code this}). If WS-Addressing is enabled, <code>action</code> 932 * is used as Action Message Addressing Property. 933 * <p><p> 934 * This method should be called only for creating protocol response messages 935 * that require a particular value of Action since they are not associated 936 * with a {@link WSBinding} and {@link WSDLPort} but do know the {@link AddressingVersion} 937 * and {@link SOAPVersion}. 938 * 939 * @param responseMessage The {@link Message} that represents a reply. Can be null. 940 * @param addressingVersion The WS-Addressing version of the response message. 941 * @param soapVersion The SOAP version of the response message. 942 * @param action The response Action Message Addressing Property value. 943 * @return response packet 944 */ 945 public Packet createServerResponse(@Nullable Message responseMessage, @NotNull AddressingVersion addressingVersion, @NotNull SOAPVersion soapVersion, @NotNull String action) { 946 Packet responsePacket = createClientResponse(responseMessage); 947 responsePacket.setState(State.ServerResponse); 948 // populate WS-A headers only if WS-A is enabled 949 if (addressingVersion == null) { 950 return responsePacket; 951 } 952 //populate WS-A headers only if the request has addressing headers 953 String inputAction = AddressingUtils.getAction(this.getMessage().getHeaders(), addressingVersion, soapVersion); 954 if (inputAction == null) { 955 return responsePacket; 956 } 957 958 populateAddressingHeaders(responsePacket, addressingVersion, soapVersion, action, false); 959 return responsePacket; 960 } 961 962 /** 963 * Overwrites the {@link Message} of the response packet ({@code this}) by the given {@link Message}. 964 * Unlike {@link #setMessage(Message)}, fill in the addressing headers correctly, and this process 965 * requires the access to the request packet. 966 * 967 * <p> 968 * This method is useful when the caller needs to swap a response message completely to a new one. 969 * 970 * @see #createServerResponse(Message, AddressingVersion, SOAPVersion, String) 971 */ 972 public void setResponseMessage(@NotNull Packet request, @Nullable Message responseMessage, @NotNull AddressingVersion addressingVersion, @NotNull SOAPVersion soapVersion, @NotNull String action) { 973 Packet temp = request.createServerResponse(responseMessage, addressingVersion, soapVersion, action); 974 setMessage(temp.getMessage()); 975 } 976 977 private void populateAddressingHeaders(Packet responsePacket, AddressingVersion av, SOAPVersion sv, String action, boolean mustUnderstand) { 978 // populate WS-A headers only if WS-A is enabled 979 if (av == null) return; 980 981 // if one-way, then dont populate any WS-A headers 982 if (responsePacket.getMessage() == null) 983 return; 984 985 MessageHeaders hl = responsePacket.getMessage().getHeaders(); 986 987 WsaPropertyBag wpb = getSatellite(WsaPropertyBag.class); 988 Message msg = getMessage(); 989 // wsa:To 990 WSEndpointReference replyTo = null; 991 Header replyToFromRequestMsg = AddressingUtils.getFirstHeader(msg.getHeaders(), av.replyToTag, true, sv); 992 Header replyToFromResponseMsg = hl.get(av.toTag, false); 993 boolean replaceToTag = true; 994 try{ 995 if (replyToFromRequestMsg != null){ 996 replyTo = replyToFromRequestMsg.readAsEPR(av); 997 } 998 if (replyToFromResponseMsg != null && replyTo == null) { 999 replaceToTag = false; 1000 } 1001 } catch (XMLStreamException e) { 1002 throw new WebServiceException(AddressingMessages.REPLY_TO_CANNOT_PARSE(), e); 1003 } 1004 if (replyTo == null) { 1005 replyTo = AddressingUtils.getReplyTo(msg.getHeaders(), av, sv); 1006 } 1007 1008 // wsa:Action, add if the message doesn't already contain it, 1009 // generally true for SEI case where there is SEIModel or WSDLModel 1010 // false for Provider with no wsdl, Expects User to set the coresponding header on the Message. 1011 if (AddressingUtils.getAction(responsePacket.getMessage().getHeaders(), av, sv) == null) { 1012 //wsa:Action header is not set in the message, so use the wsa:Action passed as the parameter. 1013 hl.add(new StringHeader(av.actionTag, action, sv, mustUnderstand)); 1014 } 1015 1016 // wsa:MessageID 1017 if (responsePacket.getMessage().getHeaders().get(av.messageIDTag, false) == null) { 1018 // if header doesn't exist, method getID creates a new random id 1019 String newID = Message.generateMessageID(); 1020 hl.add(new StringHeader(av.messageIDTag, newID)); 1021 } 1022 1023 // wsa:RelatesTo 1024 String mid = null; 1025 if (wpb != null) { 1026 mid = wpb.getMessageID(); 1027 } 1028 if (mid == null) { 1029 mid = AddressingUtils.getMessageID(msg.getHeaders(), av, sv); 1030 } 1031 if (mid != null) { 1032 hl.addOrReplace(new RelatesToHeader(av.relatesToTag, mid)); 1033 } 1034 1035 1036 // populate reference parameters 1037 WSEndpointReference refpEPR = null; 1038 if (responsePacket.getMessage().isFault()) { 1039 // choose FaultTo 1040 if (wpb != null) { 1041 refpEPR = wpb.getFaultToFromRequest(); 1042 } 1043 if (refpEPR == null) { 1044 refpEPR = AddressingUtils.getFaultTo(msg.getHeaders(), av, sv); 1045 } 1046 // if FaultTo is null, then use ReplyTo 1047 if (refpEPR == null) { 1048 refpEPR = replyTo; 1049 } 1050 } else { 1051 // choose ReplyTo 1052 refpEPR = replyTo; 1053 } 1054 if (replaceToTag && refpEPR != null) { 1055 hl.addOrReplace(new StringHeader(av.toTag, refpEPR.getAddress())); 1056 refpEPR.addReferenceParametersToList(hl); 1057 } 1058 } 1059 1060 private void populateAddressingHeaders(WSBinding binding, Packet responsePacket, WSDLPort wsdlPort, SEIModel seiModel) { 1061 AddressingVersion addressingVersion = binding.getAddressingVersion(); 1062 1063 if (addressingVersion == null) { 1064 return; 1065 } 1066 1067 WsaTubeHelper wsaHelper = addressingVersion.getWsaHelper(wsdlPort, seiModel, binding); 1068 String action = responsePacket.getMessage().isFault() ? 1069 wsaHelper.getFaultAction(this, responsePacket) : 1070 wsaHelper.getOutputAction(this); 1071 if (action == null) { 1072 LOGGER.info("WSA headers are not added as value for wsa:Action cannot be resolved for this message"); 1073 return; 1074 } 1075 populateAddressingHeaders(responsePacket, addressingVersion, binding.getSOAPVersion(), action, AddressingVersion.isRequired(binding)); 1076 } 1077 1078 public String toShortString() { 1079 return super.toString(); 1080 } 1081 1082 // For use only in a debugger 1083 @Override 1084 public String toString() { 1085 StringBuilder buf = new StringBuilder(); 1086 buf.append(super.toString()); 1087 String content; 1088 try { 1089 Message msg = getMessage(); 1090 if (msg != null) { 1091 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 1092 XMLStreamWriter xmlWriter = XMLStreamWriterFactory.create(baos, "UTF-8"); 1093 msg.copy().writeTo(xmlWriter); 1094 xmlWriter.flush(); 1095 xmlWriter.close(); 1096 baos.flush(); 1097 XMLStreamWriterFactory.recycle(xmlWriter); 1098 1099 byte[] bytes = baos.toByteArray(); 1100 //message = Messages.create(XMLStreamReaderFactory.create(null, new ByteArrayInputStream(bytes), "UTF-8", true)); 1101 content = new String(bytes, "UTF-8"); 1102 } else { 1103 content = "<none>"; 1104 } 1105 } catch (Throwable t) { 1106 throw new WebServiceException(t); 1107 } 1108 buf.append(" Content: ").append(content); 1109 return buf.toString(); 1110 } 1111 1112 // completes TypedMap 1113 private static final PropertyMap model; 1114 1115 static { 1116 model = parse(Packet.class); 1117 } 1118 1119 @Override 1120 protected PropertyMap getPropertyMap() { 1121 return model; 1122 } 1123 1124 public Map<String, Object> asMapIncludingInvocationProperties() { 1125 final Map<String, Object> asMap = asMap(); 1126 return new AbstractMap<String, Object>() { 1127 @Override 1128 public Object get(Object key) { 1129 Object o = asMap.get(key); 1130 if (o != null) 1131 return o; 1132 1133 return invocationProperties.get(key); 1134 } 1135 1136 @Override 1137 public int size() { 1138 return asMap.size() + invocationProperties.size(); 1139 } 1140 1141 @Override 1142 public boolean containsKey(Object key) { 1143 if (asMap.containsKey(key)) 1144 return true; 1145 return invocationProperties.containsKey(key); 1146 } 1147 1148 @Override 1149 public Set<Entry<String, Object>> entrySet() { 1150 final Set<Entry<String, Object>> asMapEntries = asMap.entrySet(); 1151 final Set<Entry<String, Object>> ipEntries = invocationProperties.entrySet(); 1152 1153 return new AbstractSet<Entry<String, Object>>() { 1154 @Override 1155 public Iterator<Entry<String, Object>> iterator() { 1156 final Iterator<Entry<String, Object>> asMapIt = asMapEntries.iterator(); 1157 final Iterator<Entry<String, Object>> ipIt = ipEntries.iterator(); 1158 1159 return new Iterator<Entry<String, Object>>() { 1160 @Override 1161 public boolean hasNext() { 1162 return asMapIt.hasNext() || ipIt.hasNext(); 1163 } 1164 1165 @Override 1166 public java.util.Map.Entry<String, Object> next() { 1167 if (asMapIt.hasNext()) 1168 return asMapIt.next(); 1169 return ipIt.next(); 1170 } 1171 1172 @Override 1173 public void remove() { 1174 throw new UnsupportedOperationException(); 1175 } 1176 }; 1177 } 1178 1179 @Override 1180 public int size() { 1181 return asMap.size() + invocationProperties.size(); 1182 } 1183 }; 1184 } 1185 1186 @Override 1187 public Object put(String key, Object value) { 1188 if (supports(key)) 1189 return asMap.put(key, value); 1190 1191 return invocationProperties.put(key, value); 1192 } 1193 1194 @Override 1195 public void clear() { 1196 asMap.clear(); 1197 invocationProperties.clear(); 1198 } 1199 1200 @Override 1201 public Object remove(Object key) { 1202 if (supports(key)) 1203 return asMap.remove(key); 1204 1205 return invocationProperties.remove(key); 1206 } 1207 }; 1208 } 1209 1210 private static final Logger LOGGER = Logger.getLogger(Packet.class.getName()); 1211 1212 @Override 1213 public SOAPMessage getSOAPMessage() throws SOAPException { 1214 return getAsSOAPMessage(); 1215 } 1216 1217 //TODO replace the message to a SAAJMEssage issue - JRFSAAJMessage or SAAJMessage? 1218 @Override 1219 public SOAPMessage getAsSOAPMessage() throws SOAPException { 1220 Message msg = this.getMessage(); 1221 if (msg == null) 1222 return null; 1223 if (msg instanceof MessageWritable) 1224 ((MessageWritable) msg).setMTOMConfiguration(mtomFeature); 1225 return msg.readAsSOAPMessage(this, this.getState().isInbound()); 1226 } 1227 1228 public 1229 Codec codec = null; 1230 public Codec getCodec() { 1231 if (codec != null) { 1232 return codec; 1233 } 1234 if (endpoint != null) { 1235 codec = endpoint.createCodec(); 1236 } 1237 WSBinding wsb = getBinding(); 1238 if (wsb != null) { 1239 codec = wsb.getBindingId().createEncoder(wsb); 1240 } 1241 return codec; 1242 } 1243 1244 @Override 1245 public com.oracle.webservices.internal.api.message.ContentType writeTo( OutputStream out ) throws IOException { 1246 Message msg = getInternalMessage(); 1247 if (msg instanceof MessageWritable) { 1248 ((MessageWritable) msg).setMTOMConfiguration(mtomFeature); 1249 return ((MessageWritable)msg).writeTo(out); 1250 } 1251 return getCodec().encode(this, out); 1252 } 1253 1254 public com.oracle.webservices.internal.api.message.ContentType writeTo( WritableByteChannel buffer ) { 1255 return getCodec().encode(this, buffer); 1256 } 1257 1258 private ContentType contentType; 1259 1260 /** 1261 * If the request's Content-Type is multipart/related; type=application/xop+xml, then this set to to true 1262 * 1263 * Used on server-side, for encoding the repsonse. 1264 */ 1265 private Boolean mtomRequest; 1266 1267 /** 1268 * Based on request's Accept header this is set. 1269 * Currently only set if MTOMFeature is enabled. 1270 * 1271 * Should be used on server-side, for encoding the response. 1272 */ 1273 private Boolean mtomAcceptable; 1274 1275 private MTOMFeature mtomFeature; 1276 1277 public Boolean getMtomRequest() { 1278 return mtomRequest; 1279 } 1280 1281 public void setMtomRequest(Boolean mtomRequest) { 1282 this.mtomRequest = mtomRequest; 1283 } 1284 1285 public Boolean getMtomAcceptable() { 1286 return mtomAcceptable; 1287 } 1288 1289 Boolean checkMtomAcceptable; 1290 public void checkMtomAcceptable() { 1291 if (checkMtomAcceptable == null) { 1292 if (acceptableMimeTypes == null || isFastInfosetDisabled) { 1293 checkMtomAcceptable = false; 1294 } else { 1295 checkMtomAcceptable = (acceptableMimeTypes.indexOf(MtomCodec.XOP_XML_MIME_TYPE) != -1); 1296 // StringTokenizer st = new StringTokenizer(acceptableMimeTypes, ","); 1297 // while (st.hasMoreTokens()) { 1298 // final String token = st.nextToken().trim(); 1299 // if (token.toLowerCase().contains(MtomCodec.XOP_XML_MIME_TYPE)) { 1300 // mtomAcceptable = true; 1301 // } 1302 // } 1303 // if (mtomAcceptable == null) mtomAcceptable = false; 1304 } 1305 } 1306 mtomAcceptable = checkMtomAcceptable; 1307 } 1308 1309 private Boolean fastInfosetAcceptable; 1310 1311 public Boolean getFastInfosetAcceptable(String fiMimeType) { 1312 if (fastInfosetAcceptable == null) { 1313 if (acceptableMimeTypes == null || isFastInfosetDisabled) { 1314 fastInfosetAcceptable = false; 1315 } else { 1316 fastInfosetAcceptable = (acceptableMimeTypes.indexOf(fiMimeType) != -1); 1317 } 1318 // if (accept == null || isFastInfosetDisabled) return false; 1319 // 1320 // StringTokenizer st = new StringTokenizer(accept, ","); 1321 // while (st.hasMoreTokens()) { 1322 // final String token = st.nextToken().trim(); 1323 // if (token.equalsIgnoreCase(fiMimeType)) { 1324 // return true; 1325 // } 1326 // } 1327 // return false; 1328 } 1329 return fastInfosetAcceptable; 1330 } 1331 1332 1333 public void setMtomFeature(MTOMFeature mtomFeature) { 1334 this.mtomFeature = mtomFeature; 1335 } 1336 1337 public MTOMFeature getMtomFeature() { 1338 //If we have a binding, use that in preference to an explicitly 1339 //set MTOMFeature 1340 WSBinding binding = getBinding(); 1341 if (binding != null) { 1342 return binding.getFeature(MTOMFeature.class); 1343 } 1344 return mtomFeature; 1345 } 1346 1347 @Override 1348 public com.oracle.webservices.internal.api.message.ContentType getContentType() { 1349 if (contentType == null) { 1350 contentType = getInternalContentType(); 1351 } 1352 if (contentType == null) { 1353 contentType = getCodec().getStaticContentType(this); 1354 } 1355 if (contentType == null) { 1356 //TODO write to buffer 1357 } 1358 return contentType; 1359 } 1360 1361 public ContentType getInternalContentType() { 1362 Message msg = getInternalMessage(); 1363 if (msg instanceof MessageWritable) { 1364 return ((MessageWritable)msg).getContentType(); 1365 } 1366 return contentType; 1367 } 1368 1369 public void setContentType(ContentType contentType) { 1370 this.contentType = contentType; 1371 } 1372 1373 public enum Status { 1374 Request, Response, Unknown; 1375 public boolean isRequest() { return Request.equals(this); } 1376 public boolean isResponse() { return Response.equals(this); } 1377 } 1378 1379 public enum State { 1380 ServerRequest(true), ClientRequest(false), ServerResponse(false), ClientResponse(true); 1381 private boolean inbound; 1382 State(boolean inbound) { 1383 this.inbound = inbound; 1384 } 1385 public boolean isInbound() { 1386 return inbound; 1387 } 1388 } 1389 1390 // private Status status = Status.Unknown; 1391 1392 //Default state is ServerRequest - some custom adapters may not set the value of state 1393 //upon server request - all other code paths should set it 1394 private State state = State.ServerRequest; 1395 1396 // public Status getStatus() { return status; } 1397 1398 public State getState() { return state; } 1399 public void setState(State state) { this.state = state; } 1400 1401 public boolean shouldUseMtom() { 1402 if (getState().isInbound()) { 1403 return isMtomContentType(); 1404 } else { 1405 return shouldUseMtomOutbound(); 1406 } 1407 } 1408 1409 private boolean shouldUseMtomOutbound() { 1410 //Use the getter to make sure all the logic is executed correctly 1411 MTOMFeature myMtomFeature = getMtomFeature(); 1412 if(myMtomFeature != null && myMtomFeature.isEnabled()) { 1413 //On client, always use XOP encoding if MTOM is enabled 1414 //On Server, mtomAcceptable and mtomRequest will be set - use XOP encoding 1415 //if either request is XOP encoded (mtomRequest) or 1416 //client accepts XOP encoding (mtomAcceptable) 1417 if (getMtomAcceptable() == null && getMtomRequest() == null) { 1418 return true; 1419 } else { 1420 if (getMtomAcceptable() != null && getMtomAcceptable() && getState().equals(State.ServerResponse)) { 1421 return true; 1422 } 1423 if (getMtomRequest() != null && getMtomRequest() && getState().equals(State.ServerResponse)) { 1424 return true; 1425 } 1426 if (getMtomRequest() != null && getMtomRequest() && getState().equals(State.ClientRequest)) { 1427 return true; 1428 } 1429 } 1430 } 1431 return false; 1432 } 1433 1434 private boolean isMtomContentType() { 1435 return (getInternalContentType() != null) && 1436 (getInternalContentType().getContentType().contains("application/xop+xml")); 1437 } 1438 1439 /** 1440 * @deprecated 1441 */ 1442 public void addSatellite(@NotNull com.sun.xml.internal.ws.api.PropertySet satellite) { 1443 super.addSatellite(satellite); 1444 } 1445 1446 /** 1447 * @deprecated 1448 */ 1449 public void addSatellite(@NotNull Class keyClass, @NotNull com.sun.xml.internal.ws.api.PropertySet satellite) { 1450 super.addSatellite(keyClass, satellite); 1451 } 1452 1453 /** 1454 * @deprecated 1455 */ 1456 public void copySatelliteInto(@NotNull com.sun.xml.internal.ws.api.DistributedPropertySet r) { 1457 super.copySatelliteInto(r); 1458 } 1459 1460 /** 1461 * @deprecated 1462 */ 1463 public void removeSatellite(com.sun.xml.internal.ws.api.PropertySet satellite) { 1464 super.removeSatellite(satellite); 1465 } 1466 1467 /** 1468 * This is propogated from SOAPBindingCodec and will affect isMtomAcceptable and isFastInfosetAcceptable 1469 */ 1470 private boolean isFastInfosetDisabled; 1471 1472 public void setFastInfosetDisabled(boolean b) { 1473 isFastInfosetDisabled = b; 1474 } 1475 }