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

Tue, 06 Mar 2012 16:09:35 -0800

author
ohair
date
Tue, 06 Mar 2012 16:09:35 -0800
changeset 286
f50545b5e2f1
child 368
0989ad8c0860
permissions
-rw-r--r--

7150322: Stop using drop source bundles in jaxws
Reviewed-by: darcy, ohrstrom

ohair@286 1 /*
ohair@286 2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
ohair@286 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ohair@286 4 *
ohair@286 5 * This code is free software; you can redistribute it and/or modify it
ohair@286 6 * under the terms of the GNU General Public License version 2 only, as
ohair@286 7 * published by the Free Software Foundation. Oracle designates this
ohair@286 8 * particular file as subject to the "Classpath" exception as provided
ohair@286 9 * by Oracle in the LICENSE file that accompanied this code.
ohair@286 10 *
ohair@286 11 * This code is distributed in the hope that it will be useful, but WITHOUT
ohair@286 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ohair@286 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
ohair@286 14 * version 2 for more details (a copy is included in the LICENSE file that
ohair@286 15 * accompanied this code).
ohair@286 16 *
ohair@286 17 * You should have received a copy of the GNU General Public License version
ohair@286 18 * 2 along with this work; if not, write to the Free Software Foundation,
ohair@286 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ohair@286 20 *
ohair@286 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@286 22 * or visit www.oracle.com if you need additional information or have any
ohair@286 23 * questions.
ohair@286 24 */
ohair@286 25
ohair@286 26 package com.sun.xml.internal.ws.client;
ohair@286 27
ohair@286 28 import com.sun.istack.internal.NotNull;
ohair@286 29 import com.sun.xml.internal.ws.api.DistributedPropertySet;
ohair@286 30 import com.sun.xml.internal.ws.api.EndpointAddress;
ohair@286 31 import com.sun.xml.internal.ws.api.PropertySet;
ohair@286 32 import com.sun.xml.internal.ws.api.message.Packet;
ohair@286 33 import com.sun.xml.internal.ws.transport.Headers;
ohair@286 34
ohair@286 35 import javax.xml.ws.BindingProvider;
ohair@286 36 import javax.xml.ws.handler.MessageContext;
ohair@286 37
ohair@286 38 import java.util.Collection;
ohair@286 39 import java.util.HashMap;
ohair@286 40 import java.util.HashSet;
ohair@286 41 import java.util.List;
ohair@286 42 import java.util.Map;
ohair@286 43 import java.util.Map.Entry;
ohair@286 44 import java.util.Set;
ohair@286 45 import java.util.logging.Logger;
ohair@286 46
ohair@286 47 /**
ohair@286 48 * Request context implementation.
ohair@286 49 *
ohair@286 50 * <h2>Why a custom map?</h2>
ohair@286 51 * <p>
ohair@286 52 * The JAX-WS spec exposes properties as a {@link Map}, but if we just use
ohair@286 53 * an ordinary {@link HashMap} for this, it doesn't work as fast as we'd like
ohair@286 54 * it to be. Hence we have this class.
ohair@286 55 *
ohair@286 56 * <p>
ohair@286 57 * We expect the user to set a few properties and then use that same
ohair@286 58 * setting to make a bunch of invocations. So we'd like to take some hit
ohair@286 59 * when the user actually sets a property to do some computation,
ohair@286 60 * then use that computed value during a method invocation again and again.
ohair@286 61 *
ohair@286 62 * <p>
ohair@286 63 * For this goal, we use {@link PropertySet} and implement some properties
ohair@286 64 * as virtual properties backed by methods. This allows us to do the computation
ohair@286 65 * in the setter, and store it in a field.
ohair@286 66 *
ohair@286 67 * <p>
ohair@286 68 * These fields are used by {@link Stub#process} to populate a {@link Packet}.
ohair@286 69 *
ohair@286 70 *
ohair@286 71 *
ohair@286 72 * <h2>How it works?</h2>
ohair@286 73 * <p>
ohair@286 74 * We make an assumption that a request context is mostly used to just
ohair@286 75 * get and put values, not really for things like enumerating or size.
ohair@286 76 *
ohair@286 77 * <p>
ohair@286 78 * So we start by maintaining state as a combination of {@link #others}
ohair@286 79 * bag and strongly-typed fields. As long as the application uses
ohair@286 80 * just {@link Map#put}, {@link Map#get}, and {@link Map#putAll}, we can
ohair@286 81 * do things in this way. In this mode a {@link Map} we return works as
ohair@286 82 * a view into {@link RequestContext}, and by itself it maintains no state.
ohair@286 83 *
ohair@286 84 * <p>
ohair@286 85 * If {@link RequestContext} is in this mode, its state can be copied
ohair@286 86 * efficiently into {@link Packet}.
ohair@286 87 *
ohair@286 88 * <p>
ohair@286 89 * Once the application uses any other {@link Map} method, we move to
ohair@286 90 * the "fallback" mode, where the data is actually stored in a {@link HashMap},
ohair@286 91 * this is necessary for implementing the map interface contract correctly.
ohair@286 92 *
ohair@286 93 * <p>
ohair@286 94 * To be safe, once we fallback, we'll never come back to the efficient state.
ohair@286 95 *
ohair@286 96 *
ohair@286 97 *
ohair@286 98 * <h2>Caution</h2>
ohair@286 99 * <p>
ohair@286 100 * Once we are in the fallback mode, none of the strongly typed field will
ohair@286 101 * be used, and they may contain stale values. So the only method
ohair@286 102 * the code outside this class can safely use is {@link #copy()},
ohair@286 103 * {@link #fill(Packet)}, and constructors. Do not access the strongly
ohair@286 104 * typed fields nor {@link #others} directly.
ohair@286 105 *
ohair@286 106 * @author Kohsuke Kawaguchi
ohair@286 107 */
ohair@286 108 @SuppressWarnings({"SuspiciousMethodCalls"})
ohair@286 109 public final class RequestContext extends DistributedPropertySet {
ohair@286 110 private static final Logger LOGGER = Logger.getLogger(RequestContext.class.getName());
ohair@286 111
ohair@286 112 /**
ohair@286 113 * The default value to be use for {@link #contentNegotiation} obtained
ohair@286 114 * from a system property.
ohair@286 115 * <p>
ohair@286 116 * This enables content negotiation to be easily switched on by setting
ohair@286 117 * a system property on the command line for testing purposes tests.
ohair@286 118 */
ohair@286 119 private static ContentNegotiation defaultContentNegotiation =
ohair@286 120 ContentNegotiation.obtainFromSystemProperty();
ohair@286 121
ohair@286 122 /**
ohair@286 123 * Stores properties that don't fit the strongly-typed fields.
ohair@286 124 */
ohair@286 125 private final Map<String,Object> others;
ohair@286 126
ohair@286 127 /**
ohair@286 128 * The endpoint address to which this message is sent to.
ohair@286 129 *
ohair@286 130 * <p>
ohair@286 131 * This is the actual data store for {@link BindingProvider#ENDPOINT_ADDRESS_PROPERTY}.
ohair@286 132 */
ohair@286 133 private @NotNull EndpointAddress endpointAddress;
ohair@286 134
ohair@286 135 /**
ohair@286 136 * Creates {@link BindingProvider#ENDPOINT_ADDRESS_PROPERTY} view
ohair@286 137 * on top of {@link #endpointAddress}.
ohair@286 138 *
ohair@286 139 * @deprecated
ohair@286 140 * always access {@link #endpointAddress}.
ohair@286 141 */
ohair@286 142 @Property(BindingProvider.ENDPOINT_ADDRESS_PROPERTY)
ohair@286 143 public String getEndPointAddressString() {
ohair@286 144 return endpointAddress != null ? endpointAddress.toString() : null;
ohair@286 145 }
ohair@286 146
ohair@286 147 public void setEndPointAddressString(String s) {
ohair@286 148 if(s==null)
ohair@286 149 throw new IllegalArgumentException();
ohair@286 150 else
ohair@286 151 this.endpointAddress = EndpointAddress.create(s);
ohair@286 152 }
ohair@286 153
ohair@286 154 public void setEndpointAddress(@NotNull EndpointAddress epa) {
ohair@286 155 this.endpointAddress = epa;
ohair@286 156 }
ohair@286 157
ohair@286 158 public @NotNull EndpointAddress getEndpointAddress() {
ohair@286 159 return endpointAddress;
ohair@286 160 }
ohair@286 161
ohair@286 162 /**
ohair@286 163 * The value of {@link ContentNegotiation#PROPERTY}
ohair@286 164 * property.
ohair@286 165 */
ohair@286 166 public ContentNegotiation contentNegotiation = defaultContentNegotiation;
ohair@286 167
ohair@286 168 @Property(ContentNegotiation.PROPERTY)
ohair@286 169 public String getContentNegotiationString() {
ohair@286 170 return contentNegotiation.toString();
ohair@286 171 }
ohair@286 172
ohair@286 173 public void setContentNegotiationString(String s) {
ohair@286 174 if(s==null)
ohair@286 175 contentNegotiation = ContentNegotiation.none;
ohair@286 176 else {
ohair@286 177 try {
ohair@286 178 contentNegotiation = ContentNegotiation.valueOf(s);
ohair@286 179 } catch (IllegalArgumentException e) {
ohair@286 180 // If the value is not recognized default to none
ohair@286 181 contentNegotiation = ContentNegotiation.none;
ohair@286 182 }
ohair@286 183 }
ohair@286 184 }
ohair@286 185 /**
ohair@286 186 * The value of the SOAPAction header associated with the message.
ohair@286 187 *
ohair@286 188 * <p>
ohair@286 189 * For outgoing messages, the transport may sends out this value.
ohair@286 190 * If this field is null, the transport may choose to send <tt>""</tt>
ohair@286 191 * (quoted empty string.)
ohair@286 192 *
ohair@286 193 * For incoming messages, the transport will set this field.
ohair@286 194 * If the incoming message did not contain the SOAPAction header,
ohair@286 195 * the transport sets this field to null.
ohair@286 196 *
ohair@286 197 * <p>
ohair@286 198 * If the value is non-null, it must be always in the quoted form.
ohair@286 199 * The value can be null.
ohair@286 200 *
ohair@286 201 * <p>
ohair@286 202 * Note that the way the transport sends this value out depends on
ohair@286 203 * transport and SOAP version.
ohair@286 204 *
ohair@286 205 * For HTTP transport and SOAP 1.1, BP requires that SOAPAction
ohair@286 206 * header is present (See {@BP R2744} and {@BP R2745}.) For SOAP 1.2,
ohair@286 207 * this is moved to the parameter of the "application/soap+xml".
ohair@286 208 */
ohair@286 209
ohair@286 210 private String soapAction;
ohair@286 211
ohair@286 212 @Property(BindingProvider.SOAPACTION_URI_PROPERTY)
ohair@286 213 public String getSoapAction(){
ohair@286 214 return soapAction;
ohair@286 215 }
ohair@286 216 public void setSoapAction(String sAction){
ohair@286 217 if(sAction == null) {
ohair@286 218 throw new IllegalArgumentException("SOAPAction value cannot be null");
ohair@286 219 }
ohair@286 220 soapAction = sAction;
ohair@286 221 }
ohair@286 222
ohair@286 223 /**
ohair@286 224 * This controls whether BindingProvider.SOAPACTION_URI_PROPERTY is used.
ohair@286 225 * See BindingProvider.SOAPACTION_USE_PROPERTY for details.
ohair@286 226 *
ohair@286 227 * This only control whether value of BindingProvider.SOAPACTION_URI_PROPERTY is used or not and not
ohair@286 228 * if it can be sent if it can be obtained by other means such as WSDL binding
ohair@286 229 */
ohair@286 230 private Boolean soapActionUse;
ohair@286 231 @Property(BindingProvider.SOAPACTION_USE_PROPERTY)
ohair@286 232 public Boolean getSoapActionUse(){
ohair@286 233 return soapActionUse;
ohair@286 234 }
ohair@286 235 public void setSoapActionUse(Boolean sActionUse){
ohair@286 236 soapActionUse = sActionUse;
ohair@286 237 }
ohair@286 238
ohair@286 239 /**
ohair@286 240 * {@link Map} exposed to the user application.
ohair@286 241 */
ohair@286 242 private final MapView mapView = new MapView();
ohair@286 243
ohair@286 244 /**
ohair@286 245 * Creates an empty {@link RequestContext}.
ohair@286 246 */
ohair@286 247 /*package*/ RequestContext() {
ohair@286 248 others = new HashMap<String, Object>();
ohair@286 249 }
ohair@286 250
ohair@286 251 /**
ohair@286 252 * Copy constructor.
ohair@286 253 */
ohair@286 254 private RequestContext(RequestContext that) {
ohair@286 255 others = new HashMap<String,Object>(that.others);
ohair@286 256 mapView.fallbackMap = that.mapView.fallbackMap != null ?
ohair@286 257 new HashMap<String, Object>(that.mapView.fallback()) : null;
ohair@286 258 endpointAddress = that.endpointAddress;
ohair@286 259 soapAction = that.soapAction;
ohair@286 260 contentNegotiation = that.contentNegotiation;
ohair@286 261 that.copySatelliteInto(this);
ohair@286 262 }
ohair@286 263
ohair@286 264 /**
ohair@286 265 * The efficient get method that reads from {@link RequestContext}.
ohair@286 266 */
ohair@286 267 public Object get(Object key) {
ohair@286 268 if(super.supports(key))
ohair@286 269 return super.get(key);
ohair@286 270 else
ohair@286 271 return others.get(key);
ohair@286 272 }
ohair@286 273
ohair@286 274 /**
ohair@286 275 * The efficient put method that updates {@link RequestContext}.
ohair@286 276 */
ohair@286 277 public Object put(String key, Object value) {
ohair@286 278 if(super.supports(key))
ohair@286 279 return super.put(key,value);
ohair@286 280 else
ohair@286 281 return others.put(key,value);
ohair@286 282 }
ohair@286 283
ohair@286 284 /**
ohair@286 285 * Gets the {@link Map} view of this request context.
ohair@286 286 *
ohair@286 287 * @return
ohair@286 288 * Always same object. Returned map is live.
ohair@286 289 */
ohair@286 290 public Map<String,Object> getMapView() {
ohair@286 291 return mapView;
ohair@286 292 }
ohair@286 293
ohair@286 294 /**
ohair@286 295 * Fill a {@link Packet} with values of this {@link RequestContext}.
ohair@286 296 */
ohair@286 297 public void fill(Packet packet, boolean isAddressingEnabled) {
ohair@286 298 if(mapView.fallbackMap==null) {
ohair@286 299 if (endpointAddress != null)
ohair@286 300 packet.endpointAddress = endpointAddress;
ohair@286 301 packet.contentNegotiation = contentNegotiation;
ohair@286 302
ohair@286 303 //JAX-WS-596: Check the semantics of SOAPACTION_USE_PROPERTY before using the SOAPACTION_URI_PROPERTY for
ohair@286 304 // SoapAction as specified in the javadoc of BindingProvider. The spec seems to be little contradicting with
ohair@286 305 // javadoc and says that the use property effects the sending of SOAPAction property.
ohair@286 306 // Since the user has the capability to set the value as "" if needed, implement the javadoc behavior.
ohair@286 307
ohair@286 308 if ((soapActionUse != null && soapActionUse) || (soapActionUse == null && isAddressingEnabled)) {
ohair@286 309 if (soapAction != null) {
ohair@286 310 packet.soapAction = soapAction;
ohair@286 311 }
ohair@286 312 }
ohair@286 313
ohair@286 314 if((!isAddressingEnabled && (soapActionUse == null || !soapActionUse)) && soapAction != null) {
ohair@286 315 LOGGER.warning("BindingProvider.SOAPACTION_URI_PROPERTY is set in the RequestContext but is ineffective," +
ohair@286 316 " Either set BindingProvider.SOAPACTION_USE_PROPERTY to true or enable AddressingFeature");
ohair@286 317 }
ohair@286 318
ohair@286 319 copySatelliteInto((DistributedPropertySet)packet);
ohair@286 320
ohair@286 321 if(!others.isEmpty()) {
ohair@286 322 //for bug 12883765
ohair@286 323 //retrieve headers which is set in soap message
ohair@286 324 Headers headerFromPacketProperty = (Headers)packet.invocationProperties.get(MessageContext.HTTP_REQUEST_HEADERS);
ohair@286 325 //retrieve headers from request context
ohair@286 326 Map<String,List<String>> headerFromOthers =(Map<String,List<String>>) others.get(MessageContext.HTTP_REQUEST_HEADERS);
ohair@286 327 if((headerFromPacketProperty != null) && (headerFromOthers != null) ) {
ohair@286 328 //update the headers set in soap message with those in request context
ohair@286 329 for(String key: headerFromOthers.keySet()) {
ohair@286 330 if(key!=null && key.trim().length()!=0) {
ohair@286 331 List<String> valueFromPacketProperty = headerFromPacketProperty.get(key);
ohair@286 332 //if the two headers contain the same key, combine the value
ohair@286 333 if(valueFromPacketProperty!=null) {
ohair@286 334 valueFromPacketProperty.addAll(headerFromOthers.get(key));
ohair@286 335 }else{
ohair@286 336 //add the headers in request context to those set in soap message
ohair@286 337 headerFromPacketProperty.put(key, headerFromOthers.get(key));
ohair@286 338 }
ohair@286 339 }
ohair@286 340 }
ohair@286 341 // update headers in request context with those set in soap message since 'others' may contain other properties..
ohair@286 342 others.put(MessageContext.HTTP_REQUEST_HEADERS, headerFromPacketProperty);
ohair@286 343 }
ohair@286 344 packet.invocationProperties.putAll(others);
ohair@286 345 //if it is not standard property it deafults to Scope.HANDLER
ohair@286 346 packet.getHandlerScopePropertyNames(false).addAll(others.keySet());
ohair@286 347 }
ohair@286 348 } else {
ohair@286 349 Set<String> handlerScopePropertyNames = new HashSet<String>();
ohair@286 350 // fallback mode, simply copy map in a slow way
ohair@286 351 for (Entry<String,Object> entry : mapView.fallbackMap.entrySet()) {
ohair@286 352 String key = entry.getKey();
ohair@286 353 if(packet.supports(key))
ohair@286 354 packet.put(key,entry.getValue());
ohair@286 355 else
ohair@286 356 packet.invocationProperties.put(key,entry.getValue());
ohair@286 357
ohair@286 358 //if it is not standard property it deafults to Scope.HANDLER
ohair@286 359 if(!super.supports(key)) {
ohair@286 360 handlerScopePropertyNames.add(key);
ohair@286 361 }
ohair@286 362 }
ohair@286 363
ohair@286 364 if(!handlerScopePropertyNames.isEmpty())
ohair@286 365 packet.getHandlerScopePropertyNames(false).addAll(handlerScopePropertyNames);
ohair@286 366 }
ohair@286 367 }
ohair@286 368
ohair@286 369 public RequestContext copy() {
ohair@286 370 return new RequestContext(this);
ohair@286 371 }
ohair@286 372
ohair@286 373 private final class MapView implements Map<String,Object> {
ohair@286 374 private Map<String,Object> fallbackMap;
ohair@286 375
ohair@286 376 private Map<String,Object> fallback() {
ohair@286 377 if(fallbackMap==null) {
ohair@286 378 // has to fall back. fill in fallbackMap
ohair@286 379 fallbackMap = new HashMap<String,Object>(others);
ohair@286 380 // then put all known properties
ohair@286 381 fallbackMap.putAll(createMapView());
ohair@286 382 }
ohair@286 383 return fallbackMap;
ohair@286 384 }
ohair@286 385
ohair@286 386 public int size() {
ohair@286 387 return fallback().size();
ohair@286 388 }
ohair@286 389
ohair@286 390 public boolean isEmpty() {
ohair@286 391 return fallback().isEmpty();
ohair@286 392 }
ohair@286 393
ohair@286 394 public boolean containsKey(Object key) {
ohair@286 395 return fallback().containsKey(key);
ohair@286 396 }
ohair@286 397
ohair@286 398 public boolean containsValue(Object value) {
ohair@286 399 return fallback().containsValue(value);
ohair@286 400 }
ohair@286 401
ohair@286 402 public Object get(Object key) {
ohair@286 403 if (fallbackMap ==null) {
ohair@286 404 return RequestContext.this.get(key);
ohair@286 405 } else {
ohair@286 406 return fallback().get(key);
ohair@286 407 }
ohair@286 408 }
ohair@286 409
ohair@286 410 public Object put(String key, Object value) {
ohair@286 411 if(fallbackMap ==null)
ohair@286 412 return RequestContext.this.put(key,value);
ohair@286 413 else
ohair@286 414 return fallback().put(key, value);
ohair@286 415 }
ohair@286 416
ohair@286 417 public Object remove(Object key) {
ohair@286 418 if (fallbackMap ==null) {
ohair@286 419 return RequestContext.this.remove(key);
ohair@286 420 } else {
ohair@286 421 return fallback().remove(key);
ohair@286 422 }
ohair@286 423 }
ohair@286 424
ohair@286 425 public void putAll(Map<? extends String, ? extends Object> t) {
ohair@286 426 for (Entry<? extends String, ? extends Object> e : t.entrySet()) {
ohair@286 427 put(e.getKey(),e.getValue());
ohair@286 428 }
ohair@286 429 }
ohair@286 430
ohair@286 431 public void clear() {
ohair@286 432 fallback().clear();
ohair@286 433 }
ohair@286 434
ohair@286 435 public Set<String> keySet() {
ohair@286 436 return fallback().keySet();
ohair@286 437 }
ohair@286 438
ohair@286 439 public Collection<Object> values() {
ohair@286 440 return fallback().values();
ohair@286 441 }
ohair@286 442
ohair@286 443 public Set<Entry<String, Object>> entrySet() {
ohair@286 444 return fallback().entrySet();
ohair@286 445 }
ohair@286 446 }
ohair@286 447
ohair@286 448 protected PropertyMap getPropertyMap() {
ohair@286 449 return propMap;
ohair@286 450 }
ohair@286 451
ohair@286 452 private static final PropertyMap propMap = parse(RequestContext.class);
ohair@286 453 }

mercurial