| /******************************************************************************* |
| * Copyright (c) 2010 SAP AG. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Emil Simeonov - initial API and implementation. |
| * Dimitar Donchev - initial API and implementation. |
| * Dimitar Tenev - initial API and implementation. |
| * Nevena Manova - initial API and implementation. |
| * Georgi Konstantinov - initial API and implementation. |
| *******************************************************************************/ |
| package org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability; |
| |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.DOCUMENT_STYLE; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.ELEMENT_ATTRIBUTE_HAS_INVALID_VALUE; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.HAS_AT_MOST_ONE_PART_LISTED_IN_PARTS_ATTRIBUTE; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.INAPPROPRIATE_SOAP_BINDING; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.INAPPROPRIATE_SOAP_BINDING_STYLE; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.INCOMPATIBILITY_BETWEEN_THE_INPUT_OUTPUT_IN_OPERATION_AND_INPUT_OUTPUT_IN_BINDING_OPERATION; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.LITERAL; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.MISSING_NAMESPACE_ATTRIBUTE_IN_SOAP_BODY; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.NAMESPACE_ATTRIBUTE_ISNOT_ALLOWED_IN_SOAPBIND_ELEMENTS_WHEN_DOCUMENT_STYLE_IS_SPECIFIED; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.NAMESPACE_ATTRIBUTE_MUST_NOT_BE_SPECIFIED_IN_SOAP_FAULT_HEADER_FAULT_AND_HEADER; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.OPERATION_DOESNOT_HAVE_SIMILAR_BINDING_OPERATION; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.PARTS_ATTRIBUTE; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.RPC_STYLE; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.THE_OPERATION_HAS_MORE_THAN_ONE_INPUT_PARAMETER; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.THE_OPERATION_HAS_MORE_THAN_ONE_OUTPUT_PARAMETER; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.THE_PART_DOESNOT_HAVE_ELEMENT_ATTRIBUTE_IN_SOME_INPUT_MESSAGE; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.THE_PART_DOESNOT_HAVE_ELEMENT_ATTRIBUTE_IN_SOME_OUTPUT_MESSAGE; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.THE_PART_DOESNOT_HAVE_TYPE_ATTRIBUTE_IN_SOME_INPUT_MESSAGE; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.THE_PART_DOESNOT_HAVE_TYPE_ATTRIBUTE_IN_SOME_OUTPUT_MESSAGE; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIConstants.THE_VALUE_OF_USE_ATTRIBUTE_IN_SOAP_BODY_IS_NOT_LITERAL; |
| import static org.eclipse.wst.sse.sieditor.model.validation.constraints.webservice.interoperability.WSIUtils.getSOAPBinding; |
| |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.emf.validation.IValidationContext; |
| import org.eclipse.emf.validation.model.ConstraintStatus; |
| import org.eclipse.wst.wsdl.Binding; |
| import org.eclipse.wst.wsdl.BindingFault; |
| import org.eclipse.wst.wsdl.BindingInput; |
| import org.eclipse.wst.wsdl.BindingOperation; |
| import org.eclipse.wst.wsdl.BindingOutput; |
| import org.eclipse.wst.wsdl.Definition; |
| import org.eclipse.wst.wsdl.ExtensibilityElement; |
| import org.eclipse.wst.wsdl.ExtensibleElement; |
| import org.eclipse.wst.wsdl.Fault; |
| import org.eclipse.wst.wsdl.Input; |
| import org.eclipse.wst.wsdl.Message; |
| import org.eclipse.wst.wsdl.Operation; |
| import org.eclipse.wst.wsdl.Output; |
| import org.eclipse.wst.wsdl.Part; |
| import org.eclipse.wst.wsdl.PortType; |
| import org.eclipse.wst.wsdl.binding.soap.SOAPBinding; |
| import org.eclipse.wst.wsdl.binding.soap.SOAPBody; |
| import org.eclipse.wst.wsdl.binding.soap.SOAPFault; |
| import org.eclipse.wst.wsdl.binding.soap.SOAPHeader; |
| import org.eclipse.wst.wsdl.binding.soap.SOAPHeaderFault; |
| import org.eclipse.wst.wsdl.util.WSDLConstants; |
| import org.eclipse.xsd.util.XSDConstants; |
| import org.w3c.dom.Element; |
| |
| import org.eclipse.wst.sse.sieditor.model.utils.ElementAttributeUtils; |
| import org.eclipse.wst.sse.sieditor.model.validation.constraints.AbstractConstraint; |
| |
| public class WSIOperationCompliant extends AbstractConstraint { |
| |
| private Operation operation; |
| private List<Part> partsInInputMessage; |
| private List<Part> partsInOutputMessage; |
| private boolean hasPartsAttributeInBindingInputParameters; |
| private boolean hasPartsAttributeInBindingOutputParameters; |
| |
| @SuppressWarnings("unchecked") |
| @Override |
| protected IStatus doValidate(final IValidationContext validationContext) { |
| this.operation = (Operation) validationContext.getTarget(); |
| |
| final Definition definition = this.operation.getEnclosingDefinition(); |
| for (final PortType port : (List<PortType>) definition.getEPortTypes()) { |
| // check whether current operation is in this service(port) |
| if (!port.getEOperations().contains(this.operation)) |
| continue; |
| |
| final List<Binding> soapBindingsForTheCurrentPort = WSIManager.getSoapBindings(port); |
| if (soapBindingsForTheCurrentPort == null) { |
| break; |
| } |
| for (final Binding currentBinding : soapBindingsForTheCurrentPort) { |
| // check whether currentBinding contains target operation |
| boolean isBindingContainOperation = false; |
| for (final BindingOperation currentBindingOperation : (List<BindingOperation>) currentBinding |
| .getEBindingOperations()) { |
| if (currentBindingOperation == null) |
| continue; |
| |
| final Operation currentEOperation = currentBindingOperation.getEOperation(); |
| if (currentEOperation != null && currentEOperation.equals(this.operation)) { |
| isBindingContainOperation = true; |
| break; |
| } |
| } |
| if (!isBindingContainOperation) |
| continue; |
| |
| final SOAPBinding currentSoapBinding = getSOAPBinding(currentBinding); |
| if (currentSoapBinding == null) { |
| return ConstraintStatus.createStatus(validationContext, port, null, INAPPROPRIATE_SOAP_BINDING, |
| INAPPROPRIATE_SOAP_BINDING); |
| } |
| |
| final String theBindingStyle = currentSoapBinding.getStyle(); |
| return getStatusAccordingToSoapBindingStyle(validationContext, port, currentBinding, theBindingStyle); |
| } |
| } |
| |
| return statusThatOperationDoesNotHaveSimilarBindingOperation(validationContext); |
| |
| } |
| |
| @Override |
| protected boolean shouldExecute(final IValidationContext ctx) { |
| // if bindings are not specified or bindings are not SOAP bindings, then |
| // validation over wsdl:operations shouldn't be executed |
| return WSIManager.shouldExecuteContraintsOnOperation(); |
| } |
| |
| /** |
| * R2718 A wsdl:binding in a DESCRIPTION MUST have the same set of |
| * wsdl:operations as the wsdl:portType to which it refers. |
| * |
| * @param validationContext |
| * is the IValidationContext from the doValidate(..) method |
| * |
| * @return status for "this.operation" according to WS-I specification |
| */ |
| private IStatus statusThatOperationDoesNotHaveSimilarBindingOperation(final IValidationContext validationContext) { |
| return ConstraintStatus.createStatus(validationContext, this.operation, null, |
| OPERATION_DOESNOT_HAVE_SIMILAR_BINDING_OPERATION, OPERATION_DOESNOT_HAVE_SIMILAR_BINDING_OPERATION); |
| } |
| |
| /** |
| * |
| * "R2705 A wsdl:binding in a DESCRIPTION MUST either be a rpc-literal |
| * binding or a document-literal binding." |
| * |
| * @param validationContext |
| * is the IValidationContext from the doValidate(..) method |
| * @param port |
| * is the PortType which contain the current "this.operation" |
| * @param currentBinding |
| * is the Binding which contain the current "this.operation" |
| * @param theBindingStyle |
| * is the specified binding style |
| * @return status for "this.operation" according to WS-I specification |
| */ |
| private IStatus getStatusAccordingToSoapBindingStyle(final IValidationContext validationContext, final PortType port, |
| final Binding currentBinding, final String theBindingStyle) { |
| |
| initializeInputAndOutputParts(); |
| |
| if (DOCUMENT_STYLE.equalsIgnoreCase(theBindingStyle)) { |
| return checkInCaseOfDocumentStyleBinding(validationContext, port, currentBinding); |
| } |
| |
| if (RPC_STYLE.equalsIgnoreCase(theBindingStyle)) { |
| return checkInCaseOfRpcStyleBinding(validationContext, port, currentBinding); |
| } |
| |
| if (WSIManager.isShouldBeShownAMessageForInappropriateSOAPBindingStyle(port)) { |
| WSIManager.setShouldBeShownAMessageForInappropriateSOAPBindingStyle(port, false); |
| return ConstraintStatus.createStatus(validationContext, port, null, INAPPROPRIATE_SOAP_BINDING_STYLE, |
| INAPPROPRIATE_SOAP_BINDING_STYLE); |
| } else { |
| return ConstraintStatus.createSuccessStatus(validationContext, port, null); |
| } |
| } |
| |
| @SuppressWarnings("unchecked") |
| private void initializeInputAndOutputParts() { |
| this.hasPartsAttributeInBindingInputParameters = false; |
| this.hasPartsAttributeInBindingOutputParameters = false; |
| |
| final Input input = this.operation.getEInput(); |
| if (input != null) { |
| final Message message = input.getEMessage(); |
| if (message != null) { |
| this.partsInInputMessage = message.getEParts(); |
| } |
| } |
| final Output output = this.operation.getEOutput(); |
| if (output != null) { |
| final Message message = output.getEMessage(); |
| if (message != null) { |
| this.partsInOutputMessage = message.getEParts(); |
| } |
| } |
| } |
| |
| /** |
| * Validate different fine grained rules, when Document-literal SOAP binding |
| * style is specified |
| * |
| * @param validationContext |
| * is the IValidationContext from the doValidate(..) method |
| * @param portType |
| * is the PortType which contain the current "this.operation" |
| * @param currentBinding |
| * is the Binding which contain the current "this.operation" |
| * @return status in case of document-style binding |
| */ |
| @SuppressWarnings("unchecked") |
| private IStatus checkInCaseOfDocumentStyleBinding(final IValidationContext validationContext, final PortType portType, |
| final Binding currentBinding) { |
| for (final BindingOperation bindingOperationForWSIChecking : (List<BindingOperation>) currentBinding |
| .getEBindingOperations()) { |
| if (!this.operation.equals(bindingOperationForWSIChecking.getEOperation())) |
| continue; |
| |
| if (!haveConsistentBetweenInputOutputAndBindingInputOutput(bindingOperationForWSIChecking)) { |
| return ConstraintStatus.createStatus(validationContext, this.operation, null, |
| INCOMPATIBILITY_BETWEEN_THE_INPUT_OUTPUT_IN_OPERATION_AND_INPUT_OUTPUT_IN_BINDING_OPERATION, |
| INCOMPATIBILITY_BETWEEN_THE_INPUT_OUTPUT_IN_OPERATION_AND_INPUT_OUTPUT_IN_BINDING_OPERATION); |
| } |
| |
| if (!hasLiteralValueForAllUseAttributesInBindingOperation(bindingOperationForWSIChecking)) { |
| return ConstraintStatus.createStatus(validationContext, this.operation, null, |
| THE_VALUE_OF_USE_ATTRIBUTE_IN_SOAP_BODY_IS_NOT_LITERAL, |
| THE_VALUE_OF_USE_ATTRIBUTE_IN_SOAP_BODY_IS_NOT_LITERAL); |
| } |
| |
| if (isNamespaceAttributeExistInSoapElementsForSpecifiedBindingOperation(bindingOperationForWSIChecking)) { |
| return ConstraintStatus.createStatus(validationContext, this.operation, null, |
| NAMESPACE_ATTRIBUTE_ISNOT_ALLOWED_IN_SOAPBIND_ELEMENTS_WHEN_DOCUMENT_STYLE_IS_SPECIFIED, |
| NAMESPACE_ATTRIBUTE_ISNOT_ALLOWED_IN_SOAPBIND_ELEMENTS_WHEN_DOCUMENT_STYLE_IS_SPECIFIED); |
| } |
| |
| final Collection<IStatus> statuses = new HashSet<IStatus>(); |
| |
| validateFaults(validationContext, statuses, bindingOperationForWSIChecking); |
| |
| return getStatusForMoreThenOnePartInMessage(validationContext, bindingOperationForWSIChecking, statuses); |
| } |
| // Possible when current this.operation hasn't binding operation |
| return ConstraintStatus.createStatus(validationContext, portType, null, OPERATION_DOESNOT_HAVE_SIMILAR_BINDING_OPERATION, |
| OPERATION_DOESNOT_HAVE_SIMILAR_BINDING_OPERATION); |
| } |
| |
| /** |
| * R2201 A document-literal binding in a DESCRIPTION MUST, in each of its |
| * soapbind:body element(s), have at most one part listed in the parts |
| * attribute, if the parts attribute is specified. |
| * |
| * R2209 A wsdl:binding in a DESCRIPTION SHOULD bind every wsdl:part of a |
| * wsdl:message in the wsdl:portType to which it refers with a binding |
| * extension element. |
| * |
| * @param bindingOperationForWSIChecking |
| * is not null binding operation for check according to WS-I |
| * @return whether has at most one part listed in parts attribute for each |
| * soapbind:body |
| */ |
| @SuppressWarnings("unchecked") |
| private boolean isCorrectIfPartsAttributeIsSpecifiedInSomeSoapBody(final BindingOperation bindingOperationForWSIChecking) { |
| final BindingInput input = (BindingInput) bindingOperationForWSIChecking.getBindingInput(); |
| final BindingOutput output = (BindingOutput) bindingOperationForWSIChecking.getBindingOutput(); |
| final List<BindingFault> faults = bindingOperationForWSIChecking.getEBindingFaults(); |
| |
| final boolean resultFromFaultsCheking = hasAtMostOnePartListedInPartsAttributeInFaults(faults); |
| |
| return (ensureAppropriatePartElements(input) & ensureAppropriatePartElements(output)) && resultFromFaultsCheking; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private boolean ensureAppropriatePartElements(final ExtensibleElement extensibleElement) { |
| if (extensibleElement == null) { |
| return true; |
| } |
| final List<ExtensibilityElement> extensibilityElements = ((extensibleElement).getExtensibilityElements()); |
| |
| if (extensibleElement instanceof BindingInput) { |
| return checkThePartsWhichAreRefferedByBindingOperation(extensibilityElements, this.partsInInputMessage, true); |
| } |
| |
| if (extensibleElement instanceof BindingOutput) { |
| return checkThePartsWhichAreRefferedByBindingOperation(extensibilityElements, this.partsInOutputMessage, false); |
| } |
| |
| return true; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private boolean checkThePartsWhichAreRefferedByBindingOperation(final List<ExtensibilityElement> extensibilityElements, |
| final List<Part> partsInTheMessage, final boolean areElementsFromBindingInput) { |
| |
| if (partsInTheMessage == null || partsInTheMessage.size() == 0) { |
| return true; |
| } |
| |
| boolean isSpecifiedPartsAttribute = false; |
| int numberOfPartsRefferedBySoapHeader = 0; |
| boolean isCorrectTheSizeOfListedParts = true;// change the name |
| |
| for (final ExtensibilityElement element : extensibilityElements) { |
| if (element instanceof SOAPBody) { |
| final SOAPBody soapPart = (SOAPBody) element; |
| if (!soapPart.getElement().hasAttribute(PARTS_ATTRIBUTE)) { |
| continue; |
| } |
| final List<Part> listedParts = soapPart.getParts(); |
| if (listedParts == null || listedParts.size() == 0) { |
| continue; |
| } |
| isSpecifiedPartsAttribute = true; |
| if (areElementsFromBindingInput) { |
| this.hasPartsAttributeInBindingInputParameters = true; |
| } else { |
| this.hasPartsAttributeInBindingOutputParameters = true; |
| } |
| if (listedParts.size() > 1) { |
| isCorrectTheSizeOfListedParts = false; |
| } |
| } else if (element instanceof SOAPHeader) { |
| final SOAPHeader soapPart = (SOAPHeader) element; |
| final Part partInHeader = soapPart.getEPart(); |
| if (partInHeader == null) { |
| continue; |
| } |
| if (partsInTheMessage.contains(partInHeader)) { |
| ++numberOfPartsRefferedBySoapHeader; |
| } |
| } |
| } |
| |
| if (isSpecifiedPartsAttribute && (numberOfPartsRefferedBySoapHeader != (partsInTheMessage.size() - 1))) { |
| return false; |
| } |
| return isCorrectTheSizeOfListedParts; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private boolean hasAtMostOnePartListedInSoapBody(final List extensibilityElements) { |
| for (final ExtensibilityElement element : (List<ExtensibilityElement>) extensibilityElements) { |
| if (!(element instanceof SOAPBody)) { |
| continue; |
| } |
| final SOAPBody soapPart = (SOAPBody) element; |
| final List<Part> listedParts = soapPart.getEParts(); |
| if (listedParts != null && listedParts.size() > 1) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private boolean hasAtMostOnePartListedInPartsAttributeInFaults(final List<BindingFault> faults) { |
| boolean resultFromFaultsCheking = true; |
| if (faults == null || faults.isEmpty()) { |
| return resultFromFaultsCheking; |
| } |
| for (final BindingFault bindingFault : faults) { |
| if (bindingFault == null) { |
| continue; |
| } |
| resultFromFaultsCheking &= hasAtMostOnePartListedInSoapBody(bindingFault.getExtensibilityElements()); |
| } |
| return resultFromFaultsCheking; |
| } |
| |
| /** |
| * R2716 A document-literal binding in a DESCRIPTION MUST NOT have the |
| * namespace attribute specified on contained soapbind:body, |
| * soapbind:header, soapbind:headerfault and soapbind:fault elements. |
| * |
| * @param bindingOperationForWSIChecking |
| * is not null binding operation for check according to WS-I |
| * @return is namespace attribute exist in soap element for a given binding |
| * operation |
| */ |
| @SuppressWarnings("unchecked") |
| private boolean isNamespaceAttributeExistInSoapElementsForSpecifiedBindingOperation(final BindingOperation bindingOperation) { |
| final BindingInput input = (BindingInput) bindingOperation.getBindingInput(); |
| final BindingOutput output = (BindingOutput) bindingOperation.getBindingOutput(); |
| final List<BindingFault> faults = bindingOperation.getEBindingFaults(); |
| return haveNamespaceAttributesForExtensibleElement(input) || haveNamespaceAttributesForExtensibleElement(output) |
| || isNamespaceAttributeExistInSoapFaults(faults); |
| } |
| |
| @SuppressWarnings("unchecked") |
| private <T extends ExtensibleElement> boolean haveNamespaceAttributesForExtensibleElement(final T bindingExtensibleElement) { |
| boolean hasNamespaceAttribute = false; |
| if (bindingExtensibleElement == null) |
| return false; |
| |
| hasNamespaceAttribute = haveNamespaceAttributesInExtensibilityElements((bindingExtensibleElement) |
| .getExtensibilityElements()); |
| |
| return hasNamespaceAttribute; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private boolean isNamespaceAttributeExistInSoapFaults(final List<BindingFault> faults) { |
| if (faults == null || faults.isEmpty()) |
| return false; |
| boolean isNamespaceAttributeExist = false; |
| for (final BindingFault bindingFault : faults) { |
| final List<ExtensibilityElement> extensibilityElements = bindingFault.getExtensibilityElements(); |
| if (extensibilityElements == null) |
| return true; |
| isNamespaceAttributeExist = haveNamespaceAttributesInExtensibilityElements(extensibilityElements); |
| if (isNamespaceAttributeExist == true) |
| break; |
| } |
| return isNamespaceAttributeExist; |
| } |
| |
| private boolean haveNamespaceAttributesInExtensibilityElements(final List<ExtensibilityElement> extensibleElements) { |
| if (extensibleElements == null || extensibleElements.isEmpty()) |
| return false; |
| for (final ExtensibilityElement element : extensibleElements) { |
| if (element instanceof SOAPBody) { |
| final SOAPBody soapPart = (SOAPBody) element; |
| if (soapPart.getNamespaceURI() == null) |
| return false; |
| } else if (element instanceof SOAPFault) { |
| final SOAPFault soapPart = (SOAPFault) element; |
| if (soapPart.getNamespaceURI() == null) |
| return false; |
| } else if (element instanceof SOAPHeader) { |
| final SOAPHeader soapPart = (SOAPHeader) element; |
| if (soapPart.getNamespaceURI() == null) |
| return false; |
| } else if (element instanceof SOAPHeaderFault) { |
| final SOAPHeaderFault soapPart = (SOAPHeaderFault) element; |
| if (soapPart.getNamespaceURI() == null) |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * A document-literal binding in a DESCRIPTION MUST refer only to wsdl:part |
| * element(s) that have been defined using the element attribute. |
| * |
| * R2205 A wsdl:binding in a DESCRIPTION MUST refer, in each of its |
| * soapbind:header, soapbind:headerfault and soapbind:fault elements, only |
| * to wsdl:part element(s) that have been defined using the element |
| * attribute. |
| * |
| * R2210 If a document-literal binding in a DESCRIPTION does not specify the |
| * parts attribute on a soapbind:body element, the corresponding abstract |
| * wsdl:message MUST define zero or one wsdl:parts. |
| * |
| * @param validationContext |
| * @return status according to the rules mentioned above from WS-I |
| * validation |
| */ |
| private IStatus getStatusForMoreThenOnePartInMessage(final IValidationContext validationContext, |
| final BindingOperation bindingOperationForWSIChecking, final Collection<IStatus> statuses) { |
| |
| if (!isCorrectIfPartsAttributeIsSpecifiedInSomeSoapBody(bindingOperationForWSIChecking)) { |
| statuses.add(ConstraintStatus.createStatus(validationContext, this.operation, null, |
| HAS_AT_MOST_ONE_PART_LISTED_IN_PARTS_ATTRIBUTE, HAS_AT_MOST_ONE_PART_LISTED_IN_PARTS_ATTRIBUTE)); |
| } |
| |
| final Input input = (Input) this.operation.getInput(); |
| if (input != null) { |
| checkThePartsForWSICompliantWhenDocumentBindingStyleIsSpecified(validationContext, statuses, |
| !this.hasPartsAttributeInBindingInputParameters, this.partsInInputMessage, |
| THE_OPERATION_HAS_MORE_THAN_ONE_INPUT_PARAMETER, |
| THE_PART_DOESNOT_HAVE_ELEMENT_ATTRIBUTE_IN_SOME_INPUT_MESSAGE); |
| } |
| final Output output = (Output) this.operation.getOutput(); |
| if (output != null) { |
| checkThePartsForWSICompliantWhenDocumentBindingStyleIsSpecified(validationContext, statuses, |
| !this.hasPartsAttributeInBindingOutputParameters, this.partsInOutputMessage, |
| THE_OPERATION_HAS_MORE_THAN_ONE_OUTPUT_PARAMETER, |
| THE_PART_DOESNOT_HAVE_ELEMENT_ATTRIBUTE_IN_SOME_OUTPUT_MESSAGE); |
| } |
| |
| return createStatusFromAGivenListOfStatues(validationContext, statuses); |
| } |
| |
| private void checkThePartsForWSICompliantWhenDocumentBindingStyleIsSpecified(final IValidationContext validationContext, |
| final Collection<IStatus> statuses, final Boolean shouldBeCheckedForMoreThanOneInputParameter, |
| final List<Part> currentParts, final String warningForInappropiateCountOfParts, |
| final String warningForMissingElementAttribute) { |
| |
| if (shouldBeCheckedForMoreThanOneInputParameter && currentParts != null && currentParts.size() > 1) { |
| statuses.add(ConstraintStatus.createStatus(validationContext, this.operation, null, |
| warningForInappropiateCountOfParts, warningForInappropiateCountOfParts)); |
| } |
| checkTheElementAttributes(validationContext, currentParts, warningForMissingElementAttribute, statuses); |
| } |
| |
| private void checkTheElementAttributes(final IValidationContext validationContext, final List<Part> currentParts, |
| final String warningMessage, final Collection<IStatus> statuses) { |
| if (currentParts == null) { |
| return; |
| } |
| for (final Part part : currentParts) { |
| if (!ElementAttributeUtils.hasAttributeValue(part.getElement(), WSDLConstants.ELEMENT_ATTRIBUTE)) { |
| statuses.add(ConstraintStatus.createStatus(validationContext, part, null, warningMessage, warningMessage)); |
| |
| } else if (XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001.equals(part.getElement().getAttributeNS( |
| XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001, WSDLConstants.ELEMENT_ATTRIBUTE))) { |
| statuses.add(ConstraintStatus.createStatus(validationContext, part, null, ELEMENT_ATTRIBUTE_HAS_INVALID_VALUE, |
| ELEMENT_ATTRIBUTE_HAS_INVALID_VALUE)); |
| } |
| } |
| } |
| |
| /** |
| * Validate different fine grained rules, when RPC-literal SOAP binding |
| * style is specified |
| * |
| * @param validationContext |
| * is the IValidationContext from the doValidate(..) method |
| * @param portType |
| * is the PortType which contain the current "this.operation" |
| * @param currentBinding |
| * is the Binding which contain the current "this.operation" |
| * @return status in case of document-style binding |
| */ |
| @SuppressWarnings("unchecked") |
| private IStatus checkInCaseOfRpcStyleBinding(final IValidationContext validationContext, final PortType portType, |
| final Binding currentBinding) { |
| for (final BindingOperation bindingOperationForWSIChecking : (List<BindingOperation>) currentBinding |
| .getEBindingOperations()) { |
| // if current binding operation != from the target operation |
| if (!this.operation.equals(bindingOperationForWSIChecking.getEOperation())) |
| continue; |
| |
| if (!haveConsistentBetweenInputOutputAndBindingInputOutput(bindingOperationForWSIChecking)) { |
| return ConstraintStatus.createStatus(validationContext, this.operation, null, |
| INCOMPATIBILITY_BETWEEN_THE_INPUT_OUTPUT_IN_OPERATION_AND_INPUT_OUTPUT_IN_BINDING_OPERATION, |
| INCOMPATIBILITY_BETWEEN_THE_INPUT_OUTPUT_IN_OPERATION_AND_INPUT_OUTPUT_IN_BINDING_OPERATION); |
| } |
| if (!hasLiteralValueForAllUseAttributesInBindingOperation(bindingOperationForWSIChecking)) { |
| return ConstraintStatus.createStatus(validationContext, this.operation, null, |
| THE_VALUE_OF_USE_ATTRIBUTE_IN_SOAP_BODY_IS_NOT_LITERAL, |
| THE_VALUE_OF_USE_ATTRIBUTE_IN_SOAP_BODY_IS_NOT_LITERAL); |
| } |
| if (!hasNamespaceAttributeInAllSoapBodies(bindingOperationForWSIChecking)) { |
| return ConstraintStatus.createStatus(validationContext, this.operation, null, |
| MISSING_NAMESPACE_ATTRIBUTE_IN_SOAP_BODY, MISSING_NAMESPACE_ATTRIBUTE_IN_SOAP_BODY); |
| } |
| if (!isNamespaceAttributeMissingInNonSoapBodyElement(bindingOperationForWSIChecking)) { |
| return ConstraintStatus.createStatus(validationContext, this.operation, null, |
| NAMESPACE_ATTRIBUTE_MUST_NOT_BE_SPECIFIED_IN_SOAP_FAULT_HEADER_FAULT_AND_HEADER, |
| NAMESPACE_ATTRIBUTE_MUST_NOT_BE_SPECIFIED_IN_SOAP_FAULT_HEADER_FAULT_AND_HEADER); |
| } |
| |
| final Collection<IStatus> statuses = new HashSet<IStatus>(); |
| |
| validateFaults(validationContext, statuses, bindingOperationForWSIChecking); |
| |
| return hasTypeAttributeInAllParts(validationContext, statuses); |
| |
| } |
| // Possible when current operation hasn't binding for operation |
| return ConstraintStatus.createStatus(validationContext, portType, null, OPERATION_DOESNOT_HAVE_SIMILAR_BINDING_OPERATION, |
| OPERATION_DOESNOT_HAVE_SIMILAR_BINDING_OPERATION); |
| } |
| |
| private void validateFaults(final IValidationContext validationContext, final Collection<IStatus> statuses, |
| final BindingOperation bindingOperationForWSIChecking) { |
| final FaultsState faultState = getFaultsState(bindingOperationForWSIChecking); |
| if (faultState != FaultsState.FAULT_STATE_IS_OK) { |
| statuses.add(ConstraintStatus.createStatus(validationContext, operation, null, faultState.getMessage(), faultState |
| .getMessage())); |
| } |
| |
| } |
| |
| /** |
| * R2726 An rpc-literal binding in a DESCRIPTION MUST NOT have the namespace |
| * attribute specified on contained soapbind:header, soapbind:headerfault |
| * and soapbind:fault elements. |
| * |
| * @param bindingOperation |
| * @return whether namespace attribute missing in non soap body element |
| */ |
| @SuppressWarnings("unchecked") |
| private boolean isNamespaceAttributeMissingInNonSoapBodyElement(final BindingOperation bindingOperation) { |
| final BindingInput input = (BindingInput) bindingOperation.getBindingInput(); |
| final BindingOutput output = (BindingOutput) bindingOperation.getBindingOutput(); |
| final List<BindingFault> faults = bindingOperation.getEBindingFaults(); |
| |
| boolean isNamespaceAttributeMissingInFaultsExtensibleElementWhichIsNotSoapBody = true; |
| if (faults != null && !faults.isEmpty()) { |
| for (final BindingFault bindingFault : faults) { |
| if (bindingFault == null) { |
| continue; |
| } |
| isNamespaceAttributeMissingInFaultsExtensibleElementWhichIsNotSoapBody &= isNamespaceAttributeMissingInNonSoapBodyExtensibleElements(bindingFault |
| .getExtensibilityElements()); |
| } |
| } |
| return isNamespaceAttributeMissingInFaultsExtensibleElementWhichIsNotSoapBody |
| && isNamespaceAttributesMissingInNonSoapBodyForExtensibleElement(input) |
| && isNamespaceAttributesMissingInNonSoapBodyForExtensibleElement(output); |
| |
| } |
| |
| @SuppressWarnings("unchecked") |
| private <T extends ExtensibleElement> boolean isNamespaceAttributesMissingInNonSoapBodyForExtensibleElement( |
| final T bindingExtensibleElement) { |
| boolean isNamespaceAttributeMissing = true; |
| if (bindingExtensibleElement == null) { |
| return isNamespaceAttributeMissing; |
| } |
| |
| isNamespaceAttributeMissing = isNamespaceAttributeMissingInNonSoapBodyExtensibleElements((bindingExtensibleElement) |
| .getExtensibilityElements()); |
| |
| return isNamespaceAttributeMissing; |
| } |
| |
| private boolean isNamespaceAttributeMissingInNonSoapBodyExtensibleElements(final List<ExtensibilityElement> extensibleElements) { |
| if (extensibleElements == null || extensibleElements.isEmpty()) { |
| return true; |
| } |
| for (final ExtensibilityElement element : extensibleElements) { |
| if (element instanceof SOAPFault) { |
| final SOAPFault soapPart = (SOAPFault) element; |
| if (soapPart.getNamespaceURI() != null) |
| return false; |
| } else if (element instanceof SOAPHeader) { |
| final SOAPHeader soapPart = (SOAPHeader) element; |
| if (soapPart.getNamespaceURI() != null) |
| return false; |
| } else if (element instanceof SOAPHeaderFault) { |
| final SOAPHeaderFault soapPart = (SOAPHeaderFault) element; |
| if (soapPart.getNamespaceURI() != null) |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * R2717 An rpc-literal binding in a DESCRIPTION MUST have the namespace |
| * attribute specified, the value of which MUST be an absolute URI, on |
| * contained soapbind:body elements. |
| * |
| * @param bindingOperation |
| * is not null binding operation which content must be validated |
| * @return whether have namespace attribute for all soap bodies when RPC |
| * binding style is specified |
| */ |
| private boolean hasNamespaceAttributeInAllSoapBodies(final BindingOperation bindingOperation) { |
| final BindingInput input = (BindingInput) bindingOperation.getBindingInput(); |
| final BindingOutput output = (BindingOutput) bindingOperation.getBindingOutput(); |
| return isNamespaceAttributesAppearForExtensibleElement(input) && isNamespaceAttributesAppearForExtensibleElement(output); |
| } |
| |
| @SuppressWarnings("unchecked") |
| private <T extends ExtensibleElement> boolean isNamespaceAttributesAppearForExtensibleElement(final T bindingExtensibleElement) { |
| boolean isNamespaceAttributeExist = true; |
| if (bindingExtensibleElement == null) { |
| return isNamespaceAttributeExist; |
| } |
| isNamespaceAttributeExist = isNamespaceAttributeAppearCorrectlyInSoapBodyWhenRPCStyleIsSpecified((bindingExtensibleElement) |
| .getExtensibilityElements()); |
| return isNamespaceAttributeExist; |
| } |
| |
| /** |
| * An rpc-literal binding in a DESCRIPTION MUST refer,only to wsdl:part |
| * element(s) that have been defined using the type attribute. |
| * |
| * @param validationContext |
| * is the parameter from the doValidate(..) method |
| * @return status according to referred messages |
| */ |
| private IStatus hasTypeAttributeInAllParts(final IValidationContext validationContext, final Collection<IStatus> statuses) { |
| if (this.operation.getInput() != null) { |
| checkForTypeAttribute(validationContext, this.partsInInputMessage, statuses, |
| THE_PART_DOESNOT_HAVE_TYPE_ATTRIBUTE_IN_SOME_INPUT_MESSAGE); |
| } |
| |
| if (this.operation.getOutput() != null) {// in case of asynchronous |
| // operations |
| checkForTypeAttribute(validationContext, this.partsInOutputMessage, statuses, |
| THE_PART_DOESNOT_HAVE_TYPE_ATTRIBUTE_IN_SOME_OUTPUT_MESSAGE); |
| } |
| |
| return createStatusFromAGivenListOfStatues(validationContext, statuses); |
| } |
| |
| private void checkForTypeAttribute(final IValidationContext validationContext, final List<Part> currentParts, |
| final Collection<IStatus> statuses, final String warringMessage) { |
| if (currentParts == null) { |
| return; |
| } |
| for (final Part part : currentParts) { |
| final Element partElement = part.getElement(); |
| if (ElementAttributeUtils.hasAttributeValue(partElement, WSDLConstants.TYPE_ATTRIBUTE)) { |
| continue; |
| } |
| statuses.add(ConstraintStatus.createStatus(validationContext, part, null, warringMessage, warringMessage)); |
| } |
| } |
| |
| private boolean isNamespaceAttributeAppearCorrectlyInSoapBodyWhenRPCStyleIsSpecified( |
| final List<ExtensibilityElement> extensibleElements) { |
| for (final ExtensibilityElement element : extensibleElements) { |
| if (!(element instanceof SOAPBody)) { |
| continue; |
| } |
| final SOAPBody soapBody = (SOAPBody) element; |
| final String namespaceURI = soapBody.getNamespaceURI(); |
| if (namespaceURI == null) { |
| return false; |
| } |
| try { |
| final URI uri = new URI(namespaceURI); |
| if (!uri.isAbsolute()) { |
| return false; |
| } |
| } catch (final URISyntaxException e) { |
| // in this case the namespace attribute is not valid |
| return false; |
| } |
| } |
| |
| return true; |
| |
| } |
| |
| /** |
| * Incompatibility between the Input/Output in Operation and |
| * BindingInput/BindingOutput in BindingOperation. Check missing of |
| * WSDL:Input or WSDL:Output in WSDL:binding element. |
| * |
| * @param bindingOperationForWSIChecking |
| * the binding operation which must be validated |
| * @return whether have consistent between Input/Output in binding operation |
| * and Input/Output in wsdl:operation |
| */ |
| private boolean haveConsistentBetweenInputOutputAndBindingInputOutput(final BindingOperation bindingOperationForWSIChecking) { |
| final BindingInput input = (BindingInput) bindingOperationForWSIChecking.getBindingInput(); |
| final BindingOutput output = (BindingOutput) bindingOperationForWSIChecking.getBindingOutput(); |
| |
| final Input operationInput = this.operation.getEInput(); |
| if ((operationInput != null && input == null) || (operationInput == null && input != null)) { |
| return false; |
| } |
| |
| final Output operationOutput = this.operation.getEOutput(); |
| if ((operationOutput != null && output == null) || (operationOutput == null && output != null)) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * 2706 A wsdl:binding in a DESCRIPTION MUST use the value of "literal" for |
| * the use attribute in all soapbind:body, soapbind:fault, soapbind:header |
| * and soapbind:headerfault elements. |
| * |
| * R2707 A wsdl:binding in a DESCRIPTION that contains one or more |
| * soapbind:body, soapbind:fault, soapbind:header or soapbind:headerfault |
| * elements that do not specify the use attribute MUST be interpreted as |
| * though the value "literal" had been specified in each case. |
| * |
| * @param bindingOperationForWSIChecking |
| * the binding operation which must be validated |
| * @return whether have literal value for all use attributes |
| */ |
| @SuppressWarnings("unchecked") |
| private boolean hasLiteralValueForAllUseAttributesInBindingOperation(final BindingOperation bindingOperationForWSIChecking) { |
| final BindingInput input = (BindingInput) bindingOperationForWSIChecking.getBindingInput(); |
| final BindingOutput output = (BindingOutput) bindingOperationForWSIChecking.getBindingOutput(); |
| final List<BindingFault> faults = bindingOperationForWSIChecking.getEBindingFaults(); |
| |
| final boolean resultFromFaultsCheking = hasLiteralValueForUseAttributeInSoapFaults(faults); |
| |
| return hasLiteralValueInExtensibilityElements(input) && hasLiteralValueInExtensibilityElements(output) |
| && resultFromFaultsCheking; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private <T extends ExtensibleElement> boolean hasLiteralValueInExtensibilityElements(final T bindingExtensibleElement) { |
| boolean hasLiteralValueForUseAttributeInExtensibilityElements = true; |
| if (bindingExtensibleElement == null) { |
| return hasLiteralValueForUseAttributeInExtensibilityElements; |
| } |
| hasLiteralValueForUseAttributeInExtensibilityElements = hasApproriateValueForUseAttributeInExtesibilityElements((bindingExtensibleElement) |
| .getExtensibilityElements()); |
| return hasLiteralValueForUseAttributeInExtensibilityElements; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private boolean hasLiteralValueForUseAttributeInSoapFaults(final List<BindingFault> faults) { |
| boolean resultFromFaultsCheking = true; |
| if (faults == null || faults.isEmpty()) { |
| return resultFromFaultsCheking; |
| } |
| for (final BindingFault bindingFault : faults) { |
| if (bindingFault == null) |
| continue; |
| resultFromFaultsCheking &= hasApproriateValueForUseAttributeInExtesibilityElements(bindingFault |
| .getExtensibilityElements()); |
| } |
| return resultFromFaultsCheking; |
| } |
| |
| private boolean hasApproriateValueForUseAttributeInExtesibilityElements(final List<ExtensibilityElement> extensions) { |
| for (final ExtensibilityElement element : extensions) { |
| if (element instanceof SOAPBody) { |
| final SOAPBody soapPart = (SOAPBody) element; |
| if ((soapPart.getUse() != null) && !soapPart.getUse().equalsIgnoreCase(LITERAL)) |
| return false; |
| } else if (element instanceof SOAPFault) { |
| final SOAPFault soapPart = (SOAPFault) element; |
| if ((soapPart.getUse() != null) && !soapPart.getUse().equalsIgnoreCase(LITERAL)) |
| return false; |
| } else if (element instanceof SOAPHeader) { |
| final SOAPHeader soapPart = (SOAPHeader) element; |
| if ((soapPart.getUse() != null) && !soapPart.getUse().equalsIgnoreCase(LITERAL)) |
| return false; |
| } else if (element instanceof SOAPHeaderFault) { |
| final SOAPHeaderFault soapPart = (SOAPHeaderFault) element; |
| if ((soapPart.getUse() != null) && !soapPart.getUse().equalsIgnoreCase(LITERAL)) |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * R2754 In a DESCRIPTION, the value of the name attribute on a |
| * soapbind:fault element MUST match the value of the name attribute on its |
| * parent wsdl:fault element. |
| * |
| * R2721 A wsdl:binding in a DESCRIPTION MUST have the name attribute |
| * specified on all contained soapbind:fault elements |
| * |
| * R2740 A wsdl:binding in a DESCRIPTION SHOULD contain a soapbind:fault |
| * describing each known fault. |
| * |
| * R2722 A wsdl:binding in a DESCRIPTION MAY specify the use attribute on |
| * contained soapbind:fault elements. |
| * |
| * R2723 If in a wsdl:binding in a DESCRIPTION the use attribute on a |
| * contained soapbind:fault element is present, its value MUST be "literal". |
| * |
| * R2728 A wsdl:binding in a DESCRIPTION that omits the use attribute on a |
| * contained soapbind:fault element MUST be interpreted as though |
| * use="literal" had been specified.(from WS-I BP 1.0) |
| * |
| * |
| * R2742 An ENVELOPE MAY contain fault with a detail element that is not |
| * described by a soapbind:fault element in the corresponding WSDL |
| * description.(not for WSDL description) |
| * |
| * R2743 An ENVELOPE MAY contain the details of a header processing related |
| * fault in a SOAP header block that is not described by a |
| * soapbind:headerfault element in the corresponding WSDL description.(not |
| * for WSDL description) |
| * |
| * @param bindingOperationForWSIChecking |
| * is not null binding operation for check according to WS-I |
| * @return FaultState according to WS-I |
| */ |
| @SuppressWarnings("unchecked") |
| private FaultsState getFaultsState(final BindingOperation bindingOperationForWSIChecking) { |
| final List<BindingFault> bindingFaultsForCurrentOperation = bindingOperationForWSIChecking.getEBindingFaults(); |
| final List<Fault> wsdlFaultsDescribedForCurrentOperation = this.operation.getEFaults(); |
| final int expectedSoapFaultsCount = bindingFaultsForCurrentOperation.size(); |
| int actualSoapFaultsCount = 0; |
| for (final BindingFault fault : bindingFaultsForCurrentOperation) { |
| if (fault == null) |
| continue; |
| for (final ExtensibilityElement element : (List<ExtensibilityElement>) fault.getEExtensibilityElements()) { |
| if (!(element instanceof SOAPFault)) { |
| continue; |
| } |
| ++actualSoapFaultsCount; |
| final SOAPFault soapFault = (SOAPFault) element; |
| if (soapFault.getName() == null) |
| return FaultsState.MISSING_NAME_ATTRIBUTE_IN_SOME_SOAPFAULT; |
| if (!soapFault.getName().equals(fault.getName())) |
| return FaultsState.SOAPFAULT_NAME_AND_WSDLBINDING_FAULT_NAME_DONOT_MATCH; |
| if (soapFault.getUse() != null && !soapFault.getUse().equals(LITERAL)) |
| return FaultsState.THE_SOAPFAULT_HAS_SPECIFIED_USE_ATTTRIBUTE_WITH_NOT_LITERAL_VALUE; |
| break;// only one soap:fault is needed |
| } |
| |
| } |
| if ((expectedSoapFaultsCount == actualSoapFaultsCount) |
| && bindingFaultsForCurrentOperation.size() >= wsdlFaultsDescribedForCurrentOperation.size()) { |
| return FaultsState.FAULT_STATE_IS_OK; |
| } else { |
| return FaultsState.FOR_EVERY_WSDL_FAULT_MUST_HAVE_CORRESPONDING_SOAP_FAULT_IN_OPERATION_BINDING; |
| } |
| } |
| |
| private IStatus createStatusFromAGivenListOfStatues(final IValidationContext validationContext, |
| final Collection<IStatus> statuses) { |
| if (statuses.isEmpty()) { |
| return ConstraintStatus.createSuccessStatus(validationContext, this.operation, null); |
| } else { |
| return ConstraintStatus.createMultiStatus(validationContext, statuses); |
| } |
| } |
| |
| } |