Implements all functionality assumed necessary

This commit is contained in:
Kristian Knarvik 2020-08-22 14:40:46 +02:00
parent b9fce4f59b
commit c94164f10e
7 changed files with 387 additions and 0 deletions

99
pom.xml Normal file
View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
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>
<groupId>net.knarcraft.jarupdater</groupId>
<artifactId>jar-updater</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Jar Updater</name>
<url>https://git.knarcraft.net/KnarCraft/Jar-Updater</url>
<inceptionYear>2020</inceptionYear>
<developers>
<developer>
<id>EpicKnarvik97</id>
<name>Kristian Knarvik</name>
<url>https://kristianknarvik.knarcraft.net</url>
<roles>
<role>leader</role>
<role>developer</role>
</roles>
<timezone>Europe/Oslo</timezone>
</developer>
</developers>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<!-- Build an executable JAR -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>net.knarcraft.jarupdater.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>true</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<directory>${project.basedir}/target</directory>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<finalName>${project.artifactId}-${project.version}</finalName>
<testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>${project.basedir}/src/test/resources</directory>
</testResource>
</testResources>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,75 @@
package net.knarcraft.jarupdater;
import net.knarcraft.jarupdater.utility.DownloaderUtil;
import net.knarcraft.jarupdater.validation.DownloadURLValidator;
import net.knarcraft.jarupdater.validation.Validator;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;
public class Main {
private static final String usageString = "Usage: downloadURL [sourceProgram] [targetFile] [delay]\nThe source " +
"program will be executed upon successful download. The default target will be the file name defined in " +
"the download URL. The default delay is 5 seconds, and is the time to wait for the calling .jar file to " +
"be writable.";
private static final String invalidTargetFilename = "Target filename is invalid. Please set a targetFile argument" +
" ending with a three-letter extension";
private static final String invalidDownloadURL = "Invalid download URL. Only URLs pointing to knarcraft.net can " +
"be used.";
private static String downloadURL;
private static String targetFile;
private static String sourceProgram;
private static int delay = 5;
public static void main(String[] args) throws InterruptedException, IOException {
parseAndValidateArguments(args);
TimeUnit.SECONDS.sleep(delay);
boolean success = DownloaderUtil.downloadFile(downloadURL,
Paths.get(DownloaderUtil.getApplicationWorkDirectory() + File.separator + targetFile));
if (success && sourceProgram != null && !sourceProgram.equals("")) {
DownloaderUtil.runExecutable(sourceProgram);
}
}
/**
* Parses and validates command line arguments
*
* @param args <p>The arguments given by the user</p>
*/
private static void parseAndValidateArguments(String[] args) {
if (args.length >= 2) {
sourceProgram = args[1];
}
if (args.length >= 4) {
delay = Integer.parseInt(args[3]);
}
if (args.length >= 1) {
downloadURL = args[0];
} else {
System.out.println(usageString);
System.exit(1);
return;
}
if (args.length >= 3) {
targetFile = args[2];
} else {
targetFile = DownloaderUtil.getFileNameFromURL(downloadURL);
if (!DownloaderUtil.stringEndsWithExtension(targetFile)) {
throw new IllegalArgumentException(invalidTargetFilename);
}
}
Validator<String> urlValidator = new DownloadURLValidator();
if (!urlValidator.validate(downloadURL)) {
throw new IllegalArgumentException(invalidDownloadURL);
}
}
}

View File

@ -0,0 +1,98 @@
package net.knarcraft.jarupdater.utility;
import net.knarcraft.jarupdater.Main;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
/**
* A utility class for the downloader
*/
public final class DownloaderUtil {
private static String applicationWorkDirectory;
/**
* Gets the file name of the downloaded file from the URL
*
* @param url <p>The URL to parse</p>
* @return <p>The file name at the end of the URL, or an empty string if not able to parse the URL</p>
*/
public static String getFileNameFromURL(String url) {
String[] urlParts = url.split("/");
if (urlParts.length < 4) {
throw new IllegalArgumentException("URL is m");
}
return urlParts[urlParts.length - 1];
}
/**
* Checks if a string ends with an extension
*
* @param string <p>The string to test</p>
* @return <p>True if the string seems to end with an extension</p>
*/
public static boolean stringEndsWithExtension(String string) {
return string.matches(".*\\.[a-zA-Z]{3}$");
}
/**
* Runs an executable given its name
*
* @param executable <p>The executable to execute</p>
* @throws IOException <p>If unable to start the process</p>
*/
public static void runExecutable(String executable) throws IOException {
ProcessBuilder builder;
if (executable.endsWith(".jar")) {
builder = new ProcessBuilder("java", "-jar", executable, "nogui");
} else {
builder = new ProcessBuilder(executable);
}
builder.redirectErrorStream(true);
builder.start();
}
/**
* Downloads a file from a website and replaces the target file
*
* @param path <p>The full url of the file to download</p>
* @param outfile <p>The file to save to</p>
* @return <p>True if successful. False otherwise</p>
*/
public static boolean downloadFile(String path, Path outfile) {
try {
URL url = new URL(path);
InputStream in = url.openStream();
Files.copy(in, outfile, StandardCopyOption.REPLACE_EXISTING);
return true;
} catch (IOException e) {
return false;
}
}
/**
* Retrieves the directory the .jar file is running from
*
* @return <p>The directory the .jar file is running from</p>
*/
public static String getApplicationWorkDirectory() {
if (applicationWorkDirectory == null) {
try {
applicationWorkDirectory = String.valueOf(new File(Main.class.getProtectionDomain().getCodeSource()
.getLocation().toURI().getPath()).getParentFile());
} catch (URISyntaxException e) {
e.printStackTrace();
System.exit(1);
}
}
return applicationWorkDirectory;
}
}

