// Path: distribution/src/main/java/nl/crowndov/displaydirect/distribution/Configuration.java
// public class Configuration {
// 
//     private static final Logger LOGGER = LoggerFactory.getLogger(Configuration.class);
// 
//     private static AbstractConfiguration config = ConfigurationManager.getConfigInstance();
// 
//     public static List<String> getKvEndpoints() {
//         return Arrays.asList(config.getStringArray("distribution.kv78turbo.endpoints"));
//     }
// 
//     public static String[] getKvPublishers() {
//         return config.getStringArray("distribution.kv78turbo.publishers");
//     }
// 
//     public static ZoneId getZoneId() {
//         return ZoneId.of(config.getString("distribution.timezone.default"));
//     }
// 
//     public static String getOutputTransport() {
//         return config.getString("distribution.transport", "mqtt");
//     }
// 
//     public static String getMqttBrokerHost() {
//         return config.getString("distribution.mqtt.host", "localhost:1883");
//     }
// 
//     public static int getZmqInternalPort() {
//         return 9800;
//     }
// 
//     public static String getMqttClientId() {
//         return config.getString("distribution.mqtt.client_id", "distribution");
//     }
// 
//     public static int getAuthorizationTokenMaxAge() {
//         return config.getInt("distribution.authorization.max_age_hours");
//     }
// 
//     public static List<String> getAuthorizationWhitelist() {
//         return Arrays.asList(config.getStringArray("distribution.authorization.whitelist_prefix"));
//     }
// 
//     public static String getBaseUrl() {
//         return config.getString("distribution.install.base_url", "http://localhost:8080");
//     }
// 
//     public static String getSmtpUsername() {
//         return config.getString("distribution.smtp.username", null);
//     }
// 
//     public static String getSmtpPassword() {
//         return config.getString("distribution.smtp.password", null);
//     }
// 
//     public static String getSmtpFrom() {
//         return config.getString("distribution.smtp.from");
//     }
// 
//     public static String getSmtpHostname() {
//         return config.getString("distribution.smtp.hostname");
//     }
// 
//     public static String getSmtpReplyTo() {
//         return config.getString("distribution.smtp.reply_to");
//     }
// 
//     public static boolean getSmtpSsl() { return config.getBoolean("distribution.smtp.ssl", false); }
// 
//     public static int getSmtpPort() {
//         return config.getInt("distribution.smtp.port", 25);
//     }
// 
//     public static int getSmtpConnectTimeout() {
//         return  config.getInt("distribution.smtp.connect_timeout", 10*1000);
//     }
// 
//     public static String getFileBasePath() {
//         return config.getString("distribution.backup.path", System.getProperty("java.io.tmpdir"));
//     }
// 
//     public static String getKv7PlanningPath() {
//         return config.getString("distribution.kv78turbo.path.planning");
//     }
// 
//     public static String getKv7CalendarPath() {
//         return config.getString("distribution.kv78turbo.path.calendar");
//     }
// 
//     public static String getChbPath() {
//         return config.getString("distribution.chb.path");
//     }
// 
// 
//     public static String getPlanningLoaderTime() {
//         return config.getString("distribution.planning.loadTime", "03:30");
//     }
// 
//     public static String getPlanningCleanupTime() {
//         return config.getString("distribution.planning.cleanupTime", "04:00");
//     }
// 
// }


