blob: 342eeda342ed3faadebf62aa5c5e990f07ad4a19 [file] [log] [blame]
/**
*
*/
package net.sf.taverna.t2.activities.interaction;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import net.sf.taverna.t2.activities.interaction.atom.AtomUtils;
import net.sf.taverna.t2.activities.interaction.jetty.InteractionJetty;
import net.sf.taverna.t2.activities.interaction.preference.InteractionPreference;
import net.sf.taverna.t2.activities.interaction.velocity.InteractionVelocity;
import net.sf.taverna.t2.security.credentialmanager.CredentialManager;
import org.apache.abdera.Abdera;
import org.apache.abdera.i18n.text.Normalizer;
import org.apache.abdera.i18n.text.Sanitizer;
import org.apache.abdera.model.Element;
import org.apache.abdera.model.Entry;
import org.apache.abdera.parser.stax.FOMElement;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.log4j.Logger;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
public final class InteractionActivityRunnable implements Runnable {
private static final Logger logger = Logger
.getLogger(InteractionActivityRunnable.class);
private static final Abdera ABDERA = Abdera.getInstance();
private final Template presentationTemplate;
private final InteractionRequestor requestor;
private CredentialManager credentialManager;
private InteractionRecorder interactionRecorder;
private InteractionUtils interactionUtils;
private InteractionJetty interactionJetty;
private InteractionPreference interactionPreference;
private ResponseFeedListener responseFeedListener;
private InteractionVelocity interactionVelocity;
public InteractionActivityRunnable(final InteractionRequestor requestor,
final Template presentationTemplate,
final CredentialManager credentialManager,
final InteractionRecorder interactionRecorder,
final InteractionUtils interactionUtils,
final InteractionJetty interactionJetty,
final InteractionPreference interactionPreference,
final ResponseFeedListener responseFeedListener,
final InteractionVelocity interactionVelocity) {
this.requestor = requestor;
this.presentationTemplate = presentationTemplate;
this.credentialManager = credentialManager;
this.interactionRecorder = interactionRecorder;
this.interactionUtils = interactionUtils;
this.interactionJetty = interactionJetty;
this.interactionPreference = interactionPreference;
this.responseFeedListener = responseFeedListener;
this.interactionVelocity = interactionVelocity;
}
@Override
public void run() {
/*
* InvocationContext context = callback.getContext();
*/
final String runId = InteractionUtils.getUsedRunId(this.requestor
.getRunId());
final String id = Sanitizer.sanitize(UUID.randomUUID().toString(), "",
true, Normalizer.Form.D);
final Map<String, Object> inputData = this.requestor.getInputData();
if (interactionPreference.getUseJetty()) {
interactionJetty.startJettyIfNecessary(credentialManager);
}
interactionJetty.startListenersIfNecessary();
try {
interactionUtils.copyFixedFile("pmrpc.js");
interactionUtils.copyFixedFile("interaction.css");
} catch (final IOException e1) {
logger.error(e1);
this.requestor.fail("Unable to copy necessary fixed file");
return;
}
synchronized (ABDERA) {
final Entry interactionNotificationMessage = this
.createBasicInteractionMessage(id, runId);
for (final String key : inputData.keySet()) {
final Object value = inputData.get(key);
if (value instanceof byte[]) {
final String replacementUrl = interactionPreference
.getPublicationUrlString(id, key);
final ByteArrayInputStream bais = new ByteArrayInputStream(
(byte[]) value);
try {
interactionUtils.publishFile(replacementUrl, bais,
runId, id);
bais.close();
inputData.put(key, replacementUrl);
} catch (final IOException e) {
logger.error(e);
this.requestor.fail("Unable to publish to " + replacementUrl);
return;
}
}
}
final String inputDataString = this.createInputDataJson(inputData);
if (inputDataString == null) {
return;
}
final String inputDataUrl = interactionPreference
.getInputDataUrlString(id);
try {
interactionUtils.publishFile(inputDataUrl, inputDataString,
runId, id);
} catch (final IOException e) {
logger.error(e);
this.requestor.fail("Unable to publish to " + inputDataUrl);
return;
}
String outputDataUrl = null;
if (!this.requestor.getInteractionType().equals(
InteractionType.Notification)) {
outputDataUrl = interactionPreference
.getOutputDataUrlString(id);
}
final String interactionUrlString = this.generateHtml(inputDataUrl,
outputDataUrl, inputData, runId, id);
try {
this.postInteractionMessage(id, interactionNotificationMessage,
interactionUrlString, runId);
} catch (IOException e) {
logger.error(e);
this.requestor.fail("Unable to post message");
return;
}
if (!this.requestor.getInteractionType().equals(
InteractionType.Notification)) {
responseFeedListener.registerInteraction(
interactionNotificationMessage, this.requestor);
} else {
this.requestor.carryOn();
}
}
}
private String createInputDataJson(final Map<String, Object> inputData) {
try {
return InteractionUtils.objectToJson(inputData);
} catch (final IOException e) {
logger.error(e);
this.requestor.fail("Unable to generate JSON");
}
return null;
}
private Entry createBasicInteractionMessage(final String id,
final String runId) {
final Entry interactionNotificationMessage = ABDERA.newEntry();
interactionNotificationMessage.setId(id);
final Date timestamp = new Date();
interactionNotificationMessage.setPublished(timestamp);
interactionNotificationMessage.setUpdated(timestamp);
interactionNotificationMessage.addAuthor("Taverna");
interactionNotificationMessage.setTitle("Interaction from Taverna for "
+ this.requestor.generateId());
final Element runIdElement = interactionNotificationMessage
.addExtension(AtomUtils.getRunIdQName());
runIdElement.setText(StringEscapeUtils.escapeJavaScript(runId));
final Element pathIdElement = interactionNotificationMessage.addExtension(AtomUtils.getPathIdQName());
pathIdElement.setText(StringEscapeUtils.escapeJavaScript(this.requestor.getPath()));
final Element countElement = interactionNotificationMessage.addExtension(AtomUtils.getCountQName());
countElement.setText(StringEscapeUtils.escapeJavaScript(this.requestor.getInvocationCount().toString()));
if (this.requestor.getInteractionType().equals(
InteractionType.Notification)) {
interactionNotificationMessage.addExtension(AtomUtils
.getProgressQName());
}
final Element idElement = interactionNotificationMessage
.addExtension(AtomUtils.getIdQName());
idElement.setText(id);
return interactionNotificationMessage;
}
private void postInteractionMessage(final String id, final Entry entry,
final String interactionUrlString, final String runId) throws IOException {
entry.addLink(StringEscapeUtils.escapeXml(interactionUrlString),
"presentation");
entry.setContentAsXhtml("<p><a href=\""
+ StringEscapeUtils.escapeXml(interactionUrlString)
+ "\">Open: "
+ StringEscapeUtils.escapeXml(interactionUrlString)
+ "</a></p>");
URL feedUrl;
feedUrl = new URL(interactionPreference
.getFeedUrlString());
final String entryContent = ((FOMElement) entry)
.toFormattedString();
final HttpURLConnection httpCon = (HttpURLConnection) feedUrl
.openConnection();
httpCon.setDoOutput(true);
httpCon.setRequestProperty("Content-Type",
"application/atom+xml;type=entry;charset=UTF-8");
httpCon.setRequestProperty("Content-Length",
"" + entryContent.length());
httpCon.setRequestProperty("Slug", id);
httpCon.setRequestMethod("POST");
httpCon.setConnectTimeout(5000);
final OutputStream outputStream = httpCon.getOutputStream();
IOUtils.write(entryContent, outputStream, "UTF-8");
outputStream.close();
final int response = httpCon.getResponseCode();
if ((response < 0) || (response >= 400)) {
logger.error("Received response code" + response);
throw (new IOException ("Received response code " + response));
}
if (response == HttpURLConnection.HTTP_CREATED) {
interactionRecorder.addResource(runId, id,
httpCon.getHeaderField("Location"));
}
}
String generateHtml(final String inputDataUrl, final String outputDataUrl,
final Map<String, Object> inputData, final String runId,
final String id) {
final VelocityContext velocityContext = new VelocityContext();
for (final String inputName : inputData.keySet()) {
final Object input = inputData.get(inputName);
velocityContext.put(inputName, input);
}
velocityContext.put("feed", interactionPreference
.getFeedUrlString());
velocityContext.put("runId", runId);
velocityContext.put("entryId", id);
final String pmrpcUrl = interactionPreference
.getLocationUrl() + "/pmrpc.js";
velocityContext.put("pmrpcUrl", pmrpcUrl);
velocityContext.put("inputDataUrl", inputDataUrl);
velocityContext.put("outputDataUrl", outputDataUrl);
final String interactionUrl = interactionPreference
.getInteractionUrlString(id);
velocityContext.put("interactionUrl", interactionUrl);
String presentationUrl = "";
final String authorizeUrl = "";
try {
if (this.requestor.getPresentationType().equals(
InteractionActivityType.VelocityTemplate)) {
presentationUrl = interactionPreference
.getPresentationUrlString(id);
final String presentationString = this.processTemplate(
this.presentationTemplate, velocityContext);
interactionUtils.publishFile(presentationUrl,
presentationString, runId, id);
} else if (this.requestor.getPresentationType().equals(
InteractionActivityType.LocallyPresentedHtml)) {
presentationUrl = this.requestor.getPresentationOrigin();
}
velocityContext.put("presentationUrl", presentationUrl);
final String interactionString = this.processTemplate(
interactionVelocity.getInteractionTemplate(),
velocityContext);
interactionUtils.publishFile(interactionUrl, interactionString,
runId, id);
if (!authorizeUrl.isEmpty()) {
return authorizeUrl;
}
return interactionUrl;
} catch (final IOException e) {
logger.error(e);
this.requestor.fail("Unable to generate HTML");
return null;
}
}
private String processTemplate(final Template template,
final VelocityContext context) throws IOException {
final StringWriter resultWriter = new StringWriter();
template.merge(context, resultWriter);
resultWriter.close();
return resultWriter.toString();
}
}