package nl.ipo.cds.webservices;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axiom.om.xpath.AXIOMXPath;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jaxen.JaxenException;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
public class FeatureCollectionComparator {
private static final Log logger = LogFactory.getLog(FeatureCollectionComparator.class);
private final String FEATURECOLLECTION_SORTFILE = "/nl/ipo/cds/webservices/featureCollectionSortfile.xslt";
private Resource featureCollectionTransformerFile = new ClassPathResource(FEATURECOLLECTION_SORTFILE);
public FeatureCollectionComparisonResult compareFeatureCollections(Resource resourceA, Resource resourceB) throws IOException, TransformerException, XMLStreamException, FactoryConfigurationError, JaxenException{
List<String> featureMemberIdsA = createFeatureIdStringCollectionFlat(resourceA);
List<String> featureMemberIdsB = createFeatureIdStringCollectionFlat(resourceB);
return this.compareFeatureCollections(featureMemberIdsA, featureMemberIdsB);
}
public FeatureCollectionComparisonResult compareFeatureCollectionsByResources(List<Resource> getFeatureResources, List<String> featureMemberIdsB) throws IOException, TransformerException, XMLStreamException, FactoryConfigurationError, JaxenException{
List<String> featureMemberIdsA = new ArrayList<String>();
for (Iterator<Resource> iterator = getFeatureResources.iterator(); iterator
.hasNext();) {
Resource resource = (Resource) iterator.next();
logger.debug("Adding cachedResource" + "\"" + resource.getDescription() + "\" to the feature-id-list.");
featureMemberIdsA.addAll(this.createFeatureIdStringCollectionFlat(resource));
}
return this.compareFeatureCollections(featureMemberIdsA, featureMemberIdsB);
}
public FeatureCollectionComparisonResult compareFeatureCollections(List<String> featureMemberIdsA, List<String> featureMemberIdsB) throws IOException, TransformerException, XMLStreamException, FactoryConfigurationError, JaxenException{
FeatureCollectionComparisonResult featureCollectionComparisonResult = new FeatureCollectionComparisonResult();
logger.debug("Start comparing collections");
boolean success = true;
// Collection same size?
if(featureMemberIdsA.size() != featureMemberIdsB.size()){
success = false;
featureCollectionComparisonResult.addMessage("Collection A has \"" + featureMemberIdsA.size() + "\" features, but Collection B has \"" + featureMemberIdsB.size() + "\" features");
} else {
logger.debug("Start comparing collections on equality");
success = CollectionUtils.isEqualCollection(featureMemberIdsA, featureMemberIdsB);
logger.debug("Done comparing collections on equality");
}
if(!success){
logger.debug("There are differences. Start making report of differences");
Collection<String> subtraction = CollectionUtils.subtract(featureMemberIdsA, featureMemberIdsB);
for (Iterator<String> iterator = subtraction.iterator(); iterator.hasNext();) {
String inspireId = (String) iterator.next();
featureCollectionComparisonResult.addMessage("inspireID \"" + inspireId + "\" resides not in collection B");
}
subtraction = CollectionUtils.subtract(featureMemberIdsB, featureMemberIdsA);
for (Iterator<String> iterator = subtraction.iterator(); iterator.hasNext();) {
String inspireId = (String) iterator.next();
featureCollectionComparisonResult.addMessage("inspireID \"" + inspireId + "\" resides not in collection A");
}
}
featureCollectionComparisonResult.setFeatureCount(featureMemberIdsA.size());
featureCollectionComparisonResult.setSuccess(success);
logger.debug("Done comparing collections");
return featureCollectionComparisonResult;
}
public static List<String> createFeatureIdStringCollectionFlat(Resource resource)
throws JaxenException, XMLStreamException,
FactoryConfigurationError, IOException {
Source xmlSource = new StreamSource(resource.getInputStream());
final String FEATURE_ID_STRING = "//*[ends-with(lower-case(local-name(.)),'member')]//*[ends-with(lower-case(local-name(.)),'inspireid')]";
AXIOMXPath queryXPath;
queryXPath = new AXIOMXPath(FEATURE_ID_STRING);
// queryXPath.addNamespace("wfs", "http://www.opengis.net/wfs");
queryXPath.addNamespace("gml", "http://www.opengis.net/gml");
XMLStreamReader parserA = XMLInputFactory.newInstance().createXMLStreamReader(xmlSource);
StAXOMBuilder builderA = new StAXOMBuilder(parserA);
OMElement featureCollectionA = builderA.getDocumentElement();
List<OMElement> featureMemberIdElements = queryXPath.selectNodes(featureCollectionA);
List<String> featureMemberStringIds = new ArrayList<String>();
for (Iterator<OMElement> iterator = featureMemberIdElements.iterator(); iterator.hasNext();) {
String id = null;
OMElement inspireId = (OMElement) iterator.next();
OMElement identifier = inspireId.getFirstElement();
if(identifier != null){
id = identifier.getFirstChildWithName(new QName("urn:x-inspire:specification:gmlas:BaseTypes:3.2","localId")).getText();
id = identifier.getFirstChildWithName(new QName("urn:x-inspire:specification:gmlas:BaseTypes:3.2","namespace")).getText() + "." + id;
} else {
id = inspireId.getText();
}
featureMemberStringIds.add(id);
}
return featureMemberStringIds;
}
private FeatureCollectionComparisonResult compareViaSort(final Source xmlSourceA, final Source xmlSourceB)
throws IOException, TransformerFactoryConfigurationError,
TransformerConfigurationException, TransformerException,
XMLStreamException, FactoryConfigurationError {
// NOTE: Cannot work. Only allowed to use Pipes in different threads
String message = null;
boolean success = true;
PipedOutputStream pipedOutputStreamA = new PipedOutputStream();
PipedInputStream pipedInputStreamA = new PipedInputStream(pipedOutputStreamA);
StreamResult sortedCollectionA = new StreamResult(pipedOutputStreamA);
sortCollection(xmlSourceA, sortedCollectionA);
PipedOutputStream pipedOutputStreamB = new PipedOutputStream();
PipedInputStream pipedInputStreamB = new PipedInputStream(pipedOutputStreamB);
StreamResult sortedCollectionB = new StreamResult(pipedOutputStreamB);
sortCollection(xmlSourceB, sortedCollectionB);
XMLStreamReader parserA = XMLInputFactory.newInstance().createXMLStreamReader(pipedInputStreamA);
StAXOMBuilder builderA = new StAXOMBuilder(parserA);
OMElement featureCollectionA = builderA.getDocumentElement();
XMLStreamReader parserB = XMLInputFactory.newInstance().createXMLStreamReader(pipedInputStreamB);
StAXOMBuilder builderB = new StAXOMBuilder(parserB);
OMElement featureCollectionB = builderB.getDocumentElement();
Iterator<OMElement> featureCollectionIteratorA = featureCollectionA.getChildrenWithLocalName("featureMember");
Iterator<OMElement> featureCollectionIteratorB = featureCollectionB.getChildrenWithLocalName("featureMember");
long i = 0;
for (Iterator<OMElement> iterator = featureCollectionIteratorA; iterator.hasNext();) {
i++;
OMElement featureMemberA = (OMElement) iterator.next();
OMElement featureMemberB = featureCollectionIteratorB.next();
boolean equal = StringUtils.equalsIgnoreCase(featureMemberA.getText(), featureMemberB.getText());
System.out.println(i + "; id=" + featureMemberA.getText());
if(!equal){
message = "FeatureId \"" + featureMemberA.getText() + "\" not equal FeatureId \"" + featureMemberB.getText() + "\"";
success = false;
break;
}
}
FeatureCollectionComparisonResult featureCollectionComparisonResult = new FeatureCollectionComparisonResult();
return featureCollectionComparisonResult;
}
private StreamResult sortCollection(Source xmlSource, StreamResult sortedCollection)
throws IOException, TransformerFactoryConfigurationError,
TransformerConfigurationException, TransformerException {
Source xsltSource = new StreamSource(featureCollectionTransformerFile.getInputStream());
// create an instance of TransformerFactory
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer(xsltSource);
transformer.transform(xmlSource, sortedCollection);
return sortedCollection;
}
}