/*
* ALMA - Atacama Large Millimiter Array
* (c) European Southern Observatory, 2005
* Copyright by ESO (in the framework of the ALMA collaboration),
* All rights reserved
*
* This library 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 library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package alma.acs.config.validators;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* Class that can recognize XML files that are known to be not config files.
*
* @author hsommer
*/
public class ConfigFileRedeemerXml extends ConfigFileRedeemer {
protected List<XPathMatchSetup> xpathMatchSetupList;
public static final String XSD_NS = "http://www.w3.org/2001/XMLSchema";
/**
*
*/
public ConfigFileRedeemerXml(Logger logger) throws Exception {
super(logger);
xpathMatchSetupList = new ArrayList<XPathMatchSetup>();
configure();
}
/**
* Configures information about known files which should not be accused of being config files.
*/
protected void configure() {
// Castor config files
addXPathMatch(new XPathMatchSetup("/EntitybuilderSettings/EntitySchema", null, null, XPathConstants.NODESET));
// ACS error system type/code definition files
addXPathMatch(new XPathMatchSetup("/Type/@type", null, null, XPathConstants.NUMBER));
addXPathMatch(new XPathMatchSetup("/bla:Type/@type", "bla", "Alma/ACSError", XPathConstants.NUMBER)); // error schema used to have a target namespace
// UML-XMI files
addXPathMatch(new XPathMatchSetup("/XMI/@xmi.version", null, null, XPathConstants.NUMBER));
// APDM entities
addXPathMatch(new XPathMatchSetup("/oprp:ObsProposal", "oprp", "Alma/ObsPrep/ObsProposal", XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/oprj:ObsProject", "oprj", "Alma/ObsPrep/ObsProject", XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/sbl:SchedBlock", "sbl", "Alma/ObsPrep/SchedBlock", XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema[@targetNamespace='Alma/ObsPrep/ObsProposal']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema[@targetNamespace='Alma/ObsPrep/ObsProject']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema[@targetNamespace='Alma/ObsPrep/ObsReview']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema[@targetNamespace='Alma/ObsPrep/SchedBlock']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema[@targetNamespace='Alma/ObsPrep/ProjectStatus']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema[@targetNamespace='Alma/ValueTypes']", "xsd", XSD_NS, XPathConstants.NODE));
// OAW mappings
addXPathMatch(new XPathMatchSetup("/MetaMap", null, null, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/MetaModel", null, null, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/bla:AcsCommandCenterProject", "bla", "Alma/Acs/AcsCommandCenterProject", XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/bla:AcsCommandCenterTools", "bla", "Alma/Acs/AcsCommandCenterTools", XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/bla:cosydoc", "bla", "urn:schemas-cosylab-com:Document", XPathConstants.NODE));
// known ACS schema files
addXPathMatch(new XPathMatchSetup("/xsd:schema/xsd:simpleType[@name='ErrorType']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema/xsd:element[@name='AcsCommandCenterProject']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema/xsd:element[@name='AcsCommandCenterTools']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema/xsd:complexType[@name='EventChannel']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema/xsd:element[@name='SimulatedComponent']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema/xsd:complexType[@name='EntityT']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema/xsd:element[@name='IdentifierRange']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema/xsd:element[@name='ComponentHelperInfo']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema/xsd:element[@name='EntitybuilderSettings']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema/xsd:complexType[@name='ComponentInfo']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema/xsd:complexType[@name='Container']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema/xsd:complexType[@name='Manager']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema/xsd:element[@name='Log']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema/xsd:element[@name='paramset']", "xsd", XSD_NS, XPathConstants.NODE));
addXPathMatch(new XPathMatchSetup("/xsd:schema/xsd:element[@name='pset']", "xsd", XSD_NS, XPathConstants.NODE));
// Ant build files (incl. Eclipse external build files)
addXPathMatch(new XPathMatchSetup("/project/@basedir", null, null, XPathConstants.STRING));
addXPathMatch(new XPathMatchSetup("/project/target/javadoc", null, null, XPathConstants.NODESET));
// addXPathMatch(new XPathMatchSetup("/bla:Container", "bla", "urn:schemas-cosylab-com:Container:1.0", XPathConstants.NODE));
}
public String[] getFileEndings() {
return new String[] {".xml", ".xsd", ".xslt"};
}
public boolean _isNotAConfigFile(File xmlFile) {
try {
// parse the XML file into a DOM
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Element rootElement = builder.parse(xmlFile).getDocumentElement();
// create an XPath engine
XPath xpath = XPathFactory.newInstance().newXPath();
// for each XPath expression configured in method #addXPathMatch,
// we try if it matches anything in our DOM
for (Iterator<XPathMatchSetup> iter = xpathMatchSetupList.iterator(); iter.hasNext();) {
XPathMatchSetup xpathSetup = iter.next();
XmlNamespaceContextContainer nsContext = new XmlNamespaceContextContainer();
nsContext.addNamespace(xpathSetup.getPrefix(), xpathSetup.getNamespace());
xpath.setNamespaceContext(nsContext);
Object xpathResult = xpath.evaluate(xpathSetup.getExpression(), rootElement, xpathSetup.getReturnType());
if (xpathResult != null) {
// NUMBER must not be NaN
if (xpathSetup.getReturnType().equals(XPathConstants.NUMBER) && ((Double)xpathResult).isNaN()) {
// System.out.println("result: Number " + xpathResult.getClass().getName() + xpathResult);
continue;
}
// NODESET must not be empty
else if (xpathSetup.getReturnType().equals(XPathConstants.NODESET) && ((NodeList)xpathResult).getLength() == 0) {
continue;
}
// STRING must not be empty
else if (xpathSetup.getReturnType().equals(XPathConstants.STRING) && ((String)xpathResult).trim().length() == 0) {
continue;
}
else if (xpathSetup.getReturnType().equals(XPathConstants.NODE)) {
// Node node = (Node) xpathResult;
// System.out.println("*** got a node: " + node.toString());
}
System.out.println("XML file '" + xmlFile + "' is not a config file. " +
"The query '" + xpathSetup.getExpression() + "' found a matching " + xpathSetup.getReturnType().getLocalPart());
return true;
}
}
return false;
}
catch (Exception e) {
logger.log(Level.WARNING, "xml file '" + xmlFile + "' failed to be parsed and will be treated as suspect.", e);
return false;
}
}
public static class XPathMatchSetup {
private String expression;
private String prefix;
private String namespace;
private QName returnType;
public XPathMatchSetup(String expression, String prefix, String namespace, QName returnType) {
this.expression = expression;
this.namespace = namespace;
this.prefix = prefix;
this.returnType = returnType;
}
String getExpression() {
return expression;
}
String getPrefix() {
return prefix;
}
String getNamespace() {
return namespace;
}
QName getReturnType() {
return returnType;
}
}
public void addXPathMatch(XPathMatchSetup xpathMatchSetup) {
this.xpathMatchSetupList.add(xpathMatchSetup);
}
}