Initial Check-In
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b377fd1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+.git
+.idea/**/*.xml
+.settings
+.classpath
+target
+/.idea/compiler.xml
+/.idea/*.xml
+/.idea/modules.xml
+/.idea/vcs.xml
+/bin/
+*.iml
+.project
+.classpath
+.idea
+/dependency-reduced-pom.xml
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..fc24ab4
--- /dev/null
+++ b/README.md
@@ -0,0 +1,13 @@
+# micsCentral
+
+How to start the micsCentral application
+---
+
+1. Run `mvn clean install` to build your application
+1. Start application with `java -jar target/mics-central-service-0.1.1-SNAPSHOT.jar server config.yml`
+1. To check that your application is running enter url `http://localhost:8080`
+
+Health Check
+---
+
+To see your applications health enter url `http://localhost:8081/healthcheck`
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..254c82a
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project
+        xmlns="http://maven.apache.org/POM/4.0.0"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <prerequisites>
+        <maven>3.0.0</maven>
+    </prerequisites>
+
+    <groupId>pta.de</groupId>
+    <artifactId>mics-central-service</artifactId>
+    <version>0.1.1-SNAPSHOT</version>
+    <packaging>jar</packaging>
+
+    <name>micsCentral</name>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <dropwizard.version>1.2.0</dropwizard.version>
+        <mainClass>pta.de.micsCentralApplication</mainClass>
+        <easymock.version>3.4</easymock.version>
+        <powermock-api-easymock.version>1.6.6</powermock-api-easymock.version>
+        <jacoco-maven-plugin.version>0.7.9</jacoco-maven-plugin.version>
+        <commons-io.version>2.5</commons-io.version>
+        <gson.version>2.8.0</gson.version>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>io.dropwizard</groupId>
+                <artifactId>dropwizard-bom</artifactId>
+                <version>${dropwizard.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.dropwizard</groupId>
+            <artifactId>dropwizard-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>${commons-io.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <version>${gson.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <version>${easymock.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-module-junit4</artifactId>
+            <version>${powermock-api-easymock.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-api-easymock</artifactId>
+            <version>${powermock-api-easymock.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jacoco</groupId>
+            <artifactId>jacoco-maven-plugin</artifactId>
+            <version>${jacoco-maven-plugin.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>2.4.1</version>
+                <configuration>
+                    <createDependencyReducedPom>true</createDependencyReducedPom>
+                    <transformers>
+                        <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
+                        <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                            <mainClass>${mainClass}</mainClass>
+                        </transformer>
+                    </transformers>
+                    <!-- exclude signed Manifests -->
+                    <filters>
+                        <filter>
+                            <artifact>*:*</artifact>
+                            <excludes>
+                                <exclude>META-INF/*.SF</exclude>
+                                <exclude>META-INF/*.DSA</exclude>
+                                <exclude>META-INF/*.RSA</exclude>
+                            </excludes>
+                        </filter>
+                    </filters>
+                </configuration>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.6</version>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <addClasspath>true</addClasspath>
+                            <mainClass>${mainClass}</mainClass>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.6.1</version>
+                <configuration>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-source-plugin</artifactId>
+                <version>2.4</version>
+                <executions>
+                    <execution>
+                        <id>attach-sources</id>
+                        <goals>
+                            <goal>jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <version>2.10.3</version>
+                <executions>
+                    <execution>
+                        <id>attach-javadocs</id>
+                        <goals>
+                            <goal>jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <reporting>
+        <plugins>
+            <plugin>
+                <artifactId>maven-project-info-reports-plugin</artifactId>
+                <version>2.8.1</version>
+                <configuration>
+                    <dependencyLocationsEnabled>false</dependencyLocationsEnabled>
+                    <dependencyDetailsEnabled>false</dependencyDetailsEnabled>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <version>2.10.3</version>
+            </plugin>
+        </plugins>
+    </reporting>
+</project>
diff --git a/serviceConfigDevLocal.yml b/serviceConfigDevLocal.yml
new file mode 100644
index 0000000..59921dc
--- /dev/null
+++ b/serviceConfigDevLocal.yml
@@ -0,0 +1,25 @@
+servicesDistributionFileName: servicesDistributionDevLocal.json
+
+
+logging:
+  level: INFO
+  appenders:
+    - type: file
+      currentLogFilename: /log/mics-central-service.log
+      threshold: ALL
+      archive: true
+      archivedLogFilenamePattern: /log/mics-central-service-%d.log
+      archivedFileCount: 5
+      timeZone: UTC
+  loggers:
+    pta: DEBUG
+    org.eclipse.jetty.servlets: DEBUG
+
+server:
+  applicationConnectors:
+  - type: http
+    port: 9010
+  adminConnectors:
+  - type: http
+    port: 9011
+
diff --git a/servicesDistributionDevLocal.json b/servicesDistributionDevLocal.json
new file mode 100644
index 0000000..ed508c4
--- /dev/null
+++ b/servicesDistributionDevLocal.json
@@ -0,0 +1,18 @@
+[
+  {
+    "active": "true",
+    "clustername": "elogbook.openK",
+    "description": "elogbook service cluster for openKonsequenz",
+    "distributions": [
+      {
+        "active": "true",
+        "name": "auth-n-auth.mics",
+        "protocol": "http",
+        "host": "172.18.22.160",
+        "portApp": "9002",
+        "portHealth": "9003",
+        "description": "Authentication Service"
+      }
+    ]
+  }
+]
\ No newline at end of file
diff --git a/src/main/java/pta/de/api/ServiceDistributionCluster.java b/src/main/java/pta/de/api/ServiceDistributionCluster.java
new file mode 100644
index 0000000..baa8a2b
--- /dev/null
+++ b/src/main/java/pta/de/api/ServiceDistributionCluster.java
@@ -0,0 +1,149 @@
+package pta.de.api;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.hibernate.validator.constraints.NotEmpty;
+
+
+public class ServiceDistributionCluster {
+
+    public static class ServiceDistribution {
+
+        public boolean active;
+
+        @NotEmpty
+        public String name;
+
+        @NotEmpty
+        public String host;
+
+        @NotEmpty
+        public String protocol;
+
+        @NotEmpty
+        public int portApp;
+
+        public int portHealth;
+
+        public String description;
+
+        public ServiceDistribution() {
+        }
+
+        @JsonProperty
+        public boolean isActive() {
+            return active;
+        }
+
+        @JsonProperty
+        public void setActive(boolean active) {
+            this.active = active;
+        }
+
+        @JsonProperty
+        public String getName() {
+            return name;
+        }
+
+        @JsonProperty
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        @JsonProperty
+        public String getHost() {
+            return host;
+        }
+
+        @JsonProperty
+        public void setHost(String host) {
+            this.host = host;
+        }
+
+        @JsonProperty
+        public String getProtocol() {
+            return protocol;
+        }
+
+        @JsonProperty
+        public void setProtocol(String protocol) {
+            this.protocol = protocol;
+        }
+
+        @JsonProperty
+        public int getPortApp() {
+            return portApp;
+        }
+
+        @JsonProperty
+        public void setPortApp(int portApp) {
+            this.portApp = portApp;
+        }
+
+        @JsonProperty
+        public String getDescription() {
+            return description;
+        }
+
+        @JsonProperty
+        public void setDescription(String description) {
+            this.description = description;
+        }
+
+        @JsonProperty
+        public int getPortHealth() {
+            return portHealth;
+        }
+
+        @JsonProperty
+        public void setPortHealth(int portHealth) {
+            this.portHealth = portHealth;
+        }
+    }
+
+    public boolean active;
+
+    @NotEmpty
+    public String clustername;
+
+    public String description;
+
+    ServiceDistribution[] distributions;
+
+    @JsonProperty
+    public boolean isActive() {
+        return active;
+    }
+
+    @JsonProperty
+    public void setActive(boolean active) {
+        this.active = active;
+    }
+
+    @JsonProperty
+    public String getClustername() {
+        return clustername;
+    }
+
+    @JsonProperty
+    public void setClustername(String clustername) {
+        this.clustername = clustername;
+    }
+
+    @JsonProperty
+    public String getDescription() {
+        return description;
+    }
+
+    @JsonProperty
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public ServiceDistribution[] getDistributions() {
+        return distributions;
+    }
+
+    public void setDistributions(ServiceDistribution[] distributions) {
+        this.distributions = distributions;
+    }
+}
diff --git a/src/main/java/pta/de/api/VersionInfo.java b/src/main/java/pta/de/api/VersionInfo.java
new file mode 100644
index 0000000..1a95df3
--- /dev/null
+++ b/src/main/java/pta/de/api/VersionInfo.java
@@ -0,0 +1,15 @@
+package pta.de.api;
+
+public class VersionInfo {
+    private String backendVersion;
+
+    public String getBackendVersion() {
+        return backendVersion;
+    }
+
+    public void setBackendVersion(String backendVersion) {
+        this.backendVersion = backendVersion;
+    }
+
+
+}
diff --git a/src/main/java/pta/de/core/common/GsonUTCDateAdapter.java b/src/main/java/pta/de/core/common/GsonUTCDateAdapter.java
new file mode 100644
index 0000000..024080b
--- /dev/null
+++ b/src/main/java/pta/de/core/common/GsonUTCDateAdapter.java
@@ -0,0 +1,35 @@
+package pta.de.core.common;
+
+import com.google.gson.*;
+
+import java.lang.reflect.Type;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+public class GsonUTCDateAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {
+
+    private final DateFormat dateFormat;
+
+    public GsonUTCDateAdapter() {
+        dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);      //This is the format I need
+        dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));                               //This is the key line which converts the date to UTC which cannot be accessed with the default serializer
+    }
+
+    @Override
+    public synchronized JsonElement serialize(Date date, Type type, JsonSerializationContext jsonSerializationContext) {
+        return new JsonPrimitive(dateFormat.format(date));
+    }
+
+    @Override
+    public synchronized Date deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) {
+        try {
+            return dateFormat.parse(jsonElement.getAsString());
+        } catch (ParseException e) {
+            throw new JsonParseException(e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/pta/de/core/common/JsonGeneratorBase.java b/src/main/java/pta/de/core/common/JsonGeneratorBase.java
new file mode 100644
index 0000000..af20a84
--- /dev/null
+++ b/src/main/java/pta/de/core/common/JsonGeneratorBase.java
@@ -0,0 +1,16 @@
+package pta.de.core.common;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import java.util.Date;
+
+public class JsonGeneratorBase {
+    private JsonGeneratorBase() {}
+    public static Gson getGson() {
+        return new GsonBuilder()
+                .registerTypeAdapter(Date.class, new GsonUTCDateAdapter())
+                .disableHtmlEscaping()
+                .create();
+    }
+}
diff --git a/src/main/java/pta/de/core/common/util/ResourceLoaderBase.java b/src/main/java/pta/de/core/common/util/ResourceLoaderBase.java
new file mode 100644
index 0000000..ba3c3e6
--- /dev/null
+++ b/src/main/java/pta/de/core/common/util/ResourceLoaderBase.java
@@ -0,0 +1,26 @@
+package pta.de.core.common.util;
+
+import org.apache.commons.io.IOUtils;
+
+import java.io.InputStream;
+import java.io.StringWriter;
+
+public class ResourceLoaderBase {
+    private String stream2String(InputStream is) {
+        StringWriter writer = new StringWriter();
+        try {
+            IOUtils.copy(is, writer, "UTF-8");
+        } catch (Exception e) { // NOSONAR
+            return "";
+        }
+        return writer.toString();
+
+
+    }
+
+    public String loadStringFromResource(String filename) {
+        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+        InputStream jsonstream = classLoader.getResourceAsStream(filename);
+        return stream2String(jsonstream);
+    }
+}
diff --git a/src/main/java/pta/de/core/controller/BackendController.java b/src/main/java/pta/de/core/controller/BackendController.java
new file mode 100644
index 0000000..82e5974
--- /dev/null
+++ b/src/main/java/pta/de/core/controller/BackendController.java
@@ -0,0 +1,44 @@
+package pta.de.core.controller;
+
+import com.google.common.collect.Lists;
+import org.apache.log4j.Logger;
+import org.eclipse.jetty.http.HttpStatus;
+import pta.de.api.ServiceDistributionCluster;
+import pta.de.api.VersionInfo;
+import pta.de.core.exceptions.HttpStatusException;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class BackendController {
+    private static Logger logger = Logger.getLogger(BackendController.class.getName());
+
+    public ServiceDistributionCluster readServerDistribution(String cluster) throws HttpStatusException {
+        ServiceDistributionCluster[] dcs = ServicesConfigCache.getInstance().getCache();
+
+        for (ServiceDistributionCluster item : dcs) {
+            if (item.clustername.equalsIgnoreCase(cluster) && item.isActive()) {
+                return removeInactiveItems(item);
+            }
+        }
+        throw new HttpStatusException(HttpStatus.NOT_FOUND_404);
+    }
+
+    public VersionInfo getVersionInfo( String version ) {
+        VersionInfo vi = new VersionInfo();
+        vi.setBackendVersion( version );
+        return vi;
+    }
+
+    private ServiceDistributionCluster removeInactiveItems( ServiceDistributionCluster cluster ) {
+        List<ServiceDistributionCluster.ServiceDistribution> dlist = Arrays.asList(cluster.getDistributions());
+        dlist = dlist.stream().filter(d -> d.isActive()).collect(Collectors.toList());
+        ServiceDistributionCluster.ServiceDistribution distArr[]
+                = new ServiceDistributionCluster.ServiceDistribution[dlist.size()];
+        cluster.setDistributions(dlist.toArray(distArr));
+        return cluster;
+    }
+
+
+}
diff --git a/src/main/java/pta/de/core/controller/BaseWebService.java b/src/main/java/pta/de/core/controller/BaseWebService.java
new file mode 100644
index 0000000..123e859
--- /dev/null
+++ b/src/main/java/pta/de/core/controller/BaseWebService.java
@@ -0,0 +1,60 @@
+package pta.de.core.controller;
+
+import org.apache.log4j.Logger;
+import org.eclipse.jetty.http.HttpStatus;
+import pta.de.core.exceptions.HttpStatusException;
+
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+public abstract class BaseWebService {
+    public interface Invokable <T> {
+        public T invoke() throws Exception;
+    }
+    private final Map<String, Long> currentTimeMeasures = new HashMap<>();
+    private final Logger logger;
+
+    public BaseWebService(Logger logger) {
+        this.logger = logger;
+    }
+
+    protected Response invokeRunnable(Invokable runnable)
+    {
+        try  { // NOSONAR
+            Object o =  runnable.invoke();
+            return Response.ok(o).build();
+        } catch (HttpStatusException hse) {
+            logger.error(hse);
+            return Response.status(hse.getHttpStatus()).build();
+        }
+        catch (Exception e) {
+            logger.error("Caught unexpected Exception:", e);
+            return Response.status(HttpStatus.INTERNAL_SERVER_ERROR_500).build();
+        }
+    }
+
+
+
+    protected static String getVersionString() {
+        try {
+            // determine static VersionInfo
+            final Properties properties = new Properties();
+
+            properties.load(BaseWebService.class.getClassLoader().getResourceAsStream("project.properties"));
+
+            String beversion = properties.getProperty("backend.version");
+            if( beversion.contains("$")) {
+                beversion = "LOCAL-DEV";
+            }
+            return beversion;
+        } catch (IOException e) {
+            throw new RuntimeException("Exception during start up");
+        }
+    }
+
+
+
+}
diff --git a/src/main/java/pta/de/core/controller/InitServicesConfigCacheJob.java b/src/main/java/pta/de/core/controller/InitServicesConfigCacheJob.java
new file mode 100644
index 0000000..1c39866
--- /dev/null
+++ b/src/main/java/pta/de/core/controller/InitServicesConfigCacheJob.java
@@ -0,0 +1,19 @@
+package pta.de.core.controller;
+
+import org.apache.log4j.Logger;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class InitServicesConfigCacheJob {
+
+    private static final Logger LOGGER = Logger.getLogger(InitServicesConfigCacheJob.class.getName());
+
+
+    public static void init( String configFileName ) {
+        LOGGER.info("InitServicesConfigCacheJob called");
+        TimerTask timerTask = new ServicesConfigCacheTimerTask(configFileName);
+        Timer timer = new Timer();
+        timer.scheduleAtFixedRate(timerTask, 100, 5000L);
+    }
+}
diff --git a/src/main/java/pta/de/core/controller/ServicesConfigCache.java b/src/main/java/pta/de/core/controller/ServicesConfigCache.java
new file mode 100644
index 0000000..0fb4435
--- /dev/null
+++ b/src/main/java/pta/de/core/controller/ServicesConfigCache.java
@@ -0,0 +1,74 @@
+package pta.de.core.controller;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.log4j.Logger;
+import org.eclipse.jetty.http.HttpStatus;
+import pta.de.api.ServiceDistributionCluster;
+
+import pta.de.core.exceptions.HttpStatusException;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Set;
+
+public class ServicesConfigCache {
+  private static final Logger logger = Logger.getLogger(ServicesConfigCache.class.getName());
+  private static final ServicesConfigCache SERIVCECONFIGCACHE_INSTANCE = new ServicesConfigCache();
+  private String criticalSection = "CRITICAL_SECTION";
+
+  private ServiceDistributionCluster[] cache;
+
+  private ServicesConfigCache(){
+  }
+
+  public static ServicesConfigCache getInstance() {
+      return SERIVCECONFIGCACHE_INSTANCE;
+  }
+
+
+  public void readServerDistribution(String configFileName) throws HttpStatusException {
+    try {
+      ServiceDistributionCluster[] dcs = readServerDistributionFromText(new String(Files.readAllBytes(Paths.get(configFileName)), Charset.forName("UTF-8")));
+      cache = dcs;
+
+    } catch (IOException e) {
+      logger.error("Could not read file "+configFileName+"!", e);
+      throw new HttpStatusException(HttpStatus.INTERNAL_SERVER_ERROR_500);
+    }
+  }
+
+  private ServiceDistributionCluster[] readServerDistributionFromText(String jsonText) throws HttpStatusException {
+    ServiceDistributionCluster[] dcs;
+
+    try {
+      final ObjectMapper mapper = new ObjectMapper();
+      dcs = mapper.readValue(jsonText, ServiceDistributionCluster[].class);
+    } catch (IOException e) {
+      logger.error("Could not parse file!", e);
+      throw new HttpStatusException(HttpStatus.INTERNAL_SERVER_ERROR_500);
+    }
+
+    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
+    Validator validator = factory.getValidator();
+
+    for (ServiceDistributionCluster item : dcs) {
+      Set<ConstraintViolation<ServiceDistributionCluster>> violations
+              = validator.validate(item);
+      if (violations.size() > 0) {
+        logger.error("Error in configfile!: ");
+        throw new HttpStatusException(HttpStatus.INTERNAL_SERVER_ERROR_500);
+      }
+    }
+    return dcs;
+  }
+
+  public ServiceDistributionCluster[] getCache() {
+      return cache;
+  }
+}
diff --git a/src/main/java/pta/de/core/controller/ServicesConfigCacheTimerTask.java b/src/main/java/pta/de/core/controller/ServicesConfigCacheTimerTask.java
new file mode 100644
index 0000000..47f6b02
--- /dev/null
+++ b/src/main/java/pta/de/core/controller/ServicesConfigCacheTimerTask.java
@@ -0,0 +1,31 @@
+package pta.de.core.controller;
+
+import org.apache.log4j.Logger;
+import pta.de.core.exceptions.HttpStatusException;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.TimerTask;
+
+public class ServicesConfigCacheTimerTask extends TimerTask {
+  private String configFileName;
+
+  public ServicesConfigCacheTimerTask( String configFileName ) {
+    this.configFileName = configFileName;
+  }
+
+  private static final Logger logger = Logger.getLogger(ServicesConfigCacheTimerTask.class.getName());
+
+  @Override
+  public void run() {
+    logger.debug("ServicesConfigCacheTimerTask started");
+
+    try {
+      ServicesConfigCache.getInstance().readServerDistribution(this.configFileName);
+    } catch (HttpStatusException e) {
+      logger.error("Error reading ServerDistributionFile", e);
+    }
+
+    logger.debug("ServicesConfigCacheTimerTask finished");
+  }
+}
diff --git a/src/main/java/pta/de/core/exceptions/HttpStatusException.java b/src/main/java/pta/de/core/exceptions/HttpStatusException.java
new file mode 100644
index 0000000..ae0bb4f
--- /dev/null
+++ b/src/main/java/pta/de/core/exceptions/HttpStatusException.java
@@ -0,0 +1,13 @@
+package pta.de.core.exceptions;
+
+public class HttpStatusException extends Exception {
+    private int httpStatus;
+
+    public HttpStatusException(int httpStatus ) {
+        this.httpStatus = httpStatus;
+    }
+
+    public int getHttpStatus() {
+        return httpStatus;
+    }
+}
diff --git a/src/main/java/pta/de/health/ConfigFilePresentHealthCheck.java b/src/main/java/pta/de/health/ConfigFilePresentHealthCheck.java
new file mode 100644
index 0000000..9b116e7
--- /dev/null
+++ b/src/main/java/pta/de/health/ConfigFilePresentHealthCheck.java
@@ -0,0 +1,20 @@
+package pta.de.health;
+
+import com.codahale.metrics.health.HealthCheck;
+import pta.de.api.ServiceDistributionCluster;
+import pta.de.core.controller.BackendController;
+import pta.de.core.controller.ServicesConfigCache;
+
+public class ConfigFilePresentHealthCheck extends HealthCheck {
+    @Override
+    protected Result check() throws Exception {
+        ServiceDistributionCluster[] sdc = ServicesConfigCache.getInstance().getCache(); // Throws Exception if it fails
+
+        if( sdc.length > 0 ) {
+            return Result.healthy();
+        }
+        else {
+            return Result.unhealthy("No ServiceDistributionCluster available!");
+        }
+    }
+}
diff --git a/src/main/java/pta/de/micsCentralApplication.java b/src/main/java/pta/de/micsCentralApplication.java
new file mode 100644
index 0000000..7f705e8
--- /dev/null
+++ b/src/main/java/pta/de/micsCentralApplication.java
@@ -0,0 +1,68 @@
+package pta.de;
+
+import com.codahale.metrics.health.HealthCheck;
+import io.dropwizard.Application;
+import io.dropwizard.setup.Bootstrap;
+import io.dropwizard.setup.Environment;
+import org.eclipse.jetty.servlets.CrossOriginFilter;
+import pta.de.core.controller.BackendController;
+import pta.de.core.controller.InitServicesConfigCacheJob;
+import pta.de.health.ConfigFilePresentHealthCheck;
+import pta.de.resources.MicsCentralResource;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.FilterRegistration;
+import java.util.EnumSet;
+
+public class micsCentralApplication extends Application<micsCentralConfiguration> {
+
+    public static void main(final String[] args) throws Exception {
+        new micsCentralApplication().run(args);
+    }
+
+    @Override
+    public String getName() {
+        return "micsCentral";
+    }
+
+    @Override
+    public void initialize(final Bootstrap<micsCentralConfiguration> bootstrap) {
+    }
+
+    @Override
+    public void run(final micsCentralConfiguration configuration,
+                    final Environment environment) {
+
+        initAppEnvironment( configuration );
+
+        final MicsCentralResource micsCentralResource = new MicsCentralResource();
+        final HealthCheck configFilePresentHC = new ConfigFilePresentHealthCheck();
+
+        environment.healthChecks().register("configFilePresent", configFilePresentHC );
+        environment.jersey().register(micsCentralResource);
+
+        configureCors(environment);
+    }
+
+    private void initAppEnvironment( micsCentralConfiguration conf ) {
+        InitServicesConfigCacheJob.init(conf.getServicesDistributionFileName());
+    }
+
+    private void configureCors(Environment environment) {
+        final FilterRegistration.Dynamic cors =
+                environment.servlets().addFilter("CORS", CrossOriginFilter.class);
+
+        // Configure CORS parameters
+        cors.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
+        cors.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin,Authorization,X-XSRF-TOKEN");
+        cors.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "OPTIONS,GET,PUT,POST,DELETE,HEAD");
+        cors.setInitParameter(CrossOriginFilter.ALLOW_CREDENTIALS_PARAM, "true");
+
+        // Add URL mapping
+        cors.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
+        // DO NOT pass a preflight request to down-stream auth filters
+        // unauthenticated preflight requests should be permitted by spec
+        cors.setInitParameter(CrossOriginFilter.CHAIN_PREFLIGHT_PARAM, Boolean.FALSE.toString());
+    }
+
+}
diff --git a/src/main/java/pta/de/micsCentralConfiguration.java b/src/main/java/pta/de/micsCentralConfiguration.java
new file mode 100644
index 0000000..3566350
--- /dev/null
+++ b/src/main/java/pta/de/micsCentralConfiguration.java
@@ -0,0 +1,20 @@
+package pta.de;
+
+import io.dropwizard.Configuration;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.hibernate.validator.constraints.*;
+
+public class micsCentralConfiguration extends Configuration {
+    @NotEmpty
+    private String servicesDistributionFileName;
+
+    @JsonProperty
+    public String getServicesDistributionFileName() {
+        return servicesDistributionFileName;
+    }
+
+    @JsonProperty
+    public void setServicesDistributionFileName(String servicesDistributionFileName) {
+        this.servicesDistributionFileName = servicesDistributionFileName;
+    }
+}
diff --git a/src/main/java/pta/de/resources/MicsCentralResource.java b/src/main/java/pta/de/resources/MicsCentralResource.java
new file mode 100644
index 0000000..48e039e
--- /dev/null
+++ b/src/main/java/pta/de/resources/MicsCentralResource.java
@@ -0,0 +1,41 @@
+package pta.de.resources;
+
+
+import org.apache.log4j.Logger;
+import org.hibernate.validator.constraints.NotEmpty;
+import pta.de.core.controller.BackendController;
+import pta.de.core.controller.BaseWebService;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Path("/mics/central")
+@Produces(MediaType.APPLICATION_JSON)
+public class MicsCentralResource extends BaseWebService{
+    private static Logger logger = Logger.getLogger(MicsCentralResource.class.getName());
+
+    public MicsCentralResource() {
+        super(logger);
+    }
+
+    @GET
+    @Path("/serviceDistribution/{clustername}")
+    public Response getServiceDistribution(@PathParam("clustername") @NotEmpty String clustername) {
+        return invokeRunnable( () -> {
+            return new BackendController().readServerDistribution(clustername);
+        });
+    }
+
+    @GET
+    @Path("/versionInfo")
+    public Response getVersionInfo() {
+        return invokeRunnable( () -> {
+            return new BackendController().getVersionInfo(getVersionString());
+        });
+    }
+
+}
diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt
new file mode 100644
index 0000000..561b172
--- /dev/null
+++ b/src/main/resources/banner.txt
@@ -0,0 +1,6 @@
+================================================================================
+
+                              micsCentral
+
+================================================================================
+
diff --git a/src/main/resources/project.properties b/src/main/resources/project.properties
new file mode 100644
index 0000000..25e06ec
--- /dev/null
+++ b/src/main/resources/project.properties
@@ -0,0 +1 @@
+backend.version =${project.version}
\ No newline at end of file
diff --git a/src/test/java/pta/de/core/common/util/ResourceLoaderBaseTest.java b/src/test/java/pta/de/core/common/util/ResourceLoaderBaseTest.java
new file mode 100644
index 0000000..c310452
--- /dev/null
+++ b/src/test/java/pta/de/core/common/util/ResourceLoaderBaseTest.java
@@ -0,0 +1,15 @@
+package pta.de.core.common.util;
+
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class ResourceLoaderBaseTest {
+    @Test
+    public void testloadStringFromResourceError() {
+        ResourceLoaderBase rlb = new ResourceLoaderBase();
+        String str = rlb.loadStringFromResource("UNKNOWN_FILE");
+        assertEquals(str, "");
+    }
+}
diff --git a/src/test/java/pta/de/core/controller/BackendControllerTest.java b/src/test/java/pta/de/core/controller/BackendControllerTest.java
new file mode 100644
index 0000000..ac3b32a
--- /dev/null
+++ b/src/test/java/pta/de/core/controller/BackendControllerTest.java
@@ -0,0 +1,69 @@
+package pta.de.core.controller;
+
+import org.eclipse.jetty.http.HttpStatus;
+import org.junit.Test;
+import org.powermock.reflect.Whitebox;
+import pta.de.api.ServiceDistributionCluster;
+import pta.de.core.common.util.ResourceLoaderBase;
+import pta.de.core.exceptions.HttpStatusException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+
+public class BackendControllerTest {
+
+    private ServiceDistributionCluster baseTestReadServerDistribution(String clustername, String jsonFile) throws Exception {
+        ResourceLoaderBase resourceLoaderBase = new ResourceLoaderBase();
+        String json = resourceLoaderBase.loadStringFromResource(jsonFile);
+
+        ServicesConfigCache scc = ServicesConfigCache.getInstance();
+        ServiceDistributionCluster[] sdc = (ServiceDistributionCluster[])
+                Whitebox.invokeMethod(scc,"readServerDistributionFromText", json);
+
+        Whitebox.setInternalState(scc, "cache", sdc);
+
+        BackendController be = new BackendController();
+
+        ServiceDistributionCluster ret = be.readServerDistribution(clustername);
+
+        return ret;
+    }
+
+    @Test
+    public void testReadServerDistribution() throws Exception {
+
+        ServiceDistributionCluster sdc = baseTestReadServerDistribution("elogbook.openK", "testServiceDistributions.json");
+
+        assertEquals(sdc.clustername, "elogbook.openK");
+        assertEquals(sdc.getDistributions().length, 1);
+        assertEquals(sdc.getDistributions()[0].host, "172.18.22.160");
+    }
+
+    @Test
+    public void testFailReadServerDistribution() throws Exception {
+        try {
+            baseTestReadServerDistribution("doesntMatter", "testServiceDist_False.json");
+        } catch( HttpStatusException e ) {
+            assertEquals(e.getHttpStatus(), HttpStatus.INTERNAL_SERVER_ERROR_500);
+        }
+    }
+
+    @Test
+    public void testReadServerDistribution_notfound() throws Exception {
+        try {
+            ServiceDistributionCluster sdc = baseTestReadServerDistribution("invalidCluster", "testServiceDistributions.json");
+        } catch( HttpStatusException e ) {
+            assertEquals(e.getHttpStatus(), HttpStatus.NOT_FOUND_404);
+        }
+    }
+
+    @Test
+    public void testReadServerDistribution_activeInactive() throws Exception {
+        ServiceDistributionCluster sdc = baseTestReadServerDistribution( "elogbook.openK", "testServiceDistributionsTwo_OneIsInactive.json");
+
+        assertEquals( 1, sdc.getDistributions().length);
+        assertTrue( sdc.getDistributions()[0].isActive());
+        assertEquals( "172.18.22.160", sdc.getDistributions()[0].getHost());
+    }
+}
diff --git a/src/test/java/pta/de/core/controller/ServicesConfigCacheTest.java b/src/test/java/pta/de/core/controller/ServicesConfigCacheTest.java
new file mode 100644
index 0000000..67407d5
--- /dev/null
+++ b/src/test/java/pta/de/core/controller/ServicesConfigCacheTest.java
@@ -0,0 +1,48 @@
+package pta.de.core.controller;
+
+import org.eclipse.jetty.http.HttpStatus;
+import org.junit.Test;
+import org.powermock.reflect.Whitebox;
+import pta.de.api.ServiceDistributionCluster;
+import pta.de.core.common.util.ResourceLoaderBase;
+import pta.de.core.exceptions.HttpStatusException;
+
+import static org.junit.Assert.assertEquals;
+
+
+public class ServicesConfigCacheTest {
+
+    private ServiceDistributionCluster[] baseTestReadServerDistribution(String jsonFile) throws Exception {
+        ResourceLoaderBase resourceLoaderBase = new ResourceLoaderBase();
+        String json = resourceLoaderBase.loadStringFromResource(jsonFile);
+
+        ServicesConfigCache scc = ServicesConfigCache.getInstance();
+
+
+
+        ServiceDistributionCluster[] sdc = (ServiceDistributionCluster[])
+                Whitebox.invokeMethod(scc,"readServerDistributionFromText", json);
+
+        return sdc;
+    }
+
+    @Test
+    public void testReadServerDistribution() throws Exception {
+
+        ServiceDistributionCluster[] sdc = baseTestReadServerDistribution("testServiceDistributions.json");
+
+        assertEquals(sdc[0].clustername, "elogbook.openK");
+        assertEquals(sdc[0].getDistributions().length, 1);
+        assertEquals(sdc[0].getDistributions()[0].host, "172.18.22.160");
+    }
+
+    @Test
+    public void testFailReadServerDistribution() throws Exception {
+        try {
+            baseTestReadServerDistribution("testServiceDist_False.json");
+        } catch( HttpStatusException e ) {
+            assertEquals(e.getHttpStatus(), HttpStatus.INTERNAL_SERVER_ERROR_500);
+        }
+    }
+
+}
diff --git a/src/test/java/pta/de/core/exceptions/HttpStatusExceptionTest.java b/src/test/java/pta/de/core/exceptions/HttpStatusExceptionTest.java
new file mode 100644
index 0000000..9779181
--- /dev/null
+++ b/src/test/java/pta/de/core/exceptions/HttpStatusExceptionTest.java
@@ -0,0 +1,15 @@
+package pta.de.core.exceptions;
+
+
+import org.eclipse.jetty.http.HttpStatus;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class HttpStatusExceptionTest {
+    @Test
+    public void testAll() {
+        HttpStatusException hse = new HttpStatusException( 200 );
+        assertEquals( hse.getHttpStatus(), HttpStatus.OK_200);
+    }
+}
diff --git a/src/test/resources/testServiceDist_False.json b/src/test/resources/testServiceDist_False.json
new file mode 100644
index 0000000..759fd24
--- /dev/null
+++ b/src/test/resources/testServiceDist_False.json
@@ -0,0 +1,18 @@
+[
+  {
+    "active": "true",
+
+    "description": "elogbook service cluster for openKonsequenz",
+    "distributions": [
+      {
+        "active": "true",
+        "name": "auth-n-auth.mics",
+        "protocol": "http",
+        "host": "172.18.22.160",
+        "portApp": "9002",
+        "portHealth": "9003",
+        "description": "Authentication Service"
+      }
+    ]
+  }
+]
\ No newline at end of file
diff --git a/src/test/resources/testServiceDistributions.json b/src/test/resources/testServiceDistributions.json
new file mode 100644
index 0000000..40d8558
--- /dev/null
+++ b/src/test/resources/testServiceDistributions.json
@@ -0,0 +1,18 @@
+[
+  {
+  "active": "true",
+  "clustername": "elogbook.openK",
+  "description": "elogbook service cluster for openKonsequenz",
+  "distributions": [
+      {
+      "active": "true",
+      "name": "auth-n-auth.mics",
+      "protocol": "http",
+      "host": "172.18.22.160",
+      "portApp": "9002",
+      "portHealth": "9003",
+      "description": "Authentication Service"
+      }
+    ]
+  }
+]
\ No newline at end of file
diff --git a/src/test/resources/testServiceDistributionsTwo_OneIsInactive.json b/src/test/resources/testServiceDistributionsTwo_OneIsInactive.json
new file mode 100644
index 0000000..fe36fee
--- /dev/null
+++ b/src/test/resources/testServiceDistributionsTwo_OneIsInactive.json
@@ -0,0 +1,52 @@
+[
+  {
+    "active": "false",
+    "clustername": "elogbook.openK",
+    "description": "elogbook service cluster for openKonsequenz",
+    "distributions": [
+      {
+        "active": "true",
+        "name": "auth-n-auth.mics",
+        "protocol": "http",
+        "host": "172.18.22.160",
+        "portApp": "9002",
+        "portHealth": "9003",
+        "description": "Authentication Service"
+      },
+      {
+        "active": "false",
+        "name": "auth-n-auth.mics",
+        "protocol": "http",
+        "host": "localhost",
+        "portApp": "9002",
+        "portHealth": "9003",
+        "description": "Authentication Service"
+      }
+    ]
+  },
+  {
+  "active": "true",
+  "clustername": "elogbook.openK",
+  "description": "elogbook service cluster for openKonsequenz",
+  "distributions": [
+      {
+        "active": "true",
+        "name": "auth-n-auth.mics",
+        "protocol": "http",
+        "host": "172.18.22.160",
+        "portApp": "9002",
+        "portHealth": "9003",
+        "description": "Authentication Service"
+      },
+      {
+        "active": "false",
+        "name": "auth-n-auth.mics",
+        "protocol": "http",
+        "host": "localhost",
+        "portApp": "9002",
+        "portHealth": "9003",
+        "description": "Authentication Service"
+      }
+    ]
+  }
+]
\ No newline at end of file