diff --git a/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/FormatUtils.java b/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/FormatUtils.java index cb9ab3635a..e1299934cb 100644 --- a/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/FormatUtils.java +++ b/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/FormatUtils.java @@ -35,8 +35,8 @@ public class FormatUtils { private static final double BYTES_IN_TERABYTE = BYTES_IN_GIGABYTE * 1024; // for Time Durations - private static final String NANOS = join(UNION, "ns", "nano", "nanos", "nanoseconds"); - private static final String MILLIS = join(UNION, "ms", "milli", "millis", "milliseconds"); + private static final String NANOS = join(UNION, "ns", "nano", "nanos", "nanosecond", "nanoseconds"); + private static final String MILLIS = join(UNION, "ms", "milli", "millis", "millisecond", "milliseconds"); private static final String SECS = join(UNION, "s", "sec", "secs", "second", "seconds"); private static final String MINS = join(UNION, "m", "min", "mins", "minute", "minutes"); private static final String HOURS = join(UNION, "h", "hr", "hrs", "hour", "hours"); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java index c4da7b6ae9..3634850b3b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java @@ -87,7 +87,7 @@ public class FingerprintFactory { // no fingerprint value public static final String NO_VALUE = "NO_VALUE"; - private static final String FLOW_CONFIG_XSD = "/FlowConfiguration.xsd"; + static final String FLOW_CONFIG_XSD = "/FlowConfiguration.xsd"; private static final String ENCRYPTED_VALUE_PREFIX = "enc{"; private static final String ENCRYPTED_VALUE_SUFFIX = "}"; private final StringEncryptor encryptor; @@ -115,6 +115,11 @@ public class FingerprintFactory { } } + public FingerprintFactory(final StringEncryptor encryptor, final DocumentBuilder docBuilder) { + this.encryptor = encryptor; + this.flowConfigDocBuilder = docBuilder; + } + /** * Creates a fingerprint of a flow. The order of elements or attributes in the flow does not influence the fingerprint generation. * This method does not accept a FlowController, which means that Processors cannot be created in order to verify default property diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/resources/FlowConfiguration.xsd b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/resources/FlowConfiguration.xsd index 08038bd49f..4607320270 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/resources/FlowConfiguration.xsd +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/resources/FlowConfiguration.xsd @@ -315,7 +315,7 @@ - + diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/fingerprint/FingerprintFactoryTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/fingerprint/FingerprintFactoryTest.java index bb12e7842c..5b4e8416be 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/fingerprint/FingerprintFactoryTest.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/fingerprint/FingerprintFactoryTest.java @@ -16,8 +16,9 @@ */ package org.apache.nifi.fingerprint; +import static org.apache.nifi.fingerprint.FingerprintFactory.FLOW_CONFIG_XSD; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; @@ -26,6 +27,15 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.junit.Before; import org.junit.Test; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; /** */ @@ -42,8 +52,6 @@ public class FingerprintFactoryTest { public void testSameFingerprint() throws IOException { final String fp1 = fingerprinter.createFingerprint(getResourceBytes("/nifi/fingerprint/flow1a.xml"), null); final String fp2 = fingerprinter.createFingerprint(getResourceBytes("/nifi/fingerprint/flow1b.xml"), null); - System.out.println(fp1); - System.out.println(fp2); assertEquals(fp1, fp2); } @@ -51,7 +59,7 @@ public class FingerprintFactoryTest { public void testDifferentFingerprint() throws IOException { final String fp1 = fingerprinter.createFingerprint(getResourceBytes("/nifi/fingerprint/flow1a.xml"), null); final String fp2 = fingerprinter.createFingerprint(getResourceBytes("/nifi/fingerprint/flow2.xml"), null); - assertFalse(fp1.equals(fp2)); + assertNotEquals(fp1, fp2); } @Test @@ -61,8 +69,48 @@ public class FingerprintFactoryTest { assertTrue(fingerprint.contains("In Connection")); } + @Test + public void testSchemaValidation() throws IOException { + FingerprintFactory fp = new FingerprintFactory(null, getValidatingDocumentBuilder()); + final String fingerprint = fp.createFingerprint(getResourceBytes("/nifi/fingerprint/validating-flow.xml"), null); + } + private byte[] getResourceBytes(final String resource) throws IOException { return IOUtils.toByteArray(FingerprintFactoryTest.class.getResourceAsStream(resource)); } + private DocumentBuilder getValidatingDocumentBuilder() { + final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setNamespaceAware(true); + final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + final Schema schema; + try { + schema = schemaFactory.newSchema(FingerprintFactory.class.getResource(FLOW_CONFIG_XSD)); + } catch (final Exception e) { + throw new RuntimeException("Failed to parse schema for file flow configuration.", e); + } + try { + documentBuilderFactory.setSchema(schema); + DocumentBuilder docBuilder = documentBuilderFactory.newDocumentBuilder(); + docBuilder.setErrorHandler(new ErrorHandler() { + @Override + public void warning(SAXParseException e) throws SAXException { + throw e; + } + + @Override + public void error(SAXParseException e) throws SAXException { + throw e; + } + + @Override + public void fatalError(SAXParseException e) throws SAXException { + throw e; + } + }); + return docBuilder; + } catch (final Exception e) { + throw new RuntimeException("Failed to create document builder for flow configuration.", e); + } + } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/resources/nifi/fingerprint/validating-flow.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/resources/nifi/fingerprint/validating-flow.xml new file mode 100644 index 0000000000..a762dc9e1d --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/resources/nifi/fingerprint/validating-flow.xml @@ -0,0 +1,157 @@ + + + + 10 + 5 + + 289ff050-015a-1000-b21b-a39f56e56729 + NiFi Flow + + + + 28a67671-015a-1000-77dd-8130e16012ec + PutFile + + + + + write a file + org.apache.nifi.processors.standard.PutFile + 1 + 0 sec + 3000 millisecond + 1 sec + WARN + false + STOPPED + TIMER_DRIVEN + ALL + 0 + + Directory + + + Conflict Resolution Strategy + fail + + + Create Missing Directories + true + + + Maximum File Count + + + Last Modified Time + + + Permissions + + + Owner + + + Group + + + + 28a6579e-015a-1000-2856-975c9a5af27e + GetFile + + + + + + org.apache.nifi.processors.standard.GetFile + 1 + 0 sec + 30 sec + 1000000000 nanosecond + WARN + false + STOPPED + TIMER_DRIVEN + ALL + 0 + + Input Directory + + + File Filter + [^\.].* + + + Path Filter + + + Batch Size + 10 + + + Keep Source File + false + + + Recurse Subdirectories + true + + + Polling Interval + 0 sec + + + Ignore Hidden Files + true + + + Minimum File Age + 0 sec + + + Maximum File Age + + + Minimum File Size + 0 B + + + Maximum File Size + + + + 28a77d72-015a-1000-32e4-c6fe548f5c9d + + + + + 0 + 0 + 28a6579e-015a-1000-2856-975c9a5af27e + 289ff050-015a-1000-b21b-a39f56e56729 + PROCESSOR + 28a67671-015a-1000-77dd-8130e16012ec + 289ff050-015a-1000-b21b-a39f56e56729 + PROCESSOR + success + 10000 + 1 GB + 1 hour + org.apache.nifi.prioritizer.FirstInFirstOutPrioritizer + + + + +