/*
 * Copyright (c) 1997, 2014, 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.binding;

import com.sun.istack.internal.NotNull;
import com.sun.istack.internal.Nullable;
import com.sun.xml.internal.ws.api.BindingID;
import com.sun.xml.internal.ws.api.FeatureListValidator;
import com.sun.xml.internal.ws.api.FeatureListValidatorAnnotation;
import com.sun.xml.internal.ws.api.ImpliesWebServiceFeature;
import com.sun.xml.internal.ws.api.SOAPVersion;
import com.sun.xml.internal.ws.api.WSBinding;
import com.sun.xml.internal.ws.api.WSFeatureList;
import com.sun.xml.internal.ws.api.FeatureConstructor;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLFeaturedObject;
import com.sun.xml.internal.ws.model.RuntimeModelerException;
import com.sun.xml.internal.ws.resources.ModelerMessages;
import com.sun.xml.internal.bind.util.Which;

import javax.xml.ws.RespectBinding;
import javax.xml.ws.RespectBindingFeature;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.soap.Addressing;
import javax.xml.ws.soap.AddressingFeature;
import javax.xml.ws.soap.MTOM;
import javax.xml.ws.soap.MTOMFeature;
import javax.xml.ws.spi.WebServiceFeatureAnnotation;

import com.oracle.webservices.internal.api.EnvelopeStyleFeature;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

Represents a list of WebServiceFeatures that has bunch of utility methods pertaining to web service features.
Author:Rama Pulavarthi
/** * Represents a list of {@link WebServiceFeature}s that has bunch of utility * methods pertaining to web service features. * * @author Rama Pulavarthi */
public final class WebServiceFeatureList extends AbstractMap<Class<? extends WebServiceFeature>, WebServiceFeature> implements WSFeatureList { public static WebServiceFeatureList toList(Iterable<WebServiceFeature> features) { if (features instanceof WebServiceFeatureList) return (WebServiceFeatureList) features; WebServiceFeatureList w = new WebServiceFeatureList(); if (features != null) w.addAll(features); return w; } private Map<Class<? extends WebServiceFeature>, WebServiceFeature> wsfeatures = new HashMap<Class<? extends WebServiceFeature>, WebServiceFeature>(); private boolean isValidating = false; public WebServiceFeatureList() { }
Delegate to this parent if non-null.
/** * Delegate to this parent if non-null. */
private @Nullable WSDLFeaturedObject parent; public WebServiceFeatureList(@NotNull WebServiceFeature... features) { if (features != null) { for (WebServiceFeature f : features) { addNoValidate(f); } } } public void validate() { if (!isValidating) { isValidating = true; // validation for (WebServiceFeature ff : this) { validate(ff); } } } private void validate(WebServiceFeature feature) { // run validation FeatureListValidatorAnnotation fva = feature.getClass().getAnnotation(FeatureListValidatorAnnotation.class); if (fva != null) { Class<? extends FeatureListValidator> beanClass = fva.bean(); try { FeatureListValidator validator = beanClass.newInstance(); validator.validate(this); } catch (InstantiationException e) { throw new WebServiceException(e); } catch (IllegalAccessException e) { throw new WebServiceException(e); } } } public WebServiceFeatureList(WebServiceFeatureList features) { if (features != null) { wsfeatures.putAll(features.wsfeatures); parent = features.parent; isValidating = features.isValidating; } }
Creates a list by reading featuers from the annotation on a class.
/** * Creates a list by reading featuers from the annotation on a class. */
public WebServiceFeatureList(@NotNull Class<?> endpointClass) { parseAnnotations(endpointClass); }
Adds the corresponding features to the list for feature annotations(i.e which have WebServiceFeatureAnnotation meta annotation)
Params:
  • annIt – collection of annotations(that can have non-feature annotations)
/** * Adds the corresponding features to the list for feature annotations(i.e * which have {@link WebServiceFeatureAnnotation} meta annotation) * * @param annIt collection of annotations(that can have non-feature annotations) */
public void parseAnnotations(Iterable<Annotation> annIt) { for(Annotation ann : annIt) { WebServiceFeature feature = getFeature(ann); if (feature != null) { add(feature); } } }
Returns a corresponding feature for a feature annotation(i.e which has WebServiceFeatureAnnotation meta annotation)
Returns:corresponding feature for the annotation null, if the annotation is nota feature annotation
/** * Returns a corresponding feature for a feature annotation(i.e which has * {@link WebServiceFeatureAnnotation} meta annotation) * * @return corresponding feature for the annotation * null, if the annotation is nota feature annotation */
public static WebServiceFeature getFeature(Annotation a) { WebServiceFeature ftr = null; if (!(a.annotationType().isAnnotationPresent(WebServiceFeatureAnnotation.class))) { ftr = null; } else if (a instanceof Addressing) { Addressing addAnn = (Addressing) a; try { ftr = new AddressingFeature(addAnn.enabled(), addAnn.required(),addAnn.responses()); } catch(NoSuchMethodError e) { //throw error. We can't default to Responses.ALL as we dont know if the user has not used 2.2 annotation with responses. throw new RuntimeModelerException(ModelerMessages.RUNTIME_MODELER_ADDRESSING_RESPONSES_NOSUCHMETHOD(toJar(Which.which(Addressing.class)))); } } else if (a instanceof MTOM) { MTOM mtomAnn = (MTOM) a; ftr = new MTOMFeature(mtomAnn.enabled(), mtomAnn.threshold()); } else if (a instanceof RespectBinding) { RespectBinding rbAnn = (RespectBinding) a; ftr = new RespectBindingFeature(rbAnn.enabled()); } else { ftr = getWebServiceFeatureBean(a); } return ftr; }
Params:
  • endpointClass – web service impl class
/** * * @param endpointClass web service impl class */
public void parseAnnotations(Class<?> endpointClass) { for (Annotation a : endpointClass.getAnnotations()) { WebServiceFeature ftr = getFeature(a); if (ftr != null) { if (ftr instanceof MTOMFeature) { // check conflict with @BindingType BindingID bindingID = BindingID.parse(endpointClass); MTOMFeature bindingMtomSetting = bindingID.createBuiltinFeatureList().get(MTOMFeature.class); if (bindingMtomSetting != null && bindingMtomSetting.isEnabled() ^ ftr.isEnabled()) { throw new RuntimeModelerException( ModelerMessages.RUNTIME_MODELER_MTOM_CONFLICT(bindingID, ftr.isEnabled())); } } add(ftr); } } }
Given the URL String inside jar, returns the URL to the jar itself.
/** * Given the URL String inside jar, returns the URL to the jar itself. */
private static String toJar(String url) { if(!url.startsWith("jar:")) return url; url = url.substring(4); // cut off jar: return url.substring(0,url.lastIndexOf('!')); // cut off everything after '!' } private static WebServiceFeature getWebServiceFeatureBean(Annotation a) { WebServiceFeatureAnnotation wsfa = a.annotationType().getAnnotation(WebServiceFeatureAnnotation.class); Class<? extends WebServiceFeature> beanClass = wsfa.bean(); WebServiceFeature bean; Constructor ftrCtr = null; String[] paramNames = null; for (Constructor con : beanClass.getConstructors()) { FeatureConstructor ftrCtrAnn = (FeatureConstructor) con.getAnnotation(FeatureConstructor.class); if (ftrCtrAnn != null) { if (ftrCtr == null) { ftrCtr = con; paramNames = ftrCtrAnn.value(); } else { throw new WebServiceException( ModelerMessages.RUNTIME_MODELER_WSFEATURE_MORETHANONE_FTRCONSTRUCTOR(a, beanClass)); } } } if (ftrCtr == null) { bean = getWebServiceFeatureBeanViaBuilder(a, beanClass); if (bean != null) { return bean; } else { throw new WebServiceException( ModelerMessages.RUNTIME_MODELER_WSFEATURE_NO_FTRCONSTRUCTOR(a, beanClass)); } } if (ftrCtr.getParameterTypes().length != paramNames.length) { throw new WebServiceException( ModelerMessages.RUNTIME_MODELER_WSFEATURE_ILLEGAL_FTRCONSTRUCTOR(a, beanClass)); } try { Object[] params = new Object[paramNames.length]; for (int i = 0; i < paramNames.length; i++) { Method m = a.annotationType().getDeclaredMethod(paramNames[i]); params[i] = m.invoke(a); } bean = (WebServiceFeature) ftrCtr.newInstance(params); } catch (Exception e) { throw new WebServiceException(e); } return bean; } private static WebServiceFeature getWebServiceFeatureBeanViaBuilder( final Annotation annotation, final Class<? extends WebServiceFeature> beanClass) { try { final Method featureBuilderMethod = beanClass.getDeclaredMethod("builder"); final Object builder = featureBuilderMethod.invoke(beanClass); final Method buildMethod = builder.getClass().getDeclaredMethod("build"); for (Method builderMethod : builder.getClass().getDeclaredMethods()) { if (!builderMethod.equals(buildMethod) && !builderMethod.isSynthetic()) { final String methodName = builderMethod.getName(); final Method annotationMethod = annotation.annotationType().getDeclaredMethod(methodName); final Object annotationFieldValue = annotationMethod.invoke(annotation); final Object[] arg = { annotationFieldValue }; if (skipDuringOrgJvnetWsToComOracleWebservicesPackageMove(builderMethod, annotationFieldValue)) { continue; } builderMethod.invoke(builder, arg); } } final Object result = buildMethod.invoke(builder); if (result instanceof WebServiceFeature) { return (WebServiceFeature) result; } else { throw new WebServiceException("Not a WebServiceFeature: " + result); } } catch (final NoSuchMethodException e) { LOGGER.log(Level.INFO, "Unable to find builder method on webservice feature: " + beanClass.getName(), e); return null; } catch (final IllegalAccessException e) { throw new WebServiceException(e); } catch (final InvocationTargetException e) { throw new WebServiceException(e); } } // TODO this will be removed after package move is complete. private static boolean skipDuringOrgJvnetWsToComOracleWebservicesPackageMove( final Method builderMethod, final Object annotationFieldValue) { final Class<?> annotationFieldValueClass = annotationFieldValue.getClass(); if (! annotationFieldValueClass.isEnum()) { return false; } final Class<?>[] builderMethodParameterTypes = builderMethod.getParameterTypes(); if (builderMethodParameterTypes.length != 1) { throw new WebServiceException("expected only 1 parameter"); } final String builderParameterTypeName = builderMethodParameterTypes[0].getName(); if (! builderParameterTypeName.startsWith("com.oracle.webservices.internal.test.features_annotations_enums.apinew") && ! builderParameterTypeName.startsWith("com.oracle.webservices.internal.api")) { return false; } return false; } public Iterator<WebServiceFeature> iterator() { if (parent != null) return new MergedFeatures(parent.getFeatures()); return wsfeatures.values().iterator(); } public @NotNull WebServiceFeature[] toArray() { if (parent != null) return new MergedFeatures(parent.getFeatures()).toArray(); return wsfeatures.values().toArray(new WebServiceFeature[] {}); } public boolean isEnabled(@NotNull Class<? extends WebServiceFeature> feature) { WebServiceFeature ftr = get(feature); return ftr != null && ftr.isEnabled(); } public boolean contains(@NotNull Class<? extends WebServiceFeature> feature) { WebServiceFeature ftr = get(feature); return ftr != null; } public @Nullable <F extends WebServiceFeature> F get(@NotNull Class<F> featureType) { WebServiceFeature f = featureType.cast(wsfeatures.get(featureType)); if (f == null && parent != null) { return parent.getFeatures().get(featureType); } return (F) f; }
Adds a feature to the list if it's not already added.
/** * Adds a feature to the list if it's not already added. */
public void add(@NotNull WebServiceFeature f) { if(addNoValidate(f) && isValidating) validate(f); } private boolean addNoValidate(@NotNull WebServiceFeature f) { if (!wsfeatures.containsKey(f.getClass())) { wsfeatures.put(f.getClass(), f); if (f instanceof ImpliesWebServiceFeature) ((ImpliesWebServiceFeature) f).implyFeatures(this); return true; } return false; }
Adds features to the list if it's not already added.
/** * Adds features to the list if it's not already added. */
public void addAll(@NotNull Iterable<WebServiceFeature> list) { for (WebServiceFeature f : list) add(f); }
Sets MTOM feature, overriding any existing feature. This is necessary for compatibility with the existing setMTOMEnabled.
Params:
  • b – if MTOM will be enabled
/** * Sets MTOM feature, overriding any existing feature. This is necessary for compatibility * with the existing {@link SOAPBinding.setMTOMEnabled}. * @param b if MTOM will be enabled */
void setMTOMEnabled(boolean b) { wsfeatures.put(MTOMFeature.class, new MTOMFeature(b)); } public boolean equals(Object other) { if (!(other instanceof WebServiceFeatureList)) return false; WebServiceFeatureList w = (WebServiceFeatureList) other; return wsfeatures.equals(w.wsfeatures) && (parent == w.parent); } public String toString() { return wsfeatures.toString(); }
Merges the extra features that are not already set on binding. i.e, if a feature is set already on binding through some other API the corresponding wsdlFeature is not set.
Params:
  • features – Web Service features that need to be merged with already configured features.
  • reportConflicts – If true, checks if the feature setting in WSDL (wsdl extension or policy configuration) conflicts with feature setting in Deployed Service and logs warning if there are any conflicts.
/** * Merges the extra features that are not already set on binding. * i.e, if a feature is set already on binding through some other API * the corresponding wsdlFeature is not set. * * @param features Web Service features that need to be merged with already configured features. * @param reportConflicts If true, checks if the feature setting in WSDL (wsdl extension or * policy configuration) conflicts with feature setting in Deployed Service and * logs warning if there are any conflicts. */
public void mergeFeatures(@NotNull Iterable<WebServiceFeature> features, boolean reportConflicts) { for (WebServiceFeature wsdlFtr : features) { if (get(wsdlFtr.getClass()) == null) { add(wsdlFtr); } else if (reportConflicts) { if (isEnabled(wsdlFtr.getClass()) != wsdlFtr.isEnabled()) { LOGGER.warning(ModelerMessages.RUNTIME_MODELER_FEATURE_CONFLICT( get(wsdlFtr.getClass()), wsdlFtr)); } } } } public void mergeFeatures(WebServiceFeature[] features, boolean reportConflicts) { for (WebServiceFeature wsdlFtr : features) { if (get(wsdlFtr.getClass()) == null) { add(wsdlFtr); } else if (reportConflicts) { if (isEnabled(wsdlFtr.getClass()) != wsdlFtr.isEnabled()) { LOGGER.warning(ModelerMessages.RUNTIME_MODELER_FEATURE_CONFLICT( get(wsdlFtr.getClass()), wsdlFtr)); } } } }
Extracts features from WSDLFeaturedObject.getFeatures(). Extra features that are not already set on binding. i.e, if a feature is set already on binding through some other API the corresponding wsdlFeature is not set.
Params:
  • wsdlPort – WSDLPort model
  • honorWsdlRequired – If this is true add WSDL Feature only if wsd:Required=true In SEI case, it should be false In Provider case, it should be true
  • reportConflicts – If true, checks if the feature setting in WSDL (wsdl extension or policy configuration) conflicts with feature setting in Deployed Service and logs warning if there are any conflicts.
/** * Extracts features from {@link WSDLPort#getFeatures()}. Extra features * that are not already set on binding. i.e, if a feature is set already on * binding through some other API the corresponding wsdlFeature is not set. * * @param wsdlPort * WSDLPort model * @param honorWsdlRequired * If this is true add WSDL Feature only if wsd:Required=true In * SEI case, it should be false In Provider case, it should be * true * @param reportConflicts * If true, checks if the feature setting in WSDL (wsdl extension * or policy configuration) conflicts with feature setting in * Deployed Service and logs warning if there are any conflicts. */
public void mergeFeatures(@NotNull WSDLPort wsdlPort, boolean honorWsdlRequired, boolean reportConflicts) { if (honorWsdlRequired && !isEnabled(RespectBindingFeature.class)) return; if (!honorWsdlRequired) { addAll(wsdlPort.getFeatures()); return; } // Add only if isRequired returns true, when honorWsdlRequired is true for (WebServiceFeature wsdlFtr : wsdlPort.getFeatures()) { if (get(wsdlFtr.getClass()) == null) { try { // if it is a WSDL Extension , it will have required // attribute Method m = (wsdlFtr.getClass().getMethod("isRequired")); try { boolean required = (Boolean) m.invoke(wsdlFtr); if (required) add(wsdlFtr); } catch (IllegalAccessException e) { throw new WebServiceException(e); } catch (InvocationTargetException e) { throw new WebServiceException(e); } } catch (NoSuchMethodException e) { // this wsdlFtr is not an WSDL extension, just add it add(wsdlFtr); } } else if (reportConflicts) { if (isEnabled(wsdlFtr.getClass()) != wsdlFtr.isEnabled()) { LOGGER.warning(ModelerMessages.RUNTIME_MODELER_FEATURE_CONFLICT( get(wsdlFtr.getClass()), wsdlFtr)); } } } }
Set the parent features. Basically the parent feature list will be overriden by this feature list.
/** * Set the parent features. Basically the parent feature list will be * overriden by this feature list. */
public void setParentFeaturedObject(@NotNull WSDLFeaturedObject parent) { this.parent = parent; } public static @Nullable <F extends WebServiceFeature> F getFeature(@NotNull WebServiceFeature[] features, @NotNull Class<F> featureType) { for (WebServiceFeature f : features) { if (f.getClass() == featureType) return (F) f; } return null; }
A Union of this WebServiceFeatureList and the parent.
/** * A Union of this WebServiceFeatureList and the parent. */
private final class MergedFeatures implements Iterator<WebServiceFeature> { private final Stack<WebServiceFeature> features = new Stack<WebServiceFeature>(); public MergedFeatures(@NotNull WSFeatureList parent) { for (WebServiceFeature f : wsfeatures.values()) { features.push(f); } for (WebServiceFeature f : parent) { if (!wsfeatures.containsKey(f.getClass())) { features.push(f); } } } public boolean hasNext() { return !features.empty(); } public WebServiceFeature next() { if (!features.empty()) { return features.pop(); } throw new NoSuchElementException(); } public void remove() { if (!features.empty()) { features.pop(); } } public WebServiceFeature[] toArray() { return features.toArray(new WebServiceFeature[] {}); } } private static final Logger LOGGER = Logger.getLogger(WebServiceFeatureList.class.getName()); @Override public Set<java.util.Map.Entry<Class<? extends WebServiceFeature>, WebServiceFeature>> entrySet() { return wsfeatures.entrySet(); } @Override public WebServiceFeature put(Class<? extends WebServiceFeature> key, WebServiceFeature value) { return wsfeatures.put(key, value); } static public SOAPVersion getSoapVersion(WSFeatureList features) { { EnvelopeStyleFeature env = features.get(EnvelopeStyleFeature.class); if (env != null) { return SOAPVersion.from(env); } } com.oracle.webservices.internal.api.EnvelopeStyleFeature env = features.get(com.oracle.webservices.internal.api.EnvelopeStyleFeature.class); return env != null ? SOAPVersion.from(env) : null; } static public boolean isFeatureEnabled(Class<? extends WebServiceFeature> type, WebServiceFeature[] features) { WebServiceFeature ftr = getFeature(features, type); return ftr != null && ftr.isEnabled(); } static public WebServiceFeature[] toFeatureArray(WSBinding binding) { //TODO scchen convert BindingID to WebServiceFeature[] if(!binding.isFeatureEnabled(EnvelopeStyleFeature.class)) { WebServiceFeature[] f = { binding.getSOAPVersion().toFeature() }; binding.getFeatures().mergeFeatures(f, false); } return binding.getFeatures().toArray(); } }