summaryrefslogtreecommitdiffstats
path: root/dcae-analytics/dcae-analytics-web/src/main/java
diff options
context:
space:
mode:
authorSingla, Rajiv (rs153v) <rs153v@att.com>2018-08-15 11:46:10 -0400
committerSingla, Rajiv (rs153v) <rs153v@att.com>2018-08-16 11:09:15 -0400
commit7a2c23b3ad83eab0eed5b990c70a1603447d5ee5 (patch)
tree24293333fd3cc566c1d77f9c9eedeb034dce9c6c /dcae-analytics/dcae-analytics-web/src/main/java
parent9650bd18f6b88721628ebedac2575b44e1b0028e (diff)
Standalone TCA with EELF Logger
Issue-ID: DCAEGEN2-633 Change-Id: I4da76b532021c0d6248455e7bd6e77f4614c35a7 Signed-off-by: Singla, Rajiv (rs153v) <rs153v@att.com>
Diffstat (limited to 'dcae-analytics/dcae-analytics-web/src/main/java')
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/AnalyticsWebConfig.java33
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/DmaapMrConfig.java159
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/DmaapPollerConfig.java79
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/DmaapRetryConfig.java120
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/MessageStoreConfig.java52
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrMessageSplitter.java188
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrPublisherPreferences.java59
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrSubscriberPollingAdvice.java148
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrSubscriberPollingPreferences.java46
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrSubscriberPreferences.java100
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrTriggerMessageProvider.java72
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/exception/AnalyticsParsingException.java33
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/exception/AnalyticsValidationException.java32
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/http/BaseHttpClientPreferences.java80
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/http/EelfAuditLogInterceptor.java206
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/http/HttpClientPreferences.java50
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/http/HttpClientPreferencesCustomizer.java277
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/mongo/MongoProfileCondition.java54
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/spring/ConfigBindingServiceEnvironmentPostProcessor.java148
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/spring/MongoAutoConfigurationPostProcessor.java95
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/util/AnalyticsHttpUtils.java124
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/util/AnalyticsWebUtils.java42
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/util/ValidationUtils.java108
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/util/function/MrSubscriberURLFunction.java106
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/validation/AnalyticsValidator.java39
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/validation/GenericValidationResponse.java80
-rw-r--r--dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/validation/ValidationResponse.java88
27 files changed, 2618 insertions, 0 deletions
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/AnalyticsWebConfig.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/AnalyticsWebConfig.java
new file mode 100644
index 0000000..a3863f5
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/AnalyticsWebConfig.java
@@ -0,0 +1,33 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+/**
+ * @author Rajiv Singla
+ */
+@Configuration
+@Import(DmaapMrConfig.class)
+public class AnalyticsWebConfig {
+
+
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/DmaapMrConfig.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/DmaapMrConfig.java
new file mode 100644
index 0000000..97fdcc5
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/DmaapMrConfig.java
@@ -0,0 +1,159 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.util.Map;
+
+import org.onap.dcae.analytics.model.AnalyticsHttpConstants;
+import org.onap.dcae.analytics.model.AnalyticsProfile;
+import org.onap.dcae.analytics.model.DmaapMrConstants;
+import org.onap.dcae.analytics.web.dmaap.MrMessageSplitter;
+import org.onap.dcae.analytics.web.dmaap.MrPublisherPreferences;
+import org.onap.dcae.analytics.web.dmaap.MrSubscriberPollingAdvice;
+import org.onap.dcae.analytics.web.dmaap.MrSubscriberPreferences;
+import org.onap.dcae.analytics.web.dmaap.MrTriggerMessageProvider;
+import org.onap.dcae.analytics.web.http.HttpClientPreferencesCustomizer;
+import org.onap.dcae.analytics.web.util.AnalyticsWebUtils;
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.context.annotation.Profile;
+import org.springframework.http.HttpMethod;
+import org.springframework.integration.channel.DirectChannel;
+import org.springframework.integration.channel.QueueChannel;
+import org.springframework.integration.core.MessageSource;
+import org.springframework.integration.dsl.IntegrationFlow;
+import org.springframework.integration.dsl.IntegrationFlows;
+import org.springframework.integration.dsl.channel.MessageChannels;
+import org.springframework.integration.endpoint.MethodInvokingMessageSource;
+import org.springframework.integration.handler.advice.RequestHandlerRetryAdvice;
+import org.springframework.integration.http.dsl.Http;
+import org.springframework.integration.scheduling.PollerMetadata;
+import org.springframework.integration.store.BasicMessageGroupStore;
+import org.springframework.integration.store.MessageGroupQueue;
+import org.springframework.integration.support.MessageBuilder;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author Rajiv Singla
+ */
+@Configuration
+@Import(value = {DmaapPollerConfig.class, DmaapRetryConfig.class})
+@Profile(AnalyticsProfile.DMAAP_PROFILE_NAME)
+public class DmaapMrConfig {
+
+ private static final String[] DMAAP_MAPPED_REQUEST_HEADERS =
+ DmaapMrConstants.DMAAP_MAPPED_HEADERS.toArray(new String[DmaapMrConstants.DMAAP_MAPPED_HEADERS.size()]);
+
+ @Bean(name = DmaapMrConstants.DMAAP_MR_SUBSCRIBER_OUTPUT_CHANNEL_NAME)
+ public QueueChannel mrSubscriberOutputChannel(final BasicMessageGroupStore basicMessageGroupStore) {
+ return MessageChannels.queue(new MessageGroupQueue(basicMessageGroupStore,
+ DmaapMrConstants.DMAAP_MR_SUBSCRIBER_OUTPUT_MESSAGE_STORE_GROUP_ID)).get();
+ }
+
+ @Bean(name = DmaapMrConstants.DMAAP_MR_PUBLISHER_INPUT_CHANNEL)
+ public DirectChannel mrPublisherInputChannel() {
+ return MessageChannels.direct().get();
+ }
+
+
+ @Bean
+ public RestTemplate mrSubscriberRestTemplate(final MrSubscriberPreferences mrSubscriberPreferences,
+ final RestTemplateBuilder restTemplateBuilder) {
+ return restTemplateBuilder
+ .additionalCustomizers(new HttpClientPreferencesCustomizer<>(mrSubscriberPreferences))
+ .build();
+ }
+
+ @Bean
+ public RestTemplate mrPublisherRestTemplate(final MrPublisherPreferences mrPublisherPreferences,
+ final RestTemplateBuilder restTemplateBuilder) {
+ return restTemplateBuilder
+ .additionalCustomizers(new HttpClientPreferencesCustomizer<>(mrPublisherPreferences))
+ .build();
+ }
+
+ @Bean
+ public MrMessageSplitter mrMessageSplitter(final ObjectMapper objectMapper,
+ final Integer processingBatchSize) {
+ final Integer batchSize = processingBatchSize != null ? processingBatchSize :
+ DmaapMrConstants.SUBSCRIBER_DEFAULT_PROCESSING_BATCH_SIZE;
+ return new MrMessageSplitter(objectMapper, batchSize);
+ }
+
+
+ @Bean
+ public MrTriggerMessageProvider mrTriggerMessageProvider(
+ final MrSubscriberPreferences mrSubscriberPreferences) {
+ return new MrTriggerMessageProvider(mrSubscriberPreferences);
+ }
+
+ @Bean
+ public MessageSource mrMessageSource(final MrTriggerMessageProvider mrTriggerMessageProvider) {
+ final MethodInvokingMessageSource source = new MethodInvokingMessageSource();
+ source.setObject(mrTriggerMessageProvider);
+ source.setMethodName(MrTriggerMessageProvider.TRIGGER_METHOD_NAME);
+ return source;
+ }
+
+ @Bean
+ public IntegrationFlow mrSubscriberFlow(final PollerMetadata pollerMetadata,
+ final RestTemplate mrSubscriberRestTemplate,
+ final MessageSource mrMessageSource,
+ final QueueChannel mrSubscriberOutputChannel,
+ final MrMessageSplitter mrMessageSplitter,
+ final MrSubscriberPollingAdvice mrSubscriberPollingAdvice) {
+ return IntegrationFlows.from(mrMessageSource, c -> c.poller(pollerMetadata))
+ .handle(Http.outboundGateway(m -> String.class.cast(m.getPayload()), mrSubscriberRestTemplate)
+ .mappedRequestHeaders(DMAAP_MAPPED_REQUEST_HEADERS)
+ .httpMethod(HttpMethod.GET)
+ .expectedResponseType(String.class), c -> c.advice(mrSubscriberPollingAdvice))
+ .split(mrMessageSplitter)
+ .channel(mrSubscriberOutputChannel)
+ .get();
+ }
+
+
+ @Bean
+ public IntegrationFlow mrPublisherFlow(final MrPublisherPreferences mrPublisherPreferences,
+ final RestTemplate mrPublisherRestTemplate,
+ final DirectChannel mrPublisherInputChannel,
+ final RequestHandlerRetryAdvice requestHandlerRetryAdvice) {
+
+ return IntegrationFlows.from(mrPublisherInputChannel)
+ .handle(Http.outboundGateway(mrPublisherPreferences.getRequestURL(), mrPublisherRestTemplate)
+ .mappedRequestHeaders(DMAAP_MAPPED_REQUEST_HEADERS)
+ .httpMethod(HttpMethod.POST)
+ .extractPayload(true)
+ .expectedResponseType(String.class), c -> c.advice(requestHandlerRetryAdvice))
+ // add end timestamp
+ .handle((String p, Map<String, Object> headers) ->
+ MessageBuilder.withPayload(p).copyHeaders(headers)
+ .setHeader(AnalyticsHttpConstants.REQUEST_END_TS_HEADER_KEY,
+ AnalyticsWebUtils.CREATION_TIMESTAMP_SUPPLIER.get()).build()
+ )
+ .channel(DmaapMrConstants.DMAAP_MR_PUBLISHER_OUTPUT_CHANNEL)
+ .get();
+ }
+
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/DmaapPollerConfig.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/DmaapPollerConfig.java
new file mode 100644
index 0000000..ab85d5f
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/DmaapPollerConfig.java
@@ -0,0 +1,79 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.config;
+
+import java.util.concurrent.TimeUnit;
+
+import org.onap.dcae.analytics.model.AnalyticsProfile;
+import org.onap.dcae.analytics.web.dmaap.MrSubscriberPollingAdvice;
+import org.onap.dcae.analytics.web.dmaap.MrSubscriberPollingPreferences;
+import org.onap.dcae.analytics.web.dmaap.MrSubscriberPreferences;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.integration.scheduling.PollerMetadata;
+import org.springframework.integration.util.DynamicPeriodicTrigger;
+import org.springframework.scheduling.support.PeriodicTrigger;
+
+/**
+ * @author Rajiv Singla
+ */
+@Configuration
+@Profile(AnalyticsProfile.DMAAP_PROFILE_NAME)
+public class DmaapPollerConfig {
+
+ @Bean
+ public MrSubscriberPollingAdvice mrSubscriberPollingAdvice(final DynamicPeriodicTrigger dynamicPeriodicTrigger,
+ final MrSubscriberPreferences mrSubscriberPreferences) {
+ final MrSubscriberPollingPreferences pollingPreferences = mrSubscriberPreferences.getPollingPreferences();
+ final int minInterval = pollingPreferences.getMinPollingInterval();
+ final int stepUpDelta = pollingPreferences.getStepUpDelta();
+ final int maxInterval = pollingPreferences.getMaxPollingInterval();
+ final int stepDownDelta = pollingPreferences.getStepDownDelta();
+ return new MrSubscriberPollingAdvice(dynamicPeriodicTrigger, minInterval,
+ stepUpDelta, maxInterval, stepDownDelta);
+ }
+
+ @Bean
+ public DynamicPeriodicTrigger dynamicPeriodicTrigger(final MrSubscriberPreferences mrSubscriberPreferences) {
+ final MrSubscriberPollingPreferences pollingPreferences = mrSubscriberPreferences.getPollingPreferences();
+ final int minInterval = pollingPreferences.getMinPollingInterval();
+ final DynamicPeriodicTrigger dynamicPeriodicTrigger =
+ new DynamicPeriodicTrigger(minInterval, TimeUnit.MILLISECONDS);
+ dynamicPeriodicTrigger.setFixedRate(true);
+ return dynamicPeriodicTrigger;
+ }
+
+ @Bean
+ public PollerMetadata pollerMetadata(final DynamicPeriodicTrigger dynamicPeriodicTrigger) {
+ final PollerMetadata pollerMetadata = new PollerMetadata();
+ pollerMetadata.setTrigger(dynamicPeriodicTrigger);
+ return pollerMetadata;
+ }
+
+
+ @Bean(name = PollerMetadata.DEFAULT_POLLER)
+ public PollerMetadata defaultPoller() {
+ PollerMetadata pollerMetadata = new PollerMetadata();
+ pollerMetadata.setTrigger(new PeriodicTrigger(1000));
+ return pollerMetadata;
+ }
+
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/DmaapRetryConfig.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/DmaapRetryConfig.java
new file mode 100644
index 0000000..48f0144
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/DmaapRetryConfig.java
@@ -0,0 +1,120 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.config;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.onap.dcae.analytics.model.AnalyticsProfile;
+import org.onap.dcae.analytics.model.DmaapMrConstants;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.context.annotation.Profile;
+import org.springframework.integration.channel.QueueChannel;
+import org.springframework.integration.dsl.IntegrationFlow;
+import org.springframework.integration.dsl.IntegrationFlows;
+import org.springframework.integration.dsl.channel.MessageChannels;
+import org.springframework.integration.handler.LoggingHandler;
+import org.springframework.integration.handler.advice.ErrorMessageSendingRecoverer;
+import org.springframework.integration.handler.advice.RequestHandlerRetryAdvice;
+import org.springframework.integration.store.BasicMessageGroupStore;
+import org.springframework.integration.store.MessageGroupQueue;
+import org.springframework.messaging.MessageHandlingException;
+import org.springframework.messaging.PollableChannel;
+import org.springframework.retry.RetryPolicy;
+import org.springframework.retry.backoff.BackOffPolicy;
+import org.springframework.retry.backoff.ExponentialBackOffPolicy;
+import org.springframework.retry.policy.SimpleRetryPolicy;
+import org.springframework.retry.support.RetryTemplate;
+import org.springframework.web.client.HttpStatusCodeException;
+import org.springframework.web.client.RestClientException;
+
+/**
+ * @author Rajiv Singla
+ */
+@Configuration
+@Profile(AnalyticsProfile.DMAAP_PROFILE_NAME)
+@Import(MessageStoreConfig.class)
+public class DmaapRetryConfig {
+
+ @Bean
+ public QueueChannel errorChannel() {
+ return MessageChannels.queue().get();
+ }
+
+ @Bean
+ public IntegrationFlow loggingFlow() {
+ return IntegrationFlows.from(errorChannel())
+ .log(LoggingHandler.Level.ERROR)
+ .get();
+ }
+
+ @Bean
+ public ErrorMessageSendingRecoverer errorMessageSendingRecoverer(final PollableChannel recoveryChannel) {
+ final ErrorMessageSendingRecoverer errorMessageSendingRecoverer = new ErrorMessageSendingRecoverer();
+ errorMessageSendingRecoverer.setChannel(recoveryChannel);
+ return errorMessageSendingRecoverer;
+ }
+
+ @Bean
+ public PollableChannel recoveryChannel(final BasicMessageGroupStore basicMessageGroupStore) {
+ return MessageChannels.queue(new MessageGroupQueue(basicMessageGroupStore,
+ DmaapMrConstants.DMAAP_MR_PUBLISHER_RECOVERY_MESSAGE_STORE_GROUP_ID)).get();
+ }
+
+ @Bean
+ public RequestHandlerRetryAdvice requestHandlerRetryAdvice(final RetryTemplate retryTemplate,
+ final ErrorMessageSendingRecoverer
+ errorMessageSendingRecoverer) {
+ final RequestHandlerRetryAdvice requestHandlerRetryAdvice = new RequestHandlerRetryAdvice();
+ requestHandlerRetryAdvice.setRetryTemplate(retryTemplate);
+ requestHandlerRetryAdvice.setRecoveryCallback(errorMessageSendingRecoverer);
+ return requestHandlerRetryAdvice;
+ }
+
+ @Bean
+ public RetryTemplate retryTemplate(final RetryPolicy retryPolicy,
+ final BackOffPolicy backOffPolicy) {
+ final RetryTemplate retryTemplate = new RetryTemplate();
+ retryTemplate.setRetryPolicy(retryPolicy);
+ retryTemplate.setBackOffPolicy(backOffPolicy);
+ return retryTemplate;
+ }
+
+ @Bean
+ public RetryPolicy retryPolicy() {
+ final Map<Class<? extends Throwable>, Boolean> retryableExceptions = new LinkedHashMap<>();
+ retryableExceptions.put(MessageHandlingException.class, true);
+ retryableExceptions.put(HttpStatusCodeException.class, true);
+ retryableExceptions.put(RestClientException.class, true);
+ return new SimpleRetryPolicy(DmaapMrConstants.DEFAULT_NUM_OF_RETRIES_ON_FAILURE, retryableExceptions);
+ }
+
+ @Bean
+ public BackOffPolicy backOffPolicy() {
+ final ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
+ backOffPolicy.setInitialInterval(DmaapMrConstants.DEFAULT_RETRY_INITIAL_INTERVAL);
+ backOffPolicy.setMultiplier(DmaapMrConstants.DEFAULT_RETRY_MULTIPLIER);
+ backOffPolicy.setMaxInterval(DmaapMrConstants.DEFAULT_RETRY_MAX_INTERVAL);
+ return backOffPolicy;
+ }
+
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/MessageStoreConfig.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/MessageStoreConfig.java
new file mode 100644
index 0000000..aa1c502
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/config/MessageStoreConfig.java
@@ -0,0 +1,52 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.config;
+
+import org.onap.dcae.analytics.model.AnalyticsProfile;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.data.mongodb.MongoDbFactory;
+import org.springframework.integration.mongodb.store.MongoDbChannelMessageStore;
+import org.springframework.integration.store.BasicMessageGroupStore;
+import org.springframework.integration.store.SimpleMessageStore;
+
+/**
+ * @author Rajiv Singla
+ */
+@Configuration
+@Profile(AnalyticsProfile.DMAAP_PROFILE_NAME)
+public class MessageStoreConfig {
+
+ @Bean
+ @Profile(AnalyticsProfile.NOT_MONGO_PROFILE_NAME)
+ public BasicMessageGroupStore simpleMessageGroupStore() {
+ return new SimpleMessageStore();
+ }
+
+ @Bean
+ @Profile(AnalyticsProfile.MONGO_PROFILE_NAME)
+ public BasicMessageGroupStore mongoMessageGroupStore(final MongoDbFactory mongoDbFactory) {
+ final MongoDbChannelMessageStore store = new MongoDbChannelMessageStore(mongoDbFactory);
+ store.setPriorityEnabled(true);
+ return store;
+ }
+
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrMessageSplitter.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrMessageSplitter.java
new file mode 100644
index 0000000..fe8f7ed
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrMessageSplitter.java
@@ -0,0 +1,188 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.dmaap;
+
+import static org.apache.commons.text.StringEscapeUtils.unescapeJava;
+import static org.apache.commons.text.StringEscapeUtils.unescapeJson;
+import static org.onap.dcae.analytics.model.AnalyticsHttpConstants.REQUEST_ID_HEADER_KEY;
+import static org.onap.dcae.analytics.model.AnalyticsModelConstants.ANALYTICS_REQUEST_ID_DELIMITER;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.IntStream;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.onap.dcae.analytics.model.DmaapMrConstants;
+import org.onap.dcae.analytics.web.exception.AnalyticsParsingException;
+import org.onap.dcae.analytics.web.util.AnalyticsHttpUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.integration.splitter.AbstractMessageSplitter;
+import org.springframework.integration.support.MessageBuilder;
+import org.springframework.messaging.Message;
+
+/**
+ * DMaaP MR message splitter split the incoming messages into batch of given batch size
+ *
+ * @author Rajiv Singla
+ */
+public class MrMessageSplitter extends AbstractMessageSplitter {
+
+ private static final Logger logger = LoggerFactory.getLogger(MrMessageSplitter.class);
+
+ private final ObjectMapper objectMapper;
+ private final Integer batchSize;
+
+ public MrMessageSplitter(@Nonnull final ObjectMapper objectMapper,
+ @Nonnull final Integer batchSize) {
+ this.objectMapper = objectMapper;
+ this.batchSize = batchSize;
+ }
+
+ @Override
+ protected Object splitMessage(final Message<?> message) {
+
+ final List<String> dmaapMessages = convertJsonToStringMessages(String.class.cast(message.getPayload()).trim());
+
+ final String requestId = AnalyticsHttpUtils.getRequestId(message.getHeaders());
+ final String transactionId = AnalyticsHttpUtils.getTransactionId(message.getHeaders());
+
+ logger.info("Request Id: {}, Transaction Id: {}, Received new messages from DMaaP MR. Count: {}",
+ requestId, transactionId, dmaapMessages.size());
+
+ final List<List<String>> messagePartitions = partition(dmaapMessages, batchSize);
+
+ logger.debug("Request Id: {}, Transaction Id: {}, Max allowed messages per batch: {}. " +
+ "No of batches created: {}", requestId, transactionId, batchSize, messagePartitions.size());
+
+ // append batch id to request id header
+ return messagePartitions.isEmpty() ? null : IntStream.range(0, messagePartitions.size())
+ .mapToObj(batchIndex ->
+ MessageBuilder
+ .withPayload(messagePartitions.get(0))
+ .copyHeaders(message.getHeaders())
+ .setHeader(REQUEST_ID_HEADER_KEY,
+ requestId + ANALYTICS_REQUEST_ID_DELIMITER + batchIndex)
+ .build()
+
+ );
+ }
+
+ /**
+ * Converts DMaaP MR subscriber messages json string to List of messages. If message Json String is empty
+ * or null
+ *
+ * @param messagesJsonString json messages String
+ *
+ * @return List containing DMaaP MR Messages
+ */
+ private List<String> convertJsonToStringMessages(@Nullable final String messagesJsonString) {
+
+ final LinkedList<String> messages = new LinkedList<>();
+
+ // If message string is not null or not empty parse json message array to List of string messages
+ if (messagesJsonString != null && !messagesJsonString.trim().isEmpty()
+ && !DmaapMrConstants.SUBSCRIBER_EMPTY_MESSAGE_RESPONSE_STRING.equals(messagesJsonString.trim())) {
+
+ try {
+ // get root node
+ final JsonNode rootNode = objectMapper.readTree(messagesJsonString);
+ // iterate over root node and parse arrays messages
+ for (JsonNode jsonNode : rootNode) {
+ // if array parse it is array of messages
+ final String incomingMessageString = jsonNode.toString();
+ if (jsonNode.isArray()) {
+ final List messageList = objectMapper.readValue(incomingMessageString, List.class);
+ for (Object message : messageList) {
+ final String jsonMessageString = objectMapper.writeValueAsString(message);
+ addUnescapedJsonToMessage(messages, jsonMessageString);
+ }
+ } else {
+ // parse it as object
+ addUnescapedJsonToMessage(messages, incomingMessageString);
+ }
+ }
+
+ } catch (IOException e) {
+ final String errorMessage = String.format("Unable to convert subscriber Json String to Messages. " +
+ "Subscriber Response String: %s, Json Error: %s", messagesJsonString, e);
+ logger.error(errorMessage, e);
+ throw new AnalyticsParsingException(errorMessage, e);
+ }
+
+ }
+ return messages;
+ }
+
+ /**
+ * Adds unescaped Json messages to given messages list
+ *
+ * @param messages message list in which unescaped messages will be added
+ * @param incomingMessageString incoming message string that may need to be escaped
+ */
+ private static void addUnescapedJsonToMessage(List<String> messages, String incomingMessageString) {
+ if (incomingMessageString.startsWith("\"") && incomingMessageString.endsWith("\"")) {
+ messages.add(unescapeJava(unescapeJson(
+ incomingMessageString.substring(1, incomingMessageString.length() - 1))));
+ } else {
+ messages.add(unescapeJava(unescapeJson(incomingMessageString)));
+ }
+ }
+
+ /**
+ * Partition list into multiple lists
+ *
+ * @param list input list that needs to be broken into chunks
+ * @param batchSize batch size for each list
+ * @param <E> element type of the list
+ *
+ * @return List containing list of entries of specified batch size
+ */
+ private static <E> List<List<E>> partition(List<E> list, final Integer batchSize) {
+
+ if (list == null || batchSize == null || batchSize <= 0 || list.size() < batchSize) {
+ return Collections.singletonList(list);
+ }
+
+ final List<List<E>> result = new LinkedList<>();
+
+ for (int i = 0; i < list.size(); i++) {
+
+ if (i == 0 || i % batchSize == 0) {
+ List<E> sublist = new LinkedList<>();
+ result.add(sublist);
+ }
+
+ final List<E> lastSubList = result.get(result.size() - 1);
+ lastSubList.add(list.get(i));
+
+ }
+ return result;
+ }
+
+
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrPublisherPreferences.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrPublisherPreferences.java
new file mode 100644
index 0000000..c37049d
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrPublisherPreferences.java
@@ -0,0 +1,59 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.dmaap;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+import java.net.URL;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.onap.dcae.analytics.web.http.BaseHttpClientPreferences;
+import org.springframework.http.HttpHeaders;
+
+/**
+ * @author Rajiv Singla
+ */
+@Getter
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class MrPublisherPreferences extends BaseHttpClientPreferences {
+
+ private static final long serialVersionUID = 1L;
+
+ public MrPublisherPreferences(@Nonnull final String requestURL) {
+ super(requestURL);
+ }
+
+ public MrPublisherPreferences(@Nonnull final String requestURL,
+ @Nullable final String httpClientId,
+ @Nullable final HttpHeaders httpHeaders,
+ @Nullable final String username,
+ @Nullable final String password,
+ @Nullable final URL proxyURL,
+ @Nullable final Boolean ignoreSSLValidation,
+ @Nullable final Boolean enableEcompAuditLogging) {
+ super(requestURL, httpClientId, httpHeaders, username, password, proxyURL,
+ ignoreSSLValidation, enableEcompAuditLogging);
+ }
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrSubscriberPollingAdvice.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrSubscriberPollingAdvice.java
new file mode 100644
index 0000000..33115c5
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrSubscriberPollingAdvice.java
@@ -0,0 +1,148 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.dmaap;
+
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.onap.dcae.analytics.model.AnalyticsHttpConstants;
+import org.onap.dcae.analytics.model.DmaapMrConstants;
+import org.onap.dcae.analytics.web.util.AnalyticsHttpUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
+import org.springframework.integration.support.MessageBuilder;
+import org.springframework.integration.util.DynamicPeriodicTrigger;
+import org.springframework.messaging.Message;
+
+/**
+ * A polling advice which can auto adjust polling intervals depending on DMaaP MR message availability.
+ * Can be configured to slow down polling when messages are not available and increase polling when messages are
+ * indeed available.
+ * <p>
+ * The next polling interval is <b>increased</b> by given step up delta if message is <b>not found</b> up to maximum
+ * Polling Interval
+ * <br>
+ * The next polling interval is <b>decreased</b> by step down delta if message <b>is found</b> up to minimum
+ * polling interval
+ *
+ * @author Rajiv Singla
+ */
+public class MrSubscriberPollingAdvice extends AbstractRequestHandlerAdvice {
+
+ private static final Logger log = LoggerFactory.getLogger(MrSubscriberPollingAdvice.class);
+
+ private final DynamicPeriodicTrigger trigger;
+ private final int minPollingInterval;
+ private final int stepUpPollingDelta;
+ private final int maxPollingInterval;
+ private final int stepDownPollingDelta;
+
+ private final AtomicInteger nextPollingInterval;
+
+ /**
+ * Creates variable polling intervals based on message availability.
+ *
+ * @param trigger Dynamic Trigger instance
+ * @param minPollingInterval Minimum polling interval
+ * @param stepUpPollingDelta Delta by which next polling interval will be increased when message is not found
+ * @param maxPollingInterval Maximum polling interval
+ * @param stepDownPollingDelta Delta by which next polling interval will be decreased when message is found
+ */
+ public MrSubscriberPollingAdvice(final DynamicPeriodicTrigger trigger,
+ final int minPollingInterval,
+ final int stepUpPollingDelta,
+ final int maxPollingInterval,
+ final int stepDownPollingDelta) {
+ this.trigger = trigger;
+ this.minPollingInterval = minPollingInterval;
+ this.stepUpPollingDelta = stepUpPollingDelta;
+ this.maxPollingInterval = maxPollingInterval;
+ this.stepDownPollingDelta = stepDownPollingDelta;
+ nextPollingInterval = new AtomicInteger(minPollingInterval);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected Object doInvoke(final ExecutionCallback callback, final Object target, final Message<?> message)
+ throws Exception {
+
+ // execute call back
+ Object result = callback.execute();
+
+ // if result is not of type message builder just return
+ if (!(result instanceof MessageBuilder)) {
+ return result;
+ }
+
+ final MessageBuilder<String> resultMessageBuilder = (MessageBuilder<String>) result;
+ final String payload = resultMessageBuilder.getPayload();
+ final Map<String, Object> headers = resultMessageBuilder.getHeaders();
+ final Object httpStatusCode = headers.get(AnalyticsHttpConstants.HTTP_STATUS_CODE_HEADER_KEY);
+
+ // get http status code
+ if (httpStatusCode == null) {
+ return result;
+ }
+ final HttpStatus httpStatus = HttpStatus.resolve(Integer.parseInt(httpStatusCode.toString()));
+
+
+ // if status code is present and successful apply polling adjustments
+ if (httpStatus != null && httpStatus.is2xxSuccessful()) {
+ final boolean areMessagesPresent = areMessagesPresent(payload);
+ updateNextPollingInterval(areMessagesPresent);
+
+ final String requestId = AnalyticsHttpUtils.getRequestId(message.getHeaders());
+ final String transactionId = AnalyticsHttpUtils.getTransactionId(message.getHeaders());
+
+ log.debug("Request Id: {}, Transaction Id: {}, Messages Present: {}, " +
+ "Next Polling Interval will be: {}", requestId, transactionId,
+ areMessagesPresent, nextPollingInterval);
+
+ trigger.setPeriod(nextPollingInterval.get());
+
+ // if no messages were found in dmaap poll - terminate further processing
+ if (!areMessagesPresent) {
+ log.info("Request Id: {}, Transaction Id: {}, No new messages found in DMaaP MR Response. " +
+ "No further processing required", requestId, transactionId);
+ return null;
+ }
+
+ }
+
+ return result;
+ }
+
+ private boolean areMessagesPresent(final String payload) {
+
+ return !(payload.isEmpty() || payload.equals(DmaapMrConstants.SUBSCRIBER_EMPTY_MESSAGE_RESPONSE_STRING));
+ }
+
+ private void updateNextPollingInterval(final boolean areMessagesPresent) {
+ if (areMessagesPresent) {
+ nextPollingInterval.getAndUpdate(interval -> interval - stepDownPollingDelta <= minPollingInterval ?
+ minPollingInterval : interval - stepDownPollingDelta);
+ } else {
+ nextPollingInterval.getAndUpdate(interval -> interval + stepUpPollingDelta >= maxPollingInterval ?
+ maxPollingInterval : interval + stepUpPollingDelta);
+ }
+ }
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrSubscriberPollingPreferences.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrSubscriberPollingPreferences.java
new file mode 100644
index 0000000..0fe662e
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrSubscriberPollingPreferences.java
@@ -0,0 +1,46 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.dmaap;
+
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+import java.io.Serializable;
+
+/**
+ * @author Rajiv Singla
+ */
+@Getter
+@ToString
+@AllArgsConstructor
+@EqualsAndHashCode
+public class MrSubscriberPollingPreferences implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private final int minPollingInterval;
+ private final int stepUpDelta;
+ private final int maxPollingInterval;
+ private final int stepDownDelta;
+
+
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrSubscriberPreferences.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrSubscriberPreferences.java
new file mode 100644
index 0000000..0590d83
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrSubscriberPreferences.java
@@ -0,0 +1,100 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.dmaap;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+import java.net.URL;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.onap.dcae.analytics.model.DmaapMrConstants;
+import org.onap.dcae.analytics.web.http.BaseHttpClientPreferences;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpHeaders;
+
+/**
+ * DMaaP MR Subscriber config
+ *
+ * @author Rajiv Singla
+ */
+@Getter
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class MrSubscriberPreferences extends BaseHttpClientPreferences {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final Logger logger = LoggerFactory.getLogger(MrSubscriberPreferences.class);
+
+ private String consumerGroup;
+ private List<String> consumerIds;
+ private Integer messageLimit;
+ private Integer timeout;
+ private MrSubscriberPollingPreferences pollingPreferences;
+
+ public MrSubscriberPreferences(@Nonnull final String requestURL) {
+ super(requestURL);
+ }
+
+ public MrSubscriberPreferences(@Nonnull final String requestURL,
+ @Nullable final String httpClientId,
+ @Nullable final HttpHeaders httpHeaders,
+ @Nullable final String username,
+ @Nullable final String password,
+ @Nullable final URL proxyURL,
+ @Nullable final Boolean ignoreSSLValidation,
+ @Nullable final Boolean enableEcompAuditLogging,
+ @Nullable final String consumerGroup,
+ @Nullable final List<String> consumerIds,
+ @Nullable final Integer messageLimit,
+ @Nullable final Integer timeout,
+ @Nullable final MrSubscriberPollingPreferences pollingPreferences) {
+ super(requestURL, httpClientId, httpHeaders, username, password, proxyURL,
+ ignoreSSLValidation, enableEcompAuditLogging);
+ this.consumerGroup = consumerGroup;
+ this.consumerIds = consumerIds;
+ this.messageLimit = messageLimit;
+ this.timeout = timeout;
+ this.pollingPreferences = pollingPreferences;
+ }
+
+
+ public MrSubscriberPollingPreferences getPollingPreferences() {
+ if (pollingPreferences == null) {
+ logger.warn("DMaaP MR Subscriber Polling details are missing. " +
+ "Fixed polling rate will be used by default with polling interval: {}",
+ DmaapMrConstants.SUBSCRIBER_DEFAULT_FIXED_POLLING_INTERVAL);
+ setFixedPollingRate(DmaapMrConstants.SUBSCRIBER_DEFAULT_FIXED_POLLING_INTERVAL);
+ }
+ return pollingPreferences;
+ }
+
+ private void setFixedPollingRate(final int fixedPollingInterval) {
+ this.pollingPreferences =
+ new MrSubscriberPollingPreferences(fixedPollingInterval, 0, fixedPollingInterval, 0);
+ }
+
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrTriggerMessageProvider.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrTriggerMessageProvider.java
new file mode 100644
index 0000000..183957d
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/dmaap/MrTriggerMessageProvider.java
@@ -0,0 +1,72 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.dmaap;
+
+
+import java.net.URL;
+import java.util.List;
+import java.util.function.Supplier;
+
+import org.onap.dcae.analytics.model.AnalyticsHttpConstants;
+import org.onap.dcae.analytics.model.util.supplier.UnboundedSupplier;
+import org.onap.dcae.analytics.web.util.AnalyticsWebUtils;
+import org.onap.dcae.analytics.web.util.function.MrSubscriberURLFunction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.integration.support.MessageBuilder;
+import org.springframework.messaging.Message;
+
+/**
+ * Provides DMaaP MR Subscriber Trigger Message
+ *
+ * @author Rajiv Singla
+ */
+public class MrTriggerMessageProvider {
+
+ private static final Logger logger = LoggerFactory.getLogger(MrTriggerMessageProvider.class);
+
+ public static final String TRIGGER_METHOD_NAME = "getTriggerMessage";
+
+ private final Supplier<URL> subscriberUrlSupplier;
+
+ public MrTriggerMessageProvider(final MrSubscriberPreferences subscriberPreferences) {
+ final List<URL> urls = new MrSubscriberURLFunction().apply(subscriberPreferences);
+ subscriberUrlSupplier = new UnboundedSupplier<>(urls.toArray(new URL[urls.size()]));
+ }
+
+ /**
+ * DMaaP MR subscriber trigger message
+ *
+ * @return dmaap mr subscriber trigger message
+ */
+ public Message<String> getTriggerMessage() {
+ final String requestId = AnalyticsWebUtils.REQUEST_ID_SUPPLIER.get();
+ final String transactionId = AnalyticsWebUtils.RANDOM_ID_SUPPLIER.get();
+ final String beginTimestamp = AnalyticsWebUtils.CREATION_TIMESTAMP_SUPPLIER.get();
+ logger.debug("Request Id: {}. Transaction Id: {}. Begin TS: {}. Starting new DMaaP MR Subscriber poll.",
+ requestId, transactionId, beginTimestamp);
+ return MessageBuilder
+ .withPayload(subscriberUrlSupplier.get().toString())
+ .setHeader(AnalyticsHttpConstants.REQUEST_ID_HEADER_KEY, requestId)
+ .setHeader(AnalyticsHttpConstants.REQUEST_TRANSACTION_ID_HEADER_KEY, transactionId)
+ .setHeader(AnalyticsHttpConstants.REQUEST_BEGIN_TS_HEADER_KEY, beginTimestamp)
+ .build();
+ }
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/exception/AnalyticsParsingException.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/exception/AnalyticsParsingException.java
new file mode 100644
index 0000000..1af40f2
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/exception/AnalyticsParsingException.java
@@ -0,0 +1,33 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.exception;
+
+/**
+ * @author Rajiv Singla
+ */
+public class AnalyticsParsingException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ public AnalyticsParsingException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/exception/AnalyticsValidationException.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/exception/AnalyticsValidationException.java
new file mode 100644
index 0000000..b59a2bd
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/exception/AnalyticsValidationException.java
@@ -0,0 +1,32 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.exception;
+
+/**
+ * @author Rajiv Singla
+ */
+public class AnalyticsValidationException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ public AnalyticsValidationException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/http/BaseHttpClientPreferences.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/http/BaseHttpClientPreferences.java
new file mode 100644
index 0000000..3799961
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/http/BaseHttpClientPreferences.java
@@ -0,0 +1,80 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.http;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+import java.net.URL;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.onap.dcae.analytics.model.AnalyticsHttpConstants;
+import org.onap.dcae.analytics.model.AnalyticsModelConstants;
+import org.onap.dcae.analytics.model.util.supplier.RandomIdSupplier;
+import org.springframework.http.HttpHeaders;
+
+/**
+ * Base implementation for {@link HttpClientPreferences}
+ *
+ * @author Rajiv Singla
+ */
+@Getter
+@ToString(exclude = "password")
+@EqualsAndHashCode
+public abstract class BaseHttpClientPreferences implements HttpClientPreferences {
+
+ protected String requestURL;
+ protected String httpClientId;
+ protected HttpHeaders requestHeaders;
+ protected String username;
+ protected String password;
+ protected URL proxyURL;
+ protected Boolean ignoreSSLValidation;
+ protected Boolean enableEcompAuditLogging;
+
+ public BaseHttpClientPreferences(@Nonnull final String requestURL) {
+ this.requestURL = requestURL;
+ }
+
+ public BaseHttpClientPreferences(@Nonnull final String requestURL,
+ @Nullable final String httpClientId,
+ @Nullable final HttpHeaders httpHeaders,
+ @Nullable final String username,
+ @Nullable final String password,
+ @Nullable final URL proxyURL,
+ @Nullable final Boolean ignoreSSLValidation,
+ @Nullable final Boolean enableEcompAuditLogging) {
+ this.requestURL = requestURL;
+ // create http client id if not present
+ this.httpClientId = httpClientId != null ? httpClientId :
+ AnalyticsHttpConstants.DEFAULT_HTTP_CLIENT_ID_PREFIX +
+ new RandomIdSupplier(AnalyticsModelConstants.DEFAULT_RANDOM_ID_LENGTH);
+ this.requestHeaders = httpHeaders;
+ this.username = username;
+ this.password = password;
+ this.proxyURL = proxyURL;
+ this.ignoreSSLValidation = ignoreSSLValidation != null && ignoreSSLValidation;
+ this.enableEcompAuditLogging = enableEcompAuditLogging != null && enableEcompAuditLogging;
+ }
+
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/http/EelfAuditLogInterceptor.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/http/EelfAuditLogInterceptor.java
new file mode 100644
index 0000000..54b5446
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/http/EelfAuditLogInterceptor.java
@@ -0,0 +1,206 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.http;
+
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.util.Date;
+import java.util.Locale;
+
+import org.onap.dcae.analytics.model.AnalyticsModelConstants;
+import org.onap.dcae.analytics.model.TcaModelConstants;
+import org.onap.dcae.analytics.model.ecomplogger.AnalyticsErrorType;
+import org.onap.dcae.analytics.web.util.AnalyticsHttpUtils;
+import org.onap.dcae.utils.eelf.logger.api.info.ResponseLogInfo;
+import org.onap.dcae.utils.eelf.logger.api.info.ServiceLogInfo;
+import org.onap.dcae.utils.eelf.logger.api.info.TargetServiceLogInfo;
+import org.onap.dcae.utils.eelf.logger.api.log.EELFLogFactory;
+import org.onap.dcae.utils.eelf.logger.api.log.EELFLogger;
+import org.onap.dcae.utils.eelf.logger.model.info.RequestIdLogInfoImpl;
+import org.onap.dcae.utils.eelf.logger.model.info.RequestTimingLogInfoImpl;
+import org.onap.dcae.utils.eelf.logger.model.info.ResponseLogInfoImpl;
+import org.onap.dcae.utils.eelf.logger.model.info.ServiceLogInfoImpl;
+import org.onap.dcae.utils.eelf.logger.model.info.TargetServiceLogInfoImpl;
+import org.onap.dcae.utils.eelf.logger.model.spec.MetricLogSpecImpl;
+import org.springframework.core.Ordered;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpRequest;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.client.AbstractClientHttpResponse;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.util.StreamUtils;
+
+/**
+ * Eelf Audit log interceptor is used to log ECOMP Audit Logging
+ *
+ * @author Rajiv Singla
+ */
+public class EelfAuditLogInterceptor implements ClientHttpRequestInterceptor, Ordered {
+
+ private static final EELFLogger logger = EELFLogFactory.getLogger(EelfAuditLogInterceptor.class);
+
+ private final ServiceLogInfo serviceLogInfo;
+ private final String targetEntityName;
+
+ public EelfAuditLogInterceptor(final HttpClientPreferences httpClientPreferences) {
+ this.serviceLogInfo = getServiceLogInfo(httpClientPreferences);
+ this.targetEntityName = getTargetEntityName(httpClientPreferences);
+ }
+
+ @Override
+ public ClientHttpResponse intercept(final HttpRequest request,
+ final byte[] body,
+ final ClientHttpRequestExecution execution) throws IOException {
+
+ final String requestId = AnalyticsHttpUtils.getRequestId(request.getHeaders());
+ final String transactionId = AnalyticsHttpUtils.getTransactionId(request.getHeaders());
+
+ ClientHttpResponse clientHttpResponse = null;
+ HttpStatus httpStatus = null;
+ String statusText = "";
+ String errorMessage = null;
+ final Date requestBeginTimeStamp = new Date();
+ try {
+ clientHttpResponse = execution.execute(request, body);
+ httpStatus = clientHttpResponse.getStatusCode();
+ if (httpStatus.is2xxSuccessful()) {
+ errorMessage = null;
+ statusText = clientHttpResponse.getStatusText();
+ } else {
+ errorMessage = StreamUtils.copyToString(clientHttpResponse.getBody(), Charset.defaultCharset());
+ statusText = clientHttpResponse.getStatusText();
+ }
+ } catch (IOException e) {
+ httpStatus = HttpStatus.SERVICE_UNAVAILABLE;
+ statusText = AnalyticsErrorType.TIMEOUT_ERROR.getErrorDescription();
+ errorMessage = e.toString();
+ }
+ final Date requestEndTimeStamp = new Date();
+ final long elapsedTime = requestEndTimeStamp.getTime() - requestBeginTimeStamp.getTime();
+ final RequestTimingLogInfoImpl requestTimingLogInfo = new RequestTimingLogInfoImpl(requestBeginTimeStamp,
+ requestEndTimeStamp, elapsedTime);
+ final MetricLogSpecImpl metricLogSpec = new MetricLogSpecImpl(new RequestIdLogInfoImpl(requestId),
+ serviceLogInfo, requestTimingLogInfo,
+ getResponseLogInfo(httpStatus, statusText), getTargetServiceLogInfo(request, targetEntityName));
+
+ if (errorMessage != null) {
+ logger.metricLog().error("Request Id: {}, Transaction Id: {}, Elapsed Time: {} ms, Error Message: {} ",
+ metricLogSpec, requestId, transactionId, Long.toString(elapsedTime), errorMessage);
+ } else {
+ logger.metricLog().info("Request Id: {}, Transaction Id: {}, Elapsed Time: {} ms, REST Endpoint Call: {}",
+ metricLogSpec, requestId, transactionId, Long.toString(elapsedTime),
+ statusText + "-" + getTargetService(request));
+ }
+
+ return clientHttpResponse != null ? clientHttpResponse : new SimpleClientHttpResponse();
+ }
+
+ @Override
+ public int getOrder() {
+ return LOWEST_PRECEDENCE;
+ }
+
+ private static ServiceLogInfo getServiceLogInfo(final HttpClientPreferences httpClientPreferences) {
+ return new ServiceLogInfoImpl(TcaModelConstants.TCA_SERVICE_NAME,
+ httpClientPreferences.getUsername(), "");
+ }
+
+ // translate well known http status code to corresponding Ecomp Logging error codes
+ private static ResponseLogInfo getResponseLogInfo(final HttpStatus httpStatus, final String statusText) {
+ if (httpStatus.is2xxSuccessful()) {
+ return new ResponseLogInfoImpl(AnalyticsErrorType.SUCCESSFUL.getErrorCode(), statusText);
+ } else if (httpStatus.is4xxClientError()) {
+ if (httpStatus == HttpStatus.UNAUTHORIZED || httpStatus == HttpStatus.FORBIDDEN) {
+ return new ResponseLogInfoImpl(AnalyticsErrorType.PERMISSION_ERROR.getErrorCode(), statusText);
+ }
+ return new ResponseLogInfoImpl(AnalyticsErrorType.DATA_ERROR.getErrorCode(), statusText);
+ } else if (httpStatus.is5xxServerError()) {
+ if (httpStatus == HttpStatus.SERVICE_UNAVAILABLE) {
+ return new ResponseLogInfoImpl(AnalyticsErrorType.TIMEOUT_ERROR.getErrorCode(), statusText);
+ }
+ return new ResponseLogInfoImpl(AnalyticsErrorType.BUSINESS_PROCESS_ERROR.getErrorCode(),
+ statusText);
+ }
+ return new ResponseLogInfoImpl(AnalyticsErrorType.UNKNOWN_ERROR.getErrorCode(), statusText);
+ }
+
+
+ private static TargetServiceLogInfo getTargetServiceLogInfo(final HttpRequest httpRequest,
+ final String targetEntityName) {
+ return new TargetServiceLogInfoImpl(targetEntityName, getTargetService(httpRequest),
+ getTargetVirtualEntity(httpRequest));
+ }
+
+ private static String getTargetVirtualEntity(final HttpRequest httpRequest) {
+ return httpRequest.getURI().getAuthority();
+ }
+
+ private static String getTargetService(final HttpRequest httpRequest) {
+ return httpRequest.getMethod() + "-" + httpRequest.getURI().getPath();
+ }
+
+ private static String getTargetEntityName(final HttpClientPreferences httpClientPreferences) {
+ final String simpleName = httpClientPreferences.getClass().getSimpleName().toUpperCase(Locale.getDefault());
+ if (simpleName.contains("MRSUB")) {
+ return "DMAAP_MR_SUBSCRIBER";
+ } else if (simpleName.contains("MRPUB")) {
+ return "DMAAP_MR_PUBLISHER";
+ } else if (simpleName.contains("AAI")) {
+ return "AAI_ENRICHMENT";
+ } else {
+ return "UNKNOWN";
+ }
+ }
+
+
+ private static class SimpleClientHttpResponse extends AbstractClientHttpResponse {
+ @Override
+ public int getRawStatusCode() throws IOException {
+ return HttpStatus.SERVICE_UNAVAILABLE.value();
+ }
+
+ @Override
+ public String getStatusText() throws IOException {
+ return HttpStatus.SERVICE_UNAVAILABLE.getReasonPhrase();
+ }
+
+ @Override
+ public void close() {
+ // do nothing
+ }
+
+ @Override
+ public InputStream getBody() throws IOException {
+ return new ByteArrayInputStream("".getBytes(Charset.forName(AnalyticsModelConstants.UTF8_CHARSET_NAME)));
+ }
+
+ @Override
+ public HttpHeaders getHeaders() {
+ return new HttpHeaders();
+ }
+ }
+
+
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/http/HttpClientPreferences.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/http/HttpClientPreferences.java
new file mode 100644
index 0000000..34d0124
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/http/HttpClientPreferences.java
@@ -0,0 +1,50 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.http;
+
+import java.io.Serializable;
+import java.net.URL;
+
+import org.springframework.http.HttpHeaders;
+
+/**
+ * DCAE Analytics HTTP Client Preferences
+ *
+ * @author Rajiv Singla
+ */
+public interface HttpClientPreferences extends Serializable {
+
+ String getRequestURL();
+
+ String getHttpClientId();
+
+ HttpHeaders getRequestHeaders();
+
+ String getUsername();
+
+ String getPassword();
+
+ URL getProxyURL();
+
+ Boolean getIgnoreSSLValidation();
+
+ Boolean getEnableEcompAuditLogging();
+
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/http/HttpClientPreferencesCustomizer.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/http/HttpClientPreferencesCustomizer.java
new file mode 100644
index 0000000..c5f66be
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/http/HttpClientPreferencesCustomizer.java
@@ -0,0 +1,277 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.http;
+
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.http.HttpHost;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.TrustStrategy;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.onap.dcae.analytics.model.AnalyticsHttpConstants;
+import org.onap.dcae.analytics.model.util.function.StringToURLFunction;
+import org.onap.dcae.analytics.web.util.AnalyticsWebUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.web.client.RestTemplateCustomizer;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpRequest;
+import org.springframework.http.client.BufferingClientHttpRequestFactory;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.http.client.support.BasicAuthorizationInterceptor;
+import org.springframework.util.ReflectionUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.DefaultUriBuilderFactory;
+
+/**
+ * Creates a {@link RestTemplateCustomizer} which can be used to configure the spring rest templates
+ * based on given {@link HttpClientPreferences}
+ *
+ * @param <T> Http Client Configurations
+ *
+ * @author Rajiv Singla
+ */
+public class HttpClientPreferencesCustomizer<T extends HttpClientPreferences> implements RestTemplateCustomizer {
+
+ private static final Logger logger = LoggerFactory.getLogger(HttpClientPreferencesCustomizer.class);
+
+ private final T httpClientConfig;
+
+ public HttpClientPreferencesCustomizer(final T httpClientConfig) {
+ this.httpClientConfig = httpClientConfig;
+ }
+
+ @Override
+ public void customize(final RestTemplate restTemplate) {
+
+ final String httpClientId = httpClientConfig.getHttpClientId() != null ? httpClientConfig.getHttpClientId()
+ : AnalyticsHttpConstants.DEFAULT_HTTP_CLIENT_ID_PREFIX + AnalyticsWebUtils.RANDOM_ID_SUPPLIER.get();
+ logger.debug("Customizing Rest Template for Http Client Id: {}", httpClientId);
+
+ // set request url
+ final URL requestURL = new StringToURLFunction().apply(httpClientConfig.getRequestURL())
+ .orElseThrow(() -> new IllegalArgumentException("Http Client URL is required"));
+ restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(requestURL.toString()));
+
+ // add basic authentication headers
+ final String username = httpClientConfig.getUsername();
+ if (username != null) {
+ restTemplate.getInterceptors().add(
+ new BasicAuthorizationInterceptor(username, httpClientConfig.getPassword()));
+ }
+
+ // set default request headers
+ final HttpHeaders defaultRequestHeaders = httpClientConfig.getRequestHeaders();
+ if (defaultRequestHeaders != null) {
+ restTemplate.getInterceptors().add(new DefaultHeadersRequestInterceptor(defaultRequestHeaders));
+ }
+
+ // create new http client builder
+ final HttpClientBuilder httpClientBuilder = HttpClients.custom().useSystemProperties()
+ .disableContentCompression();
+ final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+
+ // set basic authentication credentials
+ configureAuthenticationCredentials(httpClientId, requestURL, credentialsProvider);
+ // set up proxy url
+ configureProxySettings(httpClientId, httpClientBuilder, credentialsProvider);
+ // setup credentials provider
+ httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
+ // set up ssl Context
+ configureSSLContext(httpClientId, httpClientBuilder);
+
+ // set rest client builder
+ final HttpComponentsClientHttpRequestFactory httpRequestFactory =
+ new HttpComponentsClientHttpRequestFactory(httpClientBuilder.build());
+
+ // set ecomp logging interceptor
+ if (httpClientConfig.getEnableEcompAuditLogging()) {
+ restTemplate.getInterceptors().add(new EelfAuditLogInterceptor(httpClientConfig));
+ }
+
+ restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(httpRequestFactory));
+ }
+
+ /**
+ * Configures authentication credentials
+ *
+ * @param httpClientId http client id
+ * @param requestURL request url
+ * @param credentialsProvider credentials provider
+ */
+ private void configureAuthenticationCredentials(final String httpClientId, final URL requestURL,
+ final CredentialsProvider credentialsProvider) {
+ final String username = httpClientConfig.getUsername();
+ if (username != null) {
+ logger.info("Setting basic Authentication credentials for Http Client Id: {} with username: {}",
+ httpClientId, username);
+ final String requestURLProtocol = requestURL.getProtocol();
+ final String requestUrlHost = requestURL.getHost();
+ final Integer requestUrlPortNumber = requestURL.getPort();
+ final HttpHost requestURLHost = new HttpHost(requestUrlHost, requestUrlPortNumber, requestURLProtocol);
+ final String password = httpClientConfig.getPassword();
+ final AuthScope httpClientAuthScope = new AuthScope(requestURLHost);
+ final Credentials credentials = new UsernamePasswordCredentials(username, password);
+ credentialsProvider.setCredentials(httpClientAuthScope, credentials);
+ } else {
+ logger.warn("No credentials set for Http Client Id: {}. No username present", httpClientId);
+ }
+ }
+
+ /**
+ * Configures proxy host, port and authentication
+ *
+ * @param httpClientId http client id
+ * @param httpClientBuilder http client builder
+ * @param credentialsProvider http credentials provider
+ */
+ private void configureProxySettings(final String httpClientId, final HttpClientBuilder httpClientBuilder,
+ final CredentialsProvider credentialsProvider) {
+
+ final URL proxyURL = httpClientConfig.getProxyURL();
+
+ if (proxyURL == null) {
+ logger.debug("Proxy not Enabled - bypassing setting Proxy settings for Http Client Id: {}", httpClientId);
+ return;
+ }
+
+ final String proxyProtocol = proxyURL.getProtocol();
+ final String proxyHost = proxyURL.getHost();
+ final Integer proxyPort = proxyURL.getPort();
+ final HttpHost proxy = new HttpHost(proxyHost, proxyPort, proxyProtocol);
+
+ logger.info("Setting up proxy for Http Client Id: {} as: {}", httpClientId, proxy);
+
+ final DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
+ httpClientBuilder.setRoutePlanner(routePlanner);
+
+ // get proxy credentials information
+ final String userInfo = proxyURL.getUserInfo();
+
+ if (!StringUtils.hasText(userInfo)) {
+ logger.debug("Proxy username not present. " +
+ "No proxy authentication credentials will be set for Http Client Id: {}", httpClientId);
+ return;
+ }
+
+ final String[] userInfoArray = userInfo.split(":");
+ final String proxyUsername = userInfoArray[0];
+ String proxyPassword = null;
+ if (userInfoArray.length > 1) {
+ proxyPassword = userInfoArray[1];
+ }
+ logger.info("Setting proxy credentials with username: {} for Http Client Id: {}", proxyUsername, httpClientId);
+ final AuthScope proxyAuthScope = new AuthScope(proxyHost, proxyPort);
+ final Credentials proxyCredentials = new UsernamePasswordCredentials(proxyUsername, proxyPassword);
+ credentialsProvider.setCredentials(proxyAuthScope, proxyCredentials);
+ }
+
+ /**
+ * Configures SSL Context
+ *
+ * @param httpClientId http client id
+ * @param httpClientBuilder http client builder
+ */
+ private void configureSSLContext(final String httpClientId, final HttpClientBuilder httpClientBuilder) {
+
+ // Setup SSL Context to ignore SSL certificate issues if ignoreSSLCertificateErrors is true
+ final boolean ignoreSSLValidation =
+ Optional.ofNullable(httpClientConfig.getIgnoreSSLValidation()).orElse(false);
+ logger.info("Ignore SSL Certificate Errors attributed is set to: {} for Http Client Id: {}",
+ ignoreSSLValidation, httpClientId);
+
+ if (!ignoreSSLValidation) {
+ logger.info("SSL Validation will be enforced for Http Client Id: {}", httpClientId);
+ return;
+ }
+
+ logger.warn("SSL Certificate Errors will be ignored for Http Client Id: {}", httpClientId);
+ try {
+ SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
+ sslContextBuilder.loadTrustMaterial(null, new AlwaysTrustingTrustStrategy());
+ httpClientBuilder.setSSLContext(sslContextBuilder.build());
+ } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
+ ReflectionUtils.rethrowRuntimeException(e);
+ }
+ httpClientBuilder.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE);
+
+ }
+
+
+ /**
+ * Header Request Interceptor adds defaults headers if not set explicitly
+ */
+ private static class DefaultHeadersRequestInterceptor implements ClientHttpRequestInterceptor {
+ private final HttpHeaders httpHeaders;
+
+ DefaultHeadersRequestInterceptor(final HttpHeaders httpHeaders) {
+ this.httpHeaders = httpHeaders;
+ }
+
+ @Override
+ public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
+ final ClientHttpRequestExecution execution) throws IOException {
+ final HttpHeaders currentRequestHeaders = request.getHeaders();
+ for (Map.Entry<String, List<String>> defaultHttpHeader : httpHeaders.entrySet()) {
+ if (!currentRequestHeaders.containsKey(defaultHttpHeader.getKey())) {
+ currentRequestHeaders.addAll(defaultHttpHeader.getKey(), defaultHttpHeader.getValue());
+ }
+ }
+ currentRequestHeaders.setAccept(httpHeaders.getAccept());
+ currentRequestHeaders.setAcceptCharset(httpHeaders.getAcceptCharset());
+ currentRequestHeaders.remove(HttpHeaders.ACCEPT_ENCODING);
+ return execution.execute(request, body);
+ }
+ }
+
+ /**
+ * An implementation of SSL Trust Strategy which does no SSL certificate validation effectively
+ * bypassing any SSL certificate related issues
+ */
+ private static class AlwaysTrustingTrustStrategy implements TrustStrategy {
+ @Override
+ public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ return true;
+ }
+ }
+
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/mongo/MongoProfileCondition.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/mongo/MongoProfileCondition.java
new file mode 100644
index 0000000..d984085
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/mongo/MongoProfileCondition.java
@@ -0,0 +1,54 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.mongo;
+
+import java.util.Arrays;
+
+import org.onap.dcae.analytics.model.AnalyticsProfile;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Condition;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+
+/**
+ * Condition that configures mongo support only if mongo profile is present
+ *
+ * @author Rajiv Singla
+ */
+public class MongoProfileCondition implements Condition {
+
+ private static final Logger logger = LoggerFactory.getLogger(MongoProfileCondition.class);
+
+ @Override
+ public boolean matches(final ConditionContext context, final AnnotatedTypeMetadata metadata) {
+
+ final boolean isMongoProfileActive = Arrays.stream(context.getEnvironment().getActiveProfiles())
+ .anyMatch(activeProfile -> activeProfile.equalsIgnoreCase(AnalyticsProfile.MONGO_PROFILE_NAME));
+
+ if (isMongoProfileActive) {
+ logger.info("Mongo Profile is Active. Mongo support is enabled");
+ return true;
+ }
+
+ logger.info("Mongo Profile is NOT Active. Mongo support is disabled");
+ return false;
+ }
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/spring/ConfigBindingServiceEnvironmentPostProcessor.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/spring/ConfigBindingServiceEnvironmentPostProcessor.java
new file mode 100644
index 0000000..2073127
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/spring/ConfigBindingServiceEnvironmentPostProcessor.java
@@ -0,0 +1,148 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.spring;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.onap.dcae.analytics.model.AnalyticsProfile;
+import org.onap.dcae.analytics.model.configbindingservice.ConfigBindingServiceConstants;
+import org.onap.dcae.analytics.model.util.function.JsonStringToMapFunction;
+import org.onap.dcae.analytics.model.util.supplier.ConfigBindingServiceJsonSupplier;
+import org.onap.dcae.analytics.web.exception.AnalyticsValidationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.env.EnvironmentPostProcessor;
+import org.springframework.core.Ordered;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.MapPropertySource;
+import org.springframework.core.env.MutablePropertySources;
+import org.springframework.core.env.PropertySource;
+import org.springframework.core.env.StandardEnvironment;
+import org.springframework.util.ClassUtils;
+import org.springframework.web.context.support.StandardServletEnvironment;
+
+/**
+ * A custom spring framework environment post processor which can fetch and populate spring context with
+ * Config Binding Service application properties.
+ * <p>
+ * Activated only when config binding service profile is active.
+ *
+ * @author Rajiv Singla
+ */
+public class ConfigBindingServiceEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
+
+ private static final Logger logger = LoggerFactory.getLogger(ConfigBindingServiceEnvironmentPostProcessor.class);
+ private static final String SERVLET_ENVIRONMENT_CLASS =
+ "org.springframework.web.context.support.StandardServletEnvironment";
+
+ private static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE;
+
+ @Override
+ public void postProcessEnvironment(final ConfigurableEnvironment environment, final SpringApplication application) {
+
+ final boolean isConfigServiceProfilePresent = Arrays.stream(environment.getActiveProfiles())
+ .anyMatch(p -> p.equalsIgnoreCase(AnalyticsProfile.CONFIG_BINDING_SERVICE_PROFILE_NAME));
+
+ if (!isConfigServiceProfilePresent) {
+ logger.info("Config Binding Service Profile is not active. " +
+ "Skipping Adding config binding service properties");
+ return;
+ }
+
+ logger.info("Config Binding Service Profile is active. " +
+ "Application properties will be fetched from config binding service");
+
+ // Fetch config binding service json
+ final Optional<String> configServiceJsonOptional = new ConfigBindingServiceJsonSupplier().get();
+
+ if (!configServiceJsonOptional.isPresent()) {
+ final String errorMessage = "Unable to get fetch application configuration from config binding service";
+ throw new AnalyticsValidationException(errorMessage, new IllegalStateException(errorMessage));
+ }
+
+ final String configServicePropertiesKey = ConfigBindingServiceConstants.CONFIG_BINDING_SERVICE_PROPERTIES_KEY;
+
+ // convert fetch config binding service json string to Map of property key and values
+ final Map<String, Object> configPropertiesMap = configServiceJsonOptional
+ .map(new JsonStringToMapFunction(configServicePropertiesKey))
+ .orElse(Collections.emptyMap());
+
+ if (configPropertiesMap.isEmpty()) {
+
+ logger.warn("No properties found in config binding service");
+
+ } else {
+
+ // remove config service key prefix on spring reserved property key prefixes
+ final Set<String> springKeyPrefixes = ConfigBindingServiceConstants.SPRING_RESERVED_PROPERTIES_KEY_PREFIXES;
+ final Set<String> springKeys = springKeyPrefixes.stream()
+ .map(springKeyPrefix -> configServicePropertiesKey + "." + springKeyPrefix)
+ .collect(Collectors.toSet());
+
+ final Map<String, Object> filterKeyMap = configPropertiesMap.entrySet()
+ .stream()
+ .collect(Collectors.toMap(
+ (Map.Entry<String, Object> e) ->
+ springKeys.stream().anyMatch(springKey -> e.getKey().startsWith(springKey)) ?
+ e.getKey().substring(configServicePropertiesKey.toCharArray().length + 1) :
+ e.getKey(),
+ Map.Entry::getValue)
+ );
+
+ filterKeyMap.forEach((key, value) ->
+ logger.info("Adding property from config service in spring context: {} -> {}", key, value));
+
+ addJsonPropertySource(environment, new MapPropertySource(configServicePropertiesKey, filterKeyMap));
+ }
+
+ }
+
+ @Override
+ public int getOrder() {
+ return DEFAULT_ORDER;
+ }
+
+
+ private void addJsonPropertySource(final ConfigurableEnvironment environment, final PropertySource<?> source) {
+ final MutablePropertySources sources = environment.getPropertySources();
+ final String name = findPropertySource(sources);
+ if (sources.contains(name)) {
+ sources.addBefore(name, source);
+ } else {
+ sources.addFirst(source);
+ }
+ }
+
+ private String findPropertySource(final MutablePropertySources sources) {
+ if (ClassUtils.isPresent(SERVLET_ENVIRONMENT_CLASS, null) &&
+ sources.contains(StandardServletEnvironment.JNDI_PROPERTY_SOURCE_NAME)) {
+ return StandardServletEnvironment.JNDI_PROPERTY_SOURCE_NAME;
+
+ }
+ return StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME;
+ }
+
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/spring/MongoAutoConfigurationPostProcessor.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/spring/MongoAutoConfigurationPostProcessor.java
new file mode 100644
index 0000000..94f877e
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/spring/MongoAutoConfigurationPostProcessor.java
@@ -0,0 +1,95 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.spring;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.onap.dcae.analytics.model.AnalyticsProfile;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.env.EnvironmentPostProcessor;
+import org.springframework.core.Ordered;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.MapPropertySource;
+import org.springframework.core.env.MutablePropertySources;
+import org.springframework.core.env.PropertySource;
+
+/**
+ * Disables mongo auto configuration if {@link AnalyticsProfile#MONGO_PROFILE_NAME} is not present
+ *
+ * @author Rajiv Singla
+ */
+public class MongoAutoConfigurationPostProcessor implements EnvironmentPostProcessor, Ordered {
+
+ private static final Logger logger = LoggerFactory.getLogger(MongoAutoConfigurationPostProcessor.class);
+
+ private static final String PROPERTY_SOURCE_NAME = "defaultProperties";
+ private static final String SPRING_AUTO_CONFIG_EXCLUDE_PROPERTY_KEY = "spring.autoconfigure.exclude";
+ private static final List<String> MONGO_AUTO_CONFIG_PROPERTIES = Arrays.asList(
+ "org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration",
+ "org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration",
+ "org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration");
+
+ @Override
+ public void postProcessEnvironment(final ConfigurableEnvironment environment, final SpringApplication application) {
+
+ final boolean isMongoProfileActive = Arrays.stream(environment.getActiveProfiles())
+ .anyMatch(profile -> profile.equalsIgnoreCase(AnalyticsProfile.MONGO_PROFILE_NAME));
+
+ // if mongo profile is not active disable mongo auto configuration
+ if (!isMongoProfileActive) {
+ logger.info("Mongo Profile is not active - disabling Mongo Auto Configuration");
+ final Map<String, Object> mongoExcludePropsMap = new HashMap<>();
+ mongoExcludePropsMap.put(SPRING_AUTO_CONFIG_EXCLUDE_PROPERTY_KEY, MONGO_AUTO_CONFIG_PROPERTIES);
+ addMongoPropertiesIfAbsent(environment.getPropertySources(), mongoExcludePropsMap);
+ }
+ }
+
+ private void addMongoPropertiesIfAbsent(final MutablePropertySources propertySources,
+ final Map<String, Object> mongoPropertiesMap) {
+ MapPropertySource target = null;
+ if (propertySources.contains(PROPERTY_SOURCE_NAME)) {
+ PropertySource<?> source = propertySources.get(PROPERTY_SOURCE_NAME);
+ if (source instanceof MapPropertySource) {
+ target = (MapPropertySource) source;
+ for (final Map.Entry<String, Object> entry : mongoPropertiesMap.entrySet()) {
+ if (!target.containsProperty(entry.getKey())) {
+ target.getSource().putIfAbsent(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+ }
+ if (target == null) {
+ target = new MapPropertySource(PROPERTY_SOURCE_NAME, mongoPropertiesMap);
+ }
+ if (!propertySources.contains(PROPERTY_SOURCE_NAME)) {
+ propertySources.addLast(target);
+ }
+ }
+
+ @Override
+ public int getOrder() {
+ return Ordered.LOWEST_PRECEDENCE;
+ }
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/util/AnalyticsHttpUtils.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/util/AnalyticsHttpUtils.java
new file mode 100644
index 0000000..96e16f9
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/util/AnalyticsHttpUtils.java
@@ -0,0 +1,124 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.util;
+
+/**
+ * @author Rajiv Singla
+ */
+
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Map;
+import java.util.Optional;
+
+import javax.annotation.Nullable;
+
+import org.onap.dcae.analytics.model.AnalyticsHttpConstants;
+import org.onap.dcae.analytics.model.AnalyticsModelConstants;
+import org.onap.dcae.analytics.model.configbindingservice.ConfigBindingServiceConstants;
+import org.onap.dcae.analytics.model.util.supplier.CreationTimestampSupplier;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.messaging.MessageHeaders;
+
+/**
+ * Provides utility methods for Analytics HTTP Operations
+ *
+ * @author Rajiv Singla
+ */
+public abstract class AnalyticsHttpUtils {
+
+ /**
+ * Creates default http headers for analytics http requests to other services like DMaaP, AAI etc with randomly
+ * generated request id header
+ *
+ * @return default analytics http headers
+ */
+ public static HttpHeaders createDefaultHttpHeaders() {
+ return createDefaultHttpHeaders(null);
+ }
+
+ /**
+ * Creates default http headers for analytics http requests to other services like DMaaP, AAI etc
+ *
+ * @param requestId request id
+ *
+ * @return default analytics http headers
+ */
+ public static HttpHeaders createDefaultHttpHeaders(@Nullable final String requestId) {
+
+ final HttpHeaders httpHeaders = new HttpHeaders();
+
+ // set analytics from app name header.
+ // Look up service name set by config service "SERVICE_NAME" environment variable or assign default value
+ httpHeaders.add(
+ AnalyticsHttpConstants.REQUEST_APP_NAME_HEADER_KEY,
+ ConfigBindingServiceConstants.SERVICE_NAME_ENV_VARIABLE_VALUE != null ?
+ ConfigBindingServiceConstants.SERVICE_NAME_ENV_VARIABLE_VALUE :
+ AnalyticsHttpConstants.REQUEST_APP_NAME_HEADER_DEFAULT_VALUE);
+
+ // if request id is not present create random UUID
+ httpHeaders.add(AnalyticsHttpConstants.REQUEST_ID_HEADER_KEY, requestId != null ?
+ requestId : AnalyticsWebUtils.REQUEST_ID_SUPPLIER.get());
+
+ // sub transaction id is created randomly for each http request
+ httpHeaders.add(AnalyticsHttpConstants.REQUEST_TRANSACTION_ID_HEADER_KEY,
+ AnalyticsWebUtils.RANDOM_ID_SUPPLIER.get());
+
+ // by default analytics will accept only json
+ httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON_UTF8));
+ httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
+ httpHeaders.setAcceptCharset(
+ Collections.singletonList(Charset.forName(AnalyticsModelConstants.UTF8_CHARSET_NAME)));
+
+ return httpHeaders;
+ }
+
+
+ public static String getRequestId(final MessageHeaders messageHeaders) {
+ return Optional.ofNullable(messageHeaders.get(AnalyticsHttpConstants.REQUEST_ID_HEADER_KEY))
+ .map(requestId -> (String) requestId).orElse("UNKNOWN-REQUEST_ID");
+ }
+
+ public static String getTransactionId(final MessageHeaders messageHeaders) {
+ return Optional.ofNullable(messageHeaders.get(AnalyticsHttpConstants.REQUEST_TRANSACTION_ID_HEADER_KEY))
+ .map(transactionId -> (String) transactionId).orElse("UNKNOWN-TRANSACTION_ID");
+ }
+
+ public static Date getTimestampFromHeaders(final Map<String, Object> headers, final String headerTsKey) {
+ return Optional.ofNullable(headers.get(headerTsKey))
+ .map(ts -> CreationTimestampSupplier.getParsedDate((String) ts)).orElse(new Date());
+ }
+
+ public static String getRequestId(final HttpHeaders httpHeaders) {
+ return Optional.ofNullable(
+ httpHeaders.get(AnalyticsHttpConstants.REQUEST_ID_HEADER_KEY)).map(headerList ->
+ headerList.get(0)).orElse(AnalyticsWebUtils.REQUEST_ID_SUPPLIER.get());
+ }
+
+ public static String getTransactionId(final HttpHeaders httpHeaders) {
+ return Optional.ofNullable(
+ httpHeaders.get(AnalyticsHttpConstants.REQUEST_TRANSACTION_ID_HEADER_KEY)).map(headerList ->
+ headerList.get(0)).orElse(AnalyticsWebUtils.RANDOM_ID_SUPPLIER.get());
+ }
+
+
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/util/AnalyticsWebUtils.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/util/AnalyticsWebUtils.java
new file mode 100644
index 0000000..a0bf558
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/util/AnalyticsWebUtils.java
@@ -0,0 +1,42 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.util;
+
+import java.util.function.Supplier;
+
+import org.onap.dcae.analytics.model.AnalyticsModelConstants;
+import org.onap.dcae.analytics.model.util.supplier.AnalyticsRequestIdSupplier;
+import org.onap.dcae.analytics.model.util.supplier.CreationTimestampSupplier;
+import org.onap.dcae.analytics.model.util.supplier.RandomIdSupplier;
+
+/**
+ * @author Rajiv Singla
+ */
+public abstract class AnalyticsWebUtils {
+
+ public static final Supplier<String> REQUEST_ID_SUPPLIER = new AnalyticsRequestIdSupplier();
+ public static final Supplier<String> RANDOM_ID_SUPPLIER =
+ new RandomIdSupplier(AnalyticsModelConstants.DEFAULT_RANDOM_ID_LENGTH);
+ public static final Supplier<String> CREATION_TIMESTAMP_SUPPLIER = new CreationTimestampSupplier();
+
+ private AnalyticsWebUtils() {
+ // private constructor
+ }
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/util/ValidationUtils.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/util/ValidationUtils.java
new file mode 100644
index 0000000..5c734d8
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/util/ValidationUtils.java
@@ -0,0 +1,108 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.util;
+
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.onap.dcae.analytics.web.exception.AnalyticsValidationException;
+import org.onap.dcae.analytics.web.validation.AnalyticsValidator;
+import org.onap.dcae.analytics.web.validation.ValidationResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.Assert;
+
+/**
+ * Validation Utilities
+ *
+ * @author Rajiv Singla
+ */
+public abstract class ValidationUtils {
+
+ private static final Logger log = LoggerFactory.getLogger(ValidationUtils.class);
+
+ private ValidationUtils() {
+
+ }
+
+ /**
+ * Checks if String is empty. For null string true is returned
+ *
+ * @param stringValue string value
+ *
+ * @return returns true is string is empty or null
+ */
+ public static boolean isEmpty(@Nullable final String stringValue) {
+ return stringValue == null || stringValue.isEmpty() || stringValue.trim().isEmpty();
+ }
+
+
+ /**
+ * Checks if String value is present. A null, empty, or blank values of string
+ * are considered not present.
+ *
+ * @param stringValue string value to check if it is present or not
+ *
+ * @return true if string value is not null, empty or blank
+ */
+ public static boolean isPresent(@Nullable final String stringValue) {
+ return !isEmpty(stringValue);
+ }
+
+
+ /**
+ * Provides common functionality to validate analytics objects.
+ * Throws {@link AnalyticsValidationException} exception if validation fails
+ *
+ * @param targetObject target object that needs to be validated
+ * @param validator validator that will be used to validate the target object
+ * @param <T> target object type that needs to be validated
+ * @param <R> Validation Response type
+ * @param <V> Validator Type
+ *
+ * @return target object if validation is successful
+ */
+ public static <T, R extends ValidationResponse, V extends AnalyticsValidator<T, R>> T validate(
+ @Nonnull final T targetObject,
+ @Nonnull final V validator) {
+
+ Assert.notNull(targetObject, "target object that needs to validated must not be null");
+ Assert.notNull(validator, "validator must not be null");
+
+ final String targetObjectClass = targetObject.getClass().getSimpleName();
+ final String validatorClass = validator.getClass().getSimpleName();
+
+ log.debug("Validating target object of type: {} with validator type: {} ", targetObjectClass, validatorClass);
+
+ final R validationResponse = validator.apply(targetObject);
+
+ // If setting validation fails throw an exception
+ if (validationResponse.hasErrors()) {
+ throw new AnalyticsValidationException(validationResponse.getAllErrorMessage(),
+ new IllegalArgumentException(validationResponse.getAllErrorMessage()));
+ }
+
+ log.info("Validation Successful for target object type: {} with validator type: {}", targetObjectClass,
+ validatorClass);
+
+ return targetObject;
+ }
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/util/function/MrSubscriberURLFunction.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/util/function/MrSubscriberURLFunction.java
new file mode 100644
index 0000000..2f32d6d
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/util/function/MrSubscriberURLFunction.java
@@ -0,0 +1,106 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.util.function;
+
+
+import static org.onap.dcae.analytics.web.util.AnalyticsWebUtils.RANDOM_ID_SUPPLIER;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.onap.dcae.analytics.model.DmaapMrConstants;
+import org.onap.dcae.analytics.web.dmaap.MrSubscriberPreferences;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.util.UriComponentsBuilder;
+
+/**
+ * Creates DMaaP MR Subscriber URLs from {@link MrSubscriberPreferences}
+ *
+ * @author Rajiv Singla
+ */
+public class MrSubscriberURLFunction implements Function<MrSubscriberPreferences, List<URL>> {
+
+ private static final Logger logger = LoggerFactory.getLogger(MrSubscriberURLFunction.class);
+ private static final String URL_PATH_SEPARATOR = "/";
+
+ @Override
+ public List<URL> apply(final MrSubscriberPreferences subscriberConfig) {
+
+ final List<URL> subscriberURLs = new LinkedList<>();
+
+ // if consumer ids is not present generate single random consumer id
+ final List<String> consumerIds = subscriberConfig.getConsumerIds() != null ?
+ subscriberConfig.getConsumerIds() : Stream.of(RANDOM_ID_SUPPLIER.get()).collect(Collectors.toList());
+
+ for (final String consumerId : consumerIds) {
+
+ // request url must be present
+ final String requestURL = subscriberConfig.getRequestURL();
+
+ // generate random consumer group if not present
+ final String consumerGroup = subscriberConfig.getConsumerGroup() != null ?
+ subscriberConfig.getConsumerGroup() :
+ DmaapMrConstants.SUBSCRIBER_RANDOM_CONSUMER_GROUP_PREFIX + RANDOM_ID_SUPPLIER.get();
+
+ // set default message limit if not present
+ final Integer messageLimit = subscriberConfig.getMessageLimit() != null ?
+ subscriberConfig.getMessageLimit() : DmaapMrConstants.SUBSCRIBER_DEFAULT_MESSAGE_LIMIT;
+
+ // set default timeout if not present
+ final Integer timeout = subscriberConfig.getTimeout() != null ?
+ subscriberConfig.getTimeout() : DmaapMrConstants.SUBSCRIBER_DEFAULT_TIMEOUT;
+
+ final UriComponentsBuilder componentsBuilder = UriComponentsBuilder
+ .fromHttpUrl(requestURL)
+ .path(URL_PATH_SEPARATOR + consumerGroup + URL_PATH_SEPARATOR + consumerId);
+
+ if (messageLimit != null && messageLimit >= 1) {
+ componentsBuilder
+ .queryParam(DmaapMrConstants.SUBSCRIBER_MSG_LIMIT_QUERY_PARAM_NAME, messageLimit);
+ }
+
+ if (timeout != null && timeout >= 1) {
+ componentsBuilder
+ .queryParam(DmaapMrConstants.SUBSCRIBER_TIMEOUT_QUERY_PARAM_NAME, timeout);
+ }
+
+ subscriberURLs.add(createURL(componentsBuilder));
+
+ }
+
+ return subscriberURLs;
+ }
+
+ private URL createURL(final UriComponentsBuilder uriComponentsBuilder) {
+ try {
+ final URL subscriberURL = uriComponentsBuilder.build().toUri().toURL();
+ logger.info("Created DMaaP MR Subscriber URL: {}", subscriberURL);
+ return subscriberURL;
+ } catch (MalformedURLException e) {
+ throw new IllegalStateException("Unable to build DMaaP MR Subscriber URL", e);
+ }
+ }
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/validation/AnalyticsValidator.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/validation/AnalyticsValidator.java
new file mode 100644
index 0000000..0eaa800
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/validation/AnalyticsValidator.java
@@ -0,0 +1,39 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.validation;
+
+import java.io.Serializable;
+import java.util.function.Function;
+
+import org.springframework.validation.Validator;
+
+/**
+ * Analytics Validator can be used to validate Analytics components
+ *
+ * @param <T> object class that needs too be validated
+ * @param <R> validation Response
+ *
+ * @author Rajiv Singla
+ */
+public interface AnalyticsValidator<T, R extends ValidationResponse> extends Function<T, R>, Validator, Serializable {
+
+}
+
+
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/validation/GenericValidationResponse.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/validation/GenericValidationResponse.java
new file mode 100644
index 0000000..d5da8f2
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/validation/GenericValidationResponse.java
@@ -0,0 +1,80 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.validation;
+
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * A generic implementation of Validation Response
+ *
+ * @author Rajiv Singla
+ */
+@ToString
+@EqualsAndHashCode
+public class GenericValidationResponse implements ValidationResponse {
+
+ private static final String DEFAULT_DELIMITER = ",";
+
+ private LinkedHashMap<String, String> errorMessageMap = new LinkedHashMap<>();
+
+ @Override
+ public boolean hasErrors() {
+ return !errorMessageMap.isEmpty();
+ }
+
+ @Override
+ public Set<String> getFieldNamesWithError() {
+ return errorMessageMap.keySet();
+ }
+
+ @Override
+ public Collection<String> getErrorMessages() {
+ return errorMessageMap.values();
+ }
+
+ @Override
+ public Map<String, String> getValidationResultsAsMap() {
+ return errorMessageMap;
+ }
+
+ @Override
+ public String getAllErrorMessage() {
+ return getAllErrorMessage(DEFAULT_DELIMITER);
+ }
+
+ @Override
+ public String getAllErrorMessage(String delimiter) {
+ return errorMessageMap.values()
+ .stream().collect(Collectors.joining(delimiter));
+ }
+
+ @Override
+ public void addErrorMessage(String fieldName, String filedErrorMessage) {
+ errorMessageMap.put(fieldName, filedErrorMessage);
+ }
+
+}
diff --git a/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/validation/ValidationResponse.java b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/validation/ValidationResponse.java
new file mode 100644
index 0000000..bf06263
--- /dev/null
+++ b/dcae-analytics/dcae-analytics-web/src/main/java/org/onap/dcae/analytics/web/validation/ValidationResponse.java
@@ -0,0 +1,88 @@
+/*
+ * ================================================================================
+ * Copyright (c) 2018 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.onap.dcae.analytics.web.validation;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Validation Response
+ *
+ * @author Rajiv Singla
+ */
+public interface ValidationResponse {
+
+ /**
+ * Returns true if validation resulted in one or more errors
+ *
+ * @return true if validation has errors
+ */
+ boolean hasErrors();
+
+ /**
+ * Returns all field names which have error
+ *
+ * @return names of fields which have error
+ */
+ Set<String> getFieldNamesWithError();
+
+ /**
+ * Returns list of all error messages
+ *
+ * @return list of error messages
+ */
+ Collection<String> getErrorMessages();
+
+
+ /**
+ * Returns all error messages as string delimited by comma
+ *
+ * @return all error messages delimited by given delimiter
+ */
+ String getAllErrorMessage();
+
+ /**
+ * Returns all error messages as string delimited by given delimited
+ *
+ * @param delimiter delimited to be used for error message
+ *
+ * @return all error messages delimited by given delimiter
+ */
+ String getAllErrorMessage(String delimiter);
+
+ /**
+ * Adds field name and error message to the validation response
+ *
+ * @param fieldName field name which has validation error
+ * @param filedErrorMessage validation error message
+ */
+ void addErrorMessage(String fieldName, String filedErrorMessage);
+
+
+ /**
+ * Returns validation results as map containing values as keys and values
+ * as error Message
+ *
+ * @return Map containing field names and error message associated with those fields
+ */
+ Map<String, String> getValidationResultsAsMap();
+
+}