Lukas Cerny %!s(int64=2) %!d(string=hai) anos
pai
achega
315acb8c80
Modificáronse 100 ficheiros con 3788 adicións e 631 borrados
  1. 16 5
      build.gradle
  2. 53 0
      config/config-test.yaml
  3. 53 17
      config/config.yaml
  4. 1 0
      config/db_update.sql
  5. BIN=BIN
      doc/data_model.png
  6. 68 0
      src/main/generated/proxy/cz/senslog/analyzer/analysis/AnalyzerModule_ProvideSimpleAnalyzerFactory.java
  7. 180 0
      src/main/generated/proxy/cz/senslog/analyzer/analysis/DaggerAnalyzerComponent.java
  8. 41 0
      src/main/generated/proxy/cz/senslog/analyzer/analysis/module/HandlersModule_ProvideFilterHandlerFactory.java
  9. 41 0
      src/main/generated/proxy/cz/senslog/analyzer/analysis/module/HandlersModule_ProvideGroupThresholdHandlerFactory.java
  10. 57 0
      src/main/generated/proxy/cz/senslog/analyzer/analysis/module/HandlersModule_ProvideObservationCollectorFactory.java
  11. 41 0
      src/main/generated/proxy/cz/senslog/analyzer/analysis/module/HandlersModule_ProvideSensorThresholdHandlerFactory.java
  12. 52 0
      src/main/generated/proxy/cz/senslog/analyzer/core/EventBusModule_ProvideEventBusFactory.java
  13. 33 0
      src/main/generated/proxy/cz/senslog/analyzer/core/config/ConfigurationModule_EventBusConfigFactory.java
  14. 33 0
      src/main/generated/proxy/cz/senslog/analyzer/core/config/ConfigurationModule_StorageConfigFactory.java
  15. 142 0
      src/main/generated/proxy/cz/senslog/analyzer/provider/DaggerDataProviderComponent.java
  16. 40 0
      src/main/generated/proxy/cz/senslog/analyzer/provider/DatabaseProviderModule_ProvideLoopedDatabaseProviderFactory.java
  17. 39 0
      src/main/generated/proxy/cz/senslog/analyzer/provider/DatabaseProviderModule_ProvideLoopedProviderFactory.java
  18. 47 0
      src/main/generated/proxy/cz/senslog/analyzer/provider/DatabaseProviderModule_ProvideScheduleDatabaseProviderFactory.java
  19. 39 0
      src/main/generated/proxy/cz/senslog/analyzer/provider/DatabaseProviderModule_ProvideScheduledProviderFactory.java
  20. 35 0
      src/main/generated/proxy/cz/senslog/analyzer/provider/HttpMiddlewareProviderModule_ProvideHttpMiddlewareProviderFactory.java
  21. 39 0
      src/main/generated/proxy/cz/senslog/analyzer/provider/HttpMiddlewareProviderModule_ProvideMiddlewareProviderFactory.java
  22. 29 0
      src/main/generated/proxy/cz/senslog/analyzer/provider/HttpMiddlewareProvider_Factory.java
  23. 34 0
      src/main/generated/proxy/cz/senslog/analyzer/provider/LoopedDatabaseProvider_Factory.java
  24. 41 0
      src/main/generated/proxy/cz/senslog/analyzer/provider/ScheduledDatabaseProvider_Factory.java
  25. 33 0
      src/main/generated/proxy/cz/senslog/analyzer/storage/ConnectionModule_Factory.java
  26. 34 0
      src/main/generated/proxy/cz/senslog/analyzer/storage/ConnectionModule_ProvideInMemoryStorageConnectionFactory.java
  27. 34 0
      src/main/generated/proxy/cz/senslog/analyzer/storage/ConnectionModule_ProvidePermanentStorageConnectionFactory.java
  28. 41 0
      src/main/generated/proxy/cz/senslog/analyzer/storage/RepositoryModule_ProvideCollectedStatisticsRepositoryFactory.java
  29. 41 0
      src/main/generated/proxy/cz/senslog/analyzer/storage/RepositoryModule_ProvideObservationRepositoryFactory.java
  30. 41 0
      src/main/generated/proxy/cz/senslog/analyzer/storage/RepositoryModule_ProvideScheduledDatabaseRepositoryFactory.java
  31. 41 0
      src/main/generated/proxy/cz/senslog/analyzer/storage/RepositoryModule_ProvideStatisticsConfigRepositoryFactory.java
  32. 41 0
      src/main/generated/proxy/cz/senslog/analyzer/storage/RepositoryModule_ProvideStatisticsRepositoryFactory.java
  33. 35 0
      src/main/generated/proxy/cz/senslog/analyzer/storage/inmemory/repository/CollectedStatisticsRepository_Factory.java
  34. 34 0
      src/main/generated/proxy/cz/senslog/analyzer/storage/inmemory/repository/TimestampRepository_Factory.java
  35. 34 0
      src/main/generated/proxy/cz/senslog/analyzer/storage/permanent/repository/SensLogRepository_Factory.java
  36. 35 0
      src/main/generated/proxy/cz/senslog/analyzer/storage/permanent/repository/StatisticsConfigRepository_Factory.java
  37. 34 0
      src/main/generated/proxy/cz/senslog/analyzer/storage/permanent/repository/StatisticsRepository_Factory.java
  38. 112 0
      src/main/generated/proxy/cz/senslog/analyzer/ws/DaggerServerComponent.java
  39. 34 0
      src/main/generated/proxy/cz/senslog/analyzer/ws/handler/GroupsHandler_Factory.java
  40. 29 0
      src/main/generated/proxy/cz/senslog/analyzer/ws/handler/InfoHandler_Factory.java
  41. 33 0
      src/main/generated/proxy/cz/senslog/analyzer/ws/handler/StatisticsHandler_Factory.java
  42. 41 0
      src/main/generated/proxy/cz/senslog/analyzer/ws/manager/WSStatisticsManager_Factory.java
  43. 46 0
      src/main/generated/proxy/cz/senslog/analyzer/ws/vertx/VertxServer_Factory.java
  44. 12 12
      src/main/java/cz/senslog/analyzer/analysis/Analyzer.java
  45. 15 15
      src/main/java/cz/senslog/analyzer/analysis/AnalyzerComponent.java
  46. 16 0
      src/main/java/cz/senslog/analyzer/analysis/ManualAnalyticsConfig.java
  47. 38 38
      src/main/java/cz/senslog/analyzer/analysis/ObservationAnalyzer.java
  48. 69 0
      src/main/java/cz/senslog/analyzer/analysis/TaskConfig.java
  49. 2 1
      src/main/java/cz/senslog/analyzer/analysis/module/CollectorHandler.java
  50. 79 74
      src/main/java/cz/senslog/analyzer/analysis/module/HandlersModule.java
  51. 52 51
      src/main/java/cz/senslog/analyzer/analysis/module/ThresholdHandler.java
  52. 32 19
      src/main/java/cz/senslog/analyzer/app/Application.java
  53. 0 112
      src/main/java/cz/senslog/analyzer/app/Configuration.java
  54. 10 10
      src/main/java/cz/senslog/analyzer/app/Main.java
  55. 13 0
      src/main/java/cz/senslog/analyzer/broker/AbstractBrokerConfig.java
  56. 39 0
      src/main/java/cz/senslog/analyzer/broker/AlertFormatter.java
  57. 5 0
      src/main/java/cz/senslog/analyzer/broker/BrokerType.java
  58. 28 0
      src/main/java/cz/senslog/analyzer/broker/database/DatabaseBroker.java
  59. 18 0
      src/main/java/cz/senslog/analyzer/broker/database/DatabaseBrokerConfig.java
  60. 39 0
      src/main/java/cz/senslog/analyzer/broker/email/EmailBroker.java
  61. 38 0
      src/main/java/cz/senslog/analyzer/broker/email/EmailMessageConfig.java
  62. 38 0
      src/main/java/cz/senslog/analyzer/broker/email/EmailServerConfig.java
  63. 61 0
      src/main/java/cz/senslog/analyzer/broker/email/EmailServerConnection.java
  64. 19 0
      src/main/java/cz/senslog/analyzer/broker/statistic/StatisticBroker.java
  65. 40 0
      src/main/java/cz/senslog/analyzer/core/AbstractEventBroker.java
  66. 15 15
      src/main/java/cz/senslog/analyzer/core/EventBus.java
  67. 78 42
      src/main/java/cz/senslog/analyzer/core/EventBusModule.java
  68. 12 0
      src/main/java/cz/senslog/analyzer/core/config/Attribute.java
  69. 10 0
      src/main/java/cz/senslog/analyzer/core/config/ConfigurationManager.java
  70. 36 0
      src/main/java/cz/senslog/analyzer/core/config/ConfigurationModule.java
  71. 5 0
      src/main/java/cz/senslog/analyzer/core/config/ConfigurationType.java
  72. 141 0
      src/main/java/cz/senslog/analyzer/core/config/FileConfigurationManager.java
  73. 32 0
      src/main/java/cz/senslog/analyzer/core/config/TaskAnalytics.java
  74. 6 0
      src/main/java/cz/senslog/analyzer/core/config/domain/AbstractConfig.java
  75. 42 0
      src/main/java/cz/senslog/analyzer/core/config/domain/EmailServers.java
  76. 36 0
      src/main/java/cz/senslog/analyzer/core/config/domain/EventBusConfig.java
  77. 10 0
      src/main/java/cz/senslog/analyzer/core/config/domain/MessageBrokerConfig.java
  78. 39 0
      src/main/java/cz/senslog/analyzer/core/config/domain/MessageBrokers.java
  79. 287 0
      src/main/java/cz/senslog/analyzer/core/config/domain/PropertyConfig.java
  80. 28 0
      src/main/java/cz/senslog/analyzer/core/config/domain/SchedulerConfig.java
  81. 15 0
      src/main/java/cz/senslog/analyzer/core/config/domain/ServerConfig.java
  82. 36 0
      src/main/java/cz/senslog/analyzer/core/config/domain/StorageConfig.java
  83. 32 23
      src/main/java/cz/senslog/analyzer/domain/Alert.java
  84. 10 3
      src/main/java/cz/senslog/analyzer/domain/Group.java
  85. 9 5
      src/main/java/cz/senslog/analyzer/provider/DataProvider.java
  86. 3 1
      src/main/java/cz/senslog/analyzer/provider/DataProviderComponent.java
  87. 2 2
      src/main/java/cz/senslog/analyzer/provider/DataProviderDeployment.java
  88. 31 21
      src/main/java/cz/senslog/analyzer/provider/DatabaseProviderModule.java
  89. 9 0
      src/main/java/cz/senslog/analyzer/provider/LoopedDataProviderConfig.java
  90. 99 0
      src/main/java/cz/senslog/analyzer/provider/LoopedDatabaseProvider.java
  91. 5 2
      src/main/java/cz/senslog/analyzer/provider/ScheduledDataProviderConfig.java
  92. 7 6
      src/main/java/cz/senslog/analyzer/provider/ScheduledDataProviderConfigImpl.java
  93. 3 6
      src/main/java/cz/senslog/analyzer/provider/ScheduledDatabaseProvider.java
  94. 55 55
      src/main/java/cz/senslog/analyzer/provider/ScheduledProviderConfig.java
  95. 2 0
      src/main/java/cz/senslog/analyzer/provider/task/ObservationAnalyzerTask.java
  96. 6 6
      src/main/java/cz/senslog/analyzer/storage/ConnectionModule.java
  97. 0 24
      src/main/java/cz/senslog/analyzer/storage/StorageConfig.java
  98. 87 63
      src/main/java/cz/senslog/analyzer/storage/permanent/repository/SensLogRepository.java
  99. 4 1
      src/main/java/cz/senslog/analyzer/storage/permanent/repository/StatisticsConfigRepository.java
  100. 6 2
      src/main/java/cz/senslog/analyzer/storage/permanent/repository/StatisticsRepository.java

+ 16 - 5
build.gradle

@@ -1,9 +1,10 @@
 plugins {
     id 'java'
+    id "io.dotinc.vertx-codegen-plugin" version "0.1.1"
 }
 
 group 'cz.senslog'
-version '1.2'
+version '1.2.2'
 //version '1.3-SNAPSHOT'
 
 sourceCompatibility = 1.8
@@ -13,6 +14,12 @@ repositories {
     mavenLocal()
 }
 
+codeGen {
+    vertxVersion = '4.2.1'
+    generatedDirs = "src/main/generated"
+    generationPath = "proxy"
+}
+
 test {
     useJUnitPlatform()
 }
@@ -37,18 +44,22 @@ dependencies {
     implementation group: 'org.yaml', name: 'snakeyaml', version: '1.29'
     implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.13'
     implementation group: 'org.everit.json', name: 'org.everit.json.schema', version: '1.5.1'
-
+    implementation group: 'javax.mail', name: 'javax.mail-api', version: '1.6.2'
+    implementation group: 'com.sun.mail', name: 'javax.mail', version: '1.6.2'
 
     compile group: 'io.vertx', name: 'vertx-core', version: '4.2.1'
     compile group: 'io.vertx', name: 'vertx-web', version: '4.2.1'
+    annotationProcessor 'io.vertx:vertx-codegen:4.2.1:processor'
+    annotationProcessor 'io.vertx:vertx-service-proxy:4.2.1'
+
 
-    compile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.13.1'
+    compile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.17.0'
     compile group: 'org.jdbi', name: 'jdbi3-postgres', version: '3.12.2'
     compile group: 'org.jdbi', name: 'jdbi3-jodatime2', version: '3.12.2'
     compile group: 'com.zaxxer', name: 'HikariCP', version: '3.4.2'
     compile group: 'org.postgresql', name: 'postgresql', version: '42.2.10'
     compile group: 'com.h2database', name: 'h2', version: '1.4.200'
 
-    implementation 'com.google.dagger:dagger:2.40.1'
-    annotationProcessor 'com.google.dagger:dagger-compiler:2.40.1'
+    implementation 'com.google.dagger:dagger:2.40.3'
+    annotationProcessor 'com.google.dagger:dagger-compiler:2.40.3'
 }

+ 53 - 0
config/config-test.yaml

@@ -0,0 +1,53 @@
+server:
+  port: 9090
+
+eventBus:
+  notifyBrokers: [  emailMessage,   dbAlert]
+
+
+emailServers:
+  lspEmail:
+    smtpHost: "mail.lesprojekt.cz"
+    smtpPort: 465
+    authUsername: "watchdog@senslog.org"
+    authPassword: "5jspdD"
+
+messageBrokers:
+  emailMessage:
+    type: EMAIL
+#    filter: [] // whiteList / blackList ...
+    config:
+      server: lspEmail
+      senderEmail: "analytics@senslog.org"
+      recipientEmail:
+        - "luccerny@ntis.zcu.cz"
+      subject: "[Analytics] Alert for the group $group_name"
+
+  dbAlert:
+    type: DATABASE
+#    filter: []
+    config:
+      msgPattern: "'$group_name' failed at $timestamp in $messages."
+
+storage:
+  permanent:
+    url: "jdbc:postgresql://localhost:5432/senslog1"
+    username: "senslog_app"
+    password: "SENSlog"
+    connectionPoolSize: 6
+
+  inMemory:
+    path: "./statistics"
+    persistence: true
+    parameters: ""
+
+scheduler:
+  initDate: "1970-02-01T10:02:00.00+00:00"
+  period: 10
+
+
+#manualAnalytics:
+#  osek:
+#    from: "1970-01-01T00:00:00.00+00:00"
+#    to: "2022-01-01T00:00:00.00+00:00"
+#    groupIds: [1]

+ 53 - 17
config/config.yaml

@@ -1,17 +1,53 @@
-permanentStorage:
-  url: "jdbc:postgresql://localhost:5432/senslog1"
-  username: "postgres"
-  password: "root"
-  connectionPoolSize: 6
-
-inMemoryStorage:
-  path: "./statistics"
-  persistence: true
-  parameters: ""
-
-scheduler:
-  initDate: "1970-01-01T00:00:00.00+02:00"
-  period: 10
-
-server:
-  port: 9090
+server:
+  port: 9090
+
+eventBus:
+  notifyBrokers: [  emailMessage,   dbAlert]
+
+
+emailServers:
+  lspEmail:
+    smtpHost: "10.0.0.100" # "mail.lesprojekt.cz"
+    smtpPort: 465
+    authUsername: "watchdog@senslog.org"
+    authPassword: "5jspdD"
+
+messageBrokers:
+  emailMessage:
+    type: EMAIL
+#    filter: [] // whiteList / blackList ...
+    config:
+      server: lspEmail
+      senderEmail: "analytics@senslog.org"
+      recipientEmail:
+        - "luccerny@ntis.zcu.cz"
+      subject: "[Analytics] Alert for the group $group_name"
+
+  dbAlert:
+    type: DATABASE
+#    filter: []
+    config:
+      msgPattern: "'$group_name' failed at $timestamp in $messages."
+
+storage:
+  permanent:
+    url: "jdbc:postgresql://localhost:5432/senslog1"
+    username: "senslog_app"
+    password: "SENSlog"
+    connectionPoolSize: 6
+
+  inMemory:
+    path: "./statistics"
+    persistence: true
+    parameters: ""
+
+scheduler:
+  initDate: "1970-02-01T10:02:00.00+00:00"
+  period: 10
+
+
+manualAnalytics:
+  osek:
+    from: "1970-01-01T00:00:00.00+00:00"
+    to: "2022-01-01T00:00:00.00+00:00"
+    groupIds: [1649, 1650, 1651, 1652, 1653, 1654, 1655, 1656. 1657, 1658, 1659, 1660, 1661]

+ 1 - 0
config/db_update.sql

@@ -0,0 +1 @@
+ALTER TABLE statistics.groups_interval ADD COLUMN name varchar(256) not null default 'undefined';

BIN=BIN
doc/data_model.png


+ 68 - 0
src/main/generated/proxy/cz/senslog/analyzer/analysis/AnalyzerModule_ProvideSimpleAnalyzerFactory.java

@@ -0,0 +1,68 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.analysis;
+
+import cz.senslog.analyzer.analysis.module.FilterHandler;
+import cz.senslog.analyzer.analysis.module.ThresholdHandler;
+import cz.senslog.analyzer.core.EventBus;
+import cz.senslog.analyzer.core.api.BlockingHandler;
+import cz.senslog.analyzer.domain.DoubleStatistics;
+import cz.senslog.analyzer.domain.Observation;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class AnalyzerModule_ProvideSimpleAnalyzerFactory implements Factory<Analyzer<Observation>> {
+  private final AnalyzerModule module;
+
+  private final Provider<FilterHandler<Observation>> sensorFilterHandlerProvider;
+
+  private final Provider<ThresholdHandler<Observation>> sensorThresholdHandlerProvider;
+
+  private final Provider<BlockingHandler<Observation, DoubleStatistics>> aggregateCollectorHandlerProvider;
+
+  private final Provider<ThresholdHandler<DoubleStatistics>> groupThresholdHandlerProvider;
+
+  private final Provider<EventBus> eventBusProvider;
+
+  public AnalyzerModule_ProvideSimpleAnalyzerFactory(AnalyzerModule module,
+      Provider<FilterHandler<Observation>> sensorFilterHandlerProvider,
+      Provider<ThresholdHandler<Observation>> sensorThresholdHandlerProvider,
+      Provider<BlockingHandler<Observation, DoubleStatistics>> aggregateCollectorHandlerProvider,
+      Provider<ThresholdHandler<DoubleStatistics>> groupThresholdHandlerProvider,
+      Provider<EventBus> eventBusProvider) {
+    this.module = module;
+    this.sensorFilterHandlerProvider = sensorFilterHandlerProvider;
+    this.sensorThresholdHandlerProvider = sensorThresholdHandlerProvider;
+    this.aggregateCollectorHandlerProvider = aggregateCollectorHandlerProvider;
+    this.groupThresholdHandlerProvider = groupThresholdHandlerProvider;
+    this.eventBusProvider = eventBusProvider;
+  }
+
+  @Override
+  public Analyzer<Observation> get() {
+    return provideSimpleAnalyzer(module, sensorFilterHandlerProvider.get(), sensorThresholdHandlerProvider.get(), aggregateCollectorHandlerProvider.get(), groupThresholdHandlerProvider.get(), eventBusProvider.get());
+  }
+
+  public static AnalyzerModule_ProvideSimpleAnalyzerFactory create(AnalyzerModule module,
+      Provider<FilterHandler<Observation>> sensorFilterHandlerProvider,
+      Provider<ThresholdHandler<Observation>> sensorThresholdHandlerProvider,
+      Provider<BlockingHandler<Observation, DoubleStatistics>> aggregateCollectorHandlerProvider,
+      Provider<ThresholdHandler<DoubleStatistics>> groupThresholdHandlerProvider,
+      Provider<EventBus> eventBusProvider) {
+    return new AnalyzerModule_ProvideSimpleAnalyzerFactory(module, sensorFilterHandlerProvider, sensorThresholdHandlerProvider, aggregateCollectorHandlerProvider, groupThresholdHandlerProvider, eventBusProvider);
+  }
+
+  public static Analyzer<Observation> provideSimpleAnalyzer(AnalyzerModule instance,
+      FilterHandler<Observation> sensorFilterHandler,
+      ThresholdHandler<Observation> sensorThresholdHandler,
+      BlockingHandler<Observation, DoubleStatistics> aggregateCollectorHandler,
+      ThresholdHandler<DoubleStatistics> groupThresholdHandler, EventBus eventBus) {
+    return Preconditions.checkNotNullFromProvides(instance.provideSimpleAnalyzer(sensorFilterHandler, sensorThresholdHandler, aggregateCollectorHandler, groupThresholdHandler, eventBus));
+  }
+}

+ 180 - 0
src/main/generated/proxy/cz/senslog/analyzer/analysis/DaggerAnalyzerComponent.java

@@ -0,0 +1,180 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.analysis;
+
+import cz.senslog.analyzer.analysis.module.FilterHandler;
+import cz.senslog.analyzer.analysis.module.HandlersModule;
+import cz.senslog.analyzer.analysis.module.HandlersModule_ProvideFilterHandlerFactory;
+import cz.senslog.analyzer.analysis.module.HandlersModule_ProvideGroupThresholdHandlerFactory;
+import cz.senslog.analyzer.analysis.module.HandlersModule_ProvideObservationCollectorFactory;
+import cz.senslog.analyzer.analysis.module.HandlersModule_ProvideSensorThresholdHandlerFactory;
+import cz.senslog.analyzer.analysis.module.ThresholdHandler;
+import cz.senslog.analyzer.core.EventBus;
+import cz.senslog.analyzer.core.EventBusModule;
+import cz.senslog.analyzer.core.EventBusModule_ProvideEventBusFactory;
+import cz.senslog.analyzer.core.api.BlockingHandler;
+import cz.senslog.analyzer.core.config.ConfigurationModule;
+import cz.senslog.analyzer.core.config.ConfigurationModule_EventBusConfigFactory;
+import cz.senslog.analyzer.core.config.domain.EventBusConfig;
+import cz.senslog.analyzer.domain.DoubleStatistics;
+import cz.senslog.analyzer.domain.Observation;
+import cz.senslog.analyzer.storage.ConnectionModule;
+import cz.senslog.analyzer.storage.ConnectionModule_ProvideInMemoryStorageConnectionFactory;
+import cz.senslog.analyzer.storage.ConnectionModule_ProvidePermanentStorageConnectionFactory;
+import cz.senslog.analyzer.storage.RepositoryModule;
+import cz.senslog.analyzer.storage.RepositoryModule_ProvideCollectedStatisticsRepositoryFactory;
+import cz.senslog.analyzer.storage.RepositoryModule_ProvideObservationRepositoryFactory;
+import cz.senslog.analyzer.storage.RepositoryModule_ProvideScheduledDatabaseRepositoryFactory;
+import cz.senslog.analyzer.storage.RepositoryModule_ProvideStatisticsConfigRepositoryFactory;
+import cz.senslog.analyzer.storage.RepositoryModule_ProvideStatisticsRepositoryFactory;
+import cz.senslog.analyzer.storage.inmemory.InMemoryConnection;
+import cz.senslog.analyzer.storage.inmemory.repository.CollectedStatisticsRepository;
+import cz.senslog.analyzer.storage.inmemory.repository.TimestampRepository;
+import cz.senslog.analyzer.storage.permanent.PermanentConnection;
+import cz.senslog.analyzer.storage.permanent.repository.SensLogRepository;
+import cz.senslog.analyzer.storage.permanent.repository.StatisticsConfigRepository;
+import cz.senslog.analyzer.storage.permanent.repository.StatisticsRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.DoubleCheck;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class DaggerAnalyzerComponent implements AnalyzerComponent {
+  private final AnalyzerModule analyzerModule;
+
+  private final DaggerAnalyzerComponent analyzerComponent = this;
+
+  private Provider<PermanentConnection> providePermanentStorageConnectionProvider;
+
+  private Provider<StatisticsConfigRepository> provideStatisticsConfigRepositoryProvider;
+
+  private Provider<FilterHandler<Observation>> provideFilterHandlerProvider;
+
+  private Provider<ThresholdHandler<Observation>> provideSensorThresholdHandlerProvider;
+
+  private Provider<InMemoryConnection> provideInMemoryStorageConnectionProvider;
+
+  private Provider<CollectedStatisticsRepository> provideCollectedStatisticsRepositoryProvider;
+
+  private Provider<TimestampRepository> provideScheduledDatabaseRepositoryProvider;
+
+  private Provider<BlockingHandler<Observation, DoubleStatistics>> provideObservationCollectorProvider;
+
+  private Provider<ThresholdHandler<DoubleStatistics>> provideGroupThresholdHandlerProvider;
+
+  private Provider<EventBusConfig> eventBusConfigProvider;
+
+  private Provider<StatisticsRepository> provideStatisticsRepositoryProvider;
+
+  private Provider<SensLogRepository> provideObservationRepositoryProvider;
+
+  private Provider<EventBus> provideEventBusProvider;
+
+  private DaggerAnalyzerComponent(AnalyzerModule analyzerModuleParam,
+      HandlersModule handlersModuleParam, RepositoryModule repositoryModuleParam,
+      ConnectionModule connectionModuleParam, ConfigurationModule configurationModuleParam,
+      EventBusModule eventBusModuleParam) {
+    this.analyzerModule = analyzerModuleParam;
+    initialize(analyzerModuleParam, handlersModuleParam, repositoryModuleParam, connectionModuleParam, configurationModuleParam, eventBusModuleParam);
+
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  @SuppressWarnings("unchecked")
+  private void initialize(final AnalyzerModule analyzerModuleParam,
+      final HandlersModule handlersModuleParam, final RepositoryModule repositoryModuleParam,
+      final ConnectionModule connectionModuleParam,
+      final ConfigurationModule configurationModuleParam,
+      final EventBusModule eventBusModuleParam) {
+    this.providePermanentStorageConnectionProvider = DoubleCheck.provider(ConnectionModule_ProvidePermanentStorageConnectionFactory.create(connectionModuleParam));
+    this.provideStatisticsConfigRepositoryProvider = DoubleCheck.provider(RepositoryModule_ProvideStatisticsConfigRepositoryFactory.create(repositoryModuleParam, providePermanentStorageConnectionProvider));
+    this.provideFilterHandlerProvider = DoubleCheck.provider(HandlersModule_ProvideFilterHandlerFactory.create(handlersModuleParam, provideStatisticsConfigRepositoryProvider));
+    this.provideSensorThresholdHandlerProvider = DoubleCheck.provider(HandlersModule_ProvideSensorThresholdHandlerFactory.create(handlersModuleParam, provideStatisticsConfigRepositoryProvider));
+    this.provideInMemoryStorageConnectionProvider = DoubleCheck.provider(ConnectionModule_ProvideInMemoryStorageConnectionFactory.create(connectionModuleParam));
+    this.provideCollectedStatisticsRepositoryProvider = DoubleCheck.provider(RepositoryModule_ProvideCollectedStatisticsRepositoryFactory.create(repositoryModuleParam, provideInMemoryStorageConnectionProvider));
+    this.provideScheduledDatabaseRepositoryProvider = DoubleCheck.provider(RepositoryModule_ProvideScheduledDatabaseRepositoryFactory.create(repositoryModuleParam, provideInMemoryStorageConnectionProvider));
+    this.provideObservationCollectorProvider = DoubleCheck.provider(HandlersModule_ProvideObservationCollectorFactory.create(handlersModuleParam, provideStatisticsConfigRepositoryProvider, provideCollectedStatisticsRepositoryProvider, provideScheduledDatabaseRepositoryProvider));
+    this.provideGroupThresholdHandlerProvider = DoubleCheck.provider(HandlersModule_ProvideGroupThresholdHandlerFactory.create(handlersModuleParam, provideStatisticsConfigRepositoryProvider));
+    this.eventBusConfigProvider = DoubleCheck.provider(ConfigurationModule_EventBusConfigFactory.create(configurationModuleParam));
+    this.provideStatisticsRepositoryProvider = DoubleCheck.provider(RepositoryModule_ProvideStatisticsRepositoryFactory.create(repositoryModuleParam, providePermanentStorageConnectionProvider));
+    this.provideObservationRepositoryProvider = DoubleCheck.provider(RepositoryModule_ProvideObservationRepositoryFactory.create(repositoryModuleParam, providePermanentStorageConnectionProvider));
+    this.provideEventBusProvider = DoubleCheck.provider(EventBusModule_ProvideEventBusFactory.create(eventBusModuleParam, eventBusConfigProvider, provideStatisticsRepositoryProvider, provideObservationRepositoryProvider));
+  }
+
+  @Override
+  public Analyzer<Observation> createObservationAnalyzer() {
+    return AnalyzerModule_ProvideSimpleAnalyzerFactory.provideSimpleAnalyzer(analyzerModule, provideFilterHandlerProvider.get(), provideSensorThresholdHandlerProvider.get(), provideObservationCollectorProvider.get(), provideGroupThresholdHandlerProvider.get(), provideEventBusProvider.get());
+  }
+
+  public static final class Builder {
+    private AnalyzerModule analyzerModule;
+
+    private HandlersModule handlersModule;
+
+    private RepositoryModule repositoryModule;
+
+    private ConnectionModule connectionModule;
+
+    private ConfigurationModule configurationModule;
+
+    private EventBusModule eventBusModule;
+
+    private Builder() {
+    }
+
+    public Builder analyzerModule(AnalyzerModule analyzerModule) {
+      this.analyzerModule = Preconditions.checkNotNull(analyzerModule);
+      return this;
+    }
+
+    public Builder handlersModule(HandlersModule handlersModule) {
+      this.handlersModule = Preconditions.checkNotNull(handlersModule);
+      return this;
+    }
+
+    public Builder repositoryModule(RepositoryModule repositoryModule) {
+      this.repositoryModule = Preconditions.checkNotNull(repositoryModule);
+      return this;
+    }
+
+    public Builder connectionModule(ConnectionModule connectionModule) {
+      this.connectionModule = Preconditions.checkNotNull(connectionModule);
+      return this;
+    }
+
+    public Builder configurationModule(ConfigurationModule configurationModule) {
+      this.configurationModule = Preconditions.checkNotNull(configurationModule);
+      return this;
+    }
+
+    public Builder eventBusModule(EventBusModule eventBusModule) {
+      this.eventBusModule = Preconditions.checkNotNull(eventBusModule);
+      return this;
+    }
+
+    public AnalyzerComponent build() {
+      if (analyzerModule == null) {
+        this.analyzerModule = new AnalyzerModule();
+      }
+      if (handlersModule == null) {
+        this.handlersModule = new HandlersModule();
+      }
+      if (repositoryModule == null) {
+        this.repositoryModule = new RepositoryModule();
+      }
+      Preconditions.checkBuilderRequirement(connectionModule, ConnectionModule.class);
+      Preconditions.checkBuilderRequirement(configurationModule, ConfigurationModule.class);
+      if (eventBusModule == null) {
+        this.eventBusModule = new EventBusModule();
+      }
+      return new DaggerAnalyzerComponent(analyzerModule, handlersModule, repositoryModule, connectionModule, configurationModule, eventBusModule);
+    }
+  }
+}

+ 41 - 0
src/main/generated/proxy/cz/senslog/analyzer/analysis/module/HandlersModule_ProvideFilterHandlerFactory.java

@@ -0,0 +1,41 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.analysis.module;
+
+import cz.senslog.analyzer.domain.Observation;
+import cz.senslog.analyzer.storage.permanent.repository.StatisticsConfigRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class HandlersModule_ProvideFilterHandlerFactory implements Factory<FilterHandler<Observation>> {
+  private final HandlersModule module;
+
+  private final Provider<StatisticsConfigRepository> repositoryProvider;
+
+  public HandlersModule_ProvideFilterHandlerFactory(HandlersModule module,
+      Provider<StatisticsConfigRepository> repositoryProvider) {
+    this.module = module;
+    this.repositoryProvider = repositoryProvider;
+  }
+
+  @Override
+  public FilterHandler<Observation> get() {
+    return provideFilterHandler(module, repositoryProvider.get());
+  }
+
+  public static HandlersModule_ProvideFilterHandlerFactory create(HandlersModule module,
+      Provider<StatisticsConfigRepository> repositoryProvider) {
+    return new HandlersModule_ProvideFilterHandlerFactory(module, repositoryProvider);
+  }
+
+  public static FilterHandler<Observation> provideFilterHandler(HandlersModule instance,
+      StatisticsConfigRepository repository) {
+    return Preconditions.checkNotNullFromProvides(instance.provideFilterHandler(repository));
+  }
+}

+ 41 - 0
src/main/generated/proxy/cz/senslog/analyzer/analysis/module/HandlersModule_ProvideGroupThresholdHandlerFactory.java

@@ -0,0 +1,41 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.analysis.module;
+
+import cz.senslog.analyzer.domain.DoubleStatistics;
+import cz.senslog.analyzer.storage.permanent.repository.StatisticsConfigRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class HandlersModule_ProvideGroupThresholdHandlerFactory implements Factory<ThresholdHandler<DoubleStatistics>> {
+  private final HandlersModule module;
+
+  private final Provider<StatisticsConfigRepository> repositoryProvider;
+
+  public HandlersModule_ProvideGroupThresholdHandlerFactory(HandlersModule module,
+      Provider<StatisticsConfigRepository> repositoryProvider) {
+    this.module = module;
+    this.repositoryProvider = repositoryProvider;
+  }
+
+  @Override
+  public ThresholdHandler<DoubleStatistics> get() {
+    return provideGroupThresholdHandler(module, repositoryProvider.get());
+  }
+
+  public static HandlersModule_ProvideGroupThresholdHandlerFactory create(HandlersModule module,
+      Provider<StatisticsConfigRepository> repositoryProvider) {
+    return new HandlersModule_ProvideGroupThresholdHandlerFactory(module, repositoryProvider);
+  }
+
+  public static ThresholdHandler<DoubleStatistics> provideGroupThresholdHandler(
+      HandlersModule instance, StatisticsConfigRepository repository) {
+    return Preconditions.checkNotNullFromProvides(instance.provideGroupThresholdHandler(repository));
+  }
+}

+ 57 - 0
src/main/generated/proxy/cz/senslog/analyzer/analysis/module/HandlersModule_ProvideObservationCollectorFactory.java

@@ -0,0 +1,57 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.analysis.module;
+
+import cz.senslog.analyzer.core.api.BlockingHandler;
+import cz.senslog.analyzer.domain.DoubleStatistics;
+import cz.senslog.analyzer.domain.Observation;
+import cz.senslog.analyzer.storage.inmemory.repository.CollectedStatisticsRepository;
+import cz.senslog.analyzer.storage.inmemory.repository.TimestampRepository;
+import cz.senslog.analyzer.storage.permanent.repository.StatisticsConfigRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class HandlersModule_ProvideObservationCollectorFactory implements Factory<BlockingHandler<Observation, DoubleStatistics>> {
+  private final HandlersModule module;
+
+  private final Provider<StatisticsConfigRepository> statisticsConfigRepositoryProvider;
+
+  private final Provider<CollectedStatisticsRepository> collectedStatisticsRepositoryProvider;
+
+  private final Provider<TimestampRepository> timestampRepositoryProvider;
+
+  public HandlersModule_ProvideObservationCollectorFactory(HandlersModule module,
+      Provider<StatisticsConfigRepository> statisticsConfigRepositoryProvider,
+      Provider<CollectedStatisticsRepository> collectedStatisticsRepositoryProvider,
+      Provider<TimestampRepository> timestampRepositoryProvider) {
+    this.module = module;
+    this.statisticsConfigRepositoryProvider = statisticsConfigRepositoryProvider;
+    this.collectedStatisticsRepositoryProvider = collectedStatisticsRepositoryProvider;
+    this.timestampRepositoryProvider = timestampRepositoryProvider;
+  }
+
+  @Override
+  public BlockingHandler<Observation, DoubleStatistics> get() {
+    return provideObservationCollector(module, statisticsConfigRepositoryProvider.get(), collectedStatisticsRepositoryProvider.get(), timestampRepositoryProvider.get());
+  }
+
+  public static HandlersModule_ProvideObservationCollectorFactory create(HandlersModule module,
+      Provider<StatisticsConfigRepository> statisticsConfigRepositoryProvider,
+      Provider<CollectedStatisticsRepository> collectedStatisticsRepositoryProvider,
+      Provider<TimestampRepository> timestampRepositoryProvider) {
+    return new HandlersModule_ProvideObservationCollectorFactory(module, statisticsConfigRepositoryProvider, collectedStatisticsRepositoryProvider, timestampRepositoryProvider);
+  }
+
+  public static BlockingHandler<Observation, DoubleStatistics> provideObservationCollector(
+      HandlersModule instance, StatisticsConfigRepository statisticsConfigRepository,
+      CollectedStatisticsRepository collectedStatisticsRepository,
+      TimestampRepository timestampRepository) {
+    return Preconditions.checkNotNullFromProvides(instance.provideObservationCollector(statisticsConfigRepository, collectedStatisticsRepository, timestampRepository));
+  }
+}

+ 41 - 0
src/main/generated/proxy/cz/senslog/analyzer/analysis/module/HandlersModule_ProvideSensorThresholdHandlerFactory.java

@@ -0,0 +1,41 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.analysis.module;
+
+import cz.senslog.analyzer.domain.Observation;
+import cz.senslog.analyzer.storage.permanent.repository.StatisticsConfigRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class HandlersModule_ProvideSensorThresholdHandlerFactory implements Factory<ThresholdHandler<Observation>> {
+  private final HandlersModule module;
+
+  private final Provider<StatisticsConfigRepository> repositoryProvider;
+
+  public HandlersModule_ProvideSensorThresholdHandlerFactory(HandlersModule module,
+      Provider<StatisticsConfigRepository> repositoryProvider) {
+    this.module = module;
+    this.repositoryProvider = repositoryProvider;
+  }
+
+  @Override
+  public ThresholdHandler<Observation> get() {
+    return provideSensorThresholdHandler(module, repositoryProvider.get());
+  }
+
+  public static HandlersModule_ProvideSensorThresholdHandlerFactory create(HandlersModule module,
+      Provider<StatisticsConfigRepository> repositoryProvider) {
+    return new HandlersModule_ProvideSensorThresholdHandlerFactory(module, repositoryProvider);
+  }
+
+  public static ThresholdHandler<Observation> provideSensorThresholdHandler(HandlersModule instance,
+      StatisticsConfigRepository repository) {
+    return Preconditions.checkNotNullFromProvides(instance.provideSensorThresholdHandler(repository));
+  }
+}

+ 52 - 0
src/main/generated/proxy/cz/senslog/analyzer/core/EventBusModule_ProvideEventBusFactory.java

@@ -0,0 +1,52 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.core;
+
+import cz.senslog.analyzer.core.config.domain.EventBusConfig;
+import cz.senslog.analyzer.storage.permanent.repository.SensLogRepository;
+import cz.senslog.analyzer.storage.permanent.repository.StatisticsRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class EventBusModule_ProvideEventBusFactory implements Factory<EventBus> {
+  private final EventBusModule module;
+
+  private final Provider<EventBusConfig> eventBusConfigProvider;
+
+  private final Provider<StatisticsRepository> statisticsRepositoryProvider;
+
+  private final Provider<SensLogRepository> senslogRepositoryProvider;
+
+  public EventBusModule_ProvideEventBusFactory(EventBusModule module,
+      Provider<EventBusConfig> eventBusConfigProvider,
+      Provider<StatisticsRepository> statisticsRepositoryProvider,
+      Provider<SensLogRepository> senslogRepositoryProvider) {
+    this.module = module;
+    this.eventBusConfigProvider = eventBusConfigProvider;
+    this.statisticsRepositoryProvider = statisticsRepositoryProvider;
+    this.senslogRepositoryProvider = senslogRepositoryProvider;
+  }
+
+  @Override
+  public EventBus get() {
+    return provideEventBus(module, eventBusConfigProvider.get(), statisticsRepositoryProvider.get(), senslogRepositoryProvider.get());
+  }
+
+  public static EventBusModule_ProvideEventBusFactory create(EventBusModule module,
+      Provider<EventBusConfig> eventBusConfigProvider,
+      Provider<StatisticsRepository> statisticsRepositoryProvider,
+      Provider<SensLogRepository> senslogRepositoryProvider) {
+    return new EventBusModule_ProvideEventBusFactory(module, eventBusConfigProvider, statisticsRepositoryProvider, senslogRepositoryProvider);
+  }
+
+  public static EventBus provideEventBus(EventBusModule instance, EventBusConfig eventBusConfig,
+      StatisticsRepository statisticsRepository, SensLogRepository senslogRepository) {
+    return Preconditions.checkNotNullFromProvides(instance.provideEventBus(eventBusConfig, statisticsRepository, senslogRepository));
+  }
+}

+ 33 - 0
src/main/generated/proxy/cz/senslog/analyzer/core/config/ConfigurationModule_EventBusConfigFactory.java

@@ -0,0 +1,33 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.core.config;
+
+import cz.senslog.analyzer.core.config.domain.EventBusConfig;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class ConfigurationModule_EventBusConfigFactory implements Factory<EventBusConfig> {
+  private final ConfigurationModule module;
+
+  public ConfigurationModule_EventBusConfigFactory(ConfigurationModule module) {
+    this.module = module;
+  }
+
+  @Override
+  public EventBusConfig get() {
+    return eventBusConfig(module);
+  }
+
+  public static ConfigurationModule_EventBusConfigFactory create(ConfigurationModule module) {
+    return new ConfigurationModule_EventBusConfigFactory(module);
+  }
+
+  public static EventBusConfig eventBusConfig(ConfigurationModule instance) {
+    return Preconditions.checkNotNullFromProvides(instance.eventBusConfig());
+  }
+}

+ 33 - 0
src/main/generated/proxy/cz/senslog/analyzer/core/config/ConfigurationModule_StorageConfigFactory.java

@@ -0,0 +1,33 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.core.config;
+
+import cz.senslog.analyzer.core.config.domain.StorageConfig;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class ConfigurationModule_StorageConfigFactory implements Factory<StorageConfig> {
+  private final ConfigurationModule module;
+
+  public ConfigurationModule_StorageConfigFactory(ConfigurationModule module) {
+    this.module = module;
+  }
+
+  @Override
+  public StorageConfig get() {
+    return storageConfig(module);
+  }
+
+  public static ConfigurationModule_StorageConfigFactory create(ConfigurationModule module) {
+    return new ConfigurationModule_StorageConfigFactory(module);
+  }
+
+  public static StorageConfig storageConfig(ConfigurationModule instance) {
+    return Preconditions.checkNotNullFromProvides(instance.storageConfig());
+  }
+}

+ 142 - 0
src/main/generated/proxy/cz/senslog/analyzer/provider/DaggerDataProviderComponent.java

@@ -0,0 +1,142 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.provider;
+
+import cz.senslog.analyzer.core.config.ConfigurationModule;
+import cz.senslog.analyzer.storage.ConnectionModule;
+import cz.senslog.analyzer.storage.ConnectionModule_ProvideInMemoryStorageConnectionFactory;
+import cz.senslog.analyzer.storage.ConnectionModule_ProvidePermanentStorageConnectionFactory;
+import cz.senslog.analyzer.storage.RepositoryModule;
+import cz.senslog.analyzer.storage.RepositoryModule_ProvideObservationRepositoryFactory;
+import cz.senslog.analyzer.storage.RepositoryModule_ProvideScheduledDatabaseRepositoryFactory;
+import cz.senslog.analyzer.storage.inmemory.InMemoryConnection;
+import cz.senslog.analyzer.storage.inmemory.repository.TimestampRepository;
+import cz.senslog.analyzer.storage.permanent.PermanentConnection;
+import cz.senslog.analyzer.storage.permanent.repository.SensLogRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.DoubleCheck;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class DaggerDataProviderComponent implements DataProviderComponent {
+  private final DatabaseProviderModule databaseProviderModule;
+
+  private final HttpMiddlewareProviderModule httpMiddlewareProviderModule;
+
+  private final DaggerDataProviderComponent dataProviderComponent = this;
+
+  private Provider<InMemoryConnection> provideInMemoryStorageConnectionProvider;
+
+  private Provider<TimestampRepository> provideScheduledDatabaseRepositoryProvider;
+
+  private Provider<PermanentConnection> providePermanentStorageConnectionProvider;
+
+  private Provider<SensLogRepository> provideObservationRepositoryProvider;
+
+  private DaggerDataProviderComponent(DatabaseProviderModule databaseProviderModuleParam,
+      RepositoryModule repositoryModuleParam, ConnectionModule connectionModuleParam,
+      HttpMiddlewareProviderModule httpMiddlewareProviderModuleParam) {
+    this.databaseProviderModule = databaseProviderModuleParam;
+    this.httpMiddlewareProviderModule = httpMiddlewareProviderModuleParam;
+    initialize(databaseProviderModuleParam, repositoryModuleParam, connectionModuleParam, httpMiddlewareProviderModuleParam);
+
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  private ScheduledDatabaseProvider scheduledDatabaseProvider2() {
+    return DatabaseProviderModule_ProvideScheduleDatabaseProviderFactory.provideScheduleDatabaseProvider(databaseProviderModule, provideScheduledDatabaseRepositoryProvider.get(), provideObservationRepositoryProvider.get());
+  }
+
+  private LoopedDatabaseProvider loopedDatabaseProvider2() {
+    return DatabaseProviderModule_ProvideLoopedDatabaseProviderFactory.provideLoopedDatabaseProvider(databaseProviderModule, provideObservationRepositoryProvider.get());
+  }
+
+  @SuppressWarnings("unchecked")
+  private void initialize(final DatabaseProviderModule databaseProviderModuleParam,
+      final RepositoryModule repositoryModuleParam, final ConnectionModule connectionModuleParam,
+      final HttpMiddlewareProviderModule httpMiddlewareProviderModuleParam) {
+    this.provideInMemoryStorageConnectionProvider = DoubleCheck.provider(ConnectionModule_ProvideInMemoryStorageConnectionFactory.create(connectionModuleParam));
+    this.provideScheduledDatabaseRepositoryProvider = DoubleCheck.provider(RepositoryModule_ProvideScheduledDatabaseRepositoryFactory.create(repositoryModuleParam, provideInMemoryStorageConnectionProvider));
+    this.providePermanentStorageConnectionProvider = DoubleCheck.provider(ConnectionModule_ProvidePermanentStorageConnectionFactory.create(connectionModuleParam));
+    this.provideObservationRepositoryProvider = DoubleCheck.provider(RepositoryModule_ProvideObservationRepositoryFactory.create(repositoryModuleParam, providePermanentStorageConnectionProvider));
+  }
+
+  @Override
+  public ScheduledDataProviderConfig scheduledDatabaseProvider() {
+    return DatabaseProviderModule_ProvideScheduledProviderFactory.provideScheduledProvider(databaseProviderModule, scheduledDatabaseProvider2());
+  }
+
+  @Override
+  public LoopedDataProviderConfig loopedDatabaseProvider() {
+    return DatabaseProviderModule_ProvideLoopedProviderFactory.provideLoopedProvider(databaseProviderModule, loopedDatabaseProvider2());
+  }
+
+  @Override
+  public MiddlewareDataProviderConfig httpMiddlewareProvider() {
+    return HttpMiddlewareProviderModule_ProvideMiddlewareProviderFactory.provideMiddlewareProvider(httpMiddlewareProviderModule, HttpMiddlewareProviderModule_ProvideHttpMiddlewareProviderFactory.provideHttpMiddlewareProvider(httpMiddlewareProviderModule));
+  }
+
+  public static final class Builder {
+    private DatabaseProviderModule databaseProviderModule;
+
+    private RepositoryModule repositoryModule;
+
+    private ConnectionModule connectionModule;
+
+    private HttpMiddlewareProviderModule httpMiddlewareProviderModule;
+
+    private Builder() {
+    }
+
+    public Builder databaseProviderModule(DatabaseProviderModule databaseProviderModule) {
+      this.databaseProviderModule = Preconditions.checkNotNull(databaseProviderModule);
+      return this;
+    }
+
+    public Builder repositoryModule(RepositoryModule repositoryModule) {
+      this.repositoryModule = Preconditions.checkNotNull(repositoryModule);
+      return this;
+    }
+
+    public Builder connectionModule(ConnectionModule connectionModule) {
+      this.connectionModule = Preconditions.checkNotNull(connectionModule);
+      return this;
+    }
+
+    /**
+     * @deprecated This module is declared, but an instance is not used in the component. This method is a no-op. For more, see https://dagger.dev/unused-modules.
+     */
+    @Deprecated
+    public Builder configurationModule(ConfigurationModule configurationModule) {
+      Preconditions.checkNotNull(configurationModule);
+      return this;
+    }
+
+    public Builder httpMiddlewareProviderModule(
+        HttpMiddlewareProviderModule httpMiddlewareProviderModule) {
+      this.httpMiddlewareProviderModule = Preconditions.checkNotNull(httpMiddlewareProviderModule);
+      return this;
+    }
+
+    public DataProviderComponent build() {
+      if (databaseProviderModule == null) {
+        this.databaseProviderModule = new DatabaseProviderModule();
+      }
+      if (repositoryModule == null) {
+        this.repositoryModule = new RepositoryModule();
+      }
+      Preconditions.checkBuilderRequirement(connectionModule, ConnectionModule.class);
+      if (httpMiddlewareProviderModule == null) {
+        this.httpMiddlewareProviderModule = new HttpMiddlewareProviderModule();
+      }
+      return new DaggerDataProviderComponent(databaseProviderModule, repositoryModule, connectionModule, httpMiddlewareProviderModule);
+    }
+  }
+}

+ 40 - 0
src/main/generated/proxy/cz/senslog/analyzer/provider/DatabaseProviderModule_ProvideLoopedDatabaseProviderFactory.java

@@ -0,0 +1,40 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.provider;
+
+import cz.senslog.analyzer.storage.permanent.repository.SensLogRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class DatabaseProviderModule_ProvideLoopedDatabaseProviderFactory implements Factory<LoopedDatabaseProvider> {
+  private final DatabaseProviderModule module;
+
+  private final Provider<SensLogRepository> sensLogRepositoryProvider;
+
+  public DatabaseProviderModule_ProvideLoopedDatabaseProviderFactory(DatabaseProviderModule module,
+      Provider<SensLogRepository> sensLogRepositoryProvider) {
+    this.module = module;
+    this.sensLogRepositoryProvider = sensLogRepositoryProvider;
+  }
+
+  @Override
+  public LoopedDatabaseProvider get() {
+    return provideLoopedDatabaseProvider(module, sensLogRepositoryProvider.get());
+  }
+
+  public static DatabaseProviderModule_ProvideLoopedDatabaseProviderFactory create(
+      DatabaseProviderModule module, Provider<SensLogRepository> sensLogRepositoryProvider) {
+    return new DatabaseProviderModule_ProvideLoopedDatabaseProviderFactory(module, sensLogRepositoryProvider);
+  }
+
+  public static LoopedDatabaseProvider provideLoopedDatabaseProvider(
+      DatabaseProviderModule instance, SensLogRepository sensLogRepository) {
+    return Preconditions.checkNotNullFromProvides(instance.provideLoopedDatabaseProvider(sensLogRepository));
+  }
+}

+ 39 - 0
src/main/generated/proxy/cz/senslog/analyzer/provider/DatabaseProviderModule_ProvideLoopedProviderFactory.java

@@ -0,0 +1,39 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.provider;
+
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class DatabaseProviderModule_ProvideLoopedProviderFactory implements Factory<LoopedDataProviderConfig> {
+  private final DatabaseProviderModule module;
+
+  private final Provider<LoopedDatabaseProvider> providerProvider;
+
+  public DatabaseProviderModule_ProvideLoopedProviderFactory(DatabaseProviderModule module,
+      Provider<LoopedDatabaseProvider> providerProvider) {
+    this.module = module;
+    this.providerProvider = providerProvider;
+  }
+
+  @Override
+  public LoopedDataProviderConfig get() {
+    return provideLoopedProvider(module, providerProvider.get());
+  }
+
+  public static DatabaseProviderModule_ProvideLoopedProviderFactory create(
+      DatabaseProviderModule module, Provider<LoopedDatabaseProvider> providerProvider) {
+    return new DatabaseProviderModule_ProvideLoopedProviderFactory(module, providerProvider);
+  }
+
+  public static LoopedDataProviderConfig provideLoopedProvider(DatabaseProviderModule instance,
+      LoopedDatabaseProvider provider) {
+    return Preconditions.checkNotNullFromProvides(instance.provideLoopedProvider(provider));
+  }
+}

+ 47 - 0
src/main/generated/proxy/cz/senslog/analyzer/provider/DatabaseProviderModule_ProvideScheduleDatabaseProviderFactory.java

@@ -0,0 +1,47 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.provider;
+
+import cz.senslog.analyzer.storage.inmemory.repository.TimestampRepository;
+import cz.senslog.analyzer.storage.permanent.repository.SensLogRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class DatabaseProviderModule_ProvideScheduleDatabaseProviderFactory implements Factory<ScheduledDatabaseProvider> {
+  private final DatabaseProviderModule module;
+
+  private final Provider<TimestampRepository> configRepositoryProvider;
+
+  private final Provider<SensLogRepository> sensLogRepositoryProvider;
+
+  public DatabaseProviderModule_ProvideScheduleDatabaseProviderFactory(
+      DatabaseProviderModule module, Provider<TimestampRepository> configRepositoryProvider,
+      Provider<SensLogRepository> sensLogRepositoryProvider) {
+    this.module = module;
+    this.configRepositoryProvider = configRepositoryProvider;
+    this.sensLogRepositoryProvider = sensLogRepositoryProvider;
+  }
+
+  @Override
+  public ScheduledDatabaseProvider get() {
+    return provideScheduleDatabaseProvider(module, configRepositoryProvider.get(), sensLogRepositoryProvider.get());
+  }
+
+  public static DatabaseProviderModule_ProvideScheduleDatabaseProviderFactory create(
+      DatabaseProviderModule module, Provider<TimestampRepository> configRepositoryProvider,
+      Provider<SensLogRepository> sensLogRepositoryProvider) {
+    return new DatabaseProviderModule_ProvideScheduleDatabaseProviderFactory(module, configRepositoryProvider, sensLogRepositoryProvider);
+  }
+
+  public static ScheduledDatabaseProvider provideScheduleDatabaseProvider(
+      DatabaseProviderModule instance, TimestampRepository configRepository,
+      SensLogRepository sensLogRepository) {
+    return Preconditions.checkNotNullFromProvides(instance.provideScheduleDatabaseProvider(configRepository, sensLogRepository));
+  }
+}

+ 39 - 0
src/main/generated/proxy/cz/senslog/analyzer/provider/DatabaseProviderModule_ProvideScheduledProviderFactory.java

@@ -0,0 +1,39 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.provider;
+
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class DatabaseProviderModule_ProvideScheduledProviderFactory implements Factory<ScheduledDataProviderConfig> {
+  private final DatabaseProviderModule module;
+
+  private final Provider<ScheduledDatabaseProvider> providerProvider;
+
+  public DatabaseProviderModule_ProvideScheduledProviderFactory(DatabaseProviderModule module,
+      Provider<ScheduledDatabaseProvider> providerProvider) {
+    this.module = module;
+    this.providerProvider = providerProvider;
+  }
+
+  @Override
+  public ScheduledDataProviderConfig get() {
+    return provideScheduledProvider(module, providerProvider.get());
+  }
+
+  public static DatabaseProviderModule_ProvideScheduledProviderFactory create(
+      DatabaseProviderModule module, Provider<ScheduledDatabaseProvider> providerProvider) {
+    return new DatabaseProviderModule_ProvideScheduledProviderFactory(module, providerProvider);
+  }
+
+  public static ScheduledDataProviderConfig provideScheduledProvider(
+      DatabaseProviderModule instance, ScheduledDatabaseProvider provider) {
+    return Preconditions.checkNotNullFromProvides(instance.provideScheduledProvider(provider));
+  }
+}

+ 35 - 0
src/main/generated/proxy/cz/senslog/analyzer/provider/HttpMiddlewareProviderModule_ProvideHttpMiddlewareProviderFactory.java

@@ -0,0 +1,35 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.provider;
+
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class HttpMiddlewareProviderModule_ProvideHttpMiddlewareProviderFactory implements Factory<HttpMiddlewareProvider> {
+  private final HttpMiddlewareProviderModule module;
+
+  public HttpMiddlewareProviderModule_ProvideHttpMiddlewareProviderFactory(
+      HttpMiddlewareProviderModule module) {
+    this.module = module;
+  }
+
+  @Override
+  public HttpMiddlewareProvider get() {
+    return provideHttpMiddlewareProvider(module);
+  }
+
+  public static HttpMiddlewareProviderModule_ProvideHttpMiddlewareProviderFactory create(
+      HttpMiddlewareProviderModule module) {
+    return new HttpMiddlewareProviderModule_ProvideHttpMiddlewareProviderFactory(module);
+  }
+
+  public static HttpMiddlewareProvider provideHttpMiddlewareProvider(
+      HttpMiddlewareProviderModule instance) {
+    return Preconditions.checkNotNullFromProvides(instance.provideHttpMiddlewareProvider());
+  }
+}

+ 39 - 0
src/main/generated/proxy/cz/senslog/analyzer/provider/HttpMiddlewareProviderModule_ProvideMiddlewareProviderFactory.java

@@ -0,0 +1,39 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.provider;
+
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class HttpMiddlewareProviderModule_ProvideMiddlewareProviderFactory implements Factory<MiddlewareDataProviderConfig> {
+  private final HttpMiddlewareProviderModule module;
+
+  private final Provider<HttpMiddlewareProvider> providerProvider;
+
+  public HttpMiddlewareProviderModule_ProvideMiddlewareProviderFactory(
+      HttpMiddlewareProviderModule module, Provider<HttpMiddlewareProvider> providerProvider) {
+    this.module = module;
+    this.providerProvider = providerProvider;
+  }
+
+  @Override
+  public MiddlewareDataProviderConfig get() {
+    return provideMiddlewareProvider(module, providerProvider.get());
+  }
+
+  public static HttpMiddlewareProviderModule_ProvideMiddlewareProviderFactory create(
+      HttpMiddlewareProviderModule module, Provider<HttpMiddlewareProvider> providerProvider) {
+    return new HttpMiddlewareProviderModule_ProvideMiddlewareProviderFactory(module, providerProvider);
+  }
+
+  public static MiddlewareDataProviderConfig provideMiddlewareProvider(
+      HttpMiddlewareProviderModule instance, HttpMiddlewareProvider provider) {
+    return Preconditions.checkNotNullFromProvides(instance.provideMiddlewareProvider(provider));
+  }
+}

+ 29 - 0
src/main/generated/proxy/cz/senslog/analyzer/provider/HttpMiddlewareProvider_Factory.java

@@ -0,0 +1,29 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.provider;
+
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class HttpMiddlewareProvider_Factory implements Factory<HttpMiddlewareProvider> {
+  @Override
+  public HttpMiddlewareProvider get() {
+    return newInstance();
+  }
+
+  public static HttpMiddlewareProvider_Factory create() {
+    return InstanceHolder.INSTANCE;
+  }
+
+  public static HttpMiddlewareProvider newInstance() {
+    return new HttpMiddlewareProvider();
+  }
+
+  private static final class InstanceHolder {
+    private static final HttpMiddlewareProvider_Factory INSTANCE = new HttpMiddlewareProvider_Factory();
+  }
+}

+ 34 - 0
src/main/generated/proxy/cz/senslog/analyzer/provider/LoopedDatabaseProvider_Factory.java

@@ -0,0 +1,34 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.provider;
+
+import cz.senslog.analyzer.storage.permanent.repository.SensLogRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class LoopedDatabaseProvider_Factory implements Factory<LoopedDatabaseProvider> {
+  private final Provider<SensLogRepository> sensLogRepositoryProvider;
+
+  public LoopedDatabaseProvider_Factory(Provider<SensLogRepository> sensLogRepositoryProvider) {
+    this.sensLogRepositoryProvider = sensLogRepositoryProvider;
+  }
+
+  @Override
+  public LoopedDatabaseProvider get() {
+    return newInstance(sensLogRepositoryProvider.get());
+  }
+
+  public static LoopedDatabaseProvider_Factory create(
+      Provider<SensLogRepository> sensLogRepositoryProvider) {
+    return new LoopedDatabaseProvider_Factory(sensLogRepositoryProvider);
+  }
+
+  public static LoopedDatabaseProvider newInstance(SensLogRepository sensLogRepository) {
+    return new LoopedDatabaseProvider(sensLogRepository);
+  }
+}

+ 41 - 0
src/main/generated/proxy/cz/senslog/analyzer/provider/ScheduledDatabaseProvider_Factory.java

@@ -0,0 +1,41 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.provider;
+
+import cz.senslog.analyzer.storage.inmemory.repository.TimestampRepository;
+import cz.senslog.analyzer.storage.permanent.repository.SensLogRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class ScheduledDatabaseProvider_Factory implements Factory<ScheduledDatabaseProvider> {
+  private final Provider<TimestampRepository> configRepositoryProvider;
+
+  private final Provider<SensLogRepository> sensLogRepositoryProvider;
+
+  public ScheduledDatabaseProvider_Factory(Provider<TimestampRepository> configRepositoryProvider,
+      Provider<SensLogRepository> sensLogRepositoryProvider) {
+    this.configRepositoryProvider = configRepositoryProvider;
+    this.sensLogRepositoryProvider = sensLogRepositoryProvider;
+  }
+
+  @Override
+  public ScheduledDatabaseProvider get() {
+    return newInstance(configRepositoryProvider.get(), sensLogRepositoryProvider.get());
+  }
+
+  public static ScheduledDatabaseProvider_Factory create(
+      Provider<TimestampRepository> configRepositoryProvider,
+      Provider<SensLogRepository> sensLogRepositoryProvider) {
+    return new ScheduledDatabaseProvider_Factory(configRepositoryProvider, sensLogRepositoryProvider);
+  }
+
+  public static ScheduledDatabaseProvider newInstance(TimestampRepository configRepository,
+      SensLogRepository sensLogRepository) {
+    return new ScheduledDatabaseProvider(configRepository, sensLogRepository);
+  }
+}

+ 33 - 0
src/main/generated/proxy/cz/senslog/analyzer/storage/ConnectionModule_Factory.java

@@ -0,0 +1,33 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.storage;
+
+import cz.senslog.analyzer.core.config.domain.StorageConfig;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class ConnectionModule_Factory implements Factory<ConnectionModule> {
+  private final Provider<StorageConfig> configProvider;
+
+  public ConnectionModule_Factory(Provider<StorageConfig> configProvider) {
+    this.configProvider = configProvider;
+  }
+
+  @Override
+  public ConnectionModule get() {
+    return newInstance(configProvider.get());
+  }
+
+  public static ConnectionModule_Factory create(Provider<StorageConfig> configProvider) {
+    return new ConnectionModule_Factory(configProvider);
+  }
+
+  public static ConnectionModule newInstance(StorageConfig config) {
+    return new ConnectionModule(config);
+  }
+}

+ 34 - 0
src/main/generated/proxy/cz/senslog/analyzer/storage/ConnectionModule_ProvideInMemoryStorageConnectionFactory.java

@@ -0,0 +1,34 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.storage;
+
+import cz.senslog.analyzer.storage.inmemory.InMemoryConnection;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class ConnectionModule_ProvideInMemoryStorageConnectionFactory implements Factory<InMemoryConnection> {
+  private final ConnectionModule module;
+
+  public ConnectionModule_ProvideInMemoryStorageConnectionFactory(ConnectionModule module) {
+    this.module = module;
+  }
+
+  @Override
+  public InMemoryConnection get() {
+    return provideInMemoryStorageConnection(module);
+  }
+
+  public static ConnectionModule_ProvideInMemoryStorageConnectionFactory create(
+      ConnectionModule module) {
+    return new ConnectionModule_ProvideInMemoryStorageConnectionFactory(module);
+  }
+
+  public static InMemoryConnection provideInMemoryStorageConnection(ConnectionModule instance) {
+    return Preconditions.checkNotNullFromProvides(instance.provideInMemoryStorageConnection());
+  }
+}

+ 34 - 0
src/main/generated/proxy/cz/senslog/analyzer/storage/ConnectionModule_ProvidePermanentStorageConnectionFactory.java

@@ -0,0 +1,34 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.storage;
+
+import cz.senslog.analyzer.storage.permanent.PermanentConnection;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class ConnectionModule_ProvidePermanentStorageConnectionFactory implements Factory<PermanentConnection> {
+  private final ConnectionModule module;
+
+  public ConnectionModule_ProvidePermanentStorageConnectionFactory(ConnectionModule module) {
+    this.module = module;
+  }
+
+  @Override
+  public PermanentConnection get() {
+    return providePermanentStorageConnection(module);
+  }
+
+  public static ConnectionModule_ProvidePermanentStorageConnectionFactory create(
+      ConnectionModule module) {
+    return new ConnectionModule_ProvidePermanentStorageConnectionFactory(module);
+  }
+
+  public static PermanentConnection providePermanentStorageConnection(ConnectionModule instance) {
+    return Preconditions.checkNotNullFromProvides(instance.providePermanentStorageConnection());
+  }
+}

+ 41 - 0
src/main/generated/proxy/cz/senslog/analyzer/storage/RepositoryModule_ProvideCollectedStatisticsRepositoryFactory.java

@@ -0,0 +1,41 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.storage;
+
+import cz.senslog.analyzer.storage.inmemory.InMemoryConnection;
+import cz.senslog.analyzer.storage.inmemory.repository.CollectedStatisticsRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class RepositoryModule_ProvideCollectedStatisticsRepositoryFactory implements Factory<CollectedStatisticsRepository> {
+  private final RepositoryModule module;
+
+  private final Provider<InMemoryConnection> connectionProvider;
+
+  public RepositoryModule_ProvideCollectedStatisticsRepositoryFactory(RepositoryModule module,
+      Provider<InMemoryConnection> connectionProvider) {
+    this.module = module;
+    this.connectionProvider = connectionProvider;
+  }
+
+  @Override
+  public CollectedStatisticsRepository get() {
+    return provideCollectedStatisticsRepository(module, connectionProvider.get());
+  }
+
+  public static RepositoryModule_ProvideCollectedStatisticsRepositoryFactory create(
+      RepositoryModule module, Provider<InMemoryConnection> connectionProvider) {
+    return new RepositoryModule_ProvideCollectedStatisticsRepositoryFactory(module, connectionProvider);
+  }
+
+  public static CollectedStatisticsRepository provideCollectedStatisticsRepository(
+      RepositoryModule instance, InMemoryConnection connection) {
+    return Preconditions.checkNotNullFromProvides(instance.provideCollectedStatisticsRepository(connection));
+  }
+}

+ 41 - 0
src/main/generated/proxy/cz/senslog/analyzer/storage/RepositoryModule_ProvideObservationRepositoryFactory.java

@@ -0,0 +1,41 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.storage;
+
+import cz.senslog.analyzer.storage.permanent.PermanentConnection;
+import cz.senslog.analyzer.storage.permanent.repository.SensLogRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class RepositoryModule_ProvideObservationRepositoryFactory implements Factory<SensLogRepository> {
+  private final RepositoryModule module;
+
+  private final Provider<PermanentConnection> connectionProvider;
+
+  public RepositoryModule_ProvideObservationRepositoryFactory(RepositoryModule module,
+      Provider<PermanentConnection> connectionProvider) {
+    this.module = module;
+    this.connectionProvider = connectionProvider;
+  }
+
+  @Override
+  public SensLogRepository get() {
+    return provideObservationRepository(module, connectionProvider.get());
+  }
+
+  public static RepositoryModule_ProvideObservationRepositoryFactory create(RepositoryModule module,
+      Provider<PermanentConnection> connectionProvider) {
+    return new RepositoryModule_ProvideObservationRepositoryFactory(module, connectionProvider);
+  }
+
+  public static SensLogRepository provideObservationRepository(RepositoryModule instance,
+      PermanentConnection connection) {
+    return Preconditions.checkNotNullFromProvides(instance.provideObservationRepository(connection));
+  }
+}

+ 41 - 0
src/main/generated/proxy/cz/senslog/analyzer/storage/RepositoryModule_ProvideScheduledDatabaseRepositoryFactory.java

@@ -0,0 +1,41 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.storage;
+
+import cz.senslog.analyzer.storage.inmemory.InMemoryConnection;
+import cz.senslog.analyzer.storage.inmemory.repository.TimestampRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class RepositoryModule_ProvideScheduledDatabaseRepositoryFactory implements Factory<TimestampRepository> {
+  private final RepositoryModule module;
+
+  private final Provider<InMemoryConnection> connectionProvider;
+
+  public RepositoryModule_ProvideScheduledDatabaseRepositoryFactory(RepositoryModule module,
+      Provider<InMemoryConnection> connectionProvider) {
+    this.module = module;
+    this.connectionProvider = connectionProvider;
+  }
+
+  @Override
+  public TimestampRepository get() {
+    return provideScheduledDatabaseRepository(module, connectionProvider.get());
+  }
+
+  public static RepositoryModule_ProvideScheduledDatabaseRepositoryFactory create(
+      RepositoryModule module, Provider<InMemoryConnection> connectionProvider) {
+    return new RepositoryModule_ProvideScheduledDatabaseRepositoryFactory(module, connectionProvider);
+  }
+
+  public static TimestampRepository provideScheduledDatabaseRepository(RepositoryModule instance,
+      InMemoryConnection connection) {
+    return Preconditions.checkNotNullFromProvides(instance.provideScheduledDatabaseRepository(connection));
+  }
+}

+ 41 - 0
src/main/generated/proxy/cz/senslog/analyzer/storage/RepositoryModule_ProvideStatisticsConfigRepositoryFactory.java

@@ -0,0 +1,41 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.storage;
+
+import cz.senslog.analyzer.storage.permanent.PermanentConnection;
+import cz.senslog.analyzer.storage.permanent.repository.StatisticsConfigRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class RepositoryModule_ProvideStatisticsConfigRepositoryFactory implements Factory<StatisticsConfigRepository> {
+  private final RepositoryModule module;
+
+  private final Provider<PermanentConnection> connectionProvider;
+
+  public RepositoryModule_ProvideStatisticsConfigRepositoryFactory(RepositoryModule module,
+      Provider<PermanentConnection> connectionProvider) {
+    this.module = module;
+    this.connectionProvider = connectionProvider;
+  }
+
+  @Override
+  public StatisticsConfigRepository get() {
+    return provideStatisticsConfigRepository(module, connectionProvider.get());
+  }
+
+  public static RepositoryModule_ProvideStatisticsConfigRepositoryFactory create(
+      RepositoryModule module, Provider<PermanentConnection> connectionProvider) {
+    return new RepositoryModule_ProvideStatisticsConfigRepositoryFactory(module, connectionProvider);
+  }
+
+  public static StatisticsConfigRepository provideStatisticsConfigRepository(
+      RepositoryModule instance, PermanentConnection connection) {
+    return Preconditions.checkNotNullFromProvides(instance.provideStatisticsConfigRepository(connection));
+  }
+}

+ 41 - 0
src/main/generated/proxy/cz/senslog/analyzer/storage/RepositoryModule_ProvideStatisticsRepositoryFactory.java

@@ -0,0 +1,41 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.storage;
+
+import cz.senslog.analyzer.storage.permanent.PermanentConnection;
+import cz.senslog.analyzer.storage.permanent.repository.StatisticsRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class RepositoryModule_ProvideStatisticsRepositoryFactory implements Factory<StatisticsRepository> {
+  private final RepositoryModule module;
+
+  private final Provider<PermanentConnection> connectionProvider;
+
+  public RepositoryModule_ProvideStatisticsRepositoryFactory(RepositoryModule module,
+      Provider<PermanentConnection> connectionProvider) {
+    this.module = module;
+    this.connectionProvider = connectionProvider;
+  }
+
+  @Override
+  public StatisticsRepository get() {
+    return provideStatisticsRepository(module, connectionProvider.get());
+  }
+
+  public static RepositoryModule_ProvideStatisticsRepositoryFactory create(RepositoryModule module,
+      Provider<PermanentConnection> connectionProvider) {
+    return new RepositoryModule_ProvideStatisticsRepositoryFactory(module, connectionProvider);
+  }
+
+  public static StatisticsRepository provideStatisticsRepository(RepositoryModule instance,
+      PermanentConnection connection) {
+    return Preconditions.checkNotNullFromProvides(instance.provideStatisticsRepository(connection));
+  }
+}

+ 35 - 0
src/main/generated/proxy/cz/senslog/analyzer/storage/inmemory/repository/CollectedStatisticsRepository_Factory.java

@@ -0,0 +1,35 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.storage.inmemory.repository;
+
+import cz.senslog.analyzer.storage.Connection;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import javax.inject.Provider;
+import org.jdbi.v3.core.Jdbi;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class CollectedStatisticsRepository_Factory implements Factory<CollectedStatisticsRepository> {
+  private final Provider<Connection<Jdbi>> connectionProvider;
+
+  public CollectedStatisticsRepository_Factory(Provider<Connection<Jdbi>> connectionProvider) {
+    this.connectionProvider = connectionProvider;
+  }
+
+  @Override
+  public CollectedStatisticsRepository get() {
+    return newInstance(connectionProvider.get());
+  }
+
+  public static CollectedStatisticsRepository_Factory create(
+      Provider<Connection<Jdbi>> connectionProvider) {
+    return new CollectedStatisticsRepository_Factory(connectionProvider);
+  }
+
+  public static CollectedStatisticsRepository newInstance(Connection<Jdbi> connection) {
+    return new CollectedStatisticsRepository(connection);
+  }
+}

+ 34 - 0
src/main/generated/proxy/cz/senslog/analyzer/storage/inmemory/repository/TimestampRepository_Factory.java

@@ -0,0 +1,34 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.storage.inmemory.repository;
+
+import cz.senslog.analyzer.storage.Connection;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import javax.inject.Provider;
+import org.jdbi.v3.core.Jdbi;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class TimestampRepository_Factory implements Factory<TimestampRepository> {
+  private final Provider<Connection<Jdbi>> connectionProvider;
+
+  public TimestampRepository_Factory(Provider<Connection<Jdbi>> connectionProvider) {
+    this.connectionProvider = connectionProvider;
+  }
+
+  @Override
+  public TimestampRepository get() {
+    return newInstance(connectionProvider.get());
+  }
+
+  public static TimestampRepository_Factory create(Provider<Connection<Jdbi>> connectionProvider) {
+    return new TimestampRepository_Factory(connectionProvider);
+  }
+
+  public static TimestampRepository newInstance(Connection<Jdbi> connection) {
+    return new TimestampRepository(connection);
+  }
+}

+ 34 - 0
src/main/generated/proxy/cz/senslog/analyzer/storage/permanent/repository/SensLogRepository_Factory.java

@@ -0,0 +1,34 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.storage.permanent.repository;
+
+import cz.senslog.analyzer.storage.Connection;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import javax.inject.Provider;
+import org.jdbi.v3.core.Jdbi;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class SensLogRepository_Factory implements Factory<SensLogRepository> {
+  private final Provider<Connection<Jdbi>> connectionProvider;
+
+  public SensLogRepository_Factory(Provider<Connection<Jdbi>> connectionProvider) {
+    this.connectionProvider = connectionProvider;
+  }
+
+  @Override
+  public SensLogRepository get() {
+    return newInstance(connectionProvider.get());
+  }
+
+  public static SensLogRepository_Factory create(Provider<Connection<Jdbi>> connectionProvider) {
+    return new SensLogRepository_Factory(connectionProvider);
+  }
+
+  public static SensLogRepository newInstance(Connection<Jdbi> connection) {
+    return new SensLogRepository(connection);
+  }
+}

+ 35 - 0
src/main/generated/proxy/cz/senslog/analyzer/storage/permanent/repository/StatisticsConfigRepository_Factory.java

@@ -0,0 +1,35 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.storage.permanent.repository;
+
+import cz.senslog.analyzer.storage.Connection;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import javax.inject.Provider;
+import org.jdbi.v3.core.Jdbi;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class StatisticsConfigRepository_Factory implements Factory<StatisticsConfigRepository> {
+  private final Provider<Connection<Jdbi>> connectionProvider;
+
+  public StatisticsConfigRepository_Factory(Provider<Connection<Jdbi>> connectionProvider) {
+    this.connectionProvider = connectionProvider;
+  }
+
+  @Override
+  public StatisticsConfigRepository get() {
+    return newInstance(connectionProvider.get());
+  }
+
+  public static StatisticsConfigRepository_Factory create(
+      Provider<Connection<Jdbi>> connectionProvider) {
+    return new StatisticsConfigRepository_Factory(connectionProvider);
+  }
+
+  public static StatisticsConfigRepository newInstance(Connection<Jdbi> connection) {
+    return new StatisticsConfigRepository(connection);
+  }
+}

+ 34 - 0
src/main/generated/proxy/cz/senslog/analyzer/storage/permanent/repository/StatisticsRepository_Factory.java

@@ -0,0 +1,34 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.storage.permanent.repository;
+
+import cz.senslog.analyzer.storage.Connection;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import javax.inject.Provider;
+import org.jdbi.v3.core.Jdbi;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class StatisticsRepository_Factory implements Factory<StatisticsRepository> {
+  private final Provider<Connection<Jdbi>> connectionProvider;
+
+  public StatisticsRepository_Factory(Provider<Connection<Jdbi>> connectionProvider) {
+    this.connectionProvider = connectionProvider;
+  }
+
+  @Override
+  public StatisticsRepository get() {
+    return newInstance(connectionProvider.get());
+  }
+
+  public static StatisticsRepository_Factory create(Provider<Connection<Jdbi>> connectionProvider) {
+    return new StatisticsRepository_Factory(connectionProvider);
+  }
+
+  public static StatisticsRepository newInstance(Connection<Jdbi> connection) {
+    return new StatisticsRepository(connection);
+  }
+}

+ 112 - 0
src/main/generated/proxy/cz/senslog/analyzer/ws/DaggerServerComponent.java

@@ -0,0 +1,112 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.ws;
+
+import cz.senslog.analyzer.core.config.ConfigurationModule;
+import cz.senslog.analyzer.storage.ConnectionModule;
+import cz.senslog.analyzer.storage.ConnectionModule_ProvidePermanentStorageConnectionFactory;
+import cz.senslog.analyzer.storage.RepositoryModule;
+import cz.senslog.analyzer.storage.RepositoryModule_ProvideStatisticsConfigRepositoryFactory;
+import cz.senslog.analyzer.storage.RepositoryModule_ProvideStatisticsRepositoryFactory;
+import cz.senslog.analyzer.storage.permanent.PermanentConnection;
+import cz.senslog.analyzer.storage.permanent.repository.StatisticsConfigRepository;
+import cz.senslog.analyzer.storage.permanent.repository.StatisticsRepository;
+import cz.senslog.analyzer.ws.handler.GroupsHandler;
+import cz.senslog.analyzer.ws.handler.InfoHandler;
+import cz.senslog.analyzer.ws.handler.StatisticsHandler;
+import cz.senslog.analyzer.ws.manager.WSStatisticsManager;
+import cz.senslog.analyzer.ws.vertx.VertxServer;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.DoubleCheck;
+import dagger.internal.Preconditions;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class DaggerServerComponent implements ServerComponent {
+  private final DaggerServerComponent serverComponent = this;
+
+  private Provider<PermanentConnection> providePermanentStorageConnectionProvider;
+
+  private Provider<StatisticsRepository> provideStatisticsRepositoryProvider;
+
+  private Provider<StatisticsConfigRepository> provideStatisticsConfigRepositoryProvider;
+
+  private DaggerServerComponent(RepositoryModule repositoryModuleParam,
+      ConnectionModule connectionModuleParam) {
+
+    initialize(repositoryModuleParam, connectionModuleParam);
+
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  private WSStatisticsManager wSStatisticsManager() {
+    return new WSStatisticsManager(provideStatisticsRepositoryProvider.get(), provideStatisticsConfigRepositoryProvider.get());
+  }
+
+  private StatisticsHandler statisticsHandler() {
+    return new StatisticsHandler(wSStatisticsManager());
+  }
+
+  private GroupsHandler groupsHandler() {
+    return new GroupsHandler(provideStatisticsConfigRepositoryProvider.get());
+  }
+
+  private VertxServer vertxServer() {
+    return new VertxServer(new InfoHandler(), statisticsHandler(), groupsHandler());
+  }
+
+  @SuppressWarnings("unchecked")
+  private void initialize(final RepositoryModule repositoryModuleParam,
+      final ConnectionModule connectionModuleParam) {
+    this.providePermanentStorageConnectionProvider = DoubleCheck.provider(ConnectionModule_ProvidePermanentStorageConnectionFactory.create(connectionModuleParam));
+    this.provideStatisticsRepositoryProvider = DoubleCheck.provider(RepositoryModule_ProvideStatisticsRepositoryFactory.create(repositoryModuleParam, providePermanentStorageConnectionProvider));
+    this.provideStatisticsConfigRepositoryProvider = DoubleCheck.provider(RepositoryModule_ProvideStatisticsConfigRepositoryFactory.create(repositoryModuleParam, providePermanentStorageConnectionProvider));
+  }
+
+  @Override
+  public Server createServer() {
+    return vertxServer();
+  }
+
+  public static final class Builder {
+    private RepositoryModule repositoryModule;
+
+    private ConnectionModule connectionModule;
+
+    private Builder() {
+    }
+
+    public Builder repositoryModule(RepositoryModule repositoryModule) {
+      this.repositoryModule = Preconditions.checkNotNull(repositoryModule);
+      return this;
+    }
+
+    public Builder connectionModule(ConnectionModule connectionModule) {
+      this.connectionModule = Preconditions.checkNotNull(connectionModule);
+      return this;
+    }
+
+    /**
+     * @deprecated This module is declared, but an instance is not used in the component. This method is a no-op. For more, see https://dagger.dev/unused-modules.
+     */
+    @Deprecated
+    public Builder configurationModule(ConfigurationModule configurationModule) {
+      Preconditions.checkNotNull(configurationModule);
+      return this;
+    }
+
+    public ServerComponent build() {
+      if (repositoryModule == null) {
+        this.repositoryModule = new RepositoryModule();
+      }
+      Preconditions.checkBuilderRequirement(connectionModule, ConnectionModule.class);
+      return new DaggerServerComponent(repositoryModule, connectionModule);
+    }
+  }
+}

+ 34 - 0
src/main/generated/proxy/cz/senslog/analyzer/ws/handler/GroupsHandler_Factory.java

@@ -0,0 +1,34 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.ws.handler;
+
+import cz.senslog.analyzer.storage.permanent.repository.StatisticsConfigRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class GroupsHandler_Factory implements Factory<GroupsHandler> {
+  private final Provider<StatisticsConfigRepository> repositoryProvider;
+
+  public GroupsHandler_Factory(Provider<StatisticsConfigRepository> repositoryProvider) {
+    this.repositoryProvider = repositoryProvider;
+  }
+
+  @Override
+  public GroupsHandler get() {
+    return newInstance(repositoryProvider.get());
+  }
+
+  public static GroupsHandler_Factory create(
+      Provider<StatisticsConfigRepository> repositoryProvider) {
+    return new GroupsHandler_Factory(repositoryProvider);
+  }
+
+  public static GroupsHandler newInstance(StatisticsConfigRepository repository) {
+    return new GroupsHandler(repository);
+  }
+}

+ 29 - 0
src/main/generated/proxy/cz/senslog/analyzer/ws/handler/InfoHandler_Factory.java

@@ -0,0 +1,29 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.ws.handler;
+
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class InfoHandler_Factory implements Factory<InfoHandler> {
+  @Override
+  public InfoHandler get() {
+    return newInstance();
+  }
+
+  public static InfoHandler_Factory create() {
+    return InstanceHolder.INSTANCE;
+  }
+
+  public static InfoHandler newInstance() {
+    return new InfoHandler();
+  }
+
+  private static final class InstanceHolder {
+    private static final InfoHandler_Factory INSTANCE = new InfoHandler_Factory();
+  }
+}

+ 33 - 0
src/main/generated/proxy/cz/senslog/analyzer/ws/handler/StatisticsHandler_Factory.java

@@ -0,0 +1,33 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.ws.handler;
+
+import cz.senslog.analyzer.ws.manager.WSStatisticsManager;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class StatisticsHandler_Factory implements Factory<StatisticsHandler> {
+  private final Provider<WSStatisticsManager> managerProvider;
+
+  public StatisticsHandler_Factory(Provider<WSStatisticsManager> managerProvider) {
+    this.managerProvider = managerProvider;
+  }
+
+  @Override
+  public StatisticsHandler get() {
+    return newInstance(managerProvider.get());
+  }
+
+  public static StatisticsHandler_Factory create(Provider<WSStatisticsManager> managerProvider) {
+    return new StatisticsHandler_Factory(managerProvider);
+  }
+
+  public static StatisticsHandler newInstance(WSStatisticsManager manager) {
+    return new StatisticsHandler(manager);
+  }
+}

+ 41 - 0
src/main/generated/proxy/cz/senslog/analyzer/ws/manager/WSStatisticsManager_Factory.java

@@ -0,0 +1,41 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.ws.manager;
+
+import cz.senslog.analyzer.storage.permanent.repository.StatisticsConfigRepository;
+import cz.senslog.analyzer.storage.permanent.repository.StatisticsRepository;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class WSStatisticsManager_Factory implements Factory<WSStatisticsManager> {
+  private final Provider<StatisticsRepository> statisticsRepositoryProvider;
+
+  private final Provider<StatisticsConfigRepository> configRepositoryProvider;
+
+  public WSStatisticsManager_Factory(Provider<StatisticsRepository> statisticsRepositoryProvider,
+      Provider<StatisticsConfigRepository> configRepositoryProvider) {
+    this.statisticsRepositoryProvider = statisticsRepositoryProvider;
+    this.configRepositoryProvider = configRepositoryProvider;
+  }
+
+  @Override
+  public WSStatisticsManager get() {
+    return newInstance(statisticsRepositoryProvider.get(), configRepositoryProvider.get());
+  }
+
+  public static WSStatisticsManager_Factory create(
+      Provider<StatisticsRepository> statisticsRepositoryProvider,
+      Provider<StatisticsConfigRepository> configRepositoryProvider) {
+    return new WSStatisticsManager_Factory(statisticsRepositoryProvider, configRepositoryProvider);
+  }
+
+  public static WSStatisticsManager newInstance(StatisticsRepository statisticsRepository,
+      StatisticsConfigRepository configRepository) {
+    return new WSStatisticsManager(statisticsRepository, configRepository);
+  }
+}

+ 46 - 0
src/main/generated/proxy/cz/senslog/analyzer/ws/vertx/VertxServer_Factory.java

@@ -0,0 +1,46 @@
+// Generated by Dagger (https://dagger.dev).
+package cz.senslog.analyzer.ws.vertx;
+
+import cz.senslog.analyzer.ws.handler.GroupsHandler;
+import cz.senslog.analyzer.ws.handler.InfoHandler;
+import cz.senslog.analyzer.ws.handler.StatisticsHandler;
+import dagger.internal.DaggerGenerated;
+import dagger.internal.Factory;
+import javax.inject.Provider;
+
+@DaggerGenerated
+@SuppressWarnings({
+    "unchecked",
+    "rawtypes"
+})
+public final class VertxServer_Factory implements Factory<VertxServer> {
+  private final Provider<InfoHandler> infoHandlerProvider;
+
+  private final Provider<StatisticsHandler> statisticsHandlerProvider;
+
+  private final Provider<GroupsHandler> groupsHandlerProvider;
+
+  public VertxServer_Factory(Provider<InfoHandler> infoHandlerProvider,
+      Provider<StatisticsHandler> statisticsHandlerProvider,
+      Provider<GroupsHandler> groupsHandlerProvider) {
+    this.infoHandlerProvider = infoHandlerProvider;
+    this.statisticsHandlerProvider = statisticsHandlerProvider;
+    this.groupsHandlerProvider = groupsHandlerProvider;
+  }
+
+  @Override
+  public VertxServer get() {
+    return newInstance(infoHandlerProvider.get(), statisticsHandlerProvider.get(), groupsHandlerProvider.get());
+  }
+
+  public static VertxServer_Factory create(Provider<InfoHandler> infoHandlerProvider,
+      Provider<StatisticsHandler> statisticsHandlerProvider,
+      Provider<GroupsHandler> groupsHandlerProvider) {
+    return new VertxServer_Factory(infoHandlerProvider, statisticsHandlerProvider, groupsHandlerProvider);
+  }
+
+  public static VertxServer newInstance(InfoHandler infoHandler,
+      StatisticsHandler statisticsHandler, GroupsHandler groupsHandler) {
+    return new VertxServer(infoHandler, statisticsHandler, groupsHandler);
+  }
+}

+ 12 - 12
src/main/java/cz/senslog/analyzer/analysis/Analyzer.java

@@ -1,12 +1,12 @@
-package cz.senslog.analyzer.analysis;
-
-import java.util.List;
-
-public interface Analyzer<T> {
-
-    void accept(List<T> observations);
-
-    AnalyzerInfo info();
-
-    AnalyzerConfigInfo reloadConfig(List<Object> moduleConfigs);
-}
+package cz.senslog.analyzer.analysis;
+
+import java.util.List;
+
+public interface Analyzer<T> {
+
+    void accept(List<T> observations);
+
+    AnalyzerInfo info();
+
+    void reloadConfig();
+}

+ 15 - 15
src/main/java/cz/senslog/analyzer/analysis/AnalyzerComponent.java

@@ -1,15 +1,15 @@
-package cz.senslog.analyzer.analysis;
-
-import cz.senslog.analyzer.domain.Observation;
-import dagger.Component;
-
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-@Singleton
-@Component(modules = AnalyzerModule.class)
-public interface AnalyzerComponent {
-
-    @Named("statisticsAnalyzer")
-    Analyzer<Observation> createNewObservationAnalyzer();
-}
+package cz.senslog.analyzer.analysis;
+
+import cz.senslog.analyzer.domain.Observation;
+import dagger.Component;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+@Singleton
+@Component(modules = AnalyzerModule.class)
+public interface AnalyzerComponent {
+
+    @Named("statisticsAnalyzer")
+    Analyzer<Observation> createObservationAnalyzer();
+}

+ 16 - 0
src/main/java/cz/senslog/analyzer/analysis/ManualAnalyticsConfig.java

@@ -0,0 +1,16 @@
+package cz.senslog.analyzer.analysis;
+
+import java.util.List;
+
+public class ManualAnalyticsConfig {
+
+    private final List<TaskConfig> tasks;
+
+    public ManualAnalyticsConfig(List<TaskConfig> tasks) {
+        this.tasks = tasks;
+    }
+
+    public List<TaskConfig> getTasks() {
+        return tasks;
+    }
+}

+ 38 - 38
src/main/java/cz/senslog/analyzer/analysis/ObservationAnalyzer.java

@@ -1,38 +1,38 @@
-package cz.senslog.analyzer.analysis;
-
-import cz.senslog.analyzer.core.api.HandlerInvoker;
-import cz.senslog.analyzer.domain.Observation;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import java.util.List;
-
-public class ObservationAnalyzer implements Analyzer<Observation> {
-
-    private static final Logger logger = LogManager.getLogger(ObservationAnalyzer.class);
-
-    private final HandlerInvoker<Observation> invoker;
-
-    public ObservationAnalyzer(HandlerInvoker<Observation> invoker) {
-        this.invoker = invoker;
-    }
-
-    @Override
-    public void accept(List<Observation> observations) {
-        synchronized (this) {
-            logger.info("Processing of the new {} observations.", observations.size());
-            invoker.accept(observations);
-            logger.info("The process of processing new observations is finished.");
-        }
-    }
-
-    @Override
-    public AnalyzerInfo info() {
-        return null;
-    }
-
-    @Override
-    public AnalyzerConfigInfo reloadConfig(List<Object> moduleConfigs) {
-        return new AnalyzerConfigInfo();
-    }
-}
+package cz.senslog.analyzer.analysis;
+
+import cz.senslog.analyzer.core.api.HandlerInvoker;
+import cz.senslog.analyzer.domain.Observation;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.List;
+
+public class ObservationAnalyzer implements Analyzer<Observation> {
+
+    private static final Logger logger = LogManager.getLogger(ObservationAnalyzer.class);
+
+    private final HandlerInvoker<Observation> invoker;
+
+    public ObservationAnalyzer(HandlerInvoker<Observation> invoker) {
+        this.invoker = invoker;
+    }
+
+    @Override
+    public void accept(List<Observation> observations) {
+        synchronized (this) {
+            logger.info("Processing of the new {} observations.", observations.size());
+            invoker.accept(observations);
+            logger.info("The process of processing new observations is finished.");
+        }
+    }
+
+    @Override
+    public AnalyzerInfo info() {
+        return null;
+    }
+
+    @Override
+    public void reloadConfig() {
+        // TODO reload all modules' settings
+    }
+}

+ 69 - 0
src/main/java/cz/senslog/analyzer/analysis/TaskConfig.java

@@ -0,0 +1,69 @@
+package cz.senslog.analyzer.analysis;
+
+import java.time.OffsetDateTime;
+import java.util.Objects;
+import java.util.Set;
+
+public class TaskConfig {
+    private final String id;
+    private final OffsetDateTime from, to;
+    private final Set<Long> groupIds;
+
+    public TaskConfig(String id, Set<Long> groupIds, OffsetDateTime from, OffsetDateTime to) {
+        Objects.requireNonNull(id);
+        Objects.requireNonNull(groupIds);
+        Objects.requireNonNull(from);
+        Objects.requireNonNull(to);
+
+        OffsetDateTime now = OffsetDateTime.now();
+        if (from.isAfter(now)) {
+            throw new UnsupportedOperationException(String.format(
+                    "Value 'from' can not be in future for the task '%s'.", id
+            ));
+        }
+        if (to.isAfter(now)) {
+            throw new UnsupportedOperationException(String.format(
+                    "Value 'to' can not be in future for the task '%s'.", id
+            ));
+        }
+        if (to.isBefore(from) || to.isEqual(from)) {
+            throw new UnsupportedOperationException(String.format(
+                    "Value 'from' and 'to' does not create an interval in the task '%s'.", id
+            ));
+        }
+
+        this.id = id;
+        this.from = from;
+        this.to = to;
+        this.groupIds = groupIds;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public OffsetDateTime getFrom() {
+        return from;
+    }
+
+    public OffsetDateTime getTo() {
+        return to;
+    }
+
+    public Set<Long> getGroupIds() {
+        return groupIds;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        TaskConfig that = (TaskConfig) o;
+        return id.equals(that.id);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(id);
+    }
+}

+ 2 - 1
src/main/java/cz/senslog/analyzer/analysis/module/CollectorHandler.java

@@ -64,7 +64,8 @@ public abstract class CollectorHandler<I extends Data<?, ?>> extends BlockingHan
                 }
             }
         }
-        if (statisticsStorage.commit()) {
+        String providerName = Thread.currentThread().getName();
+        if (statisticsStorage.commit() && providerName.contains("db-scheduler")) { // TODO temporary hack
             timestampStorage.update(edgeDateTime, LAST_COMMITTED_INCLUSIVE);
         }
         finisher.finish(finishedData);

+ 79 - 74
src/main/java/cz/senslog/analyzer/analysis/module/HandlersModule.java

@@ -1,74 +1,79 @@
-package cz.senslog.analyzer.analysis.module;
-
-import cz.senslog.analyzer.core.api.BlockingHandler;
-import cz.senslog.analyzer.domain.*;
-import cz.senslog.analyzer.storage.RepositoryModule;
-import cz.senslog.analyzer.storage.inmemory.CollectedStatisticsStorage;
-import cz.senslog.analyzer.storage.inmemory.TimestampStorage;
-import cz.senslog.analyzer.storage.inmemory.repository.CollectedStatisticsRepository;
-import cz.senslog.analyzer.storage.inmemory.repository.TimestampRepository;
-import cz.senslog.analyzer.storage.permanent.repository.StatisticsConfigRepository;
-import dagger.Module;
-import dagger.Provides;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import javax.inject.Named;
-import javax.inject.Singleton;
-import java.util.*;
-import java.util.function.Function;
-
-@Module(includes = RepositoryModule.class)
-public class HandlersModule {
-
-    private static final Logger logger = LogManager.getLogger(HandlersModule.class);
-
-    @Provides @Singleton @Named("sensorFilterHandler")
-    public FilterHandler<Observation> provideFilterHandler(StatisticsConfigRepository repository) {
-        logger.info("Creating a new instance for the handler '{}'.", "sensorFilterHandler");
-        return new FilterHandler<Observation>() {
-            @Override protected List<Sensor> loadMapping() { return repository.getAllAvailableSensors(); }
-            @Override protected Observation newData(Sensor sensor, Observation data) {
-                return new Observation(sensor, data.getValue(), data.getTimestamp()); }
-            @Override protected Sensor getSensor(Observation data) { return data.getSource(); }
-        };
-    }
-
-    @Provides @Singleton @Named("sensorThresholdHandler")
-    public ThresholdHandler<Observation> provideSensorThresholdHandler(StatisticsConfigRepository repository) {
-        logger.info("Creating a new instance for the handler '{}'.", "sensorThresholdHandler");
-        return new ThresholdHandler<Observation>() {
-            @Override protected List<Threshold> loadThresholdValues() { return repository.getCurrentThresholdsValue(); }
-            @Override protected long getGroupId(Observation data) { return data.getSource().getGroupId(); }
-        };
-    }
-
-    @Provides @Singleton @Named("groupThresholdHandler")
-    public ThresholdHandler<DoubleStatistics> provideGroupThresholdHandler(StatisticsConfigRepository repository) {
-        logger.info("Creating a new instance for the handler '{}'.", "groupThresholdHandler");
-        return new ThresholdHandler<DoubleStatistics>() {
-            @Override protected List<Threshold> loadThresholdValues() { return repository.getIntervalThresholdsValue(); }
-            @Override protected long getGroupId(DoubleStatistics data) { return data.getSource().getId(); }
-        };
-    }
-
-    @Provides @Singleton @Named("aggregationCollectorHandler")
-    public BlockingHandler<Observation, DoubleStatistics> provideObservationCollector(
-            StatisticsConfigRepository statisticsConfigRepository,
-            CollectedStatisticsRepository collectedStatisticsRepository,
-            TimestampRepository timestampRepository
-    ) {
-        logger.info("Creating a new instance for the handler '{}'.", "aggregationCollectorHandler");
-        CollectedStatisticsStorage statisticsStorage = CollectedStatisticsStorage.createContext(collectedStatisticsRepository);
-        TimestampStorage timestampStorage = TimestampStorage.createContext(timestampRepository);
-        return new CollectorHandler<Observation>(statisticsStorage, timestampStorage) {
-            @Override protected List<Group> loadGroups() {
-                return statisticsConfigRepository.getGroupInfos();
-            }
-            @Override protected Function<Observation, Boolean> collectData(DoubleStatistics statistics) {
-                return val -> statistics.accept(val.getSource(), val.getValue());
-            }
-            @Override protected long getGroupId(Observation data) { return data.getSource().getGroupId(); }
-        };
-    }
-}
+package cz.senslog.analyzer.analysis.module;
+
+import cz.senslog.analyzer.core.api.BlockingHandler;
+import cz.senslog.analyzer.domain.*;
+import cz.senslog.analyzer.storage.RepositoryModule;
+import cz.senslog.analyzer.storage.inmemory.CollectedStatisticsStorage;
+import cz.senslog.analyzer.storage.inmemory.TimestampStorage;
+import cz.senslog.analyzer.storage.inmemory.repository.CollectedStatisticsRepository;
+import cz.senslog.analyzer.storage.inmemory.repository.TimestampRepository;
+import cz.senslog.analyzer.storage.permanent.repository.StatisticsConfigRepository;
+import dagger.Module;
+import dagger.Provides;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+import java.util.*;
+import java.util.function.Function;
+
+@Module(includes = RepositoryModule.class)
+public class HandlersModule {
+
+    private static final Logger logger = LogManager.getLogger(HandlersModule.class);
+
+    @Provides @Singleton @Named("sensorFilterHandler")
+    public FilterHandler<Observation> provideFilterHandler(StatisticsConfigRepository repository) {
+        logger.info("Creating a new instance for the handler '{}'.", "sensorFilterHandler");
+        return new FilterHandler<Observation>() {
+            @Override protected List<Sensor> loadMapping() {
+                return repository.getAllAvailableSensors(); }
+            @Override protected Observation newData(Sensor sensor, Observation data) {
+                return new Observation(sensor, data.getValue(), data.getTimestamp()); }
+            @Override protected Sensor getSensor(Observation data) {
+                return data.getSource(); }
+        };
+    }
+
+    @Provides @Singleton @Named("sensorThresholdHandler")
+    public ThresholdHandler<Observation> provideSensorThresholdHandler(StatisticsConfigRepository repository) {
+        logger.info("Creating a new instance for the handler '{}'.", "sensorThresholdHandler");
+        return new ThresholdHandler<Observation>() {
+            @Override protected List<Threshold> loadThresholdValues() {
+                return repository.getCurrentThresholdsValue(); }
+            @Override protected long getGroupId(Observation data) {
+                return data.getSource().getGroupId(); }
+        };
+    }
+
+    @Provides @Singleton @Named("groupThresholdHandler")
+    public ThresholdHandler<DoubleStatistics> provideGroupThresholdHandler(StatisticsConfigRepository repository) {
+        logger.info("Creating a new instance for the handler '{}'.", "groupThresholdHandler");
+        return new ThresholdHandler<DoubleStatistics>() {
+            @Override protected List<Threshold> loadThresholdValues() {
+                return repository.getIntervalThresholdsValue(); }
+            @Override protected long getGroupId(DoubleStatistics data) {
+                return data.getSource().getId(); }
+        };
+    }
+
+    @Provides @Singleton @Named("aggregationCollectorHandler")
+    public BlockingHandler<Observation, DoubleStatistics> provideObservationCollector(
+            StatisticsConfigRepository statisticsConfigRepository,
+            CollectedStatisticsRepository collectedStatisticsRepository,
+            TimestampRepository timestampRepository
+    ) {
+        logger.info("Creating a new instance for the handler '{}'.", "aggregationCollectorHandler");
+        CollectedStatisticsStorage statisticsStorage = CollectedStatisticsStorage.createContext(collectedStatisticsRepository);
+        TimestampStorage timestampStorage = TimestampStorage.createContext(timestampRepository);
+        return new CollectorHandler<Observation>(statisticsStorage, timestampStorage) {
+            @Override protected List<Group> loadGroups() {
+                return statisticsConfigRepository.getAllAvailableGroupInfos(); }
+            @Override protected Function<Observation, Boolean> collectData(DoubleStatistics statistics) {
+                return val -> statistics.accept(val.getSource(), val.getValue()); }
+            @Override protected long getGroupId(Observation data) {
+                return data.getSource().getGroupId(); }
+        };
+    }
+}

+ 52 - 51
src/main/java/cz/senslog/analyzer/analysis/module/ThresholdHandler.java

@@ -1,52 +1,53 @@
-package cz.senslog.analyzer.analysis.module;
-
-import cz.senslog.analyzer.domain.*;
-import cz.senslog.analyzer.core.api.Handler;
-import cz.senslog.analyzer.core.api.HandlerContext;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import java.util.*;
-
-import static java.util.Collections.emptyList;
-
-public abstract class ThresholdHandler<T extends Data<?, ?>> extends Handler<T, T> {
-
-    private static final Logger logger = LogManager.getLogger(ThresholdHandler.class);
-
-    /** Map of thresholds rules order by group_id (Map<group_id, List<ThresholdRule>>). */
-    private Map<Long, List<Threshold.Rule>> thresholdRules;
-
-    protected abstract List<Threshold> loadThresholdValues();
-    protected abstract long getGroupId(T data);
-
-    @Override
-    public void init() {
-        List<Threshold> thresholds = loadThresholdValues();
-        thresholdRules = new HashMap<>(thresholds.size());
-        for (Threshold threshold : thresholds) {
-            thresholdRules.computeIfAbsent(threshold.getGroupId(), k -> new ArrayList<>())
-                    .add(threshold.getRule());
-        }
-    }
-
-    @Override
-    public void handle(HandlerContext<T, T> context) {
-        T data = context.data();
-        long groupId = getGroupId(context.data());
-        List<Threshold.Rule> rules = getThresholdRulesByGroupId(groupId);
-        ValidationResult validateResult = data.validate(rules);
-
-        if (validateResult.isNotValid()) {
-            String message = String.format("Group(%s) failed at %s in %s.",
-                    groupId, data.getTimestamp(), validateResult.getMessages());
-            context.eventBus().send(Alert.create(message));
-        }
-
-        context.next(data);
-    }
-
-    private List<Threshold.Rule> getThresholdRulesByGroupId(long groupId) {
-        return thresholdRules.getOrDefault(groupId, emptyList());
-    }
+package cz.senslog.analyzer.analysis.module;
+
+import cz.senslog.analyzer.domain.*;
+import cz.senslog.analyzer.core.api.Handler;
+import cz.senslog.analyzer.core.api.HandlerContext;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.*;
+
+import static java.util.Collections.emptyList;
+
+public abstract class ThresholdHandler<T extends Data<?, ?>> extends Handler<T, T> {
+
+    private static final Logger logger = LogManager.getLogger(ThresholdHandler.class);
+
+    /** Map of thresholds rules order by group_id (Map<group_id, List<ThresholdRule>>). */
+    private Map<Long, List<Threshold.Rule>> thresholdRules;
+
+    protected abstract List<Threshold> loadThresholdValues();
+    protected abstract long getGroupId(T data);
+
+    @Override
+    public void init() {
+        List<Threshold> thresholds = loadThresholdValues();
+        thresholdRules = new HashMap<>(thresholds.size());
+        for (Threshold threshold : thresholds) {
+            thresholdRules.computeIfAbsent(threshold.getGroupId(), k -> new ArrayList<>())
+                    .add(threshold.getRule());
+        }
+    }
+
+    @Override
+    public void handle(HandlerContext<T, T> context) {
+        T data = context.data();
+        long groupId = getGroupId(context.data());
+        List<Threshold.Rule> rules = getThresholdRulesByGroupId(groupId);
+        ValidationResult validateResult = data.validate(rules);
+
+        if (validateResult.isNotValid()) {
+            context.eventBus().notify(new Alert(
+                    groupId, String.format("group(%d)", groupId), data.getTimestamp(),
+                    validateResult.getMessages().toArray(new String[0])
+            ));
+        }
+
+        context.next(data);
+    }
+
+    private List<Threshold.Rule> getThresholdRulesByGroupId(long groupId) {
+        return thresholdRules.getOrDefault(groupId, emptyList());
+    }
 }

+ 32 - 19
src/main/java/cz/senslog/analyzer/app/Application.java

@@ -2,16 +2,16 @@ package cz.senslog.analyzer.app;
 
 import cz.senslog.analyzer.analysis.Analyzer;
 import cz.senslog.analyzer.analysis.DaggerAnalyzerComponent;
+import cz.senslog.analyzer.core.config.ConfigurationModule;
+import cz.senslog.analyzer.core.config.FileConfigurationManager;
 import cz.senslog.analyzer.domain.Observation;
 import cz.senslog.analyzer.provider.DataProviderComponent;
 import cz.senslog.analyzer.storage.ConnectionModule;
-import cz.senslog.analyzer.storage.StorageConfig;
-import cz.senslog.analyzer.provider.ProviderConfig;
 import cz.senslog.analyzer.provider.DaggerDataProviderComponent;
 import cz.senslog.analyzer.provider.DataProvider;
+import cz.senslog.analyzer.storage.ConnectionModule_Factory;
 import cz.senslog.analyzer.ws.DaggerServerComponent;
 import cz.senslog.analyzer.ws.Server;
-import cz.senslog.analyzer.util.Triple;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -19,6 +19,8 @@ import java.io.IOException;
 import java.lang.management.ManagementFactory;
 import java.lang.management.RuntimeMXBean;
 
+import static cz.senslog.analyzer.core.config.ConfigurationType.LOCAL_FILE;
+
 /**
  * The class {@code Application} represents a trigger for entire application.
  *
@@ -74,41 +76,52 @@ public class Application extends Thread {
     public void run() {
 
         String configFile = params.getConfigFileName();
-        Triple<StorageConfig, ProviderConfig, Integer> configs = null;
+        FileConfigurationManager configManager = null;
         try {
-            configs = Configuration.load(configFile);
+            configManager = FileConfigurationManager.load(configFile);
         } catch (IOException e) {
             logger.error(e.getMessage());
             System.exit(1);
         }
 
-        StorageConfig storageConfig = configs.getItem1();
-        ProviderConfig config = configs.getItem2();
-        int port = configs.getItem3();
-
+        ConfigurationModule configurationModule = null;
+        try {
+            configurationModule = ConfigurationModule.create(LOCAL_FILE, configFile);
+        } catch (IOException e) {
+            logger.error(e.getMessage());
+            System.exit(1);
+        }
 
-        ConnectionModule connectionModule = ConnectionModule.create(storageConfig);
+        ConnectionModule connectionModule = ConnectionModule_Factory.newInstance(configManager.getStorage());
         logger.info("Module '{}' was created successfully.", connectionModule.getClass().getSimpleName());
 
         Analyzer<Observation> analyzer = DaggerAnalyzerComponent.builder()
                 .connectionModule(connectionModule)
-                .build().createNewObservationAnalyzer();
+                .configurationModule(configurationModule)
+                .build().createObservationAnalyzer();
         logger.info("Component '{}' was created successfully.", analyzer.getClass().getSimpleName());
 
 
         DataProviderComponent dataProviderComponent = DaggerDataProviderComponent.builder()
-                .connectionModule(connectionModule).build();
+                .connectionModule(connectionModule)
+                .build();
+
+        DataProvider<?, ?> scheduledDataProvider = dataProviderComponent.scheduledDatabaseProvider()
+                .config(configManager.getScheduler()).deployAnalyzer(analyzer);
+        logger.info("Component '{}' was created successfully.", scheduledDataProvider.getClass().getSimpleName());
 
-        DataProvider<Observation> dataProvider = dataProviderComponent.scheduledDatabaseProvider()
-                .config(config).deployAnalyzer(analyzer);
-        logger.info("Component '{}' was created successfully.", dataProvider.getClass().getSimpleName());
+        DataProvider<?, ?> loopedDataProvider = dataProviderComponent.loopedDatabaseProvider()
+                .config(configManager.getTaskAnalytics()).deployAnalyzer(analyzer);
 
         Server server = DaggerServerComponent.builder()
-                .connectionModule(connectionModule).build()
-                .createServer();
+                .connectionModule(connectionModule)
+                .build().createServer();
         logger.info("Component '{}' was created successfully.", server.getClass().getSimpleName());
 
-        server.start(port);
-        dataProvider.start();
+        server.start(configManager.getServer().getPort());
+
+        scheduledDataProvider.start();
+        loopedDataProvider.start();
+
     }
 }

+ 0 - 112
src/main/java/cz/senslog/analyzer/app/Configuration.java

@@ -1,112 +0,0 @@
-package cz.senslog.analyzer.app;
-
-import cz.senslog.analyzer.storage.StorageConfig;
-import cz.senslog.analyzer.storage.inmemory.InMemoryStorageConfig;
-import cz.senslog.analyzer.storage.permanent.PermanentStorageConfig;
-import cz.senslog.analyzer.provider.ProviderConfig;
-import cz.senslog.analyzer.util.Triple;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.yaml.snakeyaml.Yaml;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.time.OffsetDateTime;
-import java.util.Map;
-
-public class Configuration {
-    private static final Logger logger = LogManager.getLogger(Configuration.class);
-
-    public static Triple<StorageConfig, ProviderConfig, Integer> load(String fileName) throws IOException {
-
-        logger.info("Loading '{}' configuration file.", fileName);
-
-        if (!fileName.toLowerCase().endsWith(".yaml")) {
-            throw new IOException(fileName + "does not contain .yaml extension.");
-        }
-
-        Path filePath = Paths.get(fileName);
-        if (Files.notExists(filePath)) {
-            throw new FileNotFoundException(fileName + " does not exist");
-        }
-
-        Map<Object, Object> properties;
-
-        logger.debug("Opening the file '{}'.", fileName);
-        try (InputStream fileStream = Files.newInputStream(filePath)) {
-            logger.debug("Parsing the yaml file '{}'.", fileName);
-            properties = new Yaml().load(fileStream);
-            logger.debug("The configuration yaml file '{}' was parsed successfully.", fileName);
-        }
-
-        if (properties == null || properties.isEmpty()) {
-            throw new IOException(String.format(
-                    "The configuration yaml file %s is empty or was not loaded successfully. ", fileName
-            ));
-        }
-
-        Object permanentStMap = properties.get("permanentStorage");
-        if (!(permanentStMap instanceof Map)) {
-            throw new IOException(String.format(
-                    "Configuration file '%s' contains an error at 'permanentStorage' attribute.", fileName
-            ));
-        }
-
-        Object inMemoryStMap = properties.get("inMemoryStorage");
-        if (!(inMemoryStMap instanceof Map)) {
-            throw new IOException(String.format(
-                    "Configuration file '%s' contains an error at 'inMemoryStorage' attribute.", fileName
-            ));
-        }
-
-        Object schedulerMap = properties.get("scheduler");
-        if (!(schedulerMap instanceof Map)) {
-            throw new IOException(String.format(
-                    "Configuration file '%s' contains an error at 'scheduler' attribute.", fileName
-            ));
-        }
-
-        Object serverMap = properties.get("server");
-        if (!(serverMap instanceof Map)) {
-            throw new IOException(String.format(
-                    "Configuration file '%s' contains an error at 'server' attribute.", fileName
-            ));
-        }
-
-        Map<String, Object> permanentStConfigMap = (Map<String, Object>)permanentStMap;
-        PermanentStorageConfig permanentStConfig = new PermanentStorageConfig(
-                (String)permanentStConfigMap.get("url"),
-                (String)permanentStConfigMap.get("username"),
-                (String)permanentStConfigMap.get("password"),
-                (Integer) permanentStConfigMap.get("connectionPoolSize")
-        );
-
-        Map<String, Object> inMemoryStConfigMap = (Map<String, Object>)inMemoryStMap;
-        InMemoryStorageConfig inMemoryStConfig = new InMemoryStorageConfig(
-                (String)inMemoryStConfigMap.get("path"),
-                (Boolean)inMemoryStConfigMap.get("persistence"),
-                (String)inMemoryStConfigMap.get("parameters")
-        );
-
-        Map<String, Object> schedulerConfigMap = (Map<String, Object>)schedulerMap;
-        String initDateString = (String) schedulerConfigMap.get("initDate");
-        OffsetDateTime initDate = initDateString != null ? OffsetDateTime.parse(initDateString) : OffsetDateTime.now();
-        ProviderConfig providerConfig = ProviderConfig.config()
-                .startDateTime(initDate)
-                .period((Integer)schedulerConfigMap.get("period"))
-                .get();
-
-
-        Map<String, Object> serverConfigMap = (Map<String, Object>)serverMap;
-        Integer port = (Integer)serverConfigMap.get("port");
-
-        StorageConfig storageConfig = new StorageConfig(permanentStConfig, inMemoryStConfig);
-
-        logger.info("Configuration file '{}' was parsed successfully.", fileName);
-        return Triple.of(storageConfig, providerConfig, port);
-    }
-}

+ 10 - 10
src/main/java/cz/senslog/analyzer/app/Main.java

@@ -1,10 +1,10 @@
-package cz.senslog.analyzer.app;
-
-import java.io.IOException;
-
-public class Main {
-
-    public static void main(String[] args) throws IOException {
-        Application.init(args).start();
-    }
-}
+package cz.senslog.analyzer.app;
+
+import java.io.IOException;
+
+public class Main {
+
+    public static void main(String[] args) throws Exception {
+        Application.init(args).start();
+    }
+}

+ 13 - 0
src/main/java/cz/senslog/analyzer/broker/AbstractBrokerConfig.java

@@ -0,0 +1,13 @@
+package cz.senslog.analyzer.broker;
+
+public abstract class AbstractBrokerConfig {
+    private final BrokerType type;
+
+    protected AbstractBrokerConfig(BrokerType type) {
+        this.type = type;
+    }
+
+    public BrokerType getType() {
+        return type;
+    }
+}

+ 39 - 0
src/main/java/cz/senslog/analyzer/broker/AlertFormatter.java

@@ -0,0 +1,39 @@
+package cz.senslog.analyzer.broker;
+
+import cz.senslog.analyzer.domain.Alert;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+
+public final class AlertFormatter {
+
+    private static final Map<String, Function<Alert, String>> MAP_PROPERTIES;
+
+    static {
+        MAP_PROPERTIES = new HashMap<>();
+        MAP_PROPERTIES.put("$group_id", a -> String.valueOf(a.getGroupId()));
+        MAP_PROPERTIES.put("$group_name", Alert::getGroupName);
+        MAP_PROPERTIES.put("$timestamp", a -> a.getTimestamp().format());
+        MAP_PROPERTIES.put("$messages", a -> Arrays.toString(a.getMessages()));
+    }
+
+    public static Map<String, String> formatToProperties(Alert alert) {
+        Map<String, String> result = new HashMap<>(MAP_PROPERTIES.size());
+        for (Map.Entry<String, Function<Alert, String>> varEntry : MAP_PROPERTIES.entrySet()) {
+            result.put(varEntry.getKey(), varEntry.getValue().apply(alert));
+        }
+        return result;
+    }
+
+    public static String format(Alert alert, String pattern) {
+        String msg = pattern;
+        for (Map.Entry<String, Function<Alert, String>> varEntry : MAP_PROPERTIES.entrySet()) {
+            if (msg.contains(varEntry.getKey())) {
+                msg = msg.replace(varEntry.getKey(), varEntry.getValue().apply(alert));
+            }
+        }
+        return msg;
+    }
+}

+ 5 - 0
src/main/java/cz/senslog/analyzer/broker/BrokerType.java

@@ -0,0 +1,5 @@
+package cz.senslog.analyzer.broker;
+
+public enum BrokerType {
+    DATABASE, EMAIL
+}

+ 28 - 0
src/main/java/cz/senslog/analyzer/broker/database/DatabaseBroker.java

@@ -0,0 +1,28 @@
+package cz.senslog.analyzer.broker.database;
+
+import cz.senslog.analyzer.broker.AlertFormatter;
+import cz.senslog.analyzer.core.AbstractEventBroker;
+import cz.senslog.analyzer.domain.Alert;
+import cz.senslog.analyzer.storage.permanent.repository.SensLogRepository;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+public class DatabaseBroker extends AbstractEventBroker<Alert> {
+
+    private final SensLogRepository repository;
+    private final DatabaseBrokerConfig config;
+
+    public DatabaseBroker(SensLogRepository repository, DatabaseBrokerConfig config) {
+        this.repository = repository;
+        this.config = config;
+    }
+
+    @Override
+    protected void process(Alert value) {
+        repository.saveAlert(AlertFormatter.format(value, config.getPattern()));
+    }
+}

+ 18 - 0
src/main/java/cz/senslog/analyzer/broker/database/DatabaseBrokerConfig.java

@@ -0,0 +1,18 @@
+package cz.senslog.analyzer.broker.database;
+
+import cz.senslog.analyzer.broker.AbstractBrokerConfig;
+import cz.senslog.analyzer.broker.BrokerType;
+
+public class DatabaseBrokerConfig extends AbstractBrokerConfig {
+
+    private final String pattern;
+
+    public DatabaseBrokerConfig(String pattern) {
+        super(BrokerType.DATABASE);
+        this.pattern = pattern;
+    }
+
+    public String getPattern() {
+        return pattern;
+    }
+}

+ 39 - 0
src/main/java/cz/senslog/analyzer/broker/email/EmailBroker.java

@@ -0,0 +1,39 @@
+package cz.senslog.analyzer.broker.email;
+
+import cz.senslog.analyzer.broker.AlertFormatter;
+import cz.senslog.analyzer.core.AbstractEventBroker;
+import cz.senslog.analyzer.domain.Alert;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import javax.mail.MessagingException;
+
+public class EmailBroker extends AbstractEventBroker<Alert> {
+
+    private static final Logger logger = LogManager.getLogger(EmailBroker.class);
+
+    private final EmailServerConnection connection;
+
+    private final EmailMessageConfig messageConfig;
+
+    public EmailBroker(EmailServerConfig serverConfig, EmailMessageConfig messageConfig) {
+        if (!serverConfig.getName().equalsIgnoreCase(messageConfig.getServerName())) {
+            throw new RuntimeException(String.format("Message broker configuration uses the wrong email server. It has '%s' but expected '%s'.",
+                   serverConfig.getName(), messageConfig.getServerName()));
+        }
+        this.connection = new EmailServerConnection(serverConfig);
+        this.messageConfig = messageConfig;
+    }
+
+    @Override
+    protected void process(Alert alert) {
+
+        String message = AlertFormatter.format(alert, "'$group_name' failed at $timestamp in $messages.");
+
+        try {
+            connection.send(message, AlertFormatter.formatToProperties(alert), messageConfig);
+        } catch (MessagingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}

+ 38 - 0
src/main/java/cz/senslog/analyzer/broker/email/EmailMessageConfig.java

@@ -0,0 +1,38 @@
+package cz.senslog.analyzer.broker.email;
+
+import cz.senslog.analyzer.broker.AbstractBrokerConfig;
+import cz.senslog.analyzer.broker.BrokerType;
+
+import java.util.Set;
+
+public class EmailMessageConfig extends AbstractBrokerConfig {
+
+    private final String serverName;
+    private final String senderEmail;
+    private final Set<String> recipientEmails;
+    private final String subject;
+
+    public EmailMessageConfig(String serverName, String senderEmail, Set<String> recipientEmails, String subject) {
+        super(BrokerType.EMAIL);
+        this.serverName = serverName;
+        this.senderEmail = senderEmail;
+        this.recipientEmails = recipientEmails;
+        this.subject = subject;
+    }
+
+    public String getServerName() {
+        return serverName;
+    }
+
+    public String getSenderEmail() {
+        return senderEmail;
+    }
+
+    public Set<String> getRecipientEmails() {
+        return recipientEmails;
+    }
+
+    public String getSubject() {
+        return subject;
+    }
+}

+ 38 - 0
src/main/java/cz/senslog/analyzer/broker/email/EmailServerConfig.java

@@ -0,0 +1,38 @@
+package cz.senslog.analyzer.broker.email;
+
+public class EmailServerConfig {
+
+    private final String name;
+    private final String smtpHost;
+    private final int smtpPort;
+    private final String username;
+    private final String password;
+
+    public EmailServerConfig(String name, String smtpHost, int smtpPort, String username, String password) {
+        this.name = name;
+        this.smtpHost = smtpHost;
+        this.smtpPort = smtpPort;
+        this.username = username;
+        this.password = password;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getSmtpHost() {
+        return smtpHost;
+    }
+
+    public int getSmtpPort() {
+        return smtpPort;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+}

+ 61 - 0
src/main/java/cz/senslog/analyzer/broker/email/EmailServerConnection.java

@@ -0,0 +1,61 @@
+package cz.senslog.analyzer.broker.email;
+
+import javax.mail.*;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+import java.util.Map;
+import java.util.Properties;
+
+import static javax.mail.Message.RecipientType.TO;
+
+public class EmailServerConnection {
+
+    private final EmailServerConfig config;
+
+    public EmailServerConnection(EmailServerConfig config) {
+        this.config = config;
+    }
+
+    private Session openSession(EmailServerConfig config) {
+        Properties props = new Properties();
+        props.put("mail.smtp.host", config.getSmtpHost());
+        props.put("mail.smtp.port", config.getSmtpPort());
+        props.put("mail.smtp.auth", "true");
+        props.put("mail.smtp.starttls.enable", "true");
+        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
+
+        Authenticator auth = new Authenticator() {
+            protected PasswordAuthentication getPasswordAuthentication() {
+                return new PasswordAuthentication(config.getUsername(), config.getPassword());
+            }
+        };
+        return Session.getInstance(props, auth);
+    }
+
+    public void send(String content, Map<String, String> subjectVariables, EmailMessageConfig messageConfig) throws MessagingException {
+        Session session = openSession(config);
+        Message message = new MimeMessage(session);
+        message.setFrom(new InternetAddress(messageConfig.getSenderEmail()));
+        String recipients = String.join(",",messageConfig.getRecipientEmails());
+        message.setRecipients(TO, InternetAddress.parse(recipients));
+
+        String subjectPattern = messageConfig.getSubject();
+        for (Map.Entry<String, String> varEntry : subjectVariables.entrySet()) {
+            if (subjectPattern.contains(varEntry.getKey())) {
+                subjectPattern = subjectPattern.replace(varEntry.getKey(), varEntry.getValue());
+            }
+        }
+        message.setSubject(subjectPattern);
+
+        MimeBodyPart mimeBodyPart = new MimeBodyPart();
+        mimeBodyPart.setContent(content, "text/html;charset=UTF-8");
+
+        Multipart multipart = new MimeMultipart();
+        multipart.addBodyPart(mimeBodyPart);
+        message.setContent(multipart);
+
+        Transport.send(message);
+    }
+}

+ 19 - 0
src/main/java/cz/senslog/analyzer/broker/statistic/StatisticBroker.java

@@ -0,0 +1,19 @@
+package cz.senslog.analyzer.broker.statistic;
+
+import cz.senslog.analyzer.core.AbstractEventBroker;
+import cz.senslog.analyzer.domain.DoubleStatistics;
+import cz.senslog.analyzer.storage.permanent.repository.StatisticsRepository;
+
+public class StatisticBroker extends AbstractEventBroker<DoubleStatistics> {
+
+    private final StatisticsRepository repository;
+
+    public StatisticBroker(StatisticsRepository repository) {
+        this.repository = repository;
+    }
+
+    @Override
+    protected void process(DoubleStatistics value) {
+        repository.save(value);
+    }
+}

+ 40 - 0
src/main/java/cz/senslog/analyzer/core/AbstractEventBroker.java

@@ -0,0 +1,40 @@
+package cz.senslog.analyzer.core;
+
+import java.util.Collection;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingDeque;
+
+public abstract class AbstractEventBroker<T> {
+
+    private final BlockingQueue<T> queue;
+
+    protected AbstractEventBroker() {
+        this.queue = new LinkedBlockingDeque<>();
+        new Thread(this::take).start();
+    }
+
+    protected abstract void process(T value);
+
+    private void take() {
+        while(true) {
+            try {
+                process(queue.take());
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    public void put(T value) {
+        try {
+            queue.put(value);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public void put(Collection<T> values) {
+        values.forEach(this::put);
+    }
+
+}

+ 15 - 15
src/main/java/cz/senslog/analyzer/core/EventBus.java

@@ -1,15 +1,15 @@
-package cz.senslog.analyzer.core;
-
-import cz.senslog.analyzer.domain.Alert;
-import cz.senslog.analyzer.domain.DoubleStatistics;
-
-import java.util.List;
-
-public interface EventBus {
-
-    void send(Alert alert);
-
-    void save(DoubleStatistics statistics);
-
-    void save(List<DoubleStatistics> statistics);
-}
+package cz.senslog.analyzer.core;
+
+import cz.senslog.analyzer.domain.Alert;
+import cz.senslog.analyzer.domain.DoubleStatistics;
+
+import java.util.List;
+
+public interface EventBus {
+
+    void notify(Alert alert);
+
+    void save(DoubleStatistics statistics);
+
+    void save(List<DoubleStatistics> statistics);
+}

+ 78 - 42
src/main/java/cz/senslog/analyzer/core/EventBusModule.java

@@ -1,42 +1,78 @@
-package cz.senslog.analyzer.core;
-
-import cz.senslog.analyzer.domain.Alert;
-import cz.senslog.analyzer.domain.DoubleStatistics;
-import cz.senslog.analyzer.storage.RepositoryModule;
-import cz.senslog.analyzer.storage.permanent.repository.SensLogRepository;
-import cz.senslog.analyzer.storage.permanent.repository.StatisticsRepository;
-import dagger.Module;
-import dagger.Provides;
-
-import javax.inject.Singleton;
-import java.util.List;
-
-@Module(includes = RepositoryModule.class)
-public class EventBusModule {
-
-    @Provides @Singleton
-    public EventBus provideEventBus(
-            StatisticsRepository statisticsRepository,
-            SensLogRepository senslogRepository
-    ) {
-        return new EventBus() {
-
-            // TODO asynchronous loop queue for all events
-
-            @Override
-            public void send(Alert alert) {
-                senslogRepository.saveAlert(alert);
-            }
-
-            @Override
-            public void save(DoubleStatistics statistics) {
-                statisticsRepository.save(statistics);
-            }
-
-            @Override
-            public void save(List<DoubleStatistics> statistics) {
-                statisticsRepository.save(statistics);
-            }
-        };
-    }
-}
+package cz.senslog.analyzer.core;
+
+import cz.senslog.analyzer.broker.AbstractBrokerConfig;
+import cz.senslog.analyzer.broker.database.DatabaseBroker;
+import cz.senslog.analyzer.broker.database.DatabaseBrokerConfig;
+import cz.senslog.analyzer.broker.email.EmailBroker;
+import cz.senslog.analyzer.broker.email.EmailMessageConfig;
+import cz.senslog.analyzer.broker.email.EmailServerConfig;
+import cz.senslog.analyzer.broker.email.EmailServerConnection;
+import cz.senslog.analyzer.broker.statistic.StatisticBroker;
+import cz.senslog.analyzer.core.config.ConfigurationModule;
+import cz.senslog.analyzer.core.config.domain.EventBusConfig;
+import cz.senslog.analyzer.domain.Alert;
+import cz.senslog.analyzer.domain.DoubleStatistics;
+import cz.senslog.analyzer.storage.RepositoryModule;
+import cz.senslog.analyzer.storage.permanent.repository.SensLogRepository;
+import cz.senslog.analyzer.storage.permanent.repository.StatisticsRepository;
+import dagger.Module;
+import dagger.Provides;
+
+import javax.inject.Singleton;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Module(includes = {
+        RepositoryModule.class,
+        ConfigurationModule.class
+})
+public class EventBusModule {
+
+    @Provides @Singleton
+    public EventBus provideEventBus(
+            EventBusConfig eventBusConfig,
+            StatisticsRepository statisticsRepository,
+            SensLogRepository senslogRepository
+    ) {
+
+        List<AbstractEventBroker<Alert>> notifyBrokers = new ArrayList<>(eventBusConfig.getNotifyBrokers().size());
+        for (AbstractBrokerConfig brokerConfig : eventBusConfig.getNotifyBrokers()) {
+            switch (brokerConfig.getType()) {
+                case EMAIL: {
+                    if (brokerConfig instanceof EmailMessageConfig) {
+                        EmailMessageConfig msgConfig = (EmailMessageConfig)brokerConfig;
+                        EmailServerConfig serverConfig = eventBusConfig.getEmailServer(msgConfig.getServerName());
+                        notifyBrokers.add(new EmailBroker(serverConfig, msgConfig));
+                    }
+                } break;
+                case DATABASE: {
+                    if (brokerConfig instanceof DatabaseBrokerConfig) {
+                        notifyBrokers.add(new DatabaseBroker(senslogRepository, (DatabaseBrokerConfig) brokerConfig));
+                    }
+                } break;
+            }
+        }
+
+        StatisticBroker statisticBroker = new StatisticBroker(statisticsRepository);
+
+
+        return new EventBus() {
+
+            @Override
+            public void notify(Alert alert) {
+                // TODO filter for message brokers
+                notifyBrokers.forEach(b -> b.put(alert));
+            }
+
+            @Override
+            public void save(DoubleStatistics statistics) {
+                statisticBroker.put(statistics);
+            }
+
+            @Override
+            public void save(List<DoubleStatistics> statistics) {
+                statisticBroker.put(statistics);
+            }
+        };
+    }
+}

+ 12 - 0
src/main/java/cz/senslog/analyzer/core/config/Attribute.java

@@ -0,0 +1,12 @@
+package cz.senslog.analyzer.core.config;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Documented
+@Retention(RUNTIME)
+public @interface Attribute {
+    String value() default "";
+}

+ 10 - 0
src/main/java/cz/senslog/analyzer/core/config/ConfigurationManager.java

@@ -0,0 +1,10 @@
+package cz.senslog.analyzer.core.config;
+
+import cz.senslog.analyzer.core.config.domain.EventBusConfig;
+import cz.senslog.analyzer.core.config.domain.StorageConfig;
+
+public interface ConfigurationManager {
+
+    EventBusConfig eventBusConfig();
+    StorageConfig storageConfig();
+}

+ 36 - 0
src/main/java/cz/senslog/analyzer/core/config/ConfigurationModule.java

@@ -0,0 +1,36 @@
+package cz.senslog.analyzer.core.config;
+
+import cz.senslog.analyzer.core.config.domain.EventBusConfig;
+import cz.senslog.analyzer.core.config.domain.StorageConfig;
+import dagger.Module;
+import dagger.Provides;
+
+import javax.inject.Singleton;
+import java.io.IOException;
+
+@Module
+public class ConfigurationModule {
+
+    private final ConfigurationManager configManager;
+
+    public static ConfigurationModule create(ConfigurationType type, String... params) throws IOException {
+        switch (type) {
+            case LOCAL_FILE: return new ConfigurationModule(FileConfigurationManager.load(params));
+            default: throw new IOException("Configuration type '" + type + "' is not implemented.");
+        }
+    }
+
+    private ConfigurationModule(FileConfigurationManager configManager) {
+        this.configManager = configManager;
+    }
+
+    @Provides @Singleton
+    public EventBusConfig eventBusConfig() {
+        return configManager.eventBusConfig();
+    }
+
+    @Provides @Singleton
+    public StorageConfig storageConfig() {
+        return configManager.storageConfig();
+    }
+}

+ 5 - 0
src/main/java/cz/senslog/analyzer/core/config/ConfigurationType.java

@@ -0,0 +1,5 @@
+package cz.senslog.analyzer.core.config;
+
+public enum ConfigurationType {
+    DATABASE, LOCAL_FILE
+}

+ 141 - 0
src/main/java/cz/senslog/analyzer/core/config/FileConfigurationManager.java

@@ -0,0 +1,141 @@
+package cz.senslog.analyzer.core.config;
+
+import cz.senslog.analyzer.broker.AbstractBrokerConfig;
+import cz.senslog.analyzer.core.config.domain.*;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
+
+public class FileConfigurationManager implements ConfigurationManager {
+
+    private static final Logger logger = LogManager.getLogger(FileConfigurationManager.class);
+
+    public static class EventBusFileConfig extends AbstractConfig {
+        private Set<String> notifyBrokers;
+        public Set<String> getNotifyBrokers() {
+            return notifyBrokers;
+        }
+
+        @Override
+        public void parseConfig(PropertyConfig config) {
+            this.notifyBrokers = new HashSet<>(config.getArrayPropertyOf("notifyBrokers", String.class));
+        }
+    }
+
+    @Attribute("server")
+    private ServerConfig server;
+
+    @Attribute("eventBus")
+    private EventBusFileConfig eventBus;
+
+    @Attribute("emailServers")
+    private EmailServers emailServers;
+
+    @Attribute("messageBrokers")
+    private MessageBrokers messageBrokers;
+
+    @Attribute("storage")
+    private StorageConfig storage;
+
+    @Attribute("scheduler")
+    private SchedulerConfig scheduler;
+
+    @Attribute("manualAnalytics")
+    private TaskAnalytics taskAnalytics;
+
+    public ServerConfig getServer() {
+        return server;
+    }
+
+
+    public StorageConfig getStorage() {
+        return storage;
+    }
+
+    public SchedulerConfig getScheduler() {
+        return scheduler;
+    }
+
+    public TaskAnalytics getTaskAnalytics() {
+        return taskAnalytics;
+    }
+
+    public static FileConfigurationManager load(String... params) throws IOException {
+        if (params == null || params.length < 1) {
+            throw new IOException("The name of input configuration file is missing.");
+        }
+
+        String fileName = params[0];
+        logger.info("Loading '{}' configuration file.", fileName);
+
+        if (!fileName.toLowerCase().endsWith(".yaml")) {
+            throw new IOException(fileName + "does not contain .yaml extension.");
+        }
+
+        Path filePath = Paths.get(fileName);
+        if (Files.notExists(filePath)) {
+            throw new FileNotFoundException(fileName + " does not exist");
+        }
+
+        Map<Object, Object> properties;
+
+        logger.debug("Opening the file '{}'.", fileName);
+        try (InputStream fileStream = Files.newInputStream(filePath)) {
+            logger.debug("Parsing the yaml file '{}'.", fileName);
+            properties = new Yaml().load(fileStream);
+            logger.debug("The configuration yaml file '{}' was parsed successfully.", fileName);
+        }
+
+        if (properties == null || properties.isEmpty()) {
+            throw new IOException(String.format(
+                    "The configuration yaml file %s is empty or was not loaded successfully. ", fileName
+            ));
+        }
+
+        FileConfigurationManager fileConfigurationManager = new FileConfigurationManager();
+        for (Field attrField : fileConfigurationManager.getClass().getDeclaredFields()) {
+            Attribute attrAnn = attrField.getAnnotation(Attribute.class);
+            if (attrAnn == null) { continue; }
+            String attributeName = attrAnn.value();
+
+            Class<?> attrClass = attrField.getType();
+            if (!attrClass.getSuperclass().isAssignableFrom(AbstractConfig.class)) { continue; }
+
+            try {
+                AbstractConfig attrInstance = (AbstractConfig) attrClass.getConstructor().newInstance();
+                attrInstance.parseConfig(PropertyConfig.init(properties, attributeName));
+                attrField.set(fileConfigurationManager, attrInstance);
+            } catch (NoSuchMethodException | InvocationTargetException | InstantiationException |
+                     IllegalAccessException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        logger.info("Configuration file '{}' was parsed successfully.", fileName);
+        return fileConfigurationManager;
+    }
+
+    @Override
+    public EventBusConfig eventBusConfig() {
+        Map<String, AbstractBrokerConfig> notifyBrokers = new HashMap<>(eventBus.notifyBrokers.size());
+        for (String brokerName : eventBus.notifyBrokers) {
+            notifyBrokers.put(brokerName, messageBrokers.getMessageBroker(brokerName));
+        }
+        return new EventBusConfig(notifyBrokers, emailServers.getServers());
+    }
+
+    @Override
+    public StorageConfig storageConfig() {
+        return this.storage;
+    }
+}

+ 32 - 0
src/main/java/cz/senslog/analyzer/core/config/TaskAnalytics.java

@@ -0,0 +1,32 @@
+package cz.senslog.analyzer.core.config;
+
+import cz.senslog.analyzer.analysis.TaskConfig;
+import cz.senslog.analyzer.core.config.domain.AbstractConfig;
+import cz.senslog.analyzer.core.config.domain.PropertyConfig;
+
+import java.util.*;
+
+public class TaskAnalytics extends AbstractConfig {
+
+    private final Map<String, TaskConfig> tasks = new HashMap<>();
+
+    @Override
+    public void parseConfig(PropertyConfig config) {
+        for (String taskName : config.getAttributes()) {
+            PropertyConfig taskProperty = config.getPropertyConfig(taskName);
+            tasks.put(taskName, new TaskConfig(taskName,
+                    new HashSet<>(taskProperty.getArrayPropertyOf("groupIds", Long.class)),
+                    taskProperty.getOffDateTimeProperty("from"),
+                    taskProperty.getOffDateTimeProperty("to")
+            ));
+        }
+    }
+
+    public Collection<TaskConfig> getTasks() {
+        return tasks.values();
+    }
+
+    public TaskConfig getTaskConfig(String taskName) {
+        return tasks.getOrDefault(taskName, null);
+    }
+}

+ 6 - 0
src/main/java/cz/senslog/analyzer/core/config/domain/AbstractConfig.java

@@ -0,0 +1,6 @@
+package cz.senslog.analyzer.core.config.domain;
+
+public abstract class AbstractConfig {
+
+    public abstract void parseConfig(PropertyConfig config);
+}

+ 42 - 0
src/main/java/cz/senslog/analyzer/core/config/domain/EmailServers.java

@@ -0,0 +1,42 @@
+package cz.senslog.analyzer.core.config.domain;
+
+import cz.senslog.analyzer.broker.email.EmailServerConfig;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class EmailServers extends AbstractConfig {
+
+    private final Map<String, EmailServerConfig> servers = new HashMap<>();
+
+    @Override
+    public void parseConfig(PropertyConfig config) {
+        for (String serverName : config.getAttributes()) {
+            PropertyConfig serverConfig = config.getPropertyConfig(serverName);
+            servers.put(serverName, new EmailServerConfig(serverName,
+                    serverConfig.getStringProperty("smtpHost"),
+                    serverConfig.getIntegerProperty("smtpPort"),
+                    serverConfig.getStringProperty("authUsername"),
+                    serverConfig.getStringProperty("authPassword")
+            ));
+        }
+    }
+
+    public Map<String, EmailServerConfig> getServers() {
+        return servers;
+    }
+
+    public Set<String> getEmailServerNames() {
+        return servers.keySet();
+    }
+
+    public Collection<EmailServerConfig> getEmailServerConfigs() {
+        return servers.values();
+    }
+
+    public EmailServerConfig getEmailServerConfig(String serverName) {
+        return servers.getOrDefault(serverName, null);
+    }
+}

+ 36 - 0
src/main/java/cz/senslog/analyzer/core/config/domain/EventBusConfig.java

@@ -0,0 +1,36 @@
+package cz.senslog.analyzer.core.config.domain;
+
+import cz.senslog.analyzer.broker.AbstractBrokerConfig;
+import cz.senslog.analyzer.broker.email.EmailServerConfig;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+public class EventBusConfig {
+
+    private final Map<String, AbstractBrokerConfig> notifyBrokers;
+
+    private final Map<String, EmailServerConfig> emailServers;
+
+    public EventBusConfig(Map<String, AbstractBrokerConfig> notifyBrokers, Map<String, EmailServerConfig> emailServers) {
+        this.notifyBrokers = notifyBrokers;
+        this.emailServers = emailServers;
+    }
+
+    public Collection<AbstractBrokerConfig> getNotifyBrokers() {
+        return notifyBrokers.values();
+    }
+
+    public AbstractBrokerConfig getNotifyBroker(String name) {
+        return notifyBrokers.getOrDefault(name, null);
+    }
+
+    public Collection<EmailServerConfig> getEmailServers() {
+        return emailServers.values();
+    }
+
+    public EmailServerConfig getEmailServer(String name) {
+        return emailServers.getOrDefault(name, null);
+    }
+}

+ 10 - 0
src/main/java/cz/senslog/analyzer/core/config/domain/MessageBrokerConfig.java

@@ -0,0 +1,10 @@
+package cz.senslog.analyzer.core.config.domain;
+
+public class MessageBrokerConfig extends AbstractConfig {
+
+
+    @Override
+    public void parseConfig(PropertyConfig config) {
+
+    }
+}

+ 39 - 0
src/main/java/cz/senslog/analyzer/core/config/domain/MessageBrokers.java

@@ -0,0 +1,39 @@
+package cz.senslog.analyzer.core.config.domain;
+
+import cz.senslog.analyzer.broker.AbstractBrokerConfig;
+import cz.senslog.analyzer.broker.BrokerType;
+import cz.senslog.analyzer.broker.database.DatabaseBrokerConfig;
+import cz.senslog.analyzer.broker.email.EmailMessageConfig;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+public class MessageBrokers extends AbstractConfig {
+
+    private final Map<String, AbstractBrokerConfig> brokers = new HashMap<>();
+
+    @Override
+    public void parseConfig(PropertyConfig config) {
+        for (String brokerName : config.getAttributes()) {
+            PropertyConfig brokerProperty = config.getPropertyConfig(brokerName);
+            BrokerType type = BrokerType.valueOf(brokerProperty.getStringProperty("type"));
+            PropertyConfig cnf = brokerProperty.getPropertyConfig("config");
+            switch (type) {
+                case EMAIL: brokers.put(brokerName, new EmailMessageConfig(
+                        cnf.getStringProperty("server"),
+                        cnf.getStringProperty("senderEmail"),
+                        new HashSet<>(cnf.getArrayPropertyOf("recipientEmail", String.class)),
+                        cnf.getStringProperty("subject")
+                )); break;
+                case DATABASE: brokers.put(brokerName, new DatabaseBrokerConfig(
+                        cnf.getStringProperty("msgPattern")
+                )); break;
+            }
+        }
+    }
+
+    public AbstractBrokerConfig getMessageBroker(String msgBrokerName) {
+        return brokers.getOrDefault(msgBrokerName, null);
+    }
+}

+ 287 - 0
src/main/java/cz/senslog/analyzer/core/config/domain/PropertyConfig.java

@@ -0,0 +1,287 @@
+// Copyright (c) 2020 UWB & LESP.
+// The UWB & LESP license this file to you under the MIT license.
+
+package cz.senslog.analyzer.core.config.domain;
+
+import java.io.IOException;
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.util.*;
+
+import static java.lang.String.format;
+import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME;
+import static java.util.Optional.empty;
+import static java.util.Optional.of;
+
+/**
+ *
+ * @author Lukas Cerny
+ * @version 1.0
+ * @since 1.0
+ */
+public class PropertyConfig {
+
+    /** Path delimiter separates nodes. */
+    private static final String PATH_DELIMITER = ".";
+
+    /** Identifier of path. */
+    private final String id;
+
+    private final String fullId;
+
+    /** Map of properties. */
+    private final Map<String, Object> properties;
+
+    public static PropertyConfig init(Map<Object, Object> properties, String propertyName) throws IOException {
+        Object generalConfig = properties.get(propertyName);
+        if (generalConfig == null) {
+            return new PropertyConfig(propertyName, propertyName);
+        }
+        if (!(generalConfig instanceof Map)) {
+            throw new IOException(propertyName);
+        }
+
+        Map<?, ?> generalConfigMap = (Map<?, ?>) generalConfig;
+        PropertyConfig propertyConfig = new PropertyConfig(propertyName, propertyName);
+
+        for (Map.Entry<?, ?> entry : generalConfigMap.entrySet()) {
+            String keyName = entry.getKey().toString();
+            propertyConfig.setProperty(keyName, entry.getValue());
+        }
+        return propertyConfig;
+    }
+
+    /**
+     * Constructor sets new identifier of node.
+     * @param id - identifier of node.
+     */
+    protected PropertyConfig(String id, String fullId) {
+        this.id = id;
+        this.fullId = fullId;
+        this.properties = new HashMap<>();
+    }
+
+    /**
+     * Adds new property to properties.
+     * @param name - name of new property.
+     */
+    public void setProperty(String name, Object value) {
+        properties.put(name, value);
+    }
+
+    /**
+     * Returns value. It could be anything.
+     * @param name - name of property.
+     * @return object of value.
+     */
+    public Object getProperty(String name) {
+        if (properties.containsKey(name)) {
+            return properties.get(name);
+        }
+
+        throw new IllegalArgumentException(format(
+                "Property '%s' does not exist.", getNewPropertyId(name))
+        );
+    }
+
+    /**
+     * Checks if property key is presents in properties.
+     * @param name - name of property
+     * @return boolean
+     */
+    public boolean containsProperty(String name) {
+        return properties.containsKey(name);
+    }
+
+    /**
+     * Returns optional value. It could be anything.
+     * @param name - name of property.
+     * @return optional object
+     */
+    @SuppressWarnings("unchecked")
+    public <T> Optional<T> getOptionalProperty(String name, Class<T> aClass) {
+        Object value = properties.get(name);
+        if (value == null || value.getClass() != aClass) {
+            return empty();
+        }
+
+        return of((T)value);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> List<T> getArrayPropertyOf(String name, Class<T> aClass) {
+        Object value = getProperty(name);
+        List<?> list = value instanceof List ? (List<?>)value : null;
+        if (list == null) {
+            throw new IllegalArgumentException("Cast error " + value.getClass() + " to " + List.class);
+        }
+        List<T> result = new ArrayList<>(list.size());
+        for (Object v : list) {
+            if (v.getClass() == aClass) {
+                result.add((T)v);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns property as a String.
+     * @param name - name of property.
+     * @return string value.
+     */
+    public String getStringProperty(String name) {
+        Object value = getProperty(name);
+        if (value instanceof String) {
+            return (String)value;
+        }
+        throw new ClassCastException(format(
+                "Value '%s' can not be cast to String", value
+        ));
+    }
+
+    public boolean getBooleanProperty(String name) {
+        Object value = getProperty(name);
+        if (value instanceof Boolean) {
+            return (Boolean)value;
+        }
+        throw new ClassCastException(format(
+                "Value '%s' can not be cast to Boolean", value
+        ));
+    }
+
+    /**
+     * Returns property as an Integer.
+     * @param name - name of property.
+     * @return integer value.
+     */
+    public Integer getIntegerProperty(String name) {
+        Object value = getProperty(name);
+        if (value instanceof Integer) {
+            return (Integer)value;
+        }
+        throw new ClassCastException(format(
+                "Value '%s' can not be cast to Integer", value
+        ));
+    }
+
+    /**
+     * Returns property as an Integer. If the property is null, will return default value.
+     * @param name - name of property.
+     * @param defaultValue - default value if the property is null
+     * @return integer value
+     */
+    public Integer getIntegerProperty(String name, int defaultValue) {
+        Object value = getProperty(name);
+        if (value instanceof Integer) {
+            return (Integer)value;
+        }
+
+        return defaultValue;
+    }
+
+    /**
+     * Returns property as a LocalDateTime.
+     * @param name - name of property.
+     * @return localDateTime value.
+     */
+    public LocalDateTime getLocalDateTimeProperty(String name) {
+        Object object = getProperty(name);
+
+        if (object instanceof LocalDateTime) {
+            return (LocalDateTime) object;
+        } else if (object instanceof Date) {
+            Date date = (Date) object;
+            return date.toInstant().atZone(ZoneOffset.systemDefault()).toLocalDateTime();
+        } else if (object instanceof String) {
+            return LocalDateTime.parse((String)object, DateTimeFormatter.ISO_DATE_TIME);
+        } else {
+            throw new ClassCastException(format(
+                    "Property '%s' can not be cast to %s", getNewPropertyId(name), LocalDateTime.class)
+            );
+        }
+    }
+
+    public OffsetDateTime getOffDateTimeProperty(String name) {
+        Object object = getProperty(name);
+
+        if (object instanceof OffsetDateTime) {
+            return (OffsetDateTime) object;
+        } else if (object instanceof String) {
+            return OffsetDateTime.parse((String) object);
+        } else {
+            throw new ClassCastException(format(
+                    "Property '%s' can not be cast to %s", getNewPropertyId(name), OffsetDateTime.class)
+            );
+        }
+    }
+
+    public LocalTime getLocalTimeProperty(String name) {
+        Object object = getProperty(name);
+
+        if (object instanceof LocalTime) {
+            return (LocalTime) object;
+        } else if (object instanceof String) {
+            return LocalTime.parse((String) object);
+        } else {
+            throw new ClassCastException(format(
+                    "Property '%s' can not be cast to %s", getNewPropertyId(name), LocalTime.class)
+            );
+        }
+    }
+
+    public ZonedDateTime getZonedDateTimeProperty(String name) {
+        Object object = getProperty(name);
+
+        if (object instanceof ZonedDateTime) {
+            return (ZonedDateTime)object;
+        } else if (object instanceof String) {
+            final DateTimeFormatter formatter = new DateTimeFormatterBuilder()
+                    .append(ISO_LOCAL_DATE_TIME)
+                    .optionalStart()
+                    .appendLiteral('[')
+                    .parseCaseSensitive()
+                    .appendZoneRegionId()
+                    .appendLiteral(']')
+                    .toFormatter();
+            return ZonedDateTime.parse((String)object, formatter);
+        } else {
+            throw new ClassCastException(format(
+                    "Property '%s' can not be cast to %s", getNewPropertyId(name), ZonedDateTime.class)
+            );
+        }
+    }
+
+    /**
+     * Returns new node of configuration.
+     * @param name - name of property.
+     * @return node of configuration.
+     */
+    public PropertyConfig getPropertyConfig(String name) {
+        Object property = getProperty(name);
+        PropertyConfig config = new PropertyConfig(name, getNewPropertyId(name));
+
+        if (property instanceof Map) {
+            Map<?, ?> properties = (Map<?, ?>) property;
+            for (Map.Entry<?, ?> propertyEntry : properties.entrySet()) {
+                Object propertyName = propertyEntry.getKey();
+                config.setProperty(propertyName.toString(), propertyEntry.getValue());
+            }
+        }
+
+        return config;
+    }
+
+    public Set<String> getAttributes() {
+        return properties.keySet();
+    }
+
+    private String getNewPropertyId(String name) {
+        return fullId + PATH_DELIMITER + name;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+}

+ 28 - 0
src/main/java/cz/senslog/analyzer/core/config/domain/SchedulerConfig.java

@@ -0,0 +1,28 @@
+package cz.senslog.analyzer.core.config.domain;
+
+import cz.senslog.analyzer.domain.Timestamp;
+
+import static java.time.OffsetDateTime.now;
+import static java.time.OffsetDateTime.parse;
+import static java.util.Optional.ofNullable;
+
+public class SchedulerConfig extends AbstractConfig {
+
+    private Timestamp initDate;
+    private int period;
+
+    @Override
+    public void parseConfig(PropertyConfig config) {
+        String initDateString = config.getStringProperty("initDate");
+        this.initDate = Timestamp.of(ofNullable(parse(initDateString)).orElse(now()));
+        this.period = config.getIntegerProperty("period");
+    }
+
+    public Timestamp getInitDate() {
+        return initDate;
+    }
+
+    public int getPeriod() {
+        return period;
+    }
+}

+ 15 - 0
src/main/java/cz/senslog/analyzer/core/config/domain/ServerConfig.java

@@ -0,0 +1,15 @@
+package cz.senslog.analyzer.core.config.domain;
+
+public class ServerConfig extends AbstractConfig {
+
+    private int port;
+
+    public int getPort() {
+        return port;
+    }
+
+    @Override
+    public void parseConfig(PropertyConfig config) {
+        this.port = config.getIntegerProperty("port");
+    }
+}

+ 36 - 0
src/main/java/cz/senslog/analyzer/core/config/domain/StorageConfig.java

@@ -0,0 +1,36 @@
+package cz.senslog.analyzer.core.config.domain;
+
+import cz.senslog.analyzer.storage.inmemory.InMemoryStorageConfig;
+import cz.senslog.analyzer.storage.permanent.PermanentStorageConfig;
+
+public class StorageConfig extends AbstractConfig {
+
+    private PermanentStorageConfig permanentStorageConfig;
+
+    private InMemoryStorageConfig inMemoryStorageConfig;
+
+    @Override
+    public void parseConfig(PropertyConfig config) {
+        PropertyConfig permanentProperty = config.getPropertyConfig("permanent");
+        this.permanentStorageConfig = new PermanentStorageConfig(
+                permanentProperty.getStringProperty("url"),
+                permanentProperty.getStringProperty("username"),
+                permanentProperty.getStringProperty("password"),
+                permanentProperty.getIntegerProperty("connectionPoolSize")
+        );
+        PropertyConfig inMemoryProperty = config.getPropertyConfig("inMemory");
+        this.inMemoryStorageConfig = new InMemoryStorageConfig(
+                inMemoryProperty.getStringProperty("path"),
+                inMemoryProperty.getBooleanProperty("persistence"),
+                inMemoryProperty.getStringProperty("parameters")
+        );
+    }
+
+    public PermanentStorageConfig getPermanentStorageConfig() {
+        return permanentStorageConfig;
+    }
+
+    public InMemoryStorageConfig getInMemoryStorageConfig() {
+        return inMemoryStorageConfig;
+    }
+}

+ 32 - 23
src/main/java/cz/senslog/analyzer/domain/Alert.java

@@ -1,23 +1,32 @@
-package cz.senslog.analyzer.domain;
-
-public class Alert {
-
-    private final String message;
-
-    public static Alert create(String message) {
-        return new Alert(message);
-    }
-
-    private Alert(String message) {
-        this.message = message;
-    }
-
-    public String getMessage() {
-        return message;
-    }
-
-    @Override
-    public String toString() {
-        return message;
-    }
-}
+package cz.senslog.analyzer.domain;
+
+public class Alert {
+
+    private final long groupId;
+    private final String groupName;
+    private final Timestamp timestamp;
+    private final String[] messages;
+
+    public Alert(long groupId, String groupName, Timestamp timestamp, String[] messages) {
+        this.groupId = groupId;
+        this.groupName = groupName;
+        this.timestamp = timestamp;
+        this.messages = messages;
+    }
+
+    public long getGroupId() {
+        return groupId;
+    }
+
+    public String getGroupName() {
+        return groupName;
+    }
+
+    public Timestamp getTimestamp() {
+        return timestamp;
+    }
+
+    public String[] getMessages() {
+        return messages;
+    }
+}

+ 10 - 3
src/main/java/cz/senslog/analyzer/domain/Group.java

@@ -9,17 +9,20 @@ import static java.util.Collections.emptySet;
 public class Group {
 
     private final long id;
+
+    private final String name;
     private final long interval;
     private final boolean persistence;
     private final AggregationType aggregationType;
     private final Set<Sensor> sensors;
 
     public static Group empty() {
-        return new Group(-1, 0, false, null, emptySet());
+        return new Group(-1, "", 0, false, null, emptySet());
     }
 
-    public Group(long id, long interval, boolean persistence, AggregationType aggregationType, Set<Sensor> sensors) {
+    public Group(long id, String name, long interval, boolean persistence, AggregationType aggregationType, Set<Sensor> sensors) {
         this.id = id;
+        this.name = name;
         this.interval = interval;
         this.persistence = persistence;
         this.aggregationType = aggregationType;
@@ -27,7 +30,7 @@ public class Group {
     }
 
     public Group(Group group, Set<Sensor> sensors) {
-        this(group.id, group.interval, group.persistence, group.aggregationType, sensors);
+        this(group.id, group.name, group.interval, group.persistence, group.aggregationType, sensors);
     }
 
     public long getId() {
@@ -50,6 +53,10 @@ public class Group {
         return sensors;
     }
 
+    public String getName() {
+        return name;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;

+ 9 - 5
src/main/java/cz/senslog/analyzer/provider/DataProvider.java

@@ -1,18 +1,22 @@
 package cz.senslog.analyzer.provider;
 
 import cz.senslog.analyzer.analysis.Analyzer;
-import cz.senslog.analyzer.provider.ProviderConfig;
 
-public abstract class DataProvider<T> {
+public abstract class DataProvider<T, C> implements Runnable {
 
     protected Analyzer<T> analyzer;
 
-    protected ProviderConfig config;
+    protected C config;
 
-    public void init(Analyzer<T> analyzer, ProviderConfig providerConfiguration) {
+    public void init(Analyzer<T> analyzer, C config) {
         this.analyzer = analyzer;
-        this.config = providerConfiguration;
+        this.config = config;
     }
 
     public abstract void start();
+
+    @Override
+    final public void run() {
+        new Thread(this::start).start();
+    }
 }

+ 3 - 1
src/main/java/cz/senslog/analyzer/provider/DataProviderComponent.java

@@ -6,13 +6,15 @@ import javax.inject.Singleton;
 
 @Singleton
 @Component(modules = {
-        ScheduleDatabaseProviderModule.class,
+        DatabaseProviderModule.class,
         HttpMiddlewareProviderModule.class
 })
 public interface DataProviderComponent {
 
     ScheduledDataProviderConfig scheduledDatabaseProvider(); // TODO refactor
 
+    LoopedDataProviderConfig loopedDatabaseProvider();
+
     MiddlewareDataProviderConfig httpMiddlewareProvider();
 
 }

+ 2 - 2
src/main/java/cz/senslog/analyzer/provider/DataProviderDeployment.java

@@ -3,7 +3,7 @@ package cz.senslog.analyzer.provider;
 import cz.senslog.analyzer.analysis.Analyzer;
 import cz.senslog.analyzer.provider.DataProvider;
 
-public interface DataProviderDeployment<T> {
+public interface DataProviderDeployment<T, C> {
 
-    DataProvider<T> deployAnalyzer(Analyzer<T> analyzer);
+    DataProvider<T, C> deployAnalyzer(Analyzer<T> analyzer);
 }

+ 31 - 21
src/main/java/cz/senslog/analyzer/provider/ScheduleDatabaseProviderModule.java → src/main/java/cz/senslog/analyzer/provider/DatabaseProviderModule.java

@@ -1,21 +1,31 @@
-package cz.senslog.analyzer.provider;
-
-import cz.senslog.analyzer.storage.RepositoryModule;
-import cz.senslog.analyzer.storage.inmemory.repository.TimestampRepository;
-import cz.senslog.analyzer.storage.permanent.repository.SensLogRepository;
-import dagger.Module;
-import dagger.Provides;
-
-@Module(includes = RepositoryModule.class)
-public class ScheduleDatabaseProviderModule {
-
-    @Provides
-    public ScheduledDataProviderConfig provideScheduledProvider(ScheduledDatabaseProvider provider) {
-        return new ScheduledDataProviderConfigImpl(provider);
-    }
-
-    @Provides
-    public ScheduledDatabaseProvider provideScheduleDatabaseProvider(TimestampRepository configRepository, SensLogRepository sensLogRepository) {
-        return new ScheduledDatabaseProvider(configRepository, sensLogRepository);
-    }
-}
+package cz.senslog.analyzer.provider;
+
+import cz.senslog.analyzer.storage.RepositoryModule;
+import cz.senslog.analyzer.storage.inmemory.repository.TimestampRepository;
+import cz.senslog.analyzer.storage.permanent.repository.SensLogRepository;
+import dagger.Module;
+import dagger.Provides;
+
+@Module(includes = RepositoryModule.class)
+public class DatabaseProviderModule {
+
+    @Provides
+    public ScheduledDataProviderConfig provideScheduledProvider(ScheduledDatabaseProvider provider) {
+        return new ScheduledDataProviderConfigImpl(provider);
+    }
+
+    @Provides
+    public ScheduledDatabaseProvider provideScheduleDatabaseProvider(TimestampRepository configRepository, SensLogRepository sensLogRepository) {
+        return new ScheduledDatabaseProvider(configRepository, sensLogRepository);
+    }
+
+    @Provides
+    public LoopedDataProviderConfig provideLoopedProvider(LoopedDatabaseProvider provider) {
+        return config -> analyzer -> { provider.init(analyzer, config); return provider; };
+    }
+
+    @Provides
+    public LoopedDatabaseProvider provideLoopedDatabaseProvider(SensLogRepository sensLogRepository) {
+        return new LoopedDatabaseProvider(sensLogRepository);
+    }
+}

+ 9 - 0
src/main/java/cz/senslog/analyzer/provider/LoopedDataProviderConfig.java

@@ -0,0 +1,9 @@
+package cz.senslog.analyzer.provider;
+
+import cz.senslog.analyzer.core.config.TaskAnalytics;
+import cz.senslog.analyzer.domain.Observation;
+
+public interface LoopedDataProviderConfig {
+
+    DataProviderDeployment<Observation, TaskAnalytics> config(TaskAnalytics config);
+}

+ 99 - 0
src/main/java/cz/senslog/analyzer/provider/LoopedDatabaseProvider.java

@@ -0,0 +1,99 @@
+package cz.senslog.analyzer.provider;
+
+import cz.senslog.analyzer.analysis.Analyzer;
+import cz.senslog.analyzer.analysis.TaskConfig;
+import cz.senslog.analyzer.core.config.TaskAnalytics;
+import cz.senslog.analyzer.domain.Observation;
+import cz.senslog.analyzer.domain.Timestamp;
+import cz.senslog.analyzer.storage.permanent.repository.SensLogRepository;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import javax.inject.Inject;
+import java.time.OffsetDateTime;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import static cz.senslog.analyzer.util.ListUtils.sublistToEnd;
+
+public class LoopedDatabaseProvider extends DataProvider<Observation, TaskAnalytics> {
+
+    private static final Logger logger = LogManager.getLogger(LoopedDatabaseProvider.class);
+
+    private final SensLogRepository repository;
+
+    @Inject
+    public LoopedDatabaseProvider(SensLogRepository sensLogRepository) {
+        this.repository = sensLogRepository;
+    }
+
+    @Override
+    public void start() {
+        config.getTasks().forEach(
+                t -> new Thread(new LoopedTask(analyzer, repository, t), "task-"+t.getId()).start()
+        );
+    }
+
+    private static class LoopedTask implements Runnable {
+
+        private static final int MAX_OBSERVATIONS = 200;
+
+        private final Analyzer<Observation> analyzer;
+        private final SensLogRepository repository;
+
+        private final Set<Long> groupIds;
+        private final Timestamp to;
+        private Timestamp from;
+
+        protected LoopedTask(Analyzer<Observation> analyzer, SensLogRepository repository, TaskConfig config) {
+            this.analyzer = analyzer;
+            this.repository = repository;
+            this.from = Timestamp.of(config.getFrom());
+            this.to = Timestamp.of(config.getTo());
+            this.groupIds = config.getGroupIds();
+
+        }
+
+        @Override
+        public final void run() {
+            while (from.isBefore(to)) {
+                long startTime = System.currentTimeMillis();
+                analyzer.accept(loadData());
+                long stopTime = System.currentTimeMillis();
+                long durationMilliSec = stopTime - startTime;
+                logger.info("Duration of the task '{}' was {} ms.", getClass().getSimpleName(), durationMilliSec);
+
+                // TODO make the thread to sleep?
+            }
+        }
+
+        private List<Observation> loadData() {
+            List<Observation> newObservations = repository.getObservationsByGroupIdsFromTime(from, groupIds, MAX_OBSERVATIONS);
+
+            if (newObservations.isEmpty()) {
+                from = to;
+                return Collections.emptyList();
+            }
+
+            if (newObservations.size() < MAX_OBSERVATIONS) {
+                from = to;
+                return newObservations;
+            }
+
+            Timestamp end = newObservations.get(newObservations.size() - 1).getTimestamp();
+
+            List<Observation> observations;
+            if (end.isAfter(to)) {
+                observations = sublistToEnd(newObservations, to, true, Observation::getTimestamp);
+                from = to;
+            } else {
+                observations = sublistToEnd(newObservations, end, false, Observation::getTimestamp);
+                from = end;
+            }
+
+            return observations;
+        }
+    }
+}

+ 5 - 2
src/main/java/cz/senslog/analyzer/provider/ScheduledDataProviderConfig.java

@@ -1,6 +1,9 @@
 package cz.senslog.analyzer.provider;
 
-public interface ScheduledDataProviderConfig<T> {
+import cz.senslog.analyzer.core.config.domain.SchedulerConfig;
+import cz.senslog.analyzer.domain.Observation;
 
-    DataProviderDeployment<T> config(ProviderConfig providerConfiguration);
+public interface ScheduledDataProviderConfig {
+
+    DataProviderDeployment<Observation, SchedulerConfig> config(SchedulerConfig scheduledProviderConfiguration);
 }

+ 7 - 6
src/main/java/cz/senslog/analyzer/provider/ScheduledDataProviderConfigImpl.java

@@ -1,27 +1,28 @@
 package cz.senslog.analyzer.provider;
 
 import cz.senslog.analyzer.analysis.Analyzer;
+import cz.senslog.analyzer.core.config.domain.SchedulerConfig;
 import cz.senslog.analyzer.domain.Observation;
 
-public class ScheduledDataProviderConfigImpl implements ScheduledDataProviderConfig<Observation>, DataProviderDeployment<Observation> {
+public class ScheduledDataProviderConfigImpl implements ScheduledDataProviderConfig, DataProviderDeployment<Observation, SchedulerConfig> {
 
     private final ScheduledDatabaseProvider provider;
 
-    private ProviderConfig providerConfiguration;
+    private SchedulerConfig schedulerConfig;
 
     public ScheduledDataProviderConfigImpl(ScheduledDatabaseProvider provider) {
         this.provider = provider;
     }
 
     @Override
-    public DataProvider<Observation> deployAnalyzer(Analyzer<Observation> analyzer) {
-        provider.init(analyzer, providerConfiguration);
+    public DataProvider<Observation, SchedulerConfig> deployAnalyzer(Analyzer<Observation> analyzer) {
+        provider.init(analyzer, schedulerConfig);
         return provider;
     }
 
     @Override
-    public DataProviderDeployment<Observation> config(ProviderConfig providerConfiguration) {
-        this.providerConfiguration = providerConfiguration;
+    public DataProviderDeployment<Observation, SchedulerConfig> config(SchedulerConfig scheduledProviderConfiguration) {
+        this.schedulerConfig = scheduledProviderConfiguration;
         return this;
     }
 }

+ 3 - 6
src/main/java/cz/senslog/analyzer/provider/ScheduledDatabaseProvider.java

@@ -1,5 +1,6 @@
 package cz.senslog.analyzer.provider;
 
+import cz.senslog.analyzer.core.config.domain.SchedulerConfig;
 import cz.senslog.analyzer.domain.Observation;
 import cz.senslog.analyzer.provider.task.ObservationAnalyzerTask;
 import cz.senslog.analyzer.storage.inmemory.TimestampStorage;
@@ -11,7 +12,7 @@ import org.apache.logging.log4j.Logger;
 
 import javax.inject.Inject;
 
-public class ScheduledDatabaseProvider extends DataProvider<Observation> {
+public class ScheduledDatabaseProvider extends DataProvider<Observation, SchedulerConfig> {
 
     private static final Logger logger = LogManager.getLogger(ScheduledDatabaseProvider.class);
 
@@ -30,14 +31,10 @@ public class ScheduledDatabaseProvider extends DataProvider<Observation> {
     public void start() {
 
         scheduler = Scheduler.createBuilder()
-                .addTask(new ObservationAnalyzerTask(analyzer, storage, repository, config.getStartDateTime()), config.getPeriod())
+                .addTask("db-scheduler", new ObservationAnalyzerTask(analyzer, storage, repository, config.getInitDate().get()), config.getPeriod())
         .build();
 
         scheduler.start();
 
     }
-
-    private Scheduler registerTask(AnalyzerTask<Observation> mainTask, AnalyzerTask<Observation>... tasks) {
-        return null;
-    }
 }

+ 55 - 55
src/main/java/cz/senslog/analyzer/provider/ProviderConfig.java → src/main/java/cz/senslog/analyzer/provider/ScheduledProviderConfig.java

@@ -1,55 +1,55 @@
-package cz.senslog.analyzer.provider;
-
-import java.time.OffsetDateTime;
-
-public class ProviderConfig {
-
-    public interface ConfigurationBuilder {
-
-        ConfigurationBuilder period(int period);
-        ConfigurationBuilder startDateTime(OffsetDateTime startDateTime);
-
-        ProviderConfig get();
-    }
-
-    public static ConfigurationBuilder config() {
-        return new ConfigurationBuilder() {
-
-            private int period;
-            private OffsetDateTime startDateTime;
-
-            @Override
-            public ConfigurationBuilder period(int period) {
-                this.period = period;
-                return this;
-            }
-
-            @Override
-            public ConfigurationBuilder startDateTime(OffsetDateTime startDateTime) {
-                this.startDateTime = startDateTime;
-                return this;
-            }
-
-            @Override
-            public ProviderConfig get() {
-                return new ProviderConfig(period, startDateTime);
-            }
-        };
-    }
-
-    private final int period;
-    private final OffsetDateTime startDateTime;
-
-    private ProviderConfig(int period, OffsetDateTime startDateTime) {
-        this.period = period;
-        this.startDateTime = startDateTime;
-    }
-
-    public int getPeriod() {
-        return period;
-    }
-
-    public OffsetDateTime getStartDateTime() {
-        return startDateTime;
-    }
-}
+package cz.senslog.analyzer.provider;
+
+import java.time.OffsetDateTime;
+
+public class ScheduledProviderConfig {
+
+    public interface ConfigurationBuilder {
+
+        ConfigurationBuilder period(int period);
+        ConfigurationBuilder startDateTime(OffsetDateTime startDateTime);
+
+        ScheduledProviderConfig get();
+    }
+
+    public static ConfigurationBuilder config() {
+        return new ConfigurationBuilder() {
+
+            private int period;
+            private OffsetDateTime startDateTime;
+
+            @Override
+            public ConfigurationBuilder period(int period) {
+                this.period = period;
+                return this;
+            }
+
+            @Override
+            public ConfigurationBuilder startDateTime(OffsetDateTime startDateTime) {
+                this.startDateTime = startDateTime;
+                return this;
+            }
+
+            @Override
+            public ScheduledProviderConfig get() {
+                return new ScheduledProviderConfig(period, startDateTime);
+            }
+        };
+    }
+
+    private final int period;
+    private final OffsetDateTime startDateTime;
+
+    private ScheduledProviderConfig(int period, OffsetDateTime startDateTime) {
+        this.period = period;
+        this.startDateTime = startDateTime;
+    }
+
+    public int getPeriod() {
+        return period;
+    }
+
+    public OffsetDateTime getStartDateTime() {
+        return startDateTime;
+    }
+}

+ 2 - 0
src/main/java/cz/senslog/analyzer/provider/task/ObservationAnalyzerTask.java

@@ -7,6 +7,7 @@ import cz.senslog.analyzer.domain.Timestamp;
 import cz.senslog.analyzer.provider.AnalyzerTask;
 import cz.senslog.analyzer.storage.inmemory.TimestampStorage;
 import cz.senslog.analyzer.storage.permanent.repository.SensLogRepository;
+import cz.senslog.analyzer.util.TimestampUtil;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -74,6 +75,7 @@ public class ObservationAnalyzerTask extends AnalyzerTask<Observation> {
         Timestamp start = newObservations.get(0).getTimestamp();
         Timestamp end = newObservations.get(newObservations.size() - 1).getTimestamp();
 
+//        List<Observation> observations = new ArrayList<>(newObservations);
         List<Observation> observations = sublistToEnd(newObservations, end, false, Observation::getTimestamp);
 
         if (observations.isEmpty()) {

+ 6 - 6
src/main/java/cz/senslog/analyzer/storage/ConnectionModule.java

@@ -2,6 +2,8 @@ package cz.senslog.analyzer.storage;
 
 import com.zaxxer.hikari.HikariConfig;
 import com.zaxxer.hikari.HikariDataSource;
+import cz.senslog.analyzer.core.config.ConfigurationModule;
+import cz.senslog.analyzer.core.config.domain.StorageConfig;
 import cz.senslog.analyzer.storage.inmemory.InMemoryConnection;
 import cz.senslog.analyzer.storage.inmemory.InMemoryStorageConfig;
 import cz.senslog.analyzer.storage.permanent.PermanentStorageConfig;
@@ -15,22 +17,20 @@ import org.jdbi.v3.jodatime2.JodaTimePlugin;
 import org.jdbi.v3.postgres.PostgresPlugin;
 import org.postgresql.ds.PGSimpleDataSource;
 
+import javax.inject.Inject;
 import javax.inject.Singleton;
 
 import static java.lang.String.format;
 
-@Module
+@Module(includes = ConfigurationModule.class)
 public class ConnectionModule {
 
     private static final Logger logger = LogManager.getLogger(ConnectionModule.class);
 
     private final StorageConfig config;
 
-    public static ConnectionModule create(StorageConfig storageConfig) {
-        return new ConnectionModule(storageConfig);
-    }
-
-    private ConnectionModule(StorageConfig config) {
+    @Inject
+    public ConnectionModule(StorageConfig config) {
         this.config = config;
     }
 

+ 0 - 24
src/main/java/cz/senslog/analyzer/storage/StorageConfig.java

@@ -1,24 +0,0 @@
-package cz.senslog.analyzer.storage;
-
-import cz.senslog.analyzer.storage.inmemory.InMemoryStorageConfig;
-import cz.senslog.analyzer.storage.permanent.PermanentStorageConfig;
-
-public class StorageConfig {
-
-    private final PermanentStorageConfig permanentStorageConfig;
-
-    private final InMemoryStorageConfig inMemoryStorageConfig;
-
-    public StorageConfig(PermanentStorageConfig permanentStorageConfig, InMemoryStorageConfig inMemoryStorageConfig) {
-        this.permanentStorageConfig = permanentStorageConfig;
-        this.inMemoryStorageConfig = inMemoryStorageConfig;
-    }
-
-    public PermanentStorageConfig getPermanentStorageConfig() {
-        return permanentStorageConfig;
-    }
-
-    public InMemoryStorageConfig getInMemoryStorageConfig() {
-        return inMemoryStorageConfig;
-    }
-}

+ 87 - 63
src/main/java/cz/senslog/analyzer/storage/permanent/repository/SensLogRepository.java

@@ -1,64 +1,88 @@
-package cz.senslog.analyzer.storage.permanent.repository;
-
-import cz.senslog.analyzer.domain.Alert;
-import cz.senslog.analyzer.domain.Observation;
-import cz.senslog.analyzer.domain.Sensor;
-import cz.senslog.analyzer.domain.Timestamp;
-import cz.senslog.analyzer.storage.Connection;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.jdbi.v3.core.Jdbi;
-
-import javax.inject.Inject;
-import java.time.OffsetDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.Collections;
-import java.util.List;
-
-public class SensLogRepository {
-
-    private static final DateTimeFormatter POSTGRESQL_TIMESTAMPWTZ_PATTERN =
-            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSX");
-
-    private static final Logger logger = LogManager.getLogger(SensLogRepository.class);
-
-    private final Jdbi jdbi;
-
-    @Inject
-    public SensLogRepository(Connection<Jdbi> connection) {
-        this.jdbi = connection.get();
-    }
-
-    public List<Observation> getObservationsFromTime(Timestamp timestamp, boolean inclusive, int limit) {
-        logger.info("Getting new observations from: " + timestamp);
-        if (limit <= 0) { return Collections.emptyList(); }
-        return jdbi.withHandle(h -> h.createQuery(
-                "SELECT unit_id, sensor_id, observed_value, time_stamp FROM public.observations " +
-                        "WHERE time_stamp " + (inclusive ? ">=" : ">") + " :timestamp ORDER BY time_stamp LIMIT :limit"
-                )
-                    .bind("timestamp", timestamp.get())
-                    .bind("limit", limit)
-                    .map((rs, ctx) -> new Observation(
-                            new Sensor(
-                                    rs.getLong("unit_id"),
-                                    rs.getLong("sensor_id")
-                            ),
-                            rs.getDouble("observed_value"),
-                            Timestamp.parse(rs.getString("time_stamp"))
-                    )).list()
-        );
-    }
-
-    public void saveAlert(Alert alert) {
-        String message = alert.getMessage();
-        String shortMsg = message.length() >= 100 ? message.substring(0, 99) : message;
-        try {
-            jdbi.<Exception>useHandle(h -> h.inTransaction(t -> t.execute(
-                    "INSERT INTO public.alerts(alert_id, alert_description) SELECT coalesce(MAX(alert_id),0)+1, ? FROM public.alerts;", shortMsg)
-            ));
-        } catch (Exception e) {
-            logger.error("Can not persist this data: {}.", shortMsg);
-            logger.error(e.getMessage());
-        }
-    }
+package cz.senslog.analyzer.storage.permanent.repository;
+
+import cz.senslog.analyzer.domain.Alert;
+import cz.senslog.analyzer.domain.Observation;
+import cz.senslog.analyzer.domain.Sensor;
+import cz.senslog.analyzer.domain.Timestamp;
+import cz.senslog.analyzer.storage.Connection;
+import dagger.BindsOptionalOf;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.jdbi.v3.core.Jdbi;
+
+import javax.inject.Inject;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class SensLogRepository {
+
+    private static final DateTimeFormatter POSTGRESQL_TIMESTAMPWTZ_PATTERN =
+            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSX");
+
+    private static final Logger logger = LogManager.getLogger(SensLogRepository.class);
+
+    private final Jdbi jdbi;
+
+    @Inject
+    public SensLogRepository(Connection<Jdbi> connection) {
+        this.jdbi = connection.get();
+    }
+
+    public List<Observation> getObservationsByGroupIdsFromTime(Timestamp timestamp, Set<Long> groupIds, int limit) {
+       if (groupIds.isEmpty() || limit <= 0) { return Collections.emptyList(); }
+
+        return jdbi.withHandle(h -> h.createQuery(
+            "SELECT o.unit_id, o.sensor_id, o.observed_value, o.time_stamp FROM statistics.sensor_to_group AS sg " +
+                    "JOIN statistics.sensors AS s ON s.id = sg.sensor_id " +
+                    "JOIN public.observations AS o ON o.sensor_id = s.sensor_id AND o.unit_id = s.unit_id " +
+                    "WHERE sg.group_id = ANY(:group_ids) AND time_stamp >= :timestamp " +
+                    "ORDER BY o.time_stamp LIMIT :limit"
+                )
+                .bindArray("group_ids", Integer.class, groupIds)
+                .bind("timestamp", timestamp.get())
+                .bind("limit", limit)
+                .map((rs, ctx) -> new Observation(
+                        new Sensor(
+                                rs.getLong("unit_id"),
+                                rs.getLong("sensor_id")
+                        ),
+                        rs.getDouble("observed_value"),
+                        Timestamp.parse(rs.getString("time_stamp"))
+                )).list()
+        );
+    }
+
+    public List<Observation> getObservationsFromTime(Timestamp timestamp, boolean inclusive, int limit) {
+        logger.info("Getting new observations from: " + timestamp);
+        if (limit <= 0) { return Collections.emptyList(); }
+        return jdbi.withHandle(h -> h.createQuery(
+            "SELECT unit_id, sensor_id, observed_value, time_stamp FROM public.observations " +
+                    "WHERE time_stamp " + (inclusive ? ">=" : ">") + " :timestamp ORDER BY time_stamp LIMIT :limit"
+            )
+                .bind("timestamp", timestamp.get())
+                .bind("limit", limit)
+                .map((rs, ctx) -> new Observation(
+                        new Sensor(
+                                rs.getLong("unit_id"),
+                                rs.getLong("sensor_id")
+                        ),
+                        rs.getDouble("observed_value"),
+                        Timestamp.parse(rs.getString("time_stamp"))
+                )).list()
+        );
+    }
+
+    public void saveAlert(String message) {
+        String shortMsg = message.length() >= 100 ? message.substring(0, 99) : message;
+        try {
+            jdbi.<Exception>useHandle(h -> h.inTransaction(t -> t.execute(
+                    "INSERT INTO public.alerts(alert_id, alert_description) SELECT coalesce(MAX(alert_id),0)+1, ? FROM public.alerts;", shortMsg)
+            ));
+        } catch (Exception e) {
+            logger.error("Can not persist this data: {}.", shortMsg);
+            logger.error(e.getMessage());
+        }
+    }
 }

+ 4 - 1
src/main/java/cz/senslog/analyzer/storage/permanent/repository/StatisticsConfigRepository.java

@@ -14,6 +14,7 @@ import java.time.format.DateTimeFormatter;
 import java.util.AbstractMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static java.util.Collections.emptyList;
 import static java.util.Collections.emptySet;
@@ -52,10 +53,11 @@ public class StatisticsConfigRepository {
         );
     }
 
-    public List<Group> getGroupInfos() {
+    public List<Group> getAllAvailableGroupInfos() {
         return jdbi.withHandle(h -> h.createQuery(
                 "SELECT " +
                         "g.id AS group_id, " +
+                        "g.name AS group_name, " +
                         "s.sensor_id AS sensor_id, " +
                         "s.unit_id AS unit_id, " +
                         "g.time_interval AS time_interval, " +
@@ -75,6 +77,7 @@ public class StatisticsConfigRepository {
                     );
                     Group group = new Group(
                             groupId,
+                            rs.getString("group_name"),
                             rs.getLong("time_interval"),
                             rs.getBoolean("persistence"),
                             AggregationType.valueOf(rs.getString("aggregation_type")),

+ 6 - 2
src/main/java/cz/senslog/analyzer/storage/permanent/repository/StatisticsRepository.java

@@ -88,6 +88,7 @@ public class StatisticsRepository {
 
         class RawRecord {
             long recordId, groupId, sensorId, unitId;
+            String groupName;
             double value; int interval;
             AttributeValue attribute;
             Timestamp timestamp;
@@ -97,6 +98,7 @@ public class StatisticsRepository {
         List<RawRecord> rawRecords = jdbi.withHandle(h -> h.createQuery(
                 "SELECT r.id AS record_id," +
                         "g.id AS group_id," +
+                        "g.name AS group_name," +
                         "s.sensor_id AS sensor_id," +
                         "s.unit_id AS unit_id," +
                         "r.value_attribute AS attribute," +
@@ -120,6 +122,7 @@ public class StatisticsRepository {
                     RawRecord r = new RawRecord();
                     r.recordId = rs.getLong("record_id");
                     r.groupId = rs.getLong("group_id");
+                    r.groupName = rs.getString("group_name");
                     r.sensorId = rs.getLong("sensor_id");
                     r.unitId = rs.getLong("unit_id");
                     r.attribute = AttributeValue.valueOf(rs.getString("attribute"));
@@ -153,7 +156,7 @@ public class StatisticsRepository {
             List<RawRecord> records = stEntry.getValue();
 
             double min=0, max=0, sum=0; long count=0;
-            boolean unknown = false;
+            boolean unknown = records.isEmpty();
             for (RawRecord r : records) {
                 switch (r.attribute) {
                     case MAX: max = r.value; break;
@@ -164,7 +167,8 @@ public class StatisticsRepository {
                 }
             }
             if (!unknown) {
-                Group group = new Group(groupId, interval, true, DOUBLE, sensors);
+                String groupName = records.get(0).groupName;
+                Group group = new Group(groupId, groupName, interval, true, DOUBLE, sensors);
                 statistics.add(new DoubleStatistics(group, count, min, max, sum, timestamp));
             }
         }

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio