001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2012 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.batch.bootstrap;
021    
022    import com.google.common.base.Joiner;
023    import com.google.common.collect.Maps;
024    import com.google.common.collect.Sets;
025    import org.apache.commons.lang.StringUtils;
026    import org.slf4j.Logger;
027    import org.slf4j.LoggerFactory;
028    import org.sonar.api.CoreProperties;
029    import org.sonar.api.Plugin;
030    import org.sonar.api.Properties;
031    import org.sonar.api.Property;
032    import org.sonar.api.config.Settings;
033    import org.sonar.api.platform.PluginMetadata;
034    import org.sonar.api.platform.PluginRepository;
035    import org.sonar.core.plugins.PluginClassloaders;
036    import org.sonar.core.plugins.PluginInstaller;
037    import org.sonar.core.plugins.RemotePlugin;
038    
039    import java.io.File;
040    import java.util.Arrays;
041    import java.util.Collection;
042    import java.util.Collections;
043    import java.util.List;
044    import java.util.Map;
045    import java.util.Set;
046    
047    public class BatchPluginRepository implements PluginRepository {
048    
049      private static final Logger LOG = LoggerFactory.getLogger(BatchPluginRepository.class);
050      private static final String CORE_PLUGIN = "core";
051      private static final String ENGLISH_PACK_PLUGIN = "l10nen";
052    
053      private ArtifactDownloader artifactDownloader;
054      private Map<String, Plugin> pluginsByKey;
055      private Map<String, PluginMetadata> metadataByKey;
056      private Set<String> whiteList = null;
057      private Set<String> blackList = null;
058      private PluginClassloaders classLoaders;
059    
060      public BatchPluginRepository(ArtifactDownloader artifactDownloader, Settings settings) {
061        this.artifactDownloader = artifactDownloader;
062        if (settings.hasKey(CoreProperties.BATCH_INCLUDE_PLUGINS)) {
063          whiteList = Sets.newTreeSet(Arrays.asList(settings.getStringArray(CoreProperties.BATCH_INCLUDE_PLUGINS)));
064          LOG.info("Include plugins: " + Joiner.on(", ").join(whiteList));
065        }
066        if (settings.hasKey(CoreProperties.BATCH_EXCLUDE_PLUGINS)) {
067          blackList = Sets.newTreeSet(Arrays.asList(settings.getStringArray(CoreProperties.BATCH_EXCLUDE_PLUGINS)));
068          LOG.info("Exclude plugins: " + Joiner.on(", ").join(blackList));
069        }
070      }
071    
072      public void start() {
073        doStart(artifactDownloader.downloadPluginIndex());
074      }
075    
076      void doStart(List<RemotePlugin> remotePlugins) {
077        PluginInstaller extractor = new PluginInstaller();
078        metadataByKey = Maps.newHashMap();
079        for (RemotePlugin remote : remotePlugins) {
080          if (isAccepted(remote.getKey())) {
081            List<File> pluginFiles = artifactDownloader.downloadPlugin(remote);
082            List<File> extensionFiles = pluginFiles.subList(1, pluginFiles.size());
083            PluginMetadata metadata = extractor.installInSameLocation(pluginFiles.get(0), remote.isCore(), extensionFiles);
084            if (StringUtils.isBlank(metadata.getBasePlugin()) || isAccepted(metadata.getBasePlugin())) {
085              LOG.debug("Excluded plugin: " + metadata.getKey());
086              metadataByKey.put(metadata.getKey(), metadata);
087            }
088          }
089        }
090        classLoaders = new PluginClassloaders(Thread.currentThread().getContextClassLoader());
091        pluginsByKey = classLoaders.init(metadataByKey.values());
092      }
093    
094      public void stop() {
095        if (classLoaders != null) {
096          classLoaders.clean();
097          classLoaders = null;
098        }
099      }
100    
101      public Collection<Plugin> getPlugins() {
102        return pluginsByKey.values();
103      }
104    
105      public Plugin getPlugin(String key) {
106        return pluginsByKey.get(key);
107      }
108    
109      public Map<String, Plugin> getPluginsByKey() {
110        return Collections.unmodifiableMap(pluginsByKey);
111      }
112    
113      // TODO remove this method. Not used in batch.
114      public Property[] getProperties(Plugin plugin) {
115        if (plugin != null) {
116          Class<? extends Plugin> classInstance = plugin.getClass();
117          if (classInstance.isAnnotationPresent(Properties.class)) {
118            return classInstance.getAnnotation(Properties.class).value();
119          }
120        }
121        return new Property[0];
122      }
123    
124      public Collection<PluginMetadata> getMetadata() {
125        return metadataByKey.values();
126      }
127    
128      public PluginMetadata getMetadata(String pluginKey) {
129        return metadataByKey.get(pluginKey);
130      }
131    
132      boolean isAccepted(String pluginKey) {
133        if (CORE_PLUGIN.equals(pluginKey) || ENGLISH_PACK_PLUGIN.equals(pluginKey)) {
134          return true;
135        }
136        if (whiteList != null) {
137          return whiteList.contains(pluginKey);
138        }
139        return blackList == null || !blackList.contains(pluginKey);
140      }
141    
142      public Map<PluginMetadata, Plugin> getPluginsByMetadata() {
143        Map<PluginMetadata, Plugin> result = Maps.newHashMap();
144        for (Map.Entry<String, PluginMetadata> entry : metadataByKey.entrySet()) {
145          String pluginKey = entry.getKey();
146          PluginMetadata metadata = entry.getValue();
147          result.put(metadata, pluginsByKey.get(pluginKey));
148        }
149        return result;
150      }
151    }