001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2011 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * Sonar is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * Sonar is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with Sonar; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019     */
020    package org.sonar.core.plugin;
021    
022    import com.google.common.collect.BiMap;
023    import com.google.common.collect.HashBiMap;
024    import com.google.common.collect.Maps;
025    import org.picocontainer.Characteristics;
026    import org.picocontainer.MutablePicoContainer;
027    import org.picocontainer.PicoContainer;
028    import org.slf4j.Logger;
029    import org.slf4j.LoggerFactory;
030    import org.sonar.api.*;
031    import org.sonar.api.platform.PluginRepository;
032    
033    import java.util.Collection;
034    import java.util.List;
035    import java.util.Map;
036    
037    /**
038     * @since 2.2
039     */
040    public abstract class AbstractPluginRepository implements PluginRepository {
041    
042      private static final Logger LOG = LoggerFactory.getLogger(AbstractPluginRepository.class);
043    
044      private BiMap<String, Plugin> pluginByKey = HashBiMap.create();
045      private Map<Object, Plugin> pluginByExtension = Maps.newIdentityHashMap();
046    
047      protected void registerPlugin(MutablePicoContainer container, Plugin plugin, String pluginKey) {
048        LOG.debug("Register the plugin {}", pluginKey);
049        pluginByKey.put(pluginKey, plugin);
050        for (Object extension : plugin.getExtensions()) {
051          registerExtension(container, plugin, pluginKey, extension);
052        }
053      }
054    
055      /**
056       * Must be executed by implementations when all plugins are registered.
057       */
058      protected void invokeExtensionProviders(MutablePicoContainer container) {
059        List<ExtensionProvider> providers = container.getComponents(ExtensionProvider.class);
060        for (ExtensionProvider provider : providers) {
061          Plugin plugin = getPluginForExtension(provider);
062          Object obj = provider.provide();
063          if (obj instanceof Iterable) {
064            for (Object elt : (Iterable) obj) {
065              registerExtension(container, plugin, getPluginKey(plugin), elt);
066            }
067          } else {
068            registerExtension(container, plugin, getPluginKey(plugin), obj);
069          }
070        }
071      }
072    
073      private void registerExtension(MutablePicoContainer container, Plugin plugin, String pluginKey, Object extension) {
074        if (shouldRegisterExtension(container, pluginKey, extension)) {
075          LOG.debug("Register the extension: {}", extension);
076          container.as(Characteristics.CACHE).addComponent(getExtensionKey(extension), extension);
077          pluginByExtension.put(extension, plugin);
078    
079        }
080      }
081    
082      protected abstract boolean shouldRegisterExtension(PicoContainer container, String pluginKey, Object extension);
083    
084      public Collection<Plugin> getPlugins() {
085        return pluginByKey.values();
086      }
087    
088      public Plugin getPlugin(String key) {
089        return pluginByKey.get(key);
090      }
091    
092      public String getPluginKey(Plugin plugin) {
093        return pluginByKey.inverse().get(plugin);
094      }
095    
096      /**
097       * Returns the list of properties of a plugin
098       */
099      public Property[] getProperties(Plugin plugin) {
100        if (plugin != null) {
101          Class<? extends Plugin> classInstance = plugin.getClass();
102          if (classInstance.isAnnotationPresent(Properties.class)) {
103            return classInstance.getAnnotation(Properties.class).value();
104          }
105        }
106        return new Property[0];
107      }
108    
109      public Property[] getProperties(String pluginKey) {
110        return getProperties(pluginByKey.get(pluginKey));
111      }
112    
113      public Plugin getPluginForExtension(Object extension) {
114        Plugin plugin = pluginByExtension.get(extension);
115        if (plugin == null && !(extension instanceof Class)) {
116          plugin = pluginByExtension.get(extension.getClass());
117        }
118        return plugin;
119      }
120    
121      protected static boolean isType(Object extension, Class<? extends Extension> extensionClass) {
122        Class clazz = (extension instanceof Class ? (Class) extension : extension.getClass());
123        return extensionClass.isAssignableFrom(clazz);
124      }
125    
126      protected static boolean isExtensionProvider(Object extension) {
127        return isType(extension, ExtensionProvider.class);
128      }
129    
130      protected static Object getExtensionKey(Object component) {
131        if (component instanceof Class) {
132          return component;
133        }
134        return component.getClass().getCanonicalName() + "-" + component.toString();
135      }
136    }