/** * This method processes a plugin instance that is assumed to not being cached. This method takes care of creating a * strong reference to the plugin wich is assumed to be the only strong reference to this plugin instance. Then a * proxy object is created to interact with the plugin instance. The proxy object itself only holds a weak reference * to the plugin. After this the plugin is initialized and the plugin type is added to the local plugin cache. * * @param The * classname of the requested plugin. <b>Important: The classname of the plugin is the identifying element * for an instance. This ensures that the plugin type can occur multiple times for different plugin * implementations.</b> * @param pluginType * The plugin type. The plugin type is trusted and must be checked before calling this method. * @param lifecycleHook * The lifecycle hook to be called on demand. * @param limbusPlugin * The limbus plugin instance. <b>Do not cache the plugin instance outside!</b> * @return Returns a proxy interaction object of the desired plugin type to interact with the plugin instance. * @throws LimbusClasspathException * Thrown on any exception. */ private <T extends LimbusPlugin> T initializePlugin(String pluginClassName, Class<T> pluginType, LimbusLifecycleHook<T> lifecycleHook, T limbusPlugin) throws LimbusClasspathException { // schuettec - 27.01.2017 : Safe the strong reference to the plugin object. This should be the only point in // the whole Limbus Engine that is able to hold a strong reference to a plugin. createStrongReference(limbusPlugin); T interactionProxy = createInitializableProxy(pluginType, limbusPlugin, lifecycleHook); _initializePlugin(interactionProxy); cachePlugin(pluginClassName, interactionProxy); return interactionProxy; }
/** * @return Returns the {@link LimbusContext} for this deployment. */ public LimbusContext getLimbusContext() { // schuettec - 30.01.2017 : This method returns the public version of the limbus context not holding strong // references. return createWeakContext(); }
/** * This method returns the classloader of the specified classpath. * * @param classpath * The currently deployed classpath * @return Returns the corresponding classloader this classpath was loaded from. * @throws NoSuchDeploymentException * Thrown if this classpath is not deployed on this container. */ protected URLClassLoader getClassloader(Classpath classpath) throws NoSuchDeploymentException { if (deploymentMap.containsKey(classpath)) { Deployment deployContext = deploymentMap.get(classpath); if (deployContext.getClassloader() != null) { return deployContext.getClassloader(); } } throw NoSuchDeploymentException.createDefault(); }
LimbusLifecycleHook<T> lifecycleHook) throws LimbusException { try { denyNotALimbusPluginInterface(pluginInterface); if (pluginRegistry.containsKey(classname)) { return getPluginFromRegistry(classname, pluginInterface); } else { T limbusPlugin = createPlugin(classname, pluginInterface); limbusPlugin = initializePlugin(classname, pluginInterface, lifecycleHook, limbusPlugin); return limbusPlugin;
private void _undeployClasspath(Deployment deployment) { // Close the logging environment for this classpath if this classpath is not anonymous // Get the classloader before finishing the deployment (this will erase the reference) URLClassLoader classloader = deployment.getClassloader(); // Enqueue the classloader reference to the reference observer this.referenceObserver.observeReferenceTo(classloader); try { // Finish the deploy context and delete references deployment.finish(); } finally { // Close logTarget for plugin Classpath classpath = deployment.getClasspath(); if (classpath.hasDeployName()) { logTarget.closeChannel(classloader); } // Try to ad-hoc garbage collect the classloadfer. WeakReference<Object> classloaderWeakRef = new WeakReference<Object>(classloader); classloader = null; boolean garbageCollected = LimbusUtil.isGarbageCollected(classloaderWeakRef); if (garbageCollected) { log.info("Classloader was unloaded - the ad-hoc garbage collection was successful!"); } else { log.info( "The ad-hoc garbage collection was not successful - see log output of LimbusReferenceObserver to get long-term garbage collection notifications."); } } }
private void _deployClasspath(Deployment deployment) throws LimbusException { URLClassLoader classLoader = deployment.getClassloader(); Classpath classpath = deployment.getClasspath(); if (classpath.hasDeployName()) { String deployName = classpath.getDeployName(); deployment.initialize(); } catch (Throwable e) { // schuettec - 13.12.2016 : Catch Throwable here, because different Throwables and Errors
private <T extends LimbusPlugin> T createPlugin(String classname, Class<T> expectedType) throws LimbusClasspathException { // schuettec - 06.10.2016 : Class loading without running plugin code, no LimbusContextAction needed. denyClassNotFound(getClassloader(), classname); // schuettec - 06.10.2016 : Class loading without running plugin code, no LimbusContextAction needed. boolean isPlugin = isLimbusPlugin(getClassloader(), classname); if (isPlugin) { // schuettec - 06.10.2016 : LimbusContextAction is used internally in the following method. LimbusPlugin limbusPlugin = getLimbusPlugin(classname); return ReflectionUtil.getAsExpectedType(limbusPlugin, expectedType); } else { throw new LimbusClasspathException(String.format("The class %s is not a Limbus plugin.", classname)); } }
private void _deployPlugin(Classpath classpath, Set<Permission> permissions) throws LimbusException { if (deploymentMap.containsKey(classpath)) { return; } log.info("Deploy process started for plugin classpath."); LimbusUtil.logClasspath("plugin", classpath, log); LimbusUtil.logPermissions("plugin", permissions, log); PluginClassLoader pluginClassLoader = new PluginClassLoader(filesystem, sharedClassLoader, classpath.getClasspath()); pluginClassLoader.setPermissions(permissions); Deployment deployment = new Deployment(classpath, pluginClassLoader); deploymentMap.put(classpath, deployment); _deployClasspath(deployment); log.info("Deploy process finished successfully."); if (classpath.hasDeployName()) { deploynames.put(classpath.getDeployName(), classpath); } // Notify deployment subscribers deploymentListeners.multicastSilently() .classpathDeployed(classpath); }
@Override protected void performInitialize() throws Exception { // schuettec - 05.04.2017 : In earlier versions this was done in Engine Launcher. Workarounds.executePreventiveWorkarounds(); this.deploymentListeners = EventMulticasterFactory.create(DeploymentListener.class); this.referenceObserver = new LimbusReferenceObserver<ClassLoader>(); this.referenceObserver.initialize(); this.deploymentMap = new ConcurrentHashMap<Classpath, Deployment>(); this.deploynames = new ConcurrentHashMap<String, Classpath>(); // Deploy all components from shared classpath sharedClassPathProvider.checkClasspath(); Classpath sharedClasspath = sharedClassPathProvider.getSharedClasspath(); this.sharedClassLoader = new SharedClassLoader(filesystem, LimbusEngine.class.getClassLoader(), getAllowedPackagePrefixes(), sharedClasspath.getClasspath()); Deployment sharedDeployment = new Deployment(sharedClasspath, sharedClassLoader); deploymentMap.put(sharedClasspath, sharedDeployment); try { _deployClasspath(sharedDeployment); } catch (Exception e) { // If plugins from shared classpath fail to deploy we are not forced to shutdown the whole engine. log.warn("Error while deploying plugins from shared classpath.", e); } }
/** * Creates a proxy instance for the specified plugin object using the plugin interface. * * @param pluginInterface * The plugin interface. <b>The object specified here is trusted to be an interface that extends * {@link LimbusPlugin}.</b> * @param pluginObject * The plugin instance. <b>The object specified here is trusted to be uninitialized.</b> * @return Returns the plugin object proxy. */ @SuppressWarnings("unchecked") private <T extends LimbusPlugin> T createInitializableProxy(Class<T> pluginInterface, T pluginObject, LimbusLifecycleHook<T> lifecycleHook) { // schuettec - 27.01.2017 : Let the proxy be defined by the Limbus Engine's classloader. LifecycleProxyHandler<T> handler = new LifecycleProxyHandler<T>(createWeakContext(), pluginObject, lifecycleHook); return (T) Proxy.newProxyInstance(Deployment.class.getClassLoader(), new Class<?>[] { pluginInterface }, handler); }