📄 runlevelmanager.java
字号:
/*------------------------------------------------------------------------------Name: RunlevelManager.javaProject: xmlBlaster.orgCopyright: xmlBlaster.org, see xmlBlaster-LICENSE file------------------------------------------------------------------------------*/package org.xmlBlaster.engine.runlevel;import java.io.File;import java.io.IOException;import java.util.logging.Logger;import java.util.logging.Level;import org.xmlBlaster.util.FileLocator;import org.xmlBlaster.util.MsgUnit;import org.xmlBlaster.util.Timestamp;import org.xmlBlaster.util.XmlBlasterException;import org.xmlBlaster.util.admin.extern.JmxMBeanHandle;import org.xmlBlaster.util.classloader.StandaloneClassLoaderFactory;import org.xmlBlaster.util.context.ContextNode;import org.xmlBlaster.util.def.Constants;import org.xmlBlaster.util.def.ErrorCode;import org.xmlBlaster.engine.ServerScope;import org.xmlBlaster.engine.qos.PublishQosServer;import org.xmlBlaster.authentication.Authenticate;import org.xmlBlaster.authentication.SessionInfo;import java.util.Properties;import java.util.Set;import java.util.HashSet;import java.util.TreeSet;import java.util.Collections;import java.util.Iterator;import org.xmlBlaster.util.plugin.PluginInfo;import org.xmlBlaster.util.plugin.I_Plugin;/** * This starts/stops xmlBlaster with different run levels. * <p> * @author <a href="mailto:xmlBlaster@marcelruff.info">Marcel Ruff</a> * @see <a href="http://www.xmlblaster.org/xmlBlaster/doc/requirements/engine.runlevel.html">engine.runlevel requirement</a> */public final class RunlevelManager implements RunlevelManagerMBean{ private String ME = "RunlevelManager"; private final ServerScope glob; private static Logger log = Logger.getLogger(RunlevelManager.class.getName()); private int currRunlevel = 0; public static final int RUNLEVEL_HALTED_PRE = -1; public static final int RUNLEVEL_HALTED = 0; public static final int RUNLEVEL_HALTED_POST = 1; public static final int RUNLEVEL_STANDBY_PRE = 2; public static final int RUNLEVEL_STANDBY = 3; public static final int RUNLEVEL_STANDBY_POST = 4; public static final int RUNLEVEL_CLEANUP_PRE = 5; public static final int RUNLEVEL_CLEANUP = 6; public static final int RUNLEVEL_CLEANUP_POST = 7; public static final int RUNLEVEL_RUNNING_PRE = 8; public static final int RUNLEVEL_RUNNING = 9; public static final int RUNLEVEL_RUNNING_POST = 10; private final I_RunlevelListener[] DUMMY_ARR = new I_RunlevelListener[0]; /** My JMX registration */ private JmxMBeanHandle mbeanHandle; private ContextNode contextNode; private boolean allowDynamicPlugins; /** * For listeners who want to be informed about runlevel changes. */ private final Set runlevelListenerSet = Collections.synchronizedSet(new HashSet()); /** * One instance of this represents one xmlBlaster server. * <p /> * You need to call initPluginManagers() after creation. */ public RunlevelManager(ServerScope glob) { this.glob = glob; this.ME = "RunlevelManager" + this.glob.getLogPrefixDashed(); if (log.isLoggable(Level.FINER)) log.finer("Incarnated run level manager"); // For JMX instanceName may not contain "," this.contextNode = new ContextNode(ContextNode.SERVICE_MARKER_TAG, "RunlevelManager", this.glob.getScopeContextNode()); this.allowDynamicPlugins = this.glob.getProperty().get("xmlBlaster/allowDynamicPlugins", false); if (allowDynamicPlugins) { String text = "xmlBlaster/allowDynamicPlugins=true: Please protect this feature as any code can be injected, add preventive authorization settings, see http://www.xmlBlaster.org/xmlBlaster/doc/requirements/engine.runlevel.howto.html#dynamic"; log.warning(text); } } // Is done from external engine.Global to avoid public void initJmx() { try { this.mbeanHandle = this.glob.registerMBean(this.contextNode, this); } catch(XmlBlasterException e) { log.severe(e.getMessage()); } } public ContextNode getContextNode() { return this.contextNode; } /** * Sets the cluster node ID as soon as it is known. */ public void setId(String id) { this.ME = "RunlevelManager" + this.glob.getLogPrefixDashed(); } /** * Incarnate the different managers which handle run levels. */ public void initPluginManagers() throws XmlBlasterException { // TODO: This should be configurable new Authenticate(glob); // glob.getProtocolManager(); // force incarnation if (log.isLoggable(Level.FINER)) log.finer("Initialized run level manager"); } /** * Called from RequestBroker when a new plugin XML is arriving. * <br /> * Allows to send dynamically new plugins * <br /> * java javaclients.HelloWorldPublish * -oid __sys__RunlevelManager * -contentFile dynamic.jar * -clientProperty[__plugin.jarName] dynamic.jar * -clientProperty[__plugin.xml] "<plugin id='DynamicPlugin' className='javaclients.DynamicPlugin'><action do='LOAD' onStartupRunlevel='3' sequence='0' onFail='resource.configuration.pluginFailed'/><action do='STOP' onShutdownRunlevel='6' sequence='4'/></plugin>" * @param sessionInfo The publisher * @param msgUnit The content contains the jar file, and some client properties the configuration * @param publishQos * @return * @throws XmlBlasterException */ public final String publish(SessionInfo sessionInfo, MsgUnit msgUnit, PublishQosServer publishQos) throws XmlBlasterException { PluginConfigSaxFactory factory = new PluginConfigSaxFactory(this.glob); // TODO: Send the jar in the content, and the XML in clientProperty String jarName = msgUnit.getQosData().getClientProperty(Constants.CLIENTPROPERTY_PLUGIN_JARNAME, "dynamicPlugin.jar"); if (!this.allowDynamicPlugins) { String text = "xmlBlaster/allowDynamicPlugins=false: Your dynamic plugin '" + jarName + "' is rejected, see http://www.xmlBlaster.org/xmlBlaster/doc/requirements/engine.runlevel.howto.html#dynamic"; log.warning(text); throw new XmlBlasterException(this.glob, ErrorCode.RESOURCE_CONFIGURATION, ME, text); } String xml = msgUnit.getQosData().getClientProperty(Constants.CLIENTPROPERTY_PLUGIN_XML, ""); if (xml == null) { String text = "Missing '" + Constants.CLIENTPROPERTY_PLUGIN_XML + "' with plugin registration markup as in xmlBlasterPlugins.xml"; log.warning(text); throw new XmlBlasterException(this.glob, ErrorCode.RESOURCE_CONFIGURATION, ME, text); } PluginConfig pluginConfig = factory.readObject(xml); byte[] jarFile = msgUnit.getContent(); if (jarFile.length > 0) { try { String dir = StandaloneClassLoaderFactory.getDirectoryForWrite(); File file = (dir == null) ? File.createTempFile("dynamicPlugin", ".jar") : new File(dir, jarName); FileLocator.writeFile(file.getAbsolutePath(), jarFile); log.info("Writing new arrived jar file '" + file.getAbsolutePath() + "' for plugin id=" + pluginConfig.getId() + " with className=" + pluginConfig.getPluginInfo().getClassName()); //URLClassLoader loader = clFactory.getPluginClassLoader(pluginConfig.getPluginInfo()); // See StandaloneClassLoader.java:62 Properties params = pluginConfig.getPluginInfo().getParameters(); String classpath = params.getProperty(PluginInfo.KEY_CLASSPATH); if (classpath == null || classpath.length() < 1) classpath = file.getAbsolutePath(); else classpath += ":"+file.getAbsolutePath(); params.put(PluginInfo.KEY_CLASSPATH, classpath); //loader.newInstance(urls); } catch (IOException e) { log.warning("Problems creating plugin " + pluginConfig.getId() +" with jar '" + jarName + "': " + e.toString()); } } addPlugin(pluginConfig); return Constants.RET_OK; } /** * Adds the specified runlevel listener to receive runlevel change events. * Multiple registrations fo the same listener will overwrite the old one. */ public void addRunlevelListener(I_RunlevelListener l) { if (l == null) { return; } synchronized (runlevelListenerSet) { runlevelListenerSet.add(l); } } /** * Removes the specified listener. */ public void removeRunlevelListener(I_RunlevelListener l) { if (l == null) { return; } synchronized (runlevelListenerSet) { runlevelListenerSet.remove(l); } } /** * Allows to pass the newRunlevel as a String like "RUNLEVEL_STANDBY" or "6" * @see #changeRunlevel(int, boolean) */ public final int changeRunlevel(String newRunlevel, boolean force) throws XmlBlasterException { if (newRunlevel == null || newRunlevel.length() < 1) { String text = "Runlevel " + newRunlevel + " is not allowed, please choose one of " + RUNLEVEL_HALTED + "|" + RUNLEVEL_STANDBY + "|" + RUNLEVEL_CLEANUP + "|" + RUNLEVEL_RUNNING; if (log.isLoggable(Level.FINE)) log.fine(text); throw new XmlBlasterException(this.glob, ErrorCode.RESOURCE_CONFIGURATION, ME, text); } int level = 0; try { level = Integer.parseInt(newRunlevel.trim()); return glob.getRunlevelManager().changeRunlevel(level, true); } catch(NumberFormatException e) { level = toRunlevelInt(newRunlevel); return glob.getRunlevelManager().changeRunlevel(level, true); } } /** * JMX: Change the run level of xmlBlaster. * @param 0 is halted and 9 is fully operational */ public String setRunlevel(String level) throws Exception { try { int numErrors = changeRunlevel(level, true); return "Changed to run level " +toRunlevelStr(getCurrentRunlevel())+" '" + level + "'" + ((numErrors>0) ? (" with "+numErrors+" errors") : ""); } catch (XmlBlasterException e) { throw new Exception(e.getMessage()); } } /** * Change the run level to the given newRunlevel. * <p /> * See RUNLEVEL_HALTED etc. * <p /> * Note that there are four main run levels: * <ul> * <li>RUNLEVEL_HALTED</li> * <li>RUNLEVEL_STANDBY</li> * <li>RUNLEVEL_CLEANUP</li> * <li>RUNLEVEL_RUNNING</li> * </ul> * and every RUNLEVEL sends a pre and a post run level event, to allow * the listeners to prepare or log before or after successfully changing levels.<br /> * NOTE that the pre/post events are <b>no</b> run level states - they are just events. * @param newRunlevel The new run level we want to switch to * @param force Ignore exceptions during change, currently only force == true is supported * @return numErrors * @exception XmlBlasterException for invalid run level */ public final int changeRunlevel(int newRunlevel, boolean force) throws XmlBlasterException { if (log.isLoggable(Level.FINER)) log.finer("Changing from run level " + currRunlevel + " to run level " + newRunlevel + " with force=" + force); long start = System.currentTimeMillis(); int numErrors = 0; if (currRunlevel == newRunlevel) { return numErrors; } int from = currRunlevel; int to = newRunlevel; log.info("Change request from run level " + toRunlevelStr(from) + " to run level " + toRunlevelStr(to) + " ..."); if (!isMajorLevel(to)) { String text = "Runlevel " + to + " is not allowed, please choose one of " + RUNLEVEL_HALTED + "|" + RUNLEVEL_STANDBY + "|" + RUNLEVEL_CLEANUP + "|" + RUNLEVEL_RUNNING; if (log.isLoggable(Level.FINE)) log.fine(text); throw new XmlBlasterException(this.glob, ErrorCode.RESOURCE_CONFIGURATION, ME, text); } if (from < to) { // startup for (int ii=from; ii<to; ii++) { int dest = ii+1; try { startupPlugins(ii, dest); fireRunlevelEvent(ii, dest, force); } finally { currRunlevel = dest; // pre/post events are not marked as run levels if (dest > from && isMajorLevel(dest)) { long elapsed = System.currentTimeMillis() - start; if (numErrors == 0) log.fine("Successful startup to run level " + toRunlevelStr(dest) + Timestamp.millisToNice(elapsed)); else log.info("Startup to run level " + toRunlevelStr(dest) + " done with " + numErrors + " errors."); } } } if (to == RUNLEVEL_RUNNING) { // Main.java to display banner fireRunlevelEvent(RUNLEVEL_RUNNING, RUNLEVEL_RUNNING_POST, force); } } else if (from > to) { // shutdown for (int ii=from; ii>to; ii--) { int dest = ii-1; try { shutdownPlugins(ii, dest); fireRunlevelEvent(ii, dest, force); } finally { currRunlevel = dest; if (dest < from && isMajorLevel(dest)) { long elapsed = System.currentTimeMillis() - start;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -