import de.todesbaum.jsite.application.Node;
import de.todesbaum.jsite.application.Project;
import de.todesbaum.jsite.application.ProjectInserter;
+import de.todesbaum.jsite.main.JarFileLocator.DefaultJarFileLocator;
/**
* Command-line interface for jSite.
}
}
- ConfigurationLocator configurationLocator = new ConfigurationLocator();
+ ConfigurationLocator configurationLocator = new ConfigurationLocator(new DefaultJarFileLocator(getClass().getClassLoader()));
if (configFile != null) {
configurationLocator.setCustomLocation(configFile);
}
import java.io.File;
import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
/**
* Locator for configuration files in different places.
* list, {@link ConfigurationLocation#CUSTOM} has to be enabled by calling
* {@link #setCustomLocation(String)}.
*/
- public ConfigurationLocator() {
+ public ConfigurationLocator(JarFileLocator jarFileLocator) {
/* are we executed from a JAR file? */
- String resource = getClass().getResource("/" + getClass().getName().replace(".", "/") + ".class").toString();
- if (resource.startsWith("jar:")) {
- String jarFileLocation = resource.substring(9, resource.indexOf(".jar!") + 4);
- String jarFileDirectory = new File(jarFileLocation).getParent();
- File configurationFile = new File(jarFileDirectory, "jSite.conf");
+ Optional<File> jarFile = jarFileLocator.locateJarFile();
+ if (jarFile.isPresent()) {
+ File configurationFile = new File(jarFile.get().getParent(), "jSite.conf");
configurationFiles.put(ConfigurationLocation.NEXT_TO_JAR_FILE, configurationFile.getPath());
}
File homeDirectoryFile = new File(System.getProperty("user.home"), ".jSite/config7");
--- /dev/null
+package de.todesbaum.jsite.main;
+
+import static java.util.Optional.empty;
+
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.Optional;
+
+/**
+ * Locates the JAR file used to load jSite in the filesystem.
+ */
+public interface JarFileLocator {
+
+ Optional<File> locateJarFile();
+
+ class DefaultJarFileLocator implements JarFileLocator {
+
+ private final ClassLoader classLoader;
+
+ public DefaultJarFileLocator(ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ }
+
+ @Override
+ public Optional<File> locateJarFile() {
+ URL resourceUrl = classLoader.getResource(Main.class.getName().replace(".", "/") + ".class");
+ if (resourceUrl == null) {
+ return empty();
+ }
+ String resource = resourceUrl.toString();
+ if (resource.startsWith("jar:")) {
+ try {
+ String jarFileLocation = URLDecoder.decode(resource.substring(9, resource.indexOf(".jar!") + 4), "UTF-8");
+ return Optional.of(new File(jarFileLocation));
+ } catch (UnsupportedEncodingException e) {
+ /* location is not available, ignore. */
+ }
+ }
+ return empty();
+ }
+ }
+
+}
import de.todesbaum.jsite.i18n.I18n;
import de.todesbaum.jsite.i18n.I18nContainer;
import de.todesbaum.jsite.main.ConfigurationLocator.ConfigurationLocation;
+import de.todesbaum.jsite.main.JarFileLocator.DefaultJarFileLocator;
import de.todesbaum.util.swing.TWizard;
import de.todesbaum.util.swing.TWizardPage;
import de.todesbaum.util.swing.WizardListener;
*/
private Main(String configFilename) {
/* collect all possible configuration file locations. */
- ConfigurationLocator configurationLocator = new ConfigurationLocator();
+ ConfigurationLocator configurationLocator = new ConfigurationLocator(new DefaultJarFileLocator(getClass().getClassLoader()));
if (configFilename != null) {
configurationLocator.setCustomLocation(configFilename);
}
--- /dev/null
+package de.todesbaum.jsite.main;
+
+import static de.todesbaum.jsite.main.ConfigurationLocator.ConfigurationLocation.CUSTOM;
+import static de.todesbaum.jsite.main.ConfigurationLocator.ConfigurationLocation.HOME_DIRECTORY;
+import static de.todesbaum.jsite.main.ConfigurationLocator.ConfigurationLocation.NEXT_TO_JAR_FILE;
+import static java.util.Optional.empty;
+import static java.util.Optional.of;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.endsWith;
+import static org.hamcrest.Matchers.is;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+/**
+ * Unit test for {@link ConfigurationLocator}.
+ */
+public class ConfigurationLocatorTest {
+
+ @Rule
+ public final TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Test
+ public void configurationLocatorPrefersHomeDirectoryIfJarFileCanNotBeFound() {
+ JarFileLocator jarFileLocator = mock(JarFileLocator.class);
+ when(jarFileLocator.locateJarFile()).thenReturn(empty());
+ ConfigurationLocator locator = new ConfigurationLocator(jarFileLocator);
+ assertThat(locator.findPreferredLocation(), is(HOME_DIRECTORY));
+ assertThat(locator.getFile(HOME_DIRECTORY), endsWith("/config7"));
+ assertThat(locator.isValidLocation(HOME_DIRECTORY), is(true));
+ }
+
+ @Test
+ public void configurationLocatorUsesFileNextToJarFileIfJarFileIsFound() throws Exception {
+ File jarFile = temporaryFolder.newFile("test.jar");
+ temporaryFolder.newFile("jSite.conf");
+ JarFileLocator jarFileLocator = mock(JarFileLocator.class);
+ when(jarFileLocator.locateJarFile()).thenReturn(of(jarFile));
+ ConfigurationLocator locator = new ConfigurationLocator(jarFileLocator);
+ assertThat(locator.findPreferredLocation(), is(NEXT_TO_JAR_FILE));
+ assertThat(locator.getFile(NEXT_TO_JAR_FILE), endsWith("/jSite.conf"));
+ assertThat(locator.isValidLocation(NEXT_TO_JAR_FILE), is(true));
+ }
+
+ @Test
+ public void customLocationCanBeSet() throws Exception {
+ File configFile = temporaryFolder.newFile("jSite.conf");
+ JarFileLocator jarFileLocator = mock(JarFileLocator.class);
+ when(jarFileLocator.locateJarFile()).thenReturn(empty());
+ ConfigurationLocator locator = new ConfigurationLocator(jarFileLocator);
+ locator.setCustomLocation(configFile.getPath());
+ assertThat(locator.findPreferredLocation(), is(CUSTOM));
+ assertThat(locator.getFile(CUSTOM), is(configFile.getPath()));
+ assertThat(locator.isValidLocation(CUSTOM), is(true));
+ }
+
+}
--- /dev/null
+package de.todesbaum.jsite.main;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Optional;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+
+import net.pterodactylus.util.io.StreamCopier;
+
+import de.todesbaum.jsite.main.JarFileLocator.DefaultJarFileLocator;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+/**
+ * Unit test for {@link JarFileLocator}.
+ */
+public class JarFileLocatorTest {
+
+ @Rule
+ public final TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ private static final Class<?> CLASS_TO_LOAD = Main.class;
+ private static final String RESOURCE_TO_COPY = CLASS_TO_LOAD.getName().replace('.', '/') + ".class";
+ private static final String PACKAGE_NAME = CLASS_TO_LOAD.getPackage().getName();
+ private static final String CLASS_FILENAME = CLASS_TO_LOAD.getSimpleName() + ".class";
+
+ @Test
+ public void jarFileCanBeLocatedOnPathWithNonUsAsciiCharacters() throws Exception {
+ File jarFilePath = temporaryFolder.newFolder("Фото café");
+ File jarFile = createJarFile(jarFilePath);
+ URLClassLoader urlClassLoader = createClassLoader(jarFile.toURI().toURL());
+ JarFileLocator jarFileLocator = new DefaultJarFileLocator(urlClassLoader);
+ File locatedJarFile = jarFileLocator.locateJarFile().get();
+ assertThat(locatedJarFile, is(jarFile));
+ }
+
+ private File createJarFile(File folder) throws Exception {
+ File jarFile = new File(folder, "test.jar");
+ copyClassFileToStream(RESOURCE_TO_COPY, new FileOutputStream(jarFile));
+ return jarFile;
+ }
+
+ private void copyClassFileToStream(String fileToCopy, FileOutputStream outputStream) throws IOException {
+ try (JarOutputStream jarOutputStream = new JarOutputStream(outputStream);
+ InputStream inputStream = getClass().getResourceAsStream("/" + fileToCopy)) {
+ jarOutputStream.putNextEntry(new JarEntry(fileToCopy));
+ StreamCopier.copy(inputStream, jarOutputStream);
+ jarOutputStream.closeEntry();
+ }
+ }
+
+ private URLClassLoader createClassLoader(URL url) throws MalformedURLException {
+ return new URLClassLoader(new URL[] { url }) {
+ @Override
+ public URL getResource(String name) {
+ /* ignore parent class loader here. */
+ return findResource(name);
+ }
+ };
+ }
+
+ @Test
+ public void jarFileCanNotBeLocatedWhenLoadedFromFile() throws Exception {
+ File folder = temporaryFolder.newFolder(PACKAGE_NAME.split("\\."));
+ createClassFile(folder);
+ ClassLoader classLoader = createClassLoader(temporaryFolder.getRoot().toURI().toURL());
+ JarFileLocator jarFileLocator = new DefaultJarFileLocator(classLoader);
+ Optional<File> locatedJarFile = jarFileLocator.locateJarFile();
+ assertThat(locatedJarFile.isPresent(), is(false));
+ }
+
+ private void createClassFile(File folder) throws IOException {
+ File classFile = new File(folder, CLASS_FILENAME);
+ try (FileOutputStream outputStream = new FileOutputStream(classFile)) {
+ copyClassFileToStream(RESOURCE_TO_COPY, outputStream);
+ }
+ }
+
+ @Test
+ public void jarFileCanNotBeLoadedIfClasspathIsSuperWeirdAndClassDoesNotExist() throws Exception {
+ ClassLoader classLoader = createClassLoader(temporaryFolder.getRoot().toURI().toURL());
+ JarFileLocator jarFileLocator = new DefaultJarFileLocator(classLoader);
+ Optional<File> locatedJarFile = jarFileLocator.locateJarFile();
+ assertThat(locatedJarFile.isPresent(), is(false));
+ }
+
+}