package org.gcube.smartgears.application.manager; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.gcube.common.events.Observes; import org.gcube.common.events.Observes.Kind; import org.gcube.common.security.providers.SecretManagerProvider; import org.gcube.common.security.secrets.Secret; import org.gcube.smartgears.ApplicationManager; import org.gcube.smartgears.Constants; import org.gcube.smartgears.ManagerPair; import org.gcube.smartgears.context.application.ApplicationContext; import org.gcube.smartgears.security.AuthorizationProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class OnlineObserver implements AppManagerObserver{ private static Logger log = LoggerFactory.getLogger(OnlineObserver.class); private static ExecutorService service = Executors.newCachedThreadPool(); private Map> instanciatedManagerPerScope = new HashMap>(); private OnlineProvider provider; private AuthorizationProvider authProvider; private Set> managersClasses; public OnlineObserver(OnlineProvider provider) { this.provider = provider; } public void register() { for (String context : authProvider.getContexts()) { this.onRegistration(context); } } @Observes(value=Constants.token_registered, kind=Kind.safe) public synchronized void onRegistration(String context){ log.info("registration called in context {}", context); List futureList = new ArrayList(); try { Secret secret = authProvider.getSecretForContext(context); for (Class appManager: managersClasses){ Future appManagerFuture = service.submit(new InitAppManager(secret, appManager)); log.info("intializing app using manager {} in context {}",appManager.getClass().getCanonicalName(),context); futureList.add(new ManagerPair(appManager, appManagerFuture)); if (provider.getAppmanagerMap().containsKey(appManager.getCanonicalName())) provider.getAppmanagerMap().get(appManager.getCanonicalName()).put(context, appManagerFuture); else { Map> tokenFutureMap = new HashMap>(); tokenFutureMap.put(context, appManagerFuture); provider.getAppmanagerMap().put(appManager.getCanonicalName(), tokenFutureMap); } } if (!futureList.isEmpty()) instanciatedManagerPerScope.put(context, futureList); } catch (Exception e1) { log.error("something failed getting authorization",e1); throw new RuntimeException("something failed getting authorization",e1); } } @Observes(value=Constants.token_removed, kind=Kind.critical) public synchronized void onRemove(String context){ try { Secret secret = authProvider.getSecretForContext(context); if(instanciatedManagerPerScope.get(context) != null ) { for (ManagerPair manager: instanciatedManagerPerScope.get(context)){ service.execute(new ShutDownAppManager(secret, manager.getFuture())); provider.getAppmanagerMap().get(manager.getImplementationClass().getCanonicalName()).remove(context); } instanciatedManagerPerScope.remove(context); } instanciatedManagerPerScope.remove(context); } catch (Exception e1) { log.error("something failed getting token",e1); throw new RuntimeException("something failed getting token",e1); } } public synchronized void onStop(ApplicationContext appContext){ for (String context :appContext.authorizationProvider().getContexts()) this.onRemove(context); unregister(); } public void unregister(){ service.shutdownNow(); } public class InitAppManager implements Callable{ private Class managerClass; private Secret secret; public InitAppManager(Secret secret, Class managerClass){ this.managerClass = managerClass; this.secret = secret; } @Override public ApplicationManager call() throws Exception { log.info("on init called"); SecretManagerProvider.instance.set(secret); ApplicationManager manager = null; try { manager = managerClass.newInstance(); log.info("calling on onInit on manager {} with secret {}",manager.getClass().getCanonicalName(),secret); manager.onInit(); } catch (Exception e) { log.warn("error on onInit of {} on context {}",manager.getClass().getCanonicalName(), secret.getContext(), e); } finally{ SecretManagerProvider.instance.reset(); } return manager; } } public class ShutDownAppManager implements Runnable{ private Future appManager; private Secret secret; public ShutDownAppManager(Secret secret, Future appManager){ this.appManager = appManager; } @Override public void run() { SecretManagerProvider.instance.set(secret); try { log.info("calling on ShutDown of {} on context {}",appManager.getClass().getCanonicalName(), secret.getContext()); appManager.get().onShutdown(); } catch (Exception e) { log.warn("error on onShutdown of {} on context {}",appManager.getClass().getCanonicalName(), secret.getContext(), e); } finally{ SecretManagerProvider.instance.reset(); } } } @Override public void setAuthorizationProvider(AuthorizationProvider authProvider) { this.authProvider = authProvider; } @Override public void setApplicationManagerClasses(Set> managersClasses) { this.managersClasses = managersClasses; } }