📄 boot.java
字号:
/*****************************************************************************
* Java Plug-in Framework (JPF)
* Copyright (C) 2004-2007 Dmitry Olshansky
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*****************************************************************************/
package org.java.plugin.boot;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Locale;
import org.apache.commons.logging.LogFactory;
import org.java.plugin.PluginManager;
import org.java.plugin.util.ExtendedProperties;
import org.java.plugin.util.IoUtil;
import org.java.plugin.util.ResourceManager;
/**
* Main class to get JPF based application running in different modes.
* Application mode may be specified as <code>jpf.boot.mode</code> configuration
* parameter or System property (via <code>-Djpf.boot.mode=</code> command line
* argument). Supported values are:
* <dl>
* <dt>start</dt>
* <dd>Runs application in "background" ("service") mode.</dd>
* <dt>stop</dt>
* <dd>Stops application, running in "background" mode.</dd>
* <dt>restart</dt>
* <dd>Restarts application, running in "background" mode. If it is not
* started, the action is the same as just starting application.</dd>
* <dt>shell</dt>
* <dd>Runs application in "shell" (or "interactive") mode. It is possible to
* control "service" style application from command line. Note, that
* already running application will be stopped first.</dd>
* <dt>load</dt>
* <dd>Only loads application but not starts it as in other modes. This mode
* is useful when doing application unit testing or when you only need to
* get initialized and ready to be started JPF environment.</dd>
* </dl>
* The "shell" mode is default. Application will be started in this mode if no
* <code>jpf.boot.mode</code> configuration parameter can be found.
* <p>
* Application configuration is expected to be in Java properties format file.
* File look-up procedure is the following:
* </p>
* <ul>
* <li>Check <code>jpf.boot.config</code> System property, if present, load
* configuration from that file location</li>
* <li>Look for <code>boot.properties</code> file in the current folder.</li>
* <li>Look for <code>boot.properties</code> resource in classpath (using
* <code>Boot.class.getClassLoader().getResource("boot.properties")</code>
* and <code>Boot.class.getResource("boot.properties")</code> methods).</li>
* </ul>
* <p>
* If configuration could not be found, a warning will be printed to console.
* It is generally not an error to not use configuration file, you may provide
* JPF configuration parameters as System properties. They are always used as
* defaults for configuration properties.
* </p>
* <p>
* Note that configuration properties will be loaded using
* {@link org.java.plugin.util.ExtendedProperties specially extended}
* version of {@link java.util.Properties} class, which supports parameters
* substitution. If there is no <code>applicationRoot</code> property available
* in the given configuration, the current folder will be published as default
* value.
* </p>
* <p>
* Standard configuration parameters are (all are optional when application is
* running in "shell" mode):
* <dl>
* <dt>jpf.boot.mode</dt>
* <dd>Application boot mode. Always available as System property also.
* Default value is <code>shell</code>.</dd>
* <dt>org.java.plugin.boot.appInitializer</dt>
* <dd>Application initializer class, for details see
* {@link org.java.plugin.boot.ApplicationInitializer}. Default is
* {@link org.java.plugin.boot.DefaultApplicationInitializer}.</dd>
* <dt>org.java.plugin.boot.errorHandler</dt>
* <dd>Error handler class, for details see
* {@link org.java.plugin.boot.BootErrorHandler}. Default is
* {@link org.java.plugin.boot.BootErrorHandlerConsole} for "service" style
* applications and {@link org.java.plugin.boot.BootErrorHandlerGui} for
* "interactive" applications.</dd>
* <dt>org.java.plugin.boot.controlHost</dt>
* <dd>Host to be used by background control service, no default values.</dd>
* <dt>org.java.plugin.boot.controlPort</dt>
* <dd>Port number to be used by background control service, no default
* values.</dd>
* <dt>org.java.plugin.boot.splashHandler</dt>
* <dd>Splash screen handler class, for details see
* {@link org.java.plugin.boot.SplashHandler}. Default is simple splash
* handler that can only display an image.</dd>
* <dt>org.java.plugin.boot.splashImage</dt>
* <dd>Path to an image file to be shown as splash screen. This may be any
* valid URL. If no file and no handler given, the splash screen will not
* be shown.</dd>
* <dt>org.java.plugin.boot.splashLeaveVisible</dt>
* <dd>If set to <code>true</code>, the Boot class will not hide splash screen
* at the end of boot procedure but delegate this function to application
* code. Default value is <code>false</code>.</dd>
* <dt>org.java.plugin.boot.splashDisposeOnHide</dt>
* <dd>If set to <code>false</code>, the Boot class will not dispose splash
* screen handler when hiding it. This allows you to reuse handler and show
* splash screen back after it was hidden. Default value is
* <code>true</code>.</dd>
* </dl>
*
* @version $Id: Boot.java,v 1.18 2007/01/04 17:10:36 ddimon Exp $
*/
public final class Boot {
/**
* Name of the file, where to put boot error details.
*/
public static final String BOOT_ERROR_FILE_NAME = "jpf-boot-error.txt"; //$NON-NLS-1$
/**
* Boot configuration file location System property name.
*/
public static final String PROP_BOOT_CONFIG = "jpf.boot.config"; //$NON-NLS-1$
/**
* Boot mode System property name.
*/
public static final String PROP_BOOT_MODE = "jpf.boot.mode"; //$NON-NLS-1$
/**
* "shell" mode boot command value.
*/
public static final String BOOT_MODE_SHELL = "shell"; //$NON-NLS-1$
/**
* "start" mode boot command value.
*/
public static final String BOOT_MODE_START = "start"; //$NON-NLS-1$
/**
* "stop" mode boot command value.
*/
public static final String BOOT_MODE_STOP = "stop"; //$NON-NLS-1$
/**
* "restart" mode boot command value.
*/
public static final String BOOT_MODE_RESTART = "restart"; //$NON-NLS-1$
/**
* "load" mode boot command value.
*/
public static final String BOOT_MODE_LOAD = "load"; //$NON-NLS-1$
// This is for ResourceManager to look up resources.
static final String PACKAGE_NAME = "org.java.plugin.boot"; //$NON-NLS-1$
// Application bootstrap configuration parameter names goes here
private static final String PARAM_CONTROL_HOST =
"org.java.plugin.boot.controlHost"; //$NON-NLS-1$
private static final String PARAM_CONTROL_PORT =
"org.java.plugin.boot.controlPort"; //$NON-NLS-1$
private static final String PARAM_ERROR_HANDLER =
"org.java.plugin.boot.errorHandler"; //$NON-NLS-1$
private static final String PARAM_APP_INITIALIZER =
"org.java.plugin.boot.appInitializer"; //$NON-NLS-1$
private static final String PARAM_SPLASH_HANDLER =
"org.java.plugin.boot.splashHandler"; //$NON-NLS-1$
private static final String PARAM_SPLASH_IMAGE =
"org.java.plugin.boot.splashImage"; //$NON-NLS-1$
private static final String PARAM_SPLASH_LEAVE_VISIBLE =
"org.java.plugin.boot.splashLeaveVisible"; //$NON-NLS-1$
private static final String PARAM_SPLASH_DISPOSE_ON_HIDE =
"org.java.plugin.boot.splashDisposeOnHide"; //$NON-NLS-1$
private static final String PARAM_SPLASH_CONFIG_PREFIX =
"org.java.plugin.boot.splash."; //$NON-NLS-1$
static SplashHandler splashHandler = null;
/**
* Call this method to start/stop application.
* @param args command line arguments, not interpreted by this method but
* passed to
* {@link ApplicationPlugin#initApplication(ExtendedProperties, String[])}
* method
*/
public static void main(final String[] args) {
clearBootLog();
// Load start-up configuration
ExtendedProperties props = new ExtendedProperties(
System.getProperties());
try {
InputStream strm = lookupConfig();
try {
props.load(strm);
} finally {
strm.close();
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
String mode = props.getProperty(PROP_BOOT_MODE);
if (mode != null) {
mode = mode.trim().toLowerCase(Locale.ENGLISH);
} else {
// set SHELL mode by default
mode = BOOT_MODE_SHELL;
}
props.setProperty(PROP_BOOT_MODE, mode);
// Make sure that boot mode is always available as System property:
System.setProperty(PROP_BOOT_MODE, mode);
boolean useControlService = props.containsKey(PARAM_CONTROL_HOST)
&& props.containsKey(PARAM_CONTROL_PORT);
BootErrorHandler errorHandler = getErrorHandlerInstance(
props.getProperty(PARAM_ERROR_HANDLER), useControlService);
try {
if (props.getProperty("applicationRoot") == null) { //$NON-NLS-1$
// Publish current folder as configuration parameter
// to get it available as ${applicationRoot} variable
// in extended properties syntax.
String applicationRoot = new File(".").getCanonicalPath(); //$NON-NLS-1$
props.put("applicationRoot", applicationRoot); //$NON-NLS-1$
}
boot(props, useControlService, mode, errorHandler, args);
} catch (Throwable t) {
if (splashHandler != null) {
splashHandler.setVisible(false);
splashHandler = null;
}
bootLog(t);
errorHandler.handleFatalError(ResourceManager.getMessage(
Boot.PACKAGE_NAME, "bootFailed"), t); //$NON-NLS-1$
System.exit(1);
}
}
/**
* Boots application according to given configuration data.
* @param config boot configuration data
* @param useControlService if <code>true</code>, the control service will
* started to allow handling application instance
* from another process
* @param mode application run mode
* @param errorHandler boot errors handler instance
* @param args command line arguments, not interpreted by this method but
* passed to
* {@link ApplicationPlugin#initApplication(ExtendedProperties, String[])}
* method
* @return initialized application instance or <code>null</code>
* @throws Exception if any un-handled error has occurred
*/
public static Application boot(final ExtendedProperties config,
final boolean useControlService, final String mode,
final BootErrorHandler errorHandler, final String[] args)
throws Exception {
InetAddress controlHost = useControlService ? InetAddress.getByName(
config.getProperty(PARAM_CONTROL_HOST)) : null;
int controlPort = useControlService ? Integer.parseInt(
config.getProperty(PARAM_CONTROL_PORT), 10) : 0;
// handle given command
if (useControlService && BOOT_MODE_STOP.equals(mode)) {
if (!ControlThread.stopRunningApplication(controlHost,
controlPort)) {
System.out.println("application not running"); //$NON-NLS-1$
} else {
System.out.println("application stopped"); //$NON-NLS-1$
}
return null;
}
if (useControlService && BOOT_MODE_START.equals(mode)) {
if (ControlThread.isApplicationRunning(controlHost,
controlPort)) {
errorHandler.handleFatalError(
"Application already running."); //$NON-NLS-1$
return null;
}
Application application =
initApplication(errorHandler, config, args);
if (!(application instanceof ServiceApplication)) {
errorHandler.handleFatalError(
"Application is not a service."); //$NON-NLS-1$
return null;
}
ControlThread controlThread = new ControlThread(controlHost,
controlPort, (ServiceApplication) application);
application.startApplication();
controlThread.start();
System.out.println(
"application started in BACKGROUND mode"); //$NON-NLS-1$
return application;
}
if (useControlService && BOOT_MODE_RESTART.equals(mode)) {
if (ControlThread.stopRunningApplication(controlHost,
controlPort)) {
System.out.println("another instance of application stopped"); //$NON-NLS-1$
}
Application application =
initApplication(errorHandler, config, args);
if (!(application instanceof ServiceApplication)) {
errorHandler.handleFatalError(
"Application is not a service."); //$NON-NLS-1$
return null;
}
ControlThread controlThread = new ControlThread(controlHost,
controlPort, (ServiceApplication) application);
application.startApplication();
controlThread.start();
System.out.println(
"application started in BACKGROUND mode"); //$NON-NLS-1$
return application;
}
// SHELL or LOAD or an unknown modes
if (useControlService
&& ControlThread.stopRunningApplication(controlHost,
controlPort)) {
System.out.println("another instance of application stopped"); //$NON-NLS-1$
}
if (!BOOT_MODE_LOAD.equals(mode)) {
initSplashHandler(config);
if (splashHandler != null) {
splashHandler.setVisible(true);
}
}
Application application =
initApplication(errorHandler, config, args);
if (!BOOT_MODE_LOAD.equals(mode)) {
application.startApplication();
if ((splashHandler != null)
&& !"true".equalsIgnoreCase(config.getProperty( //$NON-NLS-1$
PARAM_SPLASH_LEAVE_VISIBLE, "false"))) { //$NON-NLS-1$
splashHandler.setVisible(false);
}
if ((application instanceof ServiceApplication)
&& BOOT_MODE_SHELL.equals(mode)) {
System.out.println("application started in SHELL mode"); //$NON-NLS-1$
runShell();
stopApplication(application);
}
}
return application;
}
/**
* Stops the application, shuts down plug-in manager and disposes log
* service. Call this method before exiting interactive application. For
* service applications this method will be called automatically by control
* service or from shell.
* @param application application instance being stopped
* @throws Exception if any error has occurred during application stopping
*/
public static void stopApplication(final Application application)
throws Exception {
if (application instanceof ServiceApplication) {
((ServiceApplication) application).stopApplication();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -