Implement second part of dynamic DMaaP config 17/58617/4
authorPawelSzalapski <pawel.szalapski@nokia.com>
Thu, 2 Aug 2018 08:31:56 +0000 (10:31 +0200)
committerPawelSzalapski <pawel.szalapski@nokia.com>
Mon, 6 Aug 2018 07:43:32 +0000 (09:43 +0200)
VESCollector app can now fetch CBS configuration and
rebuilt the part regarding sending events dynamically,
without restarting application.
Application will still be restarted by a .sh script,
if there were changes regarding collector.properties file.
The decision of whether dynamic configuration should be
triggered is now based on existence of env vars
CONSUL_HOST, CONFIG_BINDING_SERVICE, HOSTNAME,
not as previously on CBSPOLLTIME.
Frequency at which the config check should happen is
now exposed via property from collector.properties

Change-Id: I98ff160fa51d08d84a23c716d90ceaacbe17ada6
Signed-off-by: PawelSzalapski <pawel.szalapski@nokia.com>
Issue-ID: DCAEGEN2-519

33 files changed:
etc/collector.properties
pom.xml
src/main/java/org/onap/dcae/ApplicationSettings.java
src/main/java/org/onap/dcae/VesApplication.java
src/main/java/org/onap/dcae/commonFunction/event/publishing/DMaaPConfigurationParser.java
src/main/java/org/onap/dcae/commonFunction/event/publishing/DMaaPPublishersBuilder.java
src/main/java/org/onap/dcae/commonFunction/event/publishing/VavrUtils.java
src/main/java/org/onap/dcae/controller/ConfigFilesFacade.java [new file with mode: 0644]
src/main/java/org/onap/dcae/controller/ConfigLoader.java [new file with mode: 0644]
src/main/java/org/onap/dcae/controller/ConfigParsing.java [new file with mode: 0644]
src/main/java/org/onap/dcae/controller/ConfigSource.java [new file with mode: 0644]
src/main/java/org/onap/dcae/controller/Conversions.java [new file with mode: 0644]
src/main/java/org/onap/dcae/controller/EnvPropertiesReader.java [new file with mode: 0644]
src/main/java/org/onap/dcae/controller/EnvProps.java [new file with mode: 0644]
src/main/java/org/onap/dcae/controller/FetchDynamicConfig.java [deleted file]
src/main/java/org/onap/dcae/controller/LoadDynamicConfig.java [deleted file]
src/main/java/org/onap/dcae/controller/PreAppStartupConfigUpdater.java [new file with mode: 0644]
src/main/java/org/onap/dcae/restapi/VesRestController.java
src/main/scripts/VESConfigPoller.sh [deleted file]
src/main/scripts/VESrestfulCollector.sh [deleted file]
src/main/scripts/appController.sh [new file with mode: 0644]
src/main/scripts/configurationPoller.sh [new file with mode: 0644]
src/main/scripts/docker-entry.sh
src/test/java/org/onap/dcae/ApplicationSettingsTest.java
src/test/java/org/onap/dcae/TestingUtilities.java [new file with mode: 0644]
src/test/java/org/onap/dcae/WiremockBasedTest.java [new file with mode: 0644]
src/test/java/org/onap/dcae/controller/ConfigCBSSourceTest.java [new file with mode: 0644]
src/test/java/org/onap/dcae/controller/ConfigFilesFacadeTest.java [new file with mode: 0644]
src/test/java/org/onap/dcae/controller/ConfigLoaderIntegrationE2ETest.java [new file with mode: 0644]
src/test/java/org/onap/dcae/controller/ConfigParsingTest.java [new file with mode: 0644]
src/test/java/org/onap/dcae/controller/EnvPropertiesReaderTest.java [new file with mode: 0644]
src/test/java/org/onap/dcae/vestest/TestFetchConfig.java [deleted file]
src/test/java/org/onap/dcae/vestest/TestLoadDynamicConfig.java [deleted file]

index 4354eb6..7ff24b1 100755 (executable)
@@ -64,6 +64,9 @@ header.authlist=sample1,c2FtcGxlMQ==
 ## Enabled by default; to disable set to 0\r
 event.transform.flag=1\r
 \r
+# Describes at what frequency (measured in minutes) should application try to fetch config from CBS\r
+collector.dynamic.config.update.frequency=5\r
+\r
 ###############################################################################\r
 ##\r
 ## Tomcat control\r
diff --git a/pom.xml b/pom.xml
index 16492e2..0ba074f 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -377,7 +377,13 @@ limitations under the License.
             <artifactId>cambriaClient</artifactId>
             <version>0.0.1</version>
         </dependency>
+        <dependency>
+            <groupId>com.mashape.unirest</groupId>
+            <artifactId>unirest-java</artifactId>
+            <version>1.4.9</version>
+        </dependency>
 
+        <!-- MISCELLANEOUS -->
         <dependency>
             <groupId>commons-collections</groupId>
             <artifactId>commons-collections</artifactId>
@@ -414,7 +420,8 @@ limitations under the License.
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-log4j2</artifactId>
+            <artifactId>spring-boot-starter-log4j</artifactId>
+            <version>1.3.8.RELEASE</version>
         </dependency>
 
         <!-- TESTING -->
@@ -436,6 +443,18 @@ limitations under the License.
             <version>3.8.0</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>com.google.jimfs</groupId>
+            <artifactId>jimfs</artifactId>
+            <version>1.1</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.github.tomakehurst</groupId>
+            <artifactId>wiremock-standalone</artifactId>
+            <version>2.17.0</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <repositories>
index 9063faa..e462184 100644 (file)
@@ -34,7 +34,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Nullable;
-import java.io.File;
+import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Base64;
 
