SLING-7672 The feature model converter should not overwrite exising newer file.
diff --git a/pom.xml b/pom.xml
index 458324b..0d305ee 100644
--- a/pom.xml
+++ b/pom.xml
@@ -121,6 +121,12 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.utils</artifactId>
+            <version>1.11.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.feature</artifactId>
             <version>0.1.0</version>
diff --git a/src/main/java/org/apache/sling/feature/modelconverter/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/FeatureToProvisioning.java
index 9896aff..6754456 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/FeatureToProvisioning.java
@@ -60,8 +60,15 @@
     private static final Logger LOGGER = LoggerFactory.getLogger(FeatureToProvisioning.class);
     static final String PROVISIONING_MODEL_NAME_VARIABLE = "provisioning.model.name";
 
-    public static void convert(File file, String output, ArtifactManager am) throws IOException {
-        org.apache.sling.feature.Feature feature = IOUtils.getFeature(file.getAbsolutePath(), am, SubstituteVariables.NONE);
+    public static void convert(File inputFile, File outputFile, ArtifactManager am) throws IOException {
+        if (outputFile.exists()) {
+            if (outputFile.lastModified() > inputFile.lastModified()) {
+                LOGGER.debug("Skipping the generation of {} as this file already exists and is newer.", outputFile);
+                return;
+            }
+        }
+
+        org.apache.sling.feature.Feature feature = IOUtils.getFeature(inputFile.getAbsolutePath(), am, SubstituteVariables.NONE);
 
         Object featureNameVar = feature.getVariables().remove(PROVISIONING_MODEL_NAME_VARIABLE);
         String featureName;
@@ -72,7 +79,8 @@
         }
 
         Feature newFeature = new Feature(featureName);
-        convert(newFeature, feature.getVariables(), feature.getBundles(), feature.getConfigurations(), feature.getFrameworkProperties(), feature.getExtensions(), output);
+        convert(newFeature, feature.getVariables(), feature.getBundles(), feature.getConfigurations(),
+                feature.getFrameworkProperties(), feature.getExtensions(), outputFile.getAbsolutePath());
     }
 
     /*
@@ -242,7 +250,6 @@
             }
         }
 
-        LOGGER.info("Writing feature...");
         final String out = outputFile;
         final File file = new File(out);
         final Model m = new Model();
diff --git a/src/main/java/org/apache/sling/feature/modelconverter/ProvisioningToFeature.java b/src/main/java/org/apache/sling/feature/modelconverter/ProvisioningToFeature.java
index 8f404e5..f53236a 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/ProvisioningToFeature.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/ProvisioningToFeature.java
@@ -84,12 +84,18 @@
             id = bareFileName + "_" + id;
 
             File outFile = new File(outDir, id + ".json");
-            int counter = 0;
-            while (outFile.exists()) {
-                outFile = new File(outDir, id + "_" + (++counter) + ".json");
+            files.add(outFile);
+
+            if (outFile.exists()) {
+                if (outFile.lastModified() > file.lastModified()) {
+                    LOGGER.debug("Skipping the generation of {} as this file already exists and is newer.", outFile);
+                    continue;
+                } else {
+                    LOGGER.debug("Deleting existing file {} as source is newer", outFile);
+                    outFile.delete();
+                }
             }
 
-            files.add(outFile);
             writeFeature(f, outFile.getAbsolutePath(), 0);
         }
         return files;
@@ -508,7 +514,6 @@
     }
 
     private static void writeFeature(final org.apache.sling.feature.Feature f, String out, final int index) {
-        LOGGER.info("Writing feature...");
         if ( index > 0 ) {
             final int lastDot = out.lastIndexOf('.');
             if ( lastDot == -1 ) {
diff --git a/src/test/java/org/apache/sling/feature/modelconverter/ModelConverterTest.java b/src/test/java/org/apache/sling/feature/modelconverter/ModelConverterTest.java
index 7938f23..ccdcd59 100644
--- a/src/test/java/org/apache/sling/feature/modelconverter/ModelConverterTest.java
+++ b/src/test/java/org/apache/sling/feature/modelconverter/ModelConverterTest.java
@@ -50,6 +50,7 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -64,6 +65,7 @@
 
 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 static org.junit.Assert.fail;
 
@@ -191,6 +193,67 @@
         assertFeaturesEqual(expected, actual);
     }
 
+    @Test
+    public void testConvertToProvisioningModelOverwriteLogic() throws Exception {
+        String originalJSON = "/boot.json";
+        String expectedProvModel = "/boot.txt";
+
+        File inFile = new File(getClass().getResource(originalJSON).toURI());
+        File outFile = new File(tempDir.toFile(), expectedProvModel + ".generated");
+
+        FeatureToProvisioning.convert(inFile, outFile, artifactManager);
+        List<String> orgLines = Files.readAllLines(outFile.toPath());
+        assertNotEquals("Test precondition", "modified!", orgLines.get(orgLines.size() - 1));
+
+        // Append to the output file:
+        Files.write(outFile.toPath(), "\nmodified!".getBytes(), StandardOpenOption.APPEND);
+
+        // Convert again and see that the output file is not modified
+        FeatureToProvisioning.convert(inFile, outFile, artifactManager);
+
+        List<String> lines = Files.readAllLines(outFile.toPath());
+        assertEquals("modified!", lines.get(lines.size() - 1));
+
+        // Modify the modification time of the generated file to be older than the input file
+        outFile.setLastModified(inFile.lastModified() - 100000);
+        FeatureToProvisioning.convert(inFile, outFile, artifactManager);
+
+        List<String> owLines = Files.readAllLines(outFile.toPath());
+        assertEquals("The file should have been overwritten since the source has modified since it's edit timestamp",
+                orgLines, owLines);
+    }
+
+    @Test
+    public void testConvertToFeature() throws Exception {
+        File inFile = new File(getClass().getResource("/boot.txt").toURI());
+
+        List<File> files = ProvisioningToFeature.convert(inFile, tempDir.toFile(), Collections.emptyMap());
+        assertEquals("The testing code expects a single output file here", 1, files.size());
+        File outFile = files.get(0);
+
+        List<String> orgLines = Files.readAllLines(outFile.toPath());
+        assertNotEquals("Test precondition", "modified!", orgLines.get(orgLines.size() - 1));
+
+        // Append to the output file:
+        Files.write(outFile.toPath(), "\nmodified!".getBytes(), StandardOpenOption.APPEND);
+
+        // Convert again and see that the output file is not modified
+        List<File> files2 = ProvisioningToFeature.convert(inFile, tempDir.toFile(), Collections.emptyMap());
+        assertEquals("Should return the same file list", files, files2);
+
+        List<String> lines = Files.readAllLines(outFile.toPath());
+        assertEquals("modified!", lines.get(lines.size() - 1));
+
+        // Modify the modification time of the generated file to be older than the input file
+        outFile.setLastModified(inFile.lastModified() - 100000);
+        List<File> files3 = ProvisioningToFeature.convert(inFile, tempDir.toFile(), Collections.emptyMap());
+        assertEquals("Should return the same file list", files, files3);
+
+        List<String> owLines = Files.readAllLines(outFile.toPath());
+        assertEquals("The file should have been overwritten since the source has modified since it's edit timestamp",
+                orgLines, owLines);
+    }
+
     public void testConvertFromProvModelRoundTrip(File orgProvModel) throws Exception {
         System.out.println("*** Roundtrip converting: " + orgProvModel.getName());
         List<File> allGenerateProvisioningModelFiles = new ArrayList<>();
@@ -202,7 +265,7 @@
             assertFalse("File name cannot contain a colon", baseName.contains(":"));
             File genFile = new File(tempDir.toFile(), baseName + ".txt");
             allGenerateProvisioningModelFiles.add(genFile);
-            FeatureToProvisioning.convert(f, genFile.getAbsolutePath(), artifactManager);
+            FeatureToProvisioning.convert(f, genFile, artifactManager);
         }
 
         Model expected = readProvisioningModel(orgProvModel);
@@ -227,8 +290,7 @@
         File inFile = new File(getClass().getResource(originalJSON).toURI());
         File outFile = new File(tempDir.toFile(), expectedProvModel + ".generated");
 
-        FeatureToProvisioning.convert(inFile, outFile.getAbsolutePath(),
-                artifactManager);
+        FeatureToProvisioning.convert(inFile, outFile, artifactManager);
 
         File expectedFile = new File(getClass().getResource(expectedProvModel).toURI());
         Model expected = readProvisioningModel(expectedFile);