001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.xml.ws.binding;
038:
039: import com.sun.istack.NotNull;
040: import com.sun.istack.Nullable;
041: import com.sun.xml.ws.api.BindingID;
042: import com.sun.xml.ws.api.WSFeatureList;
043: import com.sun.xml.ws.api.FeatureConstructor;
044: import com.sun.xml.ws.api.model.wsdl.WSDLPort;
045: import com.sun.xml.ws.api.model.wsdl.WSDLFeaturedObject;
046: import com.sun.xml.ws.model.RuntimeModelerException;
047: import com.sun.xml.ws.model.wsdl.WSDLPortImpl;
048: import com.sun.xml.ws.resources.ModelerMessages;
049:
050: import javax.xml.ws.RespectBinding;
051: import javax.xml.ws.RespectBindingFeature;
052: import javax.xml.ws.WebServiceException;
053: import javax.xml.ws.WebServiceFeature;
054: import javax.xml.ws.soap.Addressing;
055: import javax.xml.ws.soap.AddressingFeature;
056: import javax.xml.ws.soap.MTOM;
057: import javax.xml.ws.soap.MTOMFeature;
058: import javax.xml.ws.spi.WebServiceFeatureAnnotation;
059: import java.lang.annotation.Annotation;
060: import java.lang.reflect.InvocationTargetException;
061: import java.lang.reflect.Method;
062: import java.lang.reflect.Constructor;
063: import java.util.*;
064: import java.util.logging.Logger;
065:
066: /**
067: * Represents a list of {@link WebServiceFeature}s that has bunch of utility methods
068: * pertaining to web service features.
069: *
070: * @author Rama Pulavarthi
071: */
072: public final class WebServiceFeatureList implements WSFeatureList {
073: private Map<Class<? extends WebServiceFeature>, WebServiceFeature> wsfeatures = new HashMap<Class<? extends WebServiceFeature>, WebServiceFeature>();
074:
075: public WebServiceFeatureList() {
076: }
077:
078: /**
079: * Delegate to this parent if non-null.
080: */
081: private @Nullable
082: WSDLFeaturedObject parent;
083:
084: public WebServiceFeatureList(@NotNull
085: WebServiceFeature... features) {
086: if (features != null)
087: for (WebServiceFeature f : features) {
088: wsfeatures.put(f.getClass(), f);
089: }
090: }
091:
092: /**
093: * Creates a list by reading featuers from the annotation on a class.
094: */
095: public WebServiceFeatureList(@NotNull
096: Class<?> endpointClass) {
097: parseAnnotations(endpointClass);
098: }
099:
100: /**
101: * Reads {@link WebServiceFeatureAnnotation feature annotations} on a class
102: * and adds them to the list.
103: */
104: public void parseAnnotations(Class<?> endpointClass) {
105: for (Annotation a : endpointClass.getAnnotations()) {
106: // TODO: this really needs generalization
107: WebServiceFeature ftr;
108: if (!(a.annotationType()
109: .isAnnotationPresent(WebServiceFeatureAnnotation.class))) {
110: continue;
111: } else if (a instanceof Addressing) {
112: Addressing addAnn = (Addressing) a;
113: ftr = new AddressingFeature(addAnn.enabled(), addAnn
114: .required());
115: } else if (a instanceof MTOM) {
116: MTOM mtomAnn = (MTOM) a;
117: ftr = new MTOMFeature(mtomAnn.enabled(), mtomAnn
118: .threshold());
119:
120: // check conflict with @BindingType
121: BindingID bindingID = BindingID.parse(endpointClass);
122: MTOMFeature bindingMtomSetting = bindingID
123: .createBuiltinFeatureList().get(
124: MTOMFeature.class);
125: if (bindingMtomSetting != null
126: && bindingMtomSetting.isEnabled()
127: ^ ftr.isEnabled()) {
128: throw new RuntimeModelerException(ModelerMessages
129: .RUNTIME_MODELER_MTOM_CONFLICT(bindingID,
130: ftr.isEnabled()));
131: }
132:
133: } else if (a instanceof RespectBinding) {
134: RespectBinding rbAnn = (RespectBinding) a;
135: ftr = new RespectBindingFeature(rbAnn.enabled());
136: } else {
137: ftr = getWebServiceFeatureBean(a);
138: }
139: add(ftr);
140: }
141: }
142:
143: private static WebServiceFeature getWebServiceFeatureBean(
144: Annotation a) {
145: WebServiceFeatureAnnotation wsfa = a.annotationType()
146: .getAnnotation(WebServiceFeatureAnnotation.class);
147: Class<? extends WebServiceFeature> beanClass = wsfa.bean();
148: WebServiceFeature bean;
149:
150: Constructor ftrCtr = null;
151: String[] paramNames = null;
152: for (Constructor con : beanClass.getConstructors()) {
153: FeatureConstructor ftrCtrAnn = (FeatureConstructor) con
154: .getAnnotation(FeatureConstructor.class);
155: if (ftrCtrAnn != null) {
156: if (ftrCtr == null) {
157: ftrCtr = con;
158: paramNames = ftrCtrAnn.value();
159: } else {
160: throw new WebServiceException(
161: ModelerMessages
162: .RUNTIME_MODELER_WSFEATURE_MORETHANONE_FTRCONSTRUCTOR(
163: a, beanClass));
164: }
165: }
166: }
167: if (ftrCtr == null) {
168: throw new WebServiceException(ModelerMessages
169: .RUNTIME_MODELER_WSFEATURE_NO_FTRCONSTRUCTOR(a,
170: beanClass));
171: }
172: if (ftrCtr.getParameterTypes().length != paramNames.length) {
173: throw new WebServiceException(ModelerMessages
174: .RUNTIME_MODELER_WSFEATURE_ILLEGAL_FTRCONSTRUCTOR(
175: a, beanClass));
176: }
177:
178: try {
179: Object[] params = new Object[paramNames.length];
180: for (int i = 0; i < paramNames.length; i++) {
181: Method m = a.annotationType().getDeclaredMethod(
182: paramNames[i]);
183: params[i] = m.invoke(a);
184: }
185: bean = (WebServiceFeature) ftrCtr.newInstance(params);
186: } catch (Exception e) {
187: throw new WebServiceException(e);
188: }
189: return bean;
190: }
191:
192: public Iterator<WebServiceFeature> iterator() {
193: if (parent != null)
194: return new MergedFeatures(parent.getFeatures());
195: return wsfeatures.values().iterator();
196: }
197:
198: public @NotNull
199: WebServiceFeature[] toArray() {
200: if (parent != null)
201: return new MergedFeatures(parent.getFeatures()).toArray();
202: return wsfeatures.values().toArray(new WebServiceFeature[] {});
203: }
204:
205: public boolean isEnabled(@NotNull
206: Class<? extends WebServiceFeature> feature) {
207: WebServiceFeature ftr = get(feature);
208: return ftr != null && ftr.isEnabled();
209: }
210:
211: public @Nullable
212: <F extends WebServiceFeature> F get(@NotNull
213: Class<F> featureType) {
214: WebServiceFeature f = featureType.cast(wsfeatures
215: .get(featureType));
216: if (f == null && parent != null) {
217: return parent.getFeatures().get(featureType);
218: }
219: return (F) f;
220: }
221:
222: /**
223: * Adds a feature to the list if it's not already added.
224: */
225: public void add(@NotNull
226: WebServiceFeature f) {
227: if (!wsfeatures.containsKey(f.getClass())) {
228: wsfeatures.put(f.getClass(), f);
229: }
230: }
231:
232: /**
233: * Adds features to the list if it's not already added.
234: */
235: public void addAll(@NotNull
236: WSFeatureList list) {
237: for (WebServiceFeature f : list)
238: add(f);
239: }
240:
241: /**
242: * Extracts features from {@link WSDLPortImpl#getFeatures()}.
243: * Extra features that are not already set on binding.
244: * i.e, if a feature is set already on binding through someother API
245: * the coresponding wsdlFeature is not set.
246: *
247: * @param wsdlPort WSDLPort model
248: * @param honorWsdlRequired If this is true add WSDL Feature only if wsd:Required=true
249: * In SEI case, it should be false
250: * In Provider case, it should be true
251: * @param reportConflicts If true, checks if the feature setting in WSDL (wsdl extension or
252: * policy configuration) colflicts with feature setting in Deployed Service and
253: * logs warning if there are any conflicts.
254: */
255: public void mergeFeatures(@NotNull
256: WSDLPort wsdlPort, boolean honorWsdlRequired,
257: boolean reportConflicts) {
258: if (honorWsdlRequired
259: && !isEnabled(RespectBindingFeature.class))
260: return;
261: if (!honorWsdlRequired) {
262: addAll(wsdlPort.getFeatures());
263: return;
264: }
265: // Add only if isRequired returns true, when honorWsdlRequired is true
266: for (WebServiceFeature wsdlFtr : wsdlPort.getFeatures()) {
267: if (get(wsdlFtr.getClass()) == null) {
268: try {
269: // if it is a WSDL Extension , it will have required attribute
270: Method m = (wsdlFtr.getClass()
271: .getMethod("isRequired"));
272: try {
273: boolean required = (Boolean) m.invoke(wsdlFtr);
274: if (required)
275: add(wsdlFtr);
276: } catch (IllegalAccessException e) {
277: throw new WebServiceException(e);
278: } catch (InvocationTargetException e) {
279: throw new WebServiceException(e);
280: }
281: } catch (NoSuchMethodException e) {
282: // this wsdlFtr is not an WSDL extension, just add it
283: add(wsdlFtr);
284: }
285: } else if (reportConflicts) {
286: if (isEnabled(wsdlFtr.getClass()) != wsdlFtr
287: .isEnabled()) {
288: LOGGER.warning(ModelerMessages
289: .RUNTIME_MODELER_FEATURE_CONFLICT(
290: get(wsdlFtr.getClass()), wsdlFtr));
291: }
292:
293: }
294: }
295: }
296:
297: /**
298: * Set the parent features. Basically the parent feature list will be overriden
299: * by this feature list.
300: */
301: public void setParentFeaturedObject(@NotNull
302: WSDLFeaturedObject parent) {
303: this .parent = parent;
304: }
305:
306: /**
307: * A Union of this WebServiceFeatureList and the parent.
308: */
309: private final class MergedFeatures implements
310: Iterator<WebServiceFeature> {
311: private final Stack<WebServiceFeature> features = new Stack<WebServiceFeature>();
312:
313: public MergedFeatures(@NotNull
314: WSFeatureList parent) {
315:
316: for (WebServiceFeature f : wsfeatures.values()) {
317: features.push(f);
318: }
319:
320: for (WebServiceFeature f : parent) {
321: if (!wsfeatures.containsKey(f.getClass())) {
322: features.push(f);
323: }
324: }
325: }
326:
327: public boolean hasNext() {
328: return !features.empty();
329: }
330:
331: public WebServiceFeature next() {
332: if (!features.empty()) {
333: return features.pop();
334: }
335: throw new NoSuchElementException();
336: }
337:
338: public void remove() {
339: if (!features.empty()) {
340: features.pop();
341: }
342: }
343:
344: public WebServiceFeature[] toArray() {
345: return features.toArray(new WebServiceFeature[] {});
346: }
347: }
348:
349: private static final Logger LOGGER = Logger
350: .getLogger(WebServiceFeatureList.class.getName());
351: }
|