1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/jaxws_classes/com/sun/xml/internal/ws/api/BindingID.java Tue Mar 06 16:09:35 2012 -0800 1.3 @@ -0,0 +1,439 @@ 1.4 +/* 1.5 + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.xml.internal.ws.api; 1.30 + 1.31 +import com.sun.istack.internal.NotNull; 1.32 +import com.sun.xml.internal.ws.api.message.Message; 1.33 +import com.sun.xml.internal.ws.api.pipe.Codec; 1.34 +import com.sun.xml.internal.ws.api.pipe.Tube; 1.35 +import com.sun.xml.internal.ws.binding.BindingImpl; 1.36 +import com.sun.xml.internal.ws.binding.SOAPBindingImpl; 1.37 +import com.sun.xml.internal.ws.binding.WebServiceFeatureList; 1.38 +import com.sun.xml.internal.ws.encoding.SOAPBindingCodec; 1.39 +import com.sun.xml.internal.ws.encoding.XMLHTTPBindingCodec; 1.40 +import com.sun.xml.internal.ws.encoding.soap.streaming.SOAPNamespaceConstants; 1.41 +import com.sun.xml.internal.ws.encoding.soap.streaming.SOAP12NamespaceConstants; 1.42 +import com.sun.xml.internal.ws.util.ServiceFinder; 1.43 +import com.sun.xml.internal.ws.developer.JAXWSProperties; 1.44 +import static com.sun.xml.internal.ws.binding.WebServiceFeatureList.toFeatureArray; 1.45 + 1.46 +import javax.xml.ws.BindingType; 1.47 +import javax.xml.ws.WebServiceException; 1.48 +import javax.xml.ws.WebServiceFeature; 1.49 +import javax.xml.ws.handler.Handler; 1.50 +import javax.xml.ws.http.HTTPBinding; 1.51 +import javax.xml.ws.soap.MTOMFeature; 1.52 +import javax.xml.ws.soap.SOAPBinding; 1.53 + 1.54 +import java.io.UnsupportedEncodingException; 1.55 +import java.net.URL; 1.56 +import java.net.URLDecoder; 1.57 +import java.util.HashMap; 1.58 +import java.util.Map; 1.59 + 1.60 +/** 1.61 + * Parsed binding ID string. 1.62 + * 1.63 + * <p> 1.64 + * {@link BindingID} is an immutable object that represents a binding ID, 1.65 + * much like how {@link URL} is a representation of an URL. 1.66 + * Like {@link URL}, this class offers a bunch of methods that let you 1.67 + * query various traits/properties of a binding ID. 1.68 + * 1.69 + * <p> 1.70 + * {@link BindingID} is extensible; one can plug in a parser from 1.71 + * {@link String} to {@link BindingID} to interpret binding IDs that 1.72 + * the JAX-WS RI does no a-priori knowledge of. 1.73 + * Technologies such as Tango uses this to make the JAX-WS RI understand 1.74 + * binding IDs defined in their world. 1.75 + * 1.76 + * Such technologies are free to extend this class and expose more characterstics. 1.77 + * 1.78 + * <p> 1.79 + * Even though this class defines a few well known constants, {@link BindingID} 1.80 + * instances do not necessarily have singleton semantics. Use {@link #equals(Object)} 1.81 + * for the comparison. 1.82 + * 1.83 + * <h3>{@link BindingID} and {@link WSBinding}</h3> 1.84 + * <p> 1.85 + * {@link WSBinding} is mutable and represents a particular "use" of a {@link BindingID}. 1.86 + * As such, it has state like a list of {@link Handler}s, which are inherently local 1.87 + * to a particular usage. For example, if you have two proxies, you need two instances. 1.88 + * 1.89 + * {@link BindingID}, OTOH, is immutable and thus the single instance 1.90 + * that represents "SOAP1.2/HTTP" can be shared and reused by all proxies in the same VM. 1.91 + * 1.92 + * @author Kohsuke Kawaguchi 1.93 + */ 1.94 +public abstract class BindingID { 1.95 + 1.96 + /** 1.97 + * Creates an instance of {@link WSBinding} (which is conceptually an "use" 1.98 + * of {@link BindingID}) from a {@link BindingID}. 1.99 + * 1.100 + * @return 1.101 + * Always a new instance. 1.102 + */ 1.103 + public final @NotNull WSBinding createBinding() { 1.104 + return BindingImpl.create(this); 1.105 + } 1.106 + 1.107 + /** 1.108 + * Returns wsdl:binding@transport attribute. Sub classes 1.109 + * are expected to override this method to provide their transport 1.110 + * attribute. 1.111 + * 1.112 + * @return wsdl:binding@transport attribute 1.113 + * @since JAX-WS RI 2.1.6 1.114 + */ 1.115 + public @NotNull String getTransport() { 1.116 + return SOAPNamespaceConstants.TRANSPORT_HTTP; 1.117 + } 1.118 + 1.119 + public final @NotNull WSBinding createBinding(WebServiceFeature... features) { 1.120 + return BindingImpl.create(this, features); 1.121 + } 1.122 + 1.123 + public final @NotNull WSBinding createBinding(WSFeatureList features) { 1.124 + return createBinding(features.toArray()); 1.125 + } 1.126 + 1.127 + /** 1.128 + * Gets the SOAP version of this binding. 1.129 + * 1.130 + * TODO: clarify what to do with XML/HTTP binding 1.131 + * 1.132 + * @return 1.133 + * If the binding is using SOAP, this method returns 1.134 + * a {@link SOAPVersion} constant. 1.135 + * 1.136 + * If the binding is not based on SOAP, this method 1.137 + * returns null. See {@link Message} for how a non-SOAP 1.138 + * binding shall be handled by {@link Tube}s. 1.139 + */ 1.140 + public abstract SOAPVersion getSOAPVersion(); 1.141 + 1.142 + /** 1.143 + * Creates a new {@link Codec} for this binding. 1.144 + * 1.145 + * @param binding 1.146 + * Ocassionally some aspects of binding can be overridden by 1.147 + * {@link WSBinding} at runtime by users, so some {@link Codec}s 1.148 + * need to have access to {@link WSBinding} that it's working for. 1.149 + */ 1.150 + public abstract @NotNull Codec createEncoder(@NotNull WSBinding binding); 1.151 + 1.152 + /** 1.153 + * Gets the binding ID, which uniquely identifies the binding. 1.154 + * 1.155 + * <p> 1.156 + * The relevant specs define the binding IDs and what they mean. 1.157 + * The ID is used in many places to identify the kind of binding 1.158 + * (such as SOAP1.1, SOAP1.2, REST, ...) 1.159 + * 1.160 + * @return 1.161 + * Always non-null same value. 1.162 + */ 1.163 + public abstract String toString(); 1.164 + 1.165 + /** 1.166 + * Returna a new {@link WebServiceFeatureList} instance 1.167 + * that represents the features that are built into this binding ID. 1.168 + * 1.169 + * <p> 1.170 + * For example, {@link BindingID} for 1.171 + * <tt>"{@value SOAPBinding#SOAP11HTTP_MTOM_BINDING}"</tt> 1.172 + * would always return a list that has {@link MTOMFeature} enabled. 1.173 + */ 1.174 + public WebServiceFeatureList createBuiltinFeatureList() { 1.175 + return new WebServiceFeatureList(); 1.176 + } 1.177 + 1.178 + /** 1.179 + * Returns true if this binding can generate WSDL. 1.180 + * 1.181 + * <p> 1.182 + * For e.g.: SOAP 1.1 and "XSOAP 1.2" is supposed to return true 1.183 + * from this method. For SOAP1.2, there is no standard WSDL, so the 1.184 + * runtime is not generating one and it expects the WSDL is packaged. 1.185 + * 1.186 + */ 1.187 + public boolean canGenerateWSDL() { 1.188 + return false; 1.189 + } 1.190 + 1.191 + /** 1.192 + * Returns a parameter of this binding ID. 1.193 + * 1.194 + * <p> 1.195 + * Some binding ID, such as those for SOAP/HTTP, uses the URL 1.196 + * query syntax (like <tt>?mtom=true</tt>) to control 1.197 + * the optional part of the binding. This method obtains 1.198 + * the value for such optional parts. 1.199 + * 1.200 + * <p> 1.201 + * For implementors of the derived classes, if your binding ID 1.202 + * does not define such optional parts (such as the XML/HTTP binding ID), 1.203 + * then you should simply return the specified default value 1.204 + * (which is what this implementation does.) 1.205 + * 1.206 + * @param parameterName 1.207 + * The parameter name, such as "mtom" in the above example. 1.208 + * @param defaultValue 1.209 + * If this binding ID doesn't have the specified parameter explicitly, 1.210 + * this value will be returned. 1.211 + * 1.212 + * @return 1.213 + * the value of the parameter, if it's present (such as "true" 1.214 + * in the above example.) If not present, this method returns 1.215 + * the {@code defaultValue}. 1.216 + */ 1.217 + public String getParameter(String parameterName, String defaultValue) { 1.218 + return defaultValue; 1.219 + } 1.220 + 1.221 + /** 1.222 + * Compares the equality based on {@link #toString()}. 1.223 + */ 1.224 + public boolean equals(Object obj) { 1.225 + if(!(obj instanceof BindingID)) 1.226 + return false; 1.227 + return toString().equals(obj.toString()); 1.228 + } 1.229 + 1.230 + public int hashCode() { 1.231 + return toString().hashCode(); 1.232 + } 1.233 + 1.234 + /** 1.235 + * Parses a binding ID string into a {@link BindingID} object. 1.236 + * 1.237 + * <p> 1.238 + * This method first checks for a few known values and then delegate 1.239 + * the parsing to {@link BindingIDFactory}. 1.240 + * 1.241 + * <p> 1.242 + * If parsing succeeds this method returns a value. Otherwise 1.243 + * throws {@link WebServiceException}. 1.244 + * 1.245 + * @throws WebServiceException 1.246 + * If the binding ID is not understood. 1.247 + */ 1.248 + public static @NotNull BindingID parse(String lexical) { 1.249 + if(lexical.equals(XML_HTTP.toString())) 1.250 + return XML_HTTP; 1.251 + if(lexical.equals(REST_HTTP.toString())) 1.252 + return REST_HTTP; 1.253 + if(belongsTo(lexical,SOAP11_HTTP.toString())) 1.254 + return customize(lexical,SOAP11_HTTP); 1.255 + if(belongsTo(lexical,SOAP12_HTTP.toString())) 1.256 + return customize(lexical,SOAP12_HTTP); 1.257 + if(belongsTo(lexical,SOAPBindingImpl.X_SOAP12HTTP_BINDING)) 1.258 + return customize(lexical,X_SOAP12_HTTP); 1.259 + 1.260 + // OK, it's none of the values JAX-WS understands. 1.261 + for( BindingIDFactory f : ServiceFinder.find(BindingIDFactory.class) ) { 1.262 + BindingID r = f.parse(lexical); 1.263 + if(r!=null) 1.264 + return r; 1.265 + } 1.266 + 1.267 + // nobody understood this value 1.268 + throw new WebServiceException("Wrong binding ID: "+lexical); 1.269 + } 1.270 + 1.271 + private static boolean belongsTo(String lexical, String id) { 1.272 + return lexical.equals(id) || lexical.startsWith(id+'?'); 1.273 + } 1.274 + 1.275 + /** 1.276 + * Parses parameter portion and returns appropriately populated {@link SOAPHTTPImpl} 1.277 + */ 1.278 + private static SOAPHTTPImpl customize(String lexical, SOAPHTTPImpl base) { 1.279 + if(lexical.equals(base.toString())) 1.280 + return base; 1.281 + 1.282 + // otherwise we must have query parameter 1.283 + // we assume the spec won't define any tricky parameters that require 1.284 + // complicated handling (such as %HH or non-ASCII char), so this parser 1.285 + // is quite simple-minded. 1.286 + SOAPHTTPImpl r = new SOAPHTTPImpl(base.getSOAPVersion(), lexical, base.canGenerateWSDL()); 1.287 + try { 1.288 + // With X_SOAP12_HTTP, base != lexical and lexical does n't have any query string 1.289 + if(lexical.indexOf('?') == -1) { 1.290 + return r; 1.291 + } 1.292 + String query = URLDecoder.decode(lexical.substring(lexical.indexOf('?')+1),"UTF-8"); 1.293 + for( String token : query.split("&") ) { 1.294 + int idx = token.indexOf('='); 1.295 + if(idx<0) 1.296 + throw new WebServiceException("Malformed binding ID (no '=' in "+token+")"); 1.297 + r.parameters.put(token.substring(0,idx),token.substring(idx+1)); 1.298 + } 1.299 + } catch (UnsupportedEncodingException e) { 1.300 + throw new AssertionError(e); // UTF-8 is supported everywhere 1.301 + } 1.302 + 1.303 + return r; 1.304 + } 1.305 + 1.306 + 1.307 + /** 1.308 + * Figures out the binding from {@link BindingType} annotation. 1.309 + * 1.310 + * @return 1.311 + * default to {@link BindingID#SOAP11_HTTP}, if no such annotation is present. 1.312 + * @see #parse(String) 1.313 + */ 1.314 + public static @NotNull BindingID parse(Class<?> implClass) { 1.315 + BindingType bindingType = implClass.getAnnotation(BindingType.class); 1.316 + if (bindingType != null) { 1.317 + String bindingId = bindingType.value(); 1.318 + if (bindingId.length() > 0) { 1.319 + return BindingID.parse(bindingId); 1.320 + } 1.321 + } 1.322 + return SOAP11_HTTP; 1.323 + } 1.324 + 1.325 + /** 1.326 + * Constant that represents implementation specific SOAP1.2/HTTP which is 1.327 + * used to generate non-standard WSDLs 1.328 + */ 1.329 + public static final SOAPHTTPImpl X_SOAP12_HTTP = new SOAPHTTPImpl( 1.330 + SOAPVersion.SOAP_12, SOAPBindingImpl.X_SOAP12HTTP_BINDING, true); 1.331 + 1.332 + /** 1.333 + * Constant that represents SOAP1.2/HTTP. 1.334 + */ 1.335 + public static final SOAPHTTPImpl SOAP12_HTTP = new SOAPHTTPImpl( 1.336 + SOAPVersion.SOAP_12, SOAPBinding.SOAP12HTTP_BINDING, true); 1.337 + /** 1.338 + * Constant that represents SOAP1.1/HTTP. 1.339 + */ 1.340 + public static final SOAPHTTPImpl SOAP11_HTTP = new SOAPHTTPImpl( 1.341 + SOAPVersion.SOAP_11, SOAPBinding.SOAP11HTTP_BINDING, true); 1.342 + 1.343 + /** 1.344 + * Constant that represents SOAP1.2/HTTP. 1.345 + */ 1.346 + public static final SOAPHTTPImpl SOAP12_HTTP_MTOM = new SOAPHTTPImpl( 1.347 + SOAPVersion.SOAP_12, SOAPBinding.SOAP12HTTP_MTOM_BINDING, true, true); 1.348 + /** 1.349 + * Constant that represents SOAP1.1/HTTP. 1.350 + */ 1.351 + public static final SOAPHTTPImpl SOAP11_HTTP_MTOM = new SOAPHTTPImpl( 1.352 + SOAPVersion.SOAP_11, SOAPBinding.SOAP11HTTP_MTOM_BINDING, true, true); 1.353 + 1.354 + 1.355 + /** 1.356 + * Constant that represents REST. 1.357 + */ 1.358 + public static final BindingID XML_HTTP = new Impl(SOAPVersion.SOAP_11, HTTPBinding.HTTP_BINDING,false) { 1.359 + public Codec createEncoder(WSBinding binding) { 1.360 + return new XMLHTTPBindingCodec(binding.getFeatures()); 1.361 + } 1.362 + }; 1.363 + 1.364 + /** 1.365 + * Constant that represents REST. 1.366 + */ 1.367 + private static final BindingID REST_HTTP = new Impl(SOAPVersion.SOAP_11, JAXWSProperties.REST_BINDING,true) { 1.368 + public Codec createEncoder(WSBinding binding) { 1.369 + return new XMLHTTPBindingCodec(binding.getFeatures()); 1.370 + } 1.371 + }; 1.372 + 1.373 + private static abstract class Impl extends BindingID { 1.374 + final SOAPVersion version; 1.375 + private final String lexical; 1.376 + private final boolean canGenerateWSDL; 1.377 + 1.378 + public Impl(SOAPVersion version, String lexical, boolean canGenerateWSDL) { 1.379 + this.version = version; 1.380 + this.lexical = lexical; 1.381 + this.canGenerateWSDL = canGenerateWSDL; 1.382 + } 1.383 + 1.384 + public SOAPVersion getSOAPVersion() { 1.385 + return version; 1.386 + } 1.387 + 1.388 + public String toString() { 1.389 + return lexical; 1.390 + } 1.391 + 1.392 + @Deprecated 1.393 + public boolean canGenerateWSDL() { 1.394 + return canGenerateWSDL; 1.395 + } 1.396 + } 1.397 + 1.398 + /** 1.399 + * Internal implementation for SOAP/HTTP. 1.400 + */ 1.401 + private static final class SOAPHTTPImpl extends Impl implements Cloneable { 1.402 + /*final*/ Map<String,String> parameters = new HashMap<String,String>(); 1.403 + 1.404 + static final String MTOM_PARAM = "mtom"; 1.405 + Boolean mtomSetting = null; 1.406 + 1.407 + public SOAPHTTPImpl(SOAPVersion version, String lexical, boolean canGenerateWSDL) { 1.408 + super(version, lexical, canGenerateWSDL); 1.409 + } 1.410 + 1.411 + public SOAPHTTPImpl(SOAPVersion version, String lexical, boolean canGenerateWSDL, 1.412 + boolean mtomEnabled) { 1.413 + this(version, lexical, canGenerateWSDL); 1.414 + String mtomStr = mtomEnabled ? "true" : "false"; 1.415 + parameters.put(MTOM_PARAM, mtomStr); 1.416 + mtomSetting = mtomEnabled; 1.417 + } 1.418 + 1.419 + public @NotNull Codec createEncoder(WSBinding binding) { 1.420 + return new SOAPBindingCodec(binding.getFeatures()); 1.421 + } 1.422 + 1.423 + private Boolean isMTOMEnabled() { 1.424 + String mtom = parameters.get(MTOM_PARAM); 1.425 + return mtom==null?null:Boolean.valueOf(mtom); 1.426 + } 1.427 + 1.428 + public WebServiceFeatureList createBuiltinFeatureList() { 1.429 + WebServiceFeatureList r=super.createBuiltinFeatureList(); 1.430 + Boolean mtom = isMTOMEnabled(); 1.431 + if(mtom != null) 1.432 + r.add(new MTOMFeature(mtom)); 1.433 + return r; 1.434 + } 1.435 + 1.436 + public String getParameter(String parameterName, String defaultValue) { 1.437 + if (parameters.get(parameterName) == null) 1.438 + return super.getParameter(parameterName, defaultValue); 1.439 + return parameters.get(parameterName); 1.440 + } 1.441 + } 1.442 +}