package org.gcube.smartgears.managers; import static org.gcube.smartgears.Constants.container_profile_file_path; import static org.gcube.smartgears.lifecycle.container.ContainerState.active; import static org.gcube.smartgears.lifecycle.container.ContainerState.down; import static org.gcube.smartgears.lifecycle.container.ContainerState.failed; import static org.gcube.smartgears.lifecycle.container.ContainerState.stopped; import static org.gcube.smartgears.provider.ProviderFactory.provider; import java.io.File; import java.io.FileOutputStream; import java.io.ObjectOutputStream; import java.util.List; import java.util.Set; import org.gcube.common.events.Observes; import org.gcube.common.events.Observes.Kind; import org.gcube.smartgears.configuration.Mode; import org.gcube.smartgears.context.application.ApplicationContext; import org.gcube.smartgears.context.container.ContainerContext; import org.gcube.smartgears.handlers.ProfileEvents; import org.gcube.smartgears.handlers.container.ContainerHandler; import org.gcube.smartgears.handlers.container.ContainerLifecycleEvent; import org.gcube.smartgears.handlers.container.ContainerPipeline; import org.gcube.smartgears.lifecycle.application.ApplicationLifecycle; import org.gcube.smartgears.lifecycle.container.ContainerState; import org.gcube.smartgears.utils.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Coordinates management of the container as a gCube resource. * * @author Fabio Simeoni * */ public class ContainerManager { private static Logger log = LoggerFactory.getLogger(ContainerManager.class); public static ContainerManager instance = new ContainerManager(); private ContainerContext context; private ContainerPipeline pipeline; private ContainerManager() {} /** * Starts container management. */ public ContainerContext start(ContainerContext context) { this.context = context; try { if (context.configuration().mode()!=Mode.offline) validateContainer(context); saveContainerState(); List handlers = provider().containerHandlers(); log.trace("managing container lifecycle with {}", handlers); startHandlers(handlers); context.lifecycle().moveTo(active); return context; } catch (RuntimeException e) { log.error("cannot manage container (see cause)", e); if (context != null) context.lifecycle().moveTo(failed); throw e; } } private void saveContainerState() { File file = context.persistenceWriter().file(container_profile_file_path); try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))) { oos.writeObject(context.id()); } catch (Exception e) { log.error("error serializing cointainer state"); throw new RuntimeException(e); } } private void validateContainer(ContainerContext context) { // List tokensToRemove = new ArrayList(); context.configuration().validate(); Set foundContexts; try { foundContexts = context.authorizationProvider().getContexts(); } catch (Exception e) { log.error("error authorizing container", e); throw new RuntimeException("error authorizing container, moving the container to failed", e); } if (foundContexts.isEmpty()) { log.error("no valid contexts found, moving the container to failed"); throw new RuntimeException("no valid contexts found, moving the container to failed"); } } public void manage(ApplicationContext app) { app.events().subscribe(this); } @Observes(value = { ApplicationLifecycle.failure, ApplicationLifecycle.stop }, kind = Kind.critical) void monitorApplication(ApplicationLifecycle lifecycle) { context.lifecycle().tryMoveTo(ContainerState.partActive); } /** * Stops container management on remote request. * */ public void stop() { stop(false); } /** * Stops container management on remote request or container shutdown. * */ public void stop(boolean shutdown) { // two cases: stop-on-shutdown and stop-on-request, some listeners will be // selective about this, // shutdown is triggered by probe app, which is notified among other apps // if other app have been already notified, the container may already be // part-active. // apps still to notify will listen only on stop, hence won't react to this but // will go down when their turn arrives. if (context == null) return; log.info("stopping container management"); try { context.lifecycle().tryMoveTo(shutdown ? down : stopped); stopHandlers(); // no further reactions log.info("stopping container events"); context.events().stop(); Utils.scheduledServicePool.shutdownNow(); } catch (RuntimeException e) { log.warn("cannot stop container management (see cause)", e); } } // helpers private void startHandlers(List handlers) { try { pipeline = new ContainerPipeline(handlers); pipeline.forward(new ContainerLifecycleEvent.Start(context)); } catch (RuntimeException e) { context.lifecycle().tryMoveTo(failed); throw e; } } private void stopHandlers() { if (pipeline == null) return; // copy pipeline, flip it, and ContainerPipeline returnPipeline = pipeline.reverse(); // start lifetime pipeline in inverse order with stop event returnPipeline.forward(new ContainerLifecycleEvent.Stop(context)); } /* * private void loadKeyForToken(List tokens) { String initialToken = * SecurityTokenProvider.instance.get(); * * //TODO: change this String filePath = "/tmp/keys"; File PathDirs = new * File(filePath+"/"); PathDirs.mkdirs(); try{ for (String token : tokens) { * try{ SecurityTokenProvider.instance.set(token); File key = * authProvider.getSymmKey(filePath); * log.trace("loading key {} file name ",key.getAbsolutePath()); * log.trace("loaded key {} file name ",key.getAbsolutePath()); }catch(Exception * e){ log.warn("error loading key for token {}", token, e); } } * loadFileIntoClasspath(PathDirs); }finally{ * SecurityTokenProvider.instance.set(initialToken); } } * * * private void loadFileIntoClasspath(File file){ try { URL url = * file.toURI().toURL(); * * ClassLoader currentClassloader = * Thread.currentThread().getContextClassLoader().getParent()==null? * Thread.currentThread().getContextClassLoader() : * Thread.currentThread().getContextClassLoader().getParent(); * * URLClassLoader classLoader = (URLClassLoader)currentClassloader; Method * method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); * method.setAccessible(true); method.invoke(classLoader, url); } catch * (Exception ex) { log.error("error loading file into classpath",ex); } } */ }