/** * Copyright (c) <2013> <Radware Ltd.> and others. All rights reserved. * * This program and the accompanying materials are made available under the terms of the Eclipse Public License * v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html * @author Gera Goft * @author Konstantin Pozdeev * @version 0.1 */ package org.opendaylight.defense4all.framework.core.impl; import java.security.ProtectionDomain; import java.util.Properties; import java.util.logging.LogManager; import javax.persistence.EntityManager; import me.prettyprint.cassandra.serializers.StringSerializer; import org.opendaylight.defense4all.framework.core.AppRoot; import org.opendaylight.defense4all.framework.core.ClusterInfo; import org.opendaylight.defense4all.framework.core.ClusterMgr; import org.opendaylight.defense4all.framework.core.CoreState; import org.opendaylight.defense4all.framework.core.ExceptionControlApp; import org.opendaylight.defense4all.framework.core.FMHolder; import org.opendaylight.defense4all.framework.core.FR; import org.opendaylight.defense4all.framework.core.FrameworkMain; import org.opendaylight.defense4all.framework.core.HealthTracker; import org.opendaylight.defense4all.framework.core.Repo; import org.opendaylight.defense4all.framework.core.RepoFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.bridge.SLF4JBridgeHandler; import org.springframework.context.ApplicationContext; import org.springframework.context.support.GenericXmlApplicationContext; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.webapp.WebAppClassLoader; import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.server.Handler; public class FrameworkMainImpl implements FrameworkMain { public static ApplicationContext contextG; protected Properties configProperties; protected AppRoot appRoot; protected RepoFactoryImpl repoFactoryImpl; protected ClusterMgrImpl clusterMgrImpl; protected PeerCommunicatorImpl peerCommunicatorImpl; protected FrameworkMgmtPointImpl frameworkMgmtPointImpl; protected EntityManager frameworkEM; public Repo<String> coreStateRepo = null; protected String stateClassPaths; protected String restWarPath; // Path to the WAR containing the rest service protected String guiWarPath; // Path to the WAR containing the gui service protected String restPath; // REST Path (in HTTP URL) to service requests protected String guiPath; // GUI Path (in HTTP URL) to service requests protected int port; protected Server jettyServer; protected FRImpl frImpl; protected HealthTrackerImpl healthTrackerImpl; protected boolean openForBusiness = false; public boolean debugRun = false; public String hostAddr; public int demoRun; static Logger log = LoggerFactory.getLogger(FrameworkMainImpl.class); /** * Framework core entity manager id */ public static final String FRAMEWORK_CORE_EM_ID = "framework.core"; private static final String SPRING_CONTEXT_FILENAME = "context.xml"; /** ### Description ### * @param param_name */ public FrameworkMainImpl(Properties configProperties) { this.configProperties = configProperties; } /** Setters for Spring */ public void setRepoFactoryImpl(RepoFactoryImpl repoFactoryImpl) {this.repoFactoryImpl = repoFactoryImpl;} public void setClusterMgrImpl(ClusterMgrImpl clusterMgr) {this.clusterMgrImpl = clusterMgr;} public void setPeerCommunicatorImpl(PeerCommunicatorImpl peerCommunicator) {this.peerCommunicatorImpl = peerCommunicator;} public void setFrameworkMgmtPointImpl(FrameworkMgmtPointImpl frameworkMgmtPoint) {this.frameworkMgmtPointImpl = frameworkMgmtPoint;} public void setStateClassPaths(String stateClassPaths) {this.stateClassPaths = stateClassPaths;} public void setAppRoot(AppRoot appRoot) {this.appRoot = appRoot;} public void setPort(int port) { this.port = port; } public void setRestWarPath(String restWarPath) { this.restWarPath = restWarPath; } public void setGuiWarPath(String guiWarPath) { this.guiWarPath = guiWarPath; } public void setRestPath(String restPath) { this.restPath = restPath; } public void setGuiPath(String guiPath) { this.guiPath = guiPath; } public void setFlightRecorderImpl(FRImpl flightRecorderImpl) { this.frImpl = flightRecorderImpl; } public void setHealthTrackerImpl(HealthTrackerImpl healthTrackerImpl) {this.healthTrackerImpl = healthTrackerImpl;} public void setDemoRun(int demoRun) {this.demoRun = demoRun;} /** * #### method description #### * @param param_name param description * @return return description * @throws ExceptionControlApp * @throws exception_type circumstances description */ public static void main(String[] args) throws ExceptionControlApp { FrameworkMainImpl frameworkMain = null; try { // redirect JUL to log4j LogManager.getLogManager().reset(); SLF4JBridgeHandler.install(); GenericXmlApplicationContext context = new GenericXmlApplicationContext(); context.setValidating(false); context.load(SPRING_CONTEXT_FILENAME); context.refresh(); frameworkMain = (FrameworkMainImpl) context.getBean("frameworkMain"); } catch (Throwable e1) { log.error("Failed to initialize the Spring framework." + e1.getMessage()); System.exit(1); } FMHolder.set(frameworkMain); /* Check if debug run */ for(int i=0;i<args.length;i++) { if(args[i].contains("debug")) { frameworkMain.debugRun = true; break; } } boolean runReset = false, runTest = false; if(args.length > 0) { if(args[0].equals("reset")) { runReset = true; } else if(args[0].equals("test")) { runTest = true; } } try { frameworkMain.init(runReset); } catch (Throwable e2) { System.exit(2); } if ( runReset == true ) { ResetLevel level = args.length > 1 ? ResetLevel.valueOf(args[1], ResetLevel.soft) : ResetLevel.soft; try { frameworkMain.reset(level); } catch (Throwable e3) { System.exit(3); } log.info("Reset is done"); System.exit(0); } if ( runTest == true ) { try { frameworkMain.appRoot.test(null); frameworkMain.test(); } catch (Exception e4) { log.error("The framework/application test failed." + e4.getLocalizedMessage()); System.exit(4); } System.exit(0); } /* Bring-up of the jetty web server to serve REST requests. */ try { log.info("Rest server is starting"); frameworkMain.jettyServer.start(); } catch (Throwable e) { log.error("Fail to start jettyServer", e); frameworkMain.stopRestServer(); frameworkMain.finit(); System.exit(9); } try { frameworkMain.jettyServer.join(); frameworkMain.stopRestServer(); frameworkMain.finit(); } catch (InterruptedException e) { System.exit(10); } } protected void stopRestServer() { try { /* Stop rest server */ if(jettyServer != null) { log.info("Rest server is stopping"); jettyServer.stop(); } } catch (Throwable e) {/* Ignore interrupt exceptions. */} } protected void test() { } /** * Initializes all modules after construction bottom-up. First, registers the provided ShutdownHookThread object * to be called for pre-shutdown cleanup. Next, invokes org.opendaylight.ctlapps.framework initialization, followed by application initialization. * @param bestEffort * @throws ExceptionControlApp * @throws exception_type circumstances description */ public void init(boolean bestEffort) throws ExceptionControlApp { /* This class initialization */ boolean hasException = false; Runtime.getRuntime().addShutdownHook(new ShutdownHookThread(this, appRoot)); log.info("Framework is starting"); try { setupJettyServer(); } catch (Throwable e) { String msg = "Excepted trying to setup Jetty server"; log.error(msg, e); if ( ! bestEffort) throw new ExceptionControlApp(msg); hasException = true; } /* RepoFactoryImpl initialization */ try { repoFactoryImpl.init(); } catch (Throwable e) { if ( !bestEffort) throw new ExceptionControlApp(e); hasException = true; } /* This part of frameworkMain init can only be done after RepoFactoryImpl init. */ try { frameworkEM = repoFactoryImpl.createFrameworkMainEM(FRAMEWORK_CORE_EM_ID, stateClassPaths); } catch (Throwable e) { if ( !bestEffort) throw new ExceptionControlApp(e); hasException = true; } try { coreStateRepo = (Repo<String>) repoFactoryImpl.getOrCreateRepo(RepoMajor.FWORK_GLOBAL.name(), RepoMinor.CORE_STATE.name(), StringSerializer.get(), true, CoreState.getRCDs()); hostAddr = (String)coreStateRepo.getCellValue(CoreState.FWORK_CORE_STATE_ROW_KEY, CoreState.HOST_ADDRESS); } catch (Throwable e) { String msg = "Excepted trying to retrieve/construct the framework coreStateRepo"; log.error(msg, e); if ( !bestEffort) throw new ExceptionControlApp(msg); hasException = true; } /* init framework FlightLogger */ try { log.info( "FlightRecorder is starting"); frImpl.init(); } catch (Throwable e) { String msg = "Excepted trying to init Flight Recorder"; log.error(msg, e); if ( ! bestEffort) throw new ExceptionControlApp(msg); hasException = true; } /* Other modules initialization */ try { peerCommunicatorImpl.init(); clusterMgrImpl.init(); frameworkMgmtPointImpl.init(); } catch (Throwable e) { if ( ! bestEffort) throw new ExceptionControlApp(e); hasException = true; } try { frImpl.logRecord(FR_FRAMEWORK_OPERATIONAL, appRoot.name + " application starting."); appRoot.init(bestEffort); } catch (Throwable e) { String msg = "Excepted trying to init application "+ appRoot.name; log.error(msg, e); if ( ! bestEffort) throw new ExceptionControlApp(msg); hasException = true; } /* Mark completion of all initializations allowing all periodic operations to start working and using * repository and other services. */ if ( ! hasException ) { log.info("Is openForBusiness "+ appRoot.name ); openForBusiness = true; } } /** * Cleans up all modules before shutdown - top-down, app first, org.opendaylight.ctlapps.framework next. * @throws exception_type circumstances description */ public void finit() { frImpl.logRecord(FR_FRAMEWORK_OPERATIONAL, "Framework stopping"); openForBusiness = false; frImpl.logRecord(FR_FRAMEWORK_OPERATIONAL, appRoot.name + " application stopping." ); try { appRoot.finit(); } catch (Exception e1) { String appName = (appRoot.name != null) ? appRoot.name : "No appName"; log.error("The application " + appName + " did not properly stop." + e1.toString()); } frameworkMgmtPointImpl.finit(); clusterMgrImpl.finit(); peerCommunicatorImpl.finit(); frImpl.finit(); try { frameworkEM.flush(); // In current Hector implementation this is a no op, but still... } catch (Throwable e) { log.error("Could not flush the framework EM." + e.getMessage()); } repoFactoryImpl.finit(); } /** * Performs factory reset on all modules - first the application, then all org.opendaylight.ctlapps.framework modules top down. * @throws ExceptionControlApp * @throws exception_type circumstances description */ public void reset(ResetLevel resetLevel) throws ExceptionControlApp { frImpl.logRecord(FR_FRAMEWORK_OPERATIONAL, "Reset to "+ resetLevel + " settings for framework."); openForBusiness = false; StringBuilder msg = new StringBuilder(); Boolean success = true; frImpl.logRecord(FR_FRAMEWORK_OPERATIONAL, "Reset to " + resetLevel + " settings for " + appRoot.name + " application"); try { appRoot.reset(resetLevel); } catch (Throwable e5) { log.error("Could not reset the application " + appRoot.name + "." + e5.getMessage()); frImpl.logRecord(FrameworkMain.FR_FRAMEWORK_FAILURE, appRoot.name + " application failed to reset"); success = false; msg.append("Failed to reset application " + appRoot.name); // TODO: continue anyway or return - depending on resetLevel } try { frameworkMgmtPointImpl.reset(resetLevel); } catch (Throwable e1) { log.error("Could not reset framework mgmt point impl." + e1.getMessage()); //frImpl.logRecord(FrameworkMain.FR_FRAMEWORK_FAILURE, "Management point failed to reset"); success = false; msg.append("Failed to reset some framework modules"); // TODO: continue anyway or return - depending on resetLevel } try { clusterMgrImpl.reset(resetLevel); } catch (Throwable e2) { log.error("Could not reset framework mgmt cluster mgr impl." + e2.getMessage()); //frImpl.logRecord(FrameworkMain.FR_FRAMEWORK_FAILURE, "Cluster Manager failed to reset"); success = false; msg.append("Failed to reset some framework modules"); // TODO: continue anyway or return - depending on resetLevel } try { peerCommunicatorImpl.reset(resetLevel); } catch (Throwable e3) { log.error("Could not reset framework peer communicator impl." + e3.getMessage()); //frImpl.logRecord(FrameworkMain.FR_FRAMEWORK_FAILURE, "Peer Communicator failed to reset"); success = false; msg.append("Failed to reset some framework modules"); // TODO: continue anyway or return - depending on resetLevel } try { frImpl.reset(resetLevel); } catch (Throwable e4) { log.error("Flight recorder failed to reset." + e4.getMessage()); //frImpl.logRecord(FrameworkMain.FR_FRAMEWORK_FAILURE, "Flight Recorder failed to reset"); success = false; msg.append("Failed to reset some framework modules"); // TODO: continue anyway or return - depending on resetLevel } try { // Delay repos clear to allow pending threads complete their operations Thread.sleep(5000); } catch (InterruptedException e) {} try { repoFactoryImpl.reset(resetLevel); } catch (Throwable e4) { log.error("Could not reset framework repo factory impl." + e4.getMessage()); //frImpl.logRecord(FrameworkMain.FR_FRAMEWORK_FAILURE, "Repo Factory failed to reset"); success = false; msg.append("Failed to reset some framework modules"); // TODO: continue anyway or return - depending on resetLevel } if(!success) throw new ExceptionControlApp(msg.toString()); } /** * #### method description #### * @param param_name param description * @return return description * @throws exception_type circumstances description */ public void setClusterInfo(ClusterInfo clusterInfo) { // pass to cluster manager } @Override public Properties getConfigProperties() {return configProperties;} @Override public RepoFactory getRepoFactory() {return repoFactoryImpl;} @Override public ClusterMgr getClusterMgr() {return clusterMgrImpl;} @Override public PeerCommunicatorImpl getPeerCommunicator() {return peerCommunicatorImpl;} @Override public FrameworkMgmtPointImpl getFrameworkMgmtPoint() {return frameworkMgmtPointImpl;} @Override public AppRoot getAppRoot() {return appRoot;} @Override public FR getFR() {return frImpl;} /* Set the framework logic web parts */ protected void setupJettyServer() throws ExceptionControlApp { try { jettyServer = new Server(port); String restServiceWarPath = System.getProperty("restWarPath" ); // check if path to restservice war is defined in cli params String guiServiceWarPath = System.getProperty("guiWarPath" ); // check if path to gui war is defined in cli params /* if restServiceWarPath, guiWarPath is not defined use default from context file. Append current class location with * relative path to restservice war from context file. */ if (restServiceWarPath == null ) { ProtectionDomain protectionDomain = this.getClass().getProtectionDomain(); restServiceWarPath = protectionDomain.getCodeSource().getLocation().getPath() + restWarPath ; } if (guiServiceWarPath == null ) { ProtectionDomain protectionDomain = this.getClass().getProtectionDomain(); guiServiceWarPath = protectionDomain.getCodeSource().getLocation().getPath() + guiWarPath ; } /* Set fwork webapp context. */ WebAppContext fworkWebAppContext = new WebAppContext(); fworkWebAppContext.setContextPath(restPath); WebAppClassLoader classLoader = new WebAppClassLoader(this.getClass().getClassLoader(), fworkWebAppContext); fworkWebAppContext.setClassLoader(classLoader); fworkWebAppContext.setParentLoaderPriority(true); fworkWebAppContext.setWar(restServiceWarPath); /* Set gui webapp context. */ WebAppContext guiWebAppContext = new WebAppContext(); guiWebAppContext.setContextPath(guiPath); guiWebAppContext.setWar(guiServiceWarPath); /* Set both handlers (rest and gui) into the Jetty server. */ ContextHandlerCollection contexts = new ContextHandlerCollection(); Handler[] handlers = new Handler[] { fworkWebAppContext, guiWebAppContext }; contexts.setHandlers(handlers); jettyServer.setHandler(contexts); } catch (Throwable e) { log.error("Failed to initialize Jetty server." + e.getMessage()); healthTrackerImpl.reportHealthIssue(HealthTracker.SIGNIFICANT_HEALTH_ISSUE); //frImpl.logRecord(FR_FRAMEWORK_FAILURE, "Failed to initialize Jetty server"); throw new ExceptionControlApp("Failed to initialize Jetty server.", e); } } @Override public void requestShutdown(boolean graceful) { if(graceful) finit(); System.exit(0); } public void requestReset(ResetLevel resetLevel) throws ExceptionControlApp { reset(resetLevel); init(false); } @Override public HealthTracker getHealthTracker() {return healthTrackerImpl;} @Override public boolean isOpenForBusiness() {return openForBusiness;} @Override public boolean isDebugRun() {return debugRun;} @Override public boolean isDemo() {return demoRun == 1;} @Override public String getHostAddr() {return hostAddr;} }