@@ -48,9 +48,8 @@ import static java.util.Arrays.stream;
 public class ApplicationSettings {
 
     private static final Logger inlog = LoggerFactory.getLogger(ApplicationSettings.class);
-    private static final String COLLECTOR_PROPERTIES = "etc/collector.properties";
-
     private final String appInvocationDir;
+    private final String configurationFileLocation;
     private final PropertiesConfiguration properties = new PropertiesConfiguration();
 
     public ApplicationSettings(String[] args, Function1<String[], Map<String, String>> argsParser) {
@@ -61,20 +60,14 @@ public class ApplicationSettings {
         this.appInvocationDir = appInvocationDir;
         properties.setDelimiterParsingDisabled(true);
         Map<String, String> parsedArgs = argsParser.apply(args);
-        loadProperties(Paths.get(new File(COLLECTOR_PROPERTIES).getAbsolutePath()).toString());
-        loadCommandLineProperties(parsedArgs);
+        configurationFileLocation = findOutConfigurationFileLocation(parsedArgs);
+        loadPropertiesFromFile();
         parsedArgs.filterKeys(k -> !k.equals("c")).forEach(this::updateProperty);
     }
-    private void loadCommandLineProperties(Map<String, String> parsedArgs) {
-        parsedArgs.get("c").forEach(e -> {
-            properties.clear();
-            loadProperties(e);
-        });
-    }
 
-    private void loadProperties(String property) {
+    private void loadPropertiesFromFile() {
         try {
-            properties.load(property);
+            properties.load(configurationFileLocation);
         } catch (ConfigurationException ex) {
             inlog.error("Cannot load properties cause:", ex);
             throw new RuntimeException(ex);
@@ -90,6 +83,14 @@ public class ApplicationSettings {
                 .toMap(t -> t.split(",")[0].trim(), t -> new String(Base64.getDecoder().decode(t.split(",")[1])).trim());
     }
 
+    private String findOutConfigurationFileLocation(Map<String, String> parsedArgs) {
+        return prependWithUserDirOnRelative(parsedArgs.get("c").getOrElse("etc/collector.properties"));
+    }
+
+    public Path configurationFileLocation() {
+        return Paths.get(configurationFileLocation);
+    }
+
     public int maximumAllowedQueuedEvents() {
         return properties.getInt("collector.inputQueue.maxPending", 1024 * 4);
     }
@@ -115,6 +116,10 @@ public class ApplicationSettings {
         return properties.getInt("collector.service.secure.port", 8443);
     }
 
+    public int configurationUpdateFrequency() {
+        return properties.getInt("collector.dynamic.config.update.frequency", 5);
+    }
+
     public boolean httpsEnabled() {
         return httpsPort() > 0;
     }
@@ -139,7 +144,7 @@ public class ApplicationSettings {
         return properties.getString("exceptionConfig", null);
     }
 
-    public String cambriaConfigurationFileLocation() {
+    public String dMaaPConfigurationFileLocation() {
         return prependWithUserDirOnRelative(properties.getString("collector.dmaapfile", "etc/DmaapConfig.json"));
     }
 
index 86b8ccb..7eea0eb 100644 (file)
@@ -26,9 +26,11 @@ import org.onap.dcae.commonFunction.EventProcessor;
 import org.onap.dcae.commonFunction.event.publishing.DMaaPConfigurationParser;
 import org.onap.dcae.commonFunction.event.publishing.EventPublisher;
 import org.onap.dcae.commonFunction.event.publishing.PublisherConfig;
+import org.onap.dcae.controller.ConfigLoader;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.Banner;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -38,9 +40,7 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Lazy;
 
 import java.nio.file.Paths;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.*;
 
 @SpringBootApplication
 @EnableAutoConfiguration(exclude = {GsonAutoConfiguration.class, SecurityAutoConfiguration.class})
@@ -61,21 +61,39 @@ public class VesApplication {
 
         fProcessingInputQueue = new LinkedBlockingQueue<>(properties.maximumAllowedQueuedEvents());
 
-        app.setAddCommandLineProperties(true);
-        app.run();
-
+        EventPublisher publisher = EventPublisher.createPublisher(oplog,
+                DMaaPConfigurationParser
+                        .parseToDomainMapping(Paths.get(properties.dMaaPConfigurationFileLocation()))
+                        .get());
+        spawnDynamicConfigUpdateThread(publisher, properties);
         EventProcessor ep = new EventProcessor(EventPublisher.createPublisher(oplog, getDmapConfig()), properties);
 
         ExecutorService executor = Executors.newFixedThreadPool(MAX_THREADS);
         for (int i = 0; i < MAX_THREADS; ++i) {
             executor.execute(ep);
         }
+
+        app.setBannerMode(Banner.Mode.OFF);
+        app.setAddCommandLineProperties(true);
+        app.run();
     }
 
+    private static void spawnDynamicConfigUpdateThread(EventPublisher eventPublisher, ApplicationSettings properties) {
+        ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1);
+        ConfigLoader configLoader = ConfigLoader
+                .create(eventPublisher::reconfigure,
+                        Paths.get(properties.dMaaPConfigurationFileLocation()),
+                        properties.configurationFileLocation());
+        scheduledThreadPoolExecutor
+                .scheduleAtFixedRate(() -> configLoader.updateConfig(),
+                        properties.configurationUpdateFrequency(),
+                        properties.configurationUpdateFrequency(),
+                        TimeUnit.MINUTES);
+    }
 
     private static Map<String, PublisherConfig> getDmapConfig() {
         return DMaaPConfigurationParser.
-                parseToDomainMapping(Paths.get(properties.cambriaConfigurationFileLocation())).get();
+                parseToDomainMapping(Paths.get(properties.dMaaPConfigurationFileLocation())).get();
     }
 
     @Bean
index 179e882..91db517 100644 (file)
@@ -29,6 +29,8 @@ import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.Path;
 
+import org.json.JSONObject;
+
 import static io.vavr.API.*;
 import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.enhanceError;
 import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.f;
@@ -45,6 +47,11 @@ public final class DMaaPConfigurationParser {
                 .flatMap(DMaaPConfigurationParser::toConfigMap);
     }
 
+    public static Try<Map<String, PublisherConfig>> parseToDomainMapping(JSONObject config) {
+        return toJSON(config.toString())
+            .flatMap(DMaaPConfigurationParser::toConfigMap);
+    }
+
     private static Try<String> readFromFile(Path configLocation) {
         return Try(() -> new String(Files.readAllBytes(configLocation)))
                 .mapFailure(enhanceError(f("Could not read DMaaP configuration from location: '%s'", configLocation)));
index 489fcbf..4f67271 100644 (file)
@@ -33,7 +33,6 @@ import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.f;
  */
 final class DMaaPPublishersBuilder {
 
-    @SuppressWarnings("mapFailure takes a generic varargs, unchecked because of Javas type system limitation, actually safe to do")
     static Try<CambriaBatchingPublisher> buildPublisher(PublisherConfig config) {
         return Try(() -> builder(config).build())
                 .mapFailure(enhanceError(f("DMaaP client builder throws exception for this configuration: '%s'", config)));
index 78f34ff..7d535a2 100644 (file)
@@ -21,13 +21,18 @@ package org.onap.dcae.commonFunction.event.publishing;
 
 import io.vavr.API;
 import io.vavr.API.Match.Case;
+import io.vavr.Function0;
+import io.vavr.Function1;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import org.slf4j.Logger;
 
 import static io.vavr.API.$;
 
 /**
  * @author Pawel Szalapski (pawel.szalapski@nokia.com)
  */
-final class VavrUtils {
+public final class VavrUtils {
 
     private VavrUtils() {
         // utils aggregator
@@ -36,7 +41,7 @@ final class VavrUtils {
     /**
      * Shortcut for 'string interpolation'
      */
-    static String f(String msg, Object... args) {
+    public static String f(String msg, Object... args) {
         return String.format(msg, args);
     }
 
@@ -44,8 +49,17 @@ final class VavrUtils {
      * Wrap failure with a more descriptive message of what has failed and chain original cause. Used to provide a
      * context for errors instead of raw exception.
      */
-    static Case<Throwable, Throwable> enhanceError(String msg) {
+    public static Case<Throwable, Throwable> enhanceError(String msg) {
         return API.Case($(), e -> new RuntimeException(msg, e));
     }
 
+    public static Case<Throwable, Throwable> enhanceError(String pattern, Object... arguments) {
+        return API.Case($(), e -> new RuntimeException(f(pattern, arguments), e));
+    }
+
+    public static Consumer<Throwable> logError(Logger withLogger) {
+        return e -> withLogger.error(e.getMessage(), e);
+    }
+
+
 }
diff --git a/src/main/java/org/onap/dcae/controller/ConfigFilesFacade.java b/src/main/java/org/onap/dcae/controller/ConfigFilesFacade.java
new file mode 100644 (file)
index 0000000..42155ed
--- /dev/null
@@ -0,0 +1,122 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2018 Nokia. 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.controller;
+
+import static io.vavr.API.Try;
+import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.enhanceError;
+import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.f;
+import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.logError;
+import static org.onap.dcae.controller.Conversions.toList;
+
+import io.vavr.CheckedRunnable;
+import io.vavr.Tuple2;
+import io.vavr.collection.Map;
+import io.vavr.control.Try;
+import java.io.FileNotFoundException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class ConfigFilesFacade {
+
+    private static Logger log = LoggerFactory.getLogger(ConfigFilesFacade.class);
+
+    private final Path dMaaPConfigPath;
+    private final Path propertiesPath;
+
+    public ConfigFilesFacade(Path dMaaPConfigPath, Path propertiesPath) {
+        this.dMaaPConfigPath = dMaaPConfigPath;
+        this.propertiesPath = propertiesPath;
+    }
+
+    Try<Map<String, String>> readCollectorProperties() {
+        log.info(f("Reading collector properties from path: '%s'", propertiesPath));
+        return Try(() -> readProperties())
+            .map(prop -> toList(prop.getKeys()).toMap(k -> k, k -> (String) prop.getProperty(k)))
+            .mapFailure(enhanceError("Unable to read properties configuration from path '%s'", propertiesPath))
+            .onFailure(logError(log))
+            .peek(props -> log.info(f("Read following collector properties: '%s'", props)));
+    }
+
+    Try<JSONObject> readDMaaPConfiguration() {
+        log.info(f("Reading DMaaP configuration from file: '%s'", dMaaPConfigPath));
+        return readFile(dMaaPConfigPath)
+            .recover(FileNotFoundException.class, __ -> "{}")
+            .mapFailure(enhanceError("Unable to read DMaaP configuration from file '%s'", dMaaPConfigPath))
+            .flatMap(Conversions::toJson)
+            .onFailure(logError(log))
+            .peek(props -> log.info(f("Read following DMaaP properties: '%s'", props)));
+    }
+
+    Try<Void> writeDMaaPConfiguration(JSONObject dMaaPConfiguration) {
+        log.info(f("Writing DMaaP configuration '%s' into file '%s'", dMaaPConfiguration, dMaaPConfigPath));
+        return writeFile(dMaaPConfigPath, indentConfiguration(dMaaPConfiguration.toString()))
+            .mapFailure(enhanceError("Could not save new DMaaP configuration to path '%s'", dMaaPConfigPath))
+            .onFailure(logError(log))
+            .peek(__ -> log.info("Written successfully"));
+    }
+
+
+    Try<Void> writeProperties(Map<String, String> properties) {
+        log.info(f("Writing properties configuration '%s' into file '%s'", properties, propertiesPath));
+        return Try.run(saveProperties(properties))
+            .mapFailure(enhanceError("Could not save properties to path '%s'", properties))
+            .onFailure(logError(log))
+            .peek(__ -> log.info("Written successfully"));
+    }
+
+    private Try<String> readFile(Path path) {
+        return Try(() -> new String(Files.readAllBytes(path), StandardCharsets.UTF_8))
+            .mapFailure(enhanceError("Could not read content from path: '%s'", path));
+    }
+
+    private Try<Void> writeFile(Path path, String content) {
+        return Try.run(() -> Files.write(path, content.getBytes()))
+            .mapFailure(enhanceError("Could not write content to path: '%s'", path));
+    }
+
+    private PropertiesConfiguration readProperties() throws ConfigurationException {
+        PropertiesConfiguration propertiesConfiguration = new PropertiesConfiguration();
+        propertiesConfiguration.load(propertiesPath.toFile());
+        return propertiesConfiguration;
+    }
+
+    private CheckedRunnable saveProperties(Map<String, String> properties) {
+        return () -> {
+            PropertiesConfiguration propertiesConfiguration = new PropertiesConfiguration(propertiesPath.toFile());
+            propertiesConfiguration.setEncoding(null);
+            for (Tuple2<String, String> property : properties) {
+                propertiesConfiguration.addProperty(property._1, property._2);
+            }
+            propertiesConfiguration.save();
+        };
+    }
+
+    private String indentConfiguration(String configuration) {
+        return new JSONObject(configuration).toString(4);
+    }
+
+}
diff --git a/src/main/java/org/onap/dcae/controller/ConfigLoader.java b/src/main/java/org/onap/dcae/controller/ConfigLoader.java
new file mode 100644 (file)
index 0000000..fb80707
--- /dev/null
@@ -0,0 +1,128 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2018 Nokia. 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.controller;
+
+import static org.onap.dcae.commonFunction.event.publishing.DMaaPConfigurationParser.parseToDomainMapping;
+import static org.onap.dcae.controller.ConfigParsing.getDMaaPConfig;
+import static org.onap.dcae.controller.ConfigParsing.getProperties;
+import static org.onap.dcae.controller.EnvPropertiesReader.readEnvProps;
+
+import io.vavr.Function0;
+import io.vavr.Function1;
+import io.vavr.collection.HashMap;
+import io.vavr.collection.Map;
+import io.vavr.control.Try;
+import java.nio.file.Path;
+import java.util.function.Consumer;
+import org.json.JSONObject;
+import org.onap.dcae.commonFunction.event.publishing.EventPublisher;
+import org.onap.dcae.commonFunction.event.publishing.PublisherConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConfigLoader {
+
+    private static final String SKIP_MSG = "Skipping dynamic configuration update";
+    private static Logger log = LoggerFactory.getLogger(ConfigLoader.class);
+    private final Consumer<Map<String, PublisherConfig>> eventPublisherReconfigurer;
+    private final ConfigFilesFacade configFilesFacade;
+    private final Function1<EnvProps, Try<JSONObject>> configurationSource;
+    private final Function0<Map<String, String>> envVariablesSupplier;
+
+    ConfigLoader(Consumer<Map<String, PublisherConfig>> eventPublisherReconfigurer,
+                 ConfigFilesFacade configFilesFacade,
+                 Function1<EnvProps, Try<JSONObject>> configurationSource,
+                 Function0<Map<String, String>> envVariablesSupplier) {
+        this.eventPublisherReconfigurer = eventPublisherReconfigurer;
+        this.configFilesFacade = configFilesFacade;
+        this.configurationSource = configurationSource;
+        this.envVariablesSupplier = envVariablesSupplier;
+    }
+
+    public static ConfigLoader create(Consumer<Map<String, PublisherConfig>> eventPublisherReconfigurer,
+                                      Path dMaaPConfigFile, Path propertiesConfigFile) {
+        return new ConfigLoader(eventPublisherReconfigurer,
+            new ConfigFilesFacade(dMaaPConfigFile, propertiesConfigFile),
+            ConfigSource::getAppConfig,
+            () -> HashMap.ofAll(System.getenv()));
+    }
+
+    public void updateConfig() {
+        log.info("Trying to dynamically update config from Config Binding Service");
+        readEnvProps(envVariablesSupplier.get())
+            .onEmpty(() -> log.warn(SKIP_MSG))
+            .forEach(props -> updateConfig(props));
+    }
+
+    private void updateConfig(EnvProps props) {
+        configurationSource.apply(props)
+            .onFailure(logSkip())
+            .onSuccess(newConf -> {
+                    updateConfigurationProperties(newConf);
+                    updateDMaaPProperties(newConf);
+                }
+            );
+    }
+
+    private void updateDMaaPProperties(JSONObject newConf) {
+        configFilesFacade.readDMaaPConfiguration()
+            .onFailure(logSkip())
+            .onSuccess(oldDMaaPConf -> getDMaaPConfig(newConf)
+                .onEmpty(() -> log.warn(SKIP_MSG))
+                .forEach(newDMaaPConf -> compareAndOverwriteDMaaPConfig(oldDMaaPConf, newDMaaPConf)));
+    }
+
+
+    private void updateConfigurationProperties(JSONObject newConf) {
+        configFilesFacade.readCollectorProperties()
+            .onFailure(logSkip())
+            .onSuccess(oldProps -> compareAndOverwritePropertiesConfig(newConf, oldProps));
+    }
+
+    private void compareAndOverwritePropertiesConfig(JSONObject newConf, Map<String, String> oldProps) {
+        Map<String, String> newProperties = getProperties(newConf);
+        if (!oldProps.equals(newProperties)) {
+            configFilesFacade.writeProperties(newProperties)
+                .onSuccess(__ -> log.info("New properties configuration written to file"))
+                .onFailure(logSkip());
+        } else {
+            log.info("Collector properties from CBS are the same as currently used ones. " + SKIP_MSG);
+        }
+    }
+
+    private void compareAndOverwriteDMaaPConfig(JSONObject oldDMaaPConf, JSONObject newDMaaPConf) {
+        if (!oldDMaaPConf.toString().equals(newDMaaPConf.toString())) {
+            parseToDomainMapping(newDMaaPConf)
+                .onFailure(exc -> log.error(SKIP_MSG, exc))
+                .onSuccess(eventPublisherReconfigurer)
+                .onSuccess(parsedConfig ->
+                    configFilesFacade.writeDMaaPConfiguration(newDMaaPConf)
+                        .onFailure(logSkip())
+                        .onSuccess(__ -> log.info("New dMaaP configuration written to file")));
+        } else {
+            log.info("DMaaP config from CBS is the same as currently used one. " + SKIP_MSG);
+        }
+    }
+
+    private Consumer<Throwable> logSkip() {
+        return __ -> log.error(SKIP_MSG);
+    }
+}
diff --git a/src/main/java/org/onap/dcae/controller/ConfigParsing.java b/src/main/java/org/onap/dcae/controller/ConfigParsing.java
new file mode 100644 (file)
index 0000000..2ee0c91
--- /dev/null
@@ -0,0 +1,58 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2018 Nokia. 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.controller;
+
+import static io.vavr.API.Try;
+import static io.vavr.API.Tuple;
+import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.f;
+import static org.onap.dcae.controller.Conversions.toList;
+
+import io.vavr.collection.Map;
+import io.vavr.control.Option;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+interface ConfigParsing {
+
+    Logger log = LoggerFactory.getLogger(ConfigParsing.class);
+
+    static Option<JSONObject> getDMaaPConfig(JSONObject configuration) {
+        log.info(f("Getting DMaaP configuration from app configuration: '%s'", configuration));
+        return toList(configuration.toMap().entrySet().iterator())
+            .filter(t -> t.getKey().startsWith("streams_publishes"))
+            .headOption()
+            .flatMap(e -> Try(() -> configuration.getJSONObject(e.getKey())).toOption())
+            .onEmpty(() -> log.warn(f("App configuration '%s' is missing DMaaP configuration ('streams_publishes' key) "
+                + "or DMaaP configuration is not a valid json document", configuration)))
+            .peek(dMaaPConf -> log.info(f("Found following DMaaP configuration: '%s'", dMaaPConf)));
+    }
+
+    static Map<String, String> getProperties(JSONObject configuration) {
+        log.info(f("Getting properties configuration from app configuration: '%s'", configuration));
+        Map<String, String> confEntries = toList(configuration.toMap().entrySet().iterator())
+            .toMap(e -> Tuple(e.getKey(), String.valueOf(e.getValue())))
+            .filterKeys(e -> !e.startsWith("streams_publishes"));
+        log.info(f("Found following app properties: '%s'", confEntries));
+        return confEntries;
+    }
+
+}
diff --git a/src/main/java/org/onap/dcae/controller/ConfigSource.java b/src/main/java/org/onap/dcae/controller/ConfigSource.java
new file mode 100644 (file)
index 0000000..7e6a9fc
--- /dev/null
@@ -0,0 +1,88 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2018 Nokia. 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.controller;
+
+import static io.vavr.API.Try;
+import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.enhanceError;
+import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.f;
+import static org.onap.dcae.controller.Conversions.toJson;
+import static org.onap.dcae.controller.Conversions.toJsonArray;
+
+import com.mashape.unirest.http.Unirest;
+import io.vavr.control.Try;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class ConfigSource {
+
+    private static final Logger log = LoggerFactory.getLogger(ConfigSource.class);
+
+    static Try<JSONObject> getAppConfig(EnvProps envProps) {
+        log.info("Fetching app configuration from CBS");
+        return callConsulForCBSConfiguration(envProps)
+            .peek(strBody -> log.info(f("Received following CBS configuration from Consul '%s'", strBody)))
+            .flatMap(strBody -> toJsonArray(strBody))
+            .flatMap(json -> withdrawCatalog(json))
+            .flatMap(json -> constructFullCBSUrl(json))
+            .flatMap(cbsUrl -> callCBSForAppConfig(envProps, cbsUrl))
+            .flatMap(strBody -> toJson(strBody))
+            .peek(jsonNode -> log.info(f("Received app configuration: '%s'", jsonNode)))
+            .onFailure(exc -> log.error("Could not fetch application config", exc));
+    }
+
+    private static Try<String> callConsulForCBSConfiguration(EnvProps envProps) {
+        return executeGet(envProps.consulHost + ":" + envProps.consulPort + "/v1/catalog/service/" + envProps.cbsName)
+            .mapFailure(enhanceError("Unable to retrieve CBS configuration from Consul"));
+    }
+
+    private static Try<String> constructFullCBSUrl(JSONObject json) {
+        return Try(() -> json.get("ServiceAddress").toString() + ":" + json.get("ServicePort").toString())
+            .mapFailure(enhanceError("ServiceAddress / ServicePort missing from CBS conf: '%s'", json));
+    }
+
+    private static Try<JSONObject> withdrawCatalog(JSONArray json) {
+        return Try(() -> new JSONObject(json.get(0).toString()))
+            .mapFailure(enhanceError("CBS response '%s' is in invalid format,"
+                + " most probably is it not a list of configuration objects", json));
+    }
+
+    private static Try<String> callCBSForAppConfig(EnvProps envProps, String cbsUrl) {
+        log.info("Calling CBS for application config");
+        return executeGet(cbsUrl + "/service_component/" + envProps.appName)
+            .mapFailure(enhanceError("Unable to fetch configuration from CBS"));
+    }
+
+
+    private static Try<String> executeGet(String url) {
+        log.info(f("Calling HTTP GET on url: '%s'", url));
+        return Try(() -> Unirest.get(url).asString())
+            .mapFailure(enhanceError("Http call (GET '%s') failed.", url))
+            .filter(
+                res -> res.getStatus() == 200,
+                res -> new RuntimeException(f("HTTP call (GET '%s') failed with status %s and body '%s'",
+                    url, res.getStatus(), res.getBody())))
+            .map(res -> res.getBody())
+            .peek(body -> log.info(f("HTTP GET on '%s' returned body '%s'", url, body)));
+    }
+
+}
diff --git a/src/main/java/org/onap/dcae/controller/Conversions.java b/src/main/java/org/onap/dcae/controller/Conversions.java
new file mode 100644 (file)
index 0000000..09a9a43
--- /dev/null
@@ -0,0 +1,53 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2018 Nokia. 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.controller;
+
+import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.enhanceError;
+
+import io.vavr.API;
+import io.vavr.collection.List;
+import io.vavr.control.Try;
+import java.util.Iterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.StreamSupport;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+/**
+ * @author Pawel Szalapski (pawel.szalapski@nokia.com)
+ */
+interface Conversions {
+
+    static Try<JSONObject> toJson(String strBody) {
+        return API.Try(() -> new JSONObject(strBody))
+            .mapFailure(enhanceError("Value '%s' is not a valid JSON document", strBody));
+    }
+
+    static Try<JSONArray> toJsonArray(String strBody) {
+        return API.Try(() -> new JSONArray(strBody))
+            .mapFailure(enhanceError("Value '%s' is not a valid JSON array", strBody));
+    }
+
+    static <T> List<T> toList(Iterator<T> iterator) {
+        return List.ofAll(StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false));
+    }
+
+}
diff --git a/src/main/java/org/onap/dcae/controller/EnvPropertiesReader.java b/src/main/java/org/onap/dcae/controller/EnvPropertiesReader.java
new file mode 100644 (file)
index 0000000..23bcbda
--- /dev/null
@@ -0,0 +1,77 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2018 Nokia. 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.controller;
+
+import static io.vavr.API.List;
+import static io.vavr.API.Try;
+import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.f;
+
+import io.vavr.collection.Map;
+import io.vavr.control.Option;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class EnvPropertiesReader {
+
+    private final static Logger log = LoggerFactory.getLogger(EnvPropertiesReader.class);
+
+    static Option<EnvProps> readEnvProps(Map<String, String> environmentVariables) {
+        log.info("Loading necessary environment variables for dynamic configuration update");
+        int consulPort = getConsulPort(environmentVariables);
+        Option<String> consulHost = getConsulHost(environmentVariables);
+        Option<String> cbsServiceName = getCBSName(environmentVariables);
+        Option<String> vesCollectorAppName = getAppName(environmentVariables);
+        return Option.sequence(List(consulHost, cbsServiceName, vesCollectorAppName))
+            .map(e -> new EnvProps(e.get(0), consulPort, e.get(1), e.get(2)))
+            .onEmpty(() -> log.warn("Some required environment variables are missing"))
+            .peek(props -> log.info(f("Discovered following environment variables: '%s'", props)));
+    }
+
+    private static Option<String> getAppName(Map<String, String> environmentVariables) {
+        return environmentVariables.get("HOSTNAME")
+            .orElse(environmentVariables.get("SERVICE_NAME"))
+            .onEmpty(() -> log.warn("App service name (as registered in CBS) (env var: 'HOSTNAME' / 'SERVICE_NAME') "
+                + "is missing error environment variables."));
+    }
+
+    private static Option<String> getCBSName(Map<String, String> environmentVariables) {
+        return environmentVariables.get("CONFIG_BINDING_SERVICE")
+            .onEmpty(() -> log.warn("Name of CBS Service (as registered in Consul) (env var: 'CONFIG_BINDING_SERVICE') "
+                + "is missing from environment variables."));
+    }
+
+    private static Integer getConsulPort(Map<String, String> environmentVariables) {
+        return environmentVariables.get("CONSUL_PORT")
+            .flatMap(str -> Try(() -> Integer.valueOf(str))
+                .onFailure(exc -> log.warn("Consul port is not an integer value", exc))
+                .toOption())
+            .onEmpty(() -> log.warn("Consul port (env var: 'CONSUL_PORT') is missing from environment variables. "
+                + "Using default value of 8500"))
+            .getOrElse(8500);
+    }
+
+    private static Option<String> getConsulHost(Map<String, String> environmentVariables) {
+        return environmentVariables.get("CONSUL_HOST")
+            .onEmpty(() -> log.warn("Consul host (env var: 'CONSUL_HOST') (without port) "
+                + "is missing from environment variables."));
+    }
+
+}
diff --git a/src/main/java/org/onap/dcae/controller/EnvProps.java b/src/main/java/org/onap/dcae/controller/EnvProps.java
new file mode 100644 (file)
index 0000000..2ee41cc
--- /dev/null
@@ -0,0 +1,70 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2018 Nokia. 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.controller;
+
+import java.util.Objects;
+
+/**
+ * @author Pawel Szalapski (pawel.szalapski@nokia.com)
+ */
+final class EnvProps {
+
+    final String consulHost;
+    final int consulPort;
+    final String cbsName;
+    final String appName;
+
+    EnvProps(String consulHost, int consulPort, String cbsName, String appName) {
+        this.consulHost = consulHost;
+        this.consulPort = consulPort;
+        this.cbsName = cbsName;
+        this.appName = appName;
+    }
+
+    @Override
+    public String toString() {
+        return "EnvProps{" +
+            "consulHost='" + consulHost + '\'' +
+            ", consulPort=" + consulPort +
+            ", cbsName='" + cbsName + '\'' +
+            ", appName='" + appName + '\'' +
+            '}';
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        EnvProps envProps = (EnvProps) o;
+        return consulPort == envProps.consulPort &&
+            Objects.equals(consulHost, envProps.consulHost) &&
+            Objects.equals(cbsName, envProps.cbsName) &&
+            Objects.equals(appName, envProps.appName);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(consulHost, consulPort, cbsName, appName);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/onap/dcae/controller/FetchDynamicConfig.java b/src/main/java/org/onap/dcae/controller/FetchDynamicConfig.java
deleted file mode 100644 (file)
index ed42a5a..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*-\r
- * ============LICENSE_START=======================================================\r
- * PROJECT\r
- * ================================================================================\r
- * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.\r
- * ================================================================================\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- * ============LICENSE_END=========================================================\r
- */\r
-\r
-package org.onap.dcae.controller;\r
-\r
-import com.fasterxml.jackson.databind.JsonNode;\r
-import com.fasterxml.jackson.databind.ObjectMapper;\r
-import org.json.JSONArray;\r
-import org.json.JSONObject;\r
-import org.json.JSONTokener;\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-\r
-import java.io.*;\r
-import java.util.Map;\r
-\r
-public class FetchDynamicConfig {\r
-\r
-    private static final Logger log = LoggerFactory.getLogger(FetchDynamicConfig.class);\r
-\r
-    public static String configFile = "/opt/app/KV-Configuration.json";\r
-    public static String retString;\r
-    public static String retCBSString;\r
-    private static String url;\r
-    private static Map<String, String> env;\r
-\r
-    public FetchDynamicConfig() {\r
-    }\r
-\r
-    public static void main(String[] args) {\r
-        Boolean areEqual;\r
-        // Call consul api and identify the CBS Service address and port\r
-        getconsul();\r
-        // Construct and invoke CBS API to get application Configuration\r
-        getCBS();\r
-        // Verify if data has changed\r
-        areEqual = verifyConfigChange();\r
-        // If new config then write data returned into configFile for\r
-        // LoadDynamicConfig process\r
-        if (!areEqual) {\r
-            FetchDynamicConfig fc = new FetchDynamicConfig();\r
-            fc.writefile(retCBSString);\r
-        } else {\r
-            log.info("New config pull results identical -  " + configFile + " NOT refreshed");\r
-        }\r
-    }\r
-\r
-    private static void getconsul() {\r
-\r
-        env = System.getenv();\r
-        for (Map.Entry<String, String> entry : env.entrySet()) {\r
-            log.info(entry.getKey() + ":" + entry.getValue());\r
-        }\r
-\r
-        if (env.containsKey("CONSUL_HOST") && env.containsKey("CONFIG_BINDING_SERVICE")) {\r
-            // && env.containsKey("HOSTNAME")) {\r
-            log.info(">>>Dynamic configuration to be fetched from ConfigBindingService");\r
-            url = env.get("CONSUL_HOST") + ":8500/v1/catalog/service/" + env.get("CONFIG_BINDING_SERVICE");\r
-\r
-            retString = executecurl(url);\r
-\r
-        } else {\r
-            log.info(">>>Static configuration to be used");\r
-        }\r
-\r
-    }\r
-\r
-    public static boolean verifyConfigChange() {\r
-\r
-        boolean areEqual = false;\r
-        // Read current data\r
-        try {\r
-            File f = new File(configFile);\r
-            if (f.exists() && !f.isDirectory()) {\r
-\r
-                String jsonData = LoadDynamicConfig.readFile(configFile);\r
-                JSONObject jsonObject = new JSONObject(jsonData);\r
-\r
-                ObjectMapper mapper = new ObjectMapper();\r
-\r
-                JsonNode tree1 = mapper.readTree(jsonObject.toString());\r
-                JsonNode tree2 = mapper.readTree(retCBSString);\r
-                areEqual = tree1.equals(tree2);\r
-                log.info("Comparison value:" + areEqual);\r
-            } else {\r
-                log.info("First time config file read: " + configFile);\r
-            }\r
-\r
-        } catch (IOException e) {\r
-            log.error("Comparison with new fetched data failed" + e.getMessage());\r
-\r
-        }\r
-\r
-        return areEqual;\r
-\r
-    }\r
-\r
-    public static void getCBS() {\r
-\r
-        env = System.getenv();\r
-        // consul return as array\r
-        JSONTokener temp = new JSONTokener(retString);\r
-        JSONObject cbsjobj = (JSONObject) new JSONArray(temp).get(0);\r
-\r
-        String urlPart1 = null;\r
-        if (cbsjobj.has("ServiceAddress") && cbsjobj.has("ServicePort")) {\r
-            urlPart1 = cbsjobj.getString("ServiceAddress") + ":" + cbsjobj.getInt("ServicePort");\r
-        }\r
-\r
-        log.info("CONFIG_BINDING_SERVICE DNS RESOLVED:" + urlPart1);\r
-\r
-        if (env.containsKey("HOSTNAME")) {\r
-            url = urlPart1 + "/service_component/" + env.get("HOSTNAME");\r
-            retCBSString = executecurl(url);\r
-        } else if (env.containsKey("SERVICE_NAME")) {\r
-            url = urlPart1 + "/service_component/" + env.get("SERVICE_NAME");\r
-            retCBSString = executecurl(url);\r
-        } else {\r
-            log.error("Service name environment variable - HOSTNAME/SERVICE_NAME not found within container ");\r
-        }\r
-\r
-    }\r
-\r
-    private static String executecurl(String url) {\r
-\r
-        String[] command = {"curl", "-v", url};\r
-        ProcessBuilder process = new ProcessBuilder(command);\r
-        Process p;\r
-        String result = null;\r
-        try {\r
-            p = process.start();\r
-            InputStreamReader ipr = new InputStreamReader(p.getInputStream());\r
-            BufferedReader reader = new BufferedReader(ipr);\r
-            StringBuilder builder = new StringBuilder();\r
-            String line;\r
-\r
-            while ((line = reader.readLine()) != null) {\r
-                builder.append(line);\r
-            }\r
-            result = builder.toString();\r
-            log.info(result);\r
-\r
-            reader.close();\r
-            ipr.close();\r
-        } catch (IOException e) {\r
-            log.error("error", e);\r
-            e.printStackTrace();\r
-        }\r
-        return result;\r
-\r
-    }\r
-\r
-    public void writefile(String retCBSString) {\r
-        log.info("URL to fetch configuration:" + url + " Return String:" + retCBSString);\r
-\r
-        String indentedretstring = (new JSONObject(retCBSString)).toString(4);\r
-\r
-        try (FileWriter file = new FileWriter(FetchDynamicConfig.configFile)) {\r
-            file.write(indentedretstring);\r
-\r
-            log.info("Successfully Copied JSON Object to file " + configFile);\r
-        } catch (IOException e) {\r
-            log.error("Error in writing configuration into file " + configFile + retString + e.getMessage());\r
-            e.printStackTrace();\r
-        }\r
-\r
-    }\r
-\r
-}\r
diff --git a/src/main/java/org/onap/dcae/controller/LoadDynamicConfig.java b/src/main/java/org/onap/dcae/controller/LoadDynamicConfig.java
deleted file mode 100644 (file)
index c1ab80c..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * PROJECT
- * ================================================================================
- * Copyright (C) 2017-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.controller;
-
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.PropertiesConfiguration;
-import org.json.JSONObject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.Map;
-
-public class LoadDynamicConfig {
-
-    private static final Logger log = LoggerFactory.getLogger(LoadDynamicConfig.class);
-
-    public String propFile = "collector.properties";
-    public String configFile = "/opt/app/KV-Configuration.json";
-    public String dMaaPOutputFile = "./etc/DmaapConfig.json";
-
-    public LoadDynamicConfig() {
-
-    }
-
-    public static void main(String[] args) {
-        Map<String, String> env = System.getenv();
-
-        // Check again to ensure new controller deployment related config
-        if (env.containsKey("CONSUL_HOST") && env.containsKey("CONFIG_BINDING_SERVICE")
-                && env.containsKey("HOSTNAME")) {
-
-            try {
-
-                LoadDynamicConfig lc = new LoadDynamicConfig();
-                String jsonData = readFile(lc.configFile);
-                JSONObject jsonObject = new JSONObject(jsonData);
-                lc.writeconfig(jsonObject);
-
-
-            } catch (Exception e) {
-                log.error(e.getLocalizedMessage(), e);
-                e.printStackTrace();
-
-            }
-
-        } else {
-            log.info(">>>Static configuration to be used");
-        }
-
-    }
-
-    public static String readFile(String filename) {
-        String result = "";
-        try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
-            StringBuilder sb = new StringBuilder();
-            String line = br.readLine();
-            while (line != null) {
-                sb.append(line);
-                line = br.readLine();
-            }
-            result = sb.toString();
-        } catch (Exception e) {
-            log.error(e.getLocalizedMessage(), e);
-            e.printStackTrace();
-        }
-        return result;
-    }
-
-    public void writeconfig(JSONObject jsonObject) {
-
-        PropertiesConfiguration conf;
-        try {
-            conf = new PropertiesConfiguration(propFile);
-
-            conf.setEncoding(null);
-
-            // update properties based on consul dynamic configuration
-            Iterator<?> keys = jsonObject.keys();
-
-            while (keys.hasNext()) {
-                String key = (String) keys.next();
-                // check if any configuration is related to dmaap
-                // and write into dmaapconfig.json
-                if (key.startsWith("streams_publishes")) {
-                    // VESCollector only have publish streams
-                    try (FileWriter file = new FileWriter(dMaaPOutputFile)) {
-                        String indentedretstring = (new JSONObject(jsonObject.get(key).toString())).toString(4);
-                        file.write(indentedretstring);
-                        log.info("Successfully written JSON Object to DmaapConfig.json");
-                    } catch (IOException e) {
-                        log.info("Error in writing dmaap configuration into DmaapConfig.json", e);
-                    }
-                } else {
-                    conf.setProperty(key, jsonObject.get(key).toString());
-                }
-
-            }
-            conf.save();
-        } catch (ConfigurationException e) {
-            log.error(e.getLocalizedMessage(), e);
-            e.printStackTrace();
-        }
-    }
-
-}
diff --git a/src/main/java/org/onap/dcae/controller/PreAppStartupConfigUpdater.java b/src/main/java/org/onap/dcae/controller/PreAppStartupConfigUpdater.java
new file mode 100644 (file)
index 0000000..c5ee9d8
--- /dev/null
@@ -0,0 +1,49 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2018 Nokia. 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.controller;
+
+import io.vavr.collection.Map;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.function.Consumer;
+import org.onap.dcae.commonFunction.event.publishing.PublisherConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * On the first application launch, the configuration update thread that application spawns, has no chance to run yet
+ * and prepare initial application configuration. In this case, it needs to be fetched from outside of the application,
+ * so this is run from the .sh script.
+ * Later on, once application is already started it will take care of the configuration update itself
+ * @author Pawel Szalapski (pawel.szalapski@nokia.com)
+ */
+public class PreAppStartupConfigUpdater {
+    private final static Logger log = LoggerFactory.getLogger(PreAppStartupConfigUpdater.class);
+
+    private static final Path DEFAULT_CONFIGURATION_FILE_PATH = Paths.get("etc/collector.properties");
+    private static final Path DEFAULT_DMAAP_FILE_PATH = Paths.get("etc/DmaapConfig.json");
+    private static final Consumer<Map<String, PublisherConfig>> NO_OP_CONSUMER = c -> { };
+
+    public static void main(String[] args) {
+        log.info("Running initial configuration update, before the application gets started.");
+        ConfigLoader.create(NO_OP_CONSUMER, DEFAULT_DMAAP_FILE_PATH, DEFAULT_CONFIGURATION_FILE_PATH)
+            .updateConfig();
+    }
+}
index b7fc5f3..92e8d00 100644 (file)
@@ -23,7 +23,6 @@ package org.onap.dcae.restapi;
 
 import static java.util.Optional.ofNullable;
 import static java.util.stream.StreamSupport.stream;
-import static org.springframework.http.ResponseEntity.accepted;
 import static org.springframework.http.ResponseEntity.ok;
 
 import com.att.nsa.clock.SaClock;
diff --git a/src/main/scripts/VESConfigPoller.sh b/src/main/scripts/VESConfigPoller.sh
deleted file mode 100644 (file)
index 75c2b58..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-#!/bin/sh -x
-###
-# ============LICENSE_START=======================================================
-# PROJECT
-# ================================================================================
-# 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=========================================================
-###
-# redirect stdout/stderr to a file
-#exec &> /opt/app/VESCollector/logs/console.txt
-
-usage() {
-        echo "VESConfigPoller.sh"
-}
-
-
-## Remove singel execution logic (loop 0)
-## On configupdate function, remove LoadDynamicConfig and invoke VESrestfulCollector stop/start
-
-BASEDIR=/opt/app/VESCollector/
-CONFIGFILENAME=/opt/app/KV-Configuration.json
-
-
-collector_configupdate() {
-
-        echo `date +"%Y%m%d.%H%M%S%3N"` - VESConfigPoller.sh:collector_configupdate
-        if [ -z "$CONSUL_HOST" ] || [ -z "$CONFIG_BINDING_SERVICE" ] || [ -z "$HOSTNAME" ]; then
-                echo "INFO: USING STANDARD CONTROLLER CONFIGURATION"
-        else
-            # move into base directory
-            cd $BASEDIR
-
-            CONFIG_FETCH=org.onap.dcae.controller.FetchDynamicConfig
-            $JAVA -cp "etc${PATHSEP}lib/*"  $CONFIG_FETCH $*
-            if [ $? -ne 0 ]; then
-                echo "ERROR: Failed to fetch dynamic configuration from consul into container $CONFIGFILENAME"
-            else
-               echo "INFO: Dynamic config fetched successfully"
-            fi
-                sleep 10s
-                FLAG=0
-
-            if [ -f $CONFIGFILENAME ]; then
-                if [[ $(find $CONFIGFILENAME -mmin -$CBSPOLLTIMER -print) ]]; then
-                        echo "File  $CONFIGFILENAME  is updated under $CBSPOLLTIMER minutes; Loader to be invoked"
-                        FLAG=1
-                else
-                        echo "File  $CONFIGFILENAME  NOT updated in last $CBSPOLLTIMER minutes; no configuration update!"
-                        FLAG=0
-                fi
-
-                if [ $FLAG -eq 1 ]; then
-                        echo "INFO: CONFIGFILE updated; triggering restart"
-                        /opt/app/VESCollector/bin/VESrestfulCollector.sh stop
-                        /opt/app/VESCollector/bin/VESrestfulCollector.sh start &
-                else
-                        echo "INFO: CONFIGFILE load skipped"
-                fi
-            else
-                echo "ERROR: Configuration file $CONFIGFILENAME missing"
-            fi
-        fi
-}
-
-
-
-if [ -z "$CBSPOLLTIMER" ]; then
-        echo "CBSPOLLTIMER not set; set this to polling frequency in minutes"
-        exit 1
-fi
-
-
-## Pre-setting
-
-# use JAVA_HOME if provided
-if [ -z "$JAVA_HOME" ]; then
-        echo "ERROR: JAVA_HOME not setup"
-        echo "Startup Aborted!!"
-        exit 1
-        #JAVA=java
-else
-        JAVA=$JAVA_HOME/bin/java
-fi
-
-
-
-# determine a path separator that works for this platform
-PATHSEP=":"
-case "$(uname -s)" in
-
-        Darwin)
-                ;;
-
-         Linux)
-                ;;
-
-         CYGWIN*|MINGW32*|MSYS*)
-                PATHSEP=";"
-                ;;
-
-        *)
-                ;;
-esac
-
-
-
-##Run in loop the config pull and check
-while true
-do
-        sleep $(echo $CBSPOLLTIMER)m
-        collector_configupdate | tee -a ${BASEDIR}/logs/console.txt
-done
-
diff --git a/src/main/scripts/VESrestfulCollector.sh b/src/main/scripts/VESrestfulCollector.sh
deleted file mode 100644 (file)
index 7f6d17c..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/bin/bash\r
-\r
-###\r
-# ============LICENSE_START=======================================================\r
-# PROJECT\r
-# ================================================================================\r
-# Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.\r
-# Copyright (C) 2018 Nokia Networks Intellectual Property. All rights reserved.\r
-# ================================================================================\r
-# Licensed under the Apache License, Version 2.0 (the "License");\r
-# you may not use this file except in compliance with the License.\r
-# You may obtain a copy of the License at\r
-#\r
-#      http://www.apache.org/licenses/LICENSE-2.0\r
-#\r
-# Unless required by applicable law or agreed to in writing, software\r
-# distributed under the License is distributed on an "AS IS" BASIS,\r
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-# See the License for the specific language governing permissions and\r
-# limitations under the License.\r
-# ============LICENSE_END=========================================================\r
-###\r
-source bin/logger.sh\r
-\r
-start() {\r
-    log "Starting application"\r
-    appPids=`pidof java`\r
-\r
-    if [ ! -z ${appPids} ]; then\r
-        logWarn "Tried to start an application, but it is already running on PID(s): ${appPids}. Startup aborted."\r
-        exit 1\r
-    fi\r
-\r
-    ${JAVA_HOME}/bin/java -cp "etc:lib/*" \\r
-      -Xms256m -Xmx512m \\r
-      -XX:ErrorFile=logs/java_error%p.log \\r
-      -XX:+HeapDumpOnOutOfMemoryError \\r
-      -Dhttps.protocols=TLSv1.1,TLSv1.2 \\r
-      org.onap.dcae.VesApplication $* & &>> logs/collector.log\r
-}\r
-\r
-stop() {\r
-    log "Stopping application"\r
-    appPids=`pidof java`\r
-\r
-    if [ ! -z ${appPids} ]; then\r
-        echo "Killing java PID(s): ${appPids}"\r
-        kill -9 ${appPids}\r
-        sleep 5\r
-        if [ ! $(pidof java) ]; then\r
-            log "Application stopped"\r
-        else\r
-            logWarn "Application did not stop after 5 seconds"\r
-        fi\r
-    else\r
-        logWarn "Tried to stop an application, but it was not running";\r
-    fi\r
-}\r
-\r
-collector_configupdate() {\r
-    if [ -z ${CONSUL_HOST} ] || [ -z ${CONFIG_BINDING_SERVICE} ] || [ -z ${HOSTNAME} ]; then\r
-        log "Using standard controller configuration (no dynamic configuration done)"\r
-    else\r
-        ${JAVA_HOME}/bin/java -cp "etc:lib/*" org.onap.dcae.controller.FetchDynamicConfig $*\r
-\r
-        if [ $? -ne 0 ]; then\r
-            logWarn "Failed to fetch dynamic configuration from consul into container /opt/app/KV-Configuration.json"\r
-        else\r
-            log "Dynamic config fetched and written successfully into container /opt/app/KV-Configuration.json"\r
-        fi\r
-\r
-        if [ -f /opt/app/KV-Configuration.json ]; then\r
-            ${JAVA_HOME}/bin/java -cp "etc:lib/*" org.onap.dcae.controller.LoadDynamicConfig $*\r
-            if [ $? -ne 0 ]; then\r
-                echo "ERROR: Failed to update dynamic configuration into Application"\r
-            else\r
-                echo "INFO: Dynamic config updated successfully into VESCollector configuration!"\r
-            fi\r
-            paramName="collector.keystore.alias"\r
-            localpropertyfile="etc/collector.properties"\r
-            tmpfile="etc/collector.properties.tmp"\r
-            keystore=`grep collector.keystore.file.location $localpropertyfile | tr -d '[:space:]' | cut -d"=" -f2`\r
-            keypwdfile=`grep collector.keystore.passwordfile $localpropertyfile | tr -d '[:space:]' | cut -d"=" -f2`\r
-            echo "/usr/bin/keytool -list -keystore $keystore < $keypwdfile | grep "PrivateKeyEntry" | cut -d"," -f1"\r
-            tmpalias=`/usr/bin/keytool -list -keystore $keystore < $keypwdfile | grep "PrivateKeyEntry" | cut -d"," -f1`\r
-            alias=`echo $tmpalias | cut -d":" -f2`\r
-            sed "s~$paramName=.*~$paramName=$alias~g" $localpropertyfile > $tmpfile\r
-            echo `cat $tmpfile > $localpropertyfile`\r
-            rm $tmpfile\r
-            log "Keystore alias updated"\r
-        else\r
-            logWarn "Configuration file /opt/app/KV-Configuration.json missing"\r
-        fi\r
-    fi\r
-}\r
-\r
-case $1 in\r
-  "start") collector_configupdate; start ;;\r
-  "stop")  stop ;;\r
-  *)       echo "Bad usage. Should be: /bin/bash <this> start/stop"\r
-esac\r
-\r
diff --git a/src/main/scripts/appController.sh b/src/main/scripts/appController.sh
new file mode 100644 (file)
index 0000000..d141add
--- /dev/null
@@ -0,0 +1,86 @@
+#!/bin/bash
+
+###
+# ============LICENSE_START=======================================================
+# PROJECT
+# ================================================================================
+# Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+# Copyright (C) 2018 Nokia Networks 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=========================================================
+###
+source bin/logger.sh
+
+updateKeystore() {
+    log "Updating keystore configuration"
+    aliasParameterName="collector.keystore.alias"
+    originalPropertyFile="etc/collector.properties"
+    temporaryPropertyFile="etc/collector.properties.tmp"
+    keystorePath=`grep collector.keystore.file.location ${originalPropertyFile} | tr -d '[:space:]' | cut -d"=" -f2`
+    keystorePasswordFile=`grep collector.keystore.passwordfile ${originalPropertyFile} | tr -d '[:space:]' | cut -d"=" -f2`
+    temporaryAlias=`/usr/bin/keytool -list -keystore $keystorePath < $keystorePasswordFile | grep "PrivateKeyEntry" | cut -d"," -f1`
+    newAlias=`echo $temporaryAlias | cut -d":" -f2`
+    sed "s~$aliasParameterName=.*~$aliasParameterName=$newAlias~g" ${originalPropertyFile} > ${temporaryPropertyFile}
+    echo `cat ${temporaryPropertyFile} > ${originalPropertyFile}`
+    rm ${temporaryPropertyFile}
+    log "Keystore configuration updated"
+}
+
+tryToPollConfiguration() {
+    log "Trying to poll configuration from CBS before application starts"
+    ${JAVA_HOME}/bin/java -cp "etc:lib/*" org.onap.dcae.controller.PreAppStartupConfigUpdater
+}
+
+start() {
+    log "Starting application"
+    appPids=`pidof java`
+
+    if [ ! -z ${appPids} ]; then
+        logWarn "Tried to start an application, but it is already running on PID(s): ${appPids}. Startup aborted."
+        exit 1
+    fi
+
+    ${JAVA_HOME}/bin/java -cp "etc:lib/*" \
+      -Xms256m -Xmx512m \
+      -XX:ErrorFile=logs/java_error%p.log \
+      -XX:+HeapDumpOnOutOfMemoryError \
+      -Dhttps.protocols=TLSv1.1,TLSv1.2 \
+      org.onap.dcae.VesApplication $* & &>> logs/collector.log
+}
+
+stop() {
+    log "Stopping application"
+    appPids=`pidof java`
+
+    if [ ! -z ${appPids} ]; then
+        echo "Killing java PID(s): ${appPids}"
+        kill -9 ${appPids}
+        sleep 5
+        if [ ! $(pidof java) ]; then
+            log "Application stopped"
+        else
+            logWarn "Application did not stop after 5 seconds"
+        fi
+    else
+        logWarn "Tried to stop an application, but it was not running";
+    fi
+}
+
+case $1 in
+  "start")    tryToPollConfiguration; updateKeystore; start ;;
+  "stop")     stop ;;
+  "restart")  stop; start ;;
+  *)          echo "Bad usage. Should be: /bin/bash <this> start/stop"
+esac
+
diff --git a/src/main/scripts/configurationPoller.sh b/src/main/scripts/configurationPoller.sh
new file mode 100644 (file)
index 0000000..59dbf84
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/bash
+###
+# ============LICENSE_START=======================================================
+# PROJECT
+# ================================================================================
+# 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=========================================================
+###
+source bin/logger.sh
+
+# This scripts job is to continuously run in background and watch for changes in collector.properties
+# and in case it has changed, restart application.
+# collector.properties (and DmaapConfig.json) is being updated periodically by calling for configuration from CBS and it is
+# done inside the VESCollector application itself.
+# Configuration poller can be run regardless of deployment type.
+# It will always check for changes in collector.properties and in deployment scenario,
+# where dynamic configuration should not be used, necessary environment
+# variables that are needed (consul host, cbs name, app name) will be missing, and java app will
+# not update the configuration files so restart won't be triggered.
+
+# Start after a while, because once the application starts, it might happen that
+# it fetched new configuration. In that case, the application will already be started with newest config, there would
+# be no point in restarting it once again.
+sleep 2m
+
+while true
+do
+    sleep 1m
+    if [[ $(find etc/collector.properties -mmin -1 -print) ]]; then
+        log "Found change in collector.properties, updating keystore and restarting application"
+        bin/appController.sh restart
+    fi
+done
+
index 0aad758..c17dd95 100644 (file)
@@ -1,66 +1,63 @@
-#!/bin/bash\r
-###\r
-# ============LICENSE_START=======================================================\r
-# PROJECT\r
-# ================================================================================\r
-# Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.\r
-# Copyright (C) 2018 Nokia Networks Intellectual Property. All rights reserved.\r
-# ================================================================================\r
-# Licensed under the Apache License, Version 2.0 (the "License");\r
-# you may not use this file except in compliance with the License.\r
-# You may obtain a copy of the License at\r
-#\r
-#      http://www.apache.org/licenses/LICENSE-2.0\r
-#\r
-# Unless required by applicable law or agreed to in writing, software\r
-# distributed under the License is distributed on an "AS IS" BASIS,\r
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-# See the License for the specific language governing permissions and\r
-# limitations under the License.\r
-# ============LICENSE_END=========================================================\r
-###\r
-source bin/logger.sh\r
-\r
-# Redirect all stdout & stderr to a main log file, but also let it print into the console\r
-# At the time this script is invoked, these directories and files do not exist yet, so we need to create them\r
-mkdir -p logs\r
-touch logs/collector.log\r
-exec &> >(tee -a logs/collector.log)\r
-\r
-log "Enabling log rotation for collector.log"\r
-loggedCommand "cp etc/logrotate.conf /etc/logrotate.d"\r
-echo "* *      * * *   root    logrotate /etc/logrotate.conf" >> /etc/crontab\r
-log "Restarting cron"\r
-loggedCommand "service cron reload"\r
-loggedCommand "service cron start"\r
-\r
-log "Main application entry-point invoked"\r
-\r
-if [ ! -z ${COLLECTOR_IP} ]; then\r
-    log "Collector ip (${COLLECTOR_IP}) (env var 'COLLECTOR_IP') found, adding entry to /etc/hosts"\r
-    echo ${COLLECTOR_IP}  $(hostname).dcae.simpledemo.onap.org >> /etc/hosts\r
-fi\r
-\r
-if [ ! -z ${DMAAPHOST} ]; then\r
-    if [ -z "$(echo ${DMAAPHOST} | sed -e 's/[0-9\.]//g')" ]; then\r
-        log "DMaaP host (${DMAAPHOST}) (env var 'DMAAPHOST') found, adding entry to /etc/hosts"\r
-        echo "${DMAAPHOST}  onap-dmaap" >> /etc/hosts\r
-    else\r
-        log "DMaaP host (${DMAAPHOST}) (env var 'DMAAPHOST') found, adding entry to /etc/host.aliases"\r
-        echo "onap-dmaap ${DMAAPHOST}" >> /etc/host.aliases\r
-    fi\r
-else\r
-       logWarn "DMaaP host (env var 'DMAAPHOST') is missing. Events will not be published to DMaaP"\r
-fi\r
-\r
-log "Scheduling application to be started, looping indefinitely to hold the docker process"\r
-bin/VESrestfulCollector.sh stop\r
-bin/VESrestfulCollector.sh start &\r
-\r
-# Add below if config polling should be enabled. More specific to K8 deployment in ONAP\r
-if [ ! -z ${CBSPOLLTIMER} ]; then\r
-    log "Configuration poll time (${CBSPOLLTIMER}) (env var 'CBSPOLLTIMER') found, enabling configuration polling from CBS"\r
-    bin/VESConfigPoller.sh &\r
-fi\r
-\r
-while true; do sleep 1000; done\r
+#!/bin/bash
+###
+# ============LICENSE_START=======================================================
+# PROJECT
+# ================================================================================
+# Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+# Copyright (C) 2018 Nokia Networks 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=========================================================
+###
+source bin/logger.sh
+
+# Redirect all stdout & stderr to a main log file, but also let it print into the console
+# At the time this script is invoked, these directories and files do not exist yet, so we need to create them
+mkdir -p logs
+touch logs/collector.log
+exec &> >(tee -a logs/collector.log)
+
+log "Enabling log rotation for collector.log"
+loggedCommand "cp etc/logrotate.conf /etc/logrotate.d"
+echo "* *      * * *   root    logrotate /etc/logrotate.conf" >> /etc/crontab
+log "Restarting cron"
+loggedCommand "service cron reload"
+loggedCommand "service cron start"
+
+log "Main application entry-point invoked"
+
+if [ ! -z ${COLLECTOR_IP} ]; then
+    log "Collector ip (${COLLECTOR_IP}) (env var 'COLLECTOR_IP') found, adding entry to /etc/hosts"
+    echo ${COLLECTOR_IP}  $(hostname).dcae.simpledemo.onap.org >> /etc/hosts
+fi
+
+if [ ! -z ${DMAAPHOST} ]; then
+    if [ -z "$(echo ${DMAAPHOST} | sed -e 's/[0-9\.]//g')" ]; then
+        log "DMaaP host (${DMAAPHOST}) (env var 'DMAAPHOST') found, adding entry to /etc/hosts"
+        echo "${DMAAPHOST}  onap-dmaap" >> /etc/hosts
+    else
+        log "DMaaP host (${DMAAPHOST}) (env var 'DMAAPHOST') found, adding entry to /etc/host.aliases"
+        echo "onap-dmaap ${DMAAPHOST}" >> /etc/host.aliases
+    fi
+else
+       logWarn "DMaaP host (env var 'DMAAPHOST') is missing. Events will not be published to DMaaP"
+fi
+
+log "Scheduling application to be started, looping indefinitely to hold the docker process"
+bin/appController.sh stop
+bin/appController.sh start &
+
+log "Enabling configuration polling from CBS"
+bin/configurationPoller.sh &
+
+while true; do sleep 1000; done
index b483bcb..2ac4208 100644 (file)
@@ -148,6 +148,26 @@ public class ApplicationSettingsTest {
         assertEquals(8443, httpsPort);
     }
 
+    @Test
+    public void shouldReturnConfigurationUpdateInterval() throws IOException {
+        // when
+        int updateFrequency = fromTemporaryConfiguration("collector.dynamic.config.update.frequency=10")
+                .configurationUpdateFrequency();
+
+        // then
+        assertEquals(10, updateFrequency);
+    }
+
+    @Test
+    public void shouldReturnDefaultConfigurationUpdateInterval() throws IOException {
+        // when
+        int updateFrequency = fromTemporaryConfiguration()
+                .configurationUpdateFrequency();
+
+        // then
+        assertEquals(5, updateFrequency);
+    }
+
     @Test
     public void shouldReturnLocationOfThePasswordFile() throws IOException {
         // when
@@ -207,7 +227,7 @@ public class ApplicationSettingsTest {
     @Test
     public void shouldReturnDMAAPConfigFileLocation() throws IOException {
         // when
-        String dmaapConfigFileLocation = fromTemporaryConfiguration("collector.dmaapfile=/somewhere/dmaapFile").cambriaConfigurationFileLocation();
+        String dmaapConfigFileLocation = fromTemporaryConfiguration("collector.dmaapfile=/somewhere/dmaapFile").dMaaPConfigurationFileLocation();
 
         // then
         assertEquals(sanitizePath("/somewhere/dmaapFile"), dmaapConfigFileLocation);
@@ -216,7 +236,7 @@ public class ApplicationSettingsTest {
     @Test
     public void shouldReturnDefaultDMAAPConfigFileLocation() throws IOException {
         // when
-        String dmaapConfigFileLocation = fromTemporaryConfiguration().cambriaConfigurationFileLocation();
+        String dmaapConfigFileLocation = fromTemporaryConfiguration().dMaaPConfigurationFileLocation();
 
         // then
         assertEquals(sanitizePath("etc/DmaapConfig.json"), dmaapConfigFileLocation);
@@ -390,7 +410,7 @@ public class ApplicationSettingsTest {
     public void shouldReturnCambriaConfigurationFileLocation() throws IOException {
         // when
         String cambriaConfigurationFileLocation = fromTemporaryConfiguration("collector.dmaapfile=/somewhere/dmaapConfig")
-                .cambriaConfigurationFileLocation();
+                .dMaaPConfigurationFileLocation();
 
         // then
         assertEquals(sanitizePath("/somewhere/dmaapConfig"), cambriaConfigurationFileLocation);
@@ -400,7 +420,7 @@ public class ApplicationSettingsTest {
     public void shouldReturnDefaultCambriaConfigurationFileLocation() throws IOException {
         // when
         String cambriaConfigurationFileLocation = fromTemporaryConfiguration()
-                .cambriaConfigurationFileLocation();
+                .dMaaPConfigurationFileLocation();
 
         // then
         assertEquals(sanitizePath("etc/DmaapConfig.json"), cambriaConfigurationFileLocation);
diff --git a/src/test/java/org/onap/dcae/TestingUtilities.java b/src/test/java/org/onap/dcae/TestingUtilities.java
new file mode 100644 (file)
index 0000000..0bbb6cc
--- /dev/null
@@ -0,0 +1,94 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2018 Nokia. 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;
+
+import static java.nio.file.Files.readAllBytes;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import io.vavr.control.Try;
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.assertj.core.api.AbstractThrowableAssert;
+import org.assertj.core.api.Java6Assertions;
+import org.json.JSONObject;
+
+/**
+ * @author Pawel Szalapski (pawel.szalapski@nokia.com)
+ */
+public final class TestingUtilities {
+
+    private TestingUtilities() {
+        // utility class, no objects allowed
+    }
+
+    public static void assertJSONObjectsEqual(JSONObject o1, JSONObject o2) {
+        assertThat(o1.toString()).isEqualTo(o2.toString());
+    }
+
+    public static JSONObject readJSONFromFile(Path path) {
+        return rethrow(() -> new JSONObject(readFile(path)));
+    }
+
+    public static String readFile(Path path) {
+        return rethrow(() -> new String(readAllBytes(path)));
+    }
+
+    public static Path createTemporaryFile(String content) {
+        return rethrow(() -> {
+            File temp = File.createTempFile("ves-collector-tests-created-this-file", ".tmp");
+            temp.deleteOnExit();
+            Path filePath = Paths.get(temp.toString());
+            Files.write(filePath, content.getBytes());
+            return filePath;
+        });
+    }
+
+    /**
+     * Exception in test case usually means there is something wrong, it should never be catched, but rather thrown to
+     * be handled by JUnit framework.
+     */
+    private static <T> T rethrow(CheckedSupplier<T> supplier) {
+        try {
+            return supplier.get();
+        } catch (Exception e) {
+            throw new RuntimeException();
+        }
+    }
+
+    @FunctionalInterface
+    interface CheckedSupplier<T> {
+
+        T get() throws Exception;
+    }
+
+
+    public static void assertFailureHasInfo(Try any, String... msgPart) {
+        Java6Assertions.assertThat(any.isFailure()).isTrue();
+        AbstractThrowableAssert<?, ? extends Throwable> o = Java6Assertions.assertThat(any.getCause())
+            .hasCauseInstanceOf(Exception.class);
+        for (String s : msgPart) {
+            o.hasStackTraceContaining(s);
+        }
+    }
+}
diff --git a/src/test/java/org/onap/dcae/WiremockBasedTest.java b/src/test/java/org/onap/dcae/WiremockBasedTest.java
new file mode 100644 (file)
index 0000000..ae85125
--- /dev/null
@@ -0,0 +1,68 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2018 Nokia. 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;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
+import static io.vavr.API.Map;
+
+import com.github.tomakehurst.wiremock.junit.WireMockRule;
+import io.vavr.collection.Map;
+import org.junit.Rule;
+
+/**
+ * @author Pawel Szalapski (pawel.szalapski@nokia.com)
+ */
+public class WiremockBasedTest {
+
+    @Rule
+    public WireMockRule wireMockRule = new WireMockRule(
+        wireMockConfig().dynamicPort().dynamicHttpsPort().keystorePath(null));
+
+    protected void stubConsulToReturnLocalAddressOfCBS() {
+        stubFor(get(urlEqualTo("/v1/catalog/service/CBSName"))
+            .willReturn(aResponse().withBody(validLocalCBSConf())));
+    }
+
+    protected void stubCBSToReturnAppConfig(String sampleConfigForVES) {
+        stubFor(get(urlEqualTo("/service_component/VESCollector"))
+            .willReturn(aResponse().withBody(sampleConfigForVES)));
+    }
+
+    protected Map<String, String> wiremockBasedEnvProps() {
+        return Map(
+            "CONSUL_HOST", "http://localhost",
+            "CONSUL_PORT", "" + wireMockRule.port(),
+            "HOSTNAME", "VESCollector",
+            "CONFIG_BINDING_SERVICE", "CBSName"
+        );
+    }
+
+    protected String validLocalCBSConf() {
+        return ""
+            + "[{ "
+            + "\"ServiceAddress\": \"http://localhost\","
+            + "\"ServicePort\":" + wireMockRule.port()
+            + "}]";
+    }
+}
diff --git a/src/test/java/org/onap/dcae/controller/ConfigCBSSourceTest.java b/src/test/java/org/onap/dcae/controller/ConfigCBSSourceTest.java
new file mode 100644 (file)
index 0000000..336788a
--- /dev/null
@@ -0,0 +1,151 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2018 Nokia. 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.controller;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static org.assertj.core.api.Java6Assertions.assertThat;
+import static org.onap.dcae.TestingUtilities.assertFailureHasInfo;
+import static org.onap.dcae.controller.ConfigSource.getAppConfig;
+
+import io.vavr.control.Try;
+import org.json.JSONObject;
+import org.junit.Test;
+import org.onap.dcae.WiremockBasedTest;
+
+public class ConfigCBSSourceTest extends WiremockBasedTest {
+
+    @Test
+    public void shouldReturnValidAppConfiguration() {
+        // given
+        String sampleConfigForVES = "{\"collector.port\": 8080}";
+
+        stubConsulToReturnLocalAddressOfCBS();
+        stubCBSToReturnAppConfig(sampleConfigForVES);
+
+        // when
+        Try<JSONObject> actual = tryToGetConfig();
+
+        // then
+        assertThat(actual.get().toString()).isEqualTo(new JSONObject(sampleConfigForVES).toString());
+    }
+
+    @Test
+    public void shouldReturnFailureOnFailureToCommunicateWithConsul() {
+        // given
+        stubFor(get(urlEqualTo("/v1/catalog/service/CBSName"))
+            .willReturn(aResponse().withStatus(400)));
+
+        // when
+        Try<JSONObject> actual = tryToGetConfig();
+
+        // then
+        assertFailureHasInfo(actual, "HTTP", "Consul", "400",
+            "http://localhost:" + wireMockRule.port() + "/v1/catalog/service/CBSName");
+    }
+
+    @Test
+    public void shouldReturnFailureOnBadJsonFromConsul() {
+        // given
+        stubFor(get(urlEqualTo("/v1/catalog/service/CBSName"))
+            .willReturn(aResponse().withStatus(200).withBody("[{")));
+
+        // when
+        Try<JSONObject> actual = tryToGetConfig();
+
+        // then
+        assertFailureHasInfo(actual, "JSON", "array", "[{");
+    }
+
+    @Test
+    public void shouldReturnFailureOnInvalidCatalogFormat() {
+        // given
+        String notAListCatalog = ""
+            + "{"
+            + "\"ServiceAddress\":\"http://localhost\","
+            + "\"ServicePort\":" + wireMockRule.port()
+            + "}";
+
+        stubFor(get(urlEqualTo("/v1/catalog/service/CBSName"))
+            .willReturn(aResponse().withStatus(200).withBody(notAListCatalog)));
+
+        // when
+        Try<JSONObject> actual = tryToGetConfig();
+
+        // then
+        assertFailureHasInfo(actual, "JSON", "array", notAListCatalog);
+    }
+
+
+    @Test
+    public void shouldReturnFailureIfConfigIsMissingRequiredProperties() {
+        // given
+        String actualConf = "{\"ServicePort\":" + wireMockRule.port() + "}";
+        String asCatalog = "[" + actualConf + "]";
+
+        stubFor(get(urlEqualTo("/v1/catalog/service/CBSName"))
+            .willReturn(aResponse().withStatus(200).withBody(asCatalog)));
+
+        // when
+        Try<JSONObject> actual = tryToGetConfig();
+
+        // then
+        assertFailureHasInfo(actual, "ServiceAddress", "ServicePort", "missing", actualConf);
+    }
+
+
+    @Test
+    public void shouldReturnFailureOnFailureToCommunicateWithCBS() {
+        // given
+        stubFor(get(urlEqualTo("/v1/catalog/service/CBSName"))
+            .willReturn(aResponse().withStatus(200).withBody(validLocalCBSConf())));
+        stubFor(get(urlEqualTo("/service_component/VESCollector"))
+            .willReturn(aResponse().withStatus(400)));
+
+        // when
+        Try<JSONObject> actual = tryToGetConfig();
+
+        // then
+        assertFailureHasInfo(actual, "HTTP", "CBS", "400",
+            "http://localhost:" + wireMockRule.port() + "/service_component/VESCollector");
+    }
+
+    @Test
+    public void shouldReturnFailureIfAppIsInvalidJsonDocument() {
+        // given
+        String invalidAppConf = "[$";
+        stubConsulToReturnLocalAddressOfCBS();
+        stubCBSToReturnAppConfig(invalidAppConf);
+
+        // when
+        Try<JSONObject> actual = tryToGetConfig();
+
+        // then
+        assertFailureHasInfo(actual, "JSON", "document", invalidAppConf);
+    }
+
+    private Try<JSONObject> tryToGetConfig() {
+        return getAppConfig(new EnvProps("http://localhost", wireMockRule.port(), "CBSName", "VESCollector"));
+    }
+}
+
diff --git a/src/test/java/org/onap/dcae/controller/ConfigFilesFacadeTest.java b/src/test/java/org/onap/dcae/controller/ConfigFilesFacadeTest.java
new file mode 100644 (file)
index 0000000..474a77c
--- /dev/null
@@ -0,0 +1,139 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2018 Nokia. 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.controller;
+
+import static io.vavr.API.Map;
+import static io.vavr.API.Some;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.onap.dcae.TestingUtilities.assertFailureHasInfo;
+import static org.onap.dcae.TestingUtilities.assertJSONObjectsEqual;
+import static org.onap.dcae.TestingUtilities.createTemporaryFile;
+import static org.onap.dcae.TestingUtilities.readFile;
+import static org.onap.dcae.TestingUtilities.readJSONFromFile;
+
+import io.vavr.collection.Map;
+import io.vavr.control.Try;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.json.JSONObject;
+import org.junit.Test;
+
+public class ConfigFilesFacadeTest {
+
+    private static final Path NON_EXISTENT = Paths.get("/non-existent");
+    private static final ConfigFilesFacade TO_NON_EXISTENT_POINTING_FACADE = new ConfigFilesFacade(NON_EXISTENT,
+        NON_EXISTENT);
+
+    @Test
+    public void shouldReadPropertyFile() {
+        // given
+        Path temporaryFile = createTemporaryFile("some.property=10");
+
+        // when
+        ConfigFilesFacade configFilesFacade = new ConfigFilesFacade(temporaryFile, temporaryFile);
+
+        Try<Map<String, String>> propertiesConfigurations = configFilesFacade.readCollectorProperties();
+
+        // then
+        assertThat(propertiesConfigurations.isSuccess()).isTrue();
+        assertThat(propertiesConfigurations.get().containsKey("some.property")).isTrue();
+        assertThat(propertiesConfigurations.get().get("some.property")).isEqualTo(Some("10"));
+    }
+
+
+    @Test
+    public void shouldReadDMaaPFile() {
+        // given
+        Path temporaryFile = createTemporaryFile("{}");
+
+        // when
+        ConfigFilesFacade configFilesFacade = new ConfigFilesFacade(temporaryFile, temporaryFile);
+
+        Try<JSONObject> dMaaPConfiguration = configFilesFacade.readDMaaPConfiguration();
+
+        // then
+        assertThat(dMaaPConfiguration.isSuccess()).isTrue();
+        assertThat(dMaaPConfiguration.get().toString()).isEqualTo("{}");
+    }
+
+    @Test
+    public void shouldWriteDMaaPConf() {
+        // given
+        Path temporaryFile = createTemporaryFile("{}");
+        JSONObject desiredConf = new JSONObject("{\"key\": 1}");
+
+        // when
+        ConfigFilesFacade configFilesFacade = new ConfigFilesFacade(temporaryFile, temporaryFile);
+
+        Try<Void> propertiesConfigurations = configFilesFacade.writeDMaaPConfiguration(desiredConf);
+
+        // then
+        assertThat(propertiesConfigurations.isSuccess()).isTrue();
+        assertJSONObjectsEqual(readJSONFromFile(temporaryFile), desiredConf);
+    }
+
+
+    @Test
+    public void shouldWriteProperties() {
+        // given
+        Path temporaryFile = createTemporaryFile("{}");
+
+        // when
+        ConfigFilesFacade configFilesFacade = new ConfigFilesFacade(temporaryFile, temporaryFile);
+        Try<Void> propertiesConfigurations = configFilesFacade.writeProperties(Map("prop1", "hi"));
+
+        // then
+        assertThat(propertiesConfigurations.isSuccess()).isTrue();
+        assertThat(readFile(temporaryFile).trim()).isEqualTo("prop1 = hi");
+    }
+
+    @Test
+    public void shouldContainPropertiesPathInCaseOfFailures() {
+        Try<Map<String, String>> result = TO_NON_EXISTENT_POINTING_FACADE.readCollectorProperties();
+        assertThat(result.isFailure()).isTrue();
+        assertFailureHasInfo(result, NON_EXISTENT.toString());
+    }
+
+    @Test
+    public void shouldContainDMaaPPathPathInCaseOfFailures() {
+        Try<JSONObject> result = TO_NON_EXISTENT_POINTING_FACADE.readDMaaPConfiguration();
+        assertThat(result.isFailure()).isTrue();
+        assertFailureHasInfo(result, NON_EXISTENT.toString());
+    }
+
+    @Test
+    public void shouldContainPropertiesPathPathInCaseOfFailuresOnWrite() {
+        // given
+        Try<Void> result = TO_NON_EXISTENT_POINTING_FACADE.writeProperties(Map("any", "any"));
+        assertThat(result.isFailure()).isTrue();
+        assertFailureHasInfo(result, NON_EXISTENT.toString());
+    }
+
+    @Test
+    public void shouldContainDMaaPPathPathInCaseOfFailuresOnWrite() {
+        // given
+        Try<Void> result = TO_NON_EXISTENT_POINTING_FACADE.writeDMaaPConfiguration(new JSONObject());
+        assertThat(result.isFailure()).isTrue();
+        assertFailureHasInfo(result, NON_EXISTENT.toString());
+    }
+
+}
+
diff --git a/src/test/java/org/onap/dcae/controller/ConfigLoaderIntegrationE2ETest.java b/src/test/java/org/onap/dcae/controller/ConfigLoaderIntegrationE2ETest.java
new file mode 100644 (file)
index 0000000..09dca67
--- /dev/null
@@ -0,0 +1,92 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2018 Nokia. 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.controller;
+
+import static io.vavr.API.Map;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+import static org.onap.dcae.TestingUtilities.createTemporaryFile;
+import static org.onap.dcae.TestingUtilities.readFile;
+import static org.onap.dcae.TestingUtilities.readJSONFromFile;
+import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.f;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.json.JSONObject;
+import org.junit.Test;
+import org.onap.dcae.WiremockBasedTest;
+import org.onap.dcae.commonFunction.event.publishing.DMaaPConfigurationParser;
+import org.onap.dcae.commonFunction.event.publishing.EventPublisher;
+
+public class ConfigLoaderIntegrationE2ETest extends WiremockBasedTest {
+
+    @Test
+    public void testSuccessfulE2EFlow() {
+        // given
+        Path dMaaPConfigFile = createTemporaryFile("{}");
+        Path collectorPropertiesFile = createTemporaryFile("");
+        Path dMaaPConfigSource = Paths.get("src/test/resources/testParseDMaaPCredentialsGen2.json");
+        JSONObject dMaaPConf = readJSONFromFile(dMaaPConfigSource);
+        stubConsulToReturnLocalAddressOfCBS();
+        stubCBSToReturnAppConfig(f("{\"collector.port\": 8080, \"streams_publishes\": %s}}", dMaaPConf));
+
+        EventPublisher eventPublisherMock = mock(EventPublisher.class);
+        ConfigFilesFacade configFilesFacade = new ConfigFilesFacade(dMaaPConfigFile, collectorPropertiesFile);
+
+        // when
+        ConfigLoader configLoader = new ConfigLoader(eventPublisherMock::reconfigure, configFilesFacade, ConfigSource::getAppConfig, () -> wiremockBasedEnvProps());
+        configLoader.updateConfig();
+
+        // then
+        assertThat(readJSONFromFile(dMaaPConfigSource).toString()).isEqualTo(dMaaPConf.toString());
+        assertThat(readFile(collectorPropertiesFile).trim()).isEqualTo("collector.port = 8080");
+        verify(eventPublisherMock, times(1)).reconfigure(
+            DMaaPConfigurationParser.parseToDomainMapping(dMaaPConf).get()
+        );
+    }
+
+    @Test
+    public void shouldNotReconfigureNotOverwriteIfConfigurationHasNotChanged() {
+        // given
+        Path dMaaPConfigFile = createTemporaryFile("{}");
+        Path collectorPropertiesFile = createTemporaryFile("");
+        JSONObject dMaaPConf = readJSONFromFile(Paths.get("src/test/resources/testParseDMaaPCredentialsGen2.json"));
+        stubConsulToReturnLocalAddressOfCBS();
+        stubCBSToReturnAppConfig(f("{\"collector.port\": 8080, \"streams_publishes\": %s}}", dMaaPConf));
+        EventPublisher eventPublisherMock = mock(EventPublisher.class);
+        ConfigFilesFacade configFilesFacade = new ConfigFilesFacade(dMaaPConfigFile, collectorPropertiesFile);
+        configFilesFacade.writeProperties(Map("collector.port", "8080"));
+        configFilesFacade.writeDMaaPConfiguration(dMaaPConf);
+
+        // when
+        ConfigLoader configLoader = new ConfigLoader(eventPublisherMock::reconfigure, configFilesFacade, ConfigSource::getAppConfig, () -> wiremockBasedEnvProps());
+        configLoader.updateConfig();
+
+        // then
+        verifyZeroInteractions(eventPublisherMock);
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/onap/dcae/controller/ConfigParsingTest.java b/src/test/java/org/onap/dcae/controller/ConfigParsingTest.java
new file mode 100644 (file)
index 0000000..a00a3d3
--- /dev/null
@@ -0,0 +1,72 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2018 Nokia. 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.controller;
+
+
+import static io.vavr.API.Map;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.onap.dcae.TestingUtilities.assertJSONObjectsEqual;
+import static org.onap.dcae.TestingUtilities.readJSONFromFile;
+
+import io.vavr.collection.Map;
+import io.vavr.control.Option;
+import java.nio.file.Paths;
+import org.json.JSONObject;
+import org.junit.Test;
+
+public class ConfigParsingTest {
+
+    @Test
+    public void shouldReturnDMaaPConfig() {
+        JSONObject dMaaPConf = readJSONFromFile(Paths.get("src/test/resources/testParseDMaaPCredentialsGen2.json"));
+        JSONObject root = new JSONObject();
+        root.put("key1", "someProperty");
+        root.put("key2", "someProperty");
+        root.put("streams_publishes", dMaaPConf);
+
+        Option<JSONObject> dMaaPConfig = ConfigParsing.getDMaaPConfig(root);
+
+        assertThat(dMaaPConfig.isEmpty()).isFalse();
+        assertJSONObjectsEqual(dMaaPConfig.get(), dMaaPConf);
+    }
+
+    @Test
+    public void shouldReturnEmptyIfDMaaPConfigIsInvalid() {
+        JSONObject root = new JSONObject();
+        root.put("streams_publishes", 1);
+
+        Option<JSONObject> dMaaPConfig = ConfigParsing.getDMaaPConfig(root);
+
+        assertThat(dMaaPConfig.isEmpty()).isTrue();
+    }
+
+    @Test
+    public void getProperties() {
+        JSONObject dMaaPConf = readJSONFromFile(Paths.get("src/test/resources/testParseDMaaPCredentialsGen2.json"));
+        JSONObject root = new JSONObject();
+        root.put("key1", "someProperty");
+        root.put("key2", "someProperty");
+        root.put("streams_publishes", dMaaPConf);
+
+        Map<String, String> properties = ConfigParsing.getProperties(root);
+        assertThat(properties).isEqualTo(Map("key1", "someProperty", "key2", "someProperty"));
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/onap/dcae/controller/EnvPropertiesReaderTest.java b/src/test/java/org/onap/dcae/controller/EnvPropertiesReaderTest.java
new file mode 100644 (file)
index 0000000..581f6ea
--- /dev/null
@@ -0,0 +1,68 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2018 Nokia. 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.controller;
+
+import static io.vavr.API.Map;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.onap.dcae.controller.EnvPropertiesReader.readEnvProps;
+
+import io.vavr.collection.Map;
+import org.junit.Test;
+
+
+public class EnvPropertiesReaderTest {
+
+    @Test
+    public void shouldReturnEmptyOnMissingConsulHost() {
+        Map<String, String> envs = Map(
+            "CONFIG_BINDING_SERVICE", "doesNotMatter",
+            "HOSTNAME", "doesNotMatter");
+        assertTrue(readEnvProps(envs).isEmpty());
+    }
+
+    @Test
+    public void shouldReturnEmptyOnMissingCBSName() {
+        Map<String, String> envs = Map(
+            "CONSUL_HOST", "doesNotMatter",
+            "HOSTNAME", "doesNotMatter");
+        assertTrue(readEnvProps(envs).isEmpty());
+    }
+
+    @Test
+    public void shouldReturnEmptyOnMissingVESAppName() {
+        Map<String, String> envs = Map(
+            "CONSUL_HOST", "doesNotMatter",
+            "CONFIG_BINDING_SERVICE", "doesNotMatter");
+        assertTrue(readEnvProps(envs).isEmpty());
+    }
+
+    @Test
+    public void shouldReturnSomeOfAllProperties() {
+        Map<String, String> envs = Map(
+            "CONSUL_HOST", "doesNotMatter",
+            "HOSTNAME", "doesNotMatter",
+            "CONFIG_BINDING_SERVICE", "doesNotMatter");
+        assertFalse(readEnvProps(envs).isEmpty());
+    }
+
+}
+
diff --git a/src/test/java/org/onap/dcae/vestest/TestFetchConfig.java b/src/test/java/org/onap/dcae/vestest/TestFetchConfig.java
deleted file mode 100644 (file)
index 0b6b502..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*-\r
- * ============LICENSE_START=======================================================\r
- * PROJECT\r
- * ================================================================================\r
- * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.\r
- * ================================================================================\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- * ============LICENSE_END=========================================================\r
- */\r
-package org.onap.dcae.vestest;\r
-\r
-import static org.junit.Assert.assertTrue;\r
-import static org.onap.dcae.vestest.TestingUtilities.createTemporaryFile;\r
-\r
-import com.google.gson.JsonObject;\r
-import java.nio.file.Path;\r
-import org.junit.Before;\r
-import org.junit.Test;\r
-import org.onap.dcae.controller.FetchDynamicConfig;\r
-import org.onap.dcae.controller.LoadDynamicConfig;\r
-\r
-\r
-public class TestFetchConfig {\r
-\r
-    private Path temporaryFile;\r
-\r
-    @Before\r
-    public void setUp() {\r
-        temporaryFile = createTemporaryFile();\r
-    }\r
-\r
-    @Test\r
-    public void shouldWriteFileAndAttachDMaaPStreamsPropertiesFromConfiguration() {\r
-        // given\r
-        FetchDynamicConfig loadDynamicConfig = new FetchDynamicConfig();\r
-        FetchDynamicConfig.configFile = temporaryFile.toString();\r
-        String sampleConfiguration = LoadDynamicConfig.readFile("src/test/resources/controller-config_singleline_ip.json");\r
-\r
-        // when\r
-        loadDynamicConfig.writefile(sampleConfiguration);\r
-\r
-        // then\r
-        JsonObject actuallyWrittenJSONContent = TestingUtilities.readJSONFromFile(temporaryFile);\r
-        assertTrue(actuallyWrittenJSONContent.has("streams_publishes"));\r
-    }\r
-\r
-    @Test\r
-    public void shouldThrowNoErrorsWhileParsingConsulResponse() {\r
-        // given\r
-        FetchDynamicConfig.retString = "[{\"ID\":\"81bc2a17-8cfa-3f6f-30a9-a545a9b6ac2f\",\"Node\":\"zldcrdm5bdcc2dokr00\",\"Address\":\"135.25.108.161\",\"Datacenter\":\"zldcrdm5bdcc2\",\"TaggedAddresses\":{\"lan\":\"135.25.108.161\",\"wan\":\"135.25.108.161\"},\"NodeMeta\":{\"fqdn\":\"zldcrdm5bdcc2dokr00.2f3fb3.rdm5b.tci.att.com\"},\"ServiceID\":\"20299a144716:config_binding_service:10000\",\"ServiceName\":\"config_binding_service\",\"ServiceTags\":[],\"ServiceAddress\":\"135.25.108.161\",\"ServicePort\":10000,\"ServiceEnableTagOverride\":false,\"CreateIndex\":9153156,\"ModifyIndex\":9153156}]";\r
-\r
-        // then\r
-        FetchDynamicConfig.getCBS();\r
-    }\r
-\r
-\r
-    @Test\r
-    public void shouldReturnTrueOnConfigurationChange() {\r
-        // given\r
-        FetchDynamicConfig.configFile = "src/test/resources/controller-config_singleline_ip.json";\r
-        FetchDynamicConfig.retCBSString = "{\"header.authflag\": \"1\", \"collector.schema.file\": \"{\\\"v1\\\": \\\"./etc/CommonEventFormat_27.2.json\\\", \\\"v2\\\": \\\"./etc/CommonEventFormat_27.2.json\\\", \\\"v3\\\": \\\"./etc/CommonEventFormat_27.2.json\\\", \\\"v4\\\": \\\"./etc/CommonEventFormat_27.2.json\\\", \\\"v5\\\": \\\"./etc/CommonEventFormat_28.4.json\\\"}\", \"collector.keystore.passwordfile\": \"/opt/app/dcae-certificate/.password\", \"tomcat.maxthreads\": \"200\", \"collector.dmaap.streamid\": \"fault=ves-fault|syslog=ves-syslog|heartbeat=ves-heartbeat|measurementsForVfScaling=ves-measurement|mobileFlow=ves-mobileflow|other=ves-other|stateChange=ves-statechange|thresholdCrossingAlert=ves-thresholdCrossingAlert|voiceQuality=ves-voicequality|sipSignaling=ves-sipsignaling\", \"streams_subscribes\": {}, \"collector.inputQueue.maxPending\": \"8096\", \"collector.keystore.alias\": \"dynamically generated\", \"streams_publishes\": {\"ves-mobileflow\": {\"type\": \"message_router\", \"dmaap_info\": {\"client_id\": \"1517590629043\", \"client_role\": \"com.att.secCollector.member\", \"location\": \"rdm5bdcc2\", \"topic_url\": \"https://DMAAPHOST:3905/events/com.att.dcae.dmaap.FTL.24256-SEC-MOBILEFLOW-OUTPUT-v1\"}, \"aaf_username\": \"userid@namespace\", \"aaf_password\": \"authpwd\"}, \"ves-measurement\": {\"type\": \"message_router\", \"dmaap_info\": {\"client_id\": \"1517590433916\", \"client_role\": \"com.att.secCollector.member\", \"location\": \"rdm5bdcc2\", \"topic_url\": \"https://DMAAPHOST:3905/events/com.att.dcae.dmaap.FTL.24256-ENC-MEASUREMENT-OUTPUT-v1\"}, \"aaf_username\": \"userid@namespace\", \"aaf_password\": \"authpwd\"}, \"ves-voicequality\": {\"type\": \"message_router\", \"dmaap_info\": {\"client_id\": \"1517590778397\", \"client_role\": \"com.att.secCollector.member\", \"location\": \"rdm5bdcc2\", \"topic_url\": \"https://DMAAPHOST:3905/events/com.att.dcae.dmaap.FTL.24256-VES-VOICEQUALITY-OUTPUT-v1\"}, \"aaf_username\": \"userid@namespace\", \"aaf_password\": \"authpwd\"}, \"ves-thresholdCrossingAlert\": {\"type\": \"message_router\", \"dmaap_info\": {\"client_id\": \"1517590728150\", \"client_role\": \"com.att.secCollector.member\", \"location\": \"rdm5bdcc2\", \"topic_url\": \"https://DMAAPHOST:3905/events/com.att.dcae.dmaap.FTL.24256-SEC-TCA-OUTPUT-v1\"}, \"aaf_username\": \"userid@namespace\", \"aaf_password\": \"authpwd\"}, \"ves-fault\": {\"type\": \"message_router\", \"dmaap_info\": {\"client_id\": \"1517590384670\", \"client_role\": \"com.att.secCollector.member\", \"location\": \"rdm5bdcc2\", \"topic_url\": \"https://DMAAPHOST:3905/events/com.att.dcae.dmaap.FTL.24256-SEC-FAULT-OUTPUT-v1\"}, \"aaf_username\": \"userid@namespace\", \"aaf_password\": \"authpwd\"}, \"ves-heartbeat\": {\"type\": \"message_router\", \"dmaap_info\": {\"client_id\": \"1517590530041\", \"client_role\": \"com.att.secCollector.member\", \"location\": \"rdm5bdcc2\", \"topic_url\": \"https://DMAAPHOST:3905/events/com.att.dcae.dmaap.FTL.24256-SEC-HEARTBEAT-OUTPUT-v1\"}, \"aaf_username\": \"userid@namespace\", \"aaf_password\": \"authpwd\"}, \"ves-sipsignaling\": {\"type\": \"message_router\", \"dmaap_info\": {\"client_id\": \"1517590828736\", \"client_role\": \"com.att.secCollector.member\", \"location\": \"rdm5bdcc2\", \"topic_url\": \"https://DMAAPHOST:3905/events/com.att.dcae.dmaap.FTL.24256-VES-SIPSIGNALING-OUTPUT-v1\"}, \"aaf_username\": \"userid@namespace\", \"aaf_password\": \"authpwd\"}, \"ves-syslog\": {\"type\": \"message_router\", \"dmaap_info\": {\"client_id\": \"1517590482019\", \"client_role\": \"com.att.secCollector.member\", \"location\": \"rdm5bdcc2\", \"topic_url\": \"https://DMAAPHOST:3905/events/com.att.dcae.dmaap.FTL.24256-SEC-SYSLOG-OUTPUT-v1\"}, \"aaf_username\": \"userid@namespace\", \"aaf_password\": \"authpwd\"}, \"ves-other\": {\"type\": \"message_router\", \"dmaap_info\": {\"client_id\": \"1517590581045\", \"client_role\": \"com.att.secCollector.member\", \"location\": \"rdm5bdcc2\", \"topic_url\": \"https://DMAAPHOST:3905/events/com.att.dcae.dmaap.FTL.24256-SEC-OTHER-OUTPUT-v1\"}, \"aaf_username\": \"userid@namespace\", \"aaf_password\": \"authpwd\"}, \"ves-statechange\": {\"type\": \"message_router\", \"dmaap_info\": {\"client_id\": \"1517590677649\", \"client_role\": \"com.att.secCollector.member\", \"location\": \"rdm5bdcc2\", \"topic_url\": \"https://DMAAPHOST:3905/events/com.att.dcae.dmaap.FTL.24256-SEC-STATECHANGE-OUTPUT-v1\"}, \"aaf_username\": \"userid@namespace\", \"aaf_password\": \"authpwd\"}}, \"collector.schema.checkflag\": \"1\", \"services_calls\": {}, \"event.transform.flag\": \"1\", \"collector.keystore.file.location\": \"/opt/app/dcae-certificate/keystore.jks\", \"header.authlist\": \"sample1,c2FtcGxlMQ==|userid1,base64encodepwd1|userid2,base64encodepwd2\", \"collector.service.secure.port\": \"8443\", \"collector.service.port\": \"-1\"}";\r
-\r
-        // when\r
-        boolean didConfigsChange = FetchDynamicConfig.verifyConfigChange();\r
-\r
-        // then\r
-        assertTrue(didConfigsChange);\r
-    }\r
-\r
-}\r
-\r
diff --git a/src/test/java/org/onap/dcae/vestest/TestLoadDynamicConfig.java b/src/test/java/org/onap/dcae/vestest/TestLoadDynamicConfig.java
deleted file mode 100644 (file)
index 03a074d..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * PROJECT
- * ================================================================================
- * 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.vestest;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.onap.dcae.vestest.TestingUtilities.createTemporaryFile;
-
-import com.github.fge.jackson.JsonLoader;
-import com.google.gson.JsonObject;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import org.json.JSONObject;
-import org.junit.Before;
-import org.junit.Test;
-import org.onap.dcae.controller.LoadDynamicConfig;
-
-public class TestLoadDynamicConfig {
-
-    private Path temporaryFile;
-
-    @Before
-    public void setUp() {
-        temporaryFile = createTemporaryFile();
-    }
-
-    @Test
-    public void shouldReadFileContent() throws IOException {
-        // given
-        String expectedJSON = "{ \"field\" : 1 }";
-        Files.write(temporaryFile, expectedJSON.getBytes());
-
-        // when
-        String readFileContent = LoadDynamicConfig.readFile(temporaryFile.toString());
-
-        // then
-        assertEquals(JsonLoader.fromString(expectedJSON), JsonLoader.fromString(readFileContent));
-    }
-
-    @Test
-    public void shouldWriteFileAndAttachDMaaPRelatedPropertiesFromConfiguration() {
-        // given
-        LoadDynamicConfig loadDynamicConfig = new LoadDynamicConfig();
-        loadDynamicConfig.propFile = "src/test/resources/test_collector_ip_op.properties";
-        loadDynamicConfig.configFile = "src/test/resources/controller-config_dmaap_ip.json";
-        loadDynamicConfig.dMaaPOutputFile = temporaryFile.toString();
-        String sampleConfiguration = LoadDynamicConfig.readFile(loadDynamicConfig.configFile);
-
-        // when
-        loadDynamicConfig.writeconfig(new JSONObject(sampleConfiguration));
-
-        // then
-        JsonObject actuallyWrittenJSONContent = TestingUtilities.readJSONFromFile(temporaryFile);
-        assertTrue(actuallyWrittenJSONContent.has("ves-fault-secondary"));
-    }
-
-}
-