Tue, 06 Mar 2012 16:09:35 -0800
7150322: Stop using drop source bundles in jaxws
Reviewed-by: darcy, ohrstrom
1 /*
2 * Copyright (c) 1997, 2011, 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.api;
28 import com.sun.istack.internal.NotNull;
29 import com.sun.xml.internal.ws.api.message.Message;
30 import com.sun.xml.internal.ws.api.pipe.Codec;
31 import com.sun.xml.internal.ws.api.pipe.Tube;
32 import com.sun.xml.internal.ws.binding.BindingImpl;
33 import com.sun.xml.internal.ws.binding.SOAPBindingImpl;
34 import com.sun.xml.internal.ws.binding.WebServiceFeatureList;
35 import com.sun.xml.internal.ws.encoding.SOAPBindingCodec;
36 import com.sun.xml.internal.ws.encoding.XMLHTTPBindingCodec;
37 import com.sun.xml.internal.ws.encoding.soap.streaming.SOAPNamespaceConstants;
38 import com.sun.xml.internal.ws.encoding.soap.streaming.SOAP12NamespaceConstants;
39 import com.sun.xml.internal.ws.util.ServiceFinder;
40 import com.sun.xml.internal.ws.developer.JAXWSProperties;
41 import static com.sun.xml.internal.ws.binding.WebServiceFeatureList.toFeatureArray;
43 import javax.xml.ws.BindingType;
44 import javax.xml.ws.WebServiceException;
45 import javax.xml.ws.WebServiceFeature;
46 import javax.xml.ws.handler.Handler;
47 import javax.xml.ws.http.HTTPBinding;
48 import javax.xml.ws.soap.MTOMFeature;
49 import javax.xml.ws.soap.SOAPBinding;
51 import java.io.UnsupportedEncodingException;
52 import java.net.URL;
53 import java.net.URLDecoder;
54 import java.util.HashMap;
55 import java.util.Map;
57 /**
58 * Parsed binding ID string.
59 *
60 * <p>
61 * {@link BindingID} is an immutable object that represents a binding ID,
62 * much like how {@link URL} is a representation of an URL.
63 * Like {@link URL}, this class offers a bunch of methods that let you
64 * query various traits/properties of a binding ID.
65 *
66 * <p>
67 * {@link BindingID} is extensible; one can plug in a parser from
68 * {@link String} to {@link BindingID} to interpret binding IDs that
69 * the JAX-WS RI does no a-priori knowledge of.
70 * Technologies such as Tango uses this to make the JAX-WS RI understand
71 * binding IDs defined in their world.
72 *
73 * Such technologies are free to extend this class and expose more characterstics.
74 *
75 * <p>
76 * Even though this class defines a few well known constants, {@link BindingID}
77 * instances do not necessarily have singleton semantics. Use {@link #equals(Object)}
78 * for the comparison.
79 *
80 * <h3>{@link BindingID} and {@link WSBinding}</h3>
81 * <p>
82 * {@link WSBinding} is mutable and represents a particular "use" of a {@link BindingID}.
83 * As such, it has state like a list of {@link Handler}s, which are inherently local
84 * to a particular usage. For example, if you have two proxies, you need two instances.
85 *
86 * {@link BindingID}, OTOH, is immutable and thus the single instance
87 * that represents "SOAP1.2/HTTP" can be shared and reused by all proxies in the same VM.
88 *
89 * @author Kohsuke Kawaguchi
90 */
91 public abstract class BindingID {
93 /**
94 * Creates an instance of {@link WSBinding} (which is conceptually an "use"
95 * of {@link BindingID}) from a {@link BindingID}.
96 *
97 * @return
98 * Always a new instance.
99 */
100 public final @NotNull WSBinding createBinding() {
101 return BindingImpl.create(this);
102 }
104 /**
105 * Returns wsdl:binding@transport attribute. Sub classes
106 * are expected to override this method to provide their transport
107 * attribute.
108 *
109 * @return wsdl:binding@transport attribute
110 * @since JAX-WS RI 2.1.6
111 */
112 public @NotNull String getTransport() {
113 return SOAPNamespaceConstants.TRANSPORT_HTTP;
114 }
116 public final @NotNull WSBinding createBinding(WebServiceFeature... features) {
117 return BindingImpl.create(this, features);
118 }
120 public final @NotNull WSBinding createBinding(WSFeatureList features) {
121 return createBinding(features.toArray());
122 }
124 /**
125 * Gets the SOAP version of this binding.
126 *
127 * TODO: clarify what to do with XML/HTTP binding
128 *
129 * @return
130 * If the binding is using SOAP, this method returns
131 * a {@link SOAPVersion} constant.
132 *
133 * If the binding is not based on SOAP, this method
134 * returns null. See {@link Message} for how a non-SOAP
135 * binding shall be handled by {@link Tube}s.
136 */
137 public abstract SOAPVersion getSOAPVersion();
139 /**
140 * Creates a new {@link Codec} for this binding.
141 *
142 * @param binding
143 * Ocassionally some aspects of binding can be overridden by
144 * {@link WSBinding} at runtime by users, so some {@link Codec}s
145 * need to have access to {@link WSBinding} that it's working for.
146 */
147 public abstract @NotNull Codec createEncoder(@NotNull WSBinding binding);
149 /**
150 * Gets the binding ID, which uniquely identifies the binding.
151 *
152 * <p>
153 * The relevant specs define the binding IDs and what they mean.
154 * The ID is used in many places to identify the kind of binding
155 * (such as SOAP1.1, SOAP1.2, REST, ...)
156 *
157 * @return
158 * Always non-null same value.
159 */
160 public abstract String toString();
162 /**
163 * Returna a new {@link WebServiceFeatureList} instance
164 * that represents the features that are built into this binding ID.
165 *
166 * <p>
167 * For example, {@link BindingID} for
168 * <tt>"{@value SOAPBinding#SOAP11HTTP_MTOM_BINDING}"</tt>
169 * would always return a list that has {@link MTOMFeature} enabled.
170 */
171 public WebServiceFeatureList createBuiltinFeatureList() {
172 return new WebServiceFeatureList();
173 }
175 /**
176 * Returns true if this binding can generate WSDL.
177 *
178 * <p>
179 * For e.g.: SOAP 1.1 and "XSOAP 1.2" is supposed to return true
180 * from this method. For SOAP1.2, there is no standard WSDL, so the
181 * runtime is not generating one and it expects the WSDL is packaged.
182 *
183 */
184 public boolean canGenerateWSDL() {
185 return false;
186 }
188 /**
189 * Returns a parameter of this binding ID.
190 *
191 * <p>
192 * Some binding ID, such as those for SOAP/HTTP, uses the URL
193 * query syntax (like <tt>?mtom=true</tt>) to control
194 * the optional part of the binding. This method obtains
195 * the value for such optional parts.
196 *
197 * <p>
198 * For implementors of the derived classes, if your binding ID
199 * does not define such optional parts (such as the XML/HTTP binding ID),
200 * then you should simply return the specified default value
201 * (which is what this implementation does.)
202 *
203 * @param parameterName
204 * The parameter name, such as "mtom" in the above example.
205 * @param defaultValue
206 * If this binding ID doesn't have the specified parameter explicitly,
207 * this value will be returned.
208 *
209 * @return
210 * the value of the parameter, if it's present (such as "true"
211 * in the above example.) If not present, this method returns
212 * the {@code defaultValue}.
213 */
214 public String getParameter(String parameterName, String defaultValue) {
215 return defaultValue;
216 }
218 /**
219 * Compares the equality based on {@link #toString()}.
220 */
221 public boolean equals(Object obj) {
222 if(!(obj instanceof BindingID))
223 return false;
224 return toString().equals(obj.toString());
225 }
227 public int hashCode() {
228 return toString().hashCode();
229 }
231 /**
232 * Parses a binding ID string into a {@link BindingID} object.
233 *
234 * <p>
235 * This method first checks for a few known values and then delegate
236 * the parsing to {@link BindingIDFactory}.
237 *
238 * <p>
239 * If parsing succeeds this method returns a value. Otherwise
240 * throws {@link WebServiceException}.
241 *
242 * @throws WebServiceException
243 * If the binding ID is not understood.
244 */
245 public static @NotNull BindingID parse(String lexical) {
246 if(lexical.equals(XML_HTTP.toString()))
247 return XML_HTTP;
248 if(lexical.equals(REST_HTTP.toString()))
249 return REST_HTTP;
250 if(belongsTo(lexical,SOAP11_HTTP.toString()))
251 return customize(lexical,SOAP11_HTTP);
252 if(belongsTo(lexical,SOAP12_HTTP.toString()))
253 return customize(lexical,SOAP12_HTTP);
254 if(belongsTo(lexical,SOAPBindingImpl.X_SOAP12HTTP_BINDING))
255 return customize(lexical,X_SOAP12_HTTP);
257 // OK, it's none of the values JAX-WS understands.
258 for( BindingIDFactory f : ServiceFinder.find(BindingIDFactory.class) ) {
259 BindingID r = f.parse(lexical);
260 if(r!=null)
261 return r;
262 }
264 // nobody understood this value
265 throw new WebServiceException("Wrong binding ID: "+lexical);
266 }
268 private static boolean belongsTo(String lexical, String id) {
269 return lexical.equals(id) || lexical.startsWith(id+'?');
270 }
272 /**
273 * Parses parameter portion and returns appropriately populated {@link SOAPHTTPImpl}
274 */
275 private static SOAPHTTPImpl customize(String lexical, SOAPHTTPImpl base) {
276 if(lexical.equals(base.toString()))
277 return base;
279 // otherwise we must have query parameter
280 // we assume the spec won't define any tricky parameters that require
281 // complicated handling (such as %HH or non-ASCII char), so this parser
282 // is quite simple-minded.
283 SOAPHTTPImpl r = new SOAPHTTPImpl(base.getSOAPVersion(), lexical, base.canGenerateWSDL());
284 try {
285 // With X_SOAP12_HTTP, base != lexical and lexical does n't have any query string
286 if(lexical.indexOf('?') == -1) {
287 return r;
288 }
289 String query = URLDecoder.decode(lexical.substring(lexical.indexOf('?')+1),"UTF-8");
290 for( String token : query.split("&") ) {
291 int idx = token.indexOf('=');
292 if(idx<0)
293 throw new WebServiceException("Malformed binding ID (no '=' in "+token+")");
294 r.parameters.put(token.substring(0,idx),token.substring(idx+1));
295 }
296 } catch (UnsupportedEncodingException e) {
297 throw new AssertionError(e); // UTF-8 is supported everywhere
298 }
300 return r;
301 }
304 /**
305 * Figures out the binding from {@link BindingType} annotation.
306 *
307 * @return
308 * default to {@link BindingID#SOAP11_HTTP}, if no such annotation is present.
309 * @see #parse(String)
310 */
311 public static @NotNull BindingID parse(Class<?> implClass) {
312 BindingType bindingType = implClass.getAnnotation(BindingType.class);
313 if (bindingType != null) {
314 String bindingId = bindingType.value();
315 if (bindingId.length() > 0) {
316 return BindingID.parse(bindingId);
317 }
318 }
319 return SOAP11_HTTP;
320 }
322 /**
323 * Constant that represents implementation specific SOAP1.2/HTTP which is
324 * used to generate non-standard WSDLs
325 */
326 public static final SOAPHTTPImpl X_SOAP12_HTTP = new SOAPHTTPImpl(
327 SOAPVersion.SOAP_12, SOAPBindingImpl.X_SOAP12HTTP_BINDING, true);
329 /**
330 * Constant that represents SOAP1.2/HTTP.
331 */
332 public static final SOAPHTTPImpl SOAP12_HTTP = new SOAPHTTPImpl(
333 SOAPVersion.SOAP_12, SOAPBinding.SOAP12HTTP_BINDING, true);
334 /**
335 * Constant that represents SOAP1.1/HTTP.
336 */
337 public static final SOAPHTTPImpl SOAP11_HTTP = new SOAPHTTPImpl(
338 SOAPVersion.SOAP_11, SOAPBinding.SOAP11HTTP_BINDING, true);
340 /**
341 * Constant that represents SOAP1.2/HTTP.
342 */
343 public static final SOAPHTTPImpl SOAP12_HTTP_MTOM = new SOAPHTTPImpl(
344 SOAPVersion.SOAP_12, SOAPBinding.SOAP12HTTP_MTOM_BINDING, true, true);
345 /**
346 * Constant that represents SOAP1.1/HTTP.
347 */
348 public static final SOAPHTTPImpl SOAP11_HTTP_MTOM = new SOAPHTTPImpl(
349 SOAPVersion.SOAP_11, SOAPBinding.SOAP11HTTP_MTOM_BINDING, true, true);
352 /**
353 * Constant that represents REST.
354 */
355 public static final BindingID XML_HTTP = new Impl(SOAPVersion.SOAP_11, HTTPBinding.HTTP_BINDING,false) {
356 public Codec createEncoder(WSBinding binding) {
357 return new XMLHTTPBindingCodec(binding.getFeatures());
358 }
359 };
361 /**
362 * Constant that represents REST.
363 */
364 private static final BindingID REST_HTTP = new Impl(SOAPVersion.SOAP_11, JAXWSProperties.REST_BINDING,true) {
365 public Codec createEncoder(WSBinding binding) {
366 return new XMLHTTPBindingCodec(binding.getFeatures());
367 }
368 };
370 private static abstract class Impl extends BindingID {
371 final SOAPVersion version;
372 private final String lexical;
373 private final boolean canGenerateWSDL;
375 public Impl(SOAPVersion version, String lexical, boolean canGenerateWSDL) {
376 this.version = version;
377 this.lexical = lexical;
378 this.canGenerateWSDL = canGenerateWSDL;
379 }
381 public SOAPVersion getSOAPVersion() {
382 return version;
383 }
385 public String toString() {
386 return lexical;
387 }
389 @Deprecated
390 public boolean canGenerateWSDL() {
391 return canGenerateWSDL;
392 }
393 }
395 /**
396 * Internal implementation for SOAP/HTTP.
397 */
398 private static final class SOAPHTTPImpl extends Impl implements Cloneable {
399 /*final*/ Map<String,String> parameters = new HashMap<String,String>();
401 static final String MTOM_PARAM = "mtom";
402 Boolean mtomSetting = null;
404 public SOAPHTTPImpl(SOAPVersion version, String lexical, boolean canGenerateWSDL) {
405 super(version, lexical, canGenerateWSDL);
406 }
408 public SOAPHTTPImpl(SOAPVersion version, String lexical, boolean canGenerateWSDL,
409 boolean mtomEnabled) {
410 this(version, lexical, canGenerateWSDL);
411 String mtomStr = mtomEnabled ? "true" : "false";
412 parameters.put(MTOM_PARAM, mtomStr);
413 mtomSetting = mtomEnabled;
414 }
416 public @NotNull Codec createEncoder(WSBinding binding) {
417 return new SOAPBindingCodec(binding.getFeatures());
418 }
420 private Boolean isMTOMEnabled() {
421 String mtom = parameters.get(MTOM_PARAM);
422 return mtom==null?null:Boolean.valueOf(mtom);
423 }
425 public WebServiceFeatureList createBuiltinFeatureList() {
426 WebServiceFeatureList r=super.createBuiltinFeatureList();
427 Boolean mtom = isMTOMEnabled();
428 if(mtom != null)
429 r.add(new MTOMFeature(mtom));
430 return r;
431 }
433 public String getParameter(String parameterName, String defaultValue) {
434 if (parameters.get(parameterName) == null)
435 return super.getParameter(parameterName, defaultValue);
436 return parameters.get(parameterName);
437 }
438 }
439 }