Merge branch 'dev' into mkoller/atfxadapter

Conflicts:
	build.gradle
	src/main/java/org/eclipse/mdm/api/odsadapter/ReadRequestHandler.java

Signed-off-by: Matthias Koller <m.koller@peak-solution.de>
diff --git a/build.gradle b/build.gradle
index 6548e01..ad9d310 100644
--- a/build.gradle
+++ b/build.gradle
@@ -14,7 +14,7 @@
 
 description = 'MDM API - ODSAdapter'
 group = 'org.eclipse.mdm'
-version = '5.1.0M5-SNAPSHOT'
+version = '5.1.0M5-ATFX-SNAPSHOT'
 
 apply plugin: 'java'
 apply plugin: 'maven'
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManager.java b/src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManager.java
index f01c859..527a186 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManager.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManager.java
@@ -44,6 +44,8 @@
 import org.eclipse.mdm.api.base.model.Environment;
 import org.eclipse.mdm.api.base.model.MeasuredValues;
 import org.eclipse.mdm.api.base.model.StatusAttachable;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
 import org.eclipse.mdm.api.base.model.User;
 import org.eclipse.mdm.api.base.query.DataAccessException;
 import org.eclipse.mdm.api.base.query.Filter;
@@ -55,9 +57,12 @@
 import org.eclipse.mdm.api.dflt.EntityManager;
 import org.eclipse.mdm.api.dflt.model.Classification;
 import org.eclipse.mdm.api.dflt.model.Status;
+import org.eclipse.mdm.api.dflt.model.TemplateTest;
+import org.eclipse.mdm.api.dflt.model.TemplateTestStep;
 import org.eclipse.mdm.api.odsadapter.filetransfer.Transfer;
 import org.eclipse.mdm.api.odsadapter.lookup.EntityLoader;
 import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityFactory;
 import org.eclipse.mdm.api.odsadapter.query.ODSEntityType;
 import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
 import org.eclipse.mdm.api.odsadapter.transaction.ODSTransaction;
@@ -443,4 +448,20 @@
 
 		return linkMap;
 	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<TemplateTest> loadTemplate(Test test) {
+		return Optional.of(ODSEntityFactory.extract(test).getMutableStore().get(TemplateTest.class));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<TemplateTestStep> loadTemplate(TestStep testStep) {
+		return Optional.of(ODSEntityFactory.extract(testStep).getMutableStore().get(TemplateTestStep.class));
+	}
 }
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/DefaultEntityConfigRepositoryLoader.java b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/DefaultEntityConfigRepositoryLoader.java
index 6eeed7c..1b6c48b 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/DefaultEntityConfigRepositoryLoader.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/DefaultEntityConfigRepositoryLoader.java
@@ -39,9 +39,13 @@
 import org.eclipse.mdm.api.dflt.model.CatalogAttribute;
 import org.eclipse.mdm.api.dflt.model.CatalogComponent;
 import org.eclipse.mdm.api.dflt.model.CatalogSensor;
+import org.eclipse.mdm.api.dflt.model.Classification;
+import org.eclipse.mdm.api.dflt.model.Domain;
 import org.eclipse.mdm.api.dflt.model.Pool;
 import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.dflt.model.ProjectDomain;
 import org.eclipse.mdm.api.dflt.model.Role;
+import org.eclipse.mdm.api.dflt.model.Status;
 import org.eclipse.mdm.api.dflt.model.TemplateAttribute;
 import org.eclipse.mdm.api.dflt.model.TemplateComponent;
 import org.eclipse.mdm.api.dflt.model.TemplateRoot;
@@ -189,7 +193,20 @@
 		registerContextRoot(modelManager, ContextType.UNITUNDERTEST);
 		registerContextRoot(modelManager, ContextType.TESTSEQUENCE);
 		registerContextRoot(modelManager, ContextType.TESTEQUIPMENT);
+		
+		// Status
+		entityConfigRepository.register(create(modelManager, new Key<>(Status.class), "Status", false));
+		
+		// ProjectDomain
+		entityConfigRepository.register(create(modelManager, new Key<>(ProjectDomain.class), "ProjectDomain", false));
+		
+		// Domain
+		entityConfigRepository.register(create(modelManager, new Key<>(Domain.class), "Domain", false));
+		
+		// Domain
+		entityConfigRepository.register(create(modelManager, new Key<>(Classification.class), "Classification", false));
 
+		
 		LOGGER.debug("Entity configurations loaded in {} ms.", System.currentTimeMillis() - start);
 		return entityConfigRepository;
 	}
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/EventProcessor.java b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/EventProcessor.java
index 25b0f49..010d535 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/EventProcessor.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/EventProcessor.java
@@ -43,7 +43,8 @@
 	private PeakNotificationManager odsNotificationManager;
 	private MediaType eventMediaType;
 	private boolean closeInvoked = false;
