/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.bootstrapper;
import com.google.common.base.Throwables;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import org.sonar.api.utils.MessageException;
import org.sonar.scanner.bootstrap.GlobalContainer;
/**
* Entry point for SonarQube Scanner API 2.1+.
*
* @since 2.14
*/
public final class Batch {
private boolean started = false;
private LoggingConfiguration loggingConfig;
private List<Object> components;
private Map<String, String> bootstrapProperties = new HashMap<>();
private GlobalContainer bootstrapContainer;
private Batch(Builder builder) {
components = new ArrayList<>();
components.addAll(builder.components);
if (builder.environment != null) {
components.add(builder.environment);
}
if (builder.bootstrapProperties != null) {
bootstrapProperties.putAll(builder.bootstrapProperties);
}
if (builder.isEnableLoggingConfiguration()) {
loggingConfig = new LoggingConfiguration(builder.environment).setProperties(bootstrapProperties);
if (builder.logOutput != null) {
loggingConfig.setLogOutput(builder.logOutput);
}
}
}
public LoggingConfiguration getLoggingConfiguration() {
return loggingConfig;
}
/**
* @deprecated since 4.4 use {@link #start()}, {@link #executeTask(Map)} and then {@link #stop()}
*/
@Deprecated
public synchronized Batch execute() {
configureLogging();
start();
boolean threw = true;
try {
executeTask(bootstrapProperties);
threw = false;
} finally {
doStop(threw);
}
return this;
}
/**
* @since 4.4
*/
public synchronized Batch start() {
return start(false);
}
public synchronized Batch start(boolean preferCache) {
if (started) {
throw new IllegalStateException("Batch is already started");
}
configureLogging();
try {
bootstrapContainer = GlobalContainer.create(bootstrapProperties, components);
bootstrapContainer.startComponents();
} catch (RuntimeException e) {
throw handleException(e);
}
this.started = true;
return this;
}
/**
* @since 4.4
*/
public Batch executeTask(Map<String, String> analysisProperties, Object... components) {
checkStarted();
configureTaskLogging(analysisProperties);
try {
bootstrapContainer.executeTask(analysisProperties, components);
} catch (RuntimeException e) {
throw handleException(e);
}
return this;
}
/**
* @since 5.2
*/
public Batch executeTask(Map<String, String> analysisProperties, IssueListener issueListener) {
checkStarted();
configureTaskLogging(analysisProperties);
try {
bootstrapContainer.executeTask(analysisProperties, components, issueListener);
} catch (RuntimeException e) {
throw handleException(e);
}
return this;
}
private void checkStarted() {
if (!started) {
throw new IllegalStateException("Scanner engine is not started. Unable to execute task.");
}
}
private RuntimeException handleException(RuntimeException t) {
if (loggingConfig.isVerbose()) {
return t;
}
for (Throwable y : Throwables.getCausalChain(t)) {
if (y instanceof MessageException) {
return (MessageException) y;
}
}
return t;
}
/**
* @since 5.2
* @deprecated since 5.6
*/
@Deprecated
public Batch syncProject(String projectKey) {
checkStarted();
return this;
}
/**
* @since 4.4
*/
public synchronized void stop() {
doStop(false);
}
private void doStop(boolean swallowException) {
checkStarted();
configureLogging();
try {
bootstrapContainer.stopComponents(swallowException);
} catch (RuntimeException e) {
throw handleException(e);
}
this.started = false;
}
private void configureLogging() {
if (loggingConfig != null) {
loggingConfig.setProperties(bootstrapProperties);
LoggingConfigurator.apply(loggingConfig);
}
}
private void configureTaskLogging(Map<String, String> taskProperties) {
if (loggingConfig != null) {
loggingConfig.setProperties(taskProperties, bootstrapProperties);
LoggingConfigurator.apply(loggingConfig);
}
}
public static Builder builder() {
return new Builder();
}
public static final class Builder {
private Map<String, String> bootstrapProperties;
private EnvironmentInformation environment;
private List<Object> components = new ArrayList<>();
private boolean enableLoggingConfiguration = true;
private LogOutput logOutput;
private Builder() {
}
public Builder setEnvironment(EnvironmentInformation env) {
this.environment = env;
return this;
}
public Builder setComponents(List<Object> l) {
this.components = l;
return this;
}
public Builder setLogOutput(@Nullable LogOutput logOutput) {
this.logOutput = logOutput;
return this;
}
/**
* @deprecated since 3.7 use {@link #setBootstrapProperties(Map)}
*/
@Deprecated
public Builder setGlobalProperties(Map<String, String> globalProperties) {
this.bootstrapProperties = globalProperties;
return this;
}
public Builder setBootstrapProperties(Map<String, String> bootstrapProperties) {
this.bootstrapProperties = bootstrapProperties;
return this;
}
public Builder addComponents(Object... components) {
Collections.addAll(this.components, components);
return this;
}
public Builder addComponent(Object component) {
this.components.add(component);
return this;
}
public boolean isEnableLoggingConfiguration() {
return enableLoggingConfiguration;
}
/**
* Logback is configured by default. It can be disabled, but n this case the batch bootstrapper must provide its
* own implementation of SLF4J.
*/
public Builder setEnableLoggingConfiguration(boolean b) {
this.enableLoggingConfiguration = b;
return this;
}
public Batch build() {
if (components == null) {
throw new IllegalStateException("Batch components are not set");
}
return new Batch(this);
}
}
}