Skip to content

Commit

Permalink
Merge pull request #37 from RaspberryWallet/module-class-loader
Browse files Browse the repository at this point in the history
Module class loader
  • Loading branch information
PatrykMilewski committed Oct 10, 2018
2 parents cb68f0e + f14a89f commit 5761e06
Show file tree
Hide file tree
Showing 12 changed files with 230 additions and 40 deletions.
8 changes: 6 additions & 2 deletions Manager/pom.xml
Expand Up @@ -30,21 +30,25 @@
<scope>compile</scope>
</dependency>

<!--Server-->
<dependency>
<groupId>io.raspberrywallet</groupId>
<artifactId>ServerHttp</artifactId>
<version>1.0</version>
</dependency>

<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.controlsfx/controlsfx -->

<dependency>
<groupId>org.mockito</groupId>
Expand Down
Expand Up @@ -8,10 +8,12 @@
import io.raspberrywallet.manager.modules.Module;
import io.raspberrywallet.manager.modules.PinModule;

import java.util.List;

public class ExampleMockManager extends Manager {

public ExampleMockManager(Bitcoin bitcoin, TemperatureMonitor tempMonitor) {
super(bitcoin, tempMonitor);
public ExampleMockManager(List<Module> modules, Bitcoin bitcoin, TemperatureMonitor tempMonitor) {
super(modules, bitcoin, tempMonitor);
Module mod = new ExampleModule();
addModule(mod);
Module pinModule = new PinModule();
Expand Down
30 changes: 24 additions & 6 deletions Manager/src/main/java/io/raspberrywallet/manager/Main.java
@@ -1,28 +1,46 @@
package io.raspberrywallet.manager;

import com.google.common.util.concurrent.Service;
import io.raspberrywallet.manager.bitcoin.Bitcoin;
import io.raspberrywallet.manager.cli.Opts;
import io.raspberrywallet.manager.linux.TemperatureMonitor;
import io.raspberrywallet.manager.modules.Module;
import io.raspberrywallet.manager.modules.ModuleClassLoader;
import io.raspberrywallet.server.Server;
import org.apache.commons.cli.CommandLine;

import java.io.File;
import java.util.List;

import static io.raspberrywallet.ktor.KtorServerKt.startKtorServer;
import static io.raspberrywallet.manager.cli.CliUtils.parseArgs;

public class Main {

public static void main(String... args) {
CommandLine cmd = parseArgs(args);

Bitcoin bitcoin = new Bitcoin();
if (Opts.SYNC.isSet(cmd)) {
Service blockchainSyncing = bitcoin.startBlockchainAsync();
Runtime.getRuntime().addShutdownHook(new Thread(blockchainSyncing::stopAsync));
}

// Disable for now
//Service blockchainSyncing = bitcoin.startBlockchainAsync();
//Runtime.getRuntime().addShutdownHook(new Thread(blockchainSyncing::stopAsync));
File modulesDir = new File(Opts.MODULES.getValue(cmd));
List<Module> modules = ModuleClassLoader.getModulesFrom(modulesDir);

TemperatureMonitor temperatureMonitor = new TemperatureMonitor();

Manager manager = new ExampleMockManager(bitcoin, temperatureMonitor);
Manager manager = new ExampleMockManager(modules, bitcoin, temperatureMonitor);

if (args.length > 0 && args[0].equals("vertx"))
if (Opts.VERTX.isSet(cmd) || Opts.SERVER.getValue(cmd).equals(Opts.VERTX.name()))
new Server(manager).start();
else
startKtorServer(manager);

}





}
Expand Up @@ -23,7 +23,8 @@ public class Manager implements io.raspberrywallet.Manager {
private final TemperatureMonitor tempMonitor;


public Manager(Bitcoin bitcoin, TemperatureMonitor tempMonitor) {
public Manager(List<Module> modules, Bitcoin bitcoin, TemperatureMonitor tempMonitor) {
modules.forEach(module -> this.modules.put(module.getId(), module));
this.bitcoin = bitcoin;
this.tempMonitor = tempMonitor;
}
Expand Down
25 changes: 25 additions & 0 deletions Manager/src/main/java/io/raspberrywallet/manager/cli/CliUtils.java
@@ -0,0 +1,25 @@
package io.raspberrywallet.manager.cli;

import org.apache.commons.cli.*;

public class CliUtils {
public static CommandLine parseArgs(String[] args) {
Options options = new Options() {{
addOption(Opts.MODULES.option);
addOption(Opts.SYNC.option);
addOption(Opts.SERVER.option);
addOption(Opts.KTOR.option);
addOption(Opts.VERTX.option);
}};
HelpFormatter helpFormatter = new HelpFormatter();
DefaultParser parser = new DefaultParser();
try {
return parser.parse(options, args);
} catch (ParseException e) {
e.printStackTrace();
helpFormatter.printHelp("java -jar Manager.jar", options, true);
System.exit(0);
return null;
}
}
}
32 changes: 32 additions & 0 deletions Manager/src/main/java/io/raspberrywallet/manager/cli/Opts.java
@@ -0,0 +1,32 @@
package io.raspberrywallet.manager.cli;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;

public enum Opts {
SERVER(new Option("server", true, "HTTP Server impl"), "ktor"),
KTOR(new Option("ktor", "Use Ktor as HTTP Server impl")),
VERTX(new Option("vertx", "Use VertX as HTTP Server impl")),
MODULES(new Option("modules", true, "Modules classes directory path"), "modules"),
SYNC(new Option("sync", "Sync bitcoin blockchain"));

public final Option option;
public final String def;

Opts(Option option) {
this(option, null);
}

Opts(Option option, String def) {
this.option = option;
this.def = def;
}

public boolean isSet(CommandLine cmd) {
return cmd.hasOption(this.option.getOpt());
}

public String getValue(CommandLine cmd) {
return cmd.getOptionValue(this.option.getOpt(), def);
}
}
Expand Up @@ -88,25 +88,25 @@ public void start() {
/**
* Setting the status message for the user
*
* @param statusS - new status
* @param status - new status
*/
protected void setStatusString(String statusS) {
this.statusString = statusS;
void setStatusString(String status) {
this.statusString = status;
}

public String getId() {
return this.getClass().getName();
}

public static final int STATUS_OK = 200;
public static final int STATUS_TIMEOUT = 432;
public static final int STATUS_WAITING = 100;
private static final int STATUS_OK = 200;
private static final int STATUS_TIMEOUT = 432;
private static final int STATUS_WAITING = 100;

private byte[] payload;
private int status = STATUS_WAITING;
private String statusString;
private byte[] decryptedValue;
private HashMap<String, String> input = new HashMap<String, String>();
private HashMap<String, String> input = new HashMap<>();

public void newSession() {
input.clear();
Expand All @@ -126,14 +126,6 @@ public byte[] getResult() throws DecryptionException {
else return decryptedValue;
}

protected interface Decrypter {
public byte[] decrypt(byte[] payload) throws DecryptionException;
}

protected interface Encrypter {
public byte[] encrypt(byte[] data);
}

private Thread checkThread;

private class CheckRunnable implements Runnable {
Expand All @@ -143,17 +135,17 @@ private class CheckRunnable implements Runnable {
private long timeout = 3000;
private long startTime;

public CheckRunnable stop() {
CheckRunnable stop() {
run = false;
return this;
}

public CheckRunnable enable() {
CheckRunnable enable() {
run = true;
return this;
}

public CheckRunnable setSleepTime(long sleep) {
CheckRunnable setSleepTime(long sleep) {
sleepTime = sleep;
return this;
}
Expand Down Expand Up @@ -186,7 +178,7 @@ public void run() {
}
}

CheckRunnable checkRunnable = new CheckRunnable();
private CheckRunnable checkRunnable = new CheckRunnable();

/*
* Used when everything has been completed, both in "cancel" and "done" cases.
Expand Down Expand Up @@ -214,7 +206,7 @@ public void destroy() {
/*
* Fill everything with "zeroes"
*/
public synchronized void zeroFill() {
private synchronized void zeroFill() {
if (decryptedValue != null) {
for (int i = 0; i < decryptedValue.length; ++i)
decryptedValue[i] = (byte) (i % 120);
Expand All @@ -227,17 +219,17 @@ public synchronized void zeroFill() {

public class DecryptionException extends Throwable {

public static final int NO_DATA = -1;
public static final int BAD_KEY = -2;
public static final int UNKNOWN = -3;
static final int NO_DATA = -1;
static final int BAD_KEY = -2;
static final int UNKNOWN = -3;

private int code = UNKNOWN;
private int code;

public DecryptionException(int code) {
DecryptionException(int code) {
this.code = code;
}

public int getCode() {
int getCode() {
return this.code;
}

Expand Down
@@ -0,0 +1,76 @@
package io.raspberrywallet.manager.modules;

import com.stasbar.Logger;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class ModuleClassLoader {

/**
* @param modulesDir - directory where module classes are located
* @return objects of instantiated Modules {@link Module}
*/
@NotNull
public static List<Module> getModulesFrom(File modulesDir) {
if (!modulesDir.exists()) {
System.out.println("Modules folder not found, skipping");
return Collections.emptyList();
}
File[] files = Objects.requireNonNull(modulesDir.listFiles(), "moduleDir files can not be null");
try {
URL url = modulesDir.toURI().toURL();
URLClassLoader classLoader = new URLClassLoader(new URL[]{url});
List<Class<?>> classes = getClasses(files, classLoader);
List<Module> modules = instaniateModulesObjects(classes);
printLoadedModules(modules);
return modules;
} catch (MalformedURLException e) {
e.printStackTrace();
return Collections.emptyList();
}
}

private static List<Class<?>> getClasses(File[] files, final URLClassLoader classLoader) {
return Arrays.stream(files).map(file ->
{
try {
String className = "io.raspberrywallet.manager.modules." + file.getName().replace(".class", "");
return classLoader.loadClass(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
).filter(Objects::nonNull).collect(Collectors.toList());
}

private static List<Module> instaniateModulesObjects(List<Class<?>> classes) {
return classes.stream().map(clazz -> {
try {
return (Module) clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
return null;
}
}).filter(Objects::nonNull).collect(Collectors.toList());
}

private static void printLoadedModules(List<Module> modules) {
Logger.info("ModuleClassLoader", String.format("Loaded %d modules", modules.size()));
modules.forEach(module ->
Logger.info(String.format("Module {\n\tname: %s \n\tid: %s \n\tdescription: %s \n}",
module.getClass().getSimpleName(),
module.getId(),
module.getDescription()))
);
}
}
Expand Up @@ -8,20 +8,21 @@
import org.mockito.Mockito;

import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.List;

import static io.raspberrywallet.manager.Utils.println;

class ManagerTest {
private static Manager manager;
static Bitcoin bitcoin;
static TemperatureMonitor temperatureMonitor;
private static Bitcoin bitcoin;
private static TemperatureMonitor temperatureMonitor;

@BeforeAll
static void setup() {
bitcoin = Mockito.mock(Bitcoin.class);
temperatureMonitor = Mockito.mock(TemperatureMonitor.class);
manager = new Manager(bitcoin, temperatureMonitor);
manager = new Manager(Collections.emptyList(), bitcoin, temperatureMonitor);
}

@Test
Expand Down

0 comments on commit 5761e06

Please sign in to comment.