/* * ALMA - Atacama Large Millimiter Array * (c) European Southern Observatory, 2002 * Copyright by ESO (in the framework of the ALMA collaboration), * All rights reserved * * 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 alma.acs.container; import java.io.PrintWriter; import java.io.StringWriter; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Level; import alma.JavaContainerError.wrappers.AcsJContainerEx; import alma.JavaContainerError.wrappers.AcsJContainerServicesEx; import alma.acs.concurrent.DaemonThreadFactory; import alma.acs.container.corba.AcsCorba; import alma.acs.container.corba.OrbConfigurator; import alma.acs.logging.AcsLogger; import alma.acs.logging.ClientLogManager; import alma.acs.util.CmdLineArgs; import alma.acs.util.CmdLineRegisteredOption; import alma.acs.util.StopWatch; /** * The <code>main</code> method of this class starts an {@link AcsContainer}. * <p> * Tasks performed are: * <ul> * <li>registers JVM shutdown hook * <li>reads configuration info from various locations * <li>creates an AcsContainer * <li>logs in to the Manager * <li>starts ACS logging * <li>asks Manager to load a GUI component * <li>waits until the ORB terminates * </ul> * <p> * The implementation delegates many tasks to {@link alma.acs.container.AcsEmbeddedContainerRunner}, * so that other applications which have to run a container inside can be written similarly to this class. * <p> * The functionality is comparable to that of <code>maciActivate.cpp</code> and * <code>maciContainerImpl.cpp/ContainerImpl/init(argc, argv)</code> * on the C++ side. * * @author hsommer */ public class AcsContainerRunner { // properties read by this class private static final String CONTAINER_NAME_PROPERTYNAME = "ACS.containerName"; private static final String MANAGER_PROPERTYNAME = "ACS.manager"; public static final String CONTAINER_STARTTIME_DELAY_MILLIS_PROPERTYNAME = "acs.container.starttimeDelayMillis"; protected String m_containerName; protected String m_managerLoc; /** * If non-null then this value should override any default or CDB values for component recovery upon container start. */ protected Boolean m_recoveryModeOverride; protected AcsEmbeddedContainerRunner embeddedRunner; protected AcsLogger m_logger; protected AcsCorba m_acsCorba; protected int m_containerPort = -1; private ShutdownHook m_shutdownHook; protected int initialSleeptimeMillis = 0; /** * Empty constructor, only to be called from <code>AcsContainerRunner#main</code> method. */ protected AcsContainerRunner() { } /** * The one and only <code>main</code> method to run a Java container. Options: * <ul> * <li><code>-manager myManagerloc</code><br> * CORBA loc for the Manager, e.g. * <code>corbaloc::myhost:xxxx/Manager</code> * (same as property <code>ACS.manager</code>, but with higher precedence); * if missing, it will be taken from property ACS.manager, or will default to localhost.</li> * <li><code>-containerName myContainerName</code><br> * name under which the container will introduce itself to the ACS Manager * (has precedence over the property <code>ACS.containerName</code>).</li> * <li>any other arguments will be passed on to the CORBA ORB.</li> * </ul> */ public static void main(String[] args) { AcsContainerRunner contRunner = null; try { contRunner = new AcsContainerRunner(); contRunner.run(args); } catch (Throwable thr) { StringWriter sw = new StringWriter(); thr.printStackTrace(new PrintWriter(sw)); String msg = "\n *** Top level exception in AcsContainerRunner#main: " + sw.toString(); if (contRunner.m_logger != null) { contRunner.m_logger.severe(msg); } System.err.println(msg); if (contRunner.m_acsCorba != null) { contRunner.m_acsCorba.doneCorba(); } } } /** * Startup choreography: performs the various tasks in the correct order. * <p> * Note on the implementation: the steps involved are grouped as private methods * that access the instance variables. The intent was to make the sequence clearer. * * @param args command line args as given to <code>main</code>. * @throws AcsJContainerServicesEx at the slightest provocation... */ private void run(String[] args) throws AcsJContainerEx { StopWatch containerStartWatch = new StopWatch(); // just a temp logger m_logger = ClientLogManager.getAcsLogManager().getLoggerForApplication("AcsContainerRunner", true); String argsString = ""; for (String arg : args) { argsString += arg + " "; } m_logger.log(Level.INFO, "AcsContainerRunner#run with arguments " + argsString); setOptions(args); embeddedRunner = new AcsEmbeddedContainerRunner(false, m_recoveryModeOverride); embeddedRunner.setContainerName(m_containerName); embeddedRunner.setManagerLoc(m_managerLoc); checkReadyToRun(); // now that embeddedRunner knows the container name, we can switch to the real logger m_logger = embeddedRunner.getContainerLogger(); m_acsCorba = new AcsCorba(m_logger); if (initialSleeptimeMillis > 0) { m_logger.fine("Container will sleep for " + initialSleeptimeMillis + " ms, e.g. to allow remote debuggers to attach at this early stage."); try { Thread.sleep(initialSleeptimeMillis); } catch (InterruptedException e) { m_logger.info("Woken up too early from initial-delay sleep."); } } m_acsCorba.initCorba(args, m_containerPort); m_acsCorba.runCorba(); embeddedRunner.run(m_acsCorba); m_shutdownHook = new ShutdownHook(m_logger); Runtime.getRuntime().addShutdownHook(m_shutdownHook); m_shutdownHook.setAcsContainer(embeddedRunner.getContainer()); initAcsLogging(embeddedRunner.getManagerProxy()); m_logger.fine("entering orb loop"); containerStartWatch.setLogger(m_logger); containerStartWatch.logLapTime("start the container"); // here we hang for the life time of the container... m_acsCorba.blockOnORB(); m_logger.fine("orb loop over."); m_logger.exiting(AcsContainerRunner.class.getName(), "run"); m_shutdownHook.setRegularShutdownExpected(); } /** * Asynchronously connects to the log service so that after some time the locally collected log records * will be sent over the wire. */ protected void initAcsLogging(final AcsManagerProxy managerProxy) { Runnable cmd = new Runnable() { public void run() { m_logger.finer("asynchronously calling ClientLogManager#initRemoteLogging()..."); boolean gotLogService = false; try { gotLogService = ClientLogManager.getAcsLogManager().initRemoteLogging( m_acsCorba.getORB(), managerProxy.getManager(), managerProxy.getManagerHandle(), true); } catch (Exception e) { // just log below } if (gotLogService) { m_logger.finer("done ClientLogManager#initRemoteLogging"); } else { m_logger.log(Level.WARNING, "ACS central logging not available!"); } } }; ExecutorService executor = Executors.newSingleThreadExecutor(new DaemonThreadFactory("InitRemoteLogging")); executor.execute(cmd); } /** * Parses commandline and property options. * * @param args as received by main() */ void setOptions(String[] args) throws AcsJContainerEx { // -- prepare arg parser CmdLineArgs cmdArgs = new CmdLineArgs(); // container name CmdLineRegisteredOption optContainerName = new CmdLineRegisteredOption("-containerName", 1); cmdArgs.registerOption(optContainerName); // container port; TODO unify port argument / property with CDB, C++, etc., abstract from ORB option CmdLineRegisteredOption optContainerPort = new CmdLineRegisteredOption("-OAPort", "-OAport", 1); cmdArgs.registerOption(optContainerPort); // CmdLineRegisteredOption optContainerPort2 = new CmdLineRegisteredOption("-OAport", 1); // cmdArgs.registerOption(optContainerPort2); // manager reference CmdLineRegisteredOption optManagerLoc = new CmdLineRegisteredOption("-manager", "-m", 1); cmdArgs.registerOption(optManagerLoc); // recovery mode CmdLineRegisteredOption optRecoveryMode = new CmdLineRegisteredOption("-recovery", "-r", 0); cmdArgs.registerOption(optRecoveryMode); // no-recovery mode CmdLineRegisteredOption optNoRecoveryMode = new CmdLineRegisteredOption("-norecovery", "-nr", 0); cmdArgs.registerOption(optNoRecoveryMode); // -- parse and set args try { cmdArgs.parseArgs(args); // -- container name if (cmdArgs.isSpecified(optContainerName)) { m_containerName = cmdArgs.getValues(optContainerName)[0].trim(); } else { m_containerName = System.getProperty(CONTAINER_NAME_PROPERTYNAME); } // -- container port if (cmdArgs.isSpecified(optContainerPort)) { m_containerPort = Integer.parseInt(cmdArgs.getValues(optContainerPort)[0]); } else { // default port -- C++ container uses -ORBEndpoint, default 3 0 5 0 m_containerPort = OrbConfigurator.ORB_DEFAULT_PORT; } // -- manager if (cmdArgs.isSpecified(optManagerLoc)) { m_managerLoc = cmdArgs.getValues(optManagerLoc)[0].trim(); } else if (System.getProperty(MANAGER_PROPERTYNAME) != null) { m_managerLoc = System.getProperty(MANAGER_PROPERTYNAME).trim(); } else { // default = localhost m_managerLoc = AcsManagerProxy.getLocalManagerCorbaloc(); } if (cmdArgs.isSpecified(optRecoveryMode)) { m_recoveryModeOverride = Boolean.TRUE; if (cmdArgs.isSpecified(optNoRecoveryMode)) { m_logger.warning("Conflicting command line options for recovery mode: both -r and -nr are specified. Will use -r."); } } else if (cmdArgs.isSpecified(optNoRecoveryMode)) { m_recoveryModeOverride = Boolean.FALSE; } Integer starttimeDelayMillisProperty = Integer.getInteger(CONTAINER_STARTTIME_DELAY_MILLIS_PROPERTYNAME); if (starttimeDelayMillisProperty != null) { initialSleeptimeMillis = starttimeDelayMillisProperty.intValue(); } } catch (Throwable thr) { AcsJContainerEx ex = new AcsJContainerEx(thr); ex.setContextInfo("incorrect or missing arguments."); throw ex; } } protected void checkReadyToRun() throws AcsJContainerEx { String msg = null; if (m_containerPort <= 0) { msg = "no container port specified; "; } embeddedRunner.checkReadyToRun(msg); } }