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