001/* 002 * Copyright 2012 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.runtime.plugin.component; 017 018import java.lang.reflect.InvocationHandler; 019import java.lang.reflect.InvocationTargetException; 020import java.lang.reflect.Method; 021import java.lang.reflect.Proxy; 022import java.util.Collection; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026 027import org.apache.avalon.framework.component.Component; 028import org.apache.avalon.framework.component.ComponentException; 029import org.apache.avalon.framework.component.ComponentManager; 030import org.apache.avalon.framework.configuration.Configuration; 031import org.apache.avalon.framework.service.ServiceManager; 032import org.apache.avalon.framework.service.WrapperServiceManager; 033import org.apache.commons.lang3.ClassUtils; 034import org.slf4j.Logger; 035 036import org.ametys.runtime.plugin.ExtensionDefinition; 037import org.ametys.runtime.plugin.ExtensionPoint; 038 039/** 040 * Implementation of an Avalon ComponentManager handling the PluginAware and ParentAware interfaces.<br> 041 * See the {@link ThreadSafeComponentManager} for more details. 042 */ 043public class PluginsComponentManager extends ThreadSafeComponentManager<Object> implements ComponentManager 044{ 045 ComponentManager _parentManager; 046 private Map<String, Collection<ExtensionDefinition>> _extensionPoints = new HashMap<>(); 047 048 /** 049 * Constructor. 050 * @param parentManager the parent manager 051 */ 052 public PluginsComponentManager(ComponentManager parentManager) 053 { 054 _parentManager = parentManager; 055 _manager = new WrapperServiceManager(this); 056 } 057 058 @Override 059 public void initialize() throws Exception 060 { 061 super.initialize(); 062 063 // at this point, all components and extension points are initialized 064 // for extension point annotated with LazyInitializeExtensions, 065 // only extensions used during initialization are already initialized 066 // next, we should initialize all remaining extensions 067 for (String id : _extensionPoints.keySet()) 068 { 069 ExtensionPoint point = (ExtensionPoint) lookup(id); 070 071 if (point.getClass().isAnnotationPresent(LazyInitializeExtensions.class)) 072 { 073 getLogger().debug("Initializing extensions for point {}", id); 074 point.initializeExtensions(); 075 } 076 } 077 } 078 079 public boolean hasComponent(String role) 080 { 081 if (super.hasRole(role)) 082 { 083 return true; 084 } 085 else if (_parentManager != null) 086 { 087 return _parentManager.hasComponent(role); 088 } 089 090 return false; 091 } 092 093 @Override 094 public Component lookup(String role) throws ComponentException 095 { 096 Component component = (Component) super.lookup(role); 097 098 if (component != null) 099 { 100 return component; 101 } 102 else if (_parentManager != null) 103 { 104 return _parentManager.lookup(role); 105 } 106 107 return null; 108 } 109 110 public void release(Component object) 111 { 112 if (super.hasComponent(object)) 113 { 114 // does nothing, all components are ThreadSafe 115 } 116 else if (_parentManager != null) 117 { 118 _parentManager.release(object); 119 } 120 } 121 122 /** 123 * Add a new extension point, and its extensions, to the manager. 124 * @param pluginName the plugin containing the extension point 125 * @param point the extension point name. 126 * @param extensionPoint the class of the extension point. 127 * @param configuration the configuration for the extension point. 128 * @param extensions definitions of extensions. 129 */ 130 public void addExtensionPoint(String pluginName, String point, Class<? extends ExtensionPoint> extensionPoint, Configuration configuration, Collection<ExtensionDefinition> extensions) 131 { 132 ExtensionPointFactory factory = new ExtensionPointFactory(pluginName, null, point, extensionPoint, configuration, new WrapperServiceManager(this), getLogger(), extensions); 133 _addComponent(point, factory); 134 _extensionPoints.put(point, extensions); 135 } 136 137 @Override 138 ComponentFactory getComponentFactory(String pluginName, String featureName, String role, Class<? extends Object> componentClass, Configuration configuration) 139 { 140 return new ProxyComponentFactory(pluginName, featureName, role, componentClass, configuration, _manager, getLogger()); 141 } 142 143 private class ProxyComponentFactory extends ComponentFactory 144 { 145 ProxyComponentFactory(String pluginName, String featureName, String role, Class<? extends Object> componentClass, Configuration configuration, ServiceManager serviceManager, Logger logger) 146 { 147 super(pluginName, featureName, role, componentClass, configuration, serviceManager, logger); 148 } 149 150 Component proxify(Object component) 151 { 152 if (component instanceof Component) 153 { 154 return (Component) component; 155 } 156 157 List<Class<?>> interfaces = ClassUtils.getAllInterfaces(component.getClass()); 158 interfaces.add(Component.class); 159 160 Class[] proxyInterfaces = interfaces.toArray(new Class[0]); 161 162 return (Component) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), proxyInterfaces, new ComponentInvocationHandler(component)); 163 } 164 165 @Override 166 Component newInstance() throws Exception 167 { 168 Object component = instanciate(); 169 170 _componentsInitializing.put(_role, component); 171 172 if (component instanceof ParentAware && _parentManager != null) 173 { 174 Object parent = _parentManager.lookup(_role); 175 ((ParentAware) component).setParent(parent); 176 } 177 178 configureAndStart(component); 179 180 _componentsInitializing.remove(_role); 181 182 return proxify(component); 183 } 184 } 185 186 private class ComponentInvocationHandler implements InvocationHandler 187 { 188 private final Object _delegate; 189 190 ComponentInvocationHandler(Object delegate) 191 { 192 _delegate = delegate; 193 } 194 195 public Object invoke(Object proxy, Method meth, Object[] args) throws Throwable 196 { 197 try 198 { 199 return meth.invoke(_delegate, args); 200 } 201 catch (InvocationTargetException ite) 202 { 203 throw ite.getTargetException(); 204 } 205 } 206 } 207 208 private class ExtensionPointFactory extends ProxyComponentFactory 209 { 210 private Collection<ExtensionDefinition> _extensions; 211 212 public ExtensionPointFactory(String pluginName, String featureName, String role, Class<? extends ExtensionPoint> extensionPointClass, Configuration configuration, ServiceManager serviceManager, Logger logger, Collection<ExtensionDefinition> extensions) 213 { 214 super(pluginName, featureName, role, extensionPointClass, configuration, serviceManager, logger); 215 _extensions = extensions; 216 } 217 218 @Override 219 Component newInstance() throws Exception 220 { 221 Object component = instanciate(); 222 223 _componentsInitializing.put(_role, component); 224 225 if (component instanceof ParentAware && _parentManager != null) 226 { 227 Object parent = _parentManager.lookup(_role); 228 ((ParentAware) component).setParent(parent); 229 } 230 231 configureAndStart(component); 232 233 ExtensionPoint extPoint = (ExtensionPoint) component; 234 235 for (ExtensionDefinition extension : _extensions) 236 { 237 extPoint.addExtension(extension.getId(), extension.getPluginName(), extension.getFeatureName(), extension.getConfiguration()); 238 } 239 240 if (!extPoint.getClass().isAnnotationPresent(LazyInitializeExtensions.class)) 241 { 242 getLogger().debug("Initializing extensions for point {}", _role); 243 extPoint.initializeExtensions(); 244 } 245 246 _componentsInitializing.remove(_role); 247 248 return proxify(component); 249 } 250 } 251}