/* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.xml.internal.ws.api; import com.sun.istack.internal.NotNull; import com.sun.xml.internal.ws.api.message.Message; import com.sun.xml.internal.ws.api.pipe.Codec; import com.sun.xml.internal.ws.api.pipe.Tube; import com.sun.xml.internal.ws.binding.BindingImpl; import com.sun.xml.internal.ws.binding.SOAPBindingImpl; import com.sun.xml.internal.ws.binding.WebServiceFeatureList; import com.sun.xml.internal.ws.encoding.SOAPBindingCodec; import com.sun.xml.internal.ws.encoding.XMLHTTPBindingCodec; import com.sun.xml.internal.ws.encoding.soap.streaming.SOAPNamespaceConstants; import com.sun.xml.internal.ws.util.ServiceFinder; import com.sun.xml.internal.ws.developer.JAXWSProperties; import javax.xml.ws.BindingType; import javax.xml.ws.WebServiceException; import javax.xml.ws.WebServiceFeature; import javax.xml.ws.handler.Handler; import javax.xml.ws.http.HTTPBinding; import javax.xml.ws.soap.MTOMFeature; import javax.xml.ws.soap.SOAPBinding; import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLDecoder; import java.util.HashMap; import java.util.Map; /** * Parsed binding ID string. * *
* {@link BindingID} is an immutable object that represents a binding ID, * much like how {@link URL} is a representation of an URL. * Like {@link URL}, this class offers a bunch of methods that let you * query various traits/properties of a binding ID. * *
* {@link BindingID} is extensible; one can plug in a parser from * {@link String} to {@link BindingID} to interpret binding IDs that * the JAX-WS RI does no a-priori knowledge of. * Technologies such as Tango uses this to make the JAX-WS RI understand * binding IDs defined in their world. * * Such technologies are free to extend this class and expose more characterstics. * *
* Even though this class defines a few well known constants, {@link BindingID} * instances do not necessarily have singleton semantics. Use {@link #equals(Object)} * for the comparison. * *
* {@link WSBinding} is mutable and represents a particular "use" of a {@link BindingID}. * As such, it has state like a list of {@link Handler}s, which are inherently local * to a particular usage. For example, if you have two proxies, you need two instances. * * {@link BindingID}, OTOH, is immutable and thus the single instance * that represents "SOAP1.2/HTTP" can be shared and reused by all proxies in the same VM. * * @author Kohsuke Kawaguchi */ public abstract class BindingID { /** * Creates an instance of {@link WSBinding} (which is conceptually an "use" * of {@link BindingID}) from a {@link BindingID}. * * @return * Always a new instance. */ public final @NotNull WSBinding createBinding() { return BindingImpl.create(this); } /** * Returns wsdl:binding@transport attribute. Sub classes * are expected to override this method to provide their transport * attribute. * * @return wsdl:binding@transport attribute * @since JAX-WS RI 2.1.6 */ public @NotNull String getTransport() { return SOAPNamespaceConstants.TRANSPORT_HTTP; } public final @NotNull WSBinding createBinding(WebServiceFeature... features) { return BindingImpl.create(this, features); } public final @NotNull WSBinding createBinding(WSFeatureList features) { return createBinding(features.toArray()); } /** * Gets the SOAP version of this binding. * * TODO: clarify what to do with XML/HTTP binding * * @return * If the binding is using SOAP, this method returns * a {@link SOAPVersion} constant. * * If the binding is not based on SOAP, this method * returns null. See {@link Message} for how a non-SOAP * binding shall be handled by {@link Tube}s. */ public abstract SOAPVersion getSOAPVersion(); /** * Creates a new {@link Codec} for this binding. * * @param binding * Ocassionally some aspects of binding can be overridden by * {@link WSBinding} at runtime by users, so some {@link Codec}s * need to have access to {@link WSBinding} that it's working for. */ public abstract @NotNull Codec createEncoder(@NotNull WSBinding binding); /** * Gets the binding ID, which uniquely identifies the binding. * *
* The relevant specs define the binding IDs and what they mean. * The ID is used in many places to identify the kind of binding * (such as SOAP1.1, SOAP1.2, REST, ...) * * @return * Always non-null same value. */ @Override public abstract String toString(); /** * Returna a new {@link WebServiceFeatureList} instance * that represents the features that are built into this binding ID. * *
* For example, {@link BindingID} for * {@code "{@value SOAPBinding#SOAP11HTTP_MTOM_BINDING}"} * would always return a list that has {@link MTOMFeature} enabled. */ public WebServiceFeatureList createBuiltinFeatureList() { return new WebServiceFeatureList(); } /** * Returns true if this binding can generate WSDL. * *
* For e.g.: SOAP 1.1 and "XSOAP 1.2" is supposed to return true * from this method. For SOAP1.2, there is no standard WSDL, so the * runtime is not generating one and it expects the WSDL is packaged. * */ public boolean canGenerateWSDL() { return false; } /** * Returns a parameter of this binding ID. * *
* Some binding ID, such as those for SOAP/HTTP, uses the URL * query syntax (like {@code ?mtom=true}) to control * the optional part of the binding. This method obtains * the value for such optional parts. * *
* For implementors of the derived classes, if your binding ID * does not define such optional parts (such as the XML/HTTP binding ID), * then you should simply return the specified default value * (which is what this implementation does.) * * @param parameterName * The parameter name, such as "mtom" in the above example. * @param defaultValue * If this binding ID doesn't have the specified parameter explicitly, * this value will be returned. * * @return * the value of the parameter, if it's present (such as "true" * in the above example.) If not present, this method returns * the {@code defaultValue}. */ public String getParameter(String parameterName, String defaultValue) { return defaultValue; } /** * Compares the equality based on {@link #toString()}. */ @Override public boolean equals(Object obj) { if(!(obj instanceof BindingID)) return false; return toString().equals(obj.toString()); } @Override public int hashCode() { return toString().hashCode(); } /** * Parses a binding ID string into a {@link BindingID} object. * *
* This method first checks for a few known values and then delegate * the parsing to {@link BindingIDFactory}. * *
* If parsing succeeds this method returns a value. Otherwise
* throws {@link WebServiceException}.
*
* @throws WebServiceException
* If the binding ID is not understood.
*/
public static @NotNull BindingID parse(String lexical) {
if(lexical.equals(XML_HTTP.toString()))
return XML_HTTP;
if(lexical.equals(REST_HTTP.toString()))
return REST_HTTP;
if(belongsTo(lexical,SOAP11_HTTP.toString()))
return customize(lexical,SOAP11_HTTP);
if(belongsTo(lexical,SOAP12_HTTP.toString()))
return customize(lexical,SOAP12_HTTP);
if(belongsTo(lexical,SOAPBindingImpl.X_SOAP12HTTP_BINDING))
return customize(lexical,X_SOAP12_HTTP);
// OK, it's none of the values JAX-WS understands.
for( BindingIDFactory f : ServiceFinder.find(BindingIDFactory.class) ) {
BindingID r = f.parse(lexical);
if(r!=null)
return r;
}
// nobody understood this value
throw new WebServiceException("Wrong binding ID: "+lexical);
}
private static boolean belongsTo(String lexical, String id) {
return lexical.equals(id) || lexical.startsWith(id+'?');
}
/**
* Parses parameter portion and returns appropriately populated {@link SOAPHTTPImpl}
*/
private static SOAPHTTPImpl customize(String lexical, SOAPHTTPImpl base) {
if(lexical.equals(base.toString()))
return base;
// otherwise we must have query parameter
// we assume the spec won't define any tricky parameters that require
// complicated handling (such as %HH or non-ASCII char), so this parser
// is quite simple-minded.
SOAPHTTPImpl r = new SOAPHTTPImpl(base.getSOAPVersion(), lexical, base.canGenerateWSDL());
try {
// With X_SOAP12_HTTP, base != lexical and lexical does n't have any query string
if(lexical.indexOf('?') == -1) {
return r;
}
String query = URLDecoder.decode(lexical.substring(lexical.indexOf('?')+1),"UTF-8");
for( String token : query.split("&") ) {
int idx = token.indexOf('=');
if(idx<0)
throw new WebServiceException("Malformed binding ID (no '=' in "+token+")");
r.parameters.put(token.substring(0,idx),token.substring(idx+1));
}
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e); // UTF-8 is supported everywhere
}
return r;
}
/**
* Figures out the binding from {@link BindingType} annotation.
*
* @return
* default to {@link BindingID#SOAP11_HTTP}, if no such annotation is present.
* @see #parse(String)
*/
public static @NotNull BindingID parse(Class> implClass) {
BindingType bindingType = implClass.getAnnotation(BindingType.class);
if (bindingType != null) {
String bindingId = bindingType.value();
if (bindingId.length() > 0) {
return BindingID.parse(bindingId);
}
}
return SOAP11_HTTP;
}
/**
* Constant that represents implementation specific SOAP1.2/HTTP which is
* used to generate non-standard WSDLs
*/
public static final SOAPHTTPImpl X_SOAP12_HTTP = new SOAPHTTPImpl(
SOAPVersion.SOAP_12, SOAPBindingImpl.X_SOAP12HTTP_BINDING, true);
/**
* Constant that represents SOAP1.2/HTTP.
*/
public static final SOAPHTTPImpl SOAP12_HTTP = new SOAPHTTPImpl(
SOAPVersion.SOAP_12, SOAPBinding.SOAP12HTTP_BINDING, true);
/**
* Constant that represents SOAP1.1/HTTP.
*/
public static final SOAPHTTPImpl SOAP11_HTTP = new SOAPHTTPImpl(
SOAPVersion.SOAP_11, SOAPBinding.SOAP11HTTP_BINDING, true);
/**
* Constant that represents SOAP1.2/HTTP.
*/
public static final SOAPHTTPImpl SOAP12_HTTP_MTOM = new SOAPHTTPImpl(
SOAPVersion.SOAP_12, SOAPBinding.SOAP12HTTP_MTOM_BINDING, true, true);
/**
* Constant that represents SOAP1.1/HTTP.
*/
public static final SOAPHTTPImpl SOAP11_HTTP_MTOM = new SOAPHTTPImpl(
SOAPVersion.SOAP_11, SOAPBinding.SOAP11HTTP_MTOM_BINDING, true, true);
/**
* Constant that represents REST.
*/
public static final BindingID XML_HTTP = new Impl(SOAPVersion.SOAP_11, HTTPBinding.HTTP_BINDING,false) {
@Override
public Codec createEncoder(WSBinding binding) {
return new XMLHTTPBindingCodec(binding.getFeatures());
}
};
/**
* Constant that represents REST.
*/
private static final BindingID REST_HTTP = new Impl(SOAPVersion.SOAP_11, JAXWSProperties.REST_BINDING,true) {
@Override
public Codec createEncoder(WSBinding binding) {
return new XMLHTTPBindingCodec(binding.getFeatures());
}
};
private static abstract class Impl extends BindingID {
final SOAPVersion version;
private final String lexical;
private final boolean canGenerateWSDL;
public Impl(SOAPVersion version, String lexical, boolean canGenerateWSDL) {
this.version = version;
this.lexical = lexical;
this.canGenerateWSDL = canGenerateWSDL;
}
@Override
public SOAPVersion getSOAPVersion() {
return version;
}
@Override
public String toString() {
return lexical;
}
@Deprecated
@Override
public boolean canGenerateWSDL() {
return canGenerateWSDL;
}
}
/**
* Internal implementation for SOAP/HTTP.
*/
private static final class SOAPHTTPImpl extends Impl implements Cloneable {
/*final*/ Map