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