1 /*
   2  * Copyright (c) 1997, 2010, 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.pipe;
  27 
  28 import com.sun.istack.internal.NotNull;
  29 import com.sun.istack.internal.Nullable;
  30 import com.sun.xml.internal.ws.addressing.W3CWsaClientTube;
  31 import com.sun.xml.internal.ws.addressing.v200408.MemberSubmissionWsaClientTube;
  32 import com.sun.xml.internal.ws.api.EndpointAddress;
  33 import com.sun.xml.internal.ws.api.WSBinding;
  34 import com.sun.xml.internal.ws.api.WSService;
  35 import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
  36 import com.sun.xml.internal.ws.api.client.ClientPipelineHook;
  37 import com.sun.xml.internal.ws.api.client.WSPortInfo;
  38 import com.sun.xml.internal.ws.api.model.SEIModel;
  39 import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
  40 import com.sun.xml.internal.ws.api.pipe.helper.PipeAdapter;
  41 import com.sun.xml.internal.ws.api.server.Container;
  42 import com.sun.xml.internal.ws.binding.BindingImpl;
  43 import com.sun.xml.internal.ws.client.ClientSchemaValidationTube;
  44 import com.sun.xml.internal.ws.developer.SchemaValidationFeature;
  45 import com.sun.xml.internal.ws.developer.WSBindingProvider;
  46 import com.sun.xml.internal.ws.handler.ClientLogicalHandlerTube;
  47 import com.sun.xml.internal.ws.handler.ClientMessageHandlerTube;
  48 import com.sun.xml.internal.ws.handler.ClientSOAPHandlerTube;
  49 import com.sun.xml.internal.ws.handler.HandlerTube;
  50 import com.sun.xml.internal.ws.protocol.soap.ClientMUTube;
  51 import com.sun.xml.internal.ws.transport.DeferredTransportPipe;
  52 import com.sun.xml.internal.ws.util.pipe.DumpTube;
  53 
  54 import javax.xml.ws.soap.SOAPBinding;
  55 import java.io.PrintStream;
  56 
  57 /**
  58  * Factory for well-known {@link Tube} implementations
  59  * that the {@link TubelineAssembler} needs to use
  60  * to satisfy JAX-WS requirements.
  61  *
  62  * @author Jitendra Kotamraju
  63  */
  64 public class ClientTubeAssemblerContext {
  65 
  66     private final @NotNull EndpointAddress address;
  67     private final @Nullable WSDLPort wsdlModel;
  68     private final @Nullable SEIModel seiModel;
  69     private final @Nullable Class    sei;
  70     private final @NotNull WSService rootOwner;
  71     private final @NotNull WSBinding binding;
  72     private final @NotNull Container container;
  73     private @NotNull Codec codec;
  74 
  75     //Nullable only to maintain comaptibility with old constructors of this class.
  76     private final @Nullable WSBindingProvider bindingProvider;
  77 
  78     /**
  79      * This constructor should be used only by JAX-WS Runtime and is not meant for external consumption.
  80      * @deprecated
  81      *      Use {@link #ClientTubeAssemblerContext(EndpointAddress, WSDLPort, WSBindingProvider, WSBinding, Container, Codec, SEIModel)}
  82      */
  83     public ClientTubeAssemblerContext(@NotNull EndpointAddress address, @Nullable WSDLPort wsdlModel, @NotNull WSService rootOwner, @NotNull WSBinding binding) {
  84         this(address, wsdlModel, rootOwner, binding, Container.NONE);
  85     }
  86 
  87     /**
  88      * This constructor should be used only by JAX-WS Runtime and is not meant for external consumption.
  89      * @deprecated
  90      *      Use {@link #ClientTubeAssemblerContext(EndpointAddress, WSDLPort, WSBindingProvider, WSBinding, Container, Codec, SEIModel)}.
  91      */
  92     public ClientTubeAssemblerContext(@NotNull EndpointAddress address, @Nullable WSDLPort wsdlModel,
  93                                       @NotNull WSService rootOwner, @NotNull WSBinding binding,
  94                                       @NotNull Container container) {
  95         // WSBinding is actually BindingImpl
  96         this(address, wsdlModel, rootOwner, binding, container, ((BindingImpl)binding).createCodec() );
  97     }
  98 
  99     /**
 100      * This constructor should be used only by JAX-WS Runtime and is not meant for external consumption.
 101      * @deprecated
 102      *      Use {@link #ClientTubeAssemblerContext(EndpointAddress, WSDLPort, WSBindingProvider, WSBinding, Container, Codec,SEIModel)}.
 103      */
 104     public ClientTubeAssemblerContext(@NotNull EndpointAddress address, @Nullable WSDLPort wsdlModel,
 105                                       @NotNull WSService rootOwner, @NotNull WSBinding binding,
 106                                       @NotNull Container container, Codec codec) {
 107         this(address, wsdlModel, rootOwner, binding, container, codec, null, null);
 108     }
 109 
 110     /**
 111      * This constructor should be used only by JAX-WS Runtime and is not meant for external consumption.
 112      * @deprecated
 113      *      Use {@link #ClientTubeAssemblerContext(EndpointAddress, WSDLPort, WSBindingProvider, WSBinding, Container, Codec, SEIModel)}.
 114      */
 115     public ClientTubeAssemblerContext(@NotNull EndpointAddress address, @Nullable WSDLPort wsdlModel,
 116                                       @NotNull WSService rootOwner, @NotNull WSBinding binding,
 117                                       @NotNull Container container, Codec codec, SEIModel seiModel, Class sei) {
 118         this(address, wsdlModel, rootOwner, null/* no info on which port it is, so pass null*/, binding, container, codec, seiModel, sei);
 119     }
 120 
 121     /**
 122      * This constructor should be used only by JAX-WS Runtime and is not meant for external consumption.
 123      *
 124      * @since JAX-WS 2.2
 125      */
 126     public ClientTubeAssemblerContext(@NotNull EndpointAddress address, @Nullable WSDLPort wsdlModel,
 127                                       @NotNull WSBindingProvider bindingProvider, @NotNull WSBinding binding,
 128                                       @NotNull Container container, Codec codec, SEIModel seiModel, Class sei) {
 129         this(address, wsdlModel, (bindingProvider==null? null: bindingProvider.getPortInfo().getOwner()), bindingProvider, binding, container, codec, seiModel, sei);
 130 
 131     }
 132 
 133     //common constructor
 134     //WSService is null, when ClientTubeAssemblerContext is created for sending non-anonymous responses.
 135     private ClientTubeAssemblerContext(@NotNull EndpointAddress address, @Nullable WSDLPort wsdlModel,
 136                                        @Nullable WSService rootOwner, @Nullable WSBindingProvider bindingProvider, @NotNull WSBinding binding,
 137                                       @NotNull Container container, Codec codec, SEIModel seiModel, Class sei) {
 138         this.address = address;
 139         this.wsdlModel = wsdlModel;
 140         this.rootOwner = rootOwner;
 141         this.bindingProvider = bindingProvider;
 142         this.binding = binding;
 143         this.container = container;
 144         this.codec = codec;
 145         this.seiModel = seiModel;
 146         this.sei = sei;
 147     }
 148 
 149     /**
 150      * The endpoint address. Always non-null. This parameter is taken separately
 151      * from {@link com.sun.xml.internal.ws.api.model.wsdl.WSDLPort} (even though there's {@link com.sun.xml.internal.ws.api.model.wsdl.WSDLPort#getAddress()})
 152      * because sometimes WSDL is not available.
 153      */
 154     public @NotNull EndpointAddress getAddress() {
 155         return address;
 156     }
 157 
 158     /**
 159      * The created pipeline will be used to serve this port.
 160      * Null if the service isn't associated with any port definition in WSDL,
 161      * and otherwise non-null.
 162      */
 163     public @Nullable WSDLPort getWsdlModel() {
 164         return wsdlModel;
 165     }
 166 
 167     /**
 168      * The pipeline is created for this {@link com.sun.xml.internal.ws.api.WSService}.
 169      * Always non-null. (To be precise, the newly created pipeline
 170      * is owned by a proxy or a dispatch created from thsi {@link com.sun.xml.internal.ws.api.WSService}.)
 171      */
 172     public @NotNull WSService getService() {
 173         return rootOwner;
 174     }
 175 
 176     /**
 177      * The pipeline is created for this {@link com.sun.xml.internal.ws.api.client.WSPortInfo}.
 178      * Nullable incase of backwards compatible usages of this class.
 179      */
 180     public @Nullable WSPortInfo getPortInfo() {
 181         return bindingProvider == null? null: bindingProvider.getPortInfo();
 182     }
 183 
 184 
 185     /**
 186      * The pipeline is created for this {@link WSBindingProvider}.
 187      * Nullable incase of backwards compatible usages of this class.
 188      */
 189     public @Nullable WSBindingProvider getBindingProvider() {
 190         return bindingProvider;
 191     }
 192 
 193     /**
 194      * The binding of the new pipeline to be created.
 195      */
 196     public @NotNull WSBinding getBinding() {
 197         return binding;
 198     }
 199 
 200     /**
 201      * The created pipeline will use seiModel to get java concepts for the endpoint
 202      *
 203      * @return Null if the service doesn't have SEI model e.g. Dispatch,
 204      *         and otherwise non-null.
 205      */
 206     public @Nullable SEIModel getSEIModel() {
 207         return seiModel;
 208     }
 209 
 210     /**
 211      * The SEI class for the endpoint
 212      *
 213      * @return Null if the service doesn't have SEI model e.g. Dispatch,
 214      *         and otherwise non-null.
 215      */
 216     public @Nullable Class getSEI() {
 217         return sei;
 218     }
 219 
 220     /**
 221      * Returns the Container in which the client is running
 222      *
 223      * @return Container in which client is running
 224      */
 225     public Container getContainer() {
 226         return container;
 227     }
 228 
 229     /**
 230      * creates a {@link Tube} that dumps messages that pass through.
 231      */
 232     public Tube createDumpTube(String name, PrintStream out, Tube next) {
 233         return new DumpTube(name, out, next);
 234     }
 235 
 236     /**
 237      * Creates a {@link Tube} that adds container specific security
 238      */
 239     public @NotNull Tube createSecurityTube(@NotNull Tube next) {
 240         ClientPipelineHook hook = container.getSPI(ClientPipelineHook.class);
 241         if (hook != null) {
 242             ClientPipeAssemblerContext ctxt = new ClientPipeAssemblerContext(address, wsdlModel,
 243                                       rootOwner, binding, container);
 244             return PipeAdapter.adapt(hook.createSecurityPipe(ctxt, PipeAdapter.adapt(next)));
 245         }
 246         return next;
 247     }
 248 
 249     /**
 250      * Creates a {@link Tube} that invokes protocol and logical handlers.
 251      */
 252     public Tube createWsaTube(Tube next) {
 253         if (binding instanceof SOAPBinding && AddressingVersion.isEnabled(binding) && wsdlModel!=null)
 254             if(AddressingVersion.fromBinding(binding) == AddressingVersion.MEMBER) {
 255                 return new MemberSubmissionWsaClientTube(wsdlModel, binding, next);
 256             } else {
 257                 return new W3CWsaClientTube(wsdlModel, binding, next);
 258             }
 259         else
 260             return next;
 261     }
 262 
 263     /**
 264      * Creates a {@link Tube} that invokes protocol and logical handlers.
 265      */
 266     public Tube createHandlerTube(Tube next) {
 267         HandlerTube cousinHandlerTube = null;
 268         //XML/HTTP Binding can have only LogicalHandlerPipe
 269         if (binding instanceof SOAPBinding) {
 270             //Add MessageHandlerTube
 271             HandlerTube messageHandlerTube = new ClientMessageHandlerTube(seiModel, binding, wsdlModel, next);
 272             next = cousinHandlerTube = messageHandlerTube;
 273 
 274             //Add SOAPHandlerTuber
 275             HandlerTube soapHandlerTube = new ClientSOAPHandlerTube(binding, next, cousinHandlerTube);
 276             next = cousinHandlerTube = soapHandlerTube;
 277         }
 278         return new ClientLogicalHandlerTube(binding, seiModel, next, cousinHandlerTube);
 279     }
 280 
 281     /**
 282      * Creates a {@link Tube} that performs SOAP mustUnderstand processing.
 283      * This pipe should be before HandlerPipes.
 284      */
 285     public Tube createClientMUTube(Tube next) {
 286         if(binding instanceof SOAPBinding)
 287             return new ClientMUTube(binding,next);
 288         else
 289             return next;
 290     }
 291 
 292     /**
 293      * creates a {@link Tube} that validates messages against schema
 294      */
 295     public Tube createValidationTube(Tube next) {
 296         if (binding instanceof SOAPBinding && binding.isFeatureEnabled(SchemaValidationFeature.class) && wsdlModel!=null)
 297             return new ClientSchemaValidationTube(binding, wsdlModel, next);
 298         else
 299             return next;
 300     }
 301 
 302     /**
 303      * Creates a transport pipe (for client), which becomes the terminal pipe.
 304      */
 305     public Tube createTransportTube() {
 306         ClassLoader cl = Thread.currentThread().getContextClassLoader();
 307 
 308         // The application may configure the endpoint address through request context
 309         // using {@link BindingProvider#ENDPOINT_ADDRESS_PROPERTY}. Let us
 310         // defer the creation of actual transport until the service invocation,
 311         // DeferredTransportPipe is used for this purpose.
 312         return new DeferredTransportPipe(cl,this);
 313     }
 314 
 315     /**
 316      * Gets the {@link Codec} that is set by {@link #setCodec} or the default codec
 317      * based on the binding.
 318      *
 319      * @return codec to be used for web service requests
 320      */
 321     public @NotNull Codec getCodec() {
 322         return codec;
 323     }
 324 
 325     /**
 326      * Interception point to change {@link Codec} during {@link Tube}line assembly. The
 327      * new codec will be used by jax-ws client runtime for encoding/decoding web service
 328      * request/response messages. The new codec should be used by the transport tubes.
 329      *
 330      * <p>
 331      * the codec should correctly implement {@link Codec#copy} since it is used while
 332      * serving requests concurrently.
 333      *
 334      * @param codec codec to be used for web service requests
 335      */
 336     public void setCodec(@NotNull Codec codec) {
 337         this.codec = codec;
 338     }
 339 
 340 }