View File

@ -0,0 +1,13 @@
package net.knarcraft.jarupdater.validation;
/**
* This class validates a download url
*/
public class DownloadURLValidator implements Validator<String> {
@Override
public boolean validate(String argument) {
return argument.matches("https://[a-z]*\\.?knarcraft\\.net/.*") && argument.endsWith(".jar");
}
}

View File

@ -0,0 +1,18 @@
package net.knarcraft.jarupdater.validation;
/**
* An interface for a validator
*
* @param <K> <p>The type of object to validate</p>
*/
public interface Validator<K> {
/**
* Validates some object
*
* @param argument <p>The argument to validate</p>
* @return <p>True if the argument is valid. False otherwise</p>
*/
boolean validate(K argument);
}

View File

@ -0,0 +1,44 @@
package net.knarcraft.jarupdater.utility;
import org.junit.Test;
import java.io.File;
import java.nio.file.Paths;
import static junit.framework.TestCase.*;
import static net.knarcraft.jarupdater.utility.DownloaderUtil.*;
public class DownloaderUtilTest {
@Test
public void getFileNameFromURLValidTest() {
assertEquals("minecraft-server-launcher-1.1-SNAPSHOT.jar",
getFileNameFromURL("https://jenkins.knarcraft.net/job/KnarCraft/job/" +
"Minecraft-Server-Launcher/minecraft-server-launcher-1.1-SNAPSHOT.jar"));
}
@Test(expected = IllegalArgumentException.class)
public void getFileNameFromURLInvalidTest() {
getFileNameFromURL("https://knarcraft.net");
}
@Test
public void stringEndsWithExtensionValidTest() {
assertTrue(stringEndsWithExtension("MinecraftServerLauncher.jar"));
}
@Test
public void stringEndsWithExtensionInvalidTest() {
assertFalse(stringEndsWithExtension("MinecraftServerLauncherjar"));
assertFalse(stringEndsWithExtension("MinecraftServerLauncherjar.htacces"));
assertFalse(stringEndsWithExtension("MinecraftServerLauncher.jar.hahaha"));
}
@Test
public void downloadFileTest() {
assertTrue(downloadFile("https://jenkins.knarcraft.net/job/KnarCraft/job/Minecraft-Server-Launcher/job" +
"/master/10/artifact/target/minecraft-server-launcher-1.1-SNAPSHOT-jar-with-dependencies.jar",
Paths.get(getApplicationWorkDirectory() + File.separator + "launcher.jar")));
}
}

View File

@ -0,0 +1,40 @@
package net.knarcraft.jarupdater.validation;
import org.junit.BeforeClass;
import org.junit.Test;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertTrue;
public class DownloadURLValidatorTest {
private static Validator<String> validator;
@BeforeClass
public static void setUp() {
validator = new DownloadURLValidator();
}
@Test
public void validURLTest() {
assertTrue(validator.validate("https://jenkins.knarcraft.net/file.jar"));
}
@Test
public void validURLTest2() {
assertTrue(validator.validate("https://knarcraft.net/file.jar"));
}
@Test
public void invalidURLTest() {
assertFalse(validator.validate("http://www.badsite.com/knarcraft.net"));
assertFalse(validator.validate("https://www.badsite.com/knarcraft.net"));
}
@Test
public void invalidURLTest2() {
assertFalse(validator.validate("http://knarcraft.net.badsite.com/knarcraft.net"));
assertFalse(validator.validate("https://knarcraft.net.badsite.com/knarcraft.net"));
}
}