src/share/jaxws_classes/com/sun/xml/internal/ws/client/RequestContext.java

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 368
0989ad8c0860
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 1997, 2012, 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  */
    26 package com.sun.xml.internal.ws.client;
    28 import com.oracle.webservices.internal.api.message.BaseDistributedPropertySet;
    29 import com.sun.istack.internal.NotNull;
    30 import com.sun.xml.internal.ws.api.EndpointAddress;
    31 import com.sun.xml.internal.ws.api.message.Packet;
    32 import com.sun.xml.internal.ws.transport.Headers;
    34 import javax.xml.ws.BindingProvider;
    35 import java.util.HashMap;
    36 import java.util.HashSet;
    37 import java.util.List;
    38 import java.util.Map;
    39 import java.util.Map.Entry;
    40 import java.util.Set;
    41 import java.util.logging.Logger;
    44 import static javax.xml.ws.BindingProvider.*;
    45 import static javax.xml.ws.handler.MessageContext.HTTP_REQUEST_HEADERS;
    47 /**
    48  * Request context implementation.
    49  *
    50  * <h2>Why a custom map?</h2>
    51  * <p>
    52  * The JAX-WS spec exposes properties as a {@link Map}, but if we just use
    53  * an ordinary {@link HashMap} for this, it doesn't work as fast as we'd like
    54  * it to be. Hence we have this class.
    55  *
    56  * <p>
    57  * We expect the user to set a few properties and then use that same
    58  * setting to make a bunch of invocations. So we'd like to take some hit
    59  * when the user actually sets a property to do some computation,
    60  * then use that computed value during a method invocation again and again.
    61  *
    62  * <p>
    63  * For this goal, we use {@link com.sun.xml.internal.ws.api.PropertySet} and implement some properties
    64  * as virtual properties backed by methods. This allows us to do the computation
    65  * in the setter, and store it in a field.
    66  *
    67  * <p>
    68  * These fields are used by {@link Stub#process} to populate a {@link Packet}.
    69  *
    70  * <h2>How it works?</h2>
    71  * <p>
    72  * For better performance, we wan't use strongly typed field as much as possible
    73  * to avoid reflection and unnecessary collection iterations;
    74  *
    75  * Using {@link com.oracle.webservices.internal.api.message.BasePropertySet.MapView} implementation allows client to use {@link Map} interface
    76  * in a way that all the strongly typed properties are reflected to the fields
    77  * right away. Any additional (extending) properties can be added by client as well;
    78  * those would be processed using iterating the {@link MapView} and their processing,
    79  * of course, would be slower.
    80  * <p>
    81  * The previous implementation with fallback mode has been removed to simplify
    82  * the code and remove the bugs.
    83  *
    84  * @author Kohsuke Kawaguchi
    85  */
    86 @SuppressWarnings({"SuspiciousMethodCalls"})
    87 public final class RequestContext extends BaseDistributedPropertySet {
    88     private static final Logger LOGGER = Logger.getLogger(RequestContext.class.getName());
    90     /**
    91      * The default value to be use for {@link #contentNegotiation} obtained
    92      * from a system property.
    93      * <p>
    94      * This enables content negotiation to be easily switched on by setting
    95      * a system property on the command line for testing purposes tests.
    96      */
    97     private static ContentNegotiation defaultContentNegotiation =
    98             ContentNegotiation.obtainFromSystemProperty();
   100     /**
   101      * @deprecated
   102      */
   103     public void addSatellite(@NotNull com.sun.xml.internal.ws.api.PropertySet satellite) {
   104         super.addSatellite(satellite);
   105     }
   107     /**
   108      * The endpoint address to which this message is sent to.
   109      *
   110      * <p>
   111      * This is the actual data store for {@link BindingProvider#ENDPOINT_ADDRESS_PROPERTY}.
   112      */
   113     private @NotNull EndpointAddress endpointAddress;
   115     /**
   116      * Creates {@link BindingProvider#ENDPOINT_ADDRESS_PROPERTY} view
   117      * on top of {@link #endpointAddress}.
   118      *
   119      * @deprecated
   120      *      always access {@link #endpointAddress}.
   121      */
   122     @Property(ENDPOINT_ADDRESS_PROPERTY)
   123     public String getEndPointAddressString() {
   124         return endpointAddress != null ? endpointAddress.toString() : null;
   125     }
   127     public void setEndPointAddressString(String s) {
   128         if (s == null) {
   129             throw new IllegalArgumentException();
   130         } else {
   131             this.endpointAddress = EndpointAddress.create(s);
   132         }
   133     }
   135     public void setEndpointAddress(@NotNull EndpointAddress epa) {
   136         this.endpointAddress = epa;
   137     }
   139     public @NotNull EndpointAddress getEndpointAddress() {
   140         return endpointAddress;
   141     }
   143     /**
   144      * The value of {@link ContentNegotiation#PROPERTY}
   145      * property.
   146      */
   147     public ContentNegotiation contentNegotiation = defaultContentNegotiation;
   149     @Property(ContentNegotiation.PROPERTY)
   150     public String getContentNegotiationString() {
   151         return contentNegotiation.toString();
   152     }
   154     public void setContentNegotiationString(String s) {
   155         if (s == null) {
   156             contentNegotiation = ContentNegotiation.none;
   157         } else {
   158             try {
   159                 contentNegotiation = ContentNegotiation.valueOf(s);
   160             } catch (IllegalArgumentException e) {
   161                 // If the value is not recognized default to none
   162                 contentNegotiation = ContentNegotiation.none;
   163             }
   164         }
   165     }
   167     /**
   168      * The value of the SOAPAction header associated with the message.
   169      *
   170      * <p>
   171      * For outgoing messages, the transport may sends out this value.
   172      * If this field is null, the transport may choose to send <tt>""</tt>
   173      * (quoted empty string.)
   174      *
   175      * For incoming messages, the transport will set this field.
   176      * If the incoming message did not contain the SOAPAction header,
   177      * the transport sets this field to null.
   178      *
   179      * <p>
   180      * If the value is non-null, it must be always in the quoted form.
   181      * The value can be null.
   182      *
   183      * <p>
   184      * Note that the way the transport sends this value out depends on
   185      * transport and SOAP version.
   186      *
   187      * For HTTP transport and SOAP 1.1, BP requires that SOAPAction
   188      * header is present (See {@BP R2744} and {@BP R2745}.) For SOAP 1.2,
   189      * this is moved to the parameter of the "application/soap+xml".
   190      */
   192     private String soapAction;
   194     @Property(SOAPACTION_URI_PROPERTY)
   195     public String getSoapAction() {
   196         return soapAction;
   197     }
   199     public void setSoapAction(String sAction) {
   200         soapAction = sAction;
   201     }
   203     /**
   204      * This controls whether BindingProvider.SOAPACTION_URI_PROPERTY is used.
   205      * See BindingProvider.SOAPACTION_USE_PROPERTY for details.
   206      *
   207      * This only control whether value of BindingProvider.SOAPACTION_URI_PROPERTY is used or not and not
   208      * if it can be sent if it can be obtained by other means such as WSDL binding
   209      */
   210     private Boolean soapActionUse;
   212     @Property(SOAPACTION_USE_PROPERTY)
   213     public Boolean getSoapActionUse() {
   214         return soapActionUse;
   215     }
   217     public void setSoapActionUse(Boolean sActionUse) {
   218         soapActionUse = sActionUse;
   219     }
   221     /**
   222      * Creates an empty {@link RequestContext}.
   223      */
   224     RequestContext() {
   225     }
   227     /**
   228      * Copy constructor.
   229      */
   230     private RequestContext(RequestContext that) {
   231         for (Map.Entry<String, Object> entry : that.asMapLocal().entrySet()) {
   232             if (!propMap.containsKey(entry.getKey())) {
   233                 asMap().put(entry.getKey(), entry.getValue());
   234             }
   235         }
   236         endpointAddress = that.endpointAddress;
   237         soapAction = that.soapAction;
   238         soapActionUse = that.soapActionUse;
   239         contentNegotiation = that.contentNegotiation;
   240         that.copySatelliteInto(this);
   241     }
   243     /**
   244      * The efficient get method that reads from {@link RequestContext}.
   245      */
   246     @Override
   247     public Object get(Object key) {
   248         if(supports(key)) {
   249             return super.get(key);
   250         } else {
   251             // use mapView to get extending property
   252             return asMap().get(key);
   253         }
   254     }
   256     /**
   257      * The efficient put method that updates {@link RequestContext}.
   258      */
   259     @Override
   260     public Object put(String key, Object value) {
   262         if(supports(key)) {
   263             return super.put(key,value);
   264         } else {
   265             // use mapView to put extending property (if the map allows that)
   266             return asMap().put(key, value);
   267         }
   268     }
   270     /**
   271      * Fill a {@link Packet} with values of this {@link RequestContext}.
   272      *
   273      * @param packet              to be filled with context values
   274      * @param isAddressingEnabled flag if addressing enabled (to provide warning if necessary)
   275      */
   276     @SuppressWarnings("unchecked")
   277     public void fill(Packet packet, boolean isAddressingEnabled) {
   279         // handling as many properties as possible (all in propMap.keySet())
   280         // to avoid slow Packet.put()
   281         if (endpointAddress != null) {
   282             packet.endpointAddress = endpointAddress;
   283         }
   284         packet.contentNegotiation = contentNegotiation;
   285         fillSOAPAction(packet, isAddressingEnabled);
   286         mergeRequestHeaders(packet);
   288         Set<String> handlerScopeNames = new HashSet<String>();
   290         copySatelliteInto(packet);
   292         // extending properties ...
   293         for (String key : asMapLocal().keySet()) {
   295             //if it is not standard property it defaults to Scope.HANDLER
   296             if (!supportsLocal(key)) {
   297                 handlerScopeNames.add(key);
   298             }
   300             // to avoid slow Packet.put(), handle as small number of props as possible
   301             // => only properties not from RequestContext object
   302             if (!propMap.containsKey(key)) {
   303                 Object value = asMapLocal().get(key);
   304                 if (packet.supports(key)) {
   305                     // very slow operation - try to avoid it!
   306                     packet.put(key, value);
   307                 } else {
   308                     packet.invocationProperties.put(key, value);
   309                 }
   310             }
   311         }
   313         if (!handlerScopeNames.isEmpty()) {
   314             packet.getHandlerScopePropertyNames(false).addAll(handlerScopeNames);
   315         }
   316     }
   318     @SuppressWarnings("unchecked")
   319     private void mergeRequestHeaders(Packet packet) {
   320         //for bug 12883765
   321         //retrieve headers which is set in soap message
   322         Headers packetHeaders = (Headers) packet.invocationProperties.get(HTTP_REQUEST_HEADERS);
   323         //retrieve headers from request context
   324         Map<String, List<String>> myHeaders = (Map<String, List<String>>) asMap().get(HTTP_REQUEST_HEADERS);
   325         if ((packetHeaders != null) && (myHeaders != null)) {
   326             //update the headers set in soap message with those in request context
   327             for (Entry<String, List<String>> entry : myHeaders.entrySet()) {
   328                 String key = entry.getKey();
   329                 if (key != null && key.trim().length() != 0) {
   330                     List<String> listFromPacket = packetHeaders.get(key);
   331                     //if the two headers contain the same key, combine the value
   332                     if (listFromPacket != null) {
   333                         listFromPacket.addAll(entry.getValue());
   334                     } else {
   335                         //add the headers  in request context to those set in soap message
   336                         packetHeaders.put(key, myHeaders.get(key));
   337                     }
   338                 }
   339             }
   340             // update headers in request context with those set in soap message since it may contain other properties..
   341             asMap().put(HTTP_REQUEST_HEADERS, packetHeaders);
   342         }
   343     }
   345     private void fillSOAPAction(Packet packet, boolean isAddressingEnabled) {
   346         final boolean p = packet.packetTakesPriorityOverRequestContext;
   347         final String  localSoapAction    = p ? packet.soapAction : soapAction;
   348         final Boolean localSoapActionUse = p ? (Boolean) packet.invocationProperties.get(BindingProvider.SOAPACTION_USE_PROPERTY)
   349                                              : soapActionUse;
   351         //JAX-WS-596: Check the semantics of SOAPACTION_USE_PROPERTY before using the SOAPACTION_URI_PROPERTY for
   352         // SoapAction as specified in the javadoc of BindingProvider. The spec seems to be little contradicting with
   353         //  javadoc and says that the use property effects the sending of SOAPAction property.
   354         // Since the user has the capability to set the value as "" if needed, implement the javadoc behavior.
   355         if ((localSoapActionUse != null && localSoapActionUse) || (localSoapActionUse == null && isAddressingEnabled)) {
   356             if (localSoapAction != null) {
   357                 packet.soapAction = localSoapAction;
   358             }
   359         }
   361         if ((!isAddressingEnabled && (localSoapActionUse == null || !localSoapActionUse)) && localSoapAction != null) {
   362             LOGGER.warning("BindingProvider.SOAPACTION_URI_PROPERTY is set in the RequestContext but is ineffective," +
   363                     " Either set BindingProvider.SOAPACTION_USE_PROPERTY to true or enable AddressingFeature");
   364         }
   365     }
   367     public RequestContext copy() {
   368         return new RequestContext(this);
   369     }
   371     @Override
   372     protected PropertyMap getPropertyMap() {
   373         return propMap;
   374     }
   376     private static final PropertyMap propMap = parse(RequestContext.class);
   378     @Override
   379     protected boolean mapAllowsAdditionalProperties() {
   380         return true;
   381     }
   382 }

mercurial