001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2009 SonarSource SA
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.api;
021    
022    import org.sonar.api.utils.SonarException;
023    
024    import java.io.IOException;
025    import java.io.InputStream;
026    import java.net.URL;
027    import java.util.*;
028    import java.util.jar.Manifest;
029    
030    /**
031     * Plugins dictionnary.
032     *
033     * @since 1.10
034     */
035    public class Plugins {
036    
037      private Map<String, Plugin> plugins = null;
038      private List<Class<? extends Extension>> extensionClasses = null;
039      private Map<Class<? extends Extension>, Plugin> pluginsByExtensionClass = null;
040      private Map<Class<? extends Extension>, List<Class<? extends Extension>>> extensionClassesByType = null;
041    
042      public Plugins() {
043        try {
044          introspectPlugins();
045          introspectExtensions();
046    
047        } catch (Exception e) {
048          throw new SonarException("can not load plugins", e);
049        }
050      }
051    
052      public void introspectPlugins() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
053        Enumeration<URL> pluginsEnum = getClass().getClassLoader().getResources("META-INF/MANIFEST.MF");
054        plugins = new HashMap<String, Plugin>();
055        while (pluginsEnum.hasMoreElements()) {
056          URL pluginUrl = pluginsEnum.nextElement();
057          InputStream in = pluginUrl.openStream();
058          Manifest manifest = new Manifest(in);
059          in.close();
060          String pluginClassProp = manifest.getMainAttributes().getValue("Plugin-Class");
061          if (pluginClassProp != null) {
062            Class<?> pluginClass = Class.forName(pluginClassProp, true, getClass().getClassLoader());
063            Plugin pluginInstance = (Plugin) pluginClass.newInstance();
064            plugins.put(pluginInstance.getKey(), pluginInstance);
065    
066          }
067        }
068      }
069    
070      private void introspectExtensions() {
071        extensionClasses = new ArrayList<Class<? extends Extension>>();
072        pluginsByExtensionClass = new HashMap<Class<? extends Extension>, Plugin>();
073        extensionClassesByType = new HashMap<Class<? extends Extension>, List<Class<? extends Extension>>>();
074    
075        for (Plugin plugin : getPlugins()) {
076          for (Class<? extends Extension> extensionClass : plugin.getExtensions()) {
077            extensionClasses.add(extensionClass);
078            pluginsByExtensionClass.put(extensionClass, plugin);
079          }
080        }
081      }
082    
083      public Collection<Plugin> getPlugins() {
084        return plugins.values();
085      }
086    
087      public Plugin getPlugin(String key) {
088        return plugins.get(key);
089      }
090    
091    
092      public Plugin getPluginByExtension(Class<? extends Extension> clazz) {
093        return pluginsByExtensionClass.get(clazz);
094      }
095    
096      public String getPluginKeyByExtension(Class<? extends Extension> clazz) {
097        Plugin plugin = getPluginByExtension(clazz);
098        if (plugin != null) {
099          return plugin.getKey();
100        }
101        return null;
102      }
103    
104      public Plugin getPluginByExtension(Extension extension) {
105        return getPluginByExtension(extension.getClass());
106      }
107    
108      public List<Class<? extends Extension>> getExtensions() {
109        return extensionClasses;
110      }
111    
112      public List<Class<? extends Extension>> getExtensions(Class<? extends Extension> type) {
113        List<Class<? extends Extension>> list = extensionClassesByType.get(type);
114        if (list == null) {
115          list = new ArrayList<Class<? extends Extension>>();
116          for (Class<? extends Extension> extension : getExtensions()) {
117            if (type.isAssignableFrom(extension)) {
118              list.add(extension);
119            }
120          }
121          extensionClassesByType.put(type, list);
122        }
123    
124        return list;
125      }
126    
127      public Property[] getProperties(Plugin plugin) {
128        Class<? extends Plugin> classInstance = plugin.getClass();
129        if (classInstance.isAnnotationPresent(Properties.class)) {
130          return classInstance.getAnnotation(Properties.class).value();
131        }
132        return new Property[0];
133      }
134    }