/*
* Ada Sonar Plugin
* Copyright (C) 2010 Akram Ben Aissi
* dev@sonar.codehaus.org
*
* 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 02
*/
package org.sonar.plugins.ada.core;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.BatchExtension;
import org.sonar.api.utils.SonarException;
import org.sonar.plugins.ada.gnat.metric.GnatConfiguration;
/**
* Abstract plugin executor. This class handles common executor needs such as running the process, reading its common and error output
* streams and logging. In nominal case implementing executor should just construct the desire command line.
*/
public abstract class PluginAbstractExecutor implements BatchExtension {
/** The logger */
private static final Logger LOG = LoggerFactory.getLogger(PluginAbstractExecutor.class);
/**
* The Class AsyncPipe.
*/
static class AsyncPipe extends Thread {
private static final int BUFFER_SIZE = 1024;
/** The input stream. */
private InputStream inputStream;
/** The output stream. */
private OutputStream outputStream;
/**
* Instantiates a new async pipe.
*
* @param input
* an InputStream
* @param output
* an OutputStream
*/
public AsyncPipe(InputStream input, OutputStream output) {
inputStream = input;
outputStream = output;
}
/**
* @see java.lang.Thread#run()
*/
@Override
public void run() {
try {
final byte[] buffer = new byte[BUFFER_SIZE];
// Reads the process input stream and writes it to the output stream
int length = inputStream.read(buffer);
while (length != -1) {
synchronized (outputStream) {
outputStream.write(buffer, 0, length);
}
length = inputStream.read(buffer);
}
} catch (IOException e) {
LOG.error("Can't execute the Async Pipe", e);
}
}
}
/**
* Executes the external tool.
*/
public void execute() {
if ( !getConfiguration().isAnalyzeOnly()) {
// Gets the tool command line
try {
List<String> commandLine = getCommandLine();
LOG.info("Executing " + getExecutable() + " with command '{}'", prettyPrint(commandLine));
ProcessBuilder builder = new ProcessBuilder(commandLine);
// Starts the process
Process process = builder.start();
// And handles it's normal and error stream in separated threads.
new AsyncPipe(process.getInputStream(), System.out).start();
new AsyncPipe(process.getErrorStream(), System.err).start();
LOG.info(getExecutable() + " ended with returned code '{}'.", process.waitFor());
} catch (IOException e) {
LOG.error("Can't execute the external tool", e);
throw new SonarException(e);
} catch (InterruptedException e) {
LOG.error("Async pipe interrupted: ", e);
}
}
}
protected abstract GnatConfiguration getConfiguration();
/**
* Returns a String where each list member is separated with a space
*
* @param commandLine
* the external tool command line argument
* @return String where each list member is separated with a space
*/
private String prettyPrint(List<String> commandLine) {
StringBuilder sb = new StringBuilder();
for (Iterator<String> iter = commandLine.iterator(); iter.hasNext();) {
String part = iter.next();
sb.append(part);
if (iter.hasNext()) {
sb.append(" ");
}
}
return sb.toString();
}
/**
* Gets the command line.
*
* @return the command line
*/
protected abstract List<String> getCommandLine();
/**
* Gets the executed tool.
*
* @return the executed tool
*/
protected abstract String getExecutable();
}