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
+
+
+
+
+