diff --git a/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java b/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java index c56a0c55..91daf37b 100755 --- a/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java +++ b/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java @@ -35,7 +35,7 @@ import org.mustangproject.ZUGFeRD.ZUGFeRDExporter; import org.mustangproject.ZUGFeRD.ZUGFeRDExporterFromA1Factory; import org.mustangproject.ZUGFeRD.ZUGFeRDImporter; import org.mustangproject.ZUGFeRD.ZUGFeRDMigrator; -import org.mustangproject.library.extended.ZUGFeRDValidator; +import org.mustangproject.validator.ZUGFeRDValidator; /*** * This is the command line interface to mustangproject diff --git a/validator/src/main/java/org/mustangproject/library/extended/EPart.java b/validator/src/main/java/org/mustangproject/library/extended/EPart.java deleted file mode 100644 index 486bd65e..00000000 --- a/validator/src/main/java/org/mustangproject/library/extended/EPart.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.mustangproject.library.extended; - -public enum EPart { - fx, xr, pdf, none -} diff --git a/validator/src/main/java/org/mustangproject/library/extended/ESeverity.java b/validator/src/main/java/org/mustangproject/library/extended/ESeverity.java deleted file mode 100644 index 7c8184e3..00000000 --- a/validator/src/main/java/org/mustangproject/library/extended/ESeverity.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.mustangproject.library.extended; - -public enum ESeverity { - notice, warning, error, fatal, exception -} diff --git a/validator/src/main/java/org/mustangproject/library/extended/IrrecoverableValidationError.java b/validator/src/main/java/org/mustangproject/library/extended/IrrecoverableValidationError.java deleted file mode 100644 index fe03ed45..00000000 --- a/validator/src/main/java/org/mustangproject/library/extended/IrrecoverableValidationError.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.mustangproject.library.extended; - -public class IrrecoverableValidationError extends Exception { - - /** - * - */ - private static final long serialVersionUID = 1L; - public IrrecoverableValidationError(String message) { - super(message); - } - -} diff --git a/validator/src/main/java/org/mustangproject/library/extended/Main.java b/validator/src/main/java/org/mustangproject/library/extended/Main.java deleted file mode 100644 index 06d05c7a..00000000 --- a/validator/src/main/java/org/mustangproject/library/extended/Main.java +++ /dev/null @@ -1,94 +0,0 @@ -package org.mustangproject.library.extended; - -import java.io.File; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sanityinc.jargs.CmdLineParser; -import com.sanityinc.jargs.CmdLineParser.Option; - -public class Main { - - static final ClassLoader cl = Main.class.getClassLoader(); - - private static final Logger LOGGER = LoggerFactory.getLogger(Main.class.getCanonicalName()); // log output is - // ignored for the - // time being - - public void run(String[] args) { - - /*** - * prerequisite is a mvn generate-resources - */ - - CmdLineParser parser = new CmdLineParser(); - Option actionOption = parser.addStringOption('a', "action"); - Option filenameOption = parser.addStringOption('f', "Filename"); - - Option licenseOption = parser.addBooleanOption('l', "license"); - Option helpOption = parser.addBooleanOption('h', "help"); - Option logAppendOption = parser.addStringOption("logAppend"); - - boolean optionsRecognized = false; - - try { - parser.parse(args); - } catch (CmdLineParser.OptionException e) { - System.err.println(e.getMessage()); - System.exit(-2); - } - - Boolean helpRequested = parser.getOptionValue(helpOption); - - if (parser.getOptionValue(licenseOption) != null) { - optionsRecognized = true; - - System.out.println("Copyright 2018 Jochen Stärk\n" + "\n" - + "Licensed under the Apache License, Version 2.0 (the \"License\");\n" - + "you may not use this file except in compliance with the License.\n" - + "You may obtain a copy of the License at\n" + "\n" - + " http://www.apache.org/licenses/LICENSE-2.0\n" + "\n" - + "Unless required by applicable law or agreed to in writing, software\n" - + "distributed under the License is distributed on an \"AS IS\" BASIS,\n" - + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" - + "See the License for the specific language governing permissions and\n" - + "limitations under the License.\n\n\n\n\n" - + "This software is embedding the PDF/A validator VeraPDF, " - + "http://verapdf.org/, which is available under GPL and MPL licenses."); - - System.exit(0); - } - String filename = parser.getOptionValue(filenameOption); - String action = parser.getOptionValue(actionOption); - File logdir = new File("log"); - if (!logdir.exists() || !logdir.isDirectory() || !logdir.canWrite()) { - System.err.println("Need writable subdirectory 'log' for log files."); - } - - if ((action != null) && (action.equals("validate"))) { - ZUGFeRDValidator zfv=new ZUGFeRDValidator(); - zfv.setLogAppend(parser.getOptionValue(logAppendOption)); - System.out.println(zfv.validate(filename)); - - optionsRecognized = !zfv.hasOptionsError(); - if (!zfv.wasCompletelyValid()) { - System.exit(-1); - } - - } - - if ((!optionsRecognized) || (helpRequested != null && helpRequested.booleanValue())) { - System.out.println( - "usage: --action validate -f | [-l (shows license)][--logAppend \"String to be appended to validation result log\"]"); - System.exit(-1); - } - - } - - public static void main(String[] args) { - new Main().run(args); - } - - -} diff --git a/validator/src/main/java/org/mustangproject/library/extended/PDFValidator.java b/validator/src/main/java/org/mustangproject/library/extended/PDFValidator.java deleted file mode 100644 index e6ef0fbb..00000000 --- a/validator/src/main/java/org/mustangproject/library/extended/PDFValidator.java +++ /dev/null @@ -1,343 +0,0 @@ -package org.mustangproject.library.extended; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringReader; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; - -import javax.xml.XMLConstants; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; -import javax.xml.validation.Schema; -import javax.xml.validation.SchemaFactory; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpression; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -import org.mustangproject.ZUGFeRD.ZUGFeRDImporter; -import org.riversun.bigdoc.bin.BigFileSearcher; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.verapdf.core.VeraPDFException; -import org.verapdf.features.FeatureExtractorConfig; -import org.verapdf.features.FeatureFactory; -import org.verapdf.metadata.fixer.FixerFactory; -import org.verapdf.metadata.fixer.MetadataFixerConfig; -import org.verapdf.pdfa.VeraGreenfieldFoundryProvider; -import org.verapdf.pdfa.validation.validators.ValidatorConfig; -import org.verapdf.pdfa.validation.validators.ValidatorFactory; -import org.verapdf.processor.BatchProcessor; -import org.verapdf.processor.FormatOption; -import org.verapdf.processor.ProcessorConfig; -import org.verapdf.processor.ProcessorFactory; -import org.verapdf.processor.TaskType; -import org.verapdf.processor.plugins.PluginsCollectionConfig; -import org.w3c.dom.Document; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -public class PDFValidator extends Validator { - - public PDFValidator(ValidationContext ctx) { - super(ctx); - // TODO Auto-generated constructor stub - } - - private static final Logger LOGGER = LoggerFactory.getLogger(PDFValidator.class.getCanonicalName()); // log output - // is - - private String pdfFilename; - - private String pdfReport; - - private String Signature; - - private String zfXML = null; - - protected static boolean stringArrayContains(String[] arr, String targetValue) { - return Arrays.asList(arr).contains(targetValue); - } - - public void validate() throws IrrecoverableValidationError { - - zfXML = null; - File file = new File(pdfFilename); - // file existence must have been checked before - BigFileSearcher searcher = new BigFileSearcher(); - - byte[] pdfSignature = { '%', 'P', 'D', 'F' }; - if (searcher.indexOf(file, pdfSignature) != 0) { - context.addResultItem( - new ValidationResultItem(ESeverity.fatal, "Not a PDF file "+pdfFilename).setSection(20).setPart(EPart.pdf)); - - } - - long startPDFTime = Calendar.getInstance().getTimeInMillis(); - - // Step 1 Validate PDF - - VeraGreenfieldFoundryProvider.initialise(); - // Default validator config - ValidatorConfig validatorConfig = ValidatorFactory.defaultConfig(); - // Default features config - FeatureExtractorConfig featureConfig = FeatureFactory.defaultConfig(); - // Default plugins config - PluginsCollectionConfig pluginsConfig = PluginsCollectionConfig.defaultConfig(); - // Default fixer config - MetadataFixerConfig fixerConfig = FixerFactory.defaultConfig(); - // Tasks configuring - EnumSet tasks = EnumSet.noneOf(TaskType.class); - tasks.add(TaskType.VALIDATE); - // tasks.add(TaskType.EXTRACT_FEATURES); - // tasks.add(TaskType.FIX_METADATA); - // Creating processor config - ProcessorConfig processorConfig = ProcessorFactory.fromValues(validatorConfig, featureConfig, pluginsConfig, - fixerConfig, tasks); - // Creating processor and output stream. - ByteArrayOutputStream reportStream = new ByteArrayOutputStream(); - try (BatchProcessor processor = ProcessorFactory.fileBatchProcessor(processorConfig)) { - // Generating list of files for processing - List files = new ArrayList<>(); - files.add(new File(pdfFilename)); - // starting the processor - processor.process(files, ProcessorFactory.getHandler(FormatOption.MRR, true, reportStream, 100, - processorConfig.getValidatorConfig().isRecordPasses())); - - pdfReport = reportStream.toString("utf-8").replaceAll("<\\?xml version=\"1\\.0\" encoding=\"utf-8\"\\?>", - ""); - } catch (VeraPDFException e) { - ValidationResultItem vri = new ValidationResultItem(ESeverity.exception, e.getMessage()).setSection(6) - .setPart(EPart.pdf); - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - e.printStackTrace(pw); - vri.setStacktrace(sw.toString()); - context.addResultItem(vri); - } catch (IOException excep) { - context.addResultItem(new ValidationResultItem(ESeverity.exception, excep.getMessage()).setSection(7) - .setPart(EPart.pdf).setStacktrace(excep.getStackTrace().toString())); - } - - // step 2 validate XMP - ZUGFeRDImporter zi = new ZUGFeRDImporter(pdfFilename); - String xmp = zi.getXMP(); - - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - Document docXMP; - - if (xmp.length() == 0) { - context.addResultItem(new ValidationResultItem(ESeverity.error, "Invalid XMP Metadata not found") - .setSection(17).setPart(EPart.pdf)); - } - /* - * checking for sth like EXTENDED - * INVOICE - * ZUGFeRD-invoice.xml - * 1.0 - */ - try { - DocumentBuilder builder = factory.newDocumentBuilder(); - InputSource is = new InputSource(new StringReader(xmp)); - docXMP = builder.parse(is); - - XPathFactory xpathFactory = XPathFactory.newInstance(); - - // Create XPath object XPath xpath = xpathFactory.newXPath(); XPathExpression - - XPath xpath = xpathFactory.newXPath(); - // xpath.compile("//*[local-name()=\"GuidelineSpecifiedDocumentContextParameter\"]/[local-name()=\"ID\"]"); - // evaluate expression result on XML document ndList = (NodeList) - - // get the first element - XPathExpression xpr = xpath.compile( - "//*[local-name()=\"ConformanceLevel\"]|//*[local-name()=\"Description\"]/@ConformanceLevel"); - NodeList nodes = (NodeList) xpr.evaluate(docXMP, XPathConstants.NODESET); - - if (nodes.getLength() == 0) { - context.addResultItem( - new ValidationResultItem(ESeverity.error, "XMP Metadata: ConformanceLevel not found") - .setSection(11).setPart(EPart.pdf)); - } - - boolean conformanceLevelValid=false; - for (int i = 0; i < nodes.getLength(); i++) { - - String[] valueArray = { "BASIC WL", "BASIC", "MINIMUM", "EN 16931", "COMFORT", "CIUS", "EXTENDED" }; - if (stringArrayContains(valueArray, nodes.item(i).getTextContent())) { - conformanceLevelValid=true; - } - } - if (!conformanceLevelValid) { - context.addResultItem(new ValidationResultItem(ESeverity.error, - "XMP Metadata: ConformanceLevel contains invalid value").setSection(12).setPart(EPart.pdf)); - - } - xpr = xpath.compile("//*[local-name()=\"DocumentType\"]|//*[local-name()=\"Description\"]/@DocumentType"); - nodes = (NodeList) xpr.evaluate(docXMP, XPathConstants.NODESET); - - if (nodes.getLength() == 0) { - context.addResultItem(new ValidationResultItem(ESeverity.error, "XMP Metadata: DocumentType not found") - .setSection(13).setPart(EPart.pdf)); - } - - boolean documentTypeValid=false; - for (int i = 0; i < nodes.getLength(); i++) { - if (nodes.item(i).getTextContent().equals("INVOICE")) { - documentTypeValid=true; - } - } - if (!documentTypeValid) { - context.addResultItem( - new ValidationResultItem(ESeverity.error, "XMP Metadata: DocumentType invalid") - .setSection(14).setPart(EPart.pdf)); - - } - xpr = xpath.compile( - "//*[local-name()=\"DocumentFileName\"]|//*[local-name()=\"Description\"]/@DocumentFileName"); - nodes = (NodeList) xpr.evaluate(docXMP, XPathConstants.NODESET); - - if (nodes.getLength() == 0) { - context.addResultItem( - new ValidationResultItem(ESeverity.error, "XMP Metadata: DocumentFileName not found") - .setSection(21).setPart(EPart.pdf)); - } - boolean documentFilenameValid=false; - for (int i = 0; i < nodes.getLength(); i++) { - String[] valueArray = { "factur-x.xml", "ZUGFeRD-invoice.xml", "zugferd-invoice.xml" }; - if (stringArrayContains(valueArray, nodes.item(i).getTextContent())) { - documentFilenameValid=true; - } - - // e.g. ZUGFeRD-invoice.xml - } - if (!documentFilenameValid) { - - context.addResultItem(new ValidationResultItem(ESeverity.error, - "XMP Metadata: DocumentFileName contains invalid value").setSection(19).setPart(EPart.pdf)); - } - xpr = xpath.compile("//*[local-name()=\"Version\"]|//*[local-name()=\"Description\"]/@Version"); - nodes = (NodeList) xpr.evaluate(docXMP, XPathConstants.NODESET); - - // get all child nodes - // NodeList nodes = element.getChildNodes(); - // expr.evaluate(docXMP, XPathConstants.NODESET); - // print the text content of each child - if (nodes.getLength() == 0) { - context.addResultItem(new ValidationResultItem(ESeverity.error, "XMP Metadata: Version not found") - .setSection(15).setPart(EPart.pdf)); - } - - boolean versionValid=false; - for (int i = 0; i < nodes.getLength(); i++) { - String[] valueArray = { "1.0", "2p0" }; - if (stringArrayContains(valueArray, nodes.item(i).getTextContent())) { - versionValid=true; - } // e.g. 1.0 - } - if (!versionValid) { - context.addResultItem( - new ValidationResultItem(ESeverity.error, "XMP Metadata: Version contains invalid value") - .setSection(16).setPart(EPart.pdf)); - - } - - } catch (SAXException e) { - LOGGER.error(e.getMessage(), e); - } catch (IOException e) { - LOGGER.error(e.getMessage(), e); - } catch (ParserConfigurationException e) { - LOGGER.error(e.getMessage(), e); - } catch (XPathExpressionException e) { - LOGGER.error(e.getMessage(), e); - } - zfXML = zi.getUTF8(); - - // step 3 find signatures - try { - byte[] symtraxSignature = "Symtrax".getBytes("UTF-8"); - byte[] mustangSignature = "via mustangproject".getBytes("UTF-8"); - byte[] facturxpythonSignature = "by Alexis de Lattre".getBytes("UTF-8"); - byte[] intarsysSignature = "intarsys ".getBytes("UTF-8"); - byte[] konikSignature = "Konik".getBytes("UTF-8"); - byte[] pdfMachineSignature = "pdfMachine from Broadgun Software".getBytes("UTF-8"); - - if (searcher.indexOf(file, symtraxSignature) != -1) { - Signature = "Symtrax"; - } else if (searcher.indexOf(file, mustangSignature) != -1) { - Signature = "Mustang"; - } else if (searcher.indexOf(file, facturxpythonSignature) != -1) { - Signature = "Factur/X Python"; - } else if (searcher.indexOf(file, intarsysSignature) != -1) { - Signature = "Intarsys"; - } else if (searcher.indexOf(file, konikSignature) != -1) { - Signature = "Konik"; - } else if (searcher.indexOf(file, pdfMachineSignature) != -1) { - Signature = "pdfMachine"; - } - - context.setSignature(Signature); - - } catch (UnsupportedEncodingException e) { - LOGGER.error(e.getMessage(), e); - } - - // step 4:validate additional data - HashMap additionalData=zi.getAdditionalData(); - for (String filename : additionalData.keySet()) { - // validating xml in byte[] additionalData.get(filename) - LOGGER.info("validating additionalData " + filename); - validateSchema(additionalData.get(filename), "ad/basic/additional_data_base_schema.xsd", 2, EPart.pdf); - } - - - //end - - long endTime = Calendar.getInstance().getTimeInMillis(); - if (!pdfReport.contains("validationReports compliant=\"1\"")) { - context.setInvalid(); - } - if (!pdfReport.contains("PDF/A-3")) { - context.addResultItem( - new ValidationResultItem(ESeverity.error, "Not a PDF/A-3").setSection(23).setPart(EPart.pdf)); - - } - context.addCustomXML(pdfReport + "" - + ((context.getSignature() != null) ? context.getSignature() : "unknown") - + "" + (endTime - startPDFTime) + ""); - - } - - - @Override - public void setFilename(String filename) throws IrrecoverableValidationError { - this.pdfFilename = filename; - - } - - public String getRawXML() { - return zfXML; - - } - - public String getSignature() { - return Signature; - } - -} diff --git a/validator/src/main/java/org/mustangproject/library/extended/SchematronPipeline.java b/validator/src/main/java/org/mustangproject/library/extended/SchematronPipeline.java deleted file mode 100644 index 40172544..00000000 --- a/validator/src/main/java/org/mustangproject/library/extended/SchematronPipeline.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.mustangproject.library.extended; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import javax.xml.transform.Source; -import javax.xml.transform.Templates; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.URIResolver; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; - - -public class SchematronPipeline { - static final ClassLoader cl = SchematronPipeline.class.getClassLoader(); - private static final TransformerFactory factory = getTransformerFactory(); - private static final String xslExt = ".xsl"; //$NON-NLS-1$ - private static final String resourcePath = "iso-schematron-xslt2/"; //$NON-NLS-1$ - private static final String isoDsdlXsl = resourcePath + "iso_dsdl_include" + xslExt; //$NON-NLS-1$ - private static final String isoExpXsl = resourcePath + "iso_abstract_expand" + xslExt; //$NON-NLS-1$ - private static final String isoSvrlXsl = resourcePath + "iso_svrl_for_xslt2" + xslExt; //$NON-NLS-1$ - private static final Templates cachedIsoDsdXsl = createCachedTransform(isoDsdlXsl); - private static final Templates cachedExpXsl = createCachedTransform(isoExpXsl); - private static final Templates cachedIsoSvrlXsl = createCachedTransform(isoSvrlXsl); - - private static TransformerFactory getTransformerFactory() { - TransformerFactory fact = TransformerFactory.newInstance(); - fact.setURIResolver(new ClasspathResourceURIResolver()); - return fact; - } - - static Templates createCachedTransform(final String transName) { - try { - return factory.newTemplates(new StreamSource(cl.getResourceAsStream(transName))); - } catch (TransformerConfigurationException excep) { - throw new IllegalStateException("Policy Schematron transformer XSL " + transName + " not found.", excep); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - - public static void processSchematron(InputStream schematronSource, OutputStream xslDest) - throws TransformerException, IOException { - File isoDsdResult = createTempFileResult(cachedIsoDsdXsl.newTransformer(), new StreamSource(schematronSource), - "IsoDsd"); //$NON-NLS-1$ - File isoExpResult = createTempFileResult(cachedExpXsl.newTransformer(), new StreamSource(isoDsdResult), - "ExpXsl"); //$NON-NLS-1$ - cachedIsoSvrlXsl.newTransformer().transform(new StreamSource(isoExpResult), new StreamResult(xslDest)); - isoDsdResult.delete(); - isoExpResult.delete(); - } - - private static File createTempFileResult(final Transformer transformer, final StreamSource toTransform, - final String suffix) throws TransformerException, IOException { - File result = File.createTempFile("ZUV_", suffix); //$NON-NLS-1$ - result.deleteOnExit(); - - try (FileOutputStream fos = new FileOutputStream(result)) { - transformer.transform(toTransform, new StreamResult(fos)); - } - return result; - } - - private static class ClasspathResourceURIResolver implements URIResolver { - ClasspathResourceURIResolver() { - // Do nothing, just prevents synthetic access warning. - } - - @Override - public Source resolve(String href, String base) throws TransformerException { - return new StreamSource(cl.getResourceAsStream(resourcePath + href)); - } - } - - public static void applySchematronXsl(final InputStream xmlFile, - final OutputStream policyReport) throws TransformerException { - Transformer transformer = factory.newTransformer(new StreamSource(cl.getResourceAsStream(resourcePath+"ZUGFeRDSchematronStylesheetXSLT1.xsl"))); - transformer.transform(new StreamSource(xmlFile), new StreamResult(policyReport)); - } -} diff --git a/validator/src/main/java/org/mustangproject/library/extended/ValidationContext.java b/validator/src/main/java/org/mustangproject/library/extended/ValidationContext.java deleted file mode 100644 index 29397fe4..00000000 --- a/validator/src/main/java/org/mustangproject/library/extended/ValidationContext.java +++ /dev/null @@ -1,146 +0,0 @@ -package org.mustangproject.library.extended; - -import java.util.ArrayList; -import java.util.Vector; - -import org.slf4j.Logger; - -public class ValidationContext { - protected Vector results; - protected String customXML = ""; - private String version = null; - private String profile = null; - private String signature = null; - private boolean isValid = true; - protected Logger logger; - private String filename; - - public ValidationContext(Logger log) { - logger = log; - results = new Vector(); - } - - public void addResultItem(ValidationResultItem vr) throws IrrecoverableValidationError { - results.add(vr); - - if ((vr.getSeverity() == ESeverity.fatal) || (vr.getSeverity() == ESeverity.exception) - || (vr.getSeverity() == ESeverity.error)) { - isValid = false; - - } - if (logger != null) { - if ((vr.getSeverity() == ESeverity.fatal) || (vr.getSeverity() == ESeverity.exception)) { - logger.error("Fatal Error " + vr.getSection() + ": " + vr.getMessage()); - } else if ((vr.getSeverity() == ESeverity.error)) { - logger.error("Error " + vr.getSection() + ": " + vr.getMessage()); - } else if (vr.getSeverity() == ESeverity.warning) { - logger.warn("Warning " + vr.getSection() + ": " + vr.getMessage()); - } else if (vr.getSeverity() == ESeverity.notice) { - logger.info("Notice " + vr.getSection() + ": " + vr.getMessage()); - } - } - - if ((vr.getSeverity() == ESeverity.fatal) || (vr.getSeverity() == ESeverity.exception)) { - throw new IrrecoverableValidationError(vr.getMessage()); - } - - } - - public void clearCustomXML() { - customXML = ""; - } - - public void addCustomXML(String XML) { - customXML += XML; - } - - public String getCustomXML() { - return customXML; - } - - public ValidationContext setVersion(String version) { - this.version = version; - return this; - } - - public ValidationContext setProfile(String profile) { - this.profile = profile; - return this; - } - - public ValidationContext setSignature(String signature) { - this.signature = signature; - return this; - } - - public String getVersion() { - return version; - } - - public String getProfile() { - return profile; - } - - public String getSignature() { - return signature; - } - - public boolean isValid() { - return isValid; - } - - public void clear() { - results.clear(); - isValid = true; - clearCustomXML(); - version = null; - profile = null; - signature = null; - - } - - public String getXMLResult() { - String res = getCustomXML(); - if (results.size() > 0) { - res += ""; - } - - for (ValidationResultItem validationResultItem : results) { - // xml and pdf are handled in their respective sections - res += validationResultItem.getXMLOnce() + "\n"; - } - if (results.size() > 0) { - res += ""; - } - res += ""; - return res; - } - - /*** - * - * @return the unique error types as comma separated string - */ - public String getCSVResult() { - ArrayList errorcodes = new ArrayList(); - for (ValidationResultItem validationResultItem : results) { - String errorCodeStr=Integer.toString(validationResultItem.getSection()); - errorcodes.add(errorCodeStr); - } - return String.join(",", errorcodes); - } - - public void setInvalid() { - isValid = false; - } - - public void setFilename(String filename) { - this.filename=filename; - } - public String getFilename() { - if (filename==null) { - return ""; - } else { - return filename; - } - } -} diff --git a/validator/src/main/java/org/mustangproject/library/extended/ValidationResultItem.java b/validator/src/main/java/org/mustangproject/library/extended/ValidationResultItem.java deleted file mode 100644 index 67804850..00000000 --- a/validator/src/main/java/org/mustangproject/library/extended/ValidationResultItem.java +++ /dev/null @@ -1,114 +0,0 @@ -package org.mustangproject.library.extended; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ValidationResultItem { - private static final Logger LOGGER = LoggerFactory.getLogger(ValidationResultItem.class.getCanonicalName()); // log output is - // ignored for the - // time being - - - protected String message, location=null; - protected int section =-1; - - - private ESeverity severity=ESeverity.error; - private String criterion=null; - - - private String stacktrace=null; - private boolean hasBeenOutputted=false; - - - private EPart part; - private XMLTools xt; - - public ValidationResultItem(ESeverity sev, String msg) { - setSeverity(sev); - setMessage(msg); - xt=new XMLTools(); - } - public ValidationResultItem setMessage(String msg) { - message=msg; - return this; - } - - public ValidationResultItem setSection(int sec) { - section=sec; - return this; - } - public ValidationResultItem setLocation(String loc) { - location=loc; - return this; - } - public ValidationResultItem setPart(EPart loc) { - part=loc; - return this; - } - public EPart getPart() { - return part; - } - public ValidationResultItem setSeverity(ESeverity sev) { - severity=sev; - return this; - } - public ValidationResultItem setStacktrace(String stack) { - stacktrace=stack; - return this; - } - - - public String getXML() { - String tagname="error"; - if (severity==ESeverity.exception) { - tagname="exception"; - } else if (severity==ESeverity.warning) { - tagname="warning"; - } else if (severity==ESeverity.notice) { - tagname="notice"; - } - String additionalAttributes=""; - String additionalContents=""; - if (section!=-1) { - additionalAttributes+=" type=\""+section+"\""; - } - if (location!=null) { - additionalAttributes+=" location=\""+xt.escapeAttributeEntities(location)+"\""; - } - if (criterion!=null) { - additionalAttributes+=" criterion=\""+xt.escapeAttributeEntities(criterion)+"\""; - } - if (stacktrace!=null) { - additionalContents+=""+xt.escapeAttributeEntities(stacktrace)+""; - } - hasBeenOutputted=true; - return "<"+tagname+additionalAttributes+">"+xt.escapeElementEntities(message+additionalContents)+""; - } - - public String getXMLOnce() { - if (!hasBeenOutputted) { - return getXML(); - } else { - return ""; - } - } - - public ValidationResultItem setCriterion(String test) { - criterion = test; - return this; - } - public ESeverity getSeverity() { - return severity; - } - - public int getSection() { - return section; - } - - public String getMessage() { - return message; - } - - -} diff --git a/validator/src/main/java/org/mustangproject/library/extended/Validator.java b/validator/src/main/java/org/mustangproject/library/extended/Validator.java deleted file mode 100644 index ff3e4ec3..00000000 --- a/validator/src/main/java/org/mustangproject/library/extended/Validator.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.mustangproject.library.extended; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.net.URL; - -import javax.xml.XMLConstants; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; -import javax.xml.validation.Schema; -import javax.xml.validation.SchemaFactory; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xml.sax.SAXException; - -//abstract class -public abstract class Validator { - private static final Logger LOGGER = LoggerFactory.getLogger(Validator.class.getCanonicalName()); // log output - - protected ValidationContext context; - - public Validator(ValidationContext ctx){ - this.context=ctx; - } - - //abstract method - - public abstract void setFilename(String filename) throws IrrecoverableValidationError; - public abstract void validate() throws IrrecoverableValidationError; - - public String getXMLResult() { - return context.getXMLResult(); - } - - /*** - * validates a schema, which can only be needed in XML validation - and in pdf validation for additional data - * @param xmlRawData - * @param schemaPath - */ - protected void validateSchema(byte[] xmlRawData, String schemaPath,int section, EPart part) throws IrrecoverableValidationError { - URL schemaFile = ClassLoader.getSystemResource("schema/" + schemaPath); - Source xmlData = new StreamSource(new ByteArrayInputStream(xmlRawData)); - SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); - try { - Schema schema = schemaFactory.newSchema(schemaFile); - javax.xml.validation.Validator validator = schema.newValidator(); - validator.validate(xmlData); - } catch (SAXException e) { - context.addResultItem(new ValidationResultItem(ESeverity.error, "schema validation fails:" + e) - .setSection(section).setPart(part)); - } catch (IOException e) { - LOGGER.error(e.getMessage(), e); - } - - } - - - -} diff --git a/validator/src/main/java/org/mustangproject/library/extended/XMLTools.java b/validator/src/main/java/org/mustangproject/library/extended/XMLTools.java deleted file mode 100644 index ac3936e3..00000000 --- a/validator/src/main/java/org/mustangproject/library/extended/XMLTools.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.mustangproject.library.extended; - -import org.dom4j.io.XMLWriter; - -public class XMLTools extends XMLWriter { - public String escapeAttributeEntities(String s) { - return super.escapeAttributeEntities(s); - } - public String escapeElementEntities(String s) { - return super.escapeElementEntities(s); - - } - -} diff --git a/validator/src/main/java/org/mustangproject/library/extended/XMLValidator.java b/validator/src/main/java/org/mustangproject/library/extended/XMLValidator.java deleted file mode 100644 index 430e12c3..00000000 --- a/validator/src/main/java/org/mustangproject/library/extended/XMLValidator.java +++ /dev/null @@ -1,417 +0,0 @@ -package org.mustangproject.library.extended; - -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Calendar; -import java.util.List; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.*; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpression; -import javax.xml.xpath.XPathFactory; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import com.helger.schematron.svrl.jaxb.FailedAssert; -import com.helger.schematron.svrl.jaxb.FiredRule; -import com.helger.schematron.svrl.jaxb.SchematronOutputType; -import com.helger.schematron.ISchematronResource; -import com.helger.schematron.xslt.SchematronResourceXSLT; -import com.helger.schematron.svrl.SVRLHelper; -import org.xml.sax.InputSource; - -public class XMLValidator extends Validator { - public XMLValidator(ValidationContext ctx) { - super(ctx); - } - - private static final Logger LOGGER = LoggerFactory.getLogger(XMLValidator.class.getCanonicalName()); // log output - // is - // ignored for the - // time being - - protected String zfXML = ""; - protected String filename = ""; - int firedRules = 0; - int failedRules = 0; - ISchematronResource aResSCH = null; - - public void setFilename(String name) throws IrrecoverableValidationError { // from XML Filename - filename = name; - // file existence must have been checked before - - try { - zfXML = new String(Files.readAllBytes(Paths.get(name))); - } catch (IOException e) { - - ValidationResultItem vri = new ValidationResultItem(ESeverity.exception, e.getMessage()).setSection(9) - .setPart(EPart.fx); - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - e.printStackTrace(pw); - vri.setStacktrace(sw.toString()); - context.addResultItem(vri); - } - } - - public void setStringContent(String xml) { - zfXML = xml; - } - - public static boolean matchesURI(String uri1, String uri2) { - return (uri1.equals(uri2) || uri1.startsWith(uri2 + "#")); - } - - /*** - * - * @param xmlString - * @param overrideProfileCheck - * if set to true, all ZF2 files will be checked against EN16931 - * schematron, since no other schematron is available - * @return - */ - @Override - public void validate() throws IrrecoverableValidationError { - long startXMLTime = Calendar.getInstance().getTimeInMillis(); - firedRules = 0; - failedRules = 0; - - - ByteArrayInputStream xmlByteInputStream = new ByteArrayInputStream(zfXML.getBytes(StandardCharsets.UTF_8)); - - if (zfXML.isEmpty()) { - ValidationResultItem res = new ValidationResultItem(ESeverity.exception, - "XML data not found in " + filename - + ": did you specify a pdf or xml file and does the xml file contain an embedded XML file?") - .setSection(3); - context.addResultItem(res); - - } else { - - // final ISchematronResource aResSCH = - // SchematronResourceSCH.fromFile (new File("ZUGFeRD_1p0.scmt")); - // ... DOES work but is highly deprecated (and rightly so) because - // it takes 30-40min, - - try { - - /*** - * private static final String VALID_SCHEMATRON = "test-sch/valid01.sch"; - * private static final String VALID_XMLINSTANCE = "test-xml/valid01.xml"; - * - * @Test public void testWriteValid () throws Exception { final Document aDoc = - * SchematronResourceSCH.fromClassPath (VALID_SCHEMATRON) - * .applySchematronValidation (new ClassPathResource (VALID_XMLINSTANCE)); - * - */ - - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); // otherwise we can not act namespace independently, i.e. use - // document.getElementsByTagNameNS("*",... - - DocumentBuilder db = dbf.newDocumentBuilder(); - - Document doc = db.parse(xmlByteInputStream); - - Element root = doc.getDocumentElement(); - - NodeList ndList; - - // rootNode = document.getDocumentElement(); - // ApplicableSupplyChainTradeSettlement - - // Create XPathFactory object - XPathFactory xpathFactory = XPathFactory.newInstance(); - - // Create XPath object - XPath xpath = xpathFactory.newXPath(); - XPathExpression expr = xpath.compile( - "//*[local-name()=\"GuidelineSpecifiedDocumentContextParameter\"]/*[local-name()=\"ID\"]/text()"); - // evaluate expression result on XML document - ndList = (NodeList) expr.evaluate(doc, XPathConstants.NODESET); - - for (int bookingIndex = 0; bookingIndex < ndList.getLength(); bookingIndex++) { - Node booking = ndList.item(bookingIndex); - // if there is a attribute in the tag number:value - // urn:ferd:CrossIndustryDocument:invoice:1p0:extended - // setForeignReference(booking.getTextContent()); - - context.setProfile(booking.getNodeValue()); - } - boolean isMiniumum = false; - boolean isBasic = false; - boolean isBasicWithoutLines = false; - boolean isEN16931 = false; - boolean isExtended = false; - String xsltFilename = null; - // urn:ferd:CrossIndustryDocument:invoice:1p0:extended, - // urn:ferd:CrossIndustryDocument:invoice:1p0:comfort, - // urn:ferd:CrossIndustryDocument:invoice:1p0:basic, - - // urn:cen.eu:en16931:2017 - // urn:cen.eu:en16931:2017:compliant:factur-x.eu:1p0:basic - if (root.getNodeName().equalsIgnoreCase("rsm:CrossIndustryInvoice")) { // ZUGFeRD 2.0 or Factur-X - context.setVersion("2"); - - isMiniumum = context.getProfile().contains("minimum"); - isBasic = context.getProfile().contains("basic"); - isBasicWithoutLines = context.getProfile().contains("basicwl"); - if (isBasicWithoutLines) { - isBasic = false;// basicwl also contains the string basic... - } - isEN16931 = matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017:compliant:factur-x.eu:1p0:en16931") - || matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017"); - - isExtended = context.getProfile().contains("extended"); - if (isExtended) { - isEN16931 = false;// the uri for extended is urn:cen.eu:en16931:2017#conformant#urn:zugferd.de:2p0:extended and thus contains en16931... - } - if (isMiniumum) { - LOGGER.debug("is Minimum"); - validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "zf2/MINIMUM/FACTUR-X_MINIMUM.xsd", 18, EPart.fx); - xsltFilename = "/xslt/zugferd21_minimum.xsl"; - } else if (isBasicWithoutLines) { - LOGGER.debug("is Basic/WL"); - validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "zf2/BASIC-WL/FACTUR-X_BASIC-WL.xsd", 18, EPart.fx); - xsltFilename = "/xslt/zugferd21_basicwl.xsl"; - } else if (isBasic) { - LOGGER.debug("is Basic"); - validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "zf2/BASIC/FACTUR-X_BASIC.xsd", 18, EPart.fx); - xsltFilename = "/xslt/zugferd21_basic.xsl"; - } else if (isEN16931) { - LOGGER.debug("is EN16931"); - validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "zf2/EN16931/FACTUR-X_EN16931.xsd", 18, EPart.fx); - xsltFilename = "/xslt/zugferd21_en16931.xsl"; - } else if (isExtended) { - LOGGER.debug("is EXTENDED"); - validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "zf2/EXTENDED/FACTUR-X_EXTENDED.xsd", 18, EPart.fx); - xsltFilename = "/xslt/zugferd21_extended.xsl"; - } /* - * ISchematronResource aResSCH = SchematronResourceXSLT.fromFile(new File( - * "/Users/jstaerk/workspace/ZUV/src/main/resources/ZUGFeRDSchematronStylesheet.xsl" - * )); - */ - - // takes around 10 Seconds. // - // http://www.bentoweb.org/refs/TCDL2.0/tsdtf_schematron.html // explains that - // this xslt can be created using sth like - // saxon java net.sf.saxon.Transform -o tcdl2.0.tsdtf.sch.tmp.xsl -s - // tcdl2.0.tsdtf.sch iso_svrl.xsl - - } else { // ZUGFeRD 1.0 - context.setVersion("1"); - // - if ((!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:basic")) - && (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort")) - && (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:extended"))) { - context.addResultItem(new ValidationResultItem(ESeverity.error, "Unsupported profile type") - .setSection(25).setPart(EPart.fx)); - } - validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "zf1/ZUGFeRD1p0.xsd", 18, EPart.fx); - - xsltFilename = "/xslt/ZUGFeRD_1p0.xslt"; - } - if (context.getVersion().equals("2")) { - if ((!matchesURI(context.getProfile(), "urn:factur-x.eu:1p0:minimum")) - && (!matchesURI(context.getProfile(), "urn:zugferd.de:2p0:minimum")) - && (!matchesURI(context.getProfile(), "urn:factur-x.eu:1p0:basicwl")) - && (!matchesURI(context.getProfile(), "urn:zugferd.de:2p0:basicwl")) - && (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic")) - && (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#compliant#urn:zugferd.de:2p0:basic")) - && (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017")) - && (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended")) - && (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#conformant#urn:zugferd.de:2p0:extended"))) { - context.addResultItem( - new ValidationResultItem(ESeverity.error, "Unsupported profile type " + context.getProfile()) - .setSection(25).setPart(EPart.fx)); - - } - } else /** v1 */ {//urn:ferd:invoice:rc:comfort - if ((!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:basic")) - && (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort")) - && (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:extended"))) { - context.addResultItem(new ValidationResultItem(ESeverity.error, "Unsupported profile type") - .setSection(25).setPart(EPart.fx)); - - } - } - - // main schematron validation - validateSchematron(zfXML, xsltFilename, 4, ESeverity.error); - - if (context.getVersion().equals("2") - && isEN16931) { - //additionally validate against CEN - validateSchematron(zfXML, "/xslt/cii16931schematron/EN16931-CII-validation.xslt", 24, ESeverity.error); - - validateXR(zfXML); - } - - - } catch (IrrecoverableValidationError er) { - throw er; - } catch (Exception e) { - ValidationResultItem vri = new ValidationResultItem(ESeverity.exception, e.getMessage()).setSection(22) - .setPart(EPart.fx); - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - e.printStackTrace(pw); - vri.setStacktrace(sw.toString()); - context.addResultItem(vri); - } - - } - long endTime = Calendar.getInstance().getTimeInMillis(); - - context.addCustomXML("" + ((context.getVersion() != null) ? context.getVersion() : "invalid") - + "" + ((context.getProfile() != null) ? context.getProfile() : "invalid") + - "" + firedRules + "" + failedRules + "" + "" + (endTime - startXMLTime) + ""); - - } - - protected String getXRValidationResult(String xml) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - TransformerFactory factory = TransformerFactory.newInstance(); - - try { - // Use the factory to create a template containing the xsl file - Templates template = factory.newTemplates(new StreamSource( - this.getClass().getResourceAsStream("/xslt/XRechnung-CII-validation.xsl"))); - - // Use the template to create a transformer - Transformer xformer = template.newTransformer(); - - // Prepare the input and output files - - Source source = new StreamSource(new ByteArrayInputStream(xml.getBytes())); - Result result = new StreamResult(baos); - - // Apply the xsl file to the source file and write the result - // to the output file - xformer.transform(source, result); - - } catch (Exception ex) { - LOGGER.error(ex.getMessage(), ex); - } - return baos.toString(); - - } - - public void validateXR(String xml) throws IrrecoverableValidationError { - -/* - DocumentBuilderFactory docbfactory = DocumentBuilderFactory.newInstance(); - try { - DocumentBuilder builder = docbfactory.newDocumentBuilder(); - InputSource is = new InputSource(new StringReader(getXRValidationResult(xml))); - Document docXMP = builder.parse(is); - - XPathFactory xpathFactory = XPathFactory.newInstance(); - - // Create XPath object XPath xpath = xpathFactory.newXPath(); XPathExpression - - XPath xpath = xpathFactory.newXPath(); - // xpath.compile("//*[local-name()=\"GuidelineSpecifiedDocumentContextParameter\"]/[local-name()=\"ID\"]"); - // evaluate expression result on XML document ndList = (NodeList) - - // get the first element - XPathExpression xpr = xpath.compile( - "//*[local-name()=\"failed-assert\"]"); - NodeList nodes = (NodeList) xpr.evaluate(docXMP, XPathConstants.NODESET); - for (int nodeIndex = 0; nodeIndex < nodes.getLength(); nodeIndex++) { - String loc=nodes.item(nodeIndex).getAttributes().getNamedItem("location").getTextContent(); - NodeList failedSubNodes=nodes.item(nodeIndex).getChildNodes(); - for (int failedSubNodeIndex = 0; failedSubNodeIndex < nodes.getLength(); failedSubNodeIndex++) { - - if (failedSubNodes.item(failedSubNodeIndex).getNodeName().equals("svrl:text")) { - context.addResultItem( - new ValidationResultItem(ESeverity.warning, failedSubNodes.item(failedSubNodeIndex).getTextContent()) - .setLocation(loc).setSection(27).setPart(EPart.xr)); - - } - } - - - } - } catch (Exception ex) { - LOGGER.error(ex.getMessage(), ex); - - } -*/ - - validateSchematron(xml, "/xslt/XRechnung-CII-validation.xslt",27, ESeverity.notice); - - } - - - public void validateSchematron(String xml, String xsltFilename, int section, ESeverity severity) throws IrrecoverableValidationError { - ISchematronResource aResSCH = null; - aResSCH = SchematronResourceXSLT.fromClassPath(xsltFilename); - if (aResSCH != null) { - if (!aResSCH.isValidSchematron()) { - throw new IllegalArgumentException(xsltFilename + " is invalid Schematron!"); - } - - SchematronOutputType sout; - try { - sout = aResSCH - .applySchematronValidationToSVRL(new StreamSource(new StringReader(xml))); - } catch (Exception e) { - throw new IrrecoverableValidationError(e.getMessage()); - } - - List failedAsserts = sout.getActivePatternAndFiredRuleAndFailedAssert(); - if (failedAsserts.size() > 0) { - for (Object object : failedAsserts) { - if (object instanceof FailedAssert) { - - FailedAssert failedAssert = (FailedAssert) object; - LOGGER.info("FailedAssert ", failedAssert); - - context.addResultItem(new ValidationResultItem(severity, SVRLHelper.getAsString(failedAssert.getText())) - .setLocation(failedAssert.getLocation()).setCriterion(failedAssert.getTest()).setSection(section) - .setPart(EPart.fx)); - failedRules++; - } else if (object instanceof FiredRule) { - firedRules++; - } - } - - } - if (firedRules == 0) { - context.addResultItem(new ValidationResultItem(ESeverity.error, "No rules matched, XML to minimal?").setSection(26) - .setPart(EPart.fx)); - - } - // for (String currentString : sout.getText()) { - // schematronValidationString += "" + currentString + ""; - // } - - // schematronValidationString += new SVRLMarshaller ().getAsString (sout); - // returns the complete SVRL - - } - } - - - public int getFiredRules() { - return firedRules; - } - - public int getFailedRules() { - return failedRules; - } - - -} diff --git a/validator/src/main/java/org/mustangproject/library/extended/ZUGFeRDValidator.java b/validator/src/main/java/org/mustangproject/library/extended/ZUGFeRDValidator.java deleted file mode 100644 index 6b01b662..00000000 --- a/validator/src/main/java/org/mustangproject/library/extended/ZUGFeRDValidator.java +++ /dev/null @@ -1,292 +0,0 @@ -package org.mustangproject.library.extended; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.StringWriter; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; - -import javax.xml.bind.annotation.adapters.HexBinaryAdapter; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.dom4j.DocumentException; -import org.dom4j.DocumentHelper; -import org.dom4j.io.OutputFormat; -import org.dom4j.io.XMLWriter; -import org.riversun.bigdoc.bin.BigFileSearcher; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.SAXParseException; - -//abstract class -public class ZUGFeRDValidator { - private static final Logger LOGGER = LoggerFactory.getLogger(ZUGFeRDValidator.class.getCanonicalName()); // log - // output - protected ValidationContext context = new ValidationContext(LOGGER); - protected String sha1Checksum; - protected boolean pdfValidity; - protected boolean displayXMLValidationOutput; - protected long startTime; - protected boolean optionsRecognized; - protected String Signature; - protected boolean wasCompletelyValid = false; - protected String logAppend=null; - - /*** - * within the validation it turned out something in the options was wrong, e.g. - * the file did not exist. recommendation to show the help text again. Should be - * false if XML or PDF file was found - */ - public boolean hasOptionsError() { - return !optionsRecognized; - - } - - public void setLogAppend(String tobeappended) { - logAppend = tobeappended; - } - - /*** - * in case the result was not valid the error code of the app will be set to -1 - * - * @return - */ - public boolean wasCompletelyValid() { - return wasCompletelyValid; - - } - - /*** - * performs a validation on the file filename - * - * @param filename - * @return - */ - public String validate(String filename) { - boolean xmlValidity; - context.clear(); - StringBuffer finalStringResult = new StringBuffer(); - SimpleDateFormat isoDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //$NON-NLS-1$ - Date date = new Date(); - startTime = Calendar.getInstance().getTimeInMillis(); - try { - Path path = Paths.get(filename); - context.setFilename(path.getFileName().toString());// set filename without path - - } catch (NullPointerException ex) { - // ignore - } - finalStringResult - .append(""); - - try { - - if (filename == null) { - optionsRecognized = false; - context.addResultItem(new ValidationResultItem(ESeverity.fatal, "Filename not specified").setSection(10) - .setPart(EPart.pdf)); - } - - PDFValidator pdfv = new PDFValidator(context); - File file = new File(filename); - if (!file.exists()) { - context.addResultItem( - new ValidationResultItem(ESeverity.fatal, "File not found").setSection(1).setPart(EPart.pdf)); - } else if (file.length() < 32) { - // with less then 32 bytes it can not even be a proper XML file - context.addResultItem( - new ValidationResultItem(ESeverity.fatal, "File too small").setSection(5).setPart(EPart.pdf)); - } else { - BigFileSearcher searcher = new BigFileSearcher(); - XMLValidator xv = new XMLValidator(context); - - byte[] pdfSignature = { '%', 'P', 'D', 'F' }; - boolean isPDF = searcher.indexOf(file, pdfSignature) == 0; - if (isPDF) { - pdfv.setFilename(filename); - - optionsRecognized = true; - try { - if (!file.exists()) { - context.addResultItem( - new ValidationResultItem(ESeverity.exception, "File " + filename + " not found") - .setSection(1)); - } - } catch (IrrecoverableValidationError irx) { - // @todo log - } - - finalStringResult.append(""); - optionsRecognized = true; - try { - pdfv.validate(); - - sha1Checksum = calcSHA1(file); - - // Validate PDF - - finalStringResult.append(pdfv.getXMLResult()); - pdfValidity = context.isValid(); - - Signature = context.getSignature(); - context.clear();// clear sets valid to true again - if (pdfv.getRawXML() != null) { - xv.setStringContent(pdfv.getRawXML()); - displayXMLValidationOutput = true; - } else { - context.addResultItem( - new ValidationResultItem(ESeverity.exception, "XML could not be extracted") - .setSection(17)); - } - } catch (IrrecoverableValidationError irx) { - // @todo log - } - - finalStringResult.append("\n"); - - context.clearCustomXML(); - } else { - boolean isXML = false; - try { - - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db = dbf.newDocumentBuilder(); - - Document doc = db.parse(file); - - Element root = doc.getDocumentElement(); - isXML=true;//no exception so far - - } - catch (Exception ex) { - // probably no xml file, sth like SAXParseException content not allowed in prolog - // ignore isXML is already false - // in the tests, this may error-out anyway - } - if (isXML) { - pdfValidity = true; - optionsRecognized = true; - xv.setFilename(filename); - if (file.exists()) { - sha1Checksum = calcSHA1(file); - } - - displayXMLValidationOutput = true; - - } else { - optionsRecognized = false; - context.addResultItem(new ValidationResultItem(ESeverity.exception, - "File does not look like PDF nor XML (contains neither %PDF nor "); - try { - xv.validate(); - } catch (IrrecoverableValidationError irx) { - // @todo log - } - finalStringResult.append(xv.getXMLResult()); - finalStringResult.append(""); - context.clearCustomXML(); - } - - if ((isPDF)&&(!pdfValidity)) { - context.setInvalid(); - } - - } - } - - catch (IrrecoverableValidationError irx) { - // @todo log - } finally { - finalStringResult.append(context.getXMLResult()); - finalStringResult.append(""); - - } - - OutputFormat format = OutputFormat.createPrettyPrint(); - StringWriter sw = new StringWriter(); - org.dom4j.Document document = null; - try { - document = DocumentHelper.parseText(new String(finalStringResult)); - } catch (DocumentException e1) { - LOGGER.error(e1.getMessage()); - } - XMLWriter writer = new XMLWriter(sw, format); - try { - writer.write(document); - } catch (Exception e) { - LOGGER.error(e.getMessage()); - } - - xmlValidity = context.isValid(); - long duration = Calendar.getInstance().getTimeInMillis() - startTime; - - String toBeAppended=""; - if (logAppend!=null) { - toBeAppended=logAppend; - } - - - - LOGGER.info("Parsed PDF:" + (pdfValidity ? "valid" : "invalid") + " XML:" + (xmlValidity ? "valid" : "invalid") - + " Signature:" + Signature + " Checksum:" + sha1Checksum + " Profile:" + context.getProfile() - + " Version:" + context.getVersion() + " Took:" + duration + "ms Errors:["+context.getCSVResult()+"] "+toBeAppended); - wasCompletelyValid = ((pdfValidity) && (xmlValidity)); - return sw.toString(); - } - - /** - * Read the file and calculate the SHA-1 checksum - * - * @param file the file to read - * @return the hex representation of the SHA-1 using uppercase chars - * @throws FileNotFoundException if the file does not exist, is a directory - * rather than a regular file, or for some - * other reason cannot be opened for reading - * @throws IOException if an I/O error occurs - * @throws NoSuchAlgorithmException should never happen - */ - private static String calcSHA1(File file) { - MessageDigest sha1 = null; - try { - - sha1 = MessageDigest.getInstance("SHA-1"); - InputStream input = new FileInputStream(file); - byte[] buffer = new byte[8192]; - int len = input.read(buffer); - - while (len != -1) { - sha1.update(buffer, 0, len); - len = input.read(buffer); - } - input.close(); - } catch (FileNotFoundException e) { - LOGGER.error(e.getMessage(), e); - } catch (IOException e) { - LOGGER.error(e.getMessage(), e); - } catch (NoSuchAlgorithmException e) { - LOGGER.error(e.getMessage(), e); - } - if (sha1 == null) { - return ""; - } else { - return new HexBinaryAdapter().marshal(sha1.digest()); - } - } - -} diff --git a/validator/src/test/java/org/mustangproject/library/extended/MiscValidatorTest.java b/validator/src/test/java/org/mustangproject/library/extended/MiscValidatorTest.java deleted file mode 100644 index f4b9ac8c..00000000 --- a/validator/src/test/java/org/mustangproject/library/extended/MiscValidatorTest.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.mustangproject.library.extended; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; - -public class MiscValidatorTest extends ResourceCase { - - - public void testInvalidFileValidation() { - - ZUGFeRDValidator zfv=new ZUGFeRDValidator(); - - String res=zfv.validate(null); - assertTrue(res.matches("<\\?xml version=\"1.0\" encoding=\"UTF-8\"\\?>\n" + - "\n" + - "\n" + - " \n" + - " Filename not specified \n" + - " \n" + - " \n" + - "\n" + - "")); - - res=zfv.validate("/dhfkbv/sfjkh"); - assertTrue(res.matches("<\\?xml version=\"1.0\" encoding=\"UTF-8\"\\?>\n" + - "\n" + - "\n" + - " \n" + - " File not found \n" + - " \n" + - " \n" + - "\n")); - - boolean noExceptionOccurred=true; - File tempFile=null; - try { - tempFile = File.createTempFile("hello", ".tmp"); - } catch (IOException e) { - noExceptionOccurred=true; - } - assertTrue(noExceptionOccurred); - - res=zfv.validate(tempFile.getAbsolutePath()); - assertTrue(res.matches("<\\?xml version=\"1.0\" encoding=\"UTF-8\"\\?>\n" + - "\n" + - "\n" + - " \n" + - " File too small \n" + - " \n" + - " \n" + - "\n" + - "")); - - - String fileContent = "ladhvkdbfk wkhfbkhdhkb svbkfsvbksfbvk sdvsdvbksjdvbkfdsv sdvbskdvbsjhkvbfskh dvbskfvbkfsbvke" - + "ladhvkdbfk wkhfbkhdhkb svbkfsvbksfbvk sdvsdvbksjdvbkfdsv sdvbskdvbsjhkvbfskh dvbskfvbkfsbvke"; - noExceptionOccurred=true; - BufferedWriter writer; - try { - writer = new BufferedWriter(new FileWriter(tempFile)); - writer.write(fileContent); - writer.close(); - } catch (IOException e) { - noExceptionOccurred=false; - } - assertTrue(noExceptionOccurred); - - - res=zfv.validate(tempFile.getAbsolutePath()); - assertTrue(res.matches("<\\?xml version=\"1.0\" encoding=\"UTF-8\"\\?>\n" + - "\n" + - "\n" + - " \n" + - " File does not look like PDF nor XML \\(contains neither %PDF nor <\\?xml\\) \n" + - " \n" + - " \n" + - "\n" + - "")); - - - // clean up - tempFile.delete(); - - } - -} diff --git a/validator/src/test/java/org/mustangproject/library/extended/PDFValidatorTest.java b/validator/src/test/java/org/mustangproject/library/extended/PDFValidatorTest.java deleted file mode 100644 index 06b6a31e..00000000 --- a/validator/src/test/java/org/mustangproject/library/extended/PDFValidatorTest.java +++ /dev/null @@ -1,139 +0,0 @@ -package org.mustangproject.library.extended; - -import java.io.File; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class PDFValidatorTest extends ResourceCase { - private static final Logger LOGGER = LoggerFactory.getLogger(ZUGFeRDValidator.class.getCanonicalName()); // log - - public void testPDFValidation() { - ValidationContext vc = new ValidationContext(null); - PDFValidator pv = new PDFValidator(vc); - - try { - - File tempFile = getResourceAsFile("XMLinvalidV2PDF.pdf");// need a more invalid file here - - pv.setFilename(tempFile.getAbsolutePath()); - pv.validate(); - // assertEquals("", pv.getXMLResult()); - - // - tempFile = getResourceAsFile("Facture_F20180027.pdf"); - pv.setFilename(tempFile.getAbsolutePath()); - pv.validate(); - String actual = pv.getXMLResult(); - assertEquals(true, actual.contains("summary status='valid")); - assertEquals(false, actual.contains("summary status='invalid")); - - XMLValidator xv = new XMLValidator(vc); - xv.setStringContent(pv.getRawXML()); - xv.validate(); - actual = vc.getXMLResult(); - - assertEquals(true, actual.contains("validationReport profileName=\"PDF/A-3")); - assertEquals(true, actual.contains("batchSummary totalJobs=\"1\" failedToParse=\"0\" encrypted=\"0\"")); - assertEquals(true, - actual.contains("validationReports compliant=\"1\" nonCompliant=\"0\" failedJobs=\"0\">")); - // test some xml - // assertEquals(true, actual.contains("[CII-DT-031] - currencyID should not be - // present")); - // test some binary signature recognition - assertEquals(true, actual.contains("2")); - - // valid one - tempFile = getResourceAsFile("validV2PDF.pdf"); - - pv.setFilename(tempFile.getAbsolutePath()); - vc.clear(); - pv.validate(); - actual = pv.getXMLResult(); - assertEquals(true, actual.contains("validationReport profileName=\"PDF/A-3")); - assertEquals(true, actual.contains("batchSummary totalJobs=\"1\" failedToParse=\"0\" encrypted=\"0\"")); - assertEquals(true, - actual.contains("validationReports compliant=\"1\" nonCompliant=\"0\" failedJobs=\"0\">")); - - assertEquals(false, actual.contains("XMP Metadata: ConformanceLevel contains invalid value")); - - tempFile = getResourceAsFile("attributeBasedXMP_zugferd_2p0_EN16931_Einfach.pdf"); - - pv.setFilename(tempFile.getAbsolutePath()); - vc.clear(); - pv.validate(); - actual = pv.getXMLResult(); - - assertEquals(false, actual.contains("\n" - * + - * " Eine Rechnung (INVOICE) muss die Summe der Rechnungspositionen-Nettobeträge „Sum of Invoice line net amount“ (BT-106) enthalten.\n" - * + - * "\n" - * + - * " Der Inhalt des Elementes „Invoice total amount without VAT“ (BT-109) entspricht der Summe aller Inhalte der Elemente „Invoice line net amount“ (BT-131) abzüglich der Summe aller in der Rechnung enthaltenen Nachlässe der Dokumentenebene „Sum of allowances on document level“ (BT-107) zuzüglich der Summe aller in der Rechnung enthaltenen Abgaben der Dokumentenebene „Sum of charges on document level“ (BT-108).\n" - * + - * "\n" - * + - * " Der Inhalt des Elementes „Invoice total amount with VAT“ (BT-112) entspricht der Summe des Inhalts des Elementes „Invoice total amount without VAT“ (BT-109) und des Elementes „Invoice total VAT amount“ (BT-110).\n" - * + - * "\n" - * + - * " Der Inhalt des Elementes „Sum of Invoice line net amount“ (BT-106) entspricht der Summe aller Inhalte der Elemente „Invoice line net amount“ (BT-131).\n" - * + - * "\n" - * + - * " Eine Rechnung (INVOICE) muss den Erwerbernamen „Buyer name“ (BT-44) enthalten.\n" - * + - * "\n" - * + " Das Element 'ram:Name' muss genau 1 mal auftreten.\n" + - * "\n" - * + " Das Element 'ram:LineTotalAmount' muss genau 1 mal auftreten.\n" - * + - * "\n" - * + " Wert von '@unitCode' ist unzulässig.\n" + - * "")); - * - */ - - tempFile = getResourceAsFile("invalidV2Profile.xml"); - - xv.setFilename(tempFile.getAbsolutePath()); - - xv.validate(); - } catch (IrrecoverableValidationError e) { - // ignore, will be in XML output anyway - } - assertTrue(xv.getXMLResult().contains(""; - - assertThat(content).valueByXPath("count(//error)") - .asInt() - .isGreaterThan(1); //2 errors are OK because there is a known bug - - - assertThat(content).valueByXPath("//error[@type=\"4\"]") - .asString() - .contains( - "In Deutschland sind die Profile MINIMUM und BASIC WL nur als Buchungshilfe (TypeCode: 751) zugelassen."); - - - ctx.clear(); - tempFile = getResourceAsFile("validV2Basic.xml"); - try { - - xv.setFilename(tempFile.getAbsolutePath()); - xv.validate(); - assertEquals(true, xv.getXMLResult().contains("valid") && !xv.getXMLResult().contains("invalid")); - - ctx.clear(); - tempFile = getResourceAsFile("ZUGFeRD-invoice_rabatte_3_abschlag_duepayableamount.xml"); - xv.setFilename(tempFile.getAbsolutePath()); - xv.validate(); - assertEquals(true, xv.getXMLResult().contains("valid") && !xv.getXMLResult().contains("invalid")); - - ctx.clear(); - tempFile = getResourceAsFile("valid_Avoir_FR_type380_minimum_factur-x.xml"); - xv.setFilename(tempFile.getAbsolutePath()); - xv.validate(); - - source = Input.fromString("" + xv.getXMLResult() + "").build(); - content = xpath.evaluate("/validation/summary/@status", source); - assertEquals("invalid", content); - - // assertEquals(true, xv.getXMLResult().contains("valid") && - // !xv.getXMLResult().contains("invalid")); - - /* - * this test failure might have to be upstreamed ctx.clear(); tempFile = - * getResourceAsFile( - * "ZUGFeRD-invoice_rabatte_4_abschlag_taxbasistotalamount.xml"); - * xv.setFilename(tempFile.getAbsolutePath()); xv.validate(); assertEquals(true, - * xv.getXMLResult().contains("valid") && - * !xv.getXMLResult().contains("invalid")); - */ - ctx.clear(); - tempFile = getResourceAsFile("attributeBasedXMP_zugferd_2p0_EN16931_Einfach_corrected.xml"); - xv.setFilename(tempFile.getAbsolutePath()); - xv.validate(); - assertEquals(true, xv.getXMLResult().contains("valid") && !xv.getXMLResult().contains("invalid")); - - ctx.clear(); - tempFile = getResourceAsFile("validZREtestZugferd.xml"); - xv.setFilename(tempFile.getAbsolutePath()); - xv.validate(); - - source = Input.fromString("" + xv.getXMLResult() + "").build(); - content = xpath.evaluate("/validation/summary/@status", source); - assertEquals("invalid", content); - - } catch (IrrecoverableValidationError e) { - // ignore, will be in XML output anyway - } - - } - - public void testZF1XMLValidation() { - ValidationContext ctx = new ValidationContext(null); - XMLValidator xv = new XMLValidator(ctx); - File tempFile = getResourceAsFile("validV1.xml"); - try { - xv.setFilename(tempFile.getAbsolutePath()); - xv.validate(); - assertEquals(true, xv.getXMLResult().contains("valid") && !xv.getXMLResult().contains("invalid")); - - tempFile = getResourceAsFile("invalidV1ExtraTags.xml"); - xv.setFilename(tempFile.getAbsolutePath()); - xv.validate(); - assertEquals(true, xv.getXMLResult().contains("invalid")); - - tempFile = getResourceAsFile("invalidV1TooMinimal.xml"); - xv.setFilename(tempFile.getAbsolutePath()); - xv.validate(); - assertEquals(true, xv.getXMLResult().contains(" part, this one includes the root element and - * the global part as well - */ - public void testXMLValidation() { - File tempFile = getResourceAsFile("validV2.xml"); - ZUGFeRDValidator zfv = new ZUGFeRDValidator(); - - String res = zfv.validate(tempFile.getAbsolutePath()); - - assertThat(res).valueByXPath("count(//error)") - .asInt() - .isEqualTo(0); - - assertThat(res).valueByXPath("count(//notice)") - .asInt() - .isEqualTo(3); // 3 notices RE XRechnung - assertThat(res).valueByXPath("/validation/summary/@status") - .asString() - .isEqualTo("valid");// expect to be valid because XR notices are, well, only notices - assertThat(res).valueByXPath("/validation/xml/summary/@status") - .asString() - .isEqualTo("valid"); - - } -}