package org.dsa.iot.container.manager; import java.io.IOException; import java.lang.reflect.Method; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; /** * @author Samuel Grenier */ public class DSLinkManager { private final Map<String, DSLinkHandler> links = new HashMap<>(); private final List<String> loadedNatives = new ArrayList<>(); private final Path temporaryDir; public DSLinkManager() { temporaryDir = Paths.get("native-tmp"); try { if (!Files.isDirectory(temporaryDir)) { Files.createDirectory(temporaryDir); } } catch (IOException e) { throw new RuntimeException(e); } } public synchronized void loadDirectory(Path path, String brokerUrl, String token) { if (!Files.isDirectory(path)) { System.err.println(path.toString() + " is not a directory"); return; } try (DirectoryStream<Path> ds = Files.newDirectoryStream(path)) { for (Path dslinkRoot : ds) { if (!Files.isDirectory(dslinkRoot)) { continue; } try { load(dslinkRoot, brokerUrl, token, null); } catch (Exception e) { e.printStackTrace(System.err); } } } catch (IOException e) { throw new RuntimeException(e); } } public synchronized void load(Path path, String brokerUrl, String token, String logPath) throws Exception { DSLinkInfo info = DSLinkInfo.load(path, brokerUrl, token, logPath); if (info == null) { return; } try { start(path, info); } catch (Exception e) { System.err.println("Failed to start: " + info.getName()); } } public synchronized void start(Path path, DSLinkInfo info) { String name = path.toString(); DSLinkHandler link = links.get(name); if (link == null) { link = new DSLinkHandler(this, info); links.put(name, link); } try { link.start(); } catch (IOException e) { links.remove(name); throw new RuntimeException(e); } } public synchronized void stop(Path path) { String name = path.toString(); DSLinkHandler link = links.remove(name); if (link != null) { link.stop(); } } public synchronized void stopAll() { Iterator<DSLinkHandler> it = links.values().iterator(); while (it.hasNext()) { DSLinkHandler handler = it.next(); it.remove(); if (handler != null) { handler.stop(); } } } public synchronized void loadNative(URL url) { Path file = urlToPath(url); Path fileName = file.getFileName(); if (fileName == null) { return; } final String fullName = fileName.toString(); String shortName = fullName; { // Strip out version information int index = shortName.lastIndexOf("-"); if (index > -1) { shortName = shortName.substring(0, index); } if (shortName.endsWith(".jar")) { index = shortName.lastIndexOf(".jar"); index = shortName.length() - index; shortName = shortName.substring(0, index); } } { // Tell the system it is loaded if (loadedNatives.contains(shortName)) { String msg = ""; msg += "Prevented native library from loading: "; msg += shortName + " (" + fullName + ")"; System.err.println(msg); return; } String msg = ""; msg += "Loaded native library: "; msg += shortName + " (" + fullName + ")"; System.err.println(msg); loadedNatives.add(shortName); } try { // Copy the file Path path = temporaryDir.resolve(shortName + ".jar"); if (!Files.exists(path)) { Files.copy(file, path); } url = path.toUri().toURL(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } { // Add to the class path final Thread t = Thread.currentThread(); final ClassLoader l = t.getContextClassLoader(); final URLClassLoader loader = (URLClassLoader) l; try { Class<?> clazz = URLClassLoader.class; Method m = clazz.getDeclaredMethod("addURL", URL.class); m.setAccessible(true); m.invoke(loader, url); } catch (Exception e) { throw new RuntimeException(e); } } } private Path urlToPath(URL url) { try { return Paths.get(url.toURI()); } catch (URISyntaxException e) { throw new RuntimeException(e); } } }