001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.tools.validator.internal;
019:
020: import java.lang.reflect.Member;
021: import java.lang.reflect.Method;
022: import java.util.ArrayList;
023: import java.util.Collection;
024: import java.util.Iterator;
025: import java.util.List;
026: import javax.jws.soap.SOAPBinding;
027: import javax.wsdl.Binding;
028: import javax.wsdl.BindingOperation;
029: import javax.wsdl.Definition;
030: import javax.wsdl.Fault;
031: import javax.wsdl.Message;
032: import javax.wsdl.Operation;
033: import javax.wsdl.Part;
034: import javax.wsdl.PortType;
035: import javax.xml.namespace.QName;
036:
037: import org.apache.cxf.common.util.CollectionUtils;
038: import org.apache.cxf.common.util.StringUtils;
039: import org.apache.cxf.helpers.WSDLHelper;
040: import org.apache.cxf.tools.common.ToolException;
041: import org.apache.cxf.tools.common.extensions.soap.SoapBody;
042: import org.apache.cxf.tools.common.extensions.soap.SoapFault;
043: import org.apache.cxf.tools.common.extensions.soap.SoapHeader;
044: import org.apache.cxf.tools.util.SOAPBindingUtil;
045:
046: public class WSIBPValidator extends AbstractDefinitionValidator {
047: private List<String> operationMap = new ArrayList<String>();
048: private WSDLHelper wsdlHelper = new WSDLHelper();
049:
050: public WSIBPValidator(Definition def) {
051: super (def);
052: }
053:
054: public boolean isValid() {
055: for (Method m : getClass().getMethods()) {
056: Boolean res = Boolean.TRUE;
057:
058: if (m.getName().startsWith("check")
059: || m.getModifiers() == Member.PUBLIC) {
060: try {
061: res = (Boolean) m.invoke(this , new Object[] {});
062: } catch (Exception e) {
063: e.printStackTrace();
064: throw new ToolException(e);
065: }
066: if (!res.booleanValue()) {
067: return false;
068: }
069: }
070: }
071: return true;
072:
073: }
074:
075: private boolean checkR2716(final BindingOperation bop) {
076: SoapBody inSoapBody = SOAPBindingUtil
077: .getBindingInputSOAPBody(bop);
078: SoapBody outSoapBody = SOAPBindingUtil
079: .getBindingOutputSOAPBody(bop);
080: if (inSoapBody != null
081: && !StringUtils.isEmpty(inSoapBody.getNamespaceURI())
082: || outSoapBody != null
083: && !StringUtils.isEmpty(outSoapBody.getNamespaceURI())) {
084: addErrorMessage("Violate WSI-BP-1.0 R2716 operation '"
085: + bop.getName()
086: + "' soapBody MUST NOT have namespace attribute");
087: return false;
088: }
089:
090: SoapHeader inSoapHeader = SOAPBindingUtil
091: .getBindingInputSOAPHeader(bop);
092: SoapHeader outSoapHeader = SOAPBindingUtil
093: .getBindingOutputSOAPHeader(bop);
094: if (inSoapHeader != null
095: && !StringUtils.isEmpty(inSoapHeader.getNamespaceURI())
096: || outSoapHeader != null
097: && !StringUtils
098: .isEmpty(outSoapHeader.getNamespaceURI())) {
099: addErrorMessage("Violate WSI-BP-1.0 R2716 operation '"
100: + bop.getName()
101: + "' soapHeader MUST NOT have namespace attribute");
102: return false;
103: }
104:
105: List<SoapFault> soapFaults = SOAPBindingUtil
106: .getBindingOperationSoapFaults(bop);
107: for (SoapFault fault : soapFaults) {
108: if (!StringUtils.isEmpty(fault.getNamespaceURI())) {
109: addErrorMessage("Violate WSI-BP-1.0 R2716 operation '"
110: + bop.getName()
111: + "' soapFault MUST NOT have namespace attribute");
112: return false;
113: }
114: }
115: return true;
116: }
117:
118: private boolean checkR2717AndR2726(final BindingOperation bop) {
119: if (null == bop) {
120: return true;
121: }
122: SoapBody inSoapBody = SOAPBindingUtil
123: .getBindingInputSOAPBody(bop);
124: SoapBody outSoapBody = SOAPBindingUtil
125: .getBindingOutputSOAPBody(bop);
126: if (inSoapBody != null
127: && StringUtils.isEmpty(inSoapBody.getNamespaceURI())
128: || outSoapBody != null
129: && StringUtils.isEmpty(outSoapBody.getNamespaceURI())) {
130: addErrorMessage("Violate WSI-BP-1.0 R2717 soapBody in the input/output of the binding operation '"
131: + bop.getName() + "' MUST have namespace attribute");
132: return false;
133: }
134:
135: SoapHeader inSoapHeader = SOAPBindingUtil
136: .getBindingInputSOAPHeader(bop);
137: SoapHeader outSoapHeader = SOAPBindingUtil
138: .getBindingOutputSOAPHeader(bop);
139: if (inSoapHeader != null
140: && !StringUtils.isEmpty(inSoapHeader.getNamespaceURI())
141: || outSoapHeader != null
142: && !StringUtils
143: .isEmpty(outSoapHeader.getNamespaceURI())) {
144: addErrorMessage("Violate WSI-BP-1.0 R2726 operation '"
145: + bop.getName()
146: + "' soapHeader MUST NOT have namespace attribute");
147: return false;
148: }
149:
150: List<SoapFault> soapFaults = SOAPBindingUtil
151: .getBindingOperationSoapFaults(bop);
152: for (SoapFault fault : soapFaults) {
153: if (!StringUtils.isEmpty(fault.getNamespaceURI())) {
154: addErrorMessage("Violate WSI-BP-1.0 R2726 operation '"
155: + bop.getName()
156: + "' soapFault MUST NOT have namespace attribute");
157: return false;
158: }
159: }
160: return true;
161: }
162:
163: private boolean checkR2201Input(final Operation operation,
164: final BindingOperation bop) {
165: List<Part> partsList = wsdlHelper.getInMessageParts(operation);
166: int inmessagePartsCount = partsList.size();
167: SoapBody soapBody = SOAPBindingUtil
168: .getBindingInputSOAPBody(bop);
169: if (soapBody != null) {
170: List parts = soapBody.getParts();
171: int boundPartSize = parts == null ? inmessagePartsCount
172: : parts.size();
173: SoapHeader soapHeader = SOAPBindingUtil
174: .getBindingInputSOAPHeader(bop);
175: boundPartSize = soapHeader != null
176: && soapHeader.getMessage().equals(
177: operation.getInput().getMessage()
178: .getQName()) ? boundPartSize - 1
179: : boundPartSize;
180:
181: if (parts != null) {
182: Iterator partsIte = parts.iterator();
183: while (partsIte.hasNext()) {
184: String partName = (String) partsIte.next();
185: boolean isDefined = false;
186: for (Part part : partsList) {
187: if (partName.equalsIgnoreCase(part.getName())) {
188: isDefined = true;
189: break;
190: }
191: }
192: if (!isDefined) {
193: addErrorMessage("Violate WSI-BP-1.0 R2201 operation '"
194: + operation.getName()
195: + "' soapBody parts : "
196: + partName
197: + " not found in the message, wrong WSDL");
198: return false;
199: }
200: }
201: } else {
202: if (partsList.size() > 1) {
203: addErrorMessage("Violate WSI-BP-1.0 R2210: operation '"
204: + operation.getName()
205: + "' more than one part bound to body");
206: return false;
207: }
208: }
209:
210: if (boundPartSize > 1) {
211: addErrorMessage("Violate WSI-BP-1.0 R2201 operation '"
212: + operation.getName()
213: + "' more than one part bound to body");
214: return false;
215: }
216: }
217: return true;
218: }
219:
220: private boolean checkR2201Output(final Operation operation,
221: final BindingOperation bop) {
222: int outmessagePartsCount = wsdlHelper.getOutMessageParts(
223: operation).size();
224: SoapBody soapBody = SOAPBindingUtil
225: .getBindingOutputSOAPBody(bop);
226: if (soapBody != null) {
227: List parts = soapBody.getParts();
228: int boundPartSize = parts == null ? outmessagePartsCount
229: : parts.size();
230: SoapHeader soapHeader = SOAPBindingUtil
231: .getBindingOutputSOAPHeader(bop);
232: boundPartSize = soapHeader != null
233: && soapHeader.getMessage().equals(
234: operation.getOutput().getMessage()
235: .getQName()) ? boundPartSize - 1
236: : boundPartSize;
237: if (parts != null) {
238: Iterator partsIte = parts.iterator();
239: while (partsIte.hasNext()) {
240: String partName = (String) partsIte.next();
241: boolean isDefined = false;
242: for (Part part : wsdlHelper
243: .getOutMessageParts(operation)) {
244: if (partName.equalsIgnoreCase(part.getName())) {
245: isDefined = true;
246: break;
247: }
248: }
249: if (!isDefined) {
250: addErrorMessage("Violate WSI-BP-1.0 R2201 operation '"
251: + operation.getName()
252: + "' soapBody parts : "
253: + partName
254: + " not found in the message, wrong WSDL");
255: return false;
256: }
257:
258: }
259: } else {
260: if (wsdlHelper.getOutMessageParts(operation).size() > 1) {
261: addErrorMessage("Violate WSI-BP-1.0 R2210: operation '"
262: + operation.getName()
263: + "' more than one part bound to body");
264: return false;
265: }
266: }
267:
268: if (boundPartSize > 1) {
269: addErrorMessage("Violate WSI-BP-1.0 R2201 operation '"
270: + operation.getName()
271: + "' more than one part bound to body");
272: return false;
273: }
274: }
275: return true;
276: }
277:
278: public boolean checkBinding() {
279: for (PortType portType : wsdlHelper.getPortTypes(def)) {
280: Iterator ite = portType.getOperations().iterator();
281: while (ite.hasNext()) {
282: Operation operation = (Operation) ite.next();
283: if (isOverloading(operation.getName())) {
284: continue;
285: }
286: BindingOperation bop = wsdlHelper.getBindingOperation(
287: def, operation.getName());
288: Binding binding = wsdlHelper.getBinding(bop, def);
289: String bindingStyle = binding != null ? SOAPBindingUtil
290: .getBindingStyle(binding) : "";
291:
292: String style = "".equals(SOAPBindingUtil
293: .getSOAPOperationStyle(bop)) ? bindingStyle
294: : SOAPBindingUtil.getSOAPOperationStyle(bop);
295: if ("DOCUMENT".equalsIgnoreCase(style)) {
296: boolean passed = checkR2201Input(operation, bop)
297: && checkR2201Output(operation, bop)
298: && checkR2716(bop);
299: if (!passed) {
300: return false;
301: }
302: } else {
303: if (!checkR2717AndR2726(bop)) {
304: return false;
305: }
306: }
307: }
308: }
309: return true;
310: }
311:
312: private boolean isHeaderPart(final BindingOperation bop,
313: final Part part) {
314: QName elementName = part.getElementName();
315: if (elementName != null) {
316: String partName = elementName.getLocalPart();
317: SoapHeader inSoapHeader = SOAPBindingUtil
318: .getBindingInputSOAPHeader(bop);
319: if (inSoapHeader != null) {
320: return partName.equals(inSoapHeader.getPart());
321: }
322: SoapHeader outSoapHeader = SOAPBindingUtil
323: .getBindingOutputSOAPHeader(bop);
324: if (outSoapHeader != null) {
325: return partName.equals(outSoapHeader.getPart());
326: }
327: }
328: return false;
329: }
330:
331: public boolean checkR2203And2204() {
332:
333: for (Iterator ite = def.getBindings().values().iterator(); ite
334: .hasNext();) {
335: Binding binding = (Binding) ite.next();
336:
337: String style = SOAPBindingUtil
338: .getCanonicalBindingStyle(binding);
339:
340: //
341:
342: for (Iterator ite2 = binding.getPortType().getOperations()
343: .iterator(); ite2.hasNext();) {
344: Operation operation = (Operation) ite2.next();
345: BindingOperation bop = wsdlHelper.getBindingOperation(
346: def, operation.getName());
347: if (operation.getInput() != null
348: && operation.getInput().getMessage() != null) {
349: Message inMess = operation.getInput().getMessage();
350:
351: for (Iterator ite3 = inMess.getParts().values()
352: .iterator(); ite3.hasNext();) {
353: Part p = (Part) ite3.next();
354: if (style
355: .equalsIgnoreCase(SOAPBinding.Style.RPC
356: .name())
357: && p.getTypeName() == null
358: && !isHeaderPart(bop, p)) {
359: addErrorMessage("An rpc-literal binding in a DESCRIPTION MUST refer, "
360: + "in its soapbind:body element(s), only to "
361: + "wsdl:part element(s) that have been defined "
362: + "using the type attribute.");
363: return false;
364: }
365:
366: if (style
367: .equalsIgnoreCase(SOAPBinding.Style.DOCUMENT
368: .name())
369: && p.getElementName() == null) {
370: addErrorMessage("A document-literal binding in a DESCRIPTION MUST refer, "
371: + "in each of its soapbind:body element(s),"
372: + "only to wsdl:part element(s)"
373: + " that have been defined using the element attribute.");
374: return false;
375: }
376:
377: }
378: }
379: if (operation.getOutput() != null
380: && operation.getOutput().getMessage() != null) {
381: Message outMess = operation.getOutput()
382: .getMessage();
383: for (Iterator ite3 = outMess.getParts().values()
384: .iterator(); ite3.hasNext();) {
385: Part p = (Part) ite3.next();
386: if (style
387: .equalsIgnoreCase(SOAPBinding.Style.RPC
388: .name())
389: && p.getTypeName() == null
390: && !isHeaderPart(bop, p)) {
391: addErrorMessage("An rpc-literal binding in a DESCRIPTION MUST refer, "
392: + "in its soapbind:body element(s), only to "
393: + "wsdl:part element(s) that have been defined "
394: + "using the type attribute.");
395: return false;
396: }
397:
398: if (style
399: .equalsIgnoreCase(SOAPBinding.Style.DOCUMENT
400: .name())
401: && p.getElementName() == null) {
402: addErrorMessage("A document-literal binding in a DESCRIPTION MUST refer, "
403: + "in each of its soapbind:body element(s),"
404: + "only to wsdl:part element(s)"
405: + " that have been defined using the element attribute.");
406: return false;
407: }
408:
409: }
410: }
411: }
412:
413: }
414: return true;
415: }
416:
417: // TODO: Should also check SoapHeader/SoapHeaderFault
418: @SuppressWarnings("unchecked")
419: public boolean checkR2205() {
420: for (Iterator ite = def.getBindings().values().iterator(); ite
421: .hasNext();) {
422: Binding binding = (Binding) ite.next();
423:
424: if (!SOAPBindingUtil.isSOAPBinding(binding)) {
425: System.err.println("WSIBP Validator found <"
426: + binding.getQName()
427: + "> is NOT a SOAP binding");
428: continue;
429: }
430:
431: for (Iterator ite2 = binding.getPortType().getOperations()
432: .iterator(); ite2.hasNext();) {
433: Operation operation = (Operation) ite2.next();
434: Collection<Fault> faults = operation.getFaults()
435: .values();
436: if (CollectionUtils.isEmpty(faults)) {
437: continue;
438: }
439:
440: for (Fault fault : faults) {
441: Message message = fault.getMessage();
442: Collection<Part> parts = message.getParts()
443: .values();
444: for (Part part : parts) {
445: if (part.getElementName() == null) {
446: addErrorMessage("Violate WSI-BP-1.0 R2205: In Message "
447: + message.getQName()
448: + ", part "
449: + part.getName()
450: + " must specify a 'element' attribute");
451: return false;
452: }
453: }
454: }
455: }
456: }
457: return true;
458: }
459:
460: public boolean checkR2705() {
461: Iterator ite = def.getBindings().values().iterator();
462: while (ite.hasNext()) {
463: Object obj = ite.next();
464: Binding binding = (Binding) obj;
465: if (SOAPBindingUtil.isMixedStyle(binding)) {
466: addErrorMessage("Mixed style, invalid WSDL");
467: return false;
468: }
469: }
470: return true;
471: }
472:
473: private boolean isOverloading(String operationName) {
474: if (operationMap.contains(operationName)) {
475: return true;
476: } else {
477: operationMap.add(operationName);
478: }
479: return false;
480: }
481:
482: }
|