import com.google.gson.Gson;
import nl.crowndov.displaydirect.distribution.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.file.*;
import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
            T result = (T) ois.readObject();
            return Optional.of(result);
        } catch (ClassNotFoundException e) {
            LOGGER.error("Error deserializing {}", key, e);
        } catch (Exception e) {
            LOGGER.error("Error reading {}", key, e);
        }
        return Optional.empty();
    }

    protected static <T> void writeFile(String key, T data) {
        String dataStr = GSON.toJson(data);
        LOGGER.info("Got serialized data {} (len {})", key, dataStr.length());
        JsonFile.write(key, dataStr);
    }

    protected static <T> void writeFileSerialize(String key, T data) {
        String out = getPathSerialized(key+"-temp").toString();
        LOGGER.info("Writing to {}", out);
        try (FileOutputStream fos = new FileOutputStream(out, false);
             ObjectOutputStream oos = new ObjectOutputStream(fos)) {
            oos.writeObject(data);
            // Once done, move to the location we read, so that in case the (long) export is interupted, we don't lose a backup
            Files.move(getPathSerialized(key+"-temp"), getPathSerialized(key), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
        } catch (IOException e) {
            LOGGER.error("Error writing {}", key, e);
        }
    }

    private static Path getPathSerialized(String key) {
// Path: distribution/src/main/java/nl/crowndov/displaydirect/distribution/Configuration.java
// public class Configuration {
// 
//     private static final Logger LOGGER = LoggerFactory.getLogger(Configuration.class);
// 
//     private static AbstractConfiguration config = ConfigurationManager.getConfigInstance();
// 
//     public static List<String> getKvEndpoints() {
//         return Arrays.asList(config.getStringArray("distribution.kv78turbo.endpoints"));
//     }
// 
//     public static String[] getKvPublishers() {
//         return config.getStringArray("distribution.kv78turbo.publishers");
//     }
// 
//     public static ZoneId getZoneId() {
//         return ZoneId.of(config.getString("distribution.timezone.default"));
//     }
// 
//     public static String getOutputTransport() {
//         return config.getString("distribution.transport", "mqtt");
//     }
// 
//     public static String getMqttBrokerHost() {
//         return config.getString("distribution.mqtt.host", "localhost:1883");
//     }
// 
//     public static int getZmqInternalPort() {
//         return 9800;
//     }
// 
//     public static String getMqttClientId() {
//         return config.getString("distribution.mqtt.client_id", "distribution");
//     }
// 
//     public static int getAuthorizationTokenMaxAge() {
//         return config.getInt("distribution.authorization.max_age_hours");
//     }
// 
//     public static List<String> getAuthorizationWhitelist() {
//         return Arrays.asList(config.getStringArray("distribution.authorization.whitelist_prefix"));
//     }
// 
//     public static String getBaseUrl() {
//         return config.getString("distribution.install.base_url", "http://localhost:8080");
//     }
// 
//     public static String getSmtpUsername() {
//         return config.getString("distribution.smtp.username", null);
//     }
// 
//     public static String getSmtpPassword() {
//         return config.getString("distribution.smtp.password", null);
//     }
// 
//     public static String getSmtpFrom() {
//         return config.getString("distribution.smtp.from");
//     }
// 
//     public static String getSmtpHostname() {
//         return config.getString("distribution.smtp.hostname");
//     }
// 
//     public static String getSmtpReplyTo() {
//         return config.getString("distribution.smtp.reply_to");
//     }
// 
//     public static boolean getSmtpSsl() { return config.getBoolean("distribution.smtp.ssl", false); }
// 
//     public static int getSmtpPort() {
//         return config.getInt("distribution.smtp.port", 25);
//     }
// 
//     public static int getSmtpConnectTimeout() {
//         return  config.getInt("distribution.smtp.connect_timeout", 10*1000);
//     }
// 
//     public static String getFileBasePath() {
//         return config.getString("distribution.backup.path", System.getProperty("java.io.tmpdir"));
//     }
// 
//     public static String getKv7PlanningPath() {
//         return config.getString("distribution.kv78turbo.path.planning");
//     }
// 
//     public static String getKv7CalendarPath() {
//         return config.getString("distribution.kv78turbo.path.calendar");
//     }
// 
//     public static String getChbPath() {
//         return config.getString("distribution.chb.path");
//     }
// 
// 
//     public static String getPlanningLoaderTime() {
//         return config.getString("distribution.planning.loadTime", "03:30");
//     }
// 
//     public static String getPlanningCleanupTime() {
//         return config.getString("distribution.planning.cleanupTime", "04:00");
//     }
// 
// }


// Path: distribution/src/main/java/nl/crowndov/displaydirect/distribution/util/AbstractService.java
import com.google.gson.Gson;
import nl.crowndov.displaydirect.distribution.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.file.*;
import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

            T result = (T) ois.readObject();
            return Optional.of(result);
        } catch (ClassNotFoundException e) {
            LOGGER.error("Error deserializing {}", key, e);
        } catch (Exception e) {
            LOGGER.error("Error reading {}", key, e);
        }
        return Optional.empty();
    }

    protected static <T> void writeFile(String key, T data) {
        String dataStr = GSON.toJson(data);
        LOGGER.info("Got serialized data {} (len {})", key, dataStr.length());
        JsonFile.write(key, dataStr);
    }

    protected static <T> void writeFileSerialize(String key, T data) {
        String out = getPathSerialized(key+"-temp").toString();
        LOGGER.info("Writing to {}", out);
        try (FileOutputStream fos = new FileOutputStream(out, false);
             ObjectOutputStream oos = new ObjectOutputStream(fos)) {
            oos.writeObject(data);
            // Once done, move to the location we read, so that in case the (long) export is interupted, we don't lose a backup
            Files.move(getPathSerialized(key+"-temp"), getPathSerialized(key), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
        } catch (IOException e) {
            LOGGER.error("Error writing {}", key, e);
        }
    }

    private static Path getPathSerialized(String key) {
        return Paths.get(Configuration.getFileBasePath(), key+".out");