/* * Copyright (C) 2014, International Business Machines Corporation * All Rights Reserved. */ package com.ibm.streamsx.inet.http; import java.io.IOException; import java.net.HttpURLConnection; import java.util.List; import java.util.Map; import java.util.logging.Logger; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.DeflateDecompressingEntity; import org.apache.http.client.entity.GzipDecompressingEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.utils.URIBuilder; import org.apache.http.impl.client.DefaultHttpClient; import com.ibm.streams.operator.OperatorContext; import com.ibm.streams.operator.OutputTuple; import com.ibm.streams.operator.Tuple; import com.ibm.streams.operator.TupleAttribute; import com.ibm.streams.operator.logging.TraceLevel; import com.ibm.streams.operator.metrics.Metric; import com.ibm.streams.operator.metrics.Metric.Kind; import com.ibm.streams.operator.model.CustomMetric; import com.ibm.streams.operator.model.Parameter; import com.ibm.streams.operator.samples.patterns.PollingSingleTupleProducer; public abstract class AbstractHTTPGetContent<A> extends PollingSingleTupleProducer { protected static final Logger trace = Logger .getLogger("com.ibm.streamsx.inet.http"); private String url; private List<String> extraHeaders; private HttpClient client; protected URIBuilder builder; protected HttpGet get; protected TupleAttribute<Tuple, A> contentAttribute; protected int contentAttributeIndex; private Metric nFailedRequests; boolean acceptAllCertificates = false; public String getUrl() { return url; } @Parameter(description = "URL to HTTP GET content from.") public void setUrl(String url) { this.url = url; } @Parameter(optional = true, description = "Extra headers to send with request, format is \\\"Header-Name: value\\\"") public void setExtraHeaders(List<String> extraHeaders) { this.extraHeaders = extraHeaders; } @Parameter(optional = true, description = "Accept all SSL certificates, even those that are self-signed. " + "Setting this option will allow potentially insecure connections. Default is false.") public void setAcceptAllCertificates(boolean acceptAllCertificates) { this.acceptAllCertificates = acceptAllCertificates; } public Metric getnFailedRequests() { return nFailedRequests; } @CustomMetric(kind = Kind.COUNTER, description = "Number of HTTP requests that failed, did not return response 200.") public void setnFailedRequests(Metric nFailedRequests) { this.nFailedRequests = nFailedRequests; } protected static final String CA_DESC = "Output attribute to assign content to."; public TupleAttribute<Tuple, A> getContentAttribute() { return contentAttribute; } @Override public synchronized void initialize(OperatorContext context) throws Exception { super.initialize(context); if(acceptAllCertificates) client = HTTPUtils.getHttpClientWithNoSSLValidation(); else client = new DefaultHttpClient(); builder = new URIBuilder(getUrl()); get = new HttpGet(builder.build()); get.addHeader("Accept", acceptedContentTypes()); get.addHeader("Accept-Encoding", "gzip, deflate"); trace.info("Initial URL: " + get.getURI().toString()); if (getContentAttribute() != null) contentAttributeIndex = getContentAttribute().getAttribute() .getIndex(); else contentAttributeIndex = defaultContentAttributeIndex(); Map<String, String> extraHeaderMap = HTTPUtils.getHeaderMap(extraHeaders); for(Map.Entry<String, String> header : extraHeaderMap.entrySet()) { get.setHeader(header.getKey(), header.getValue()); } } protected abstract String acceptedContentTypes(); // defaults to the first attribute protected int defaultContentAttributeIndex() { return 0; } /** * Execute an HTTP GET request for each tuple that will be submitted. The * contents of the tuple will be the XML contents of the returned Content. * If the request was not OK then no tuple will be submitted. */ @Override protected boolean fetchSingleTuple(OutputTuple tuple) throws Exception { HttpResponse response = client.execute(get); try { final int responseCode = response.getStatusLine().getStatusCode(); if (trace.isLoggable(TraceLevel.TRACE)) trace.log(TraceLevel.TRACE, "HTTP GET:" + responseCode + " URL:" + get.getURI()); if (responseCode != HttpURLConnection.HTTP_OK) { getnFailedRequests().increment(); return false; } HttpEntity content = response.getEntity(); if (content != null) { content = getUncompressedEntity(content); submitContents(tuple, content); } } finally { get.reset(); } return true; } protected abstract void submitContents(OutputTuple tuple, HttpEntity content) throws Exception; // for handling compressions static HttpEntity getUncompressedEntity(HttpEntity content) throws IOException { final org.apache.http.Header contentEncodingHdr = content .getContentEncoding(); if (contentEncodingHdr == null) return content; final String encoding = contentEncodingHdr.getValue(); if (encoding == null) return content; if ("gzip".equalsIgnoreCase(encoding)) return new GzipDecompressingEntity(content); if ("deflate".equalsIgnoreCase(encoding)) return new DeflateDecompressingEntity(content); throw new IOException("Unknown encoding: " + encoding); } }