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<Path> RESOURCES = new ArrayList<Path>();
public static final String RESOURCE_FS_DIR;
private final static Map<String, String> DEFAULTS = new HashMap<String, String>() {
private static final long serialVersionUID = -5625624201188857134L;
{
put(MASTERSERVER_ADDRESS, "bwlp-masterserver.ruf.uni-freiburg.de");
put(MASTERSERVER_IDM, "bwIDM");
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<String, String> 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<String, String>() {
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<Path> 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<Path>() {
@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;
}
}