Skip to content

Commit

Permalink
Definitions updated: getElement() and getType() throw exceptions if r…
Browse files Browse the repository at this point in the history
…ef is invalid.

WSDLValidator improved: Difference for invalid element and type references.
  • Loading branch information
keshavarzi committed Dec 15, 2013
1 parent 43d47be commit ef1716c
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 33 deletions.
34 changes: 30 additions & 4 deletions core/src/main/groovy/com/predic8/wsdl/Definitions.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -142,23 +142,49 @@ class Definitions extends WSDLElement{
def lookup = { item, qname -> registry.getWsdls(qname.namespaceURI)*."$item"?.flatten().find{it.name == qname.localPart}}

Element getElement(String elementPN) {
if(!elementPN) return
getElement(getQNameForPN(new PrefixedName(elementPN)))
}

Element getElement(PrefixedName elementPN) {
if(!elementPN) return
getElement(getQNameForPN(elementPN))
}

Element getElement(GQName qname) {
schemas.elements.flatten().find{
it.schema.targetNamespace == qname.namespaceURI && it.name == qname.localPart
if(!qname) return
def element
(schemas + getSchemaLoadKnownSchemaIfNeeded(qname.namespaceURI) - null).findAll{it.targetNamespace == qname.namespaceURI}.each{ schema ->
try {
return element = schema.find{it.getElement(qname)}?.getElement(qname)
} catch (Exception e) {}
}
if(!element) throw new ElementRefAccessException("Could not find the referenced element '${qname.localPart}' in namespace '${qname.namespaceURI}'.",
qname, prefix ?: getPrefix(qname.namespaceURI))
element
}

TypeDefinition getSchemaType(String name) {
getSchemaType(getQNameForPN(new PrefixedName(name)))
}

TypeDefinition getSchemaType(PrefixedName pName) {
getSchemaType(getQNameForPN(pName))
}

TypeDefinition getSchemaType(GQName qname) {
//BuiltInSchemaTypes should be returned here, because Definitions maybe contains no schema!
if(qname?.namespaceURI == Consts.SCHEMA_NS) return new BuiltInSchemaType(qname: qname)
schemas.find{ it.getType(qname) }?.getType(qname)
def type
(schemas + getSchemaLoadKnownSchemaIfNeeded(qname.namespaceURI) - null).findAll{it.targetNamespace == qname.namespaceURI}.each{ schema ->
try {
return type = schema.find{it.getType(qname)}?.getType(qname)
} catch (Exception e) {}
}
if(!type) throw new TypeRefAccessException(
"Could not find the referenced type '${qname.localPart}' in namespace '${qname.namespaceURI}'.",
qname, getPrefix(qname.namespaceURI))
type
}

//TODO to be removed! Use getInputElementForOperation instead!
Expand Down Expand Up @@ -270,7 +296,7 @@ class Definitions extends WSDLElement{

Schema getSchemaLoadKnownSchemaIfNeeded(String ns) {
if(!getSchema(ns) && ns in KnownSchemas.docs.keySet()) {
addSchema(new SchemaParser(resourceResolver: new ClasspathResolver()).parse(KnownSchemas.docs[ns]))
return new SchemaParser(resourceResolver: new ClasspathResolver()).parse(KnownSchemas.docs[ns])
}
getSchema(ns)
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/groovy/com/predic8/wsdl/Part.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ class Part extends WSDLElement{
}

TypeDefinition getType() {
if(!typePN) return
if(type) return type
if(!typePN) return
type = definitions.getSchemaType(getQNameForPN(typePN))
}

Expand Down
20 changes: 14 additions & 6 deletions core/src/main/groovy/com/predic8/wsdl/WSDLValidator.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@

package com.predic8.wsdl

import com.predic8.soamodel.ElementRefAccessException
import com.predic8.soamodel.MessageAccessException
import com.predic8.soamodel.OperationAccessException
import com.predic8.soamodel.PortTypeAccessException
import com.predic8.soamodel.TypeRefAccessException;
import com.predic8.soamodel.ValidationError

class WSDLValidator {
Expand Down Expand Up @@ -104,14 +106,20 @@ class WSDLValidator {
}

void validateMessageParts(Message msg, ctx) {
msg.parts.each {
msg.parts.each {part ->
try {
if(it.elementPN && !it.element)
ctx.errors << new ValidationError(invalidElement : it, parent: msg, message : "The referenced element ${it.elementPN} in part ${it.name} of the message ${msg.name} is not defined in this WSDL.", wsdlTNS: it.definitions.targetNamespace)
if(it.typePN && !it.type)
ctx.errors << new ValidationError(invalidElement : it, parent: msg, message : "The referenced type ${it.typePN} in part ${it.name} of the message ${msg.name} is not defined in this WSDL.", wsdlTNS: it.definitions.targetNamespace)
part.element ?: part.type
} catch (ElementRefAccessException e) {
ctx.errors << new ValidationError(invalidElement : part, parent: msg,
message : "The referenced element ${part.elementPN} in part ${part.name} of the message ${msg.name} is not defined in this WSDL.",
wsdlTNS: part.definitions.targetNamespace, cause: e)
} catch (TypeRefAccessException e) {
ctx.errors << new ValidationError(invalidElement : part, parent: msg,
message : "The referenced type ${part.typePN} in part ${part.name} of the message ${msg.name} is not defined in this WSDL.",
wsdlTNS: part.definitions.targetNamespace, cause: e)
} catch (Exception e) {
ctx.errors << new ValidationError(invalidElement : it, parent: msg, message : (e.message ?: "The part ${it.name} in message ${msg.name} is invalid."), wsdlTNS: it.definitions.targetNamespace)
ctx.errors << new ValidationError(invalidElement : part, parent: msg,
message : (e.message ?: "The part ${part.name} in message ${msg.name} is invalid."), wsdlTNS: part.definitions.targetNamespace)
}
}
}
Expand Down
33 changes: 21 additions & 12 deletions core/src/main/groovy/com/predic8/wsdl/diff/WsdlDiffGenerator.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -228,32 +228,41 @@ class WsdlDiffGenerator extends AbstractDiffGenerator{
diffs << new Difference(description:"Type ${a.typePN} has changed to element ${b.elementPN}.", type:'type2element', breaks : true, exchange:exchange.clone())
}
else if(a.typePN && b.typePN) {
try {
a.type.exchange = exchange.clone()
b.type.exchange = exchange.clone()
} catch (Exception e) {
return [new Difference(description:"Part ${a.name} uses an invalid type:", type: 'part', exchange:exchange.clone(),
diffs : [new Difference(description:e.message, type:'type', breaks : true, exchange:exchange.clone())]
)]
}
//CompareComplexType does NOT detect if a CT has changed only the namespaceURI! So the next line is needed.
if(a.type?.qname != b.type?.qname){
def aType = a.type?.qname ?: 'an invalid type'
def bType = b.type?.qname ?: 'an invalid type'
diffs << new Difference(description:"Type has changed from ${aType} to ${bType}.",
if(a.type.qname != b.type.qname){
diffs << new Difference(description:"Type has changed from ${a.type.qname} to ${b.type.qname}.",
type:'type', breaks : true, exchange:exchange.clone())
}
else diffs.addAll(a.type.compare(new SchemaDiffGenerator(compare4WSDL:true), b.type))
}
else if(a.elementPN && b.elementPN) {
a.element?.exchange = exchange.clone()
b.element?.exchange = exchange.clone()
def document = 'original document'
try {
a.element.exchange = exchange.clone()
document = 'modified document'
b.element.exchange = exchange.clone()
} catch (Exception e) {
return [new Difference(description:"Part ${a.name} in the $document uses an invalid element:", type: 'part', exchange:exchange.clone(),
diffs : [new Difference(description:e.message, type:'element', breaks : true, exchange:exchange.clone())]
)]
}
if(a.elementPN.localName != b.elementPN.localName){
diffs << new Difference(description:"Element has changed from ${a.elementPN} to ${b.elementPN}.",
type:'element', breaks : true, exchange:exchange.clone())
}
else if(a.getNamespace(a.elementPN.prefix) != b.getNamespace(b.elementPN.prefix)) {
def aElement = a.element?.qname ?: 'an invalid element'
def bElement = b.element?.qname ?: 'an invalid element'

diffs << new Difference(description:"Element has changed from $aElement to $bElement.",
diffs << new Difference(description:"Element has changed from ${a.element.qname} to ${b.element.qname}.",
type:'element', breaks : true, exchange:exchange.clone())
}
else if(a.element && b.element) {
a.element.exchange += exchange.clone()
b.element.exchange += exchange.clone()
diffs.addAll(new ElementDiffGenerator(a:a.element, b:b.element, generator:new SchemaDiffGenerator(compare4WSDL:true)).compare())
}
}
Expand Down
18 changes: 17 additions & 1 deletion core/src/test/groovy/com/predic8/wsdl/WSDLValidatorTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@

package com.predic8.wsdl

import com.predic8.soamodel.ElementRefAccessException;
import com.predic8.soamodel.MessageAccessException
import com.predic8.soamodel.NamespaceNotDeclaredForReferenceException
import com.predic8.soamodel.TypeRefAccessException;
import com.predic8.soamodel.ValidationError
import com.predic8.xml.util.ClasspathResolver

Expand All @@ -35,7 +37,7 @@ class WSDLValidatorTest extends GroovyTestCase{
wsdl.validate(ctx)
assert ctx.errors.grep(ValidationError).find{it.invalidElement instanceof Binding}.cause.message ==
"Could not find the portType definition for 'tns:ArticleServicePTTEST' in the binding'ArticleServicePTBinding'."
assert 6 == ctx.errors.grep(ValidationError).size()
assert 7 == ctx.errors.grep(ValidationError).size()
assert ctx.errors.grep(ValidationError).invalidElement.grep(Binding)
assert ctx.errors.grep(ValidationError).invalidElement.grep(Port)
assert ctx.errors.grep(ValidationError).invalidElement.grep(Part)
Expand Down Expand Up @@ -63,6 +65,20 @@ class WSDLValidatorTest extends GroovyTestCase{
wsdl.validate(ctx)
assert ctx.errors.grep(ValidationError).findAll{it.invalidElement.name == 'BindingMissingOperation'}[0].message ==
"Could not find the definition for binding operation: [create, get, getAll] in binding 'BindingMissingOperation'."
}

void testPartValidation() {
wsdl.validate(ctx)
assert ctx.errors.grep(ValidationError).findAll{it.invalidElement instanceof Part}[0].message ==
"The referenced element create in part parameters of the message createRequest is not defined in this WSDL."
assert ctx.errors.grep(ValidationError).findAll{it.invalidElement instanceof Part}[0].cause instanceof ElementRefAccessException
assert ctx.errors.grep(ValidationError).findAll{it.invalidElement instanceof Part}[0].cause.message ==
"Could not find the referenced element 'create' in namespace 'http://schemas.xmlsoap.org/wsdl/'."

assert ctx.errors.grep(ValidationError).findAll{it.invalidElement instanceof Part}[1].message ==
"The referenced type tns:CreateTypeTEST in part parameters of the message getAllRequestTEST is not defined in this WSDL."
assert ctx.errors.grep(ValidationError).findAll{it.invalidElement instanceof Part}[1].cause instanceof TypeRefAccessException
assert ctx.errors.grep(ValidationError).findAll{it.invalidElement instanceof Part}[1].cause.message ==
"Could not find the referenced type 'CreateTypeTEST' in namespace 'http://predic8.com/wsdl/material/ArticleService/1/'."
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,31 +29,35 @@ class OnlyOnePortTypeDiffGeneratorTest extends GroovyTestCase {
void testPortTypeOperationChanges() {
def diffs = compare(wsdl2, wsdl1)
assert diffs*.dump().toString().contains('PortType BLZServicePortType:')
assert diffs*.dump().toString().contains('Element has changed from {http://thomas-bayer.com/blz/}getBank to an invalid element.')
// assert diffs*.dump().toString().contains('Element has changed from {http://thomas-bayer.com/blz/}getBank to an invalid element.')
assert diffs*.dump().toString().contains("Part parameters in the modified document uses an invalid element:")
assert diffs*.dump().toString().contains("Could not find the referenced element 'getBank' in namespace 'http://schemas.xmlsoap.org/wsdl/'.")
}

void testPortTypeNameAndOperationChanges() {
wsdl2.portTypes[0].name = 'Test'
def diffs = compare(wsdl2, wsdl1)
assert diffs*.dump().toString().contains('PortType name has changed from Test to BLZServicePortType:')
assert diffs*.dump().toString().contains('Element has changed from {http://thomas-bayer.com/blz/}getBank to an invalid element.')
assert diffs*.dump().toString().contains("Part parameters in the modified document uses an invalid element:")
assert diffs*.dump().toString().contains("Could not find the referenced element 'getBank' in namespace 'http://schemas.xmlsoap.org/wsdl/'.")
}

void testPTNameChanges() {
wsdl2 = parser.parse('diff/message-parts/BLZService1.wsdl')
wsdl2.portTypes[0].name = 'Test'
def diffs = compare(wsdl1, wsdl2)
assert diffs[0].diffs[0].description == "PortType name has changed from BLZServicePortType to Test."
assert diffs[0].diffs[0].description == "PortType name has changed from BLZServicePortType to Test:"
diffs = compare(wsdl2, wsdl1)
assert diffs[0].diffs[0].description == "PortType name has changed from Test to BLZServicePortType."
assert diffs[0].diffs[0].description == "PortType name has changed from Test to BLZServicePortType:"
}

void testPTWithNoChanges() {
void testPTWithNoChangesButInvalidDocument() {
//Because of the error in part there will be a diff, although the documents are the same!
wsdl2 = parser.parse('diff/message-parts/BLZService1.wsdl')
def diffs = compare(wsdl1, wsdl2)
assert !diffs
assert diffs*.dump().toString().contains("Could not find the referenced element 'getBank' in namespace 'http://schemas.xmlsoap.org/wsdl/'.")
diffs = compare(wsdl2, wsdl1)
assert !diffs
assert diffs*.dump().toString().contains("Could not find the referenced element 'getBank' in namespace 'http://schemas.xmlsoap.org/wsdl/'.")
}

private def compare(a, b) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ class PartDiffGeneratorTest extends GroovyTestCase {
void testDocumentationInDefinitions() {
def diffs = compare(wsdl2, wsdl1)
assert diffs[0].diffs[0].diffs[0].diffs[0].diffs[0].diffs[0].diffs[0].description ==
'Element has changed from {http://thomas-bayer.com/blz/}getBank to an invalid element.'
// 'Element has changed from {http://thomas-bayer.com/blz/}getBank to an invalid element.'
"Could not find the referenced element 'getBank' in namespace 'http://schemas.xmlsoap.org/wsdl/'."
}

private def compare(a, b) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
</xsd:schema>
</types>
<message name="createRequest">
<part name="parameters" element="tns:create" />
<part name="parameters" element="create" />
</message>
<message name="createResponse">
<part name="parameters" element="tns:createResponse" />
Expand Down

0 comments on commit ef1716c

Please sign in to comment.