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.policy.jaxws;
038:
039: import com.sun.xml.txw2.TypedXmlWriter;
040: import com.sun.xml.ws.api.WSBinding;
041: import com.sun.xml.ws.api.model.CheckedException;
042: import com.sun.xml.ws.api.model.JavaMethod;
043: import com.sun.xml.ws.api.model.SEIModel;
044: import com.sun.xml.ws.api.model.wsdl.WSDLBoundFault;
045: import com.sun.xml.ws.api.model.wsdl.WSDLBoundOperation;
046: import com.sun.xml.ws.api.model.wsdl.WSDLBoundPortType;
047: import com.sun.xml.ws.api.model.wsdl.WSDLFault;
048: import com.sun.xml.ws.api.model.wsdl.WSDLInput;
049: import com.sun.xml.ws.api.model.wsdl.WSDLMessage;
050: import com.sun.xml.ws.api.model.wsdl.WSDLOperation;
051: import com.sun.xml.ws.api.model.wsdl.WSDLOutput;
052: import com.sun.xml.ws.api.model.wsdl.WSDLPort;
053: import com.sun.xml.ws.api.model.wsdl.WSDLPortType;
054: import com.sun.xml.ws.api.model.wsdl.WSDLService;
055: import com.sun.xml.ws.api.server.WSEndpoint;
056: import com.sun.xml.ws.api.wsdl.writer.WSDLGeneratorExtension;
057: import com.sun.xml.ws.api.wsdl.writer.WSDLGenExtnContext;
058: import com.sun.xml.ws.policy.Policy;
059: import com.sun.xml.ws.policy.PolicyConstants;
060: import com.sun.xml.ws.policy.PolicyException;
061: import com.sun.xml.ws.policy.PolicyMap;
062: import com.sun.xml.ws.policy.PolicyMapExtender;
063: import com.sun.xml.ws.policy.PolicyMerger;
064: import com.sun.xml.ws.policy.PolicySubject;
065: import com.sun.xml.ws.policy.jaxws.spi.PolicyMapUpdateProvider;
066: import com.sun.xml.ws.policy.jaxws.privateutil.LocalizationMessages;
067: import com.sun.xml.ws.policy.privateutil.PolicyLogger;
068: import com.sun.xml.ws.policy.privateutil.PolicyUtils;
069: import com.sun.xml.ws.policy.sourcemodel.PolicyModelGenerator;
070: import com.sun.xml.ws.policy.sourcemodel.PolicyModelMarshaller;
071: import com.sun.xml.ws.policy.sourcemodel.PolicySourceModel;
072: import java.lang.reflect.InvocationTargetException;
073: import java.lang.reflect.Method;
074: import java.util.Arrays;
075: import java.util.Collection;
076: import java.util.HashSet;
077: import java.util.LinkedList;
078: import java.util.Set;
079: import javax.xml.namespace.QName;
080: import javax.xml.ws.WebServiceException;
081:
082: /**
083: * Marshals the contents of a policy map to WSDL.
084: *
085: * @author Jakub Podlesak (jakub.podlesak at sun.com)
086: */
087: public class PolicyWSDLGeneratorExtension extends
088: WSDLGeneratorExtension {
089:
090: static enum ScopeType {
091: SERVICE, ENDPOINT, OPERATION, INPUT_MESSAGE, OUTPUT_MESSAGE, FAULT_MESSAGE
092: }
093:
094: private final static PolicyLogger LOGGER = PolicyLogger
095: .getLogger(PolicyWSDLGeneratorExtension.class);
096:
097: private PolicyMap policyMap;
098: private SEIModel seiModel;
099: private Class endpointClass;
100: private final Collection<PolicySubject> subjects = new LinkedList<PolicySubject>();
101:
102: private final PolicyModelMarshaller marshaller = PolicyModelMarshaller
103: .getXmlMarshaller(true);
104: private final PolicyMerger merger = PolicyMerger.getMerger();
105:
106: public void start(final WSDLGenExtnContext context) {
107: LOGGER.entering();
108: try {
109: this .seiModel = context.getModel();
110: this .endpointClass = context.getEndpointClass();
111:
112: final PolicyMapUpdateProvider[] policyMapUpdateProviders = PolicyUtils.ServiceProvider
113: .load(PolicyMapUpdateProvider.class);
114: final PolicyMapExtender[] extenders = new PolicyMapExtender[policyMapUpdateProviders.length];
115: for (int i = 0; i < policyMapUpdateProviders.length; i++) {
116: extenders[i] = PolicyMapExtender
117: .createPolicyMapExtender();
118: }
119: final String configId = context.getEndpointClass()
120: .getName();
121: try {
122: policyMap = PolicyConfigParser.parse(configId, context
123: .getContainer(), extenders);
124: } catch (PolicyException e) {
125: LOGGER
126: .fine(
127: LocalizationMessages
128: .WSP_1027_FAILED_TO_READ_WSIT_CONFIG_FOR_ID(configId),
129: e);
130: }
131: if (policyMap == null) {
132: LOGGER
133: .fine(LocalizationMessages
134: .WSP_1034_CREATE_POLICY_MAP_FOR_CONFIG(configId));
135: policyMap = PolicyMap.createPolicyMap(Arrays
136: .asList(extenders));
137: }
138:
139: final TypedXmlWriter root = context.getRoot();
140: root._namespace(PolicyConstants.POLICY_NAMESPACE_URI,
141: PolicyConstants.POLICY_NAMESPACE_PREFIX);
142: root._namespace(PolicyConstants.WSU_NAMESPACE_URI,
143: PolicyConstants.WSU_NAMESPACE_PREFIX);
144: final WSBinding binding = context.getBinding();
145:
146: try {
147: for (int i = 0; i < policyMapUpdateProviders.length; i++) {
148: policyMapUpdateProviders[i].update(extenders[i],
149: policyMap, seiModel, binding);
150: extenders[i].disconnect();
151: }
152: } catch (PolicyException e) {
153: throw LOGGER
154: .logSevereException(new WebServiceException(
155: LocalizationMessages
156: .WSP_1048_MAP_UPDATE_FAILED(),
157: e));
158: }
159: } finally {
160: LOGGER.exiting();
161: }
162: }
163:
164: public void addDefinitionsExtension(final TypedXmlWriter definitions) {
165: try {
166: LOGGER.entering();
167: if (policyMap == null) {
168: LOGGER
169: .fine(LocalizationMessages
170: .WSP_1020_NOT_MARSHALLING_ANY_POLICIES_POLICY_MAP_IS_NULL());
171: } else {
172: subjects.addAll(policyMap.getPolicySubjects());
173: boolean usingPolicy = false;
174: final PolicyModelGenerator generator = PolicyModelGenerator
175: .getGenerator();
176: Set<String> policyIDsOrNamesWritten = null;
177: for (PolicySubject subject : subjects) {
178: if (subject.getSubject() == null) {
179: LOGGER
180: .fine(LocalizationMessages
181: .WSP_1019_NOT_MARSHALLING_WSDL_SUBJ_NULL(subject));
182: } else {
183: if (!usingPolicy) {
184: definitions._element(
185: PolicyConstants.USING_POLICY,
186: TypedXmlWriter.class);
187: usingPolicy = true;
188: policyIDsOrNamesWritten = new HashSet<String>();
189: }
190: final Policy policy;
191: try {
192: policy = subject.getEffectivePolicy(merger);
193: } catch (PolicyException e) {
194: throw LOGGER
195: .logSevereException(new WebServiceException(
196: LocalizationMessages
197: .WSP_1029_FAILED_TO_RETRIEVE_EFFECTIVE_POLICY_FOR_SUBJECT(subject
198: .toString()),
199: e));
200: }
201: if ((null == policy.getIdOrName())
202: || (policyIDsOrNamesWritten
203: .contains(policy.getIdOrName()))) {
204: LOGGER
205: .fine(LocalizationMessages
206: .WSP_1047_POLICY_ID_NULL_OR_DUPLICATE(policy));
207: } else {
208: try {
209: final PolicySourceModel policyInfoset = generator
210: .translate(policy);
211: marshaller.marshal(policyInfoset,
212: definitions);
213: } catch (PolicyException e) {
214: throw LOGGER
215: .logSevereException(new WebServiceException(
216: LocalizationMessages
217: .WSP_1051_FAILED_TO_MARSHALL_POLICY(policy
218: .getIdOrName()),
219: e));
220: }
221: policyIDsOrNamesWritten.add(policy
222: .getIdOrName());
223: }
224: }
225: }
226: }
227: } finally {
228: LOGGER.exiting();
229: }
230: }
231:
232: public void addServiceExtension(final TypedXmlWriter service) {
233: LOGGER.entering();
234: final String serviceName = ((null == seiModel) || (null == endpointClass)) ? null
235: : WSEndpoint.getDefaultServiceName(endpointClass)
236: .getLocalPart();
237: selectAndProcessSubject(service, WSDLService.class,
238: ScopeType.SERVICE, serviceName);
239: LOGGER.exiting();
240: }
241:
242: public void addPortExtension(final TypedXmlWriter port) {
243: LOGGER.entering();
244: final String portName = ((null == seiModel) || (null == endpointClass)) ? null
245: : WSEndpoint.getDefaultPortName(
246: seiModel.getServiceQName(), endpointClass)
247: .getLocalPart();
248: selectAndProcessSubject(port, WSDLPort.class,
249: ScopeType.ENDPOINT, portName);
250: LOGGER.exiting();
251: }
252:
253: public void addPortTypeExtension(final TypedXmlWriter portType) {
254: LOGGER.entering();
255: final String portTypeName = (null == seiModel) ? null
256: : seiModel.getPortTypeName().getLocalPart();
257: selectAndProcessSubject(portType, WSDLPortType.class,
258: ScopeType.ENDPOINT, portTypeName);
259: LOGGER.exiting();
260: }
261:
262: public void addBindingExtension(final TypedXmlWriter binding) {
263: LOGGER.entering();
264: final QName bindingName = (null == seiModel) ? null : seiModel
265: .getBoundPortTypeName();
266: selectAndProcessSubject(binding, WSDLBoundPortType.class,
267: ScopeType.ENDPOINT, bindingName);
268: LOGGER.exiting();
269: }
270:
271: public void addOperationExtension(final TypedXmlWriter operation,
272: final JavaMethod method) {
273: LOGGER.entering();
274: selectAndProcessSubject(operation, WSDLOperation.class,
275: ScopeType.OPERATION, method);
276: LOGGER.exiting();
277: }
278:
279: public void addBindingOperationExtension(
280: final TypedXmlWriter operation, final JavaMethod method) {
281: LOGGER.entering();
282: selectAndProcessSubject(operation, WSDLBoundOperation.class,
283: ScopeType.OPERATION, method);
284: LOGGER.exiting();
285: }
286:
287: public void addInputMessageExtension(final TypedXmlWriter message,
288: final JavaMethod method) {
289: LOGGER.entering();
290: final String messageName = (null == method) ? null : method
291: .getRequestMessageName();
292: selectAndProcessSubject(message, WSDLMessage.class,
293: ScopeType.INPUT_MESSAGE, messageName);
294: LOGGER.exiting();
295: }
296:
297: public void addOutputMessageExtension(final TypedXmlWriter message,
298: final JavaMethod method) {
299: LOGGER.entering();
300: final String messageName = (null == method) ? null : method
301: .getResponseMessageName();
302: selectAndProcessSubject(message, WSDLMessage.class,
303: ScopeType.OUTPUT_MESSAGE, messageName);
304: LOGGER.exiting();
305: }
306:
307: public void addFaultMessageExtension(final TypedXmlWriter message,
308: final JavaMethod method, final CheckedException exception) {
309: LOGGER.entering();
310: final String messageName = (null == exception) ? null
311: : exception.getMessageName();
312: selectAndProcessSubject(message, WSDLMessage.class,
313: ScopeType.FAULT_MESSAGE, messageName);
314: LOGGER.exiting();
315: }
316:
317: public void addOperationInputExtension(final TypedXmlWriter input,
318: final JavaMethod method) {
319: LOGGER.entering();
320: final String messageName = (null == method) ? null : method
321: .getRequestMessageName();
322: selectAndProcessSubject(input, WSDLInput.class,
323: ScopeType.INPUT_MESSAGE, messageName);
324: LOGGER.exiting();
325: }
326:
327: public void addOperationOutputExtension(
328: final TypedXmlWriter output, final JavaMethod method) {
329: LOGGER.entering();
330: final String messageName = (null == method) ? null : method
331: .getResponseMessageName();
332: selectAndProcessSubject(output, WSDLOutput.class,
333: ScopeType.OUTPUT_MESSAGE, messageName);
334: LOGGER.exiting();
335: }
336:
337: public void addOperationFaultExtension(final TypedXmlWriter fault,
338: final JavaMethod method, final CheckedException exception) {
339: LOGGER.entering();
340: final String messageName = (null == exception) ? null
341: : exception.getMessageName();
342: selectAndProcessSubject(fault, WSDLFault.class,
343: ScopeType.FAULT_MESSAGE, messageName);
344: LOGGER.exiting();
345: }
346:
347: public void addBindingOperationInputExtension(
348: final TypedXmlWriter input, final JavaMethod method) {
349: LOGGER.entering();
350: final String messageName = (null == method) ? null : method
351: .getOperationName();
352: selectAndProcessSubject(input, WSDLBoundOperation.class,
353: ScopeType.INPUT_MESSAGE, messageName);
354: LOGGER.exiting();
355: }
356:
357: public void addBindingOperationOutputExtension(
358: final TypedXmlWriter output, final JavaMethod method) {
359: LOGGER.entering();
360: final String messageName = (null == method) ? null : method
361: .getOperationName();
362: selectAndProcessSubject(output, WSDLBoundOperation.class,
363: ScopeType.OUTPUT_MESSAGE, messageName);
364: LOGGER.exiting();
365: }
366:
367: public void addBindingOperationFaultExtension(
368: final TypedXmlWriter writer, final JavaMethod method,
369: final CheckedException exception) {
370: LOGGER.entering(writer, method, exception);
371: if (subjects != null) {
372: for (PolicySubject subject : subjects) { // iterate over all subjects in policy map
373: if (this .policyMap.isFaultMessageSubject(subject)) {
374: final Object concreteSubject = subject.getSubject();
375: if (concreteSubject != null
376: && WSDLBoundFaultContainer.class
377: .isInstance(concreteSubject)) { // is it our class?
378: String exceptionName = exception == null ? null
379: : exception.getMessageName();
380: if (exceptionName == null) { // no name provided to check
381: writePolicyOrReferenceIt(subject, writer);
382: } else {
383: WSDLBoundFaultContainer faultContainer = (WSDLBoundFaultContainer) concreteSubject;
384: WSDLBoundFault fault = faultContainer
385: .getBoundFault();
386: WSDLBoundOperation operation = faultContainer
387: .getBoundOperation();
388: if (exceptionName.equals(fault.getName())
389: && operation
390: .getName()
391: .getLocalPart()
392: .equals(
393: method
394: .getOperationName())) {
395: writePolicyOrReferenceIt(subject,
396: writer);
397: }
398: }
399: }
400: }
401: }
402: }
403: LOGGER.exiting();
404: }
405:
406: /**
407: * This method should only be invoked by interface methods that deal with operations because they
408: * may use JavaMethod as PolicySubject instead of a WSDL object.
409: */
410: private void selectAndProcessSubject(
411: final TypedXmlWriter xmlWriter, final Class clazz,
412: final ScopeType scopeType, final JavaMethod method) {
413: LOGGER.entering(xmlWriter, clazz, scopeType, method);
414: if (method == null) {
415: selectAndProcessSubject(xmlWriter, clazz, scopeType,
416: (String) null);
417: } else {
418: if (subjects != null) {
419: for (PolicySubject subject : subjects) {
420: if (method.equals(subject.getSubject())) {
421: writePolicyOrReferenceIt(subject, xmlWriter);
422: }
423: }
424: }
425: selectAndProcessSubject(xmlWriter, clazz, scopeType, method
426: .getOperationName());
427: }
428: LOGGER.exiting();
429: }
430:
431: /**
432: * This method should only be invoked by interface methods that deal with WSDL binding because they
433: * may use the QName of the WSDL binding element as PolicySubject instead of a WSDL object.
434: */
435: private void selectAndProcessSubject(
436: final TypedXmlWriter xmlWriter, final Class clazz,
437: final ScopeType scopeType, final QName bindingName) {
438: LOGGER.entering(xmlWriter, clazz, scopeType, bindingName);
439: if (bindingName == null) {
440: selectAndProcessSubject(xmlWriter, clazz, scopeType,
441: (String) null);
442: } else {
443: if (subjects != null) {
444: for (PolicySubject subject : subjects) {
445: if (bindingName.equals(subject.getSubject())) {
446: writePolicyOrReferenceIt(subject, xmlWriter);
447: }
448: }
449: }
450: selectAndProcessSubject(xmlWriter, clazz, scopeType,
451: bindingName.getLocalPart());
452: }
453: LOGGER.exiting();
454: }
455:
456: private void selectAndProcessSubject(
457: final TypedXmlWriter xmlWriter, final Class clazz,
458: final ScopeType scopeType, final String wsdlName) {
459: LOGGER.entering();
460: if (subjects != null) {
461: for (PolicySubject subject : subjects) { // iterate over all subjects in policy map
462: if (isCorrectType(policyMap, subject, scopeType)) {
463: final Object concreteSubject = subject.getSubject();
464: if (concreteSubject != null
465: && clazz.isInstance(concreteSubject)) { // is it our class?
466: if (null == wsdlName) { // no name provided to check
467: writePolicyOrReferenceIt(subject, xmlWriter);
468: } else {
469: try {
470: final Method getNameMethod = clazz
471: .getDeclaredMethod("getName");
472: if (stringEqualsToStringOrQName(
473: wsdlName,
474: getNameMethod
475: .invoke(concreteSubject))) {
476: writePolicyOrReferenceIt(subject,
477: xmlWriter);
478: }
479: } catch (NoSuchMethodException e) {
480: throw LOGGER
481: .logSevereException(new WebServiceException(
482: LocalizationMessages
483: .WSP_1011_UNABLE_TO_CHECK_ELEMENT_NAME(
484: clazz
485: .getName(),
486: wsdlName),
487: e));
488: } catch (IllegalAccessException e) {
489: throw LOGGER
490: .logSevereException(new WebServiceException(
491: LocalizationMessages
492: .WSP_1011_UNABLE_TO_CHECK_ELEMENT_NAME(
493: clazz
494: .getName(),
495: wsdlName),
496: e));
497: } catch (InvocationTargetException e) {
498: throw LOGGER
499: .logSevereException(new WebServiceException(
500: LocalizationMessages
501: .WSP_1011_UNABLE_TO_CHECK_ELEMENT_NAME(
502: clazz
503: .getName(),
504: wsdlName),
505: e));
506: }
507: }
508: }
509: }
510: }
511: }
512: LOGGER.exiting();
513: }
514:
515: private static final boolean isCorrectType(final PolicyMap map,
516: final PolicySubject subject, final ScopeType type) {
517: switch (type) {
518: case OPERATION:
519: return !(map.isInputMessageSubject(subject)
520: || map.isOutputMessageSubject(subject) || map
521: .isFaultMessageSubject(subject));
522: case INPUT_MESSAGE:
523: return map.isInputMessageSubject(subject);
524: case OUTPUT_MESSAGE:
525: return map.isOutputMessageSubject(subject);
526: case FAULT_MESSAGE:
527: return map.isFaultMessageSubject(subject);
528: default:
529: return true;
530: }
531: }
532:
533: private boolean stringEqualsToStringOrQName(final String first,
534: final Object second) {
535: return (second instanceof QName) ? first
536: .equals(((QName) second).getLocalPart()) : first
537: .equals(second);
538: }
539:
540: /**
541: * Adds a PolicyReference element that points to the policy of the element,
542: * if the policy does not have any id or name. Writes policy inside the element otherwise.
543: *
544: * @param policy to be referenced or marshalled
545: * @param element A TXW element to which we shall add the PolicyReference
546: */
547: private void writePolicyOrReferenceIt(final PolicySubject subject,
548: final TypedXmlWriter writer) {
549: final Policy policy;
550: try {
551: policy = subject.getEffectivePolicy(merger);
552: } catch (PolicyException e) {
553: throw LOGGER
554: .logSevereException(new WebServiceException(
555: LocalizationMessages
556: .WSP_1029_FAILED_TO_RETRIEVE_EFFECTIVE_POLICY_FOR_SUBJECT(subject
557: .toString()), e));
558: }
559: if (policy != null) {
560: if (null == policy.getIdOrName()) {
561: final PolicyModelGenerator generator = PolicyModelGenerator
562: .getGenerator();
563: try {
564: final PolicySourceModel policyInfoset = generator
565: .translate(policy);
566: marshaller.marshal(policyInfoset, writer);
567: } catch (PolicyException pe) {
568: throw LOGGER
569: .logSevereException(new WebServiceException(
570: LocalizationMessages
571: .WSP_1010_UNABLE_TO_MARSHALL_POLICY_OR_POLICY_REFERENCE(),
572: pe));
573: }
574: } else {
575: final TypedXmlWriter policyReference = writer._element(
576: PolicyConstants.POLICY_REFERENCE,
577: TypedXmlWriter.class);
578: policyReference._attribute(PolicyConstants.POLICY_URI
579: .getLocalPart(), '#' + policy.getIdOrName());
580: }
581: }
582: }
583: }
|