Startup system using Guice and plugin loading
This commit is contained in:
parent
5622b4a2b5
commit
4670a010be
@ -25,7 +25,6 @@
|
||||
<classpathentry kind="lib" path="lib-test/junit-dep-4.8.2.jar"/>
|
||||
<classpathentry kind="lib" path="lib-test/uispec4j-2.3-jdk16.jar"/>
|
||||
<classpathentry kind="lib" path="resources"/>
|
||||
<classpathentry kind="lib" path="lib/jspf.core-1.0.2.jar" sourcepath="/home/sampo/Projects/lib/jspf/documentation/api"/>
|
||||
<classpathentry kind="lib" path="lib/opencsv-2.3.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jogl/gluegen-rt.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jogl/jogl.all.jar"/>
|
||||
|
@ -24,6 +24,7 @@
|
||||
<!-- The main class of the application -->
|
||||
<property name="main-class" value="net.sf.openrocket.startup.Startup"/>
|
||||
|
||||
<property name="expanded-libs" value="lib/miglayout15-swing.jar"/>
|
||||
|
||||
<!-- Classpath definitions -->
|
||||
<path id="classpath">
|
||||
@ -64,37 +65,40 @@
|
||||
<target name="build">
|
||||
<mkdir dir="${classes.dir}"/>
|
||||
<echo level="info">Compiling main classes</echo>
|
||||
<javac debug="true" srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/>
|
||||
<javac debug="true" srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath" includeantruntime="false"/>
|
||||
</target>
|
||||
|
||||
<!-- Executible Eclipse-Jar-In-Jar style JAR -->
|
||||
<target name="jar" depends="core-jar" description="Create the OpenRocket jar-in-jar Executable">
|
||||
<target name="jar" depends="build" description="Create the OpenRocket executable JAR">
|
||||
<mkdir dir="${jar.dir}" />
|
||||
<jar destfile="${jar.file}">
|
||||
<jar destfile="${jar.file}" basedir="${dist.dir}">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader" />
|
||||
<attribute name="Rsrc-Main-Class" value="${main-class}" />
|
||||
<attribute name="Main-Class" value="${main-class}" />
|
||||
<attribute name="SplashScreen-Image" value="pix/splashscreen.png" />
|
||||
<attribute name="Class-Path" value="." />
|
||||
<attribute name="Rsrc-Class-Path" value="./ main/${ant.project.name}-Core.jar lib/jfreechart-1.0.13.jar lib/jcommon-1.0.16.jar lib/gluegen-rt.jar lib/miglayout15-swing.jar lib/iText-5.0.2.jar lib/jogl.all.jar lib/opencsv-2.3.jar lib/OrangeExtensions-1.2.jar" />
|
||||
<attribute name="Classpath-Jars" value="lib/gluegen-rt.jar lib/jogl.all.jar" />
|
||||
</manifest>
|
||||
|
||||
<!-- Unzip the Eclipse JIJ Loader -->
|
||||
<zipfileset src="lib/jar-in-jar-loader.jar" />
|
||||
|
||||
<!-- Include, in the root of the JAR, the resources needed by OR -->
|
||||
<fileset dir="src/" includes="META-INF/" />
|
||||
<fileset dir="resources/" />
|
||||
|
||||
<!-- Include the core OpenRocket JAR -->
|
||||
<zipfileset dir="${build.dir}/" prefix="main">
|
||||
<include name="${ant.project.name}-Core.jar"/>
|
||||
</zipfileset>
|
||||
|
||||
<!-- Include libraries needed by OR -->
|
||||
<zipfileset dir="${lib.dir}" prefix="lib">
|
||||
<include name="*.jar"/>
|
||||
</zipfileset>
|
||||
<!-- Libraries to extract into base JAR -->
|
||||
<zipfileset src="lib/miglayout15-swing.jar" />
|
||||
<zipfileset src="lib/guice-3.0.jar" />
|
||||
<zipfileset src="lib/aopalliance.jar"/>
|
||||
<zipfileset src="lib/guice-3.0.jar"/>
|
||||
<zipfileset src="lib/guice-multibindings-3.0.jar"/>
|
||||
<zipfileset src="lib/iText-5.0.2.jar"/>
|
||||
<zipfileset src="lib/javax.inject.jar"/>
|
||||
<zipfileset src="lib/jcommon-1.0.16.jar"/>
|
||||
<zipfileset src="lib/jfreechart-1.0.13.jar"/>
|
||||
<zipfileset src="lib/miglayout15-swing.jar"/>
|
||||
<zipfileset src="lib/opencsv-2.3.jar"/>
|
||||
<zipfileset src="lib/OrangeExtensions-1.2.jar"/>
|
||||
|
||||
|
||||
<!-- JOGL libraries need to be jar-in-jar -->
|
||||
<zipfileset dir="${lib.dir}/jogl" prefix="lib">
|
||||
<include name="*.jar"/>
|
||||
</zipfileset>
|
||||
@ -105,16 +109,6 @@
|
||||
</target>
|
||||
|
||||
|
||||
<!-- Core OpenRocket JAR -->
|
||||
<target name="core-jar" depends="build" description="Create the OpenRocket code-only jar file">
|
||||
<jar destfile="${build.dir}/${ant.project.name}-Core.jar" basedir="${dist.dir}">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="${main-class}"/>
|
||||
<attribute name="SplashScreen-Image" value="pix/splashscreen.png"/>
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<!-- CONVERT vendor csv to ORC files -->
|
||||
<macrodef name="build-orc-file">
|
||||
<attribute name="dir"/>
|
||||
|
Binary file not shown.
Binary file not shown.
@ -1,10 +0,0 @@
|
||||
package net.sf.openrocket.plugin;
|
||||
|
||||
public class CopyOfExamplePluginImpl implements ExamplePlugin {
|
||||
|
||||
@Override
|
||||
public void doit() {
|
||||
System.out.println("CopyOfExamplePluginImpl.doit() called");
|
||||
}
|
||||
|
||||
}
|
29
core/src/net/sf/openrocket/plugin/JIJ.java
Normal file
29
core/src/net/sf/openrocket/plugin/JIJ.java
Normal file
@ -0,0 +1,29 @@
|
||||
package net.sf.openrocket.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class JIJ {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String cp = System.getProperty("java.class.path");
|
||||
String[] cps = cp.split(File.pathSeparator);
|
||||
|
||||
URL[] urls = new URL[cps.length + 1];
|
||||
for (int i = 0; i < cps.length; i++) {
|
||||
urls[i] = new File(cps[i]).toURI().toURL();
|
||||
}
|
||||
urls[cps.length] = new File("/home/sampo/Projects/OpenRocket/core/example.jar").toURL();
|
||||
|
||||
System.out.println("Classpath: " + Arrays.toString(urls));
|
||||
|
||||
URLClassLoader loader = new URLClassLoader(urls, null);
|
||||
Class<?> c = loader.loadClass("net.sf.openrocket.plugin.Test");
|
||||
Method m = c.getMethod("main", args.getClass());
|
||||
m.invoke(null, (Object) args);
|
||||
}
|
||||
|
||||
}
|
37
core/src/net/sf/openrocket/plugin/PluginHelper.java
Normal file
37
core/src/net/sf/openrocket/plugin/PluginHelper.java
Normal file
@ -0,0 +1,37 @@
|
||||
package net.sf.openrocket.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.sf.openrocket.arch.SystemInfo;
|
||||
|
||||
public class PluginHelper {
|
||||
|
||||
private static final String PLUGIN_DIRECTORY = "Plugins";
|
||||
private static final String PLUGIN_EXTENSION = ".jar";
|
||||
|
||||
public static List<File> getPluginJars() {
|
||||
File userDir = SystemInfo.getUserApplicationDirectory();
|
||||
File pluginDir = new File(userDir, PLUGIN_DIRECTORY);
|
||||
if (!pluginDir.exists()) {
|
||||
pluginDir.mkdirs();
|
||||
}
|
||||
|
||||
File[] files = pluginDir.listFiles(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.toLowerCase().endsWith(PLUGIN_EXTENSION);
|
||||
}
|
||||
});
|
||||
|
||||
if (files == null) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
return Arrays.asList(files);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -21,7 +21,7 @@ import com.google.inject.multibindings.Multibinder;
|
||||
*/
|
||||
public class PluginModule extends AbstractModule {
|
||||
|
||||
private final File[] jars;
|
||||
private final List<File> jars;
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
private Map<Class<?>, Multibinder<?>> binders = new HashMap<Class<?>, Multibinder<?>>();
|
||||
@ -33,8 +33,8 @@ public class PluginModule extends AbstractModule {
|
||||
* @param jars the JAR files to search for plugins
|
||||
* @param classLoader the class loader used to load classes from the JAR files
|
||||
*/
|
||||
public PluginModule(File[] jars, ClassLoader classLoader) {
|
||||
this.jars = jars.clone();
|
||||
public PluginModule(List<File> jars, ClassLoader classLoader) {
|
||||
this.jars = jars;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@ import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
@ -25,10 +27,20 @@ public class Test {
|
||||
|
||||
|
||||
public static void main(String[] args) throws MalformedURLException {
|
||||
// Properties p = System.getProperties();
|
||||
// Enumeration<Object> e = p.keys();
|
||||
// while (e.hasMoreElements()) {
|
||||
// Object key = e.nextElement();
|
||||
// Object value = p.get(key);
|
||||
// System.out.println(key + " = " + value);
|
||||
// }
|
||||
|
||||
File[] jars = { new File("/home/sampo/Projects/OpenRocket/core/example.jar") };
|
||||
List<File> jars = Arrays.asList(new File("/home/sampo/Projects/OpenRocket/core/example.jar"));
|
||||
URL[] urls = { new File("/home/sampo/Projects/OpenRocket/core/example.jar").toURL() };
|
||||
URLClassLoader classLoader = new URLClassLoader(urls);
|
||||
ClassLoader classLoader = new URLClassLoader(urls);
|
||||
|
||||
classLoader = Test.class.getClassLoader();
|
||||
|
||||
Injector injector = Guice.createInjector(new PluginModule(jars, classLoader));
|
||||
injector.getInstance(Test.class).run();
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import net.sf.openrocket.material.Material;
|
||||
import net.sf.openrocket.preset.ComponentPreset;
|
||||
import net.sf.openrocket.preset.xml.OpenRocketComponentSaver;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.startup.Startup;
|
||||
import net.sf.openrocket.startup.GuiceStartup;
|
||||
import net.sf.openrocket.util.ArrayList;
|
||||
|
||||
import java.io.File;
|
||||
@ -37,7 +37,7 @@ public class RocksimComponentFileTranslator {
|
||||
|
||||
LOGGER.println("Loading csv files from directory " + args[0]);
|
||||
|
||||
Startup.initializeLogging();
|
||||
GuiceStartup.initializeLogging();
|
||||
Application.setPreferences(new SwingPreferences());
|
||||
|
||||
MaterialHolder materialMap = loadAll(allPresets, new File(args[0]));
|
||||
|
15
core/src/net/sf/openrocket/startup/ApplicationModule.java
Normal file
15
core/src/net/sf/openrocket/startup/ApplicationModule.java
Normal file
@ -0,0 +1,15 @@
|
||||
package net.sf.openrocket.startup;
|
||||
|
||||
import net.sf.openrocket.logging.LogHelper;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
public class ApplicationModule extends AbstractModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(LogHelper.class).toInstance(Application.getLogger());
|
||||
bind(Preferences.class).toInstance(Application.getPreferences());
|
||||
}
|
||||
|
||||
}
|
@ -25,41 +25,45 @@ import net.sf.openrocket.gui.util.SwingPreferences;
|
||||
import net.sf.openrocket.logging.LogHelper;
|
||||
import net.sf.openrocket.util.BuildProperties;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* The second class in the OpenRocket startup sequence. This class can assume the
|
||||
* Application class to be properly set up, and can use any classes safely.
|
||||
*
|
||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||
*/
|
||||
public class Startup2 {
|
||||
private static final LogHelper log = Application.getLogger();
|
||||
|
||||
|
||||
public class ApplicationStartup {
|
||||
|
||||
@Inject
|
||||
private LogHelper log;
|
||||
|
||||
|
||||
private static final String THRUSTCURVE_DIRECTORY = "datafiles/thrustcurves/";
|
||||
|
||||
|
||||
/**
|
||||
* Run when starting up OpenRocket after Application has been set up.
|
||||
*
|
||||
* @param args command line arguments
|
||||
*/
|
||||
static void runMain(final String[] args) throws Exception {
|
||||
|
||||
public void runMain(final String[] args) throws Exception {
|
||||
|
||||
log.info("Starting up OpenRocket version " + BuildProperties.getVersion());
|
||||
|
||||
|
||||
// Check that we're not running headless
|
||||
log.info("Checking for graphics head");
|
||||
checkHead();
|
||||
|
||||
|
||||
// Check that we're running a good version of a JRE
|
||||
log.info("Checking JRE compatibility");
|
||||
VersionHelper.checkVersion();
|
||||
VersionHelper.checkOpenJDK();
|
||||
|
||||
|
||||
// If running on a MAC set up OSX UI Elements.
|
||||
if ( SystemInfo.getPlatform() == Platform.MAC_OS ){
|
||||
if (SystemInfo.getPlatform() == Platform.MAC_OS) {
|
||||
OSXStartup.setupOSX();
|
||||
}
|
||||
|
||||
|
||||
// Run the actual startup method in the EDT since it can use progress dialogs etc.
|
||||
log.info("Moving startup to EDT");
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
@ -68,50 +72,50 @@ public class Startup2 {
|
||||
runInEDT(args);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
log.info("Startup complete");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Run in the EDT when starting up OpenRocket.
|
||||
*
|
||||
* @param args command line arguments
|
||||
*/
|
||||
private static void runInEDT(String[] args) {
|
||||
|
||||
private void runInEDT(String[] args) {
|
||||
|
||||
// Initialize the splash screen with version info
|
||||
log.info("Initializing the splash screen");
|
||||
Splash.init();
|
||||
|
||||
|
||||
// Must be done after localization is initialized
|
||||
ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase(true) {
|
||||
|
||||
|
||||
@Override
|
||||
protected void load() {
|
||||
ConcurrentComponentPresetDatabaseLoader presetLoader = new ConcurrentComponentPresetDatabaseLoader( this );
|
||||
ConcurrentComponentPresetDatabaseLoader presetLoader = new ConcurrentComponentPresetDatabaseLoader(this);
|
||||
presetLoader.load();
|
||||
try {
|
||||
presetLoader.await();
|
||||
} catch ( InterruptedException iex) {
|
||||
|
||||
} catch (InterruptedException iex) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
Application.setComponentPresetDao( componentPresetDao );
|
||||
|
||||
Application.setComponentPresetDao(componentPresetDao);
|
||||
|
||||
componentPresetDao.startLoading();
|
||||
|
||||
|
||||
// Setup the uncaught exception handler
|
||||
log.info("Registering exception handler");
|
||||
SwingExceptionHandler exceptionHandler = new SwingExceptionHandler();
|
||||
Application.setExceptionHandler(exceptionHandler);
|
||||
exceptionHandler.registerExceptionHandler();
|
||||
|
||||
|
||||
// Start update info fetching
|
||||
final UpdateInfoRetriever updateInfo;
|
||||
if ( Application.getPreferences().getCheckUpdates()) {
|
||||
if (Application.getPreferences().getCheckUpdates()) {
|
||||
log.info("Starting update check");
|
||||
updateInfo = new UpdateInfoRetriever();
|
||||
updateInfo.start();
|
||||
@ -119,68 +123,68 @@ public class Startup2 {
|
||||
log.info("Update check disabled");
|
||||
updateInfo = null;
|
||||
}
|
||||
|
||||
|
||||
// Set the best available look-and-feel
|
||||
log.info("Setting best LAF");
|
||||
GUIUtil.setBestLAF();
|
||||
|
||||
|
||||
// Set tooltip delay time. Tooltips are used in MotorChooserDialog extensively.
|
||||
ToolTipManager.sharedInstance().setDismissDelay(30000);
|
||||
|
||||
|
||||
// Load defaults
|
||||
((SwingPreferences) Application.getPreferences()).loadDefaultUnits();
|
||||
|
||||
|
||||
// Load motors etc.
|
||||
log.info("Loading databases");
|
||||
|
||||
|
||||
loadMotor();
|
||||
|
||||
|
||||
Databases.fakeMethod();
|
||||
|
||||
|
||||
|
||||
|
||||
// Starting action (load files or open new document)
|
||||
log.info("Opening main application window");
|
||||
if (!handleCommandLine(args)) {
|
||||
if (!Application.getPreferences().isAutoOpenLastDesignOnStartupEnabled()) {
|
||||
BasicFrame.newAction();
|
||||
}
|
||||
else {
|
||||
String lastFile = MRUDesignFile.getInstance().getLastEditedDesignFile();
|
||||
if (lastFile != null) {
|
||||
if (!BasicFrame.open(new File(lastFile), null)) {
|
||||
MRUDesignFile.getInstance().removeFile(lastFile);
|
||||
BasicFrame.newAction();
|
||||
}
|
||||
else {
|
||||
MRUDesignFile.getInstance().addFile(lastFile);
|
||||
}
|
||||
}
|
||||
else {
|
||||
BasicFrame.newAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Application.getPreferences().isAutoOpenLastDesignOnStartupEnabled()) {
|
||||
BasicFrame.newAction();
|
||||
}
|
||||
else {
|
||||
String lastFile = MRUDesignFile.getInstance().getLastEditedDesignFile();
|
||||
if (lastFile != null) {
|
||||
if (!BasicFrame.open(new File(lastFile), null)) {
|
||||
MRUDesignFile.getInstance().removeFile(lastFile);
|
||||
BasicFrame.newAction();
|
||||
}
|
||||
else {
|
||||
MRUDesignFile.getInstance().addFile(lastFile);
|
||||
}
|
||||
}
|
||||
else {
|
||||
BasicFrame.newAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether update info has been fetched or whether it needs more time
|
||||
log.info("Checking update status");
|
||||
checkUpdateStatus(updateInfo);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* this method is useful for the python bindings.
|
||||
*/
|
||||
public static void loadMotor() {
|
||||
public void loadMotor() {
|
||||
ConcurrentLoadingThrustCurveMotorSetDatabase motorLoader = new ConcurrentLoadingThrustCurveMotorSetDatabase(THRUSTCURVE_DIRECTORY);
|
||||
motorLoader.startLoading();
|
||||
Application.setMotorSetDatabase(motorLoader);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check that the JRE is not running headless.
|
||||
*/
|
||||
private static void checkHead() {
|
||||
|
||||
private void checkHead() {
|
||||
|
||||
if (GraphicsEnvironment.isHeadless()) {
|
||||
log.error("Application is headless.");
|
||||
System.err.println();
|
||||
@ -189,36 +193,36 @@ public class Startup2 {
|
||||
System.err.println();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static void checkUpdateStatus(final UpdateInfoRetriever updateInfo) {
|
||||
|
||||
|
||||
private void checkUpdateStatus(final UpdateInfoRetriever updateInfo) {
|
||||
if (updateInfo == null)
|
||||
return;
|
||||
|
||||
|
||||
int delay = 1000;
|
||||
if (!updateInfo.isRunning())
|
||||
delay = 100;
|
||||
|
||||
|
||||
final Timer timer = new Timer(delay, null);
|
||||
|
||||
|
||||
ActionListener listener = new ActionListener() {
|
||||
private int count = 5;
|
||||
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (!updateInfo.isRunning()) {
|
||||
timer.stop();
|
||||
|
||||
|
||||
String current = BuildProperties.getVersion();
|
||||
String last = Application.getPreferences().getString(Preferences.LAST_UPDATE, "");
|
||||
|
||||
|
||||
UpdateInfo info = updateInfo.getUpdateInfo();
|
||||
if (info != null && info.getLatestVersion() != null &&
|
||||
!current.equals(info.getLatestVersion()) &&
|
||||
!last.equals(info.getLatestVersion())) {
|
||||
|
||||
|
||||
UpdateInfoDialog infoDialog = new UpdateInfoDialog(info);
|
||||
infoDialog.setVisible(true);
|
||||
if (infoDialog.isReminderSelected()) {
|
||||
@ -236,7 +240,7 @@ public class Startup2 {
|
||||
timer.addActionListener(listener);
|
||||
timer.start();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles arguments passed from the command line. This may be used either
|
||||
* when starting the first instance of OpenRocket or later when OpenRocket is
|
||||
@ -246,8 +250,8 @@ public class Startup2 {
|
||||
* @return whether a new frame was opened or similar user desired action was
|
||||
* performed as a result.
|
||||
*/
|
||||
private static boolean handleCommandLine(String[] args) {
|
||||
|
||||
private boolean handleCommandLine(String[] args) {
|
||||
|
||||
// Check command-line for files
|
||||
boolean opened = false;
|
||||
for (String file : args) {
|
||||
@ -257,5 +261,5 @@ public class Startup2 {
|
||||
}
|
||||
return opened;
|
||||
}
|
||||
|
||||
|
||||
}
|
219
core/src/net/sf/openrocket/startup/GuiceStartup.java
Normal file
219
core/src/net/sf/openrocket/startup/GuiceStartup.java
Normal file
@ -0,0 +1,219 @@
|
||||
package net.sf.openrocket.startup;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.Locale;
|
||||
import java.util.prefs.Preferences;
|
||||
|
||||
import net.sf.openrocket.gui.util.SwingPreferences;
|
||||
import net.sf.openrocket.l10n.DebugTranslator;
|
||||
import net.sf.openrocket.l10n.L10N;
|
||||
import net.sf.openrocket.l10n.ResourceBundleTranslator;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.logging.DelegatorLogger;
|
||||
import net.sf.openrocket.logging.LogHelper;
|
||||
import net.sf.openrocket.logging.LogLevel;
|
||||
import net.sf.openrocket.logging.LogLevelBufferLogger;
|
||||
import net.sf.openrocket.logging.PrintStreamLogger;
|
||||
import net.sf.openrocket.plugin.PluginHelper;
|
||||
import net.sf.openrocket.plugin.PluginModule;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
|
||||
|
||||
/**
|
||||
* Second class in the OpenRocket startup sequence, responsible for
|
||||
* IoC initialization.
|
||||
*
|
||||
* This class is responsible for initializing the Guice dependency injection
|
||||
* mechanism, and the legacy Application class.
|
||||
*
|
||||
* This class must be very cautious about what classes it calls. This is because
|
||||
* the loggers/translators for classes are initialized as static final members during
|
||||
* class initialization. For example, this class MUST NOT use the Prefs class, because
|
||||
* using it will cause LineStyle to be initialized, which then receives an invalid
|
||||
* (not-yet-initialized) translator.
|
||||
*
|
||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||
*/
|
||||
public class GuiceStartup {
|
||||
|
||||
static LogHelper log;
|
||||
|
||||
private static final String LOG_STDERR_PROPERTY = "openrocket.log.stderr";
|
||||
private static final String LOG_STDOUT_PROPERTY = "openrocket.log.stdout";
|
||||
|
||||
private static final int LOG_BUFFER_LENGTH = 50;
|
||||
|
||||
/**
|
||||
* OpenRocket startup main method.
|
||||
*/
|
||||
public static void main(final String[] args) throws Exception {
|
||||
|
||||
// Check for "openrocket.debug" property before anything else
|
||||
checkDebugStatus();
|
||||
|
||||
// Initialize logging first so we can use it
|
||||
initializeLogging();
|
||||
|
||||
// Setup the translations
|
||||
initializeL10n();
|
||||
|
||||
// Initialize preferences (*after* translator setup!)
|
||||
Application.setPreferences(new SwingPreferences());
|
||||
|
||||
|
||||
Injector injector = initializeGuice();
|
||||
injector.getInstance(ApplicationStartup.class).runMain(args);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set proper system properties if openrocket.debug is defined.
|
||||
*/
|
||||
private static void checkDebugStatus() {
|
||||
if (System.getProperty("openrocket.debug") != null) {
|
||||
setPropertyIfNotSet("openrocket.log.stdout", "VBOSE");
|
||||
setPropertyIfNotSet("openrocket.log.tracelevel", "VBOSE");
|
||||
setPropertyIfNotSet("openrocket.debug.menu", "true");
|
||||
setPropertyIfNotSet("openrocket.debug.mutexlocation", "true");
|
||||
setPropertyIfNotSet("openrocket.debug.motordigest", "true");
|
||||
}
|
||||
}
|
||||
|
||||
private static void setPropertyIfNotSet(String key, String value) {
|
||||
if (System.getProperty(key) == null) {
|
||||
System.setProperty(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the loggins system.
|
||||
*/
|
||||
public static void initializeLogging() {
|
||||
DelegatorLogger delegator = new DelegatorLogger();
|
||||
|
||||
// Log buffer
|
||||
LogLevelBufferLogger buffer = new LogLevelBufferLogger(LOG_BUFFER_LENGTH);
|
||||
delegator.addLogger(buffer);
|
||||
|
||||
// Check whether to log to stdout/stderr
|
||||
PrintStreamLogger printer = new PrintStreamLogger();
|
||||
boolean logout = setLogOutput(printer, System.out, System.getProperty(LOG_STDOUT_PROPERTY), null);
|
||||
boolean logerr = setLogOutput(printer, System.err, System.getProperty(LOG_STDERR_PROPERTY), LogLevel.ERROR);
|
||||
if (logout || logerr) {
|
||||
delegator.addLogger(printer);
|
||||
}
|
||||
|
||||
// Set the loggers
|
||||
Application.setLogger(delegator);
|
||||
Application.setLogBuffer(buffer);
|
||||
|
||||
// Initialize the log for this class
|
||||
log = Application.getLogger();
|
||||
log.info("Logging subsystem initialized");
|
||||
String str = "Console logging output:";
|
||||
for (LogLevel l : LogLevel.values()) {
|
||||
PrintStream ps = printer.getOutput(l);
|
||||
str += " " + l.name() + ":";
|
||||
if (ps == System.err) {
|
||||
str += "stderr";
|
||||
} else if (ps == System.out) {
|
||||
str += "stdout";
|
||||
} else {
|
||||
str += "none";
|
||||
}
|
||||
}
|
||||
str += " (" + LOG_STDOUT_PROPERTY + "=" + System.getProperty(LOG_STDOUT_PROPERTY) +
|
||||
" " + LOG_STDERR_PROPERTY + "=" + System.getProperty(LOG_STDERR_PROPERTY) + ")";
|
||||
log.info(str);
|
||||
}
|
||||
|
||||
private static boolean setLogOutput(PrintStreamLogger logger, PrintStream stream, String level, LogLevel defaultLevel) {
|
||||
LogLevel minLevel = LogLevel.fromString(level, defaultLevel);
|
||||
if (minLevel == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (LogLevel l : LogLevel.values()) {
|
||||
if (l.atLeast(minLevel)) {
|
||||
logger.setOutput(l, stream);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the localization system.
|
||||
*/
|
||||
private static void initializeL10n() {
|
||||
|
||||
// Check for locale propery
|
||||
String langcode = System.getProperty("openrocket.locale");
|
||||
|
||||
if (langcode != null) {
|
||||
|
||||
Locale l = L10N.toLocale(langcode);
|
||||
log.info("Setting custom locale " + l);
|
||||
Locale.setDefault(l);
|
||||
|
||||
} else {
|
||||
|
||||
// Check user-configured locale
|
||||
Locale l = getUserLocale();
|
||||
if (l != null) {
|
||||
log.info("Setting user-selected locale " + l);
|
||||
Locale.setDefault(l);
|
||||
} else {
|
||||
log.info("Using default locale " + Locale.getDefault());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Setup the translator
|
||||
Translator t;
|
||||
t = new ResourceBundleTranslator("l10n.messages");
|
||||
if (Locale.getDefault().getLanguage().equals("xx")) {
|
||||
t = new DebugTranslator(t);
|
||||
}
|
||||
|
||||
log.info("Set up translation for locale " + Locale.getDefault() +
|
||||
", debug.currentFile=" + t.get("debug.currentFile"));
|
||||
|
||||
Application.setBaseTranslator(t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static Locale getUserLocale() {
|
||||
/*
|
||||
* This method MUST NOT use the Prefs class, since is causes a multitude
|
||||
* of classes to be initialized. Therefore this duplicates the functionality
|
||||
* of the Prefs class locally.
|
||||
*/
|
||||
|
||||
if (System.getProperty("openrocket.debug.prefs") != null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return L10N.toLocale(Preferences.userRoot().node("OpenRocket").get("locale", null));
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static Injector initializeGuice() {
|
||||
Module applicationModule = new ApplicationModule();
|
||||
Module pluginModule = new PluginModule(PluginHelper.getPluginJars(), GuiceStartup.class.getClassLoader());
|
||||
|
||||
return Guice.createInjector(applicationModule, pluginModule);
|
||||
}
|
||||
|
||||
}
|
@ -102,7 +102,7 @@ final class OSXStartup {
|
||||
|
||||
// Set the dock icon to the largest icon
|
||||
final Image dockIcon = Toolkit.getDefaultToolkit().getImage(
|
||||
Startup2.class.getResource(ICON_RSRC));
|
||||
ApplicationStartup.class.getResource(ICON_RSRC));
|
||||
osxApp.setDockIconImage(dockIcon);
|
||||
|
||||
} catch (final Throwable t) {
|
||||
|
@ -1,201 +1,43 @@
|
||||
package net.sf.openrocket.startup;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.Locale;
|
||||
import java.util.prefs.Preferences;
|
||||
|
||||
import net.sf.openrocket.gui.util.SwingPreferences;
|
||||
import net.sf.openrocket.l10n.DebugTranslator;
|
||||
import net.sf.openrocket.l10n.L10N;
|
||||
import net.sf.openrocket.l10n.ResourceBundleTranslator;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.logging.DelegatorLogger;
|
||||
import net.sf.openrocket.logging.LogHelper;
|
||||
import net.sf.openrocket.logging.LogLevel;
|
||||
import net.sf.openrocket.logging.LogLevelBufferLogger;
|
||||
import net.sf.openrocket.logging.PrintStreamLogger;
|
||||
import java.net.URL;
|
||||
|
||||
import net.sf.openrocket.startup.jij.ClasspathUrlStreamHandler;
|
||||
import net.sf.openrocket.startup.jij.ConfigurableStreamHandlerFactory;
|
||||
import net.sf.openrocket.startup.jij.CurrentClasspathProvider;
|
||||
import net.sf.openrocket.startup.jij.JarInJarStarter;
|
||||
import net.sf.openrocket.startup.jij.ManifestClasspathProvider;
|
||||
import net.sf.openrocket.startup.jij.PluginClasspathProvider;
|
||||
|
||||
/**
|
||||
* The first class in the OpenRocket startup sequence. This class is responsible
|
||||
* for setting up the Application class with the statically used subsystems
|
||||
* (logging and translation) and then delegating to Startup2 class.
|
||||
* <p>
|
||||
* This class must be very cautious about what classes it calls. This is because
|
||||
* the loggers/translators for classes are initialized as static final members during
|
||||
* class initialization. For example, this class MUST NOT use the Prefs class, because
|
||||
* using it will cause LineStyle to be initialized, which then receives an invalid
|
||||
* (not-yet-initialized) translator.
|
||||
* First step in the OpenRocket startup sequence, responsible for
|
||||
* classpath setup.
|
||||
*
|
||||
* The startup class sequence is the following:
|
||||
* 1. Startup
|
||||
* 2. GuiceStartup
|
||||
* 3. ApplicationStartup
|
||||
*
|
||||
* This class changes the current classpath to contain the jar-in-jar
|
||||
* library dependencies and plugins in the current classpath, and
|
||||
* then launches the next step of the startup sequence.
|
||||
*
|
||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||
*/
|
||||
public class Startup {
|
||||
|
||||
static LogHelper log;
|
||||
private static final String STARTUP_CLASS = "net.sf.openrocket.startup.GuiceStartup";
|
||||
|
||||
private static final String LOG_STDERR_PROPERTY = "openrocket.log.stderr";
|
||||
private static final String LOG_STDOUT_PROPERTY = "openrocket.log.stdout";
|
||||
|
||||
private static final int LOG_BUFFER_LENGTH = 50;
|
||||
|
||||
/**
|
||||
* OpenRocket startup main method.
|
||||
*/
|
||||
public static void main(final String[] args) throws Exception {
|
||||
|
||||
// Check for "openrocket.debug" property before anything else
|
||||
checkDebugStatus();
|
||||
|
||||
// Initialize logging first so we can use it
|
||||
initializeLogging();
|
||||
|
||||
Application.setPreferences( new SwingPreferences() );
|
||||
|
||||
// Setup the translations
|
||||
initializeL10n();
|
||||
|
||||
// Continue startup in Startup2 class (where Application is already set up)
|
||||
Startup2.runMain(args);
|
||||
|
||||
public static void main(String[] args) {
|
||||
addClasspathUrlHandler();
|
||||
JarInJarStarter.runMain(STARTUP_CLASS, args, new CurrentClasspathProvider(),
|
||||
new ManifestClasspathProvider(), new PluginClasspathProvider());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set proper system properties if openrocket.debug is defined.
|
||||
*/
|
||||
private static void checkDebugStatus() {
|
||||
if (System.getProperty("openrocket.debug") != null) {
|
||||
setPropertyIfNotSet("openrocket.log.stdout", "VBOSE");
|
||||
setPropertyIfNotSet("openrocket.log.tracelevel", "VBOSE");
|
||||
setPropertyIfNotSet("openrocket.debug.menu", "true");
|
||||
setPropertyIfNotSet("openrocket.debug.mutexlocation", "true");
|
||||
setPropertyIfNotSet("openrocket.debug.motordigest", "true");
|
||||
}
|
||||
private static void addClasspathUrlHandler() {
|
||||
ConfigurableStreamHandlerFactory factory = new ConfigurableStreamHandlerFactory();
|
||||
factory.addHandler("classpath", new ClasspathUrlStreamHandler());
|
||||
URL.setURLStreamHandlerFactory(factory);
|
||||
}
|
||||
|
||||
private static void setPropertyIfNotSet(String key, String value) {
|
||||
if (System.getProperty(key) == null) {
|
||||
System.setProperty(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the loggins system.
|
||||
*/
|
||||
public static void initializeLogging() {
|
||||
DelegatorLogger delegator = new DelegatorLogger();
|
||||
|
||||
// Log buffer
|
||||
LogLevelBufferLogger buffer = new LogLevelBufferLogger(LOG_BUFFER_LENGTH);
|
||||
delegator.addLogger(buffer);
|
||||
|
||||
// Check whether to log to stdout/stderr
|
||||
PrintStreamLogger printer = new PrintStreamLogger();
|
||||
boolean logout = setLogOutput(printer, System.out, System.getProperty(LOG_STDOUT_PROPERTY), null);
|
||||
boolean logerr = setLogOutput(printer, System.err, System.getProperty(LOG_STDERR_PROPERTY), LogLevel.ERROR);
|
||||
if (logout || logerr) {
|
||||
delegator.addLogger(printer);
|
||||
}
|
||||
|
||||
// Set the loggers
|
||||
Application.setLogger(delegator);
|
||||
Application.setLogBuffer(buffer);
|
||||
|
||||
// Initialize the log for this class
|
||||
log = Application.getLogger();
|
||||
log.info("Logging subsystem initialized");
|
||||
String str = "Console logging output:";
|
||||
for (LogLevel l : LogLevel.values()) {
|
||||
PrintStream ps = printer.getOutput(l);
|
||||
str += " " + l.name() + ":";
|
||||
if (ps == System.err) {
|
||||
str += "stderr";
|
||||
} else if (ps == System.out) {
|
||||
str += "stdout";
|
||||
} else {
|
||||
str += "none";
|
||||
}
|
||||
}
|
||||
str += " (" + LOG_STDOUT_PROPERTY + "=" + System.getProperty(LOG_STDOUT_PROPERTY) +
|
||||
" " + LOG_STDERR_PROPERTY + "=" + System.getProperty(LOG_STDERR_PROPERTY) + ")";
|
||||
log.info(str);
|
||||
}
|
||||
|
||||
private static boolean setLogOutput(PrintStreamLogger logger, PrintStream stream, String level, LogLevel defaultLevel) {
|
||||
LogLevel minLevel = LogLevel.fromString(level, defaultLevel);
|
||||
if (minLevel == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (LogLevel l : LogLevel.values()) {
|
||||
if (l.atLeast(minLevel)) {
|
||||
logger.setOutput(l, stream);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the localization system.
|
||||
*/
|
||||
private static void initializeL10n() {
|
||||
|
||||
// Check for locale propery
|
||||
String langcode = System.getProperty("openrocket.locale");
|
||||
|
||||
if (langcode != null) {
|
||||
|
||||
Locale l = L10N.toLocale(langcode);
|
||||
log.info("Setting custom locale " + l);
|
||||
Locale.setDefault(l);
|
||||
|
||||
} else {
|
||||
|
||||
// Check user-configured locale
|
||||
Locale l = getUserLocale();
|
||||
if (l != null) {
|
||||
log.info("Setting user-selected locale " + l);
|
||||
Locale.setDefault(l);
|
||||
} else {
|
||||
log.info("Using default locale " + Locale.getDefault());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Setup the translator
|
||||
Translator t;
|
||||
t = new ResourceBundleTranslator("l10n.messages");
|
||||
if (Locale.getDefault().getLanguage().equals("xx")) {
|
||||
t = new DebugTranslator(t);
|
||||
}
|
||||
|
||||
log.info("Set up translation for locale " + Locale.getDefault() +
|
||||
", debug.currentFile=" + t.get("debug.currentFile"));
|
||||
|
||||
Application.setBaseTranslator(t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static Locale getUserLocale() {
|
||||
/*
|
||||
* This method MUST NOT use the Prefs class, since is causes a multitude
|
||||
* of classes to be initialized. Therefore this duplicates the functionality
|
||||
* of the Prefs class locally.
|
||||
*/
|
||||
|
||||
if (System.getProperty("openrocket.debug.prefs") != null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return L10N.toLocale(Preferences.userRoot().node("OpenRocket").get("locale", null));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
package net.sf.openrocket.startup.jij;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
public interface ClasspathProvider {
|
||||
|
||||
public List<URL> getUrls();
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package net.sf.openrocket.startup.jij;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLStreamHandler;
|
||||
|
||||
/**
|
||||
* A URL handler for classpath:// URLs.
|
||||
*
|
||||
* From http://stackoverflow.com/questions/861500/url-to-load-resources-from-the-classpath-in-java
|
||||
*/
|
||||
public class ClasspathUrlStreamHandler extends URLStreamHandler {
|
||||
|
||||
/** The classloader to find resources from. */
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
public ClasspathUrlStreamHandler() {
|
||||
this.classLoader = getClass().getClassLoader();
|
||||
}
|
||||
|
||||
public ClasspathUrlStreamHandler(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URLConnection openConnection(URL u) throws IOException {
|
||||
final URL resourceUrl = classLoader.getResource(u.getPath());
|
||||
return resourceUrl.openConnection();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package net.sf.openrocket.startup.jij;
|
||||
|
||||
import java.net.URLStreamHandler;
|
||||
import java.net.URLStreamHandlerFactory;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A URLStreamHandlerFactory that can be configured with various
|
||||
* handlers.
|
||||
*
|
||||
* From http://stackoverflow.com/questions/861500/url-to-load-resources-from-the-classpath-in-java
|
||||
*/
|
||||
public class ConfigurableStreamHandlerFactory implements URLStreamHandlerFactory {
|
||||
private final Map<String, URLStreamHandler> protocolHandlers;
|
||||
|
||||
public ConfigurableStreamHandlerFactory() {
|
||||
protocolHandlers = new HashMap<String, URLStreamHandler>();
|
||||
}
|
||||
|
||||
public void addHandler(String protocol, URLStreamHandler urlHandler) {
|
||||
protocolHandlers.put(protocol, urlHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URLStreamHandler createURLStreamHandler(String protocol) {
|
||||
return protocolHandlers.get(protocol);
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package net.sf.openrocket.startup.jij;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CurrentClasspathProvider implements ClasspathProvider {
|
||||
|
||||
@Override
|
||||
public List<URL> getUrls() {
|
||||
List<URL> urls = new ArrayList<URL>();
|
||||
|
||||
String classpath = System.getProperty("java.class.path");
|
||||
String[] cps = classpath.split(File.pathSeparator);
|
||||
|
||||
for (String cp : cps) {
|
||||
try {
|
||||
urls.add(new File(cp).toURI().toURL());
|
||||
} catch (MalformedURLException e) {
|
||||
System.err.println("Error initializing classpath " + e);
|
||||
}
|
||||
}
|
||||
|
||||
return urls;
|
||||
}
|
||||
|
||||
}
|
42
core/src/net/sf/openrocket/startup/jij/JarInJarStarter.java
Normal file
42
core/src/net/sf/openrocket/startup/jij/JarInJarStarter.java
Normal file
@ -0,0 +1,42 @@
|
||||
package net.sf.openrocket.startup.jij;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class JarInJarStarter {
|
||||
|
||||
/**
|
||||
* Runs a main class with an alternative classpath.
|
||||
*
|
||||
* @param mainClass the class containing the main method to call.
|
||||
* @param args the arguments to the main method.
|
||||
* @param providers the classpath sources.
|
||||
*/
|
||||
public static void runMain(String mainClass, String[] args, ClasspathProvider... providers) {
|
||||
List<URL> urls = new ArrayList<URL>();
|
||||
|
||||
for (ClasspathProvider p : providers) {
|
||||
urls.addAll(p.getUrls());
|
||||
}
|
||||
|
||||
System.out.println("New classpath:");
|
||||
for (URL u : urls) {
|
||||
System.out.println(" " + u);
|
||||
}
|
||||
|
||||
URL[] urlArray = urls.toArray(new URL[0]);
|
||||
ClassLoader loader = new URLClassLoader(urlArray, null);
|
||||
try {
|
||||
Class<?> c = loader.loadClass(mainClass);
|
||||
Method m = c.getMethod("main", args.getClass());
|
||||
m.invoke(null, (Object) args);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error starting OpenRocket", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package net.sf.openrocket.startup.jij;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import net.sf.openrocket.util.BugException;
|
||||
|
||||
public class ManifestClasspathProvider implements ClasspathProvider {
|
||||
|
||||
private static final String MANIFEST_ATTRIBUTE = "Classpath-Jars";
|
||||
|
||||
@Override
|
||||
public List<URL> getUrls() {
|
||||
try {
|
||||
List<String> manifest = readManifestLine(MANIFEST_ATTRIBUTE);
|
||||
|
||||
List<URL> urls = new ArrayList<URL>();
|
||||
for (String s : manifest) {
|
||||
parseManifestLine(urls, s);
|
||||
}
|
||||
|
||||
return urls;
|
||||
} catch (IOException e) {
|
||||
throw new BugException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private List<String> readManifestLine(String name) throws IOException {
|
||||
List<String> lines = new ArrayList<String>();
|
||||
|
||||
Enumeration<URL> resources = getClass().getClassLoader().getResources("META-INF/MANIFEST.MF");
|
||||
|
||||
while (resources.hasMoreElements()) {
|
||||
URL url = resources.nextElement();
|
||||
InputStream stream = url.openStream();
|
||||
Manifest manifest = new Manifest(stream);
|
||||
stream.close();
|
||||
|
||||
Attributes attr = manifest.getMainAttributes();
|
||||
if (attr == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String value = attr.getValue(name);
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lines.add(value);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void parseManifestLine(List<URL> urls, String manifest) throws MalformedURLException {
|
||||
String[] array = manifest.split("\\s");
|
||||
for (String s : array) {
|
||||
if (s.length() > 0) {
|
||||
if (getClass().getClassLoader().getResource(s) != null) {
|
||||
urls.add(new URL("classpath:" + s));
|
||||
} else {
|
||||
System.err.println("Library " + s + " not found on classpath, ignoring.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package net.sf.openrocket.startup.jij;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.sf.openrocket.plugin.PluginHelper;
|
||||
import net.sf.openrocket.util.BugException;
|
||||
|
||||
public class PluginClasspathProvider implements ClasspathProvider {
|
||||
|
||||
private static final String CUSTOM_PLUGIN_PROPERTY = "openrocket.plugins";
|
||||
|
||||
@Override
|
||||
public List<URL> getUrls() {
|
||||
List<URL> urls = new ArrayList<URL>();
|
||||
|
||||
findPluginDirectoryUrls(urls);
|
||||
findCustomPlugins(urls);
|
||||
|
||||
return urls;
|
||||
}
|
||||
|
||||
private void findPluginDirectoryUrls(List<URL> urls) {
|
||||
List<File> files = PluginHelper.getPluginJars();
|
||||
for (File f : files) {
|
||||
try {
|
||||
urls.add(f.toURI().toURL());
|
||||
} catch (MalformedURLException e) {
|
||||
throw new BugException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void findCustomPlugins(List<URL> urls) {
|
||||
String prop = System.getProperty(CUSTOM_PLUGIN_PROPERTY);
|
||||
if (prop == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String[] array = prop.split(File.pathSeparator);
|
||||
for (String s : array) {
|
||||
s = s.trim();
|
||||
if (s.length() > 0) {
|
||||
try {
|
||||
urls.add(new File(s).toURI().toURL());
|
||||
} catch (MalformedURLException e) {
|
||||
throw new BugException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user