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. This class is for internal use
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      /**
043       * Creates the dictionnary of plugins
044       */
045      public Plugins() {
046        try {
047          introspectPlugins();
048          introspectExtensions();
049    
050        } catch (Exception e) {
051          throw new SonarException("can not load plugins", e);
052        }
053      }
054    
055      protected final void introspectPlugins() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
056        Enumeration<URL> pluginsEnum = getClass().getClassLoader().getResources("META-INF/MANIFEST.MF");
057        plugins = new HashMap<String, Plugin>();
058        while (pluginsEnum.hasMoreElements()) {
059          URL pluginUrl = pluginsEnum.nextElement();
060          InputStream in = pluginUrl.openStream();
061          Manifest manifest = new Manifest(in);
062          in.close();
063          String pluginClassProp = manifest.getMainAttributes().getValue("Plugin-Class");
064          if (pluginClassProp != null) {
065            Class<?> pluginClass = Class.forName(pluginClassProp, true, getClass().getClassLoader());
066            Plugin pluginInstance = (Plugin) pluginClass.newInstance();
067            plugins.put(pluginInstance.getKey(), pluginInstance);
068    
069          }
070        }
071      }
072    
073      private void introspectExtensions() {
074        extensionClasses = new ArrayList<Class<? extends Extension>>();
075        pluginsByExtensionClass = new HashMap<Class<? extends Extension>, Plugin>();
076        extensionClassesByType = new HashMap<Class<? extends Extension>, List<Class<? extends Extension>>>();
077    
078        for (Plugin plugin : getPlugins()) {
079          for (Class<? extends Extension> extensionClass : plugin.getExtensions()) {
080            extensionClasses.add(extensionClass);
081            pluginsByExtensionClass.put(extensionClass, plugin);
082          }
083        }
084      }
085    
086      /**
087       * Gives a collection of available plugins in the Sonar instance
088       */
089      public Collection<Plugin> getPlugins() {
090        return plugins.values();
091      }
092    
093      /**
094       * Returns a plugin based on its key
095       */
096      public Plugin getPlugin(String key) {
097        return plugins.get(key);
098      }
099    
100    
101      /**
102       * Returns a plugin based on its extension
103       */
104      public Plugin getPluginByExtension(Class<? extends Extension> clazz) {
105        return pluginsByExtensionClass.get(clazz);
106      }
107    
108      /**
109       * Returns a plugin key based on its extension
110       */
111      public String getPluginKeyByExtension(Class<? extends Extension> clazz) {
112        Plugin plugin = getPluginByExtension(clazz);
113        if (plugin != null) {
114          return plugin.getKey();
115        }
116        return null;
117      }
118    
119      /**
120       * Returns a plugin based on its extension
121       */
122      public Plugin getPluginByExtension(Extension extension) {
123        return getPluginByExtension(extension.getClass());
124      }
125    
126      /**
127       * Returns the list of extensions in the server
128       */
129      public List<Class<? extends Extension>> getExtensions() {
130        return extensionClasses;
131      }
132    
133      /**
134       * Returns the list of extensions given an extension type
135       */
136      public List<Class<? extends Extension>> getExtensions(Class<? extends Extension> type) {
137        List<Class<? extends Extension>> list = extensionClassesByType.get(type);
138        if (list == null) {
139          list = new ArrayList<Class<? extends Extension>>();
140          for (Class<? extends Extension> extension : getExtensions()) {
141            if (type.isAssignableFrom(extension)) {
142              list.add(extension);
143            }
144          }
145          extensionClassesByType.put(type, list);
146        }
147    
148        return list;
149      }
150    
151      /**
152       * Returns the list of properties of a plugin
153       */
154      public Property[] getProperties(Plugin plugin) {
155        Class<? extends Plugin> classInstance = plugin.getClass();
156        if (classInstance.isAnnotationPresent(Properties.class)) {
157          return classInstance.getAnnotation(Properties.class).value();
158        }
159        return new Property[0];
160      }
161    }