blob: 9b7e11b9c14acd0a0f9b1e0890f7ce733434beb0 [file] [log] [blame]
/*******************************************************************************
* 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.
* Richard Birenheide - 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.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(IValidationContext validationContext) {
this.operation = (Operation) validationContext.getTarget();
Definition definition = (Definition) this.operation.getEnclosingDefinition();
for (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 (Binding currentBinding : soapBindingsForTheCurrentPort) {
// check whether currentBinding contains target operation
boolean isBindingContainOperation = false;
for (BindingOperation currentBindingOperation : (List<BindingOperation>) currentBinding.getEBindingOperations()) {
if (currentBindingOperation == null)
continue;
Operation currentEOperation = currentBindingOperation.getEOperation();
if (currentEOperation != null && currentEOperation.equals(this.operation)) {
isBindingContainOperation = true;
break;
}
}
if (!isBindingContainOperation)
continue;
SOAPBinding currentSoapBinding = getSOAPBinding(currentBinding);
if (currentSoapBinding == null) {
return ConstraintStatus.createStatus(validationContext, port, null, INAPPROPRIATE_SOAP_BINDING,
INAPPROPRIATE_SOAP_BINDING);
}
String theBindingStyle = currentSoapBinding.getStyle();
return getStatusAccordingToSoapBindingStyle(validationContext, port, currentBinding, theBindingStyle);
}
}
return statusThatOperationDoesNotHaveSimilarBindingOperation(validationContext);
}
@Override
protected boolean shouldExecute(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(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(IValidationContext validationContext, PortType port,
Binding currentBinding, 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;
Input input = (Input) this.operation.getEInput();
if (input != null) {
Message message = input.getEMessage();
if (message != null) {
this.partsInInputMessage = message.getEParts();
}
}
Output output = (Output) this.operation.getEOutput();
if (output != null) {
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(IValidationContext validationContext, PortType portType,
Binding currentBinding) {
for (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);
}
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(BindingOperation bindingOperationForWSIChecking) {
BindingInput input = (BindingInput) bindingOperationForWSIChecking.getBindingInput();
BindingOutput output = (BindingOutput) bindingOperationForWSIChecking.getBindingOutput();
List<BindingFault> faults = (List<BindingFault>) bindingOperationForWSIChecking.getEBindingFaults();
boolean resultFromFaultsCheking = hasAtMostOnePartListedInPartsAttributeInFaults(faults);
return (ensureAppropriatePartElements(input) & ensureAppropriatePartElements(output)) && resultFromFaultsCheking;
}
@SuppressWarnings("unchecked")
private boolean ensureAppropriatePartElements(ExtensibleElement extensibleElement) {
if (extensibleElement == null) {
return true;
}
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(List<ExtensibilityElement> extensibilityElements,
List<Part> partsInTheMessage, boolean areElementsFromBindingInput) {
if (partsInTheMessage == null || partsInTheMessage.size() == 0) {
return true;
}
boolean isSpecifiedPartsAttribute = false;
int numberOfPartsRefferedBySoapHeader = 0;
boolean isCorrectTheSizeOfListedParts = true;// change the name
for (ExtensibilityElement element : extensibilityElements) {
if (element instanceof SOAPBody) {
SOAPBody soapPart = (SOAPBody) element;
if (!soapPart.getElement().hasAttribute(PARTS_ATTRIBUTE)) {
continue;
}
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) {
SOAPHeader soapPart = (SOAPHeader) element;
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(List extensibilityElements) {
for (ExtensibilityElement element : (List<ExtensibilityElement>) extensibilityElements) {
if (!(element instanceof SOAPBody)) {
continue;
}
SOAPBody soapPart = (SOAPBody) element;
List<Part> listedParts = soapPart.getEParts();
if (listedParts != null && listedParts.size() > 1) {
return false;
}
}
return true;
}
@SuppressWarnings("unchecked")
private boolean hasAtMostOnePartListedInPartsAttributeInFaults(List<BindingFault> faults) {
boolean resultFromFaultsCheking = true;
if (faults == null || faults.isEmpty()) {
return resultFromFaultsCheking;
}
for (BindingFault bindingFault : faults) {
if (bindingFault == null) {
continue;
}
resultFromFaultsCheking &= hasAtMostOnePartListedInSoapBody((List<ExtensibilityElement>) 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(BindingOperation bindingOperation) {
BindingInput input = (BindingInput) bindingOperation.getBindingInput();
BindingOutput output = (BindingOutput) bindingOperation.getBindingOutput();
List<BindingFault> faults = (List<BindingFault>) bindingOperation.getEBindingFaults();
return haveNamespaceAttributesForExtensibleElement(input) || haveNamespaceAttributesForExtensibleElement(output)
|| isNamespaceAttributeExistInSoapFaults(faults);
}
@SuppressWarnings("unchecked")
private <T extends ExtensibleElement> boolean haveNamespaceAttributesForExtensibleElement(T bindingExtensibleElement) {
boolean hasNamespaceAttribute = false;
if (bindingExtensibleElement == null)
return false;
hasNamespaceAttribute = haveNamespaceAttributesInExtensibilityElements((bindingExtensibleElement)
.getExtensibilityElements());
return hasNamespaceAttribute;
}
@SuppressWarnings("unchecked")
private boolean isNamespaceAttributeExistInSoapFaults(List<BindingFault> faults) {
if (faults == null || faults.isEmpty())
return false;
boolean isNamespaceAttributeExist = false;
for (BindingFault bindingFault : faults) {
List<ExtensibilityElement> extensibilityElements = (List<ExtensibilityElement>) bindingFault
.getExtensibilityElements();
if (extensibilityElements == null)
return true;
isNamespaceAttributeExist = haveNamespaceAttributesInExtensibilityElements(extensibilityElements);
if (isNamespaceAttributeExist == true)
break;
}
return isNamespaceAttributeExist;
}
private boolean haveNamespaceAttributesInExtensibilityElements(List<ExtensibilityElement> extensibleElements) {
if (extensibleElements == null || extensibleElements.isEmpty())
return false;
for (ExtensibilityElement element : extensibleElements) {
if (element instanceof SOAPBody) {
SOAPBody soapPart = (SOAPBody) element;
if (soapPart.getNamespaceURI() == null)
return false;
} else if (element instanceof SOAPFault) {
SOAPFault soapPart = (SOAPFault) element;
if (soapPart.getNamespaceURI() == null)
return false;
} else if (element instanceof SOAPHeader) {
SOAPHeader soapPart = (SOAPHeader) element;
if (soapPart.getNamespaceURI() == null)
return false;
} else if (element instanceof SOAPHeaderFault) {
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(IValidationContext validationContext,
BindingOperation bindingOperationForWSIChecking, 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));
}
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);
}
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(IValidationContext validationContext,
Collection<IStatus> statuses, Boolean shouldBeCheckedForMoreThanOneInputParameter, List<Part> currentParts,
String warningForInappropiateCountOfParts, 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(IValidationContext validationContext, List<Part> currentParts, String warningMessage,
Collection<IStatus> statuses) {
if (currentParts == null) {
return;
}
for (Part part : currentParts) {
String valueOfElementAttribute = part.getElement().getAttribute(WSDLConstants.ELEMENT_ATTRIBUTE);
if ((valueOfElementAttribute == null)) {
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(IValidationContext validationContext, PortType portType, Binding currentBinding) {
for (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);
}
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(IValidationContext validationContext, Collection<IStatus> statuses,
BindingOperation bindingOperationForWSIChecking) {
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(BindingOperation bindingOperation) {
BindingInput input = (BindingInput) bindingOperation.getBindingInput();
BindingOutput output = (BindingOutput) bindingOperation.getBindingOutput();
List<BindingFault> faults = (List<BindingFault>) bindingOperation.getEBindingFaults();
boolean isNamespaceAttributeMissingInFaultsExtensibleElementWhichIsNotSoapBody = true;
if (faults != null && !faults.isEmpty()) {
for (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(
T bindingExtensibleElement) {
boolean isNamespaceAttributeMissing = true;
if (bindingExtensibleElement == null) {
return isNamespaceAttributeMissing;
}
isNamespaceAttributeMissing = isNamespaceAttributeMissingInNonSoapBodyExtensibleElements((bindingExtensibleElement)
.getExtensibilityElements());
return isNamespaceAttributeMissing;
}
private boolean isNamespaceAttributeMissingInNonSoapBodyExtensibleElements(List<ExtensibilityElement> extensibleElements) {
if (extensibleElements == null || extensibleElements.isEmpty()) {
return true;
}
for (ExtensibilityElement element : extensibleElements) {
if (element instanceof SOAPFault) {
SOAPFault soapPart = (SOAPFault) element;
if (soapPart.getNamespaceURI() != null)
return false;
} else if (element instanceof SOAPHeader) {
SOAPHeader soapPart = (SOAPHeader) element;
if (soapPart.getNamespaceURI() != null)
return false;
} else if (element instanceof SOAPHeaderFault) {
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(BindingOperation bindingOperation) {
BindingInput input = (BindingInput) bindingOperation.getBindingInput();
BindingOutput output = (BindingOutput) bindingOperation.getBindingOutput();
return isNamespaceAttributesAppearForExtensibleElement(input) && isNamespaceAttributesAppearForExtensibleElement(output);
}
@SuppressWarnings("unchecked")
private <T extends ExtensibleElement> boolean isNamespaceAttributesAppearForExtensibleElement(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(IValidationContext validationContext,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(IValidationContext validationContext, List<Part> currentParts,
Collection<IStatus> statuses, String warringMessage) {
if (currentParts == null) {
return;
}
for (Part part : currentParts) {
Element partElement = part.getElement();
if (partElement.getAttribute(WSDLConstants.TYPE_ATTRIBUTE) != null) {
continue;
}
statuses.add(ConstraintStatus.createStatus(validationContext, part, null, warringMessage, warringMessage));
}
}
private boolean isNamespaceAttributeAppearCorrectlyInSoapBodyWhenRPCStyleIsSpecified(
List<ExtensibilityElement> extensibleElements) {
for (ExtensibilityElement element : extensibleElements) {
if (!(element instanceof SOAPBody)) {
continue;
}
SOAPBody soapBody = (SOAPBody) element;
String namespaceURI = soapBody.getNamespaceURI();
if (namespaceURI == null) {
return false;
}
try {
URI uri = new URI(namespaceURI);
if (!uri.isAbsolute()) {
return false;
}
} catch (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(BindingOperation bindingOperationForWSIChecking) {
BindingInput input = (BindingInput) bindingOperationForWSIChecking.getBindingInput();
BindingOutput output = (BindingOutput) bindingOperationForWSIChecking.getBindingOutput();
Input operationInput = this.operation.getEInput();
if ((operationInput != null && input == null) || (operationInput == null && input != null)) {
return false;
}
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(BindingOperation bindingOperationForWSIChecking) {
BindingInput input = (BindingInput) bindingOperationForWSIChecking.getBindingInput();
BindingOutput output = (BindingOutput) bindingOperationForWSIChecking.getBindingOutput();
List<BindingFault> faults = (List<BindingFault>) bindingOperationForWSIChecking.getEBindingFaults();
boolean resultFromFaultsCheking = hasLiteralValueForUseAttributeInSoapFaults(faults);
return hasLiteralValueInExtensibilityElements(input) && hasLiteralValueInExtensibilityElements(output)
&& resultFromFaultsCheking;
}
@SuppressWarnings("unchecked")
private <T extends ExtensibleElement> boolean hasLiteralValueInExtensibilityElements(T bindingExtensibleElement) {
boolean hasLiteralValueForUseAttributeInExtensibilityElements = true;
if (bindingExtensibleElement == null) {
return hasLiteralValueForUseAttributeInExtensibilityElements;
}
hasLiteralValueForUseAttributeInExtensibilityElements = hasApproriateValueForUseAttributeInExtesibilityElements((bindingExtensibleElement)
.getExtensibilityElements());
return hasLiteralValueForUseAttributeInExtensibilityElements;
}
@SuppressWarnings("unchecked")
private boolean hasLiteralValueForUseAttributeInSoapFaults(List<BindingFault> faults) {
boolean resultFromFaultsCheking = true;
if (faults == null || faults.isEmpty()) {
return resultFromFaultsCheking;
}
for (BindingFault bindingFault : faults) {
if (bindingFault == null)
continue;
resultFromFaultsCheking &= hasApproriateValueForUseAttributeInExtesibilityElements((List<ExtensibilityElement>) bindingFault
.getExtensibilityElements());
}
return resultFromFaultsCheking;
}
private boolean hasApproriateValueForUseAttributeInExtesibilityElements(List<ExtensibilityElement> extensions) {
for (ExtensibilityElement element : extensions) {
if (element instanceof SOAPBody) {
SOAPBody soapPart = (SOAPBody) element;
if ((soapPart.getUse() != null) && !soapPart.getUse().equalsIgnoreCase(LITERAL))
return false;
} else if (element instanceof SOAPFault) {
SOAPFault soapPart = (SOAPFault) element;
if ((soapPart.getUse() != null) && !soapPart.getUse().equalsIgnoreCase(LITERAL))
return false;
} else if (element instanceof SOAPHeader) {
SOAPHeader soapPart = (SOAPHeader) element;
if ((soapPart.getUse() != null) && !soapPart.getUse().equalsIgnoreCase(LITERAL))
return false;
} else if (element instanceof SOAPHeaderFault) {
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(BindingOperation bindingOperationForWSIChecking) {
List<BindingFault> bindingFaultsForCurrentOperation = (List<BindingFault>) bindingOperationForWSIChecking
.getEBindingFaults();
List<Fault> wsdlFaultsDescribedForCurrentOperation = (List<Fault>) this.operation.getEFaults();
int expectedSoapFaultsCount = bindingFaultsForCurrentOperation.size();
int actualSoapFaultsCount = 0;
for (BindingFault fault : bindingFaultsForCurrentOperation) {
if (fault == null)
continue;
for (ExtensibilityElement element : (List<ExtensibilityElement>) fault.getEExtensibilityElements()) {
if (!(element instanceof SOAPFault)) {
continue;
}
++actualSoapFaultsCount;
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(IValidationContext validationContext, Collection<IStatus> statuses) {
if (statuses.isEmpty()) {
return ConstraintStatus.createSuccessStatus(validationContext, this.operation, null);
} else {
return ConstraintStatus.createMultiStatus(validationContext, statuses);
}
}
}