Tue, 09 Apr 2013 14:51:13 +0100
8010393: Update JAX-WS RI to 2.2.9-b12941
Reviewed-by: alanb, erikj
Contributed-by: miroslav.kos@oracle.com, martin.grebac@oracle.com
1 /*
2 * Copyright (c) 1997, 2013, 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.binding;
28 import com.sun.istack.internal.NotNull;
29 import com.sun.istack.internal.Nullable;
30 import com.sun.xml.internal.ws.api.BindingID;
31 import com.sun.xml.internal.ws.api.FeatureListValidator;
32 import com.sun.xml.internal.ws.api.FeatureListValidatorAnnotation;
33 import com.sun.xml.internal.ws.api.ImpliesWebServiceFeature;
34 import com.sun.xml.internal.ws.api.SOAPVersion;
35 import com.sun.xml.internal.ws.api.WSBinding;
36 import com.sun.xml.internal.ws.api.WSFeatureList;
37 import com.sun.xml.internal.ws.api.FeatureConstructor;
38 import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
39 import com.sun.xml.internal.ws.api.model.wsdl.WSDLFeaturedObject;
40 import com.sun.xml.internal.ws.model.RuntimeModelerException;
41 import com.sun.xml.internal.ws.model.wsdl.WSDLPortImpl;
42 import com.sun.xml.internal.ws.resources.ModelerMessages;
43 import com.sun.xml.internal.bind.util.Which;
45 import javax.xml.ws.RespectBinding;
46 import javax.xml.ws.RespectBindingFeature;
47 import javax.xml.ws.WebServiceException;
48 import javax.xml.ws.WebServiceFeature;
49 import javax.xml.ws.soap.Addressing;
50 import javax.xml.ws.soap.AddressingFeature;
51 import javax.xml.ws.soap.MTOM;
52 import javax.xml.ws.soap.MTOMFeature;
53 import javax.xml.ws.spi.WebServiceFeatureAnnotation;
55 import com.oracle.webservices.internal.api.EnvelopeStyleFeature;
57 import java.lang.annotation.Annotation;
58 import java.lang.reflect.InvocationTargetException;
59 import java.lang.reflect.Method;
60 import java.lang.reflect.Constructor;
61 import java.util.*;
62 import java.util.logging.Logger;
64 /**
65 * Represents a list of {@link WebServiceFeature}s that has bunch of utility
66 * methods pertaining to web service features.
67 *
68 * @author Rama Pulavarthi
69 */
70 public final class WebServiceFeatureList extends AbstractMap<Class<? extends WebServiceFeature>, WebServiceFeature> implements WSFeatureList {
71 public static WebServiceFeatureList toList(Iterable<WebServiceFeature> features) {
72 if (features instanceof WebServiceFeatureList)
73 return (WebServiceFeatureList) features;
74 WebServiceFeatureList w = new WebServiceFeatureList();
75 if (features != null)
76 w.addAll(features);
77 return w;
78 }
80 private Map<Class<? extends WebServiceFeature>, WebServiceFeature> wsfeatures = new HashMap<Class<? extends WebServiceFeature>, WebServiceFeature>();
81 private boolean isValidating = false;
83 public WebServiceFeatureList() {
84 }
86 /**
87 * Delegate to this parent if non-null.
88 */
89 private @Nullable
90 WSDLFeaturedObject parent;
92 public WebServiceFeatureList(@NotNull WebServiceFeature... features) {
93 if (features != null) {
94 for (WebServiceFeature f : features) {
95 addNoValidate(f);
96 }
97 }
98 }
100 public void validate() {
101 if (!isValidating) {
102 isValidating = true;
104 // validation
105 for (WebServiceFeature ff : this) {
106 validate(ff);
107 }
108 }
109 }
111 private void validate(WebServiceFeature feature) {
112 // run validation
113 FeatureListValidatorAnnotation fva = feature.getClass().getAnnotation(FeatureListValidatorAnnotation.class);
114 if (fva != null) {
115 Class<? extends FeatureListValidator> beanClass = fva.bean();
116 try {
117 FeatureListValidator validator = beanClass.newInstance();
118 validator.validate(this);
119 } catch (InstantiationException e) {
120 throw new WebServiceException(e);
121 } catch (IllegalAccessException e) {
122 throw new WebServiceException(e);
123 }
124 }
125 }
127 public WebServiceFeatureList(WebServiceFeatureList features) {
128 if (features != null) {
129 wsfeatures.putAll(features.wsfeatures);
130 parent = features.parent;
131 isValidating = features.isValidating;
132 }
133 }
135 /**
136 * Creates a list by reading featuers from the annotation on a class.
137 */
138 public WebServiceFeatureList(@NotNull Class<?> endpointClass) {
139 parseAnnotations(endpointClass);
140 }
142 /**
143 * Adds the corresponding features to the list for feature annotations(i.e
144 * which have {@link WebServiceFeatureAnnotation} meta annotation)
145 *
146 * @param annIt collection of annotations(that can have non-feature annotations)
147 */
148 public void parseAnnotations(Iterable<Annotation> annIt) {
149 for(Annotation ann : annIt) {
150 WebServiceFeature feature = getFeature(ann);
151 if (feature != null) {
152 add(feature);
153 }
154 }
155 }
157 /**
158 * Returns a corresponding feature for a feature annotation(i.e which has
159 * {@link WebServiceFeatureAnnotation} meta annotation)
160 *
161 * @return corresponding feature for the annotation
162 * null, if the annotation is nota feature annotation
163 */
164 public static WebServiceFeature getFeature(Annotation a) {
165 WebServiceFeature ftr = null;
166 if (!(a.annotationType().isAnnotationPresent(WebServiceFeatureAnnotation.class))) {
167 ftr = null;
168 } else if (a instanceof Addressing) {
169 Addressing addAnn = (Addressing) a;
170 try {
171 ftr = new AddressingFeature(addAnn.enabled(), addAnn.required(),addAnn.responses());
172 } catch(NoSuchMethodError e) {
173 //throw error. We can't default to Responses.ALL as we dont know if the user has not used 2.2 annotation with responses.
174 throw new RuntimeModelerException(ModelerMessages.RUNTIME_MODELER_ADDRESSING_RESPONSES_NOSUCHMETHOD(toJar(Which.which(Addressing.class))));
175 }
176 } else if (a instanceof MTOM) {
177 MTOM mtomAnn = (MTOM) a;
178 ftr = new MTOMFeature(mtomAnn.enabled(), mtomAnn.threshold());
179 } else if (a instanceof RespectBinding) {
180 RespectBinding rbAnn = (RespectBinding) a;
181 ftr = new RespectBindingFeature(rbAnn.enabled());
182 } else {
183 ftr = getWebServiceFeatureBean(a);
184 }
185 return ftr;
186 }
188 /**
189 *
190 * @param endpointClass web service impl class
191 */
192 public void parseAnnotations(Class<?> endpointClass) {
193 for (Annotation a : endpointClass.getAnnotations()) {
194 WebServiceFeature ftr = getFeature(a);
195 if (ftr != null) {
196 if (ftr instanceof MTOMFeature) {
197 // check conflict with @BindingType
198 BindingID bindingID = BindingID.parse(endpointClass);
199 MTOMFeature bindingMtomSetting = bindingID.createBuiltinFeatureList().get(MTOMFeature.class);
200 if (bindingMtomSetting != null && bindingMtomSetting.isEnabled() ^ ftr.isEnabled()) {
201 throw new RuntimeModelerException(
202 ModelerMessages.RUNTIME_MODELER_MTOM_CONFLICT(bindingID, ftr.isEnabled()));
203 }
204 }
205 add(ftr);
206 }
207 }
208 }
210 /**
211 * Given the URL String inside jar, returns the URL to the jar itself.
212 */
213 private static String toJar(String url) {
214 if(!url.startsWith("jar:"))
215 return url;
216 url = url.substring(4); // cut off jar:
217 return url.substring(0,url.lastIndexOf('!')); // cut off everything after '!'
218 }
220 private static WebServiceFeature getWebServiceFeatureBean(Annotation a) {
221 WebServiceFeatureAnnotation wsfa = a.annotationType().getAnnotation(WebServiceFeatureAnnotation.class);
222 Class<? extends WebServiceFeature> beanClass = wsfa.bean();
223 WebServiceFeature bean;
225 Constructor ftrCtr = null;
226 String[] paramNames = null;
227 for (Constructor con : beanClass.getConstructors()) {
228 FeatureConstructor ftrCtrAnn = (FeatureConstructor) con.getAnnotation(FeatureConstructor.class);
229 if (ftrCtrAnn != null) {
230 if (ftrCtr == null) {
231 ftrCtr = con;
232 paramNames = ftrCtrAnn.value();
233 } else {
234 throw new WebServiceException(
235 ModelerMessages.RUNTIME_MODELER_WSFEATURE_MORETHANONE_FTRCONSTRUCTOR(a, beanClass));
236 }
237 }
238 }
239 if (ftrCtr == null) {
240 bean = getWebServiceFeatureBeanViaBuilder(a, beanClass);
241 if (bean != null) {
242 return bean;
243 } else {
244 throw new WebServiceException(
245 ModelerMessages.RUNTIME_MODELER_WSFEATURE_NO_FTRCONSTRUCTOR(a, beanClass));
246 }
247 }
248 if (ftrCtr.getParameterTypes().length != paramNames.length) {
249 throw new WebServiceException(
250 ModelerMessages.RUNTIME_MODELER_WSFEATURE_ILLEGAL_FTRCONSTRUCTOR(a, beanClass));
251 }
253 try {
254 Object[] params = new Object[paramNames.length];
255 for (int i = 0; i < paramNames.length; i++) {
256 Method m = a.annotationType().getDeclaredMethod(paramNames[i]);
257 params[i] = m.invoke(a);
258 }
259 bean = (WebServiceFeature) ftrCtr.newInstance(params);
260 } catch (Exception e) {
261 throw new WebServiceException(e);
262 }
263 return bean;
264 }
266 private static WebServiceFeature getWebServiceFeatureBeanViaBuilder(
267 final Annotation annotation,
268 final Class<? extends WebServiceFeature> beanClass)
269 {
270 try {
271 final Method featureBuilderMethod = beanClass.getDeclaredMethod("builder");
272 final Object builder = featureBuilderMethod.invoke(beanClass);
273 final Method buildMethod = builder.getClass().getDeclaredMethod("build");
275 for (Method builderMethod : builder.getClass().getDeclaredMethods()) {
276 if (!builderMethod.equals(buildMethod)) {
277 final String methodName = builderMethod.getName();
278 final Method annotationMethod = annotation.annotationType().getDeclaredMethod(methodName);
279 final Object annotationFieldValue = annotationMethod.invoke(annotation);
280 final Object[] arg = { annotationFieldValue };
281 if (skipDuringOrgJvnetWsToComOracleWebservicesPackageMove(builderMethod, annotationFieldValue)) {
282 continue;
283 }
284 builderMethod.invoke(builder, arg);
285 }
286 }
288 final Object result = buildMethod.invoke(builder);
289 if (result instanceof WebServiceFeature) {
290 return (WebServiceFeature) result;
291 } else {
292 throw new WebServiceException("Not a WebServiceFeature: " + result);
293 }
294 } catch (final NoSuchMethodException e) {
295 return null;
296 } catch (final IllegalAccessException e) {
297 throw new WebServiceException(e);
298 } catch (final InvocationTargetException e) {
299 throw new WebServiceException(e);
300 }
301 }
303 // TODO this will be removed after package move is complete.
304 private static boolean skipDuringOrgJvnetWsToComOracleWebservicesPackageMove(
305 final Method builderMethod,
306 final Object annotationFieldValue)
307 {
308 final Class<?> annotationFieldValueClass = annotationFieldValue.getClass();
309 if (! annotationFieldValueClass.isEnum()) {
310 return false;
311 }
312 final Class<?>[] builderMethodParameterTypes = builderMethod.getParameterTypes();
313 if (builderMethodParameterTypes.length != 1) {
314 throw new WebServiceException("expected only 1 parameter");
315 }
316 final String builderParameterTypeName = builderMethodParameterTypes[0].getName();
317 if (! builderParameterTypeName.startsWith("com.oracle.webservices.internal.test.features_annotations_enums.apinew") &&
318 ! builderParameterTypeName.startsWith("com.oracle.webservices.internal.api")) {
319 return false;
320 }
321 return false;
322 }
324 public Iterator<WebServiceFeature> iterator() {
325 if (parent != null)
326 return new MergedFeatures(parent.getFeatures());
327 return wsfeatures.values().iterator();
328 }
330 public @NotNull
331 WebServiceFeature[] toArray() {
332 if (parent != null)
333 return new MergedFeatures(parent.getFeatures()).toArray();
334 return wsfeatures.values().toArray(new WebServiceFeature[] {});
335 }
337 public boolean isEnabled(@NotNull Class<? extends WebServiceFeature> feature) {
338 WebServiceFeature ftr = get(feature);
339 return ftr != null && ftr.isEnabled();
340 }
342 public boolean contains(@NotNull Class<? extends WebServiceFeature> feature) {
343 WebServiceFeature ftr = get(feature);
344 return ftr != null;
345 }
347 public @Nullable
348 <F extends WebServiceFeature> F get(@NotNull Class<F> featureType) {
349 WebServiceFeature f = featureType.cast(wsfeatures.get(featureType));
350 if (f == null && parent != null) {
351 return parent.getFeatures().get(featureType);
352 }
353 return (F) f;
354 }
356 /**
357 * Adds a feature to the list if it's not already added.
358 */
359 public void add(@NotNull WebServiceFeature f) {
360 if(addNoValidate(f) && isValidating)
361 validate(f);
362 }
364 private boolean addNoValidate(@NotNull WebServiceFeature f) {
365 if (!wsfeatures.containsKey(f.getClass())) {
366 wsfeatures.put(f.getClass(), f);
368 if (f instanceof ImpliesWebServiceFeature)
369 ((ImpliesWebServiceFeature) f).implyFeatures(this);
371 return true;
372 }
374 return false;
375 }
377 /**
378 * Adds features to the list if it's not already added.
379 */
380 public void addAll(@NotNull Iterable<WebServiceFeature> list) {
381 for (WebServiceFeature f : list)
382 add(f);
383 }
385 /**
386 * Sets MTOM feature, overriding any existing feature. This is necessary for compatibility
387 * with the existing {@link SOAPBinding.setMTOMEnabled}.
388 * @param b if MTOM will be enabled
389 */
390 void setMTOMEnabled(boolean b) {
391 wsfeatures.put(MTOMFeature.class, new MTOMFeature(b));
392 }
394 public boolean equals(Object other) {
395 if (!(other instanceof WebServiceFeatureList))
396 return false;
398 WebServiceFeatureList w = (WebServiceFeatureList) other;
399 return wsfeatures.equals(w.wsfeatures) && (parent == w.parent);
400 }
402 public String toString() {
403 return wsfeatures.toString();
404 }
406 /**
407 * Merges the extra features that are not already set on binding.
408 * i.e, if a feature is set already on binding through some other API
409 * the corresponding wsdlFeature is not set.
410 *
411 * @param features Web Service features that need to be merged with already configured features.
412 * @param reportConflicts If true, checks if the feature setting in WSDL (wsdl extension or
413 * policy configuration) conflicts with feature setting in Deployed Service and
414 * logs warning if there are any conflicts.
415 */
416 public void mergeFeatures(@NotNull Iterable<WebServiceFeature> features, boolean reportConflicts) {
417 for (WebServiceFeature wsdlFtr : features) {
418 if (get(wsdlFtr.getClass()) == null) {
419 add(wsdlFtr);
420 } else if (reportConflicts) {
421 if (isEnabled(wsdlFtr.getClass()) != wsdlFtr.isEnabled()) {
422 LOGGER.warning(ModelerMessages.RUNTIME_MODELER_FEATURE_CONFLICT(
423 get(wsdlFtr.getClass()), wsdlFtr));
424 }
425 }
426 }
427 }
429 public void mergeFeatures(WebServiceFeature[] features, boolean reportConflicts) {
430 for (WebServiceFeature wsdlFtr : features) {
431 if (get(wsdlFtr.getClass()) == null) {
432 add(wsdlFtr);
433 } else if (reportConflicts) {
434 if (isEnabled(wsdlFtr.getClass()) != wsdlFtr.isEnabled()) {
435 LOGGER.warning(ModelerMessages.RUNTIME_MODELER_FEATURE_CONFLICT(
436 get(wsdlFtr.getClass()), wsdlFtr));
437 }
438 }
439 }
440 }
442 /**
443 * Extracts features from {@link WSDLPortImpl#getFeatures()}. Extra features
444 * that are not already set on binding. i.e, if a feature is set already on
445 * binding through someother API the coresponding wsdlFeature is not set.
446 *
447 * @param wsdlPort
448 * WSDLPort model
449 * @param honorWsdlRequired
450 * If this is true add WSDL Feature only if wsd:Required=true In
451 * SEI case, it should be false In Provider case, it should be
452 * true
453 * @param reportConflicts
454 * If true, checks if the feature setting in WSDL (wsdl extension
455 * or policy configuration) colflicts with feature setting in
456 * Deployed Service and logs warning if there are any conflicts.
457 */
458 public void mergeFeatures(@NotNull WSDLPort wsdlPort,
459 boolean honorWsdlRequired, boolean reportConflicts) {
460 if (honorWsdlRequired && !isEnabled(RespectBindingFeature.class))
461 return;
462 if (!honorWsdlRequired) {
463 addAll(wsdlPort.getFeatures());
464 return;
465 }
466 // Add only if isRequired returns true, when honorWsdlRequired is true
467 for (WebServiceFeature wsdlFtr : wsdlPort.getFeatures()) {
468 if (get(wsdlFtr.getClass()) == null) {
469 try {
470 // if it is a WSDL Extension , it will have required
471 // attribute
472 Method m = (wsdlFtr.getClass().getMethod("isRequired"));
473 try {
474 boolean required = (Boolean) m.invoke(wsdlFtr);
475 if (required)
476 add(wsdlFtr);
477 } catch (IllegalAccessException e) {
478 throw new WebServiceException(e);
479 } catch (InvocationTargetException e) {
480 throw new WebServiceException(e);
481 }
482 } catch (NoSuchMethodException e) {
483 // this wsdlFtr is not an WSDL extension, just add it
484 add(wsdlFtr);
485 }
486 } else if (reportConflicts) {
487 if (isEnabled(wsdlFtr.getClass()) != wsdlFtr.isEnabled()) {
488 LOGGER.warning(ModelerMessages.RUNTIME_MODELER_FEATURE_CONFLICT(
489 get(wsdlFtr.getClass()), wsdlFtr));
490 }
492 }
493 }
494 }
496 /**
497 * Set the parent features. Basically the parent feature list will be
498 * overriden by this feature list.
499 */
500 public void setParentFeaturedObject(@NotNull WSDLFeaturedObject parent) {
501 this.parent = parent;
502 }
504 public static @Nullable <F extends WebServiceFeature> F getFeature(@NotNull WebServiceFeature[] features,
505 @NotNull Class<F> featureType) {
506 for (WebServiceFeature f : features) {
507 if (f.getClass() == featureType)
508 return (F) f;
509 }
510 return null;
511 }
513 /**
514 * A Union of this WebServiceFeatureList and the parent.
515 */
516 private final class MergedFeatures implements Iterator<WebServiceFeature> {
517 private final Stack<WebServiceFeature> features = new Stack<WebServiceFeature>();
519 public MergedFeatures(@NotNull WSFeatureList parent) {
521 for (WebServiceFeature f : wsfeatures.values()) {
522 features.push(f);
523 }
525 for (WebServiceFeature f : parent) {
526 if (!wsfeatures.containsKey(f.getClass())) {
527 features.push(f);
528 }
529 }
530 }
532 public boolean hasNext() {
533 return !features.empty();
534 }
536 public WebServiceFeature next() {
537 if (!features.empty()) {
538 return features.pop();
539 }
540 throw new NoSuchElementException();
541 }
543 public void remove() {
544 if (!features.empty()) {
545 features.pop();
546 }
547 }
549 public WebServiceFeature[] toArray() {
550 return features.toArray(new WebServiceFeature[] {});
551 }
552 }
554 private static final Logger LOGGER = Logger.getLogger(WebServiceFeatureList.class.getName());
556 @Override
557 public Set<java.util.Map.Entry<Class<? extends WebServiceFeature>, WebServiceFeature>> entrySet() {
558 return wsfeatures.entrySet();
559 }
561 @Override
562 public WebServiceFeature put(Class<? extends WebServiceFeature> key, WebServiceFeature value) {
563 return wsfeatures.put(key, value);
564 }
566 static public SOAPVersion getSoapVersion(WSFeatureList features) {
567 {
568 EnvelopeStyleFeature env = features.get(EnvelopeStyleFeature.class);
569 if (env != null) {
570 return SOAPVersion.from(env);
571 }
572 }
573 com.oracle.webservices.internal.api.EnvelopeStyleFeature env = features.get(com.oracle.webservices.internal.api.EnvelopeStyleFeature.class);
574 return env != null ? SOAPVersion.from(env) : null;
575 }
577 static public boolean isFeatureEnabled(Class<? extends WebServiceFeature> type, WebServiceFeature[] features) {
578 WebServiceFeature ftr = getFeature(features, type);
579 return ftr != null && ftr.isEnabled();
580 }
582 static public WebServiceFeature[] toFeatureArray(WSBinding binding) {
583 //TODO scchen convert BindingID to WebServiceFeature[]
584 if(!binding.isFeatureEnabled(EnvelopeStyleFeature.class)) {
585 WebServiceFeature[] f = { binding.getSOAPVersion().toFeature() };
586 binding.getFeatures().mergeFeatures(f, false);
587 }
588 return binding.getFeatures().toArray();
589 }
590 }