Quellcode durchsuchen

MIT license, javadoc, deleted senslog.common library, refactor scheduling

Lukas Cerny vor 5 Jahren
Ursprung
Commit
6e0a65583d
64 geänderte Dateien mit 1264 neuen und 301 gelöschten Zeilen
  1. 5 2
      build.gradle
  2. 21 0
      connector-app/license
  3. 10 4
      connector-app/src/main/java/io/connector/app/Application.java
  4. 1 1
      connector-app/src/main/java/io/connector/app/Parameters.java
  5. 35 0
      connector-app/src/main/resources/log4j2.xml
  6. 1 1
      connector-app/src/main/resources/project.properties
  7. 21 0
      connector-core/license
  8. 79 49
      connector-core/src/main/java/io/connector/core/AbstractGateway.java
  9. 6 0
      connector-core/src/main/java/io/connector/core/AbstractModule.java
  10. 7 1
      connector-core/src/main/java/io/connector/core/AddressPath.java
  11. 6 0
      connector-core/src/main/java/io/connector/core/DataCollection.java
  12. 6 0
      connector-core/src/main/java/io/connector/core/EventInfo.java
  13. 14 0
      connector-core/src/main/java/io/connector/core/Fail.java
  14. 6 0
      connector-core/src/main/java/io/connector/core/Handler.java
  15. 6 0
      connector-core/src/main/java/io/connector/core/Message.java
  16. 7 1
      connector-core/src/main/java/io/connector/core/MessageHeader.java
  17. 7 1
      connector-core/src/main/java/io/connector/core/Module.java
  18. 6 0
      connector-core/src/main/java/io/connector/core/ModuleDeployer.java
  19. 6 0
      connector-core/src/main/java/io/connector/core/ModuleDescriptor.java
  20. 7 1
      connector-core/src/main/java/io/connector/core/ModuleInfo.java
  21. 7 1
      connector-core/src/main/java/io/connector/core/ModuleLoader.java
  22. 7 1
      connector-core/src/main/java/io/connector/core/ModuleProvider.java
  23. 6 0
      connector-core/src/main/java/io/connector/core/Reply.java
  24. 7 1
      connector-core/src/main/java/io/connector/core/VertxHttpServer.java
  25. 26 4
      connector-core/src/main/java/io/connector/core/VertxScheduler.java
  26. 0 81
      connector-core/src/main/java/io/connector/core/config/AllowedStation.java
  27. 6 0
      connector-core/src/main/java/io/connector/core/config/HostConfig.java
  28. 6 0
      connector-core/src/main/java/io/connector/core/config/PropertyConfig.java
  29. 6 0
      connector-core/src/main/java/io/connector/core/config/SchedulerConfig.java
  30. 1 1
      connector-core/src/main/java/io/connector/core/config/file/FileBuilderImpl.java
  31. 9 3
      connector-core/src/main/java/io/connector/core/config/file/FileConfigurationServiceImpl.java
  32. 6 0
      connector-core/src/main/java/io/connector/core/http/ContentType.java
  33. 6 0
      connector-core/src/main/java/io/connector/core/http/Header.java
  34. 215 0
      connector-core/src/main/java/io/connector/core/http/HttpClient.java
  35. 22 0
      connector-core/src/main/java/io/connector/core/http/HttpCode.java
  36. 5 0
      connector-core/src/main/java/io/connector/core/http/HttpMethod.java
  37. 101 0
      connector-core/src/main/java/io/connector/core/http/HttpRequest.java
  38. 69 0
      connector-core/src/main/java/io/connector/core/http/HttpRequestBuilder.java
  39. 77 0
      connector-core/src/main/java/io/connector/core/http/HttpResponse.java
  40. 42 0
      connector-core/src/main/java/io/connector/core/http/HttpResponseBuilder.java
  41. 6 0
      connector-core/src/main/java/io/connector/core/http/RequestUriComponent.java
  42. 6 0
      connector-core/src/main/java/io/connector/core/http/RequestUriParser.java
  43. 113 0
      connector-core/src/main/java/io/connector/core/http/URLBuilder.java
  44. 6 0
      connector-core/src/main/java/io/connector/core/json/DeserializeFormatter.java
  45. 6 0
      connector-core/src/main/java/io/connector/core/json/JsonAttributeFormatter.java
  46. 6 0
      connector-core/src/main/java/io/connector/core/json/JsonDeserializer.java
  47. 6 0
      connector-core/src/main/java/io/connector/core/json/JsonSerializer.java
  48. 6 0
      connector-core/src/main/java/io/connector/core/json/SerializeFormatter.java
  49. 60 0
      connector-core/src/main/java/io/connector/core/util/StringUtils.java
  50. 7 0
      connector-module-afarcloud/src/main/java/io/connector/module/afarcloud/AFCConfig.java
  51. 48 14
      connector-module-afarcloud/src/main/java/io/connector/module/afarcloud/AFCHttpClient.java
  52. 9 5
      connector-module-afarcloud/src/main/java/io/connector/module/afarcloud/AFCModule.java
  53. 9 2
      connector-module-afarcloud/src/main/java/io/connector/module/afarcloud/AFCModuleProvider.java
  54. 0 18
      connector-module-afarcloud/src/main/java/io/connector/module/afarcloud/UnitCollection.java
  55. 0 17
      connector-module-afarcloud/src/main/java/io/connector/module/afarcloud/gateway/AFCGateway.java
  56. 45 10
      connector-module-afarcloud/src/main/java/io/connector/module/afarcloud/gateway/OGCSensorThingsGateway.java
  57. 21 50
      connector-module-afarcloud/src/main/java/io/connector/module/afarcloud/gateway/SensLog1Gateway.java
  58. 1 3
      connector-module-ima/src/main/java/io/connector/module/ima/ImaClient.java
  59. 2 1
      connector-module-ima/src/main/java/io/connector/module/ima/ImaModule.java
  60. 20 0
      connector-module-ima/src/main/java/io/connector/module/ima/gateway/ImaGateway.java
  61. 5 5
      connector-module-senslog1/src/main/java/io/connector/module/senslog1/SensLog1HttpClient.java
  62. 0 3
      connector-module-senslog1/src/main/java/io/connector/module/senslog1/SensLog1Module.java
  63. 1 1
      connector-module-senslog1/src/main/java/io/connector/module/senslog1/SensLog1ModuleProvider.java
  64. 0 19
      connector-module-senslog1/src/main/java/io/connector/module/senslog1/gateway/AFCGateway.java

+ 5 - 2
build.gradle

@@ -20,7 +20,7 @@ allprojects {
     apply plugin: 'java'
 
     group 'io.connector'
-    version '2.0'
+    version '1.0'
 
     repositories {
         mavenLocal()
@@ -33,7 +33,8 @@ allprojects {
     }
 
     dependencies {
-        compile group: 'cz.senslog', name: 'common', version: '1.0.0'
+        compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.12.0'
+        compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.12.0'
     }
 
     // create fat JAR
@@ -67,6 +68,8 @@ project(":connector-core") {
     dependencies {
         compile group: 'io.vertx', name: 'vertx-core', version: '3.9.1'
         compile group: 'io.vertx', name: 'vertx-web', version: '3.9.1'
+        compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.9'
+        compile group: 'org.yaml', name: 'snakeyaml', version: '1.24'
     }
 }
 

+ 21 - 0
connector-app/license

@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2020 University of West Bohemia, https://www.zcu.cz/en
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 10 - 4
connector-app/src/main/java/io/connector/app/Application.java

@@ -1,6 +1,6 @@
 package io.connector.app;
 
-import cz.senslog.common.util.StringUtils;
+import io.connector.core.util.StringUtils;
 import io.connector.core.config.ConfigurationService;
 import io.connector.core.config.file.FileConfigurationService;
 import io.connector.core.AbstractModule;
@@ -16,6 +16,13 @@ import java.util.List;
 import static io.connector.core.ModuleDeployer.deploy;
 import static io.connector.core.ModuleLoader.loadModules;
 
+/**
+ *
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public class Application extends Thread {
 
     private static final Logger logger = LogManager.getLogger(Application.class);
@@ -77,9 +84,8 @@ public class Application extends Thread {
         Vertx.vertx().deployVerticle(deploy(modules), options, res -> {
             if(res.succeeded()) {
                 logger.info("Deployment id is: {}", res.result());
-                double diffMil = System.currentTimeMillis() - startApp;
-                double sec = diffMil / 1000;
-                logger.info("Started in {} second.", sec);
+                double startingTimeMillis = System.currentTimeMillis() - startApp;
+                logger.info("Started in {} second.", startingTimeMillis / 1000.0);
             } else {
                 logger.error("Deployment failed! The reason is '{}'", res.result());
             }

+ 1 - 1
connector-app/src/main/java/io/connector/app/Parameters.java

@@ -9,7 +9,7 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.Arrays;
 
-import static cz.senslog.common.util.StringUtils.isNotBlank;
+import static io.connector.core.util.StringUtils.isNotBlank;
 import static java.lang.String.format;
 import static java.nio.file.Files.notExists;
 import static java.nio.file.Paths.get;

+ 35 - 0
connector-app/src/main/resources/log4j2.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration xmlns="http://logging.apache.org/log4j/2.0/config" status="INFO">
+
+    <Properties>
+        <Property name="logPath">./</Property>
+    </Properties>
+
+    <Appenders>
+
+        <Console name="console" target="SYSTEM_OUT">
+            <PatternLayout pattern="%-5p | %d{yyyy-MM-dd HH:mm:ss} | [%t] %C{2} (%F:%L) - %m%n" />
+        </Console>
+
+        <RollingFile name="filebeat"
+                     fileName="${sys:logPath}/app.log"
+                     filePattern="${sys:logPath}/app.%i.log.gz"
+        >
+            <PatternLayout alwaysWriteExceptions="false"
+                    pattern='{"app.date":"%d{ISO8601}","app.thread":"%t","app.level":"%level","app.logger":"%logger:%L", "app.exception":"%enc{%ex}{JSON}", "app.message":"%msg"}%n'
+            />
+            <Policies>
+<!--                <TimeBasedTriggeringPolicy interval="1"/> &lt;!&ndash; Number of days for a log file &ndash;&gt;-->
+                <SizeBasedTriggeringPolicy size="10MB" />
+            </Policies>
+        </RollingFile>
+
+    </Appenders>
+    <Loggers>
+        <Logger name="cz.senslog" level="info" />
+        <Root level="info">
+            <AppenderRef ref="console" />
+            <AppenderRef ref="filebeat" />
+        </Root>
+    </Loggers>
+</Configuration>

+ 1 - 1
connector-app/src/main/resources/project.properties

@@ -1,2 +1,2 @@
 app.name=Connector
-app.version=2.0
+app.version=1.0

+ 21 - 0
connector-core/license

@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2020 University of West Bohemia, https://www.zcu.cz/en
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 79 - 49
connector-core/src/main/java/io/connector/core/AbstractGateway.java

@@ -10,38 +10,58 @@ import io.vertx.ext.web.Router;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
-import java.util.HashMap;
+import java.util.Arrays;
 import java.util.HashSet;
-import java.util.Map;
 import java.util.Set;
 import java.util.function.Consumer;
 
+import static io.connector.core.AbstractGateway.ConsumerType.*;
 import static io.connector.core.AddressPath.Creator.createNormalized;
 import static io.connector.core.AddressPath.SCHEDULER_CONSUMER;
 import static io.connector.core.AddressPath.SCHEDULER_PROVIDER;
 import static io.connector.core.MessageHeader.*;
 import static java.lang.String.format;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public abstract class AbstractGateway {
 
     private final static Logger logger = LogManager.getLogger(AbstractGateway.class);
 
+    enum ConsumerType {
+        SCHEDULER   (true),
+        SUBSCRIBER  (false),
+        OTHER       (true),
+
+        ;
+        private final boolean canBeDefault;
+        ConsumerType(boolean canBeDefault) {
+            this.canBeDefault = canBeDefault;
+        }
+        public boolean canBeDefault() {
+            return canBeDefault;
+        }
+    }
+
     private final boolean isDefault;
     private EventBus eventBus;
     private Router router;
     private Event event;
     private String moduleId;
     protected String gatewayId;
-    private final Set<String> registeredConsumers;
-    private final Set<String> registeredScheduleConsumers;
-    private final Map<String, String> schedulerMapping;
+    private final Set<String>[] registeredConsumersMap;
 
     protected AbstractGateway(String id, boolean isDefault) {
         this.gatewayId = id;
         this.isDefault = isDefault;
-        this.registeredConsumers = new HashSet<>();
-        this.registeredScheduleConsumers = new HashSet<>();
-        this.schedulerMapping = new HashMap<>();
+        registeredConsumersMap = new Set[ConsumerType.values().length];
+        for (ConsumerType value : ConsumerType.values()) {
+            registeredConsumersMap[value.ordinal()] = new HashSet<>();
+        }
     }
 
     protected AbstractGateway(String id) {
@@ -81,7 +101,24 @@ public abstract class AbstractGateway {
     }
 
     private boolean isConsumerRegistered(String consumerName) {
-        return registeredConsumers.contains(consumerName) || registeredScheduleConsumers.contains(consumerName);
+        for (ConsumerType type : ConsumerType.values()) {
+            if (isConsumerRegistered(type, consumerName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isConsumerRegistered(ConsumerType type, String name) {
+        return registeredConsumersMap[type.ordinal()].contains(name);
+    }
+
+    private Set<String> getRegisterConsumers(ConsumerType type) {
+        return registeredConsumersMap[type.ordinal()];
+    }
+
+    private void registerConsumer(ConsumerType type, String name) {
+        getRegisterConsumers(type).add(name);
     }
 
     private String createAddress(String consumerName) {
@@ -98,37 +135,23 @@ public abstract class AbstractGateway {
         return RequestUriParser.parse(request, moduleId, gatewayId);
     }
 
-    public interface SchedulerMapping {
-        SchedulerMapping addMapping(String from, String to);
+    private void registerSchedulerConsumers() {
 
-    }
+        for (ConsumerType type : values()) {
+            Set<String> consumers = getRegisterConsumers(type);
 
-    protected final SchedulerMapping schedulerMapping() {
-        return new SchedulerMapping() {
-            @Override public SchedulerMapping addMapping(String from, String to) {
-                schedulerMapping.put(from, to);
-                return this;
+            if (isDefault && !type.canBeDefault() && !consumers.isEmpty()) {
+                logger.warn("Following consumer can not be registered. These consumers can be registered only for default gateways. {}",
+                        Arrays.toString(consumers.toArray())
+                ); continue;
             }
-        };
-    }
 
-    private void registerSchedulerConsumers() {
-        for (Map.Entry<String, String> mappingEntry : schedulerMapping.entrySet()) {
-            if (isDefault) {
-                Consumer<String> check = name -> {
-                    if (!registeredConsumers.contains(name)) {
-                        throw logger.throwing(new RuntimeException(
-                                format("Consumer '%s' in module %s and gateway %s is not registered.",
-                                        name, moduleId, gatewayId
-                                )
-                        ));
-                    }
-                };
-                check.accept(mappingEntry.getKey());
-                check.accept(mappingEntry.getValue());
+            for (String consumer : consumers) {
+                // TODO
             }
         }
 
+
         String baseAddr = isDefault ? SCHEDULER_PROVIDER : SCHEDULER_CONSUMER;
         String gatewayAddr = createNormalized(baseAddr, gatewayId);
         logger.info("[{}/{}] Creating a consumer at the address {}.", moduleId, gatewayId, gatewayAddr);
@@ -136,7 +159,9 @@ public abstract class AbstractGateway {
         eventBus.consumer(gatewayAddr, message -> {
             logger.info("[{}/{}] Handling request from address {}.", moduleId, gatewayId, message.address());
             String schedulerConsumerName = message.headers().get(ADDRESS);
-            if (!registeredScheduleConsumers.contains(schedulerConsumerName)) {
+
+            // TODO split 'consumeScheduler' and 'subscribe' -> set different address
+            if (!isConsumerRegistered(SCHEDULER, schedulerConsumerName)) {
                 logger.error("[{}/{}] Creating a fail message for the address {}.", moduleId, gatewayId, schedulerConsumerName);
                 message.fail(400, "No registered consumer for the address " + schedulerConsumerName);
             } else {
@@ -160,6 +185,7 @@ public abstract class AbstractGateway {
 
     protected interface Event {
         <T> void consumeScheduler(String address, Consumer<Message<T>> handler);
+        <T> void subscribe(String address, Consumer<Message<T>> handler);
         <T> void consume(String address, Consumer<Message<T>> handler);
         <T> void send(String address, Object body, DeliveryOptions options, Consumer<Message<T>> handler);
         <T> void send(String address, Object body, Consumer<Message<T>> handler);
@@ -175,25 +201,17 @@ public abstract class AbstractGateway {
 
         @Override
         public <T> void consumeScheduler(String address, Consumer<Message<T>> handler) {
-            if (registeredScheduleConsumers.contains(address)) {
-                throw logger.throwing(new RuntimeException(
-                        format("Consumer '%s' in module %s and gateway %s is already registered as a scheduler consumer.",
-                                address, moduleId, gatewayId
-                        )
-                ));
-            }
-            registeredScheduleConsumers.add(address);
-            String consumerAddr = createAddress(address);
-            logger.info("[{}/{}] Creating a consumer at the address {}.", moduleId, gatewayId, consumerAddr);
-//            eventBus.<T>consumer(consumerAddr, message -> {
-//                // TODO vymyslet, jak registrovat scheudler tak, aby byl dosazitelny pouze ze scheduleru
-//            });
-            consume(address, handler); // temporary hack
+            consume(SCHEDULER, address, handler);
+        }
+
+        @Override
+        public <T> void subscribe(String address, Consumer<Message<T>> handler) {
+            consume(SUBSCRIBER, address, handler);
         }
 
         @Override
         public <T> void consume(String address, Consumer<Message<T>> handler) {
-            registeredConsumers.add(address);
+            registerConsumer(OTHER, address);
             String consumerAddr = createAddress(address);
             logger.info("[{}/{}] Creating a consumer at the address {}.", moduleId, gatewayId, consumerAddr);
             eventBus.<T>consumer(consumerAddr, message -> {
@@ -245,5 +263,17 @@ public abstract class AbstractGateway {
         public <T> void send(String address, Object body, Consumer<Message<T>> handler) {
             send(address, body, new DeliveryOptions(), handler);
         }
+
+        private <T> void consume(ConsumerType type, String address, Consumer<Message<T>> handler) {
+            if (isConsumerRegistered(type, address)) {
+                throw logger.throwing(new RuntimeException(
+                        format("Consumer '%s' in module %s and gateway %s is already registered as a %s consumer.",
+                                address, moduleId, gatewayId, type.name().toLowerCase()
+                        )
+                ));
+            }
+            registerConsumer(type, address);
+            consume(address, handler);
+        }
     }
 }

+ 6 - 0
connector-core/src/main/java/io/connector/core/AbstractModule.java

@@ -9,6 +9,12 @@ import java.util.Map;
 import static io.connector.core.AddressPath.Creator.create;
 import static io.connector.core.AddressPath.INFO;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public abstract class AbstractModule extends Module {
 
     protected final ModuleDescriptor descriptor;

+ 7 - 1
connector-core/src/main/java/io/connector/core/AddressPath.java

@@ -2,6 +2,12 @@ package io.connector.core;
 
 import static io.connector.core.AddressPath.Creator.create;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public final class AddressPath {
 
     public static final String SCHEDULER_CONSUMER = create("scheduler", "consumer");
@@ -26,4 +32,4 @@ public final class AddressPath {
             return create(parts).toLowerCase();
         }
     }
-}
+}

+ 6 - 0
connector-core/src/main/java/io/connector/core/DataCollection.java

@@ -8,6 +8,12 @@ import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public class DataCollection<T> {
 
     private final List<T> list;

+ 6 - 0
connector-core/src/main/java/io/connector/core/EventInfo.java

@@ -5,6 +5,12 @@ import io.vertx.core.json.JsonObject;
 import java.util.List;
 import java.util.Map;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public class EventInfo {
 
     private String module;

+ 14 - 0
connector-core/src/main/java/io/connector/core/Fail.java

@@ -1,5 +1,11 @@
 package io.connector.core;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public class Fail {
 
     private final int code;
@@ -17,4 +23,12 @@ public class Fail {
     public String getMessage() {
         return message;
     }
+
+    @Override
+    public String toString() {
+        return "Fail{" +
+                "code=" + code +
+                ", message='" + message + '\'' +
+                '}';
+    }
 }

+ 6 - 0
connector-core/src/main/java/io/connector/core/Handler.java

@@ -8,6 +8,12 @@ import java.util.function.Consumer;
 import static io.connector.core.http.ContentType.APPLICATION_JSON;
 import static io.connector.core.http.Header.CONTENT_TYPE;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public final class Handler {
 
     public static <T> Consumer<Message<T>> replyToHttpContext(RoutingContext httpContext) {

+ 6 - 0
connector-core/src/main/java/io/connector/core/Message.java

@@ -3,6 +3,12 @@ package io.connector.core;
 import io.vertx.core.MultiMap;
 import io.vertx.core.eventbus.ReplyException;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public class Message<T> {
 
     private final io.vertx.core.eventbus.Message<T> message;

+ 7 - 1
connector-core/src/main/java/io/connector/core/MessageHeader.java

@@ -1,5 +1,11 @@
 package io.connector.core;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public final class MessageHeader {
 
     public static final String RESOURCE = createName("resource");
@@ -19,4 +25,4 @@ public final class MessageHeader {
     public static String getPrefix() {
         return "__";
     }
-}
+}

+ 7 - 1
connector-core/src/main/java/io/connector/core/Module.java

@@ -3,6 +3,12 @@ package io.connector.core;
 import io.vertx.core.AbstractVerticle;
 import io.vertx.ext.web.Router;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public abstract class Module extends AbstractVerticle {
 
     public final String moduleId;
@@ -28,4 +34,4 @@ public abstract class Module extends AbstractVerticle {
         this.router = Router.router(vertx);
         run();
     }
-}
+}

+ 6 - 0
connector-core/src/main/java/io/connector/core/ModuleDeployer.java

@@ -7,6 +7,12 @@ import org.apache.logging.log4j.Logger;
 import java.util.ArrayList;
 import java.util.List;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public class ModuleDeployer extends AbstractVerticle {
 
     private final static Logger logger = LogManager.getLogger(ModuleDeployer.class);

+ 6 - 0
connector-core/src/main/java/io/connector/core/ModuleDescriptor.java

@@ -3,6 +3,12 @@ package io.connector.core;
 import io.connector.core.config.DefaultConfig;
 import io.connector.core.config.SchedulerConfig;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public class ModuleDescriptor {
 
     private final String id;

+ 7 - 1
connector-core/src/main/java/io/connector/core/ModuleInfo.java

@@ -6,6 +6,12 @@ import io.vertx.core.json.JsonObject;
 
 import java.util.List;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public class ModuleInfo {
 
     private final String id;
@@ -59,7 +65,7 @@ public class ModuleInfo {
 
             @Override
             public String name() {
-                return this.getClass().getName();
+                return ModuleInfo.class.getName();
             }
 
             @Override

+ 7 - 1
connector-core/src/main/java/io/connector/core/ModuleLoader.java

@@ -7,6 +7,12 @@ import org.apache.logging.log4j.Logger;
 
 import java.util.*;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public final class ModuleLoader {
 
     private static final Logger logger = LogManager.getLogger(ModuleLoader.class);
@@ -38,4 +44,4 @@ public final class ModuleLoader {
 
         return modules;
     }
-}
+}

+ 7 - 1
connector-core/src/main/java/io/connector/core/ModuleProvider.java

@@ -1,6 +1,12 @@
 package io.connector.core;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public interface ModuleProvider {
 
     AbstractModule createModule(ModuleDescriptor descriptor);
-}
+}

+ 6 - 0
connector-core/src/main/java/io/connector/core/Reply.java

@@ -2,6 +2,12 @@ package io.connector.core;
 
 import io.vertx.core.eventbus.DeliveryOptions;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public class Reply<T> {
 
     protected final T data;

+ 7 - 1
connector-core/src/main/java/io/connector/core/VertxHttpServer.java

@@ -33,6 +33,12 @@ import static io.connector.core.MessageHeader.RESOURCE;
 import static io.connector.core.MessageHeader.Resource.HTTP_SERVER;
 import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public class VertxHttpServer extends AbstractVerticle {
 
     private final static Logger logger = LogManager.getLogger(VertxHttpServer.class);
@@ -125,4 +131,4 @@ public class VertxHttpServer extends AbstractVerticle {
                     }
                 });
     }
-}
+}

+ 26 - 4
connector-core/src/main/java/io/connector/core/VertxScheduler.java

@@ -26,11 +26,20 @@ import static io.connector.core.MessageHeader.*;
 import static io.connector.core.MessageHeader.Resource.SCHEDULER;
 import static java.lang.String.format;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 class VertxScheduler extends Module {
 
     private final static Logger logger = LogManager.getLogger(VertxScheduler.class);
 
+    // <moduleId, config>
     private final Map<String, SchedulerConfig> schedulerConfigs;
+
+    // <moduleId, schedulerId>
     private final Map<String, Long> scheduledModules;
 
     VertxScheduler(List<AbstractModule> modules) {
@@ -82,9 +91,22 @@ class VertxScheduler extends Module {
     @Override
     public void run() {
 
-//        vertx.setPeriodic(1000, ctx -> { // every minute?
-//            // TODO delete all rules after deadLine
-//        });
+        vertx.setPeriodic(60000, ctx -> { // 60000 = every minute
+            for (Map.Entry<String, SchedulerConfig> entry : schedulerConfigs.entrySet()) {
+                if (entry.getValue().shouldTerminate()) {
+                    long schedulerId = scheduledModules.getOrDefault(entry.getKey(), -1L);
+                    if (schedulerId >= 0) {
+                        SchedulerConfig config = entry.getValue();
+                        boolean successfullyDeleted = vertx.cancelTimer(schedulerId);
+                        if (successfullyDeleted) {
+                            logger.info("Scheduler {} of the module {} was successfully deleted.", config.getId(), entry.getKey());
+                        } else {
+                            logger.error("Scheduler {} of the module {} was not deleted successfully.", config.getId(), entry.getKey());
+                        }
+                    }
+                }
+            }
+        });
 
         for (Map.Entry<String, SchedulerConfig> configEntry : schedulerConfigs.entrySet()) {
             String moduleId = configEntry.getKey();
@@ -150,4 +172,4 @@ class VertxScheduler extends Module {
             }
         });
     }
-}
+}

+ 0 - 81
connector-core/src/main/java/io/connector/core/config/AllowedStation.java

@@ -1,81 +0,0 @@
-package io.connector.core.config;
-
-import java.util.*;
-
-public class AllowedStation {
-
-    private static class Sensor {
-        final Integer id;
-        final Set<Integer> channels;
-        Sensor(Integer id, Set<Integer> channels) {
-            this.id = id;
-            this.channels = channels;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
-            Sensor sensor = (Sensor) o;
-            return id.equals(sensor.id);
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(id);
-        }
-    }
-
-    private final Map<String, Map<Integer, Sensor>> stations;
-
-    public AllowedStation(PropertyConfig config) {
-        Set<String> attributes = config.getAttributes();
-        Map<String, Map<Integer, Sensor>> stations = new HashMap<>(attributes.size());
-        for (String stationId : attributes) {
-            Object attrValue = config.getProperty(stationId);
-            if (attrValue instanceof List) {
-                List<?> sensors = (List<?>)attrValue;
-                for (Object sensor : sensors) {
-                    if (sensor instanceof Map) {
-                        Map<?, ?> sensorMap = (Map<?, ?>)sensor;
-                        for (Map.Entry<?, ?> sensorEntry : sensorMap.entrySet()) {
-                            if (sensorEntry.getKey() instanceof Integer) {
-                                Integer sensorId = (Integer)sensorEntry.getKey();
-                                if (sensorEntry.getValue() instanceof List) {
-                                    List<?> channels = (List<?>)sensorEntry.getValue();
-                                    Set<Integer> channelsNew = new HashSet<>(channels.size());
-                                    for (Object channel : channels) {
-                                        if (channel instanceof Integer) {
-                                            channelsNew.add((Integer)channel);
-                                        }
-                                    }
-                                    stations.computeIfAbsent(stationId, k -> new HashMap<>())
-                                            .put(sensorId, new Sensor(sensorId, channelsNew));
-                                }
-                            }
-                        }
-                    } else if (sensor instanceof Integer) {
-                        Integer sensorId = (Integer)sensor;
-                        stations.computeIfAbsent(stationId, k -> new HashMap<>())
-                                .put(sensorId, new Sensor(sensorId, Collections.emptySet()));
-                    }
-                }
-            }
-        }
-
-        this.stations = stations;
-    }
-
-    public boolean isAllowed(String stationId) {
-        return stations.containsKey(stationId);
-    }
-
-    public boolean isAllowed(String stationId, Long sensorId) {
-        return isAllowed(stationId) && stations.get(stationId).containsKey(sensorId.intValue());
-    }
-
-    public boolean isAllowed(String stationId, Long sensorId, Long channel) {
-        return isAllowed(stationId, sensorId) &&
-                stations.get(stationId).get(sensorId.intValue()).channels.contains(channel.intValue());
-    }
-}

+ 6 - 0
connector-core/src/main/java/io/connector/core/config/HostConfig.java

@@ -1,5 +1,11 @@
 package io.connector.core.config;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public class HostConfig {
 
     private final String domain;

+ 6 - 0
connector-core/src/main/java/io/connector/core/config/PropertyConfig.java

@@ -11,6 +11,12 @@ import static java.lang.String.format;
 import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME;
 import static java.util.Optional.ofNullable;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public class PropertyConfig {
 
     /** Path delimiter separates nodes. */

+ 6 - 0
connector-core/src/main/java/io/connector/core/config/SchedulerConfig.java

@@ -4,6 +4,12 @@ import io.vertx.core.json.JsonObject;
 
 import java.time.LocalDateTime;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public final class SchedulerConfig {
 
     private final String id;

+ 1 - 1
connector-core/src/main/java/io/connector/core/config/file/FileBuilderImpl.java

@@ -12,7 +12,7 @@ import org.apache.logging.log4j.Logger;
  */
 class FileBuilderImpl implements FileBuilder {
 
-    private static Logger logger = LogManager.getLogger(FileBuilderImpl.class);
+    private static final Logger logger = LogManager.getLogger(FileBuilderImpl.class);
 
     /** Name of the file configuration. */
     private String fileName;

+ 9 - 3
connector-core/src/main/java/io/connector/core/config/file/FileConfigurationServiceImpl.java

@@ -1,6 +1,6 @@
 package io.connector.core.config.file;
 
-import cz.senslog.common.util.StringUtils;
+import io.connector.core.util.StringUtils;
 import io.connector.core.ModuleDescriptor;
 import io.connector.core.config.DefaultConfig;
 import io.connector.core.config.SchedulerConfig;
@@ -17,11 +17,17 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.*;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 class FileConfigurationServiceImpl  implements FileConfigurationService {
 
-    private static Logger logger = LogManager.getLogger(FileConfigurationServiceImpl.class);
+    private static final Logger logger = LogManager.getLogger(FileConfigurationServiceImpl.class);
 
-    private Map<String, ModuleDescriptor> moduleDescriptors;
+    private final Map<String, ModuleDescriptor> moduleDescriptors;
 
     /** Name of the configuration file. */
     private final String fileName;

+ 6 - 0
connector-core/src/main/java/io/connector/core/http/ContentType.java

@@ -1,5 +1,11 @@
 package io.connector.core.http;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public final class ContentType {
 
     public static final String APPLICATION_ATOM_XML = "application/atom+xml";

+ 6 - 0
connector-core/src/main/java/io/connector/core/http/Header.java

@@ -1,5 +1,11 @@
 package io.connector.core.http;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public final class Header {
 
     public static final String AUTHORIZATION = "Authorization";

+ 215 - 0
connector-core/src/main/java/io/connector/core/http/HttpClient.java

@@ -0,0 +1,215 @@
+package io.connector.core.http;
+
+import io.connector.core.util.StringUtils;
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpMessage;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.apache.http.util.EntityUtils;
+
+import javax.net.ssl.SSLContext;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.apache.http.HttpHeaders.*;
+
+/**
+ * The class {@code HttpClient} represents a wrapper for {@link org.apache.http.client.HttpClient}.
+ * Provides functionality of sending GET and POST request. Otherwise is returned response with {@see #BAD_REQUEST}.
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
+public class HttpClient {
+
+    /** Instance of http client. */
+    private final org.apache.http.client.HttpClient client;
+
+    /**
+     * Factory method to create a new instance of client.
+     * @return new instance of {@code HttpClient}.
+     */
+    public static HttpClient newHttpClient() {
+        return new HttpClient(HttpClientBuilder.create());
+    }
+
+    public static HttpClient newHttpSSLClient() {
+        try {
+            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (chain, authType) -> true).build();
+            SSLConnectionSocketFactory sslSF =  new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
+            Registry<ConnectionSocketFactory> socketFactoryRegistry =
+                    RegistryBuilder.<ConnectionSocketFactory> create()
+                            .register("https", sslSF)
+                            .register("http", new PlainConnectionSocketFactory())
+                            .build();
+            BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry);
+            HttpClientBuilder httpClientBuilder = HttpClientBuilder.create()
+                    .setConnectionManager(connectionManager)
+                    .setSSLSocketFactory(sslSF);
+
+            return new HttpClient(httpClientBuilder);
+
+        } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Private constructors sets http client.
+     */
+    private HttpClient(HttpClientBuilder httpClientBuilder) {
+        this.client = httpClientBuilder.build();
+    }
+
+    /**
+     * Sends http request.
+     * @param request - virtual request.
+     * @return virtual response.
+     */
+    public HttpResponse send(HttpRequest request) {
+        try {
+            switch (request.getMethod()) {
+                case GET:  return sendGet(request);
+                case POST: return sendPost(request);
+                default: return HttpResponse.newBuilder()
+                            .body("Request does not contain method definition.")
+                            .status(HttpCode.METHOD_NOT_ALLOWED).build();
+            }
+        } catch (URISyntaxException e) {
+            return HttpResponse.newBuilder()
+                    .body(e.getMessage()).status(HttpCode.BAD_REQUEST)
+                    .build();
+        } catch (IOException e) {
+            return  HttpResponse.newBuilder()
+                    .body(e.getMessage()).status(HttpCode.SERVER_ERROR)
+                    .build();
+        }
+    }
+
+    /**
+     * Sends GET request.
+     * @param request - virtual request.
+     * @return virtual response of the request.
+     * @throws URISyntaxException throws if host url is not valid.
+     * @throws IOException throws if anything happen during sending.
+     */
+    private HttpResponse sendGet(HttpRequest request) throws IOException, URISyntaxException {
+
+        URI uri = request.getUrl().toURI();
+        HttpGet requestGet = new HttpGet(uri);
+        setBasicHeaders(request, requestGet);
+
+        org.apache.http.HttpResponse responseGet = client.execute(requestGet);
+
+        HttpResponse response = HttpResponse.newBuilder()
+                .status(responseGet.getStatusLine().getStatusCode())
+                .headers(getHeaders(responseGet))
+                .body(getBody(responseGet.getEntity()))
+                .build();
+
+        EntityUtils.consume(responseGet.getEntity());
+
+        return response;
+    }
+
+    /**
+     * Sends POST request.
+     * @param request - virtual request.
+     * @return virtual response of the request.
+     * @throws URISyntaxException throws if host url is not valid.
+     * @throws IOException throws if anything happen during sending.
+     */
+    private HttpResponse sendPost(HttpRequest request) throws URISyntaxException, IOException {
+
+        URI uri = request.getUrl().toURI();
+        HttpPost requestPost = new HttpPost(uri);
+        setBasicHeaders(request, requestPost);
+
+        if (StringUtils.isNotBlank(request.getContentType())) {
+            requestPost.setHeader(CONTENT_TYPE, request.getContentType());
+        }
+
+        requestPost.setEntity(new StringEntity(request.getBody()));
+
+        org.apache.http.HttpResponse responsePost = client.execute(requestPost);
+
+        HttpResponse response = HttpResponse.newBuilder()
+                .headers(getHeaders(requestPost))
+                .status(responsePost.getStatusLine().getStatusCode())
+                .body(getBody(responsePost.getEntity()))
+                .build();
+
+        EntityUtils.consume(responsePost.getEntity());
+
+        return response;
+    }
+
+    /**
+     * Sets basic headers to each request.
+     * @param userRequest - virtual request.
+     * @param httpRequest - real request prepared to send.
+     */
+    private void setBasicHeaders(HttpRequest userRequest, HttpRequestBase httpRequest) {
+
+        httpRequest.setHeader(USER_AGENT, "Connector/1.0");
+        httpRequest.setHeader(CACHE_CONTROL, "no-cache");
+
+        for (Map.Entry<String, String> headerEntry : userRequest.getHeaders().entrySet()) {
+            httpRequest.setHeader(headerEntry.getKey(), headerEntry.getValue());
+        }
+    }
+
+    /**
+     * Returns map of headers from the response.
+     * @param response - response message.
+     * @return map of headers.
+     */
+    private Map<String, String> getHeaders(HttpMessage response) {
+        Map<String, String> headers = new HashMap<>();
+        for (Header header : response.getAllHeaders()) {
+            headers.put(header.getName(), header.getValue());
+        }
+        return headers;
+    }
+
+    /**
+     * Returns body from the response.
+     * @param entity - response entity.
+     * @return string body of the response.
+     * @throws IOException can not get body from the response.
+     */
+    private String getBody(HttpEntity entity) throws IOException {
+        if (entity == null) return "";
+        InputStream contentStream = entity.getContent();
+        InputStreamReader bodyStream = new InputStreamReader(contentStream);
+        BufferedReader rd = new BufferedReader(bodyStream);
+        StringBuilder bodyBuffer = new StringBuilder();
+        String line;
+        while ((line = rd.readLine()) != null) {
+            bodyBuffer.append(line);
+        }
+        return bodyBuffer.toString();
+    }
+}

+ 22 - 0
connector-core/src/main/java/io/connector/core/http/HttpCode.java

@@ -0,0 +1,22 @@
+package io.connector.core.http;
+
+public class HttpCode {
+
+    public static final int OK = 200;
+
+    public static final int NO_RESULT = 204;
+
+    public static final int NO_CONTENT = 204;
+
+    public static final int BAD_REQUEST = 400;
+
+    public static final int UNAUTHORIZED = 401;
+
+    public static final int FORBIDDEN = 403;
+
+    public static final int NOT_FOUND = 404;
+
+    public static final int METHOD_NOT_ALLOWED = 405;
+
+    public static final int SERVER_ERROR = 500;
+}

+ 5 - 0
connector-core/src/main/java/io/connector/core/http/HttpMethod.java

@@ -0,0 +1,5 @@
+package io.connector.core.http;
+
+public enum HttpMethod {
+    GET, POST
+}

+ 101 - 0
connector-core/src/main/java/io/connector/core/http/HttpRequest.java

@@ -0,0 +1,101 @@
+package io.connector.core.http;
+
+import io.vertx.core.json.Json;
+
+import java.net.URL;
+import java.util.Map;
+
+/**
+ * The class {@code HttpRequest} represents a wrapper for a http request.
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
+public class HttpRequest {
+
+    public interface Builder {
+        Builder header(String name, String value);
+        Builder url(URL url);
+        Builder POST();
+        Builder GET();
+        Builder contentType(String contentType);
+        Builder body(String body);
+        HttpRequest build();
+    }
+
+    /**
+     * Factory method to create a new builder for {@link HttpRequest}.
+     * @return new instance of builder.
+     */
+    public static Builder newBuilder() {
+        return new HttpRequestBuilder();
+    }
+
+    /**
+     * Factory method to create a new builder for {@link HttpRequest}.
+     * @param url - host url.
+     * @return new instance of builder.
+     */
+    public static Builder newBuilder(URL url) {
+        HttpRequestBuilder builder = new HttpRequestBuilder();
+        builder.url(url);
+        return builder;
+    }
+
+    /** Request url. */
+    private final URL url;
+
+    /** Request headers. */
+    private final Map<String, String> headers;
+
+    /** Request body. */
+    private final String body;
+
+    /** Request method. */
+    private final HttpMethod method;
+
+    /** Request content type. */
+    private final String contentType;
+
+    /**
+     * Constructors sets all attributes.
+     * @param url - url.
+     * @param headers - headers.
+     * @param body - body.
+     * @param method - method.
+     * @param contentType - content type.
+     */
+    HttpRequest(URL url, Map<String, String> headers, String body, HttpMethod method, String contentType) {
+        this.url = url;
+        this.headers = headers;
+        this.body = body;
+        this.method = method;
+        this.contentType = contentType;
+    }
+
+    public URL getUrl() {
+        return url;
+    }
+
+    public String getBody() {
+        return body;
+    }
+
+    public HttpMethod getMethod() {
+        return method;
+    }
+
+    public Map<String, String> getHeaders() {
+        return headers;
+    }
+
+    public String getContentType() {
+        return contentType;
+    }
+
+    @Override
+    public String toString() {
+        return Json.encode(this);
+    }
+}

+ 69 - 0
connector-core/src/main/java/io/connector/core/http/HttpRequestBuilder.java

@@ -0,0 +1,69 @@
+package io.connector.core.http;
+
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The class {@code HttpRequestBuilder} represents a builder for the {@link io.connector.core.http.HttpRequest}.
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
+final class HttpRequestBuilder implements HttpRequest.Builder {
+
+    private URL url;
+    private Map<String, String> headers;
+    private String body;
+    private HttpMethod method;
+    private String contentType;
+
+    HttpRequestBuilder() {
+        this.headers = new HashMap<>();
+        this.method = HttpMethod.GET;
+        this.body = "";
+    }
+
+    @Override
+    public HttpRequest.Builder header(String name, String value) {
+        this.headers.put(name, value);
+        return this;
+    }
+
+    @Override
+    public HttpRequest.Builder url(URL url) {
+        this.url = url;
+        return this;
+    }
+
+    @Override
+    public HttpRequest.Builder POST() {
+        this.method = HttpMethod.POST;
+        return this;
+    }
+
+    @Override
+    public HttpRequest.Builder GET() {
+        this.method = HttpMethod.GET;
+        return this;
+    }
+
+    @Override
+    public HttpRequest.Builder contentType(String contentType) {
+        this.contentType = contentType;
+        return this;
+    }
+
+    @Override
+    public HttpRequest.Builder body(String body) {
+        this.body = body;
+        return this;
+    }
+
+    @Override
+    public HttpRequest build() {
+        return new HttpRequest(url, headers, body, method, contentType);
+    }
+}

+ 77 - 0
connector-core/src/main/java/io/connector/core/http/HttpResponse.java

@@ -0,0 +1,77 @@
+package io.connector.core.http;
+
+import io.vertx.core.json.Json;
+
+import java.util.Map;
+
+/**
+ * The class {@code HttpResponse} represents a wrapper for a http response.
+ * Contains basic information like status, headers and body.
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
+public class HttpResponse {
+
+    public interface Builder {
+        Builder body(String body);
+        Builder headers(Map<String, String> headers);
+        Builder status(int status);
+        HttpResponse build();
+    }
+
+    /**
+     * Factory method to create a new builder for {@link HttpResponse}.
+     * @return new instance of builder.
+     */
+    public static Builder newBuilder() {
+        return new HttpResponseBuilder();
+    }
+
+    /** Response body. */
+    private final String body;
+
+    /** Response headers. */
+    private final Map<String, String> headers;
+
+    /** Response status. */
+    private final int status;
+
+    /**
+     * Constructors sets all attributes.
+     * @param body - body.
+     * @param headers - headers.
+     * @param status - status.
+     */
+    HttpResponse(String body, Map<String, String> headers, int status) {
+        this.body = body;
+        this.headers = headers;
+        this.status = status;
+    }
+
+    public String getBody() {
+        return body;
+    }
+
+    public String getHeader(String value) {
+        return headers.get(value);
+    }
+
+    public int getStatus() {
+        return status;
+    }
+
+    public boolean isOk() {
+        return status == HttpCode.OK;
+    }
+
+    public boolean isError() {
+        return !isOk();
+    }
+
+    @Override
+    public String toString() {
+        return Json.encode(this);
+    }
+}

+ 42 - 0
connector-core/src/main/java/io/connector/core/http/HttpResponseBuilder.java

@@ -0,0 +1,42 @@
+package io.connector.core.http;
+
+import java.util.Map;
+
+/**
+ * The class {@code HttpResponseBuilder} represents a builder for the {@link HttpResponse}.
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
+class HttpResponseBuilder implements HttpResponse.Builder {
+
+    private String body;
+    private Map<String, String> headers;
+    private int status;
+
+    HttpResponseBuilder(){}
+
+    @Override
+    public HttpResponse.Builder body(String body) {
+        this.body = body;
+        return this;
+    }
+
+    @Override
+    public HttpResponse.Builder headers(Map<String, String> headers) {
+        this.headers = headers;
+        return this;
+    }
+
+    @Override
+    public HttpResponse.Builder status(int status) {
+        this.status = status;
+        return this;
+    }
+
+    @Override
+    public HttpResponse build() {
+        return new HttpResponse(body, headers, status);
+    }
+}

+ 6 - 0
connector-core/src/main/java/io/connector/core/http/RequestUriComponent.java

@@ -2,6 +2,12 @@ package io.connector.core.http;
 
 import static io.connector.core.AddressPath.Creator.create;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public class RequestUriComponent {
 
     private final String domain;

+ 6 - 0
connector-core/src/main/java/io/connector/core/http/RequestUriParser.java

@@ -4,6 +4,12 @@ import io.vertx.core.http.HttpServerRequest;
 
 import static io.connector.core.AddressPath.Creator.create;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public final class RequestUriParser {
 
     public static RequestUriComponent parse(HttpServerRequest req, String moduleId, String gatewayId) {

+ 113 - 0
connector-core/src/main/java/io/connector/core/http/URLBuilder.java

@@ -0,0 +1,113 @@
+package io.connector.core.http;
+
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import static java.net.URLEncoder.encode;
+
+/**
+ * The class {@code URLBuilder} represents a builder to create a new instance of {@link URL}.
+ * Provides a creating a url from domain and path and adding a parameter.
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
+public final class URLBuilder {
+
+    /**
+     * Factory method to create a new instance of {@code URLBuilder} from base url.
+     * @param baseURL - host url.
+     * @return new instance of {@code URLBuilder}.
+     */
+    public static URLBuilder newBuilder(String baseURL) {
+        return new URLBuilder(baseURL);
+    }
+
+    /**
+     * Factory method to create a new instance of {@code URLBuilder} from domain and path.
+     * Normalizes domain and path to the form:
+     *
+     * domain: http://domain.com/
+     * path: /host
+     * -> url: http://domain.com/host
+     *
+     * domain: http://domain.com
+     * path: host
+     * -> url: http://domain.com/host
+     *
+     * @param domain - domain of host.
+     * @param path - path of host.
+     * @return new instance of {@code URLBuilder}.
+     */
+    public static URLBuilder newBuilder(String domain, String path) {
+        boolean domainSlash = domain.endsWith("/");
+        boolean pathSlash = path.startsWith("/");
+
+        if ((domainSlash && !pathSlash) || (!domainSlash && pathSlash)) {
+            return new URLBuilder(domain + path);
+        } else if (domainSlash) {
+            return new URLBuilder(domain + path.substring(1));
+        } else {
+            return new URLBuilder(domain + "/" + path);
+        }
+    }
+
+    /** String builder for url. */
+    private final StringBuilder urlBuilder;
+
+    /** String builder for parameters. */
+    private final StringBuilder paramsBuilder;
+
+    /**
+     * Private constructor initializes builders and normalizes url.
+     * If the url ends with slash '/', it is removed.
+     * @param baseURL - host url.
+     */
+    private URLBuilder(String baseURL) {
+        String url = baseURL.endsWith("/") ? baseURL.substring(0, baseURL.length() - 1) : baseURL;
+        this.urlBuilder = new StringBuilder(url);
+        this.paramsBuilder = new StringBuilder();
+    }
+
+    /**
+     * Adds a new parameter to the url.
+     * @param name - name of parameter.
+     * @param value - value of parameter.
+     * @return instance of {@code URLBuilder}.
+     */
+    public URLBuilder addParam(String name, String value) {
+        try {
+            paramsBuilder.append("&").append(name).append("=").append(encode(value, "UTF-8"));
+        } catch (UnsupportedEncodingException e) {
+            throw new AssertionError(e.getMessage());
+        }
+        return this;
+    }
+
+    /**
+     * Adds a new parameter to the url.
+     * @param name - name of parameter.
+     * @param value - value of parameter.
+     * @return instance of {@code URLBuilder}.
+     */
+    public URLBuilder addParam(String name, Object value) {
+        if (value == null) return this;
+        return addParam(name, value.toString());
+    }
+
+    /**
+     * Creates a new instance of {@link URL}.
+     * @return new instance of {@link URL}.
+     */
+    public URL build() {
+        try {
+            String params = paramsBuilder.replace(0, 1, "").toString();
+            return new URL(urlBuilder.append(params.isEmpty() ? "" : ("?" + params)).toString());
+        } catch (MalformedURLException e) {
+            throw new IllegalArgumentException(e.getMessage(), e);
+        }
+    }
+}
+

+ 6 - 0
connector-core/src/main/java/io/connector/core/json/DeserializeFormatter.java

@@ -1,5 +1,11 @@
 package io.connector.core.json;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 @FunctionalInterface
 public interface DeserializeFormatter<T> {
     T apply(String element);

+ 6 - 0
connector-core/src/main/java/io/connector/core/json/JsonAttributeFormatter.java

@@ -2,6 +2,12 @@ package io.connector.core.json;
 
 import com.fasterxml.jackson.databind.module.SimpleModule;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public interface JsonAttributeFormatter {
 
     static JsonAttributeFormatter builder() {

+ 6 - 0
connector-core/src/main/java/io/connector/core/json/JsonDeserializer.java

@@ -6,6 +6,12 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
 
 import java.io.IOException;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 final class JsonDeserializer<T> extends StdDeserializer<T> {
 
     private final DeserializeFormatter<T> formatter;

+ 6 - 0
connector-core/src/main/java/io/connector/core/json/JsonSerializer.java

@@ -6,6 +6,12 @@ import com.fasterxml.jackson.databind.ser.std.StdSerializer;
 
 import java.io.IOException;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 final class JsonSerializer<T> extends StdSerializer<T> {
 
     private final SerializeFormatter<T> formatter;

+ 6 - 0
connector-core/src/main/java/io/connector/core/json/SerializeFormatter.java

@@ -1,5 +1,11 @@
 package io.connector.core.json;
 
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 @FunctionalInterface
 public interface SerializeFormatter<T> {
     String apply(T element);

+ 60 - 0
connector-core/src/main/java/io/connector/core/util/StringUtils.java

@@ -0,0 +1,60 @@
+package io.connector.core.util;
+
+/**
+ * The class {@code StringUtils} represents set of tools for strings.
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
+public final class StringUtils {
+
+    /**
+     * Test if input string is null or empty.
+     * Examples:
+     *          null -> true
+     *          ""   -> true
+     *          " "  -> false
+     *          "a"  -> false
+     *
+     * @param string - input string to test.
+     * @return boolean value.
+     */
+    public static boolean isEmpty(String string) {
+        return string == null || string.isEmpty();
+    }
+
+    /**
+     * Tests if input string is null, empty or contains white characters.
+     * Examples:
+     *          null   -> true
+     *          ""     -> true
+     *          " "    -> true
+     *          "    " -> true
+     *          "a"    -> false
+     *
+     * @param string - input string to test.
+     * @return boolean value.
+     */
+    public static boolean isBlank(String string) {
+        return string == null || string.replaceAll("\\s+","").isEmpty();
+    }
+
+    /**
+     *  Tests negative functionality of {@see StringUtils#isEmpty}.
+     * @param string - input string to test.
+     * @return boolean value.
+     */
+    public static boolean isNotEmpty(String string) {
+        return !isEmpty(string);
+    }
+
+    /**
+     *  Tests negative functionality of {@see StringUtils#isBlank}.
+     * @param string - input string to test.
+     * @return boolean value.
+     */
+    public static boolean isNotBlank(String string) {
+        return !isBlank(string);
+    }
+}

+ 7 - 0
connector-module-afarcloud/src/main/java/io/connector/module/afarcloud/AFCConfig.java

@@ -2,6 +2,13 @@ package io.connector.module.afarcloud;
 
 import io.connector.core.config.DefaultConfig;
 
+/**
+ * The class contains a required configuration for the AFarCloud system.
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public class AFCConfig {
 
     private final String telemetryDomain;

+ 48 - 14
connector-module-afarcloud/src/main/java/io/connector/module/afarcloud/AFCClient.java → connector-module-afarcloud/src/main/java/io/connector/module/afarcloud/AFCHttpClient.java

@@ -1,16 +1,14 @@
 package io.connector.module.afarcloud;
 
-import cz.senslog.common.http.HttpClient;
-import cz.senslog.common.http.HttpRequest;
-import cz.senslog.common.http.HttpResponse;
-import cz.senslog.common.http.URLBuilder;
+import io.connector.core.http.HttpClient;
+import io.connector.core.http.HttpRequest;
+import io.connector.core.http.HttpResponse;
+import io.connector.core.http.URLBuilder;
 import io.connector.core.config.HostConfig;
 import io.connector.model.afarcloud.MultiSensor;
 import io.connector.model.afarcloud.MultiSimpleObservation;
 import io.connector.model.afarcloud.ResourceMeasurement;
-import io.connector.module.afarcloud.gateway.SensLog1Gateway;
 import io.vertx.core.json.Json;
-import io.vertx.core.json.JsonObject;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -20,9 +18,16 @@ import java.util.List;
 import static io.connector.core.http.ContentType.TEXT_PLAIN;
 import static java.lang.String.format;
 
-public class AFCClient {
+/**
+ *
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
+public class AFCHttpClient {
 
-    private final static Logger logger = LogManager.getLogger(SensLog1Gateway.class);
+    private final static Logger logger = LogManager.getLogger(AFCHttpClient.class);
 
     private static class ResponseOfMeasurement {
         private ResultOfMeasurement results;
@@ -49,18 +54,22 @@ public class AFCClient {
 
     private final HttpClient httpClient;
 
-    public AFCClient(AFCConfig config, HttpClient httpClient) {
+    public AFCHttpClient(AFCConfig config, HttpClient httpClient) {
         this.config = config;
         this.httpClient = httpClient;
     }
 
     public void uploadAggregatedMeasurements(List<MultiSimpleObservation> observations) {
 
+        if (observations == null || observations.isEmpty()) {
+            logger.warn("Nothing to upload. Received observations of multi-sensor are empty."); return;
+        }
+
         HostConfig host = new HostConfig(config.getTelemetryDomain(), "telemetry");
+        logger.debug("Getting observations from {}.", host.getDomain());
 
-        if (observations.size() > 0) {
-            JsonObject json = JsonObject.mapFrom(observations.get(0));
-            System.out.println(json.encodePrettily());
+        for (MultiSimpleObservation multiSensor : observations) {
+            System.out.println(Json.encode(multiSensor)); // TODO upload to the server
         }
         
         logger.info("Converted {} observations.", observations.size());
@@ -68,6 +77,7 @@ public class AFCClient {
 
     public List<ResourceMeasurement> getObservationsBySensor(Filter filter) {
         HostConfig host = new HostConfig(config.getRetrievalDomain(), "getObservationsBySensor/historic");
+        logger.debug("Getting observations from {}.", host.getDomain());
 
         URLBuilder urlBuilder = URLBuilder.newBuilder(host.getDomain(), host.getPath());
 
@@ -91,13 +101,18 @@ public class AFCClient {
 
         HttpRequest request = HttpRequest.newBuilder()
                 .contentType(TEXT_PLAIN).url(urlBuilder.build()).GET().build();
+        logger.info("Creating a http request to {}.", request);
 
         HttpResponse response = httpClient.send(request);
+        logger.info("Received a response with a status: {} for the domain {}.", response.getStatus(), host.getDomain());
 
         if (response.isError()) {
+            logger.error("Can not get data from the server {}. Error {} {}",
+                    host.getDomain(), response.getStatus(), response.getBody());
             throw new RuntimeException(response.getBody());
         }
 
+        logger.debug("Parsing body of the response to the class {}.", ResponseOfMeasurement.class);
         ResponseOfMeasurement responseModel = Json.decodeValue(response.getBody(), ResponseOfMeasurement.class);
         if (responseModel == null || responseModel.results == null || responseModel.results.resources == null) {
             return Collections.emptyList();
@@ -106,30 +121,38 @@ public class AFCClient {
     }
 
     public List<ResourceMeasurement> getLatestObservationsBySensor(Filter filter) {
-
         HostConfig host = new HostConfig(config.getRetrievalDomain(), "getObservationsBySensor/latest");
+        logger.debug("Getting observations from {}.", host.getDomain());
 
         URLBuilder urlBuilder = URLBuilder.newBuilder(host.getDomain(), host.getPath());
 
         if (filter.limit > 0) {
+            logger.debug("Adding a parameter 'limit' to the request.");
             urlBuilder.addParam("limit", filter.limit());
         }
         if (filter.entityNames != null) {
+            logger.debug("Adding a parameter 'entityNames' to the request.");
             urlBuilder.addParam("entityNames", filter.entityNames());
         }
         if (filter.measurements != null) {
+            logger.debug("Adding a parameter 'measurements' to the request.");
             urlBuilder.addParam("measurements", filter.measurements());
         }
 
         HttpRequest request = HttpRequest.newBuilder()
                 .contentType(TEXT_PLAIN).url(urlBuilder.build()).GET().build();
+        logger.info("Creating a http request to {}.", request);
 
         HttpResponse response = httpClient.send(request);
+        logger.info("Received a response with a status: {} for the domain {}.", response.getStatus(), host.getDomain());
 
         if (response.isError()) {
+            logger.error("Can not get data from the server {}. Error {} {}",
+                    host.getDomain(), response.getStatus(), response.getBody());
             throw new RuntimeException(response.getBody());
         }
 
+        logger.debug("Parsing body of the response to the class {}.", ResponseOfMeasurement.class);
         ResponseOfMeasurement responseModel = Json.decodeValue(response.getBody(), ResponseOfMeasurement.class);
         if (responseModel == null || responseModel.results == null || responseModel.results.resources == null) {
             return Collections.emptyList();
@@ -138,20 +161,25 @@ public class AFCClient {
     }
 
     public List<MultiSensor> getAllSensors() {
-
         HostConfig host = new HostConfig(config.getInfoDomain(), "registry/getAllSensors");
+        logger.debug("Getting observations from {}.", host.getDomain());
 
         HttpRequest request = HttpRequest.newBuilder()
                 .contentType(TEXT_PLAIN)
                 .url(URLBuilder.newBuilder(host.getDomain(), host.getPath()).build())
                 .GET().build();
+        logger.info("Creating a http request to {}.", request);
 
         HttpResponse response = httpClient.send(request);
+        logger.info("Received a response with a status: {} for the domain {}.", response.getStatus(), host.getDomain());
 
         if (response.isError()) {
+            logger.error("Can not get data from the server {}. Error {} {}",
+                    host.getDomain(), response.getStatus(), response.getBody());
             throw new RuntimeException(response.getBody());
         }
 
+        logger.debug("Parsing body of the response to the class {}.", ResultOfMultiSensor.class);
         ResultOfMultiSensor resultModel = Json.decodeValue(format("{\"sensors\":%s}", response.getBody()), ResultOfMultiSensor.class);
         if (resultModel == null || resultModel.sensors == null) {
             return Collections.emptyList();
@@ -161,18 +189,24 @@ public class AFCClient {
 
     public MultiSensor getSensorByResourceId(String resourceId) {
         HostConfig host = new HostConfig(config.getInfoDomain(), format("registry/getSensor/%s", resourceId));
+        logger.debug("Getting observations from {}.", host.getDomain());
 
         HttpRequest request = HttpRequest.newBuilder()
                 .contentType(TEXT_PLAIN)
                 .url(URLBuilder.newBuilder(host.getDomain(), host.getPath()).build())
                 .GET().build();
+        logger.info("Creating a http request to {}.", request);
 
         HttpResponse response = httpClient.send(request);
+        logger.info("Received a response with a status: {} for the domain {}.", response.getStatus(), host.getDomain());
 
         if (response.isError()) {
+            logger.error("Can not get data from the server {}. Error {} {}",
+                    host.getDomain(), response.getStatus(), response.getBody());
             throw new RuntimeException(response.getBody());
         }
 
+        logger.debug("Parsing body of the response to the class {}.", MultiSensor.class);
         return Json.decodeValue(response.getBody(), MultiSensor.class);
     }
 

+ 9 - 5
connector-module-afarcloud/src/main/java/io/connector/module/afarcloud/AFCModule.java

@@ -3,23 +3,27 @@ package io.connector.module.afarcloud;
 import io.connector.core.AbstractModule;
 import io.connector.core.ModuleDescriptor;
 import io.connector.core.ModuleInfo;
-import io.connector.module.afarcloud.gateway.AFCGateway;
 import io.connector.module.afarcloud.gateway.OGCSensorThingsGateway;
 import io.connector.module.afarcloud.gateway.SensLog1Gateway;
 
-
+/**
+ *
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public class AFCModule extends AbstractModule {
 
-    private final AFCClient client;
+    private final AFCHttpClient client;
 
-    public AFCModule(String id, ModuleDescriptor descriptor, AFCClient client) {
+    public AFCModule(String id, ModuleDescriptor descriptor, AFCHttpClient client) {
         super(id, descriptor);
         this.client = client;
     }
 
     @Override
     public void run() {
-        registerGateway(new AFCGateway("AFarCloud", client));
         registerGateway(new SensLog1Gateway("SensLogV1", client));
         registerGateway(new OGCSensorThingsGateway("OGCSensorThings", client));
     }

+ 9 - 2
connector-module-afarcloud/src/main/java/io/connector/module/afarcloud/AFCModuleProvider.java

@@ -1,17 +1,24 @@
 package io.connector.module.afarcloud;
 
-import cz.senslog.common.http.HttpClient;
+import io.connector.core.http.HttpClient;
 import io.connector.core.AbstractModule;
 import io.connector.core.ModuleDescriptor;
 import io.connector.core.ModuleProvider;
 
+/**
+ *
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public final class AFCModuleProvider implements ModuleProvider {
 
     @Override
     public AbstractModule createModule(ModuleDescriptor descriptor) {
 
         AFCConfig config = new AFCConfig(descriptor.getServiceConfig());
-        AFCClient client = new AFCClient(config, HttpClient.newHttpClient());
+        AFCHttpClient client = new AFCHttpClient(config, HttpClient.newHttpClient());
         AFCModule module = new AFCModule("AFarCloud", descriptor, client);
 
         return module;

+ 0 - 18
connector-module-afarcloud/src/main/java/io/connector/module/afarcloud/UnitCollection.java

@@ -1,18 +0,0 @@
-package io.connector.module.afarcloud;
-
-import io.vertx.core.json.JsonArray;
-
-public class UnitCollection extends JsonArray {
-
-    public static class Unit {
-        public String stationId;
-
-        public Unit(String stationId) {
-            this.stationId = stationId;
-        }
-    }
-
-    public void addUnit(Unit multiSensor) {
-        this.add(multiSensor);
-    }
-}

+ 0 - 17
connector-module-afarcloud/src/main/java/io/connector/module/afarcloud/gateway/AFCGateway.java

@@ -1,17 +0,0 @@
-package io.connector.module.afarcloud.gateway;
-
-import io.connector.core.AbstractGateway;
-import io.connector.module.afarcloud.AFCClient;
-
-public class AFCGateway extends AbstractGateway {
-
-    private final AFCClient client;
-
-    public AFCGateway(String id, AFCClient client) {
-        super(id, true);
-        this.client = client;
-    }
-
-    @Override
-    public void run() {}
-}

+ 45 - 10
connector-module-afarcloud/src/main/java/io/connector/module/afarcloud/gateway/OGCSensorThingsGateway.java

@@ -6,9 +6,11 @@ import io.connector.model.afarcloud.MultiSensor;
 import io.connector.model.afarcloud.ResourceMeasurement;
 import io.connector.model.afarcloud.SensorTelemetry;
 import io.connector.model.sensorthings.*;
-import io.connector.module.afarcloud.AFCClient;
+import io.connector.module.afarcloud.AFCHttpClient;
 import io.connector.module.afarcloud.Filter;
 import io.vertx.core.json.JsonObject;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 import java.time.Instant;
 import java.util.*;
@@ -24,11 +26,26 @@ import static java.lang.String.format;
 import static java.util.Arrays.asList;
 import static java.util.Optional.ofNullable;
 
+/**
+ *
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public class OGCSensorThingsGateway extends AbstractGateway {
 
-    private final AFCClient client;
+    private final static Logger logger = LogManager.getLogger(OGCSensorThingsGateway.class);
 
-    public OGCSensorThingsGateway(String id, AFCClient client) {
+    /** Attribute of a client that accesses to the AFarCloud system.  */
+    private final AFCHttpClient client;
+
+    /**
+     * Public constructor of the class that initializes final attributes.
+     * @param id - identifier of the gateway
+     * @param client - client allows access to the AFarCloud system
+     */
+    public OGCSensorThingsGateway(String id, AFCHttpClient client) {
         super(id);
         this.client = client;
     }
@@ -37,6 +54,7 @@ public class OGCSensorThingsGateway extends AbstractGateway {
     protected void run() {
 
         router().get(create("Things")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             List<MultiSensor> afcMultiSensors = client.getAllSensors();
             List<Thing> ogcThings = Converter.convertToThing(afcMultiSensors, uriComponent);
@@ -44,6 +62,7 @@ public class OGCSensorThingsGateway extends AbstractGateway {
         });
 
         router().get(create("Things(:id)")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String resourceUrn = ctx.pathParam("id"); // resourceUrn
             MultiSensor afcMultiSensor = client.getSensorByResourceUrn(resourceUrn);
@@ -52,6 +71,7 @@ public class OGCSensorThingsGateway extends AbstractGateway {
         });
 
         router().get(create("Datastreams(:id)/Thing")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String id = ctx.pathParam("id"); // resourceUrn + observedProperty
             String[] idCmp = Converter.disassemblyId(id);
@@ -60,27 +80,25 @@ public class OGCSensorThingsGateway extends AbstractGateway {
         });
 
         router().get(create("HistoricalLocations(:id)/Thing")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String id = ctx.pathParam("id"); // resourceUrn + observedProperty + time
-
             String [] idCmp = Converter.disassemblyId(id);
             String resourceUrn = idCmp[0];
-
             MultiSensor afcMultiSensor = client.getSensorByResourceUrn(resourceUrn);
             Thing ogcThing = Converter.convertToThing(afcMultiSensor, uriComponent);
             ctx.response().putHeader(CONTENT_TYPE, APPLICATION_JSON).end(ogcThing.encode());
         });
 
         router().get(create("Datastreams(:id)")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String id = ctx.pathParam("id"); // resourceUrn + observedProperty
             String[] idCmp = Converter.disassemblyId(id);
             String resourceUrn = idCmp[0], observedProperty = idCmp[1];
             MultiSensor afcMultiSensor = client.getSensorByResourceUrn(resourceUrn);
             List<ResourceMeasurement> afcMeasurements = client.getLatestObservationsBySensor(new Filter()
-                    .limit(1)
-                    .entityNames(afcMultiSensor.getResourceId())
-                    .measurements(observedProperty)
+                    .limit(1).entityNames(afcMultiSensor.getResourceId()).measurements(observedProperty)
             );
             final Supplier<IllegalArgumentException> exception = () -> new IllegalArgumentException("Can not find Datastream with @iot.id \"" + id + "\".");
 
@@ -98,6 +116,7 @@ public class OGCSensorThingsGateway extends AbstractGateway {
         });
 
         router().get(create("Things(:id)/Datastreams")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String resourceUrn = ctx.pathParam("id"); // resourceUrn
             MultiSensor afcMultiSensor = client.getSensorByResourceUrn(resourceUrn);
@@ -111,18 +130,21 @@ public class OGCSensorThingsGateway extends AbstractGateway {
         });
 
         router().get(create("Sensors(:id)/Datastreams")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String resourceUrn = ctx.pathParam("id"); // resourceUrn
             ctx.reroute(format("%s/Things(%s)/Datastreams", uriComponent.getGatewayPath(), resourceUrn));
         });
 
         router().get(create("ObservedProperties(:id)/Datastream")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String id = ctx.pathParam("id"); // resourceUrn + observedProperty
             ctx.reroute(format("%s/Datastreams(%s)", uriComponent.getGatewayPath(), id));
         });
 
         router().get(create("Observations(:id)/Datastream")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String id = ctx.pathParam("id"); // resource + measurement + time
             String[] idCmp = Converter.disassemblyId(id);
@@ -133,6 +155,7 @@ public class OGCSensorThingsGateway extends AbstractGateway {
         });
 
         router().get(create("Sensors(:id)")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String resourceUrn = ctx.pathParam("id"); // resourceUrn
             MultiSensor afcMultiSensor = client.getSensorByResourceUrn(resourceUrn);
@@ -141,6 +164,7 @@ public class OGCSensorThingsGateway extends AbstractGateway {
         });
 
         router().get(create("Datastreams(:id)/Sensor")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String id = ctx.pathParam("id"); // resourceUrn + observedProperty
             String[] idCmp = Converter.disassemblyId(id);
@@ -149,6 +173,7 @@ public class OGCSensorThingsGateway extends AbstractGateway {
         });
 
         router().get(create("ObservedProperties(:id)")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String id = ctx.pathParam("id"); // resourceUrn + observedProperty
             String[] idCmp = Converter.disassemblyId(id);
@@ -162,12 +187,14 @@ public class OGCSensorThingsGateway extends AbstractGateway {
         });
 
         router().get(create("Datastreams(:id)/ObservedProperty")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String id = ctx.pathParam("id"); // resourceUrn + observedProperty
             ctx.reroute(format("%s/ObservedProperties(%s)", uriComponent.getGatewayPath(), id));
         });
 
         router().get(create("Observations(:id)")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             ctx.response().putHeader(CONTENT_TYPE, APPLICATION_JSON);
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String id = ctx.pathParam("id"); // resource + measurement + time
@@ -197,6 +224,7 @@ public class OGCSensorThingsGateway extends AbstractGateway {
         });
 
         router().get(create("Datastreams(:id)/Observations")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             ctx.response().putHeader(CONTENT_TYPE, APPLICATION_JSON);
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String id = ctx.pathParam("id"); // resourceUrn + observedProperty
@@ -238,16 +266,17 @@ public class OGCSensorThingsGateway extends AbstractGateway {
         });
 
         router().get(create("FeaturesOfInterest(:id)")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String id = ctx.pathParam("id");
             FeatureOfInterest featureOfInterest = new FeatureOfInterest();
             featureOfInterest.setId(id);
             featureOfInterest.setSelfLink("https://storage07-afarcloud.qa.pdmfc.com/storage/rest/registry/getAllObservationTypes");
-
             ctx.response().putHeader(CONTENT_TYPE, APPLICATION_JSON).end(featureOfInterest.encode());
         });
 
         router().get(create("Locations(:id)")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String id = ctx.pathParam("id"); // resourceUrn + observedProperty + time
             String [] idCmp = Converter.disassemblyId(id);
@@ -275,6 +304,7 @@ public class OGCSensorThingsGateway extends AbstractGateway {
         });
 
         router().get(create("Things(:id)/Locations")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String resourceUrn = ctx.pathParam("id");  // resourceUrn
 
@@ -297,12 +327,14 @@ public class OGCSensorThingsGateway extends AbstractGateway {
         });
 
         router().get(create("HistoricalLocations(:id)/Locations")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String id = ctx.pathParam("id"); // resourceUrn + observedProperty + time
             ctx.reroute(format("%s/Locations(%s)", uriComponent.getGatewayPath(), id));
         });
 
         router().get(create("HistoricalLocations(:id)")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String id = ctx.pathParam("id"); // resourceUrn + observedProperty + time
 
@@ -331,6 +363,7 @@ public class OGCSensorThingsGateway extends AbstractGateway {
         });
 
         router().get(create("Things(:id)/HistoricalLocations")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             ctx.response().putHeader(CONTENT_TYPE, APPLICATION_JSON);
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String resourceUrn = ctx.pathParam("id"); // resourceUrn
@@ -367,6 +400,7 @@ public class OGCSensorThingsGateway extends AbstractGateway {
         });
 
         router().get(create("Locations(:id)/HistoricalLocations")).handler(ctx -> {
+            logger.info("Handling a request: {}.", ctx.request().absoluteURI());
             ctx.response().putHeader(CONTENT_TYPE, APPLICATION_JSON);
             RequestUriComponent uriComponent = parseUriToComponents(ctx.request());
             String id = ctx.pathParam("id"); // resourceUrn + observedProperty + time
@@ -515,6 +549,8 @@ public class OGCSensorThingsGateway extends AbstractGateway {
 
     private static class Converter {
 
+        private final static Logger logger = LogManager.getLogger(Converter.class);
+
         private static final String DELIMITER = "&";
 
         static String assemblyId(String... parts) {
@@ -526,7 +562,6 @@ public class OGCSensorThingsGateway extends AbstractGateway {
         }
 
         static Filter convertFilter(io.connector.model.sensorthings.Filter ogcFilter) {
-
             if (ogcFilter == null) {
                 throw new IllegalArgumentException("Unsupported filter attributes in filter expression '" + ogcFilter + "'.");
             }

+ 21 - 50
connector-module-afarcloud/src/main/java/io/connector/module/afarcloud/gateway/SensLog1Gateway.java

@@ -1,84 +1,55 @@
 package io.connector.module.afarcloud.gateway;
 
 import io.connector.core.AbstractGateway;
-import io.connector.core.DataCollection;
 import io.connector.model.afarcloud.MultiSimpleObservation;
 import io.connector.model.afarcloud.SimpleObservation;
 import io.connector.model.senslog1.Observation;
 import io.connector.model.senslog1.Sensor;
 import io.connector.model.senslog1.Unit;
-import io.connector.module.afarcloud.AFCClient;
-import io.vertx.core.json.JsonObject;
+import io.connector.module.afarcloud.AFCHttpClient;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
 import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import static java.lang.String.format;
-
 
+/**
+ *
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
 public class SensLog1Gateway extends AbstractGateway {
 
     private final static Logger logger = LogManager.getLogger(SensLog1Gateway.class);
 
-    private final AFCClient client;
+    /** Attribute of a client that accesses to the AFarCloud system.  */
+    private final AFCHttpClient client;
 
-    public SensLog1Gateway(String id, AFCClient client) {
+    /**
+     * Public constructor of the class that initializes final attributes.
+     * @param id - identifier of the gateway
+     * @param client - client allows access to the AFarCloud system
+     */
+    public SensLog1Gateway(String id, AFCHttpClient client) {
         super(id);
         this.client = client;
     }
 
-
     @Override
     public void run() {
 
-        schedulerMapping()
-                .addMapping("observations-with-info", "add-observations");
-
-        event().consume("add-observations", message -> {
-
-            Iterator<Object> dataIterator;
-            if (message.body() instanceof DataCollection) {
-                dataIterator = ((DataCollection<?>)message.body()).iterator();
-            } else {
-                message.fail(400, "Unknown resource of data."); return;
-            }
-
-            List<MultiSimpleObservation> afcObservations = new ArrayList<>();
-            while (dataIterator.hasNext()) {
-                Object data = dataIterator.next();
-                Unit sensLogUnit;
-                if (data instanceof Unit) {
-                    sensLogUnit = (Unit) data;
-                } else {
-                    message.fail(400, "Unknown resource of data."); return;
-                }
-
-                afcObservations.add(Converter.convertObservation(sensLogUnit));
+        event().subscribe("test", message -> {
+            if (message.isFail()) {
+                logger.error(message.cause()); return;
             }
-
-            client.uploadAggregatedMeasurements(afcObservations);
-
-            message.reply(new JsonObject().put("message",
-                    format("Added %s observations.", afcObservations.size())
-            ));
+            System.out.println(message.body());
         });
-
     }
 
     private static class Converter {
 
-        static class SensorMapping {
-            // TODO
-        }
-
-        static class UnitMapping {
-            // TODO
-        }
-
-        static MultiSimpleObservation convertObservation(Unit sensLogUnit) {
+        static MultiSimpleObservation convertToMultiSimpleObservation(Unit sensLogUnit) {
             MultiSimpleObservation afcResult = new MultiSimpleObservation();
             String resourceId = Long.toString(sensLogUnit.getInfo().getId());
             afcResult.setResourceId(resourceId);

+ 1 - 3
connector-module-ima/src/main/java/io/connector/module/ima/ImaClient.java

@@ -1,7 +1,6 @@
 package io.connector.module.ima;
 
 import io.connector.model.ima.IMAModel;
-import io.vertx.core.json.JsonObject;
 
 public class ImaClient {
 
@@ -11,8 +10,7 @@ public class ImaClient {
         this.config = config;
     }
 
-    public JsonObject push(IMAModel model) {
+    public void push(IMAModel model) {
         System.out.println(model.getData());
-        return new JsonObject().put("result", "true");
     }
 }

+ 2 - 1
connector-module-ima/src/main/java/io/connector/module/ima/ImaModule.java

@@ -3,6 +3,7 @@ package io.connector.module.ima;
 import io.connector.core.ModuleDescriptor;
 import io.connector.core.AbstractModule;
 import io.connector.core.ModuleInfo;
+import io.connector.module.ima.gateway.ImaGateway;
 
 public class ImaModule extends AbstractModule {
 
@@ -15,7 +16,7 @@ public class ImaModule extends AbstractModule {
 
     @Override
     public void run() {
-
+        registerGateway(new ImaGateway("ima", client));
     }
 
     @Override

+ 20 - 0
connector-module-ima/src/main/java/io/connector/module/ima/gateway/ImaGateway.java

@@ -0,0 +1,20 @@
+package io.connector.module.ima.gateway;
+
+import io.connector.core.AbstractGateway;
+import io.connector.module.ima.ImaClient;
+
+public class ImaGateway extends AbstractGateway {
+
+    private final ImaClient client;
+
+    public ImaGateway(String id, ImaClient client) {
+        super(id, true);
+        this.client = client;
+    }
+
+    @Override
+    public void run() {
+
+
+    }
+}

+ 5 - 5
connector-module-senslog1/src/main/java/io/connector/module/senslog1/SensLog1HttpClient.java

@@ -1,9 +1,9 @@
 package io.connector.module.senslog1;
 
-import cz.senslog.common.http.HttpClient;
-import cz.senslog.common.http.HttpRequest;
-import cz.senslog.common.http.HttpResponse;
-import cz.senslog.common.http.URLBuilder;
+import io.connector.core.http.HttpClient;
+import io.connector.core.http.HttpRequest;
+import io.connector.core.http.HttpResponse;
+import io.connector.core.http.URLBuilder;
 import io.connector.core.config.HostConfig;
 import io.connector.model.senslog1.*;
 import io.vertx.core.json.JsonArray;
@@ -408,7 +408,7 @@ public class SensLog1HttpClient {
 
     public List<SensorInfo> sensors(long unitId) {
         HostConfig host = config.getSensorServiceHost();
-        logger.info("Getting last observations from {}.", host.getDomain());
+        logger.debug("Getting last observations from {}.", host.getDomain());
 
         HttpRequest request = HttpRequest.newBuilder().GET()
                 .url(URLBuilder.newBuilder(host.getDomain(), host.getPath())

+ 0 - 3
connector-module-senslog1/src/main/java/io/connector/module/senslog1/SensLog1Module.java

@@ -4,7 +4,6 @@ import io.connector.core.ModuleDescriptor;
 import io.connector.core.config.SchedulerConfig;
 import io.connector.core.AbstractModule;
 import io.connector.core.ModuleInfo;
-import io.connector.module.senslog1.gateway.AFCGateway;
 import io.connector.module.senslog1.gateway.OGCSensorThingsGateway;
 import io.connector.module.senslog1.gateway.SensLog1Gateway;
 import io.vertx.core.json.JsonObject;
@@ -22,9 +21,7 @@ public class SensLog1Module extends AbstractModule {
 
     @Override
     public void run() {
-        registerGateway(new AFCGateway("AFarCloud", httpClient));
         registerGateway(new OGCSensorThingsGateway("OGCSensorThings", sqlClient));
-
         registerGateway(new SensLog1Gateway("SensLogV1", httpClient));
     }
 

+ 1 - 1
connector-module-senslog1/src/main/java/io/connector/module/senslog1/SensLog1ModuleProvider.java

@@ -1,6 +1,6 @@
 package io.connector.module.senslog1;
 
-import cz.senslog.common.http.HttpClient;
+import io.connector.core.http.HttpClient;
 import io.connector.core.ModuleDescriptor;
 import io.connector.core.AbstractModule;
 import io.connector.core.ModuleProvider;

+ 0 - 19
connector-module-senslog1/src/main/java/io/connector/module/senslog1/gateway/AFCGateway.java

@@ -1,19 +0,0 @@
-package io.connector.module.senslog1.gateway;
-
-import io.connector.core.AbstractGateway;
-import io.connector.module.senslog1.SensLog1HttpClient;
-
-
-public class AFCGateway extends AbstractGateway {
-
-    private final SensLog1HttpClient client;
-
-    public AFCGateway(String id, SensLog1HttpClient client) {
-        super(id);
-        this.client = client;
-    }
-
-    @Override
-    public void run() {
-    }
-}