Onboarding backend build optimization. 41/50341/5
authorGautam Shah <gautams@amdocs.com>
Tue, 5 Jun 2018 13:20:13 +0000 (18:50 +0530)
committerAvi Gaffa <avi.gaffa@amdocs.com>
Wed, 6 Jun 2018 06:27:18 +0000 (06:27 +0000)
Enhancing Test RUN/NO-RUN Logic, adding identifiers for local build state repo

Change-Id: Ie0a541f216c16ddc40605111981d7a2fa045c39d
Issue-ID: SDC-1189
Signed-off-by: GAUTAMS <gautams@amdocs.com>
onboarding/pom.xml
openecomp-be/tools/artifact-copy-plugin/src/main/java/org/openecomp/sdc/onboarding/util/ArtifactHelper.java
openecomp-be/tools/artifact-copy-plugin/src/main/java/org/openecomp/sdc/onboarding/util/InitializationHelperMojo.java
openecomp-be/tools/compile-helper-plugin/src/main/java/org/openecomp/sdc/onboarding/BuildHelper.java
openecomp-be/tools/compile-helper-plugin/src/main/java/org/openecomp/sdc/onboarding/BuildState.java
openecomp-be/tools/compile-helper-plugin/src/main/java/org/openecomp/sdc/onboarding/Constants.java
openecomp-be/tools/compile-helper-plugin/src/main/java/org/openecomp/sdc/onboarding/InitializationHelperMojo.java
openecomp-be/tools/compile-helper-plugin/src/main/java/org/openecomp/sdc/onboarding/PreCompileHelperMojo.java
openecomp-be/tools/pmd-helper-plugin/src/main/java/org/openecomp/sdc/onboarding/pmd/VerifyHelperMojo.java
openecomp-be/tools/snapshot-signature-plugin/pom.xml [new file with mode: 0644]
openecomp-be/tools/snapshot-signature-plugin/src/main/java/org/openecomp/sdc/onboarding/SnapshotSignature.java [new file with mode: 0644]

index b1e6bd3..4bc0217 100644 (file)
@@ -19,6 +19,7 @@
         <module>../common</module>
         <module>../openecomp-be</module>
         <module>../openecomp-be/tools/build-data-installer</module>
+        <module>../openecomp-be/tools/snapshot-signature-plugin</module>
         <module>../openecomp-ui</module>
     </modules>
 
index f51a8aa..f5bbbd6 100644 (file)
@@ -49,6 +49,7 @@ public class ArtifactHelper {
     private static File unicornMetaLocation = null;
     private File tempLocation = Paths.get(System.getProperties().getProperty("java.io.tmpdir")).toFile();
     private static int snapshotBuildNumber = 0;
+    private static final String HYPHEN = "-";
 
     void init(String terminalModuleCoordinate) {
         setUnicornMetaLocation(getUnicornRootFile(unicornRoot.substring(0, unicornRoot.indexOf('/')), project));
@@ -141,11 +142,13 @@ public class ArtifactHelper {
             try (InputStream is = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(is)) {
                 dataStore = HashMap.class.cast(ois.readObject());
                 dataStore.put("shutdownTime", (System.currentTimeMillis() / 1000) * 1000 + snapshotBuildNumber);
+                dataStore.put("version", project.getVersion());
             }
             try (OutputStream os = new FileOutputStream(file); ObjectOutputStream oos = new ObjectOutputStream(os)) {
                 oos.writeObject(dataStore);
             }
-            Files.copy(file.toPath(), Paths.get(tempLocation.getAbsolutePath(), file.getName()),
+            Files.copy(file.toPath(),
+                    Paths.get(tempLocation.getAbsolutePath(), file.getName() + HYPHEN + project.getVersion()),
                     StandardCopyOption.REPLACE_EXISTING);
         }
     }
index 6fa9b0e..9585057 100644 (file)
@@ -67,6 +67,11 @@ public class InitializationHelperMojo extends AbstractMojo {
     @Override
     public void execute() throws MojoExecutionException, MojoFailureException {
         if (System.getProperties().containsKey(UNICORN_INITIALIZED)) {
+            try {
+                artifactHelper.shutDown(project);
+            } catch (IOException | ClassNotFoundException e) {
+                throw new MojoExecutionException("Unexpected Error Occured during shutdown activities", e);
+            }
             return;
         }
         artifactHelper.init(groupId + ":" + artifactId);
@@ -105,7 +110,7 @@ public class InitializationHelperMojo extends AbstractMojo {
                     byte[] data = fetchContents(repo.getUrl(), artifactId, timestamp + "-" + buildNumber);
                     artifactHelper.store(artifactId, data);
                     getLog().info(artifactId + " Version to be copied is " + timestamp + "-" + buildNumber);
-                    artifactHelper.setSnapshotBuildNumber(Integer.parseInt(buildNumber));
+                    ArtifactHelper.setSnapshotBuildNumber(Integer.parseInt(buildNumber));
                     return timestamp + "-" + buildNumber;
                 }
             } catch (IOException e) {
index 8f20f22..d9767fd 100644 (file)
@@ -19,7 +19,9 @@ package org.openecomp.sdc.onboarding;
 import static org.openecomp.sdc.onboarding.Constants.CHECKSUM;
 import static org.openecomp.sdc.onboarding.Constants.COLON;
 import static org.openecomp.sdc.onboarding.Constants.DOT;
+import static org.openecomp.sdc.onboarding.Constants.JAR;
 import static org.openecomp.sdc.onboarding.Constants.JAVA_EXT;
+import static org.openecomp.sdc.onboarding.Constants.SHA1;
 import static org.openecomp.sdc.onboarding.Constants.UNICORN;
 
 import java.io.ByteArrayInputStream;
@@ -67,14 +69,26 @@ class BuildHelper {
         }
         try {
             signature = new String(fetchSnapshotSignature(snapshotFile, version));
+            if (version.equals(signature)) {
+                signature = getSHA1For(snapshotFile, Paths.get(snapshotFile.getParentFile().getAbsolutePath(),
+                        moduleCoordinate.substring(moduleCoordinate.indexOf(':') + 1) + "-" + version + DOT + JAR + DOT
+                                + SHA1).toFile());
+            }
             store.put(key, signature);
             return signature;
-        } catch (IOException ioe) {
+        } catch (IOException | NoSuchAlgorithmException e) {
             return version;
         }
 
     }
 
+    private static String getSHA1For(File file, File signatureFile) throws IOException, NoSuchAlgorithmException {
+        if (signatureFile.exists()) {
+            return new String(Files.readAllBytes(signatureFile.toPath()));
+        }
+        return getSourceChecksum(Files.readAllBytes(file.toPath()), SHA1);
+    }
+
     static long getChecksum(File file, String fileType) {
         try {
             return readSources(file, fileType).hashCode();
@@ -84,8 +98,12 @@ class BuildHelper {
     }
 
     static String getSourceChecksum(String data, String hashType) throws NoSuchAlgorithmException {
+        return getSourceChecksum(data.getBytes(), hashType);
+    }
+
+    static String getSourceChecksum(byte[] data, String hashType) throws NoSuchAlgorithmException {
         MessageDigest md = MessageDigest.getInstance(hashType);
-        md.update(data.getBytes());
+        md.update(data);
         byte[] hashBytes = md.digest();
 
         StringBuilder buffer = new StringBuilder();
@@ -197,7 +215,7 @@ class BuildHelper {
              JarInputStream jis = new JarInputStream(bais)) {
             JarEntry entry = null;
             while ((entry = jis.getNextJarEntry()) != null) {
-                if (entry.getName().equals(UNICORN + DOT + CHECKSUM)) {
+                if (entry.getName().endsWith(UNICORN + DOT + CHECKSUM)) {
                     byte[] sigStore = new byte[1024];
                     return new String(sigStore, 0, jis.read(sigStore, 0, 1024)).getBytes();
                 }
index 68557a9..c817798 100644 (file)
@@ -48,6 +48,7 @@ import org.apache.maven.project.MavenProject;
 public class BuildState {
 
     private static final String SHUTDOWN_TIME = "shutdownTime";
+    private static final String VERSION = "version";
 
     private static Map<String, Map> compileDataStore = new HashMap<>();
     private static Map<String, Object> moduleBuildData = new HashMap<>();
@@ -66,6 +67,11 @@ public class BuildState {
         initializeStore();
         Optional<HashMap> masterStore = readState("compile.dat", HashMap.class);
         compileDataStore = masterStore.isPresent() ? masterStore.get() : compileDataStore;
+        String version = String.class.cast(compileDataStore.get(VERSION));
+        if (version != null) {
+            stateFileLocation = new File(Paths.get(System.getProperties().getProperty("java.io.tmpdir")).toFile(),
+                    "compileState.dat-" + version);
+        }
         if (stateFileLocation.exists()) {
             HashMap dat = loadState(stateFileLocation);
             if (swapStates((HashMap<?, ?>) compileDataStore, dat)) {
@@ -282,11 +288,16 @@ public class BuildState {
     private static boolean swapStates(HashMap repo, HashMap last) {
         Long repoTime = repo.get(SHUTDOWN_TIME) == null ? 0 : (Long) repo.get(SHUTDOWN_TIME);
         Long lastTime = last.get(SHUTDOWN_TIME) == null ? 0 : (Long) last.get(SHUTDOWN_TIME);
-        long repoBuildNumber = repoTime / 1000;
-        long lastBuildNumber = lastTime / 1000;
+        String repoVersion = repo.get(VERSION) == null ? "" : (String) repo.get(VERSION);
+        String lastVersion = last.get(VERSION) == null ? "" : (String) last.get(VERSION);
+        long repoBuildNumber = repoTime % 1000;
+        long lastBuildNumber = lastTime % 1000;
         if (repoBuildNumber != lastBuildNumber) {
             return false;
         }
+        if (!repoVersion.equals(lastVersion)) {
+            return false;
+        }
         return Long.compare(repoTime, lastTime) < 0;
     }
 
index 195b356..c6603a7 100644 (file)
@@ -21,22 +21,26 @@ public class Constants {
 
     public static final String UNICORN = "unicorn";
     public static final String EMPTY_STRING = "";
-    public static final String PREFIX = System.getProperties().contains(UNICORN) ? EMPTY_STRING : UNICORN;
     public static final String JACOCO_SKIP = "jacoco.skip";
+    public static final String JACOCO_BUILD = Boolean.toString(
+            System.getProperties().containsKey(JACOCO_SKIP) && Boolean.FALSE.equals(Boolean.valueOf(
+                    System.getProperties().getProperty(JACOCO_SKIP))));
+    public static final String JACOCO = Boolean.valueOf(JACOCO_BUILD) ? UNICORN : EMPTY_STRING;
+    public static final String PREFIX = System.getProperties().contains(UNICORN) ? EMPTY_STRING : UNICORN;
     public static final String FORK_COUNT = "fork.count";
     public static final String FORK_MODE = "fork.mode";
     public static final String SKIP_PMD = "skipPMD";
     public static final String JAVA_EXT = ".java";
     public static final String ANY_EXT = "*";
-    public static final String SKIP_TEST_RUN = PREFIX + "skipTestRun";
+    public static final String SKIP_TEST_RUN = PREFIX + JACOCO + "skipTestRun";
     public static final String SKIP_TESTS = "skipTests";
     public static final String MAIN = "main";
     public static final String TEST = "test";
     public static final String RESOURCES_CHANGED = "resourcesChanged";
     public static final String ANSI_YELLOW = "\u001B[43m";
     public static final String ANSI_COLOR_RESET = "\u001B[0m";
-    public static final String SKIP_MAIN_SOURCE_COMPILE = PREFIX + "skipMainSourceCompile";
-    public static final String SKIP_TEST_SOURCE_COMPILE = PREFIX + "skipTestSourceCompile";
+    public static final String SKIP_MAIN_SOURCE_COMPILE = PREFIX + JACOCO + "skipMainSourceCompile";
+    public static final String SKIP_TEST_SOURCE_COMPILE = PREFIX + JACOCO + "skipTestSourceCompile";
     public static final String MAIN_CHECKSUM = "mainChecksum";
     public static final String CHECKSUM = "checksum";
     public static final String TEST_CHECKSUM = "testChecksum";
@@ -60,8 +64,8 @@ public class Constants {
     public static final String RESOURCE_WITH_TEST_ONLY = "resourceWithTestOnly";
     public static final String INSTRUMENT_ONLY = "instrumentOnly";
     public static final String TEST_ONLY = "testOnly";
-    public static final String SKIP_RESOURCE_COLLECTION = PREFIX + "skipResourceCollection";
-    public static final String SKIP_INSTALL = PREFIX + "skipInstall";
+    public static final String SKIP_RESOURCE_COLLECTION = PREFIX + JACOCO + "skipResourceCollection";
+    public static final String SKIP_INSTALL = PREFIX + JACOCO + "skipInstall";
 
 
     private Constants() {
index 6c1d2be..552ae6a 100644 (file)
@@ -18,7 +18,8 @@ package org.openecomp.sdc.onboarding;
 
 import static org.openecomp.sdc.onboarding.Constants.FORK_COUNT;
 import static org.openecomp.sdc.onboarding.Constants.FORK_MODE;
-import static org.openecomp.sdc.onboarding.Constants.JACOCO_SKIP;
+import static org.openecomp.sdc.onboarding.Constants.JACOCO;
+import static org.openecomp.sdc.onboarding.Constants.JACOCO_BUILD;
 import static org.openecomp.sdc.onboarding.Constants.PREFIX;
 import static org.openecomp.sdc.onboarding.Constants.SKIP_PMD;
 import static org.openecomp.sdc.onboarding.Constants.UNICORN;
@@ -45,15 +46,13 @@ public class InitializationHelperMojo extends AbstractMojo {
 
     @Override
     public void execute() throws MojoExecutionException, MojoFailureException {
-        if (PREFIX == UNICORN) {
+        if (PREFIX == UNICORN || JACOCO == UNICORN) {
             System.getProperties().setProperty(UNICORN, Boolean.TRUE.toString());
         }
         if (project.getPackaging().equals(excludePackaging)) {
             return;
         }
-        project.getProperties().setProperty("skipGet", Boolean.FALSE.toString());
-        if (System.getProperties().containsKey(JACOCO_SKIP) && Boolean.FALSE.equals(Boolean.valueOf(
-                System.getProperties().getProperty(JACOCO_SKIP)))) {
+        if (Boolean.valueOf(JACOCO_BUILD)) {
             project.getProperties().setProperty(FORK_COUNT, "1");
             project.getProperties().setProperty(FORK_MODE, "once");
         } else {
index e97b172..3b51398 100644 (file)
@@ -349,16 +349,19 @@ public class PreCompileHelperMojo extends AbstractMojo {
             return moduleBuildData;
         }
         for (Artifact dependency : project.getArtifacts()) {
-            String version = dependency.isSnapshot() ? getSnapshotSignature(dependency.getFile(),
-                    dependency.getGroupId() + COLON + dependency.getArtifactId(), dependency.getVersion()) :
-                                     dependency.getVersion();
-            if (excludeDependencies.contains(dependency.getScope())) {
-                HashMap.class.cast(moduleBuildData.get(TEST))
+            if (JAR.equals(dependency.getType())) {
+                String version = dependency.isSnapshot() || dependency.getFile().getName().contains("SNAPSHOT") ?
+                                         getSnapshotSignature(dependency.getFile(),
+                                                 dependency.getGroupId() + COLON + dependency.getArtifactId(),
+                                                 dependency.getVersion()) : dependency.getVersion();
+                if (excludeDependencies.contains(dependency.getScope())) {
+                    HashMap.class.cast(moduleBuildData.get(TEST))
+                                 .put(dependency.getGroupId() + COLON + dependency.getArtifactId(), version);
+                    continue;
+                }
+                HashMap.class.cast(moduleBuildData.get(MAIN))
                              .put(dependency.getGroupId() + COLON + dependency.getArtifactId(), version);
-                continue;
             }
-            HashMap.class.cast(moduleBuildData.get(MAIN))
-                         .put(dependency.getGroupId() + COLON + dependency.getArtifactId(), version);
         }
         return moduleBuildData;
     }
index c80951f..9e783d9 100644 (file)
@@ -128,7 +128,11 @@ public class VerifyHelperMojo extends AbstractMojo {
 
     private void removeProcessFiles() {
         if (moduleCoordinates.equals(persistingModuleCoordinates) && pmdStateFile.exists()) {
-            pmdStateFile.delete();
+            for (File file : pmdStateFile.getParentFile().listFiles()) {
+                if (file.isFile()) {
+                    file.delete();
+                }
+            }
         }
         if (pmdTargetLocation.exists()) {
             pmdTargetLocation.delete();
diff --git a/openecomp-be/tools/snapshot-signature-plugin/pom.xml b/openecomp-be/tools/snapshot-signature-plugin/pom.xml
new file mode 100644 (file)
index 0000000..96ecbae
--- /dev/null
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>snapshot-signature-plugin</artifactId>
+    <packaging>maven-plugin</packaging>
+    <parent>
+        <artifactId>sdc-onboarding</artifactId>
+        <groupId>org.openecomp.sdc</groupId>
+        <version>1.3.0-SNAPSHOT</version>
+        <relativePath>../../../onboarding</relativePath>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-core</artifactId>
+            <version>${maven-core.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.plugin-tools</groupId>
+            <artifactId>maven-plugin-annotations</artifactId>
+            <version>${maven-plugin-annotations.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-plugin-plugin</artifactId>
+                <version>${maven-plugin-plugin.version}</version>
+            </plugin>
+        </plugins>
+    </build>
+
+
+</project>
\ No newline at end of file
diff --git a/openecomp-be/tools/snapshot-signature-plugin/src/main/java/org/openecomp/sdc/onboarding/SnapshotSignature.java b/openecomp-be/tools/snapshot-signature-plugin/src/main/java/org/openecomp/sdc/onboarding/SnapshotSignature.java
new file mode 100644 (file)
index 0000000..f4a03ed
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright © 2018 European Support Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on a "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openecomp.sdc.onboarding;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.RecursiveTask;
+import java.util.stream.Collectors;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
+
+@Mojo(name = "generate-signature", threadSafe = true, defaultPhase = LifecyclePhase.COMPILE,
+        requiresDependencyResolution = ResolutionScope.NONE)
+public class SnapshotSignature extends AbstractMojo {
+
+    public static final String JAVA_EXT = ".java";
+    public static final String UNICORN = "unicorn";
+    public static final String CHECKSUM = "checksum";
+    public static final String DOT = ".";
+    public static final String SHA1 = "sha1";
+    public static final String COLON = ":";
+    public static final String ANY_EXT = "*";
+    public static final String SNAPSHOT = "SNAPSHOT";
+    public static final String JAR = "jar";
+
+    @Parameter
+    private File mainSourceLocation;
+    @Parameter
+    private File mainResourceLocation;
+    @Parameter(defaultValue = "${project}")
+    private MavenProject project;
+
+    @Override
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        if (!JAR.equals(project.getPackaging())) {
+            return;
+        }
+        init();
+        long resourceChecksum = getChecksum(mainResourceLocation, ANY_EXT);
+        long mainChecksum = getChecksum(mainSourceLocation, JAVA_EXT);
+        byte[] sourceChecksum = calculateChecksum(mainChecksum, resourceChecksum).getBytes();
+        generateSignature(sourceChecksum);
+    }
+
+    private void init() {
+        if (mainSourceLocation == null) {
+            mainSourceLocation = Paths.get(project.getBuild().getSourceDirectory()).toFile();
+        }
+        if (mainResourceLocation == null) {
+            mainResourceLocation = Paths.get(project.getBuild().getResources().get(0).getDirectory()).toFile();
+        }
+    }
+
+    private long getChecksum(File file, String fileType) {
+        try {
+            return readSources(file, fileType).hashCode();
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    private Map<String, List<String>> readSources(File file, String fileType) throws IOException {
+        Map<String, List<String>> source = new HashMap<>();
+        if (file.exists()) {
+            List<File> list = Files.walk(Paths.get(file.getAbsolutePath()))
+                                   .filter(JAVA_EXT.equals(fileType) ? this::isRegularJavaFile : Files::isRegularFile)
+                                   .map(Path::toFile).collect(Collectors.toList());
+            source.putAll(ForkJoinPool.commonPool()
+                                      .invoke(new FileReadTask(list.toArray(new File[0]), file.getAbsolutePath())));
+        }
+        return source;
+    }
+
+    private boolean isRegularJavaFile(Path path) {
+        File file = path.toFile();
+        return file.isFile() && file.getName().endsWith(JAVA_EXT);
+    }
+
+    private class FileReadTask extends RecursiveTask<Map<String, List<String>>> {
+
+        private Map<String, List<String>> store = new HashMap<>();
+        File[] files;
+        String pathPrefix;
+        private static final int MAX_FILES = 10;
+
+        FileReadTask(File[] files, String pathPrefix) {
+            this.files = files;
+            this.pathPrefix = pathPrefix;
+        }
+
+        private List<String> getData(File file) throws IOException {
+            List<String> coll = Files.readAllLines(file.toPath(), StandardCharsets.ISO_8859_1);
+            if (file.getAbsolutePath().contains(File.separator + "generated-sources" + File.separator)) {
+                Iterator<String> itr = coll.iterator();
+                while (itr.hasNext()) {
+                    String s = itr.next();
+                    if (s == null || s.trim().startsWith("/") || s.trim().startsWith("*")) {
+                        itr.remove();
+                    }
+                }
+            }
+            return coll;
+        }
+
+
+        @Override
+        protected Map<String, List<String>> compute() {
+            if (files.length > MAX_FILES) {
+                FileReadTask task1 = new FileReadTask(Arrays.copyOfRange(files, 0, files.length / 2), pathPrefix);
+                FileReadTask task2 =
+                        new FileReadTask(Arrays.copyOfRange(files, files.length / 2, files.length), pathPrefix);
+                task1.fork();
+                task2.fork();
+                store.putAll(task1.join());
+                store.putAll(task2.join());
+            } else {
+                for (File toRead : files) {
+                    try {
+                        store.put(toRead.getAbsolutePath().substring(pathPrefix.length())
+                                        .replace(File.separatorChar, '.'), getData(toRead));
+                    } catch (IOException e) {
+                        throw new UncheckedIOException(e);
+                    }
+                }
+            }
+
+            return store;
+        }
+    }
+
+    private void generateSignature(byte[] sourceChecksum) {
+        try {
+            Paths.get(project.getBuild().getOutputDirectory()).toFile().mkdirs();
+            Files.write(Paths.get(project.getBuild().getOutputDirectory(), UNICORN + DOT + CHECKSUM), sourceChecksum,
+                    StandardOpenOption.CREATE);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    private String calculateChecksum(long mainChecksum, long resourceChecksum) throws MojoExecutionException {
+        try {
+            return getSourceChecksum(mainChecksum + COLON + resourceChecksum, SHA1);
+        } catch (NoSuchAlgorithmException e) {
+            throw new MojoExecutionException(e.getMessage(), e);
+        }
+    }
+
+    private String getSourceChecksum(String data, String hashType) throws NoSuchAlgorithmException {
+        MessageDigest md = MessageDigest.getInstance(hashType);
+        md.update(data.getBytes());
+        byte[] hashBytes = md.digest();
+
+        StringBuilder buffer = new StringBuilder();
+        for (byte hashByte : hashBytes) {
+            buffer.append(Integer.toString((hashByte & 0xff) + 0x100, 16).substring(1));
+        }
+        return buffer.toString();
+    }
+}