diff --git a/self-extracting-jar-creator/.classpath b/self-extracting-jar-creator/.classpath
new file mode 100644
index 000000000..0ca1374d8
--- /dev/null
+++ b/self-extracting-jar-creator/.classpath
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/self-extracting-jar-creator/.project b/self-extracting-jar-creator/.project
new file mode 100644
index 000000000..a7412000c
--- /dev/null
+++ b/self-extracting-jar-creator/.project
@@ -0,0 +1,23 @@
+
+
+ self-extracting-jar-creator
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/self-extracting-jar-creator/.settings/org.eclipse.jdt.apt.core.prefs b/self-extracting-jar-creator/.settings/org.eclipse.jdt.apt.core.prefs
new file mode 100644
index 000000000..d4313d4b2
--- /dev/null
+++ b/self-extracting-jar-creator/.settings/org.eclipse.jdt.apt.core.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.apt.aptEnabled=false
diff --git a/self-extracting-jar-creator/.settings/org.eclipse.jdt.core.prefs b/self-extracting-jar-creator/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..1b6e1ef22
--- /dev/null
+++ b/self-extracting-jar-creator/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,9 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
+org.eclipse.jdt.core.compiler.processAnnotations=disabled
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/self-extracting-jar-creator/.settings/org.eclipse.m2e.core.prefs b/self-extracting-jar-creator/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 000000000..f897a7f1c
--- /dev/null
+++ b/self-extracting-jar-creator/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/self-extracting-jar-creator/pom.xml b/self-extracting-jar-creator/pom.xml
new file mode 100644
index 000000000..44b5240d0
--- /dev/null
+++ b/self-extracting-jar-creator/pom.xml
@@ -0,0 +1,29 @@
+
+ 4.0.0
+ com.github.kdvolder
+ self-extracing-jar-creator
+ 0.0.1-SNAPSHOT
+
+ 1.8
+ 1.8
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ true
+ SelfExtractor
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/self-extracting-jar-creator/src/main/java/SelfExtractor.java b/self-extracting-jar-creator/src/main/java/SelfExtractor.java
new file mode 100644
index 000000000..1250caeaa
--- /dev/null
+++ b/self-extracting-jar-creator/src/main/java/SelfExtractor.java
@@ -0,0 +1,132 @@
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+
+/**
+ * SelfExtractor
+ */
+public class SelfExtractor {
+
+ private static final String CONTENTS_ZIP_RSRC = "/contents.zip";
+ private static final int BUF_SIZE = 1024*8;
+
+ byte[] buffer = new byte[BUF_SIZE];
+
+ public static void main(String[] args) throws Exception {
+ new SelfExtractor().run(args);
+ }
+
+ private void run(String[] args) throws Exception {
+ if (args.length==0) {
+ unpack();
+ } else if (args.length==1) {
+ repack(args[0]);
+ } else {
+ throw new IllegalArgumentException("Expecting one argument pointing to zipfile to re-wrap");
+ }
+ }
+
+ private void repack(String _contentsZip) throws Exception {
+ File contentsZip = new File(_contentsZip);
+ System.out.println("Repackaging "+contentsZip);
+ if (!contentsZip.isFile()) {
+ throw new IllegalArgumentException("File not found:" + contentsZip);
+ }
+ String repackagedPath = contentsZip.toString();
+ if (repackagedPath.endsWith(".zip")) {
+ repackagedPath = repackagedPath.substring(0, repackagedPath.length()-4);
+ }
+ repackagedPath = repackagedPath + ".self-extracting.jar";
+ System.out.println(" as "+repackagedPath);
+
+ File wrapperJar = getMyJar();
+ System.out.println("wrapperJar = "+wrapperJar);
+ try (ZipInputStream zipIn = new ZipInputStream(new FileInputStream(wrapperJar))) {
+ try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(new File(repackagedPath)))) {
+ ZipEntry entry;
+ while ((entry = zipIn.getNextEntry())!=null) {
+ System.out.println("Adding: "+entry.getName());
+ if (entry.getName().equals("contents.zip")) {
+ //skip. We need to write the wrapped zip contents here.
+ } else {
+ zipOut.putNextEntry(new ZipEntry(entry));
+ if (entry.getName().endsWith("/")) {
+ //skip directory has no bytes as contents
+ } else {
+ copy(zipIn, zipOut);
+ }
+ }
+ } //end while
+ entry = new ZipEntry("contents.zip");
+ zipOut.putNextEntry(entry);
+ System.out.println("Adding: "+entry.getName());
+ try (FileInputStream contentsZipIn = new FileInputStream(contentsZip)) {
+ copy(contentsZipIn, zipOut);
+ }
+ } //end: zipOut
+ }//end: zipIn
+ }
+
+ private void copy(InputStream in, OutputStream out) throws IOException {
+ int bytesRead;
+ while ((bytesRead = in.read(buffer)) > 0) {
+ out.write(buffer, 0, bytesRead);
+ }
+ }
+
+ private File getMyJar() {
+ Class> myklass = this.getClass();
+ String resourceName = this.getClass().getName() + ".class";
+ URL resource = myklass.getResource(resourceName);
+ String myResourceUrl = resource.toString();
+ //Example: jar:file:/home/.../self-extracing-jar-creator-0.0.1-SNAPSHOT.jar!/SelfExtractor.class
+ if (!myResourceUrl.startsWith("jar:file:")) {
+ File devJar = new File("target/self-extracing-jar-creator-0.0.1-SNAPSHOT.jar");
+ if (devJar.isFile()) {
+ return devJar;
+ }
+ throw new IllegalStateException("To create self extracting jar, you must run this code from a jar");
+ }
+ return new File(myResourceUrl.substring("jar:file:".length(), myResourceUrl.indexOf('!')));
+ }
+
+ private ZipInputStream openContentsZip() {
+ InputStream zip = this.getClass().getResourceAsStream(CONTENTS_ZIP_RSRC);
+ if (zip==null) {
+ throw new IllegalArgumentException("Couldn't find embedded '"+CONTENTS_ZIP_RSRC+"");
+ }
+ return new ZipInputStream(zip);
+ }
+
+ public void unpack() throws Exception {
+ File destDir = new File(System.getProperty("user.dir"));
+ try (ZipInputStream zip = openContentsZip()) {
+ ZipEntry entry;
+ while ((entry = zip.getNextEntry())!=null) {
+ String name = entry.getName();
+ System.out.println(name);
+ File outfile = new File(destDir, name);
+ if (outfile.exists()) {
+ throw new IllegalArgumentException("File already exists: "+outfile);
+ }
+ if (name.endsWith("/")) {
+ outfile.mkdirs();
+ } else {
+ //file
+ outfile.getParentFile().mkdirs();
+ try (FileOutputStream out = new FileOutputStream(outfile)) {
+ copy(zip, out);
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/self-extracting-jar-creator/src/main/resources/META-INF/MANIFEST.MF b/self-extracting-jar-creator/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..47237f2d7
--- /dev/null
+++ b/self-extracting-jar-creator/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1 @@
+Main-Class: SelfExtractor
\ No newline at end of file