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