/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.test.ws.tools.validation;
import java.util.StringTokenizer;
import javax.xml.namespace.QName;
import org.apache.xerces.xs.XSAttributeDeclaration;
import org.apache.xerces.xs.XSComplexTypeDefinition;
import org.apache.xerces.xs.XSConstants;
import org.apache.xerces.xs.XSElementDeclaration;
import org.apache.xerces.xs.XSModelGroup;
import org.apache.xerces.xs.XSObjectList;
import org.apache.xerces.xs.XSParticle;
import org.apache.xerces.xs.XSTerm;
import org.apache.xerces.xs.XSTypeDefinition;
import org.jboss.logging.Logger;
import org.jboss.ws.Constants;
import org.jboss.ws.metadata.wsdl.WSDLDefinitions;
import org.jboss.ws.metadata.wsdl.WSDLInterface;
import org.jboss.ws.metadata.wsdl.WSDLInterfaceFault;
import org.jboss.ws.metadata.wsdl.WSDLInterfaceOperation;
import org.jboss.ws.metadata.wsdl.WSDLInterfaceOperationInput;
import org.jboss.ws.metadata.wsdl.WSDLInterfaceOperationOutput;
import org.jboss.ws.metadata.wsdl.WSDLProperty;
import org.jboss.ws.metadata.wsdl.WSDLTypes;
import org.jboss.ws.metadata.wsdl.WSDLUtils;
import org.jboss.ws.metadata.wsdl.xmlschema.JBossXSModel;
import org.jboss.ws.tools.exceptions.JBossWSToolsException;
/**
* WSDL 11 Validator
* @author <mailto:Anil.Saldhana@jboss.org>Anil Saldhana
* @since Jul 22, 2005
*/
public class WSDL11Validator extends WSDLValidator
{
private static Logger log = Logger.getLogger(WSDL11Validator.class);
/**
*
*/
public WSDL11Validator()
{
super();
}
/**
* Validates that two wsdl files represented by their WSDLDefinition objects
* are semantically equivalent
* @param wsdlExp
* @param wsdlAct
* @return true - if wsdl files are sematically equivalent, false - otherwise
*/
public boolean validate(WSDLDefinitions wsdlExp, WSDLDefinitions wsdlAct)
throws JBossWSToolsException
{
boolean bool = super.validate(wsdlExp,wsdlAct);
if( bool)
bool = validateMessages(wsdlExp,wsdlAct);
if(!bool) log.error("Message Validation Failed");
return bool;
}
//**************************************************************************
//
// PRIVATE METHODS
//
//**************************************************************************
public boolean validateMessages(WSDLDefinitions w1, WSDLDefinitions w2)
throws JBossWSToolsException
{
WSDLInterface[] intf1 = w1.getInterfaces();
WSDLInterface[] intf2 = w2.getInterfaces();
if(intf1.length != intf2.length)
throw new JBossWSToolsException("Number of portType operations in wsdl mismatch");
int len = intf1.length;
for (int i = 0; i < len; i++)
{
WSDLInterface i1 = intf1[i];
WSDLInterface i2 = intf2[i];
WSDLInterfaceOperation[] ops1 = i1.getSortedOperations();
WSDLInterfaceOperation[] ops2 = i2.getSortedOperations();
int lenOps = ops1.length;
for (int j = 0; j < lenOps; j++)
{
if(validateMessage(ops1[j],ops2[j]) == false)
{
log.error("Validation of Messages failed");
throw new JBossWSToolsException("Validation of messages failed");
}
}//end for
// Append the Faults
WSDLInterfaceFault[] faults1 = i1.getFaults();
WSDLInterfaceFault[] faults2 = i2.getFaults();
int lenf = faults1 != null ? faults1.length : 0;
for (int k = 0; k < lenf; k++)
{
WSDLInterfaceFault flt1 = faults1[k];
WSDLInterfaceFault flt2 = faults2[k];
QName elt = flt1.getElement();
QName elt2 = flt2.getElement();
if(!(elt.getLocalPart().equals(elt2.getLocalPart()) &&
elt.getNamespaceURI().equals(elt2.getNamespaceURI())))
{
log.error("Faults do not match");
throw new JBossWSToolsException("Validation of faults failed:"+elt.getLocalPart());
}
}
}//end for
return true;
}
//*********************************************************************************
//
// PRIVATE METHODS
//
//*********************************************************************************
private void checkNullParametersInconsistency(Object o1, Object o2, Class c)
{
WSDLUtils utils = WSDLUtils.getInstance();
if((o1 == null && o2 != null) || (o1 != null && o2 == null) )
throw new IllegalStateException(utils.getJustClassName(c) + " does not match");
}
private boolean validateMessage(WSDLInterfaceOperation op1,
WSDLInterfaceOperation op2 ) throws JBossWSToolsException
{
String op1name = op1.getName().getLocalPart();
String intf1name = op1.getWsdlInterface().getName().toString();
String op2name = op2.getName().getLocalPart();
String intf2name = op2.getWsdlInterface().getName().toString();
if(op1name.equals(op2name) == false)
throw new JBossWSToolsException(op1name + " does not match with " + op2name);
if( intf1name.equals(intf2name) == false)
throw new JBossWSToolsException(intf1name + " does not match with " + intf2name);
WSDLInterfaceOperationInput[] inputs1 = op1.getInputs();
WSDLInterfaceOperationInput[] inputs2 = op2.getInputs();
int lenin1 = inputs1.length;
for (int i = 0; i < lenin1; i++)
{
WSDLInterfaceOperationInput input1 = inputs1[i];
WSDLInterfaceOperationInput input2 = inputs2[i];
if(validateInputParts(input1, input2) == false)
throw new JBossWSToolsException("Validation of input parts failed:" + input1.getElement());
}
//Now the return type
WSDLInterfaceOperationOutput[] outputs1 = op1.getOutputs();
WSDLInterfaceOperationOutput[] outputs2 = op2.getOutputs();
int lenout = outputs1.length;
if(lenout != outputs2.length)
throw new JBossWSToolsException("Length of operation outputs do not match");
for (int i = 0; i < lenout; i++)
{
WSDLInterfaceOperationOutput out1 = outputs1[i];
WSDLInterfaceOperationOutput out2 = outputs2[i];
if(validateOutputParts(out1, out2) == false)
throw new JBossWSToolsException("Validation of output parts failed:" + out1);
}
return true;
}
private boolean validateInputParts(WSDLInterfaceOperationInput in1,
WSDLInterfaceOperationInput in2) throws JBossWSToolsException
{
//Check if there are any custom properties
WSDLInterfaceOperation op1 = in1.getWsdlOperation();
WSDLInterfaceOperation op2 = in2.getWsdlOperation();
String zeroarg1 = null;
String zeroarg2 = null;
WSDLProperty prop1 = op1.getProperty(Constants.WSDL_PROPERTY_ZERO_ARGS);
if (prop1 != null)
zeroarg1 = prop1.getValue();
WSDLProperty prop2 = op2.getProperty(Constants.WSDL_PROPERTY_ZERO_ARGS);
if (prop2 != null)
zeroarg2 = prop2.getValue();
if(zeroarg1 != null && zeroarg2 != null && zeroarg1.equals(zeroarg2) == false)
return false;
if (zeroarg1 != null && "true".equals(zeroarg1))
return true;
//Check if there is a property
WSDLProperty wprop1 = in1.getProperty(Constants.WSDL_PROPERTY_PART_XMLTYPE);
WSDLProperty wprop2 = in2.getProperty(Constants.WSDL_PROPERTY_PART_XMLTYPE);
QName el1 = in1.getElement();
QName el2 = in2.getElement();
WSDLDefinitions w1 = in1.getWsdlOperation().getWsdlInterface().getWsdlDefinitions();
WSDLDefinitions w2 = in2.getWsdlOperation().getWsdlInterface().getWsdlDefinitions();
if(wprop1 != null) el1 = parseQName(wprop1.getValue(),w1);
if(wprop2 != null) el2 = parseQName(wprop2.getValue(),w2);
//Validate the QNames by using types
XSTypeDefinition x1 = getTypeDefinition(el1,w1);
XSTypeDefinition x2 = getTypeDefinition(el2,w2);
boolean bool = validateType(x1,x2);
return bool;
}
private boolean validateOutputParts(WSDLInterfaceOperationOutput out1,
WSDLInterfaceOperationOutput out2) throws JBossWSToolsException
{
//Check if there are any custom properties
WSDLInterfaceOperation op1 = out1.getWsdlOperation();
WSDLInterfaceOperation op2 = out2.getWsdlOperation();
String voidreturn1 = null;
String voidreturn2 = null;
WSDLProperty prop1 = op1.getProperty(Constants.WSDL_PROPERTY_VOID_RETURN);
WSDLProperty prop2 = op2.getProperty(Constants.WSDL_PROPERTY_VOID_RETURN);
if(prop1 != null ) voidreturn1 = prop1.getValue();
if(prop2 != null ) voidreturn2 = prop2.getValue();
if(voidreturn1 != null &&
voidreturn2 != null &&
voidreturn1.equals(voidreturn2) == false) return false;
if(voidreturn1 != null && "true".equals(voidreturn1)) return true;
QName el1 = out1.getElement();
QName el2 = out2.getElement();
WSDLDefinitions w1 = out1.getWsdlOperation().getWsdlInterface().getWsdlDefinitions();
WSDLDefinitions w2 = out2.getWsdlOperation().getWsdlInterface().getWsdlDefinitions();
if( prop1 != null) el1 = parseQName( prop1.getValue(),w1);
if( prop2 != null) el2 = parseQName( prop2.getValue(),w2);
//Validate the QNames by using types
XSTypeDefinition x1 = getTypeDefinition(el1,w1);
XSTypeDefinition x2 = getTypeDefinition(el2,w2);
boolean bool = validateType(x1,x2);
return bool;
}
private XSTypeDefinition getTypeDefinition(QName xmlType, WSDLDefinitions wsdl)
{
WSDLTypes types = wsdl.getWsdlTypes();
JBossXSModel xsmodel = WSDLUtils.getSchemaModel(types);
return xsmodel.getTypeDefinition(xmlType.getLocalPart(),xmlType.getNamespaceURI());
}
private boolean validateType(XSTypeDefinition x1, XSTypeDefinition x2) throws JBossWSToolsException
{
boolean bool = false;
if(x1==null && x2 == null) return true;
this.checkNullParametersInconsistency(x1,x2,XSTypeDefinition.class);
if(x1.getName().equals(x2.getName()) == false)
throw new JBossWSToolsException("Validation of XSType failed:"
+ x1.getName() + ":" + x2.getName());
//TODO: Expand comparison of types to include attributes/elements
if(x1 instanceof XSComplexTypeDefinition &&
x2 instanceof XSComplexTypeDefinition)
{
XSComplexTypeDefinition xc1 = (XSComplexTypeDefinition) x1;
XSComplexTypeDefinition xc2 = (XSComplexTypeDefinition) x2;
bool = validateXSComplexTypeDefinitions(xc1, xc2);
}
return bool;
}
private QName parseQName( String qnamestr, WSDLDefinitions wsdl)
{
QName qn = null;
StringTokenizer st = new StringTokenizer(qnamestr,":");
while(st.hasMoreTokens())
{
String prefix = st.nextToken();
String ns = wsdl.getNamespaceURI(prefix);
String localpart = st.nextToken();
qn = new QName(ns,localpart,prefix);
}
return qn;
}
private boolean checkXSAttributesEquality(XSAttributeDeclaration x1,
XSAttributeDeclaration x2)
{
boolean bool = true;
if(x1.getName().equals(x2.getName())) return false;
XSTypeDefinition xt1 = x1.getTypeDefinition();
XSTypeDefinition xt2 = x2.getTypeDefinition();
this.checkNullParametersInconsistency(xt1,xt2,XSTypeDefinition.class);
if( xt1 != null && xt2 != null)
{
if(xt1.getName().equals(xt2.getName()) == false)
return false;
}
return bool;
}
private boolean validateXSComplexTypeDefinitions(XSComplexTypeDefinition xc1,
XSComplexTypeDefinition xc2 )
{
//First lets validate the attributes
boolean bool = true;
XSObjectList xobj1 = xc1.getAttributeUses();
XSObjectList xobj2 = xc2.getAttributeUses();
this.checkNullParametersInconsistency(xobj1,xobj2,XSObjectList.class);
if(xobj1 == null && xobj2 == null)
return true;
if(xobj1.getLength() != xobj2.getLength())
return false;
int len = xobj1.getLength();
for(int i=0; i<len ; i++)
{
XSAttributeDeclaration xat1 = (XSAttributeDeclaration)xobj1.item(i);
XSAttributeDeclaration xat2 = (XSAttributeDeclaration)xobj1.item(i);
bool = checkXSAttributesEquality(xat1,xat2);
}
//Validate the particles
XSParticle xspart1 = xc1.getParticle();
XSParticle xspart2 = xc2.getParticle();
XSTerm xt1 = xspart1.getTerm();
XSTerm xt2 = xspart2.getTerm();
if(xt1 instanceof XSModelGroup && xt2 instanceof XSModelGroup)
bool = validateXSModelGroups((XSModelGroup)xt1, (XSModelGroup)xt2);
return bool;
}
private boolean validateXSModelGroups( XSModelGroup xm1, XSModelGroup xm2)
{
boolean bool = true;
if(xm1.getCompositor() != xm2.getCompositor())
return false;
short c = xm1.getCompositor();
if( c == XSModelGroup.COMPOSITOR_ALL || c == XSModelGroup.COMPOSITOR_SEQUENCE)
{
XSObjectList xo1 = xm1.getParticles();
XSObjectList xo2 = xm2.getParticles();
if( xo1.getLength() != xo2.getLength())
throw new IllegalStateException("Length of particles do not match:"+xm1.getName());
int len = xo1.getLength();
for(int i=0; i< len; i++)
{
XSTerm xterm1 = ((XSParticle)xo1.item(i)).getTerm();
XSTerm xterm2 = ((XSParticle)xo2.item(i)).getTerm();
short termType = xterm1.getType();
if(xterm1.getType() != xterm2.getType())
throw new IllegalStateException(xm1.getName() + " does not match with "+ xm2.getName());
if(XSConstants.MODEL_GROUP == termType)
bool = validateXSModelGroups((XSModelGroup)xterm1, (XSModelGroup)xterm2);
else
if(XSConstants.ELEMENT_DECLARATION == termType)
bool = validateXSElementDeclaration((XSElementDeclaration)xterm1, (XSElementDeclaration)xterm2);
}
}
return bool;
}
private boolean validateXSElementDeclaration(XSElementDeclaration xe1,
XSElementDeclaration xe2)
{
boolean bool = true;
bool = (xe1.getName().equals(xe2.getName()));
if(bool)
{
//Check if there are types
XSTypeDefinition xt1 = xe1.getTypeDefinition();
XSTypeDefinition xt2 = xe2.getTypeDefinition();
bool = xt1.getName().equals(xt2.getName());
String ns1 = xt1.getNamespace();
String ns2 = xt2.getNamespace();
/**
* Ignore the namespace if it is wscompile generated arrays namespace
*/
if(bool && ns1 != null && ns2 != null && (ns1.lastIndexOf("arrays") < 0))
bool = xt1.getNamespace().equals(xt2.getNamespace());
//TODO:take care of enclosing CT Definition
}
return bool;
}
}