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