/** * */ package org.gcube.vremanagement.executor.pluginmanager; import java.util.Calendar; import java.util.List; import java.util.Map; import java.util.UUID; import org.gcube.vremanagement.executor.exception.AlreadyInFinalStateException; import org.gcube.vremanagement.executor.exception.InvalidPluginStateEvolutionException; import org.gcube.vremanagement.executor.plugin.Plugin; import org.gcube.vremanagement.executor.plugin.PluginDeclaration; import org.gcube.vremanagement.executor.plugin.PluginState; import org.gcube.vremanagement.executor.plugin.PluginStateEvolution; import org.gcube.vremanagement.executor.plugin.PluginStateNotification; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Luca Frosini (ISTI - CNR) http://www.lucafrosini.com/ * */ public class RunnablePlugin> implements Runnable { /** * Logger */ private static Logger logger = LoggerFactory.getLogger(RunnablePlugin.class); public static final String MAX_LAUNCH_TIMES = "___max_launch_times___"; protected static final String SEPARATOR = "---"; protected final T plugin; protected final Map inputs; protected final UUID uuid; protected final int iterationNumber; protected final List pluginStateNotifications; protected PluginStateEvolution actualStateEvolution; public RunnablePlugin(T plugin, Map inputs, UUID uuid, int iterationNumber, List pluginStateNotifications){ this.plugin = plugin; this.plugin.setPercentageSetter(new PercentageSetterImpl(this)); this.inputs = inputs; this.uuid = uuid; this.iterationNumber = iterationNumber; this.pluginStateNotifications = pluginStateNotifications; try { setState(PluginState.CREATED); } catch (AlreadyInFinalStateException | InvalidPluginStateEvolutionException e) { logger.error(" --- You should not be here. Seem that the {} is suspended before the istance is created. This is really STRANGE.", uuid); throw new RuntimeException(e); } } @Override public void run(){ try { setState(PluginState.RUNNING); plugin.launch(inputs); setState(PluginState.DONE); } catch (AlreadyInFinalStateException e1) { return; } catch(Exception e) { logger.trace(String.format("Thread %s failed", this.toString()),e); try { setState(PluginState.FAILED, e); } catch (AlreadyInFinalStateException | InvalidPluginStateEvolutionException e1) { return; } throw new RuntimeException(e); } } /** * @return the plugin */ public T getPlugin() { return plugin; } /** * @return the launchInputs */ public Map getInputs() { return inputs; } protected synchronized void setPercentage(Integer percentage) throws AlreadyInFinalStateException, InvalidPluginStateEvolutionException { PluginState pluginState = actualStateEvolution.getPluginState(); if(pluginState != PluginState.RUNNING){ throw new InvalidPluginStateEvolutionException("Percentage can be set only for runnign plugin"); } setState(pluginState, percentage, null); } public synchronized void setState(PluginState pluginState) throws AlreadyInFinalStateException, InvalidPluginStateEvolutionException { Integer percentage = 0; if(actualStateEvolution!=null){ percentage = actualStateEvolution.getPercentage(); } if(pluginState==PluginState.DONE){ percentage = 100; } setState(pluginState, percentage, null); } public synchronized void setState(PluginState pluginState, Exception e) throws AlreadyInFinalStateException, InvalidPluginStateEvolutionException { Integer percentage = 0; if(actualStateEvolution!=null){ percentage = actualStateEvolution.getPercentage(); } Exception exception = null; if(pluginState == PluginState.FAILED){ exception = new Exception(e); } setState(pluginState, percentage, exception); } /** * It is up to the plugin update the State of the Running Plugin using * this facilities function. * @param pluginState * @throws Exception */ protected void setState(PluginState pluginState, Integer percentage, Exception exception) throws AlreadyInFinalStateException, InvalidPluginStateEvolutionException { long timestamp = Calendar.getInstance().getTimeInMillis(); if(actualStateEvolution!=null && actualStateEvolution.getPluginState().isFinalState()){ logger.trace("At {} Trying to set {} in {} state, but it was already in the final state {}", timestamp, uuid, pluginState.toString(), actualStateEvolution.toString()); throw new AlreadyInFinalStateException(); } PluginStateEvolution pluginStateEvolution = new PluginStateEvolution(uuid, iterationNumber, timestamp, plugin.getPluginDeclaration(), pluginState, percentage); for(PluginStateNotification pluginStateNotification : pluginStateNotifications){ String pluginStateNotificationName = pluginStateNotification.getClass().getSimpleName(); try { logger.debug("Notifing Plugin State Evolution {} to {}.", pluginStateEvolution, pluginStateNotificationName); pluginStateNotification.pluginStateEvolution(pluginStateEvolution, exception); } catch(Exception e) { logger.error("Unable to Notify Plugin State Evolution {} to {}.", pluginStateEvolution, pluginStateNotificationName); } } actualStateEvolution = pluginStateEvolution; } @Override public String toString(){ return String.format("UUID : %s, Iteration : %d, Plugin : %s", uuid.toString(), iterationNumber, plugin.getPluginDeclaration().getName()); } /** * Stop the Plugin setting state to {@link PluginState#CANCELLED} * @throws Exception */ public void stop() throws Exception { try{ setState(PluginState.STOPPED); plugin.stop(); }catch(AlreadyInFinalStateException e){} Thread.currentThread().interrupt(); } }