-
+	private boolean disconnected = false;
+	
 	public EventProcessor(EventInput eventInput, NotificationListener listener,
 			PeakNotificationManager odsNotificationManager, MediaType eventMediaType) {
 		this.eventInput = eventInput;
@@ -64,6 +65,7 @@
 					odsNotificationManager
 							.processException(new NotificationException("Inbound event input stream closed!"));
 				}
+				disconnected = true;
 				return;
 			}
 
@@ -76,9 +78,16 @@
 			} catch (ProcessingException e) {
 				odsNotificationManager
 						.processException(new NotificationException("Cannot deserialize notification event!", e));
+				disconnected = true;
 				return;
 			}
 		}
+		
+		disconnected = true;
+	}
+
+	public boolean isDisconnected() {
+		return disconnected;
 	}
 
 	public void stop() {
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/PeakNotificationManager.java b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/PeakNotificationManager.java
index 5c3976d..37a67b7 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/PeakNotificationManager.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/PeakNotificationManager.java
@@ -18,6 +18,7 @@
 import java.util.Map;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 import javax.ws.rs.client.Client;
@@ -87,6 +88,8 @@
 					.build();
 
 			endpoint = client.target(url).path("events");
+
+			Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> reconnect(), 10, 10, TimeUnit.SECONDS);
 		} catch (Exception e) {
 			throw new NotificationException("Could not create " + PeakNotificationManager.class.getName() + "!", e);
 		}
@@ -123,27 +126,7 @@
 					"Could not create registration at notification service: " + response.readEntity(String.class));
 		}
 
-		try {
-			LOGGER.info("Requesting event input for {}", registration);
-			EventInput eventInput = endpoint.path(registration).request(SseFeature.SERVER_SENT_EVENTS_TYPE)
-					.get(EventInput.class);
-
-			LOGGER.info("Received event input, starting event processor.");
-			EventProcessor processor = new EventProcessor(eventInput, listener, this, MediaType.APPLICATION_JSON_TYPE);
-
-			executor.submit(processor);
-
-			processors.put(registration, processor);
-			LOGGER.info("Event processor started.");
-		} catch (Exception e) {
-			try {
-				deregister(registration);
-			} catch (Exception ex) {
-				LOGGER.error("Exception upon deregistering!");
-			}
-			throw new NotificationException("Could not create event input stream!", e);
-		}
-
+		recreateEventStream(registration, listener);
 	}
 
 	/*
@@ -177,6 +160,55 @@
 		}
 	}
 
+	/**
+	 * Recreates the {@link EventInput}, attaches an {@link EventProcessor} to it
+	 * and stores the {@link EventProcessor} in the processors map.
+	 * 
+	 * @param registration
+	 * @param listener
+	 * @throws NotificationException
+	 */
+	private void recreateEventStream(String registration, NotificationListener listener) throws NotificationException {
+		try {
+			LOGGER.info("Requesting event input for {}", registration);
+			EventInput eventInput = endpoint.path(registration).request(SseFeature.SERVER_SENT_EVENTS_TYPE)
+					.get(EventInput.class);
+
+			LOGGER.info("Received event input, starting event processor.");
+			EventProcessor processor = new EventProcessor(eventInput, listener, this, MediaType.APPLICATION_JSON_TYPE);
+
+			executor.submit(processor);
+
+			processors.put(registration, processor);
+			LOGGER.info("Event processor started.");
+		} catch (Exception e) {
+			try {
+				deregister(registration);
+			} catch (Exception ex) {
+				LOGGER.error("Exception upon deregistering!");
+			}
+			throw new NotificationException("Could not create event input stream!", e);
+		}
+	}
+
+	/**
+	 * Checks if any registered event processor got disconnected and tries to
+	 * recreate the event stream, if necessary.
+	 */
+	private void reconnect() {
+
+		for (Map.Entry<String, EventProcessor> entry : processors.entrySet()) {
+			if (entry.getValue().isDisconnected()) {
+				try {
+					LOGGER.trace("Registration '{}' was disconnected and will be recreated.", entry.getKey());
+					recreateEventStream(entry.getKey(), entry.getValue().getListener());
+				} catch (NotificationException e) {
+					LOGGER.warn("Cannot recreate event stream for registration " + entry.getKey(), e);
+				}
+			}
+		}
+	}
+
 	private void close(String registration) {
 		if (processors.containsKey(registration)) {
 			EventProcessor processor = processors.get(registration);
diff --git a/src/test/java/org/eclipse/mdm/api/odsadapter/ODSRoleTest.java b/src/test/java/org/eclipse/mdm/api/odsadapter/ODSRoleTest.java
index 4e84e9e..8b2a9da 100644
--- a/src/test/java/org/eclipse/mdm/api/odsadapter/ODSRoleTest.java
+++ b/src/test/java/org/eclipse/mdm/api/odsadapter/ODSRoleTest.java
@@ -36,10 +36,11 @@
 import org.eclipse.mdm.api.dflt.model.Role;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
+import org.junit.Ignore;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-//@Ignore
+@Ignore
 // FIXME 10.7.2017: this test needs a running ODS Server, that is not suitable for continous build in Jenkins.
 // Comment this in for local tests only.
 public class ODSRoleTest {