/*******************************************************************************
* Trombone is a flexible text processing and analysis library used
* primarily by Voyant Tools (voyant-tools.org).
*
* Copyright (©) 2007-2012 Stéfan Sinclair & Geoffrey Rockwell
*
* This file is part of Trombone.
*
* Trombone is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Trombone 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Trombone. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package org.voyanttools.trombone.tool.utils;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.voyanttools.trombone.input.source.InputSourcesBuilder;
import org.voyanttools.trombone.storage.Storage;
import org.voyanttools.trombone.tool.ToolFactory;
import org.voyanttools.trombone.tool.corpus.CorpusExporter;
import org.voyanttools.trombone.tool.corpus.CorpusManager;
import org.voyanttools.trombone.tool.corpus.CorpusMetadata;
import org.voyanttools.trombone.tool.resource.StoredResource;
import org.voyanttools.trombone.util.FlexibleParameters;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
import edu.stanford.nlp.util.StringUtils;
/**
* @author sgs
*
*/
@XStreamAlias("results")
public class ToolRunner extends AbstractTool {
private String version;
private String voyantVersion;
private String voyantBuild;
private long duration;
@XStreamOmitField
private Writer writer = null;
@XStreamOmitField
private OutputStream outputStream = null;
@XStreamImplicit
List<RunnableTool> results = new ArrayList<RunnableTool>();
/**
*
*/
public ToolRunner(Storage storage, FlexibleParameters parameters, Writer writer) {
super(storage, parameters);
this.version = Float.toString(getVersion());
this.writer = writer;
}
public ToolRunner(Storage storage, FlexibleParameters parameters, OutputStream outputStream) {
super(storage, parameters);
this.outputStream = outputStream;
}
public void run() throws IOException {
ToolFactory toolFactory = new ToolFactory(storage, parameters);
toolFactory.run();
List<RunnableTool> tools = toolFactory.getRunnableTools();
// handle alternative tools
if (tools.size()==1) {
RunnableTool tool = tools.get(0);
if (tool instanceof CorpusExporter) {
if (outputStream==null) {
throw new IllegalArgumentException("The CorpusExporter tool requires the outputFormat=zip parameter to be set (or otherwise an OutputStream to be used instead of a Writer).");
}
((CorpusExporter) tool).run(CorpusManager.getCorpus(storage, parameters), outputStream);
return;
}
}
StringBuilder sb = new StringBuilder("cache-ToolRunner-").append(getVersion());
for (RunnableTool tool : tools) {
sb.append("-").append(tool.getClass().getSimpleName()).append(tool.getVersion());
}
sb.append("-");
if (parameters.containsKey("corpus")) { // add corpus to make it easier to find
sb.append(parameters.getParameterValue("corpus")).append("-");
}
List<String> names = new ArrayList(parameters.getKeys());
Collections.sort(names);
StringBuilder paramsBuilder = new StringBuilder();
for (String name : names) {
if (name.startsWith("_dc")==false) {
paramsBuilder.append(name).append(StringUtils.join(parameters.getParameterValues(name)));
}
}
sb.append(DigestUtils.md5Hex(paramsBuilder.toString()));
String id = sb.toString();
boolean hasParameterSources = InputSourcesBuilder.hasParameterSources(parameters);
// skip for corpus (makes it easier to change or remove) and stored resource (cacheing not relevant, easier to change)
boolean noCache = tools.size()==1 && (tools.get(0) instanceof CorpusMetadata || tools.get(0) instanceof StoredResource);
if (noCache==false && parameters.getParameterBooleanValue("noCache")==false && parameters.getParameterBooleanValue("reCache")==false && hasParameterSources==false && storage.isStored(id, Storage.Location.cache)) {
Reader reader = storage.getStoreReader(id, Storage.Location.cache);
IOUtils.copy(reader, writer);
reader.close();
writer.flush();
}
else {
long start = Calendar.getInstance().getTimeInMillis();
for (RunnableTool tool : tools) {
tool.run();
results.add(tool);
}
duration = Calendar.getInstance().getTimeInMillis() - start;
voyantVersion = parameters.getParameterValue("VOYANT_VERSION", "");
voyantBuild = parameters.getParameterValue("VOYANT_BUILD", "");
ToolSerializer toolSerializer = new ToolSerializer(parameters, this);
if (parameters.getParameterBooleanValue("noCache") || hasParameterSources==true) { // use the configured writer directly
toolSerializer.run(writer);
}
else { // try to cache
Writer cacheWriter = storage.getStoreWriter(id, Storage.Location.cache);
toolSerializer.run(cacheWriter);
cacheWriter.close();
Reader reader = storage.getStoreReader(id, Storage.Location.cache);
IOUtils.copy(reader, writer); // now write from cache
reader.close();
writer.flush();
}
}
}
public List<RunnableTool> getRunnableToolResults() {
return results;
}
}