/*
* Copyright (C) 2014, International Business Machines Corporation
* All Rights Reserved.
*/
package com.ibm.streamsx.inet.httpxml;
import org.apache.http.HttpEntity;
import com.ibm.streams.operator.OperatorContext;
import com.ibm.streams.operator.OperatorContext.ContextCheck;
import com.ibm.streams.operator.OutputTuple;
import com.ibm.streams.operator.compile.OperatorContextChecker;
import com.ibm.streams.operator.model.Icons;
import com.ibm.streams.operator.model.OutputPortSet;
import com.ibm.streams.operator.model.OutputPortSet.WindowPunctuationOutputMode;
import com.ibm.streams.operator.model.Parameter;
import com.ibm.streams.operator.model.PrimitiveOperator;
import com.ibm.streams.operator.types.ValueFactory;
import com.ibm.streams.operator.types.XML;
import com.ibm.streamsx.inet.http.AbstractHTTPGetContent;
/**
* HTTP GET of application/xml content.
*
*/
@PrimitiveOperator(description = HTTPGetXMLContent.DESC, namespace = "com.ibm.streamsx.inet.http")
// Can't create a control port because TupleConsumer has process as final.
// @InputPortSet(optional=true, cardinality=1, controlPort=true,
// description="Control port to change the URL used for the HTTP GET.")
@OutputPortSet(cardinality = 1, windowPunctuationOutputMode = WindowPunctuationOutputMode.Free, description = "Content of the HTTP GET request as an XML attribute. Each successful HTTP request that returns a "
+ "single well-formed XML document results in a submitted tuple with an XML attribute containing the returned content.")
@Icons(location32 = "icons/HTTPGetXMLContent_32.gif", location16 = "icons/HTTPGetXMLContent_16.gif")
public class HTTPGetXMLContent extends AbstractHTTPGetContent<XML> {
static final String DESC = "Periodically connects to an HTTP endpoint to GET XML content as a single tuple. "
+ "The XML content is assigned to the first attribute in the output tuple which must be "
+ "of type `xml`."
+ ""
+ "The URL can have a single query parameter updated using the `updateParameter` parameter."
+ "When set the URL query string will be modified to set the named parameter to a new value."
+ "The default action is to set it to the number of milliseconds since the 1970 epoch.";
private String updateParameter;
private String updateXPath;
private UpdateParameter updater;
@Parameter(optional = true, description = "URL query parameter to update based upon content in a successful request.")
public void setUpdateParameter(String updateParameter) {
this.updateParameter = updateParameter;
}
public String getUpdateXPath() {
return updateXPath;
}
@Parameter(name = "updateParameterFromContent", optional = true, description = "Update the query parameter set in `updateParameter` from the value of this XPath expression against the returned content.")
public void setUpdateXPath(String updateXPath) {
this.updateXPath = updateXPath;
}
@ContextCheck
public static void checkParameters(OperatorContextChecker checker) {
checker.checkDependentParameters("updateParameterFromContent",
"updateParameter");
}
@Override
public synchronized void initialize(OperatorContext context)
throws Exception {
super.initialize(context);
if (updateParameter != null) {
if (getUpdateXPath() != null) {
// Update using XPath
updater = new UpdateFromXPath(this, getUpdateXPath());
} else {
// default updater using the current time.
updater = new UpdateCurrentTimeMills();
}
}
}
@Override
protected String acceptedContentTypes() {
return "application/xml, text/xml";
}
@Override
protected void submitContents(OutputTuple tuple, HttpEntity content)
throws Exception {
final XML xml = ValueFactory.newXML(content.getContent());
tuple.setXML(contentAttributeIndex, xml);
if (updater != null) {
if (!xml.isDefaultValue())
updater.update(xml);
}
}
/**
* How the URL query parameter will be updated.
*/
abstract class UpdateParameter {
void update(XML xml) throws Exception {
String value = getValue(xml);
if (value != null) {
builder.setParameter(updateParameter, value);
get.setURI(builder.build());
trace.info("Updated URL: " + get.getURI().toString());
}
}
abstract String getValue(XML xml) throws Exception;
}
/**
* Update the query attribute to the current time in milliseconds.
*/
class UpdateCurrentTimeMills extends UpdateParameter {
@Override
public String getValue(XML xml) throws Exception {
return Long.toString(System.currentTimeMillis());
}
}
}