package org.gcube.smartgears; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Future; import org.gcube.smartgears.annotations.ManagedBy; import org.gcube.smartgears.application.manager.AppManagerObserver; import org.gcube.smartgears.application.manager.OfflineProvider; import org.gcube.smartgears.application.manager.OnlineProvider; import org.gcube.smartgears.configuration.Mode; import org.gcube.smartgears.context.application.ApplicationContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javassist.util.proxy.MethodHandler; import javassist.util.proxy.ProxyFactory; import javassist.util.proxy.ProxyObject; public abstract class ApplicationManagerProvider { private static Logger logger = LoggerFactory.getLogger(ApplicationManagerProvider.class); private Map> proxyClassMap = Collections.synchronizedMap(new HashMap>()); private Map classProxyObjetMap = Collections.synchronizedMap(new HashMap()); protected static ApplicationManagerProvider instance; private static boolean initialized = false; protected static synchronized void init(ApplicationContext appcontext) { if (!initialized) { if (appcontext.container().configuration().mode()== Mode.offline) instance = new OfflineProvider(); else instance = new OnlineProvider(); initialized =true; } } public static synchronized ApplicationManager get(final Class applicationManagerClass){ if (!initialized) throw new RuntimeException("ApplicationManagerProvider not yet initialized"); logger.debug("retrieveing application manager of {} ",applicationManagerClass.getCanonicalName()); Object obj = instance.getApplicationManagerObject(applicationManagerClass); return applicationManagerClass.cast(obj); } private Object getApplicationManagerObject(Class applicationManagerClass) { Object obj; try { Class _class = getProxyClass(applicationManagerClass); if(classProxyObjetMap.containsKey(_class.getCanonicalName())){ obj = classProxyObjetMap.get(_class.getCanonicalName()); logger.trace("getting object {} from cache ",_class.getCanonicalName()); return obj; } else { obj = _class.newInstance(); classProxyObjetMap.put(_class.getCanonicalName(), obj); } logger.debug("proxy created for {} ",applicationManagerClass.getCanonicalName()); } catch (Exception e) { throw new RuntimeException("error creating proxy ", e); } ((ProxyObject)obj).setHandler(this.getMethodHandler(applicationManagerClass)); return obj; } protected synchronized ApplicationManager get(){ final Class applicationManagerClass = retrieveManagerClass(); return get(applicationManagerClass); } private Class getProxyClass(Class applicationManagerClass){ if (proxyClassMap.containsKey(applicationManagerClass.getCanonicalName())){ logger.debug("getting proxy class {} for appManager from cache ",applicationManagerClass.getCanonicalName()); return proxyClassMap.get(applicationManagerClass.getCanonicalName()); } logger.debug("creating new proxy class for appManager "+applicationManagerClass.getCanonicalName()); ProxyFactory proxyfactory = new ProxyFactory(); proxyfactory.setSuperclass(applicationManagerClass); Class proxyClass=proxyfactory.createClass(); proxyClassMap.put(applicationManagerClass.getCanonicalName(), proxyClass); return proxyClass; } protected Class retrieveManagerClass(){ String classname = Thread.currentThread().getStackTrace()[3].getClassName(); logger.trace("managed servlet caller is {}",classname); ManagedBy annotation; try { annotation = Class.forName(classname).getAnnotation(ManagedBy.class); } catch (ClassNotFoundException e) { throw new RuntimeException("error initializing ApplicationManager",e); } if (annotation == null){ logger.error(" {} is not managed by an ApplicationManager", classname); throw new RuntimeException(classname+" is not managed by an ApplicationManager"); } return annotation.value(); } protected abstract Future retrieveFuture(Class applicationManagerClass); protected abstract MethodHandler getMethodHandler(Class applicationManagerClass); protected abstract AppManagerObserver getObserver(); }