diff options
Diffstat (limited to 'appc-adapters/appc-dmaap-adapter/appc-dmaap-adapter-bundle/src/main/java/org/openecomp/appc/adapter/messaging/dmaap/http')
3 files changed, 404 insertions, 0 deletions
diff --git a/appc-adapters/appc-dmaap-adapter/appc-dmaap-adapter-bundle/src/main/java/org/openecomp/appc/adapter/messaging/dmaap/http/CommonHttpClient.java b/appc-adapters/appc-dmaap-adapter/appc-dmaap-adapter-bundle/src/main/java/org/openecomp/appc/adapter/messaging/dmaap/http/CommonHttpClient.java new file mode 100644 index 000000000..0d0450681 --- /dev/null +++ b/appc-adapters/appc-dmaap-adapter/appc-dmaap-adapter-bundle/src/main/java/org/openecomp/appc/adapter/messaging/dmaap/http/CommonHttpClient.java @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.appc.adapter.messaging.dmaap.http; + +import java.net.URI; + +import org.apache.commons.codec.binary.Base64; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.config.RequestConfig.Builder; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; + +public class CommonHttpClient { + + public static final int HTTPS_PORT = 3905; + + private String AUTH_STR; + + protected void setBasicAuth(String username, String password) { + if (username != null && password != null) { + String plain = String.format("%s:%s", username, password); + AUTH_STR = Base64.encodeBase64String(plain.getBytes()); + } else { + AUTH_STR = null; + } + } + + public HttpGet getReq(URI uri, int timeoutMs) throws Exception { + HttpGet out = (uri == null) ? new HttpGet() : new HttpGet(uri); + if (AUTH_STR != null) { + out.setHeader("Authorization", String.format("Basic %s", AUTH_STR)); + } + out.setConfig(getConfig(timeoutMs)); + return out; + } + + public HttpPost postReq(String url) throws Exception { + HttpPost out = (url == null) ? new HttpPost() : new HttpPost(url); + if (AUTH_STR != null) { + out.setHeader("Authorization", String.format("Basic %s", AUTH_STR)); + } + out.setConfig(getConfig(0)); + return out; + } + + private RequestConfig getConfig(int timeoutMs) { + Builder builder = RequestConfig.custom(); + builder.setSocketTimeout(timeoutMs + 5000); + return builder.build(); + } + + public CloseableHttpClient getClient() { + return getClient(false); + } + + public CloseableHttpClient getClient(boolean useHttps) { + return HttpClientBuilder.create().build(); + } + + public String formatHostString(String host) { + return formatHostString(host, host.contains(String.valueOf(HTTPS_PORT))); + } + + public String formatHostString(String host, boolean useHttps) { + // Trim trailing slash + String out = host.endsWith("/") ? host.substring(0, host.length() - 1) : host; + + boolean hasProto = out.startsWith("http"); + boolean hasPort = out.contains(":"); + + // Add protocol + if (!hasProto) { + out = String.format("%s%s", (useHttps) ? "https://" : "http://", out); + } + + // Add port + if (!hasPort) { + out = String.format("%s:%d", out, (useHttps) ? 3905 : 3904); + } + + return out; + + } +} diff --git a/appc-adapters/appc-dmaap-adapter/appc-dmaap-adapter-bundle/src/main/java/org/openecomp/appc/adapter/messaging/dmaap/http/HttpDmaapConsumerImpl.java b/appc-adapters/appc-dmaap-adapter/appc-dmaap-adapter-bundle/src/main/java/org/openecomp/appc/adapter/messaging/dmaap/http/HttpDmaapConsumerImpl.java new file mode 100644 index 000000000..2145eaa70 --- /dev/null +++ b/appc-adapters/appc-dmaap-adapter/appc-dmaap-adapter-bundle/src/main/java/org/openecomp/appc/adapter/messaging/dmaap/http/HttpDmaapConsumerImpl.java @@ -0,0 +1,164 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.appc.adapter.messaging.dmaap.http; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +import org.apache.http.HttpEntity; +import org.apache.http.NameValuePair; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.json.JSONArray; +import org.openecomp.appc.adapter.message.Consumer; + +public class HttpDmaapConsumerImpl extends CommonHttpClient implements Consumer { + + private static final EELFLogger LOG = EELFManager.getInstance().getLogger(HttpDmaapConsumerImpl.class); + + // Default values + private static final int DEFAULT_TIMEOUT_MS = 15000; + private static final int DEFAULT_LIMIT = 1000; + private static final String HTTPS_PORT = ":3905"; + private static final String URL_TEMPLATE = "%s/events/%s/%s/%s"; + + private List<String> urls; + private String filter; + + private boolean useHttps = false; + + public HttpDmaapConsumerImpl(Collection<String> hosts, String topicName, String consumerName, String consumerId) { + this(hosts, topicName, consumerName, consumerId, null); + } + + public HttpDmaapConsumerImpl(Collection<String> hosts, String topicName, String consumerName, String consumerId, + String filter) { + this(hosts, topicName, consumerName, consumerId, filter, null, null); + } + + public HttpDmaapConsumerImpl(Collection<String> hosts, String topicName, String consumerName, String consumerId, + String filter, String user, String password) { + urls = new ArrayList<String>(); + for (String host : hosts) { + urls.add(String.format(URL_TEMPLATE, formatHostString(host), topicName, consumerName, consumerId)); + } + this.filter = filter; + updateCredentials(user, password); + } + + @Override + public void updateCredentials(String user, String pass) { + LOG.debug(String.format("Setting auth to %s for %s", user, this.toString())); + this.setBasicAuth(user, pass); + } + + @Override + public List<String> fetch(int waitMs, int limit) { + LOG.debug(String.format("Fetching up to %d records with %dms wait on %s", limit, waitMs, this.toString())); + List<String> out = new ArrayList<String>(); + try { + List<NameValuePair> urlParams = new ArrayList<NameValuePair>(); + urlParams.add(new BasicNameValuePair("timeout", String.valueOf(waitMs))); + urlParams.add(new BasicNameValuePair("limit", String.valueOf(limit))); + if (filter != null) { + urlParams.add(new BasicNameValuePair("filter", filter)); + } + + URIBuilder builder = new URIBuilder(urls.get(0)); + builder.setParameters(urlParams); + + URI uri = builder.build(); + LOG.info(String.format("GET %s", uri)); + HttpGet request = getReq(uri, waitMs); + CloseableHttpResponse response = getClient().execute(request); + + int httpStatus = response.getStatusLine().getStatusCode(); + HttpEntity entity = response.getEntity(); + String body = (entity != null) ? EntityUtils.toString(entity) : null; + + LOG.debug(String.format("Request to %s completed with status %d and a body size of %s", uri, httpStatus, + (body != null ? body.length() : "null"))); + + response.close(); + if (httpStatus == 200 && body != null) { + JSONArray json = new JSONArray(body); + LOG.info(String.format("Got %d messages from DMaaP", json.length())); + for (int i = 0; i < json.length(); i++) { + out.add(json.getString(i)); + } + } else { + LOG.error(String.format("Did not get 200 from DMaaP. Got %d - %s", httpStatus, body)); + sleep(waitMs); + } + } catch (Exception e) { + if (urls.size() > 1) { + String failedUrl = urls.remove(0); + urls.add(failedUrl); + LOG.debug(String.format("Moving host %s to the end of the pool. New primary host is %s", failedUrl, + urls.get(0))); + } + LOG.error(String.format("Got exception while querying DMaaP. Message: %s", e.getMessage()), e); + sleep(waitMs); + } + + return out; + } + + @Override + public List<String> fetch() { + return fetch(DEFAULT_TIMEOUT_MS, DEFAULT_LIMIT); + } + + @Override + public String toString() { + String hostStr = (urls == null && !urls.isEmpty()) ? "N/A" : urls.get(0); + return String.format("Consumer listening to [%s]", hostStr); + } + + @Override + public void useHttps(boolean yes) { + useHttps = yes; + } + + private void sleep(int ms) { + LOG.info(String.format("Sleeping for %ds after failed request", ms / 1000)); + try { + Thread.sleep(ms); + } catch (InterruptedException e1) { + LOG.error("Interrupted while sleeping"); + } + } + + @Override + public void close() { + // Nothing to do + } + +} diff --git a/appc-adapters/appc-dmaap-adapter/appc-dmaap-adapter-bundle/src/main/java/org/openecomp/appc/adapter/messaging/dmaap/http/HttpDmaapProducerImpl.java b/appc-adapters/appc-dmaap-adapter/appc-dmaap-adapter-bundle/src/main/java/org/openecomp/appc/adapter/messaging/dmaap/http/HttpDmaapProducerImpl.java new file mode 100644 index 000000000..85e446dca --- /dev/null +++ b/appc-adapters/appc-dmaap-adapter/appc-dmaap-adapter-bundle/src/main/java/org/openecomp/appc/adapter/messaging/dmaap/http/HttpDmaapProducerImpl.java @@ -0,0 +1,135 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : APP-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.appc.adapter.messaging.dmaap.http; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.openecomp.appc.adapter.message.Producer; + +public class HttpDmaapProducerImpl extends CommonHttpClient implements Producer { + + private static final EELFLogger LOG = EELFManager.getInstance().getLogger(HttpDmaapProducerImpl.class); + + private static final String CONTENT_TYPE = "application/cambria"; + private static final String URL_TEMPLATE = "%s/events/%s"; + + private List<String> hosts; + private Set<String> topics; + + private boolean useHttps = false; + + public HttpDmaapProducerImpl(Collection<String> urls, String topicName) { + hosts = new ArrayList<String>(); + topics = new HashSet<String>(); + topics.add(topicName); + + for (String host : urls) { + hosts.add(formatHostString(host)); + } + } + + public HttpDmaapProducerImpl(Collection<String> urls, Set<String> topicNames) { + hosts = new ArrayList<String>(); + topics = topicNames; + + for (String host : urls) { + hosts.add(formatHostString(host)); + } + } + + @Override + public void updateCredentials(String user, String pass) { + LOG.debug(String.format("Setting auth to %s for %s", user, this.toString())); + this.setBasicAuth(user, pass); + } + + @Override + public boolean post(String partition, String data) { + int sent = 0; + try { + HttpPost request = postReq(null); + request.setHeader("Content-Type", CONTENT_TYPE); + request.setEntity(new StringEntity(bodyLine(partition, data))); + + for (String topic : topics) { + String uriStr = String.format(URL_TEMPLATE, hosts.get(0), topic); + try { + request.setURI(new URI(uriStr)); + CloseableHttpResponse response = getClient().execute(request); + if (response.getStatusLine().getStatusCode() == 200) { + sent++; + } + response.close(); + } catch (Exception sendEx) { + LOG.error(String.format("Failed to send message to %s. Reason: %s", uriStr, sendEx.getMessage()), + sendEx); + if (hosts.size() > 1) { + String failedUrl = hosts.remove(0); + hosts.add(failedUrl); + LOG.debug(String.format("Moving host %s to the end of the pool. New primary host is %s", + failedUrl, hosts.get(0))); + } + } + } + } catch (Exception buildEx) { + LOG.error( + String.format("Failed to build request with string [%s]. Message not sent to any topic. Reason: %s", + data, buildEx.getMessage()), + buildEx); + } + return sent == topics.size(); + } + + @Override + public void useHttps(boolean yes) { + useHttps = yes; + } + + /** + * Format the body for the application/cambria content type with no partitioning. + * + * @param msg + * The message body to format + * @return A string in the application/cambria content type + */ + private String bodyLine(String partition, String msg) { + String p = (partition == null) ? "" : partition; + String m = (msg == null) ? "" : msg; + return String.format("%d.%d.%s%s", p.length(), m.length(), p, m); + } + + @Override + public void close() { + // Nothing to do + } +} |