/** * 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 * @version 0.1 */ package org.opendaylight.defense4all.framework.core; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.opendaylight.defense4all.framework.core.FrameworkMain.ResetLevel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.jmx.access.InvalidInvocationException; public abstract class Module { protected Logger log = LoggerFactory.getLogger(this.getClass()); protected class Execution implements Runnable { protected static final int ACTION_INVALID = -1; protected static final int ACTION_RESERVED = 0; protected int actionCode = ACTION_INVALID; protected Object param = null; public Execution(int actionCode, Object param) { this.actionCode = actionCode; this.param = param; } public void run() { try { actionSwitcher(actionCode, param); } catch (Throwable e) { String paramStr = param == null ? "null" : param.toString(); log.error("Excepted in Execution run. actionCode = " + actionCode + ", param = " + paramStr); FMHolder.get().getHealthTracker().reportHealthIssue(HealthTracker.MODERATE_HEALTH_ISSUE); } } } protected FrameworkMain fMain; protected ExecutorService decoupleExecutor; protected ScheduledExecutorService periodicExecutor; protected List<Thread> backgroundExecutionThreads; // Synchronized common logging protected FR fr = null; /* Constructor for Spring */ public Module() {decoupleExecutor = null; periodicExecutor = null; backgroundExecutionThreads = null;} /* Setters for Spring */ public void setFrameworkMain(FrameworkMain frameworkMain) {this.fMain = frameworkMain;} /** * #### method description #### * @param param_name param description * @return return description * @throws exception_type circumstances description */ protected abstract void actionSwitcher(int actionCode, Object param); /** Post-constructor initialization * @throws Exception * @throws ExceptionRepoFactoryInternalError */ public void init() throws ExceptionControlApp { fr = fMain.getFR(); } /** Pre-shutdown cleanup */ public void finit() { } /** Factory reset */ public void reset(ResetLevel level) throws ExceptionControlApp { boolean terminated; boolean gotCurrentTermination = false;; if(decoupleExecutor != null) { try { decoupleExecutor.shutdown(); log.info("Waiting for thread termination"); terminated = decoupleExecutor.awaitTermination(10, TimeUnit.SECONDS); if(!terminated) { decoupleExecutor.shutdownNow(); log.info("Waiting for thread termination now"); terminated = decoupleExecutor.awaitTermination(5, TimeUnit.SECONDS); if(!terminated) log.error("Some threads did not shutdownNow."); } } catch (InterruptedException ie) { try { decoupleExecutor.shutdownNow(); // (Re-)Cancel if current thread also interrupted gotCurrentTermination = true; // Preserve interrupt status } catch (Throwable e) { log.error("Failed to shutdown decoupleExecutor." + e.getLocalizedMessage()); } } catch (Throwable e) { log.error("Failed to shutdown decoupleExecutor." + e.getLocalizedMessage()); } } decoupleExecutor = null; if(periodicExecutor != null) { try { periodicExecutor.shutdown(); log.info("Waiting for thread termination"); terminated = periodicExecutor.awaitTermination(10, TimeUnit.SECONDS); if(!terminated) { periodicExecutor.shutdownNow(); log.info("Waiting for thread termination now"); terminated = periodicExecutor.awaitTermination(5, TimeUnit.SECONDS); if(!terminated) log.error("Some threads did not shutdownNow."); } } catch (InterruptedException ie) { try { periodicExecutor.shutdownNow(); // (Re-)Cancel if current thread also interrupted gotCurrentTermination = true; // Preserve interrupt status } catch (Throwable e) { log.error("Failed to shutdown periodicExecutor." + e.getLocalizedMessage()); } } catch (Throwable e) { log.error("Failed to shutdown periodicExecutor." + e.getLocalizedMessage()); } } periodicExecutor = null; if(backgroundExecutionThreads != null) { for(Thread backgroundExecutionThread : backgroundExecutionThreads ) { backgroundExecutionThread.interrupt(); try { backgroundExecutionThread.join(10000); } catch (InterruptedException e) { gotCurrentTermination = true; // Preserve interrupt status continue; } catch (Throwable e) { log.error("Failed to shutdown backgroundExecutionThread." + e.getLocalizedMessage()); continue; } } } backgroundExecutionThreads = null; if (gotCurrentTermination == true) { // Preserve interrupt status Thread.currentThread().interrupt(); } } /** * #### method description #### * @param param_name param description * @return return description * @throws ExceptionControlApp * @throws exception_type circumstances description */ protected void invokeDecoupledSerially(int actionCode, Object param) throws ExceptionControlApp { Execution execution = new Execution(actionCode, param); if(decoupleExecutor == null) decoupleExecutor = Executors.newSingleThreadExecutor(); for(int i=0;i<3;i++) { // TODO: instead of looping add to a framework service to re-try invoking after some time try { decoupleExecutor.execute(execution); return; } catch (Throwable e) { log.error("Failed to execute " + execution.actionCode + ":" + execution.param.toString(), e); } } throw new ExceptionControlApp("Failed to execute " + execution.actionCode + ":" + execution.param.toString()); } /** * #### method description #### * @param param_name param description * @return return description * @throws ExceptionControlApp * @throws exception_type circumstances description */ protected void invokeDecoupledSerially(Runnable runnable) throws ExceptionControlApp { if(decoupleExecutor == null) decoupleExecutor = Executors.newSingleThreadExecutor(); for(int i=0;i<3;i++) { // TODO: instead of looping add to a framework service to re-try invoking after some time try { decoupleExecutor.execute(runnable); return; } catch (Throwable e) { log.error("Failed to execute." + e.getLocalizedMessage()); } } throw new ExceptionControlApp("Failed to execute."); } /** * #### method description #### * @param param_name param description * @return return description * @throws ExceptionControlApp * @throws exception_type circumstances description */ protected void addPeriodicExecution(int actionCode, Object param, Long intervalInSecs) throws ExceptionControlApp { Execution execution = new Execution(actionCode, param); if(periodicExecutor == null) periodicExecutor = Executors.newSingleThreadScheduledExecutor(); for(int i=0;i<3;i++) { // TODO: instead of looping add to a framework service to re-try invoking after some time try { periodicExecutor.scheduleAtFixedRate(execution, 0, intervalInSecs, TimeUnit.SECONDS); // start the first cycle immediately return; } catch (Throwable e) { log.error("Failed to execute "+execution.actionCode + ":"+execution.param.toString()+e.getLocalizedMessage()); } } throw new ExceptionControlApp("Failed to execute " + execution.actionCode + ":" + execution.param.toString()); } /** * #### method description #### * @param param_name param description * @return return description * @throws ExceptionControlApp * @throws exception_type circumstances description */ protected void addPeriodicExecution(Runnable runnable, Long intervalInSecs) throws InvalidInvocationException, ExceptionControlApp { if(periodicExecutor == null) periodicExecutor = Executors.newSingleThreadScheduledExecutor(); for(int i=0;i<3;i++) { // TODO: instead of looping add to a framework service to re-try invoking after some time try { periodicExecutor.scheduleAtFixedRate(runnable, 0, intervalInSecs, TimeUnit.SECONDS); // start the first cycle immediately return; } catch (Throwable e) { log.error("Failed to execute." + e.getLocalizedMessage()); } } throw new ExceptionControlApp("Failed to execute."); } /** * #### method description #### * @param param_name param description * @return return description * @throws ExceptionControlApp * @throws exception_type circumstances description */ protected void addBackgroundTask(int actionCode, Object param) throws ExceptionControlApp { Execution backGroundExecution = new Execution(actionCode, param); addBackgroundTask(backGroundExecution); } /** * #### method description #### * @param param_name param description * @return return description * @throws ExceptionControlApp * @throws exception_type circumstances description */ protected void addBackgroundTask(Runnable runnable) throws ExceptionControlApp { Thread backgroundExecutionThread = new Thread(runnable); if(backgroundExecutionThreads == null) backgroundExecutionThreads = new ArrayList<Thread>(); backgroundExecutionThreads.add(backgroundExecutionThread); for(int i=0;i<3;i++) { // TODO: instead of looping add to a framework service to re-try invoking after some time try { backgroundExecutionThread.start(); return; } catch (Throwable e) { log.error("Failed to start backgroundExecutionThread." + e.getLocalizedMessage()); } } throw new ExceptionControlApp("Failed to start backgroundExecutionThread."); } }