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 */ 016 017package org.ametys.runtime.plugin.component; 018 019import java.util.LinkedHashSet; 020import java.util.Set; 021 022import org.apache.avalon.framework.activity.Disposable; 023import org.apache.avalon.framework.activity.Initializable; 024import org.apache.avalon.framework.component.Component; 025import org.apache.avalon.framework.component.ComponentException; 026import org.apache.avalon.framework.configuration.Configuration; 027import org.apache.avalon.framework.configuration.ConfigurationException; 028import org.apache.avalon.framework.context.Context; 029import org.apache.avalon.framework.context.ContextException; 030import org.apache.avalon.framework.context.Contextualizable; 031import org.apache.avalon.framework.service.ServiceException; 032import org.apache.avalon.framework.service.ServiceManager; 033import org.apache.avalon.framework.service.Serviceable; 034import org.apache.avalon.framework.thread.ThreadSafe; 035import org.slf4j.LoggerFactory; 036 037import org.ametys.runtime.plugin.ExtensionPoint; 038 039/** 040 * Avalon based implementation of an ExtensionPoint.<br> 041 * Subclasses only need to call <code>addComponent()</code> for each new extension.<br> 042 * @param <T> the type of the managed extensions 043 */ 044public abstract class AbstractThreadSafeComponentExtensionPoint<T> extends AbstractLogEnabled implements ExtensionPoint<T>, Component, ThreadSafe, Serviceable, Initializable, Disposable, Contextualizable 045{ 046 /** Avalon ComponentManager */ 047 protected ThreadSafeComponentManager<T> _manager; 048 /** Avalon service manager */ 049 protected ServiceManager _cocoonManager; 050 /** Avalon context */ 051 protected Context _context; 052 053 private Set<String> _ids = new LinkedHashSet<>(); 054 055 public void contextualize(Context context) throws ContextException 056 { 057 _context = context; 058 } 059 060 public void service(ServiceManager manager) throws ServiceException 061 { 062 _cocoonManager = manager; 063 } 064 065 public void initialize() throws Exception 066 { 067 _manager = new ThreadSafeComponentManager<>(); 068 _manager.setLogger(LoggerFactory.getLogger("runtime.plugin.threadsafecomponent")); 069 _manager.contextualize(_context); 070 _manager.service(_cocoonManager); 071 } 072 073 public void dispose() 074 { 075 _manager.dispose(); 076 } 077 078 /** 079 * Adds a Component to the underlying ComponentManager. 080 * Each extension to this ExtensionPoint may be considered as a Component.<br> 081 * @param pluginName Unique identifier for the plugin hosting the extension 082 * @param featureName The feature name (unique for a given pluginName). 083 * @param role the Avalon role 084 * @param clazz the class of the component 085 * @param configuration the configuration of the component 086 * @throws ComponentException if an error occured whil setting up components 087 */ 088 protected void addComponent(String pluginName, String featureName, String role, Class<? extends T> clazz, Configuration configuration) throws ComponentException 089 { 090 _ids.add(role); 091 _manager.addComponent(pluginName, featureName, role, clazz, configuration); 092 } 093 094 public void initializeExtensions() throws Exception 095 { 096 _manager.initialize(); 097 } 098 099 public T getExtension(String id) 100 { 101 try 102 { 103 return _manager.lookup(id); 104 } 105 catch (ComponentException e) 106 { 107 throw new IllegalArgumentException(e); 108 } 109 } 110 111 public boolean hasExtension(String id) 112 { 113 return _ids.contains(id); 114 } 115 116 @SuppressWarnings("unchecked") 117 public void addExtension(String id, String pluginName, String featureName, Configuration configuration) throws ConfigurationException 118 { 119 if (getLogger().isDebugEnabled()) 120 { 121 getLogger().debug("Configuring extension '" + id + "' in plugin '" + pluginName + "' id '" + featureName + "'."); 122 } 123 124 String className = configuration.getAttribute("class", null); 125 126 if (className == null) 127 { 128 throw new ConfigurationException("In plugin '" + pluginName + "' id '" + featureName + "', extension '" + id + "' does not defines any class", configuration); 129 } 130 131 Class<T> extensionClass; 132 133 try 134 { 135 extensionClass = (Class<T>) Class.forName(className); 136 } 137 catch (ClassNotFoundException ex) 138 { 139 throw new ConfigurationException("Unable to instanciate class '" + className + "' for plugin '" + pluginName + "' / '" + featureName + "'", configuration, ex); 140 } 141 142 try 143 { 144 addComponent(pluginName, featureName, id, extensionClass, configuration); 145 } 146 catch (ComponentException e) 147 { 148 throw new ConfigurationException("Exception loading extension " + id, e); 149 } 150 151 if (getLogger().isDebugEnabled()) 152 { 153 getLogger().debug("Extension configured"); 154 } 155 } 156 157 public Set<String> getExtensionsIds() 158 { 159 return _ids; 160 } 161}