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 */
020package org.sonar.batch.bootstrap;
021
022import com.google.common.base.Joiner;
023import com.google.common.collect.Maps;
024import com.google.common.collect.Sets;
025import org.apache.commons.lang.StringUtils;
026import org.slf4j.Logger;
027import org.slf4j.LoggerFactory;
028import org.sonar.api.CoreProperties;
029import org.sonar.api.Plugin;
030import org.sonar.api.Properties;
031import org.sonar.api.Property;
032import org.sonar.api.config.Settings;
033import org.sonar.api.platform.PluginMetadata;
034import org.sonar.api.platform.PluginRepository;
035import org.sonar.core.plugins.PluginClassloaders;
036import org.sonar.core.plugins.PluginInstaller;
037import org.sonar.core.plugins.RemotePlugin;
038
039import java.io.File;
040import java.util.*;
041
042public 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  }
065
066  public void start() {
067    doStart(artifactDownloader.downloadPluginIndex());
068  }
069
070  void doStart(List<RemotePlugin> remotePlugins) {
071    PluginInstaller extractor = new PluginInstaller();
072    metadataByKey = Maps.newHashMap();
073    for (RemotePlugin remote : remotePlugins) {
074      if (isAccepted(remote.getKey())) {
075        List<File> pluginFiles = artifactDownloader.downloadPlugin(remote);
076        List<File> extensionFiles = pluginFiles.subList(1, pluginFiles.size());
077        PluginMetadata metadata = extractor.installInSameLocation(pluginFiles.get(0), remote.isCore(), extensionFiles);
078        if (StringUtils.isBlank(metadata.getBasePlugin()) || isAccepted(metadata.getBasePlugin())) {
079          LOG.debug("Excluded plugin: " + metadata.getKey());
080          metadataByKey.put(metadata.getKey(), metadata);
081        }
082      }
083    }
084    classLoaders = new PluginClassloaders(Thread.currentThread().getContextClassLoader());
085    pluginsByKey = classLoaders.init(metadataByKey.values());
086  }
087
088  public void stop() {
089    if (classLoaders != null) {
090      classLoaders.clean();
091      classLoaders = null;
092    }
093  }
094
095  public Collection<Plugin> getPlugins() {
096    return pluginsByKey.values();
097  }
098
099  public Plugin getPlugin(String key) {
100    return pluginsByKey.get(key);
101  }
102
103  public Map<String, Plugin> getPluginsByKey() {
104    return Collections.unmodifiableMap(pluginsByKey);
105  }
106
107  // TODO remove this method. Not used in batch.
108  public Property[] getProperties(Plugin plugin) {
109    if (plugin != null) {
110      Class<? extends Plugin> classInstance = plugin.getClass();
111      if (classInstance.isAnnotationPresent(Properties.class)) {
112        return classInstance.getAnnotation(Properties.class).value();
113      }
114    }
115    return new Property[0];
116  }
117
118  public Collection<PluginMetadata> getMetadata() {
119    return metadataByKey.values();
120  }
121
122  public PluginMetadata getMetadata(String pluginKey) {
123    return metadataByKey.get(pluginKey);
124  }
125
126  boolean isAccepted(String pluginKey) {
127    if (CORE_PLUGIN.equals(pluginKey)) {
128      return true;
129    }
130    if (whiteList != null) {
131      return whiteList.contains(pluginKey);
132    }
133    return blackList == null || !blackList.contains(pluginKey);
134  }
135
136  public Map<PluginMetadata,Plugin> getPluginsByMetadata() {
137    Map<PluginMetadata, Plugin> result = Maps.newHashMap();
138    for (Map.Entry<String, PluginMetadata> entry : metadataByKey.entrySet()) {
139      String pluginKey = entry.getKey();
140      PluginMetadata metadata = entry.getValue();
141      result.put(metadata, pluginsByKey.get(pluginKey));
142    }
143    return result;
144  }
145}