package alma.acs.component.client; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import alma.ACS.ACSComponent; import alma.ACS.ACSComponentHelper; import alma.acs.logging.ClientLogManager; import alma.acs.shutdown.ShutdownHookBase; import alma.acs.util.ACSPorts; import alma.acs.util.AcsLocations; import alma.acs.util.CmdLineArgs; import alma.acs.util.CmdLineRegisteredOption; import alma.acs.util.StopWatch; /** * A little tool inspired by http://jira.alma.cl/browse/COMP-6580 , * which connects to a component and keeps pinging its name() method. */ public class ComponentRefTracker extends ComponentClient { ComponentRefTracker(Logger logger, String managerLoc, String name) throws Exception { super(logger, managerLoc, name); } private String targetCompUrl; private ACSComponent targetComp; private int pingDelaySec = -1; private volatile CountDownLatch shutdownSync = null; private boolean checkExists = false; /** * Reader for System.in, or null if option "-interactive" was not specified. */ private BufferedReader inputReader; @Override public void initRemoteLogging() { // do nothing } @Override protected void registerShutdownHook() { m_shutdownHook = new ShutdownHookBase(m_logger, "ComponentRefTracker") { protected void interruptDetected() { try { shutdownSync = new CountDownLatch(1); m_logger.info("SIGINT received. Will terminate..."); shutdownSync.await(10, TimeUnit.SECONDS); } catch(Exception ex) { m_logger.log(Level.WARNING, "Shutdown error: ", ex); } } }; Runtime.getRuntime().addShutdownHook(m_shutdownHook); } boolean setOptions(String[] args) { CmdLineArgs cmdArgs = new CmdLineArgs(); CmdLineRegisteredOption optHelp = new CmdLineRegisteredOption("--help", "-h", 0); cmdArgs.registerOption(optHelp); CmdLineRegisteredOption optCurl = new CmdLineRegisteredOption("-curl", 1); cmdArgs.registerOption(optCurl); CmdLineRegisteredOption optPingDelaySec = new CmdLineRegisteredOption("-delaySec", 1); cmdArgs.registerOption(optPingDelaySec); CmdLineRegisteredOption optCheckExists = new CmdLineRegisteredOption("-checkExists", 0); cmdArgs.registerOption(optCheckExists); CmdLineRegisteredOption optInteractive = new CmdLineRegisteredOption("-interactive", 0); cmdArgs.registerOption(optInteractive); cmdArgs.parseArgs(args); if (cmdArgs.isSpecified(optHelp)) { System.out.println("Usage: acsStartJava " + getClass().getName() + "\n\t" + optCurl.getName() + " <curl> " + "\n\t" + "[ " + optInteractive.getName() + " | " + optPingDelaySec.getName() + " <delay in s between component calls> ]" + "\n\t" + "[ " + optCheckExists.getName() + " ]" ); return false; } else { if (cmdArgs.isSpecified(optInteractive)) { inputReader = new BufferedReader(new InputStreamReader(System.in)); } if (cmdArgs.isSpecified(optPingDelaySec)) { if (inputReader != null) { m_logger.info("Ignoring setting for ping delay because only manual component calls will be used."); } else { pingDelaySec = Integer.parseInt(cmdArgs.getValues(optPingDelaySec)[0].trim()); } } else { if (inputReader == null) { pingDelaySec = 5; } } if (cmdArgs.isSpecified(optCurl)) { targetCompUrl = cmdArgs.getValues(optCurl)[0].trim(); } else { throw new IllegalArgumentException("Option '" + optCurl.getName() + "' must be specified."); } if (cmdArgs.isSpecified(optCheckExists)) { checkExists = true; } } return true; } private void run(String[] args) throws Exception { try { // @TODO: Call setOptions before connecting to the manager etc in the base class ctor if (!setOptions(args)) { return; } // m_logger.fine("Will get reference to component '" + targetCompUrl + "'..."); try { targetComp = ACSComponentHelper.narrow(getContainerServices().getComponent(targetCompUrl)); } catch (Exception ex) { m_logger.warning("Failed to connect to component '" + targetCompUrl + "' in the first place. Will terminate."); return; } String ior = getContainerServices().getAdvancedContainerServices().corbaObjectToString(targetComp); String msg = "Got reference to component '" + targetCompUrl + "', IOR='" + ior + "'."; if (pingDelaySec > 0) { msg += " Will call it every " + pingDelaySec + " seconds."; } m_logger.info(msg); runLoop(); } finally { tearDown(); // if we exit from here through an exception rather than external SIGINT, // the shutdown hook will be called anyway, and we must prepare it for this case... m_shutdownHook.setRegularShutdownExpected(); shutdownSync.countDown(); // free the shutdown hook thread } } private void runLoop() throws IOException, InterruptedException { long nextCallTime = -1; if (inputReader != null) { m_logger.info("Press ENTER to call " + targetCompUrl); } while(shutdownSync == null) { // Check if we should simply wait for user input or more time to pass if ( (inputReader != null && !inputReader.ready()) || System.currentTimeMillis() < nextCallTime) { Thread.sleep(100); // sleep short time only, to be responsive to shutdown continue; } if (inputReader != null) { // We are in interactive mode. // There is user input, thus we can dare to call the otherwise non-interruptable blocking readLine() method. inputReader.readLine(); } StopWatch sw = new StopWatch(); try { if (checkExists && targetComp._non_existent()) { // Not sure if we gain anything from calling _non_existent. // It may only return true if our proxy object has been destroyed. // In case of target container ORB problems, it will throw an exception, just like the name() call does. m_logger.info("Component '" + targetCompUrl + "' does not exist (see Corba spec 4.3.5.1). Call took " + sw.getLapTimeMillis() + " ms."); } else { String currentName = targetComp.name(); String msg = "Call to " + targetCompUrl + "#name() returned fine"; if (!targetCompUrl.equals(currentName)) { msg += " but with unexpected name '" + currentName; } m_logger.info(msg + ". Call took " + sw.getLapTimeMillis() + " ms."); } } catch (Throwable thr) { m_logger.info("Call to component '" + targetCompUrl + "' failed with " + thr.getClass().getName() + ", after " + sw.getLapTimeMillis() + " ms."); } if (inputReader == null) { nextCallTime = System.currentTimeMillis() + pingDelaySec * 1000; } } } public static void main(String[] args) { String name = ComponentRefTracker.class.getSimpleName(); ClientLogManager.getAcsLogManager().suppressRemoteLogging(); Logger logger = ClientLogManager.getAcsLogManager().getLoggerForApplication(name, false); String managerLoc = null; if (System.getProperty("ACS.manager") != null) { managerLoc = System.getProperty("ACS.manager").trim(); } else { // default = localhost AcsLocations.convertToManagerLocation(ACSPorts.getIP(), ACSPorts.getManagerPort()); } try { new ComponentRefTracker(logger, managerLoc, name).run(args); } catch (Throwable thr) { logger.log(Level.SEVERE, "Top-level exception caught:", thr); } } }