package org.openslx.dozmod; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; import java.security.CodeSource; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.openslx.dozmod.Config.ProxyMode; import org.openslx.dozmod.util.OsHelper; import org.openslx.util.Util; public final class Branding { private final static Logger LOGGER = LogManager.getLogger(Branding.class); private static final String VIRTUALIZER_WEBSITE = "virtualizer.website"; private static final String SERVICE_EMAIL = "service.email"; private static final String CONFIG_DIRECTORY = "config.directory"; private static final String SERVICE_NAME = "service.name"; private static final String SERVICE_FAQ_WEBSITE = "service.faq.website"; private static final String APPLICATION_NAME = "application.name"; private static final String MASTERSERVER_IDM = "masterserver.idm"; private static final String MASTERSERVER_ADDRESS = "masterserver.address"; private static final String UPDATESERVER_ADDRESS = "updateserver.address"; private final static String PROPERTIES_FILE = "branding.properties"; private final static Properties PROPERTIES = new Properties(); private final static List RESOURCES = new ArrayList(); public static final String RESOURCE_FS_DIR; private final static Map DEFAULTS = new HashMap() { private static final long serialVersionUID = -5625624201188857134L; { put(MASTERSERVER_ADDRESS, "bwlp-masterserver.ruf.uni-freiburg.de"); put(MASTERSERVER_IDM, "DFN-AAI"); put(APPLICATION_NAME, "bwLehrpool-Suite"); put(SERVICE_FAQ_WEBSITE, "https://www.bwLehrpool.de"); put(SERVICE_NAME, "bwLehrpool"); put(CONFIG_DIRECTORY, "bwSuite"); put(SERVICE_EMAIL, "support@bwlehrpool.de"); put(VIRTUALIZER_WEBSITE, "https://www.bwlehrpool.de/doku.php/allgemein/virtualisierer"); put(UPDATESERVER_ADDRESS, "https://bwlp-masterserver.ruf.uni-freiburg.de/dozmod/"); } }; static { String path = null; try { RESOURCES.add(Paths.get(PROPERTIES_FILE)); RESOURCES.add(Paths.get("img")); RESOURCES.add(Paths.get("txt")); // Built-in properties file takes precedence boolean ok = false; try (InputStream in = App.class.getClassLoader().getResourceAsStream(PROPERTIES_FILE)) { PROPERTIES.load(in); LOGGER.info("Loaded branding from jar"); ok = true; } catch (Exception e) { LOGGER.debug("Failed to read 'jar:" + PROPERTIES_FILE + "': "); } if (!ok) { // Try CWD try (InputStream in = new FileInputStream(PROPERTIES_FILE)) { PROPERTIES.load(in); LOGGER.info("Loaded branding from current working directory"); path = "./"; ok = true; } catch (Exception e) { LOGGER.debug("Failed to read './" + PROPERTIES_FILE + "': "); } } if (!ok) { // Try system-wide defaults if (OsHelper.isWindows()) { path = System.getenv("ProgramData"); if (Util.isEmptyString(path)) { path = "C:\\ProgramData"; } } else { path = "/etc"; } path = path + "/bwlp/"; try (InputStream in = new FileInputStream(path + PROPERTIES_FILE)) { PROPERTIES.load(in); LOGGER.info("Loaded system-wide branding"); ok = true; } catch (Exception e) { LOGGER.debug("Failed to read '" + path + PROPERTIES_FILE + "': "); path = null; } } // Fill in missing fields for (Entry it : DEFAULTS.entrySet()) { if (!PROPERTIES.containsKey(it.getKey())) { PROPERTIES.setProperty(it.getKey(), it.getValue()); } } } catch (Throwable t) { t.printStackTrace(); System.exit(1); } RESOURCE_FS_DIR = path; } public final static String getMasterServerAddress() { return PROPERTIES.getProperty(MASTERSERVER_ADDRESS); } public final static String getMasterServerIdm() { return PROPERTIES.getProperty(MASTERSERVER_IDM); } public final static String getApplicationName() { return PROPERTIES.getProperty(APPLICATION_NAME); } public final static String getServiceFAQWebsite() { return PROPERTIES.getProperty(SERVICE_FAQ_WEBSITE); } public final static String getServiceName() { return PROPERTIES.getProperty(SERVICE_NAME); } public final static String getConfigDirectory() { return PROPERTIES.getProperty(CONFIG_DIRECTORY); } public final static String getServiceEmail() { return PROPERTIES.getProperty(SERVICE_EMAIL); } public final static String getVirtualizerWebsite() { return PROPERTIES.getProperty(VIRTUALIZER_WEBSITE); } public final static String getProxyMode() { return PROPERTIES.getProperty("proxy.mode", ProxyMode.AUTO.toString()); } public final static String getUpdateServerAddress() { return PROPERTIES.getProperty("updateserver.address"); } public static void dump(final String localDir) { if (localDir == null || localDir.isEmpty()) return; final Path dumpDir = Paths.get(localDir); if (!Files.isDirectory(dumpDir)) { try { Files.createDirectories(dumpDir); } catch (IOException e) { LOGGER.error("Failed to create missing dump directory: ", e); return; } } final URI jarUri = getRunningJarURI(); if (jarUri == null || jarUri.getPath() == null || jarUri.getPath().isEmpty()) return; copyBranding(jarUri, dumpDir.toString(), false); } public static void pack(final String localDir, final String outputJar) { final URI jarUri = getRunningJarURI(); if (jarUri == null || jarUri.getPath() == null || jarUri.getPath().isEmpty()) return; final File brandingDir = new File(localDir); if (!brandingDir.isDirectory()) { LOGGER.error("Given path is not a directory: " + localDir); return; } final Path newJarPath = Paths.get(outputJar); try { Files.copy(Paths.get(jarUri), newJarPath); } catch (Exception e) { LOGGER.error("Failed to copy jar file at location '" + jarUri.getPath() + "' to '" + newJarPath + "': ", e); try { Files.delete(newJarPath); } catch (IOException e1) { LOGGER.error("Failed to cleanup '" + newJarPath + ": ", e1); } } // copied jar successfully, now insert the contents from the directory copyBranding(newJarPath.toUri(), localDir, true); } private static void copyBranding(final URI jarUri, final String localDir, final boolean pack) { try (FileSystem fs = FileSystems.newFileSystem(URI.create("jar:" + jarUri), new HashMap() { private static final long serialVersionUID = -5625624201188857134L; { put("create", "true"); put("encoding", "UTF-8"); } })) { // hacky default using the fs' separator as root directory Path rootPathJar = fs.getPath(fs.getSeparator()); Iterator it = fs.getRootDirectories().iterator(); if (it.hasNext()) { rootPathJar = it.next(); if (it.hasNext()) { // there should only be one ... TODO handle multiples? LOGGER.debug("Multiple root directories within the JAR found? Trying with first one '" + rootPathJar + "'..."); } } Path rootPathLocal = Paths.get(localDir); for (Path res : RESOURCES) { final Path src, dst; if (pack) { src = rootPathLocal.resolve(res); dst = rootPathJar.resolve(rootPathLocal.relativize(res).toString()); } else { src = rootPathJar.resolve(res.toString()); dst = rootPathLocal.resolve(res); } if (!Files.isReadable(src)) { if (!pack && res.endsWith(PROPERTIES_FILE)) { // Missing properties file is OK, just dump current state try (FileOutputStream fos = new FileOutputStream(dst.toFile())) { PROPERTIES.store(fos, ""); } } else { LOGGER.error("Failed to find or read '" + src + "'."); } continue; } if (Files.isDirectory(src)) { Files.walkFileTree(src, new SimpleFileVisitor() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Path cur = dst.resolve(src.relativize(file).toString()); if (!Files.isDirectory(cur.getParent())) { Files.createDirectory(cur.getParent()); } Files.copy(file, cur, StandardCopyOption.REPLACE_EXISTING); return FileVisitResult.CONTINUE; } }); } else if (Files.isRegularFile(src)) { Files.copy(src, dst, StandardCopyOption.REPLACE_EXISTING); } else { LOGGER.error("Unknown file type for '" + src + "'."); } } } catch (Exception e) { LOGGER.error("Failed to dump branding resources from JAR: ", e); return; } } private static URI getRunningJarURI() { CodeSource cs = App.class.getProtectionDomain().getCodeSource(); if (cs == null) { LOGGER.error("Failed to get code source of this class."); return null; } try { return cs.getLocation().toURI(); } catch (URISyntaxException e) { LOGGER.error("Failed to get location of this JAR."); } return null; } }