Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.predic8.wsdl.diff.WsdlDiffGenerator.groovy Maven / Gradle / Ivy
/* Copyright 2012 predic8 GmbH, www.predic8.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
package com.predic8.wsdl.diff
import groovy.xml.QName
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import com.predic8.schema.ComplexType;
import com.predic8.schema.Element;
import com.predic8.schema.diff.*
import com.predic8.soamodel.*
import com.predic8.wsdl.*
import com.sun.org.apache.bcel.internal.generic.LDIV;
class WsdlDiffGenerator extends AbstractDiffGenerator{
private static final Logger log = LoggerFactory.getLogger(WsdlDiffGenerator.class)
public WsdlDiffGenerator(){ }
public WsdlDiffGenerator(Definitions a, Definitions b){
this.a = a
this.b = b
}
List compare() {
def diffs = []
def lDiffs = []
if( a.targetNamespace != b.targetNamespace )
diffs << new Difference(description:"TargetNamespace changed from ${a.targetNamespace} to ${b.targetNamespace}.", breaks:true)
if( a.services[0] && b.services[0] && a.services[0].name != b.services[0].name )
diffs << new Difference(description:"Servicename changed from ${a.services[0].name} to ${b.services[0].name}.", breaks:false)
diffs.addAll(compareDocumentation(a, b))
/* Do not change the order of comparePortTypes and compareTypes!
* Exchange information for schema elements would be available
* after comparing portTypes.
*/
diffs.addAll(comparePortTypes())
diffs.addAll(compareTypes())
diffs.addAll(compareBindings())
lDiffs.addAll(compareDocumentation(a.services[0], b.services[0]))
if ( a.services[0] && b.services[0] ) {
lDiffs.addAll(comparePorts())
}
if(lDiffs) diffs << new Difference(description:"Service ${a.services[0].name}:", type : 'service', diffs: lDiffs)
if(diffs) return [new Difference(description:"Definitions:", type : 'definitions', diffs: diffs)]
[]
}
private List compareTypes(){
def lDiffs = compareDocumentation(a.localTypes, b.localTypes)
lDiffs.addAll(compareSchemas())
if(lDiffs) return [new Difference(description:"Types:", diffs: lDiffs, type: 'types')]
[]
}
private List comparePorts(){
def aPorts = a.services[0].ports
def bPorts = b.services[0].ports
def diffs = []
diffs.addAll(compare(aPorts, bPorts,
{ new Difference(description:"Port ${it.name} removed.", breaks:true, safe:false) },
{ new Difference(description:"Port ${it.name} added.", safe:true, breaks:false) }))
def ports = aPorts.name.intersect(bPorts.name)
ports.each{ portName ->
Port aPort = aPorts.find{ it.name == portName}
Port bPort = bPorts.find{ it.name == portName}
def lDiffs = compareDocumentation(aPort, bPort)
if(lDiffs) diffs << new Difference(description:"Port $portName:", diffs : lDiffs)
if(aPort.address.location != bPort.address.location)
diffs << new Difference(description:"Location of the port $portName changed form ${aPort.address.location} to ${bPort.address.location}.", breaks:true, safe:false)
}
diffs
}
private List comparePortTypes(){
def aPortTypes = a.portTypes
def bPortTypes = b.portTypes
def diffs = []
if(aPortTypes.size() == 1 && bPortTypes.size() == 1) {
if(aPortTypes[0].name != bPortTypes[0].name) {
diffs = comparePortType(aPortTypes[0], bPortTypes[0])
if(diffs) return [
new Difference(description:"PortType name has changed from ${aPortTypes[0].name} to ${bPortTypes[0].name}:" , type: 'portType' , diffs : diffs)
]
return [new Difference(description:"PortType name has changed from ${aPortTypes[0].name} to ${bPortTypes[0].name}." , type: 'portType')]
}
}
else {
diffs.addAll( compare(aPortTypes, bPortTypes,
{ new Difference(description:"PortType ${it.name} removed." , breaks:true, type:'portType') },
{ new Difference(description:"PortType ${it.name} added." , safe:true, type:'portType') }))
}
def ptNames = aPortTypes.name.intersect(bPortTypes.name)
ptNames.each{ ptName ->
PortType aPT = aPortTypes.find{ it.name == ptName}
PortType bPT = bPortTypes.find{ it.name == ptName}
diffs.addAll(comparePortType(aPT, bPT))
}
if(diffs) return [
new Difference(description:"PortType ${aPortTypes[0].name}:" , type: 'portType' , diffs : diffs)
]
[]
}
private List comparePortType(aPT, bPT){
def diffs = compareDocumentation(aPT, bPT)
diffs.addAll(compareOperations(aPT.operations, bPT.operations))
diffs
}
private List compareOperations(aOperations, bOperations) {
def diffs = []
diffs.addAll(compare(aOperations, bOperations,
{ new Difference(description:"Operation ${it.name} removed.", original: it, breaks:true, type:'operation') },
{ new Difference(description:"Operation ${it.name} added.", modified: it, safe:true, type:'operation') }))
def opNames = aOperations.name.intersect(bOperations.name)
opNames.each{ opName ->
//TODO Test if input/output name matches.
Operation aOperation = aOperations.find{it.name == opName}
Operation bOperation = bOperations.find{it.name == opName}
diffs.addAll(compareOperation(aOperation, bOperation))
}
diffs
}
//TODO it is not implemented yet, if an operation changes the MEP.
private List compareOperation(aOperation, bOperation) {
def diffs = compareDocumentation(aOperation, bOperation)
diffs.addAll(comparePortTypeMessage(aOperation.input, bOperation.input, 'input'))
diffs.addAll(comparePortTypeMessage(aOperation.output, bOperation.output, 'output'))
diffs.addAll(compareFaults(aOperation.faults, bOperation.faults, 'fault'))
if(diffs) return [
new Difference(description:"Operation ${aOperation.name}:", original:aOperation, modified:bOperation, type:'operation', diffs: diffs)
]
[]
}
//Compare operation input/output/fault
private List comparePortTypeMessage(aPTM, bPTM, ptmName) {
def exchange
switch (ptmName) {
case "input" : exchange = ['request'] ; break
case "output" : exchange = ['response'] ; break
case "fault" : exchange = ['fault'] ; break
}
ctx.exchange = exchange[0]
if(!aPTM && !bPTM) return []
if(aPTM && !bPTM) return [new Difference(description:"${ptmName.capitalize()} removed.", exchange:exchange.clone(), type: ptmName)]
if(!aPTM && bPTM) return [new Difference(description:"${ptmName.capitalize()} added.", exchange:exchange.clone(), type: ptmName)]
def lDiffs = compareDocumentation(aPTM, bPTM)
if(aPTM.name != bPTM.name) {
lDiffs << new Difference(description:"Name has changed from ${aPTM.name} to ${bPTM.name}.", type:'input', breaks : false, exchange:['request'])
}
if(aPTM.message.name != bPTM.message.name || aPTM.message.namespaceUri != bPTM.message.namespaceUri)
lDiffs << new Difference(description: "Message has changed from ${aPTM.message.qname} to ${bPTM.message.qname}.", type: ptmName, breaks : false, exchange:exchange.clone())
lDiffs.addAll(compareMessage(aPTM.message, bPTM.message, exchange))
if(lDiffs) return [ new Difference(description:"${ptmName.capitalize()}:", diffs: lDiffs, exchange:exchange.clone(), type: ptmName)]
lDiffs
[]
}
private List compareFaults(aFaults, bFaults, exchange) {
ctx.exchange = exchange
def diffs = []
def faults = aFaults.message.qname.intersect(bFaults.message.qname)
(aFaults.message.qname - faults).each {
diffs << new Difference(description:"Fault with message ${it} removed.", type: 'fault', exchange:[exchange])
}
(bFaults.message.qname - faults).each {
diffs << new Difference(description:"Fault with message ${it} added.", type: 'fault', exchange:[exchange])
}
faults.each { f ->
diffs.addAll(comparePortTypeMessage(aFaults.find{it.message.name == f}, bFaults.find{it.message.name == f}, exchange))
}
diffs
}
protected List compareMessage(Message a, Message b, exchange) {
def diffs = compareDocumentation(a, b)
diffs.addAll( compareParts(a.parts, b.parts, exchange))
if(diffs) return [
new Difference(description:"Message${(a.name == b.name)? ' '+a.name : ''}:", type: 'message', diffs : diffs, exchange:exchange)
]
[]
}
private List compareParts(aParts, bParts, exchange) {
def diffs = []
diffs.addAll( compare(aParts, bParts,
{ new Difference(description:"Part ${it.name} removed." , breaks:true, exchange:exchange.clone()) },
{ new Difference(description:"Part ${it.name} added." , breaks:true, exchange:exchange.clone()) }))
def partNames = aParts.name.intersect(bParts.name)
partNames.each{ ptName ->
Part a = aParts.find{ it.name == ptName}
Part b = bParts.find{ it.name == ptName}
diffs.addAll(comparePart(a, b, exchange))
}
diffs
}
private List comparePart(Part a, Part b, exchange) {
def diffs = compareDocumentation(a, b)
if(a.elementPN && b.typePN) {
try {
a.element.exchange = exchange.clone()
b.type.exchange = exchange.clone()
} catch (Exception e) {
e.printStackTrace()
}
diffs << new Difference(description:"Element ${a.elementPN} has changed to type ${b.typePN}.", type:'element2type', breaks : true, exchange:exchange.clone())
}
else if(b.elementPN && a.typePN) {
try {
a.type.exchange = exchange.clone()
b.element.exchange = exchange.clone()
} catch (Exception e) {
e.printStackTrace()
}
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){
diffs << new Difference(description:"Type has changed from ${a.type.qname} to ${b.type.qname}.",
type:'type', breaks : true, exchange:exchange.clone())
}
else {
def newCtx = ctx.clone()
newCtx.visited = []
diffs.addAll(a.type.compare(new SchemaDiffGenerator(compare4WSDL:true, ctx : newCtx), b.type))
}
}
else if(a.elementPN && b.elementPN) {
try {
a.element.exchange = exchange.clone()
} catch (Exception e) {
return [new Difference(description:"Part ${a.name} in the original document uses an invalid element('${a.elementPN}'):", type: 'part', exchange:exchange.clone(),
diffs : [new Difference(description:e.message, type:'element', breaks : true, exchange:exchange.clone())]
)]
}
try {
b.element.exchange = exchange.clone()
} catch (Exception e) {
return [new Difference(description:"Part ${b.name} in the modified document uses an invalid element('${b.elementPN}'):", 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)) {
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) {
def newCtx = ctx.clone()
newCtx.visited = []
diffs.addAll(new ElementDiffGenerator(a:a.element, b:b.element, generator:new SchemaDiffGenerator(compare4WSDL:true), ctx: newCtx).compare())
}
}
if(diffs) return [new Difference(description:"Part ${a.name}:", type: 'part', diffs : diffs, exchange:exchange.clone())]
[]
}
/*
* WsdlDiffGenerator doesn't compare all schema elements but the used one.
* So compareSchema() is not really needed!
*/
private List compareSchemas(){
def aSchemas = a.localSchemas
def bSchemas = b.localSchemas
def diffs = []
(aSchemas.targetNamespace - bSchemas.targetNamespace).each { tns ->
diffs << new Difference(description:"Schema ${tns ? tns+' ' : ''}removed." , type: 'schema')
}
(bSchemas.targetNamespace - aSchemas.targetNamespace).each { tns ->
diffs << new Difference(description:"Schema ${tns ? tns+' ' : ''}added." , type: 'schema')
}
def schemas = aSchemas.targetNamespace.intersect(bSchemas.targetNamespace)
schemas.each{ tns ->
def aSchema = aSchemas.find{it.targetNamespace == tns}
def bSchema = bSchemas.find{it.targetNamespace == tns}
log.debug("comparing schemas with namespace ${aSchema.targetNamespace}.")
def schemaDiffGenerator = new SchemaDiffGenerator(a:aSchema, b:bSchema)
def lDiffs = schemaDiffGenerator.compare()
if(lDiffs) diffs << new Difference(description:"Schema ${tns ? tns+' ' : ''}has changed:" , diffs : lDiffs, type: 'schema')
}
diffs
}
protected List compareDocumentation(a,b){
if(a?.documentation && !b?.documentation) return [
new Difference(description:"Documentation removed.", breaks : false, safe : true, type: 'documentation')
]
if(!a?.documentation && b?.documentation) return [
new Difference(description:"Documentation added.", breaks : false, safe : true, type: 'documentation')
]
if(getNormalizedContent(a?.documentation?.content) != getNormalizedContent(b?.documentation?.content))
return [
new Difference(description:"Documentation has changed.", breaks : false, safe : true, type: 'documentation')
]
[]
}
private List compareBindings(){
def aBindings = a.bindings
def bBindings = b.bindings
def diffs = []
diffs.addAll(compare(aBindings, bBindings,
{ new Difference(description:"Binding ${it.name} removed.", original: it, type:'binding') },
{ new Difference(description:"Binding ${it.name} added.", modified: it, type:'binding') }))
def bndNames = aBindings.name.intersect(bBindings.name)
bndNames.each{ bndName ->
//TODO Test if input/output name matches.
Binding aBinding= aBindings.find{it.name == bndName}
Binding bBinding= bBindings.find{it.name == bndName}
diffs.addAll(compareBinding(aBinding, bBinding))
}
diffs
}
private List compareBinding(Binding a, Binding b){
def lDiffs = []
if(a.protocol != b.protocol) {
lDiffs.add(new Difference(description:"Protocol changed from '${a.protocol}' to '${b.protocol}'", type:'protocol'))
}
if(a.protocol != 'HTTP' && b.protocol != 'HTTP') {
if(a.style != b.style) {
lDiffs.add(new Difference(description:"Style changed from '${a.style}' to '${b.style}'", type:'style'))
}
}
if(lDiffs) return [new Difference(description:"Binding ${a.name} changed:", diffs: lDiffs, type:'binding')]
[]
}
def getNormalizedContent(String content){
if(!content) return
content.replaceAll("\\s+", " ").trim()
}
protected def updateLabels(){
labelTN = AbstractDiffGenerator.bundle.getString("com.predic8.wsdl.diff.labelTN")
labelTo = AbstractDiffGenerator.bundle.getString("com.predic8.wsdl.diff.labelTo")
}
}