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 } 056 057 public boolean hasComponent(String role) 058 { 059 if (super.hasRole(role)) 060 { 061 return true; 062 } 063 else if (_parentManager != null) 064 { 065 return _parentManager.hasComponent(role); 066 } 067 068 return false; 069 } 070 071 @Override 072 public Component lookup(String role) throws ComponentException 073 { 074 Component component = (Component) super.lookup(role); 075 076 if (component != null) 077 { 078 return component; 079 } 080 else if (_parentManager != null) 081 { 082 return _parentManager.lookup(role); 083 } 084 085 return null; 086 } 087 088 public void release(Component object) 089 { 090 if (super.hasComponent(object)) 091 { 092 // does nothing, all components are ThreadSafe 093 } 094 else if (_parentManager != null) 095 { 096 _parentManager.release(object); 097 } 098 } 099 100 /** 101 * Add a new extension point, and its extensions, to the manager. 102 * @param pluginName the plugin containing the extension point 103 * @param point the extension point name. 104 * @param extensionPoint the class of the extension point. 105 * @param configuration the configuration for the extension point. 106 * @param extensions definitions of extensions. 107 */ 108 public void addExtensionPoint(String pluginName, String point, Class<? extends ExtensionPoint> extensionPoint, Configuration configuration, Collection<ExtensionDefinition> extensions) 109 { 110 ExtensionPointFactory factory = new ExtensionPointFactory(pluginName, null, point, extensionPoint, configuration, new WrapperServiceManager(this), getLogger(), extensions); 111 _addComponent(point, factory); 112 _extensionPoints.put(point, extensions); 113 } 114 115 @Override 116 ComponentFactory getComponentFactory(String pluginName, String featureName, String role, Class<? extends Object> componentClass, Configuration configuration) 117 { 118 return new ProxyComponentFactory(pluginName, featureName, role, componentClass, configuration, new WrapperServiceManager(this), getLogger()); 119 } 120 121 private class ProxyComponentFactory extends ComponentFactory 122 { 123 ProxyComponentFactory(String pluginName, String featureName, String role, Class<? extends Object> componentClass, Configuration configuration, ServiceManager serviceManager, Logger logger) 124 { 125 super(pluginName, featureName, role, componentClass, configuration, serviceManager, logger); 126 } 127 128 Component proxify(Object component) 129 { 130 if (component instanceof Component) 131 { 132 return (Component) component; 133 } 134 135 List<Class<?>> interfaces = ClassUtils.getAllInterfaces(component.getClass()); 136 interfaces.add(Component.class); 137 138 Class[] proxyInterfaces = interfaces.toArray(new Class[0]); 139 140 return (Component) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), proxyInterfaces, new ComponentInvocationHandler(component)); 141 } 142 143 @Override 144 Component newInstance() throws Exception 145 { 146 Object component = instanciate(); 147 148 _componentsInitializing.put(_role, component); 149 150 if (component instanceof ParentAware && _parentManager != null) 151 { 152 Object parent = _parentManager.lookup(_role); 153 ((ParentAware) component).setParent(parent); 154 } 155 156 configureAndStart(component); 157 158 _componentsInitializing.remove(_role); 159 160 return proxify(component); 161 } 162 } 163 164 private class ComponentInvocationHandler implements InvocationHandler 165 { 166 private final Object _delegate; 167 168 ComponentInvocationHandler(Object delegate) 169 { 170 _delegate = delegate; 171 } 172 173 public Object invoke(Object proxy, Method meth, Object[] args) throws Throwable 174 { 175 try 176 { 177 return meth.invoke(_delegate, args); 178 } 179 catch (InvocationTargetException ite) 180 { 181 throw ite.getTargetException(); 182 } 183 } 184 } 185 186 private class ExtensionPointFactory extends ProxyComponentFactory 187 { 188 private Collection<ExtensionDefinition> _extensions; 189 190 public ExtensionPointFactory(String pluginName, String featureName, String role, Class<? extends ExtensionPoint> extensionPointClass, Configuration configuration, ServiceManager serviceManager, Logger logger, Collection<ExtensionDefinition> extensions) 191 { 192 super(pluginName, featureName, role, extensionPointClass, configuration, serviceManager, logger); 193 _extensions = extensions; 194 } 195 196 @Override 197 Component newInstance() throws Exception 198 { 199 Object component = instanciate(); 200 201 _componentsInitializing.put(_role, component); 202 203 if (component instanceof ParentAware && _parentManager != null) 204 { 205 Object parent = _parentManager.lookup(_role); 206 ((ParentAware) component).setParent(parent); 207 } 208 209 configureAndStart(component); 210 211 ExtensionPoint extPoint = (ExtensionPoint) component; 212 213 for (ExtensionDefinition extension : _extensions) 214 { 215 extPoint.addExtension(extension.getId(), extension.getPluginName(), extension.getFeatureName(), extension.getConfiguration()); 216 } 217 218 getLogger().debug("Initializing extensions for point {}", _role); 219 extPoint.initializeExtensions(); 220 221 _componentsInitializing.remove(_role); 222 223 return proxify(component); 224 } 225 } 226}