Merge branch 'dev'
diff --git a/build.gradle b/build.gradle
index 45038ed..27d74ee 100644
--- a/build.gradle
+++ b/build.gradle
@@ -81,7 +81,7 @@
 	// testing
 	testCompile 'junit:junit:4.12'
 	testRuntime 'org.slf4j:slf4j-simple:1.7.19'
-	testCompile 'org.mockito:mockito-core:1.+'
+	testCompile 'org.mockito:mockito-core:2.10.0'
 	testCompile 'org.assertj:assertj-core:3.6.2'
 	testCompile(group: 'org.elasticsearch', name: 'elasticsearch', version: '2.3.4')
 	testCompile(group: 'org.elasticsearch', name: 'elasticsearch', version: '2.3.4', classifier: 'tests')
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContext.java b/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContext.java
new file mode 100644
index 0000000..03874c1
--- /dev/null
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContext.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2017 Peak Solution GmbH and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.eclipse.mdm.api.odsadapter;
+
+import java.util.Map;
+import java.util.Optional;
+
+import org.asam.ods.AoException;
+import org.asam.ods.AoSession;
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.file.FileService;
+import org.eclipse.mdm.api.base.notification.NotificationService;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchService;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.eclipse.mdm.api.dflt.EntityManager;
+import org.eclipse.mdm.api.dflt.model.EntityFactory;
+import org.eclipse.mdm.api.odsadapter.filetransfer.CORBAFileService;
+import org.eclipse.mdm.api.odsadapter.filetransfer.Transfer;
+import org.eclipse.mdm.api.odsadapter.lookup.EntityLoader;
+import org.eclipse.mdm.api.odsadapter.notification.ODSNotificationServiceFactory;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityFactory;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.query.ODSQueryService;
+import org.eclipse.mdm.api.odsadapter.search.ODSSearchService;
+import org.omg.CORBA.ORB;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.highqsoft.corbafileserver.generated.CORBAFileServerIF;
+
+/**
+ * ODSContext encapsulates a session to the ASAM ODS CORBA API and 
+ * provides the ODS specific services implementations.
+ *
+ * @since 1.0.0
+ */
+public class ODSContext implements ApplicationContext {
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(ODSContext.class);
+	
+	private Map<String, String> parameters;
+	private final Transfer transfer = Transfer.SOCKET;
+	
+	private CORBAFileServerIF fileServer;
+	private ODSModelManager modelManager;
+	private ODSQueryService queryService;
+	private EntityLoader entityLoader;
+	private ODSEntityManager entityManager;
+	private ODSSearchService searchService;
+	
+	/**
+	 * Creates a new ODS application context.
+	 * @param orb the CORBA ORB used to connect to the ODS API
+	 * @param aoSession
+	 * @param fileServer
+	 * @param parameters
+	 * @throws AoException
+	 */
+	ODSContext(ORB orb, AoSession aoSession, CORBAFileServerIF fileServer, Map<String, String> parameters) throws AoException {
+		this.fileServer = fileServer;
+		this.parameters = parameters;
+		
+		this.modelManager = new ODSModelManager(orb, aoSession);
+		this.queryService = new ODSQueryService(this.modelManager);
+		this.entityManager = new ODSEntityManager(this);
+		this.entityLoader = new EntityLoader(modelManager, queryService);
+		this.searchService = new ODSSearchService(this, queryService, entityLoader);
+		LOGGER.debug("ODSContext initialized.");
+	}
+
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<EntityManager> getEntityManager() {
+		return Optional.of(entityManager);
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<EntityFactory> getEntityFactory() {
+		try {
+			return Optional.of(new ODSEntityFactory(modelManager, entityManager.loadLoggedOnUser().get()));
+		} catch (DataAccessException e) {
+			throw new IllegalStateException("Unable to load instance of the logged in user.");
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<ModelManager> getModelManager() {
+		return Optional.of(modelManager);
+	}
+
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<QueryService> getQueryService() {
+		// TODO
+		// java docs: cache this service for ONE request!
+		return Optional.of(new ODSQueryService(modelManager));
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<SearchService> getSearchService() {
+		return Optional.of(searchService);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<FileService> getFileService() {
+		if (fileServer == null) {
+			return Optional.empty();
+		}
+		return Optional.of(new CORBAFileService(this, transfer));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<NotificationService> getNotificationService() {
+		try {
+			return Optional.of(new ODSNotificationServiceFactory().create(this, parameters));
+		} catch (ConnectionException e) {
+			throw new IllegalStateException("Unable to create notification manager.", e);
+		}
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Map<String, String> getParameters() {
+		return parameters;
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void close() {
+		try {
+			modelManager.close();
+		} catch (AoException e) {
+			LOGGER.warn("Unable to close sesssion due to: " + e.reason, e);
+		}
+	}
+	
+	/**
+	 * Returns the {@link ODSModelManager} used for this context.
+	 * @return the {@link ODSModelManager}
+	 */
+	public ODSModelManager getODSModelManager() {
+		return modelManager;
+	}
+
+	/**
+	 * Returns the {@link AoSession} used for this context.
+	 * @return {@link AoSession} used for this context.
+	 */
+	public AoSession getAoSession() {
+		return modelManager.getAoSession();
+	}
+
+	/**
+	 * Returns the ORB used for this context
+	 * @return ORB used for this context
+	 */
+	public ORB getORB() {
+		return modelManager.getORB();
+	}
+
+	/**
+	 * Returns the {@link CORBAFileServerIF}.
+	 *
+	 * @return The {@code CORBAFileServerIF} is returned or null, if missing.
+	 */
+	public CORBAFileServerIF getFileServer() {
+		return fileServer;
+	}
+
+	/**
+	 * Returns a new {@link ODSContext} with a new ODS co-session.
+	 *
+	 * @return The created {@code ODSContext} is returned.
+	 * @throws AoException
+	 *             Thrown on errors.
+	 */
+	public ODSContext newContext() throws AoException {
+		return new ODSContext(modelManager.getORB(), getAoSession().createCoSession(), fileServer, parameters);
+	}
+}
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManagerFactory.java b/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContextFactory.java
similarity index 91%
rename from src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManagerFactory.java
rename to src/main/java/org/eclipse/mdm/api/odsadapter/ODSContextFactory.java
index 056655a..3ec55f7 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManagerFactory.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContextFactory.java
@@ -1,259 +1,257 @@
-/*

- * Copyright (c) 2016 Gigatronik Ingolstadt GmbH

- * All rights reserved. This program and the accompanying materials

- * are made available under the terms of the Eclipse Public License v1.0

- * which accompanies this distribution, and is available at

- * http://www.eclipse.org/legal/epl-v10.html

- */

-

-package org.eclipse.mdm.api.odsadapter;

-

-import java.util.Map;

-

-import org.asam.ods.AoException;

-import org.asam.ods.AoFactory;

-import org.asam.ods.AoFactoryHelper;

-import org.asam.ods.AoSession;

-import org.eclipse.mdm.api.base.ConnectionException;

-import org.eclipse.mdm.api.base.EntityManagerFactory;

-import org.eclipse.mdm.api.dflt.EntityManager;

-import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;

-import org.omg.CORBA.ORB;

-import org.omg.CORBA.Object;

-import org.omg.CosNaming.NameComponent;

-import org.omg.CosNaming.NamingContextExt;

-import org.omg.CosNaming.NamingContextExtHelper;

-import org.omg.CosNaming.NamingContextPackage.CannotProceed;

-import org.omg.CosNaming.NamingContextPackage.InvalidName;

-import org.omg.CosNaming.NamingContextPackage.NotFound;

-import org.slf4j.Logger;

-import org.slf4j.LoggerFactory;

-

-import com.highqsoft.corbafileserver.generated.CORBAFileServerIF;

-import com.highqsoft.corbafileserver.generated.CORBAFileServerIFHelper;

-

-/**

- * ASAM ODS implementation of the {@link EntityManagerFactory} interface.

- *

- * @since 1.0.0

- * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH

- */

-public class ODSEntityManagerFactory implements EntityManagerFactory<EntityManager> {

-

-	// ======================================================================

-	// Class variables

-	// ======================================================================

-

-	public static final String PARAM_NAMESERVICE = "nameservice";

-

-	public static final String PARAM_SERVICENAME = "servicename";

-

-	public static final String PARAM_USER = "user";

-

-	public static final String PARAM_PASSWORD = "password";

-

-	public static final String PARAM_ELASTIC_SEARCH_URL = "elasticsearch.url";

-

-	private static final String AUTH_TEMPLATE = "USER=%s,PASSWORD=%s,CREATE_COSESSION_ALLOWED=TRUE";

-

-	private static final Logger LOGGER = LoggerFactory.getLogger(ODSEntityManagerFactory.class);

-

-	// ======================================================================

-	// Instance variables

-	// ======================================================================

-

-	private final ORB orb = ORB.init(new String[] {}, System.getProperties());

-

-	// ======================================================================

-	// Public methods

-	// ======================================================================

-

-	public ODSEntityManagerFactory() {

-		LOGGER.debug("Default constructor called.");

-	}

-

-	/**

-	 * {@inheritDoc}

-	 *

-	 * <p>

-	 * <b>Note:</b> Given parameters {@code Map} must contain values for each of

-	 * the following keys:

-	 *

-	 * <ul>

-	 * <li>{@value #PARAM_NAMESERVICE}</li>

-	 * <li>{@value #PARAM_SERVICENAME}</li>

-	 * <li>{@value #PARAM_USER}</li>

-	 * <li>{@value #PARAM_PASSWORD}</li>

-	 * <li>{@value #PARAM_ELASTIC_SEARCH_URL}</li>

-	 * </ul>

-	 *

-	 * Listed names are available via public fields of this class.

-	 */

-	@Override

-	public EntityManager connect(Map<String, String> parameters) throws ConnectionException {

-		AoSession aoSession = null;

-		try (ServiceLocator serviceLocator = new ServiceLocator(orb, getParameter(parameters, PARAM_NAMESERVICE))) {

-			String nameOfService = getParameter(parameters, PARAM_SERVICENAME).replace(".ASAM-ODS", "");

-

-			AoFactory aoFactory = serviceLocator.resolveFactory(nameOfService);

-			LOGGER.info("Connecting to ODS Server ...");

-

-			LOGGER.info("AoFactory name: {}", aoFactory.getName());

-			LOGGER.info("AoFactory description: {}", aoFactory.getDescription());

-			LOGGER.info("AoFactory interface version: {}", aoFactory.getInterfaceVersion());

-			LOGGER.info("AoFactory type: {}", aoFactory.getType());

-

-			aoSession = aoFactory.newSession(String.format(AUTH_TEMPLATE, getParameter(parameters, PARAM_USER),

-					getParameter(parameters, PARAM_PASSWORD)));

-			LOGGER.info("Connection to ODS server established.");

-

-			CORBAFileServerIF fileServer = serviceLocator.resolveFileServer(nameOfService);

-			return new ODSEntityManager(new ODSModelManager(orb, aoSession, fileServer),

-					parameters.get(PARAM_ELASTIC_SEARCH_URL));

-		} catch (AoException e) {

-			closeSession(aoSession);

-			throw new ConnectionException("Unablte to connect to ODS server due to: " + e.reason, e);

-		}

-	}

-

-	// ======================================================================

-	// Private methods

-	// ======================================================================

-

-	/**

-	 * Closes given {@link AoSession} with catching and logging errors.

-	 *

-	 * @param aoSession

-	 *            The {@code AoSession} that shall be closed.

-	 */

-	private static void closeSession(AoSession aoSession) {

-		if (aoSession == null) {

-			return;

-		}

-

-		try {

-			aoSession.close();

-		} catch (AoException e) {

-			LOGGER.warn("Unable to close sesssion due to: " + e.reason, e);

-		}

-	}

-

-	/**

-	 * Reads the property identified by given property name.

-	 *

-	 * @param parameters

-	 *            The properties {@code Map}.

-	 * @param name

-	 *            The property name.

-	 * @return The property value is returned.

-	 * @throws ConnectionException

-	 *             Thrown if property does not exist or is empty.

-	 */

-	private static String getParameter(Map<String, String> parameters, String name) throws ConnectionException {

-		String value = parameters.get(name);

-		if (value == null || value.isEmpty()) {

-			throw new ConnectionException("Connection parameter with name '" + name + "' is either missing or empty.");

-		}

-

-		return value;

-	}

-

-	// ======================================================================

-	// Inner classes

-	// ======================================================================

-

-	/**

-	 * Used to resolve CORBA service object by ID and kind.

-	 */

-	private static final class ServiceLocator implements AutoCloseable {

-

-		// ======================================================================

-		// Instance variables

-		// ======================================================================

-

-		private NamingContextExt namingContext;

-

-		// ======================================================================

-		// Constructors

-		// ======================================================================

-

-		/**

-		 * Constructor.

-		 *

-		 * @param orb

-		 *            The {@link ORB} singleton instance.

-		 * @param path

-		 *            The naming context path.

-		 * @throws ConnectionException

-		 *             Thrown if unable to resolve the naming context.

-		 */

-		public ServiceLocator(ORB orb, String path) throws ConnectionException {

-			namingContext = NamingContextExtHelper.narrow(orb.string_to_object(path));

-			if (namingContext == null) {

-				throw new ConnectionException("Unable to resolve NameService '" + path + "'.");

-			}

-		}

-

-		// ======================================================================

-		// Public methods

-		// ======================================================================

-

-		/**

-		 * Resolves and returns the {@link AoFactory} service for given ID.

-		 *

-		 * @param id

-		 *            Used as identifier.

-		 * @return The {@code AoFactory} is returned.

-		 * @throws ConnectionException

-		 *             Thrown if unable to resolve the {@code

-		 * 		AoFactory}.

-		 */

-		public AoFactory resolveFactory(String id) throws ConnectionException {

-			return AoFactoryHelper.narrow(resolve(id, "ASAM-ODS"));

-		}

-

-		/**

-		 * Resolves and returns the {@link CORBAFileServerIF} service for given

-		 * ID.

-		 *

-		 * @param id

-		 *            Used as identifier.

-		 * @return The {@code CORBAFileServerIF} or null, if none found, is

-		 *         returned.

-		 */

-		public CORBAFileServerIF resolveFileServer(String id) {

-			try {

-				return CORBAFileServerIFHelper.narrow(resolve(id, "CORBA-FT"));

-			} catch (ConnectionException e) {

-				LOGGER.warn(e.getMessage());

-				return null;

-			}

-		}

-

-		/**

-		 * Resolves a CORBA service object for given id and kind.

-		 *

-		 * @param id

-		 *            Used as identifier.

-		 * @param kind

-		 *            Used as qualifier.

-		 * @return The resolved CORBA service object is returned.

-		 * @throws ConnectionException

-		 *             Thrown in case of errors.

-		 */

-		public Object resolve(String id, String kind) throws ConnectionException {

-			try {

-				return namingContext.resolve(new NameComponent[] { new NameComponent(id, kind) });

-			} catch (NotFound | CannotProceed | InvalidName e) {

-				throw new ConnectionException("Unable to resolve service '" + id + "." + kind + "'.", e);

-			}

-		}

-

-		@Override

-		public void close() throws ConnectionException {

-			namingContext._release();

-		}

-

-	}

-

-}

+/*
+ * Copyright (c) 2016 Gigatronik Ingolstadt GmbH and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.eclipse.mdm.api.odsadapter;
+
+import java.util.Map;
+
+import org.asam.ods.AoException;
+import org.asam.ods.AoFactory;
+import org.asam.ods.AoFactoryHelper;
+import org.asam.ods.AoSession;
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.eclipse.mdm.api.dflt.ApplicationContextFactory;
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.Object;
+import org.omg.CosNaming.NameComponent;
+import org.omg.CosNaming.NamingContextExt;
+import org.omg.CosNaming.NamingContextExtHelper;
+import org.omg.CosNaming.NamingContextPackage.CannotProceed;
+import org.omg.CosNaming.NamingContextPackage.InvalidName;
+import org.omg.CosNaming.NamingContextPackage.NotFound;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.highqsoft.corbafileserver.generated.CORBAFileServerIF;
+import com.highqsoft.corbafileserver.generated.CORBAFileServerIFHelper;
+
+/**
+ * ASAM ODS implementation of the {@link ApplicationContextFactory} interface.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public class ODSContextFactory implements ApplicationContextFactory {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	public static final String PARAM_NAMESERVICE = "nameservice";
+
+	public static final String PARAM_SERVICENAME = "servicename";
+
+	public static final String PARAM_USER = "user";
+
+	public static final String PARAM_PASSWORD = "password";
+
+	public static final String PARAM_ELASTIC_SEARCH_URL = "elasticsearch.url";
+
+	private static final String AUTH_TEMPLATE = "USER=%s,PASSWORD=%s,CREATE_COSESSION_ALLOWED=TRUE";
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(ODSContextFactory.class);
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final ORB orb = ORB.init(new String[] {}, System.getProperties());
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	public ODSContextFactory() {
+		LOGGER.debug("Default constructor called.");
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>
+	 * <b>Note:</b> Given parameters {@code Map} must contain values for each of
+	 * the following keys:
+	 *
+	 * <ul>
+	 * <li>{@value #PARAM_NAMESERVICE}</li>
+	 * <li>{@value #PARAM_SERVICENAME}</li>
+	 * <li>{@value #PARAM_USER}</li>
+	 * <li>{@value #PARAM_PASSWORD}</li>
+	 * <li>{@value #PARAM_ELASTIC_SEARCH_URL}</li>
+	 * </ul>
+	 *
+	 * Listed names are available via public fields of this class.
+	 */
+	@Override
+	public ApplicationContext connect(Map<String, String> parameters) throws ConnectionException {
+		AoSession aoSession = null;
+		try (ServiceLocator serviceLocator = new ServiceLocator(orb, getParameter(parameters, PARAM_NAMESERVICE))) {
+			String nameOfService = getParameter(parameters, PARAM_SERVICENAME).replace(".ASAM-ODS", "");
+
+			AoFactory aoFactory = serviceLocator.resolveFactory(nameOfService);
+			LOGGER.info("Connecting to ODS Server ...");
+
+			LOGGER.info("AoFactory name: {}", aoFactory.getName());
+			LOGGER.info("AoFactory description: {}", aoFactory.getDescription());
+			LOGGER.info("AoFactory interface version: {}", aoFactory.getInterfaceVersion());
+			LOGGER.info("AoFactory type: {}", aoFactory.getType());
+
+			aoSession = aoFactory.newSession(String.format(AUTH_TEMPLATE, getParameter(parameters, PARAM_USER),
+					getParameter(parameters, PARAM_PASSWORD)));
+			LOGGER.info("Connection to ODS server established.");
+
+			CORBAFileServerIF fileServer = serviceLocator.resolveFileServer(nameOfService);
+			return new ODSContext(orb, aoSession, fileServer, parameters); 
+		} catch (AoException e) {
+			closeSession(aoSession);
+			throw new ConnectionException("Unable to connect to ODS server due to: " + e.reason, e);
+		}
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Closes given {@link AoSession} with catching and logging errors.
+	 *
+	 * @param aoSession
+	 *            The {@code AoSession} that shall be closed.
+	 */
+	private static void closeSession(AoSession aoSession) {
+		if (aoSession == null) {
+			return;
+		}
+
+		try {
+			aoSession.close();
+		} catch (AoException e) {
+			LOGGER.warn("Unable to close sesssion due to: " + e.reason, e);
+		}
+	}
+
+	/**
+	 * Reads the property identified by given property name.
+	 *
+	 * @param parameters
+	 *            The properties {@code Map}.
+	 * @param name
+	 *            The property name.
+	 * @return The property value is returned.
+	 * @throws ConnectionException
+	 *             Thrown if property does not exist or is empty.
+	 */
+	private static String getParameter(Map<String, String> parameters, String name) throws ConnectionException {
+		String value = parameters.get(name);
+		if (value == null || value.isEmpty()) {
+			throw new ConnectionException("Connection parameter with name '" + name + "' is either missing or empty.");
+		}
+
+		return value;
+	}
+
+	// ======================================================================
+	// Inner classes
+	// ======================================================================
+
+	/**
+	 * Used to resolve CORBA service object by ID and kind.
+	 */
+	private static final class ServiceLocator implements AutoCloseable {
+
+		// ======================================================================
+		// Instance variables
+		// ======================================================================
+
+		private NamingContextExt namingContext;
+
+		// ======================================================================
+		// Constructors
+		// ======================================================================
+
+		/**
+		 * Constructor.
+		 *
+		 * @param orb
+		 *            The {@link ORB} singleton instance.
+		 * @param path
+		 *            The naming context path.
+		 * @throws ConnectionException
+		 *             Thrown if unable to resolve the naming context.
+		 */
+		public ServiceLocator(ORB orb, String path) throws ConnectionException {
+			namingContext = NamingContextExtHelper.narrow(orb.string_to_object(path));
+			if (namingContext == null) {
+				throw new ConnectionException("Unable to resolve NameService '" + path + "'.");
+			}
+		}
+
+		// ======================================================================
+		// Public methods
+		// ======================================================================
+
+		/**
+		 * Resolves and returns the {@link AoFactory} service for given ID.
+		 *
+		 * @param id
+		 *            Used as identifier.
+		 * @return The {@code AoFactory} is returned.
+		 * @throws ConnectionException
+		 *             Thrown if unable to resolve the {@code
+		 * 		AoFactory}.
+		 */
+		public AoFactory resolveFactory(String id) throws ConnectionException {
+			return AoFactoryHelper.narrow(resolve(id, "ASAM-ODS"));
+		}
+
+		/**
+		 * Resolves and returns the {@link CORBAFileServerIF} service for given
+		 * ID.
+		 *
+		 * @param id
+		 *            Used as identifier.
+		 * @return The {@code CORBAFileServerIF} or null, if none found, is
+		 *         returned.
+		 */
+		public CORBAFileServerIF resolveFileServer(String id) {
+			try {
+				return CORBAFileServerIFHelper.narrow(resolve(id, "CORBA-FT"));
+			} catch (ConnectionException e) {
+				LOGGER.warn(e.getMessage());
+				return null;
+			}
+		}
+
+		/**
+		 * Resolves a CORBA service object for given id and kind.
+		 *
+		 * @param id
+		 *            Used as identifier.
+		 * @param kind
+		 *            Used as qualifier.
+		 * @return The resolved CORBA service object is returned.
+		 * @throws ConnectionException
+		 *             Thrown in case of errors.
+		 */
+		public Object resolve(String id, String kind) throws ConnectionException {
+			try {
+				return namingContext.resolve(new NameComponent[] { new NameComponent(id, kind) });
+			} catch (NotFound | CannotProceed | InvalidName e) {
+				throw new ConnectionException("Unable to resolve service '" + id + "." + kind + "'.", e);
+			}
+		}
+
+		@Override
+		public void close() throws ConnectionException {
+			namingContext._release();
+		}
+
+	}
+
+}
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 b62782e..20fd266 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManager.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManager.java
@@ -21,8 +21,9 @@
 import org.asam.ods.AoException;
 import org.asam.ods.InstanceElement;
 import org.eclipse.mdm.api.base.ConnectionException;
-import org.eclipse.mdm.api.base.FileService;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
 import org.eclipse.mdm.api.base.Transaction;
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.massdata.ReadRequest;
 import org.eclipse.mdm.api.base.model.Channel;
 import org.eclipse.mdm.api.base.model.ChannelGroup;
@@ -34,23 +35,17 @@
 import org.eclipse.mdm.api.base.model.MeasuredValues;
 import org.eclipse.mdm.api.base.model.User;
 import org.eclipse.mdm.api.base.query.DataAccessException;
-import org.eclipse.mdm.api.base.query.EntityType;
 import org.eclipse.mdm.api.base.query.Filter;
 import org.eclipse.mdm.api.base.query.JoinType;
-import org.eclipse.mdm.api.base.query.ModelManager;
 import org.eclipse.mdm.api.base.query.Query;
+import org.eclipse.mdm.api.base.query.QueryService;
 import org.eclipse.mdm.api.base.query.Record;
 import org.eclipse.mdm.api.base.query.Result;
-import org.eclipse.mdm.api.base.query.SearchService;
 import org.eclipse.mdm.api.dflt.EntityManager;
-import org.eclipse.mdm.api.dflt.model.EntityFactory;
-import org.eclipse.mdm.api.odsadapter.filetransfer.CORBAFileService;
 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.ODSModelManager;
-import org.eclipse.mdm.api.odsadapter.search.ODSSearchService;
 import org.eclipse.mdm.api.odsadapter.transaction.ODSTransaction;
 import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
 import org.eclipse.mdm.api.odsadapter.utils.ODSUtils;
@@ -74,12 +69,12 @@
 	// ======================================================================
 	// Instance variables
 	// ======================================================================
-
-	private final ODSModelManager modelManager;
-	private final EntityLoader entityLoader;
-
 	private final Transfer transfer = Transfer.SOCKET;
-	private String esHost;
+	
+	private final ODSContext context;
+	private final ODSModelManager odsModelManager;
+	private final QueryService queryService;
+	private final EntityLoader entityLoader;
 
 	// ======================================================================
 	// Constructors
@@ -88,59 +83,21 @@
 	/**
 	 * Constructor.
 	 *
-	 * @param modelManager
-	 *            The {@link ODSModelManager}.
+	 * @param context
+	 *            The {@link ODSContext}.
 	 */
-	public ODSEntityManager(ODSModelManager modelManager, String esHost) {
-		this.modelManager = modelManager;
-		this.esHost = esHost;
-		entityLoader = new EntityLoader(modelManager);
+	public ODSEntityManager(ODSContext context) {
+		this.context = context;
+		this.odsModelManager = context.getODSModelManager();
+		this.queryService = context.getQueryService()
+				.orElseThrow(() -> new ServiceNotProvidedException(QueryService.class));
+		entityLoader = new EntityLoader(odsModelManager, queryService);
 	}
 
 	// ======================================================================
 	// Public methods
 	// ======================================================================
 
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public Optional<EntityFactory> getEntityFactory() {
-		try {
-			return Optional.of(new ODSEntityFactory(modelManager, loadLoggedOnUser().get()));
-		} catch (DataAccessException e) {
-			throw new IllegalStateException("Unable to load instance of the logged in user.");
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public Optional<ModelManager> getModelManager() {
-		return Optional.of(modelManager);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public Optional<SearchService> getSearchService() {
-		// TODO
-		// java docs: cache this service for ONE request!
-		return Optional.of(new ODSSearchService(modelManager, entityLoader, esHost));
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public Optional<FileService> getFileService() {
-		if (modelManager.getFileServer() == null) {
-			return Optional.empty();
-		}
-		return Optional.of(new CORBAFileService(modelManager, transfer));
-	}
 
 	/**
 	 * {@inheritDoc}
@@ -162,7 +119,7 @@
 	public Optional<User> loadLoggedOnUser() throws DataAccessException {
 		InstanceElement ieUser = null;
 		try {
-			ieUser = modelManager.getAoSession().getUser();
+			ieUser = odsModelManager.getAoSession().getUser();
 			return Optional.of(
 					entityLoader.load(new Key<>(User.class), Long.toString(ODSConverter.fromODSLong(ieUser.getId()))));
 		} catch (AoException e) {
@@ -202,14 +159,14 @@
 	 */
 	@Override
 	public <T extends Entity> Optional<T> loadParent(Entity child, Class<T> entityClass) throws DataAccessException {
-		EntityType parentEntityType = modelManager.getEntityType(entityClass);
-		EntityType childEntityType = modelManager.getEntityType(child);
-		Query query = modelManager.createQuery().selectID(parentEntityType);
+		EntityType parentEntityType = odsModelManager.getEntityType(entityClass);
+		EntityType childEntityType = odsModelManager.getEntityType(child);
+		Query query = queryService.createQuery().selectID(parentEntityType);
 
 		if (child instanceof Channel && ChannelGroup.class.equals(entityClass)) {
 			// this covers the gap between channel and channel group via local
 			// column
-			EntityType localColumnEntityType = modelManager.getEntityType("LocalColumn");
+			EntityType localColumnEntityType = odsModelManager.getEntityType("LocalColumn");
 			query.join(childEntityType, localColumnEntityType).join(localColumnEntityType, parentEntityType);
 		} else {
 			query.join(childEntityType, parentEntityType);
@@ -277,14 +234,14 @@
 	@Override
 	public <T extends Entity> List<T> loadChildren(Entity parent, Class<T> entityClass, String pattern)
 			throws DataAccessException {
-		EntityType parentEntityType = modelManager.getEntityType(parent);
-		EntityType childEntityType = modelManager.getEntityType(entityClass);
-		Query query = modelManager.createQuery();
+		EntityType parentEntityType = odsModelManager.getEntityType(parent);
+		EntityType childEntityType = odsModelManager.getEntityType(entityClass);
+		Query query = queryService.createQuery();
 
 		if (parent instanceof ChannelGroup && Channel.class.equals(entityClass)) {
 			// this covers the gap between channel and channel group via local
 			// column
-			EntityType localColumnEntityType = modelManager.getEntityType("LocalColumn");
+			EntityType localColumnEntityType = odsModelManager.getEntityType("LocalColumn");
 			query.join(childEntityType, localColumnEntityType).join(localColumnEntityType, parentEntityType);
 		} else {
 			query.join(childEntityType, parentEntityType);
@@ -326,12 +283,12 @@
 	 */
 	@Override
 	public List<ContextType> loadContextTypes(ContextDescribable contextDescribable) throws DataAccessException {
-		EntityType contextDescribableEntityType = modelManager.getEntityType(contextDescribable);
-		Query query = modelManager.createQuery();
+		EntityType contextDescribableEntityType = odsModelManager.getEntityType(contextDescribable);
+		Query query = queryService.createQuery();
 
 		Map<ContextType, EntityType> contextRootEntityTypes = new EnumMap<>(ContextType.class);
 		for (ContextType contextType : ContextType.values()) {
-			EntityType entityType = modelManager.getEntityType(ContextRoot.class, contextType);
+			EntityType entityType = odsModelManager.getEntityType(ContextRoot.class, contextType);
 			contextRootEntityTypes.put(contextType, entityType);
 			query.join(contextDescribableEntityType.getRelation(entityType), JoinType.OUTER).selectID(entityType);
 		}
@@ -359,12 +316,12 @@
 	@Override
 	public Map<ContextType, ContextRoot> loadContexts(ContextDescribable contextDescribable,
 			ContextType... contextTypes) throws DataAccessException {
-		EntityType contextDescribableEntityType = modelManager.getEntityType(contextDescribable);
-		Query query = modelManager.createQuery();
+		EntityType contextDescribableEntityType = odsModelManager.getEntityType(contextDescribable);
+		Query query = queryService.createQuery();
 
 		Map<ContextType, EntityType> contextRootEntityTypes = new EnumMap<>(ContextType.class);
 		for (ContextType contextType : contextTypes.length == 0 ? ContextType.values() : contextTypes) {
-			EntityType entityType = modelManager.getEntityType(ContextRoot.class, contextType);
+			EntityType entityType = odsModelManager.getEntityType(ContextRoot.class, contextType);
 			contextRootEntityTypes.put(contextType, entityType);
 			query.join(contextDescribableEntityType.getRelation(entityType), JoinType.OUTER).selectID(entityType);
 		}
@@ -392,7 +349,7 @@
 	 */
 	@Override
 	public List<MeasuredValues> readMeasuredValues(ReadRequest readRequest) throws DataAccessException {
-		return new ReadRequestHandler(modelManager).execute(readRequest);
+		return new ReadRequestHandler(odsModelManager).execute(readRequest);
 	}
 
 	/**
@@ -401,22 +358,10 @@
 	@Override
 	public Transaction startTransaction() throws DataAccessException {
 		try {
-			return new ODSTransaction(modelManager, loadEnvironment(), transfer);
+			return new ODSTransaction(context, loadEnvironment(), transfer);
 		} catch (AoException e) {
 			throw new DataAccessException("Unable to start transaction due to: " + e.reason, e);
 		}
 	}
 
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public void close() throws ConnectionException {
-		try {
-			modelManager.close();
-		} catch (AoException e) {
-			throw new ConnectionException("Unable to close the connection to the data source due to: " + e.reason, e);
-		}
-	}
-
 }
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/ODSNotificationManagerFactory.java b/src/main/java/org/eclipse/mdm/api/odsadapter/ODSNotificationManagerFactory.java
deleted file mode 100644
index 7053bd4..0000000
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/ODSNotificationManagerFactory.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package org.eclipse.mdm.api.odsadapter;
-
-import java.util.Map;
-import java.util.Optional;
-
-import javax.ejb.LocalBean;
-import javax.ejb.Stateful;
-
-import org.eclipse.mdm.api.base.BaseEntityManager;
-import org.eclipse.mdm.api.base.ConnectionException;
-import org.eclipse.mdm.api.base.NotificationManagerFactory;
-import org.eclipse.mdm.api.base.model.BaseEntityFactory;
-import org.eclipse.mdm.api.base.notification.NotificationException;
-import org.eclipse.mdm.api.base.notification.NotificationManager;
-import org.eclipse.mdm.api.base.query.ModelManager;
-import org.eclipse.mdm.api.odsadapter.notification.avalon.AvalonNotificationManager;
-import org.eclipse.mdm.api.odsadapter.notification.peak.PeakNotificationManager;
-import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Factory for creating a notification manager.
- * 
- * Currently only supports creating a notification manager for server type
- * 'peak'.
- * 
- * @since 1.0.0
- * @author Matthias Koller, Peak Solution GmbH
- *
- */
-@Stateful
-@LocalBean
-public class ODSNotificationManagerFactory implements NotificationManagerFactory {
-	private static final Logger LOGGER = LoggerFactory.getLogger(ODSNotificationManagerFactory.class);
-
-	public static final String PARAM_SERVER_TYPE = "serverType";
-	public static final String PARAM_URL = "url";
-	public static final String PARAM_EVENT_MEDIATYPE = "eventMimetype";
-	public static final String PARAM_POLLING_INTERVAL = "pollingInterval";
-
-	public static final String SERVER_TYPE_PEAK = "peak";
-	public static final String SERVER_TYPE_AVALON = "avalon";
-
-	public static final String PARAM_NAMESERVICE_URL = "nameserviceURL";
-
-	public NotificationManager create(BaseEntityManager<? extends BaseEntityFactory> entityManager,
-			Map<String, String> parameters) throws ConnectionException {
-		String type = getParameter(parameters, PARAM_SERVER_TYPE);
-
-		Optional<ModelManager> mm = entityManager.getModelManager();
-		if (!mm.isPresent()) {
-			throw new ConnectionException("EntityManager has no ModelManager!");
-		}
-		if (!ODSModelManager.class.isInstance(mm.get())) {
-			throw new ConnectionException("ModelManager is not a ODSModelManager!");
-		}
-
-		if (SERVER_TYPE_PEAK.equalsIgnoreCase(type)) {
-			String url = getParameter(parameters, PARAM_URL);
-			String eventMediaType = getParameter(parameters, PARAM_EVENT_MEDIATYPE);
-
-			LOGGER.info("Connecting to Peak Notification Server ...");
-			LOGGER.info("URL: {}", url);
-			LOGGER.info("Event MediaType: {}", eventMediaType);
-
-			try {
-				return new PeakNotificationManager((ODSModelManager) mm.get(), url, eventMediaType, true);
-			} catch (NotificationException e) {
-				throw new ConnectionException("Could not connect to notification service!", e);
-			}
-		} else if (SERVER_TYPE_AVALON.equalsIgnoreCase(type)) {
-
-			String serviceName = getParameter(parameters, ODSEntityManagerFactory.PARAM_SERVICENAME);
-			serviceName = serviceName.replace(".ASAM-ODS", "");
-			String nameServiceURL = getParameter(parameters, ODSEntityManagerFactory.PARAM_NAMESERVICE);
-
-			LOGGER.info("Connecting to Avalon Notification Server ...");
-			LOGGER.info("Name service URL: {}", nameServiceURL);
-			LOGGER.info("Service name: {}", serviceName);
-
-			long pollingInterval = 500L;
-			try {
-				pollingInterval = Long.parseLong(getParameter(parameters, PARAM_POLLING_INTERVAL));
-			} catch (NumberFormatException | ConnectionException e) {
-				LOGGER.warn("Could not parse parse parameter pollingInterval. Using default value: " + pollingInterval,
-						e);
-			}
-
-			return new AvalonNotificationManager((ODSModelManager) mm.get(), serviceName, nameServiceURL, true,
-					pollingInterval);
-		} else {
-			throw new ConnectionException("Invalid server type. Expected on of: 'peak'");
-		}
-
-	}
-
-	private String getParameter(Map<String, String> parameters, String name) throws ConnectionException {
-		String value = parameters.get(name);
-		if (value == null || value.isEmpty()) {
-			throw new ConnectionException("Connection parameter with name '" + name + "' is either missing or empty.");
-		}
-
-		return value;
-	}
-}
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileServer.java b/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileServer.java
index 13c9d19..c7cdb3c 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileServer.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileServer.java
@@ -18,7 +18,10 @@
 
 import org.asam.ods.AoSession;
 import org.asam.ods.ElemId;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
 import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.odsadapter.ODSContext;
 import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
 import org.omg.CORBA.ORB;
 import org.omg.CORBA.ORBPackage.InvalidName;
@@ -80,10 +83,15 @@
 	 * @param transfer
 	 *            The transfer type for up- and downloads.
 	 */
-	CORBAFileServer(ODSModelManager modelManager, Transfer transfer) {
-		fileServer = modelManager.getFileServer();
-		aoSession = modelManager.getAoSession();
-		orb = modelManager.getORB();
+	CORBAFileServer(ODSContext context, Transfer transfer) {
+		ModelManager mm = context.getModelManager().orElseThrow(() -> new ServiceNotProvidedException(ModelManager.class));
+		if (!(mm instanceof ODSModelManager)) {
+			throw new IllegalArgumentException("The supplied ModelManager must be an ODSModelManager!");
+		}
+		
+		fileServer = context.getFileServer();
+		aoSession = context.getAoSession();
+		orb = context.getORB();
 		this.transfer = transfer;
 
 		bufferSize = getBufferSize();
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileService.java b/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileService.java
index 0ab1058..960eb4c 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileService.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileService.java
@@ -32,11 +32,13 @@
 import java.util.stream.Collectors;
 
 import org.asam.ods.ElemId;
-import org.eclipse.mdm.api.base.FileService;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.file.FileService;
 import org.eclipse.mdm.api.base.model.Entity;
 import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.odsadapter.ODSContext;
 import org.eclipse.mdm.api.odsadapter.query.ODSEntityType;
-import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
 import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -62,8 +64,7 @@
 	// ======================================================================
 
 	private final CORBAFileServer fileServer;
-	private final ODSModelManager modelManager;
-
+	private final ModelManager modelManager;
 	// ======================================================================
 	// Constructors
 	// ======================================================================
@@ -71,14 +72,15 @@
 	/**
 	 * Constructor.
 	 *
-	 * @param modelManager
+	 * @param context
 	 *            Used for {@link Entity} to {@link ElemId} conversion.
 	 * @param transfer
 	 *            The transfer type for up- and downloads.
 	 */
-	public CORBAFileService(ODSModelManager modelManager, Transfer transfer) {
-		this.modelManager = modelManager;
-		fileServer = new CORBAFileServer(modelManager, transfer);
+	public CORBAFileService(ODSContext context, Transfer transfer) {
+		this.modelManager = context.getModelManager().orElseThrow(() -> new ServiceNotProvidedException(ModelManager.class));
+		
+		fileServer = new CORBAFileServer(context, transfer);
 	}
 
 	// ======================================================================
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/TracedInputStream.java b/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/TracedInputStream.java
index 7f1901f..0da2e73 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/TracedInputStream.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/TracedInputStream.java
@@ -11,7 +11,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 
-import org.eclipse.mdm.api.base.FileService.ProgressListener;
+import org.eclipse.mdm.api.base.file.FileService.ProgressListener;
 
 /**
  * This is an {@link InputStream} wrapper implementation to trace the progress
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/ChildRequest.java b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/ChildRequest.java
index 7baa3b5..66e1cc1 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/ChildRequest.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/ChildRequest.java
@@ -6,15 +6,15 @@
 import java.util.List;
 import java.util.Optional;
 
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
 import org.eclipse.mdm.api.base.model.Deletable;
 import org.eclipse.mdm.api.base.model.Entity;
 import org.eclipse.mdm.api.base.query.DataAccessException;
-import org.eclipse.mdm.api.base.query.EntityType;
 import org.eclipse.mdm.api.base.query.Filter;
 import org.eclipse.mdm.api.base.query.ComparisonOperator;
 import org.eclipse.mdm.api.base.query.Query;
 import org.eclipse.mdm.api.base.query.Record;
-import org.eclipse.mdm.api.base.query.Relation;
 import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
 
 /**
@@ -69,7 +69,7 @@
 		Relation parentRelation = entityConfig.getEntityType().getRelation(parent.entityConfig.getEntityType());
 		Relation reflexiveRelation = entityConfig.isReflexive() ? entityType.getRelation(entityType) : null;
 
-		Query query = modelManager.createQuery()
+		Query query = queryService.createQuery()
 				// select entity attributes
 				.selectAll(entityConfig.getEntityType())
 				// select parent entity ID
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityLoader.java b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityLoader.java
index 6179bbb..e8a0916 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityLoader.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityLoader.java
@@ -6,6 +6,7 @@
 
 import org.eclipse.mdm.api.base.model.Entity;
 import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.QueryService;
 import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
 import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
 import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
@@ -23,7 +24,7 @@
 	// ======================================================================
 
 	private final ODSModelManager modelManager;
-
+	private final QueryService queryService;
 	// ======================================================================
 	// Constructors
 	// ======================================================================
@@ -34,8 +35,9 @@
 	 * @param modelManager
 	 *            The {@link ODSModelManager}.
 	 */
-	public EntityLoader(ODSModelManager modelManager) {
+	public EntityLoader(ODSModelManager modelManager, QueryService queryService) {
 		this.modelManager = modelManager;
+		this.queryService = queryService;
 	}
 
 	// ======================================================================
@@ -116,7 +118,7 @@
 		/*
 		 * TODO: add custom request implementations here!
 		 */
-		return new EntityRequest<>(modelManager, modelManager.getEntityConfig(key));
+		return new EntityRequest<>(modelManager, queryService, key);
 	}
 
 }
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityRecord.java b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityRecord.java
index f1ede3f..4c5b243 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityRecord.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityRecord.java
@@ -1,6 +1,6 @@
 package org.eclipse.mdm.api.odsadapter.lookup;
 
-import org.eclipse.mdm.api.base.model.Core;
+import org.eclipse.mdm.api.base.adapter.Core;
 import org.eclipse.mdm.api.base.model.Entity;
 
 /**
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityRequest.java b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityRequest.java
index 6407bb4..c6b53dc 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityRequest.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityRequest.java
@@ -11,24 +11,26 @@
 import java.util.Set;
 import java.util.stream.Stream;
 
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.adapter.Relation;
 import org.eclipse.mdm.api.base.model.ContextComponent;
 import org.eclipse.mdm.api.base.model.ContextSensor;
 import org.eclipse.mdm.api.base.model.ContextType;
 import org.eclipse.mdm.api.base.model.Deletable;
 import org.eclipse.mdm.api.base.model.Entity;
 import org.eclipse.mdm.api.base.query.DataAccessException;
-import org.eclipse.mdm.api.base.query.EntityType;
 import org.eclipse.mdm.api.base.query.Filter;
-import org.eclipse.mdm.api.base.query.ModelManager;
 import org.eclipse.mdm.api.base.query.ComparisonOperator;
 import org.eclipse.mdm.api.base.query.Query;
+import org.eclipse.mdm.api.base.query.QueryService;
 import org.eclipse.mdm.api.base.query.Record;
-import org.eclipse.mdm.api.base.query.Relation;
 import org.eclipse.mdm.api.base.query.Result;
 import org.eclipse.mdm.api.dflt.model.TemplateAttribute;
 import org.eclipse.mdm.api.dflt.model.TemplateComponent;
 import org.eclipse.mdm.api.dflt.model.TemplateSensor;
 import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
 import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
 
 /**
@@ -46,8 +48,8 @@
 	// Instance variables
 	// ======================================================================
 
-	final ModelManager modelManager;
-
+	final ODSModelManager odsModelManager;
+	final QueryService queryService;
 	final EntityConfig<T> entityConfig;
 	final EntityResult<T> entityResult = new EntityResult<>(this);
 
@@ -67,9 +69,10 @@
 	 * @param config
 	 *            The {@link EntityConfig}.
 	 */
-	public EntityRequest(ModelManager modelManager, EntityConfig<T> config) {
-		this.modelManager = modelManager;
-		this.entityConfig = config;
+	public EntityRequest(ODSModelManager modelManager, QueryService queryService, Key<T> key) {
+		this.odsModelManager = modelManager;
+		this.queryService = queryService;
+		this.entityConfig = modelManager.getEntityConfig(key);
 		cache = new Cache();
 	}
 
@@ -82,7 +85,8 @@
 	 *            The {@link EntityConfig}.
 	 */
 	protected EntityRequest(EntityRequest<?> parentRequest, EntityConfig<T> entityConfig) {
-		modelManager = parentRequest.modelManager;
+		odsModelManager = parentRequest.odsModelManager;
+		queryService = parentRequest.queryService;
 		cache = parentRequest.cache;
 		this.entityConfig = entityConfig;
 	}
@@ -123,6 +127,10 @@
 
 		return load(Filter.idsOnly(entityConfig.getEntityType(), instanceIDs)).getSortedEntities();
 	}
+	
+	public ODSModelManager getODSModelManager() {
+		return odsModelManager;
+	}
 
 	// ======================================================================
 	// Protected methods
@@ -252,7 +260,7 @@
 		EntityType entityType = entityConfig.getEntityType();
 		Relation reflexiveRelation = entityConfig.isReflexive() ? entityType.getRelation(entityType) : null;
 
-		Query query = modelManager.createQuery().selectAll(entityConfig.getEntityType());
+		Query query = queryService.createQuery().selectAll(entityConfig.getEntityType());
 
 		if (entityConfig.isReflexive()) {
 			query.select(reflexiveRelation.getAttribute());
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityResult.java b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityResult.java
index 0ad1498..c1ab377 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityResult.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityResult.java
@@ -1,11 +1,9 @@
 package org.eclipse.mdm.api.odsadapter.lookup;
 
-import static org.eclipse.mdm.api.dflt.model.CatalogAttribute.VATTR_ENUMERATION_CLASS;
+import static org.eclipse.mdm.api.dflt.model.CatalogAttribute.VATTR_ENUMERATION_NAME;
 import static org.eclipse.mdm.api.dflt.model.CatalogAttribute.VATTR_SCALAR_TYPE;
 import static org.eclipse.mdm.api.dflt.model.CatalogAttribute.VATTR_SEQUENCE;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -15,19 +13,20 @@
 import java.util.Optional;
 import java.util.stream.Collectors;
 
-import org.eclipse.mdm.api.base.model.Core;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.DefaultCore;
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.Deletable;
 import org.eclipse.mdm.api.base.model.Entity;
 import org.eclipse.mdm.api.base.model.EnumRegistry;
 import org.eclipse.mdm.api.base.model.Enumeration;
 import org.eclipse.mdm.api.base.model.Value;
 import org.eclipse.mdm.api.base.model.ValueType;
-import org.eclipse.mdm.api.base.query.Attribute;
-import org.eclipse.mdm.api.base.query.DefaultCore;
-import org.eclipse.mdm.api.base.query.EntityType;
 import org.eclipse.mdm.api.base.query.Record;
 import org.eclipse.mdm.api.dflt.model.CatalogAttribute;
 import org.eclipse.mdm.api.dflt.model.CatalogComponent;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityFactory;
 
 /**
  * Container for entities by executing an {@link EntityRequest}.
@@ -91,7 +90,7 @@
 
 	/**
 	 * Creates an {@link EntityRecord} for given {@link Record} using given
-	 * parent {@code EntityRecord} and mapps it internally by its instance ID.
+	 * parent {@code EntityRecord} and maps it internally by its instance ID.
 	 *
 	 * @param parentRecord
 	 *            The created {@code EntityRecord} will be related as a child
@@ -165,14 +164,14 @@
 	 *            The {@code CatalogAttribute} {@code Core}.
 	 */
 	private void adjustCatalogAttributeCore(Entity catalogComponent, Core catalogAttributeCore) {
-		EntityType entityType = request.modelManager.getEntityType(catalogComponent.getName());
+		EntityType entityType = request.odsModelManager.getEntityType(catalogComponent.getName());
 		Attribute attribute = entityType.getAttribute(catalogAttributeCore.getValues().get(Entity.ATTR_NAME).extract());
 
 		Map<String, Value> values = catalogAttributeCore.getValues();
-		Value enumerationClass = ValueType.STRING.create(VATTR_ENUMERATION_CLASS);
-		values.put(VATTR_ENUMERATION_CLASS, enumerationClass);
+		Value enumerationName = ValueType.STRING.create(VATTR_ENUMERATION_NAME);
+		values.put(VATTR_ENUMERATION_NAME, enumerationName);
 		if (attribute.getValueType().isEnumerationType()) {
-			enumerationClass.set(attribute.getEnumObj().getName());
+			enumerationName.set(attribute.getEnumObj().getName());
 		}
 
 		Enumeration<?> scalarTypeObj=EnumRegistry.getInstance().get("ScalarType");
@@ -192,24 +191,12 @@
 	 * @return The created {@link EntityRecord} is returned.
 	 */
 	private EntityRecord<T> create(Core core) {
-		Constructor<T> constructor = null;
-		boolean isAccessible = false;
-		try {
-			constructor = request.entityConfig.getEntityClass().getDeclaredConstructor(Core.class);
-			isAccessible = constructor.isAccessible();
-			constructor.setAccessible(true);
-			EntityRecord<T> entityRecord = new EntityRecord<>(constructor.newInstance(core), core);
-			entityRecords.put(core.getID(), entityRecord);
-			entities.add(entityRecord.entity);
-			return entityRecord;
-		} catch (InstantiationException | IllegalAccessException | NoSuchMethodException
-				| InvocationTargetException e) {
-			throw new IllegalStateException(e.getMessage(), e);
-		} finally {
-			if (constructor != null) {
-				constructor.setAccessible(isAccessible);
-			}
-		}
+		ODSEntityFactory odsEntityFactory = new ODSEntityFactory(request.getODSModelManager(), null);
+		EntityRecord<T> entityRecord = new EntityRecord<>(
+				odsEntityFactory.createEntity(request.entityConfig.getEntityClass(), core), core);
+		entityRecords.put(core.getID(), entityRecord);
+		entities.add(entityRecord.entity);
+		return entityRecord;
 	}
 
 }
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/RelationConfig.java b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/RelationConfig.java
index 8df3de6..a2dee0d 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/RelationConfig.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/RelationConfig.java
@@ -6,10 +6,10 @@
 import java.util.Map;
 import java.util.Optional;
 
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
 import org.eclipse.mdm.api.base.model.Entity;
-import org.eclipse.mdm.api.base.query.EntityType;
 import org.eclipse.mdm.api.base.query.Record;
-import org.eclipse.mdm.api.base.query.Relation;
 import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
 
 /**
@@ -69,7 +69,7 @@
 		if (relatedEntityID.isPresent()) {
 			dependants.computeIfAbsent(relatedEntityID.get(), k -> new ArrayList<>()).add(entityRecord);
 		} else if (mandatory) {
-			throw new IllegalStateException("Mandatory relation unsatisfied.");
+			throw new IllegalStateException("Mandatory relation unsatisfied for relation "+relation.getName());
 		}
 	}
 
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfig.java b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfig.java
index fdb39a9..29683eb 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfig.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfig.java
@@ -7,11 +7,11 @@
 import java.util.Objects;
 import java.util.Optional;
 
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.ContextType;
 import org.eclipse.mdm.api.base.model.Deletable;
 import org.eclipse.mdm.api.base.model.Entity;
 import org.eclipse.mdm.api.base.model.StatusAttachable;
-import org.eclipse.mdm.api.base.query.EntityType;
 
 /**
  * Describes the composition of an {@link Entity} with its mandatory, optional
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfigRepository.java b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfigRepository.java
index 4bec31a..b48f46a 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfigRepository.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfigRepository.java
@@ -4,10 +4,10 @@
 import java.util.Map;
 import java.util.Optional;
 
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.ContextComponent;
 import org.eclipse.mdm.api.base.model.ContextRoot;
 import org.eclipse.mdm.api.base.model.Entity;
-import org.eclipse.mdm.api.base.query.EntityType;
 import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
 
 /**
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/NotificationEntityLoader.java b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/NotificationEntityLoader.java
index c976faa..63f5d41 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/NotificationEntityLoader.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/NotificationEntityLoader.java
@@ -5,6 +5,7 @@
 import java.util.List;
 import java.util.stream.Collectors;
 
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.ContextComponent;
 import org.eclipse.mdm.api.base.model.ContextDescribable;
 import org.eclipse.mdm.api.base.model.ContextRoot;
@@ -12,9 +13,9 @@
 import org.eclipse.mdm.api.base.model.Measurement;
 import org.eclipse.mdm.api.base.model.TestStep;
 import org.eclipse.mdm.api.base.query.DataAccessException;
-import org.eclipse.mdm.api.base.query.EntityType;
 import org.eclipse.mdm.api.base.query.Filter;
 import org.eclipse.mdm.api.base.query.JoinType;
+import org.eclipse.mdm.api.base.query.QueryService;
 import org.eclipse.mdm.api.base.query.ComparisonOperator;
 import org.eclipse.mdm.api.base.query.Record;
 import org.eclipse.mdm.api.odsadapter.lookup.EntityLoader;
@@ -29,13 +30,15 @@
 	private static final Logger LOGGER = LoggerFactory.getLogger(NotificationEntityLoader.class);
 
 	private final ODSModelManager modelManager;
+	private final QueryService queryService;
 	private final EntityLoader loader;
 
 	private boolean loadContextDescribable;
 
-	public NotificationEntityLoader(ODSModelManager modelManager, boolean loadContextDescribable) {
+	public NotificationEntityLoader(ODSModelManager modelManager, QueryService queryService, boolean loadContextDescribable) {
 		this.modelManager = modelManager;
-		this.loader = new EntityLoader(modelManager);
+		this.queryService =  queryService;
+		this.loader = new EntityLoader(modelManager, queryService);
 		this.loadContextDescribable = loadContextDescribable;
 	}
 
@@ -101,12 +104,12 @@
 		final EntityType testStep = modelManager.getEntityType(TestStep.class);
 		final EntityType measurement = modelManager.getEntityType(Measurement.class);
 
-		List<String> testStepIDs = modelManager.createQuery().selectID(testStep)
+		List<String> testStepIDs = queryService.createQuery().selectID(testStep)
 				.join(testStep.getRelation(contextRoot), JoinType.OUTER)
 				.fetch(Filter.and().add(ComparisonOperator.IN_SET.create(contextRoot.getIDAttribute(), ids)))
 				.stream().map(r -> r.getRecord(testStep)).map(Record::getID).collect(Collectors.toList());
 
-		List<String> measurementIDs = modelManager.createQuery().selectID(measurement)
+		List<String> measurementIDs = queryService.createQuery().selectID(measurement)
 				.join(measurement.getRelation(contextRoot), JoinType.OUTER)
 				.fetch(Filter.and().add(ComparisonOperator.IN_SET.create(contextRoot.getIDAttribute(), ids)))
 				.stream().map(r -> r.getRecord(measurement)).map(Record::getID).collect(Collectors.toList());
@@ -138,13 +141,13 @@
 		final EntityType testStep = modelManager.getEntityType(TestStep.class);
 		final EntityType measurement = modelManager.getEntityType(Measurement.class);
 
-		List<String> testStepIDs = modelManager.createQuery().selectID(testStep)
+		List<String> testStepIDs = queryService.createQuery().selectID(testStep)
 				.join(testStep.getRelation(contextRoot), JoinType.OUTER)
 				.join(contextRoot.getRelation(contextComponent), JoinType.OUTER)
 				.fetch(Filter.and().add(ComparisonOperator.IN_SET.create(contextComponent.getIDAttribute(), ids)))
 				.stream().map(r -> r.getRecord(testStep)).map(Record::getID).collect(Collectors.toList());
 
-		List<String> measurementIDs = modelManager.createQuery().selectID(measurement)
+		List<String> measurementIDs = queryService.createQuery().selectID(measurement)
 				.join(measurement.getRelation(contextRoot), JoinType.OUTER)
 				.join(contextRoot.getRelation(contextComponent), JoinType.OUTER)
 				.fetch(Filter.and().add(ComparisonOperator.IN_SET.create(contextComponent.getIDAttribute(), ids)))
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/ODSNotificationServiceFactory.java b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/ODSNotificationServiceFactory.java
new file mode 100644
index 0000000..3f64d9b
--- /dev/null
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/ODSNotificationServiceFactory.java
@@ -0,0 +1,96 @@
+package org.eclipse.mdm.api.odsadapter.notification;
+
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.notification.NotificationException;
+import org.eclipse.mdm.api.base.notification.NotificationService;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.eclipse.mdm.api.odsadapter.ODSContextFactory;
+import org.eclipse.mdm.api.odsadapter.notification.avalon.AvalonNotificationManager;
+import org.eclipse.mdm.api.odsadapter.notification.peak.PeakNotificationManager;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Factory for creating a notification service.
+ * 
+ * @since 1.0.0
+ * @author Matthias Koller, Peak Solution GmbH
+ *
+ */
+public class ODSNotificationServiceFactory {
+	private static final Logger LOGGER = LoggerFactory.getLogger(ODSNotificationServiceFactory.class);
+
+	public static final String PARAM_SERVER_TYPE = "freetext.notificationType";
+	public static final String PARAM_URL = "freetext.notificationUrl";
+	public static final String PARAM_POLLING_INTERVAL = "freetext.pollingInterval";
+
+	public static final String SERVER_TYPE_PEAK = "peak";
+	public static final String SERVER_TYPE_AVALON = "avalon";
+
+	public static final String PARAM_NAMESERVICE_URL = "nameserviceURL";
+	
+	public NotificationService create(ApplicationContext context, Map<String, String> parameters) throws ConnectionException {
+		String type = getParameter(parameters, PARAM_SERVER_TYPE);
+
+		ModelManager mm = context.getModelManager()
+				.orElseThrow(() -> new ServiceNotProvidedException(ModelManager.class));
+		
+		QueryService queryService = context.getQueryService()
+				.orElseThrow(() -> new ServiceNotProvidedException(QueryService.class));
+		
+		if (!ODSModelManager.class.isInstance(mm)) {
+			throw new ConnectionException("ModelManager is not a ODSModelManager!");
+		}
+
+		if (SERVER_TYPE_PEAK.equalsIgnoreCase(type)) {
+			String url = getParameter(parameters, PARAM_URL);
+			
+			LOGGER.info("Connecting to Peak Notification Server ...");
+			LOGGER.info("URL: {}", url);
+
+			try {
+				return new PeakNotificationManager((ODSModelManager) mm, queryService, url, true);
+			} catch (NotificationException e) {
+				throw new ConnectionException("Could not connect to notification service!", e);
+			}
+		} else if (SERVER_TYPE_AVALON.equalsIgnoreCase(type)) {
+
+			String serviceName = getParameter(parameters, ODSContextFactory.PARAM_SERVICENAME);
+			serviceName = serviceName.replace(".ASAM-ODS", "");
+			String nameServiceURL = getParameter(parameters, ODSContextFactory.PARAM_NAMESERVICE);
+
+			LOGGER.info("Connecting to Avalon Notification Server ...");
+			LOGGER.info("Name service URL: {}", nameServiceURL);
+			LOGGER.info("Service name: {}", serviceName);
+
+			long pollingInterval = 500L;
+			try {
+				pollingInterval = Long.parseLong(getParameter(parameters, PARAM_POLLING_INTERVAL));
+			} catch (NumberFormatException | ConnectionException e) {
+				LOGGER.warn("Could not parse parse parameter pollingInterval. Using default value: " + pollingInterval,
+						e);
+			}
+
+			return new AvalonNotificationManager((ODSModelManager) mm, queryService, serviceName, nameServiceURL, true,
+					pollingInterval);
+		} else {
+			throw new ConnectionException("Invalid server type. Expected on of: 'peak'");
+		}
+
+	}
+
+	private String getParameter(Map<String, String> parameters, String name) throws ConnectionException {
+		String value = parameters.get(name);
+		if (value == null || value.isEmpty()) {
+			throw new ConnectionException("Connection parameter with name '" + name + "' is either missing or empty.");
+		}
+
+		return value;
+	}
+}
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/AvalonNotificationManager.java b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/AvalonNotificationManager.java
index ba66a74..6233afc 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/AvalonNotificationManager.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/AvalonNotificationManager.java
@@ -12,6 +12,7 @@
 import java.util.stream.Collectors;
 
 import org.asam.ods.T_LONGLONG;
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.ContextComponent;
 import org.eclipse.mdm.api.base.model.ContextDescribable;
 import org.eclipse.mdm.api.base.model.ContextRoot;
@@ -20,9 +21,9 @@
 import org.eclipse.mdm.api.base.notification.NotificationFilter;
 import org.eclipse.mdm.api.base.notification.NotificationFilter.ModificationType;
 import org.eclipse.mdm.api.base.notification.NotificationListener;
-import org.eclipse.mdm.api.base.notification.NotificationManager;
+import org.eclipse.mdm.api.base.notification.NotificationService;
 import org.eclipse.mdm.api.base.query.DataAccessException;
-import org.eclipse.mdm.api.base.query.EntityType;
+import org.eclipse.mdm.api.base.query.QueryService;
 import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
 import org.eclipse.mdm.api.odsadapter.notification.NotificationEntityLoader;
 import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
@@ -46,7 +47,7 @@
  * @author Matthias Koller, Peak Solution GmbH
  *
  */
-public class AvalonNotificationManager implements NotificationManager {
+public class AvalonNotificationManager implements NotificationService {
 
 	private static final Logger LOGGER = LoggerFactory.getLogger(AvalonNotificationManager.class);
 
@@ -78,13 +79,13 @@
 	 * @param pollingInterval
 	 *            polling interval in milleseconds
 	 */
-	public AvalonNotificationManager(ODSModelManager modelManager, String serviceName, String nameServiceURL,
+	public AvalonNotificationManager(ODSModelManager modelManager, QueryService queryService, String serviceName, String nameServiceURL,
 			boolean loadContextDescribable, long pollingInterval) {
 		this.modelManager = modelManager;
 		this.serviceName = serviceName;
 		this.nameServiceURL = nameServiceURL;
 		this.pollingInterval = pollingInterval;
-		loader = new NotificationEntityLoader(modelManager, loadContextDescribable);
+		loader = new NotificationEntityLoader(modelManager, queryService, loadContextDescribable);
 	}
 
 	@Override
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 68b41cf..42ec47c 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
@@ -13,12 +13,13 @@
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.User;
 import org.eclipse.mdm.api.base.notification.NotificationException;
 import org.eclipse.mdm.api.base.notification.NotificationFilter;
 import org.eclipse.mdm.api.base.notification.NotificationListener;
-import org.eclipse.mdm.api.base.notification.NotificationManager;
-import org.eclipse.mdm.api.base.query.EntityType;
+import org.eclipse.mdm.api.base.notification.NotificationService;
+import org.eclipse.mdm.api.base.query.QueryService;
 import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
 import org.eclipse.mdm.api.odsadapter.notification.NotificationEntityLoader;
 import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
@@ -28,7 +29,6 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Strings;
 import com.peaksolution.ods.notification.protobuf.NotificationProtos.Notification;
 
 /**
@@ -39,7 +39,7 @@
  * @author Matthias Koller, Peak Solution GmbH
  *
  */
-public class PeakNotificationManager implements NotificationManager {
+public class PeakNotificationManager implements NotificationService {
 
 	private static final Logger LOGGER = LoggerFactory.getLogger(PeakNotificationManager.class);
 
@@ -50,7 +50,6 @@
 
 	private final ExecutorService executor = Executors.newCachedThreadPool();
 
-	private final MediaType eventMediaType;
 	private final ODSModelManager modelManager;
 
 	private final NotificationEntityLoader loader;
@@ -59,8 +58,6 @@
 	 * @param modelManager
 	 * @param url
 	 *            URL of the notification plugin
-	 * @param eventMediaType
-	 *            MediaType to use.
 	 * @param loadContextDescribable
 	 *            if true, the corresponding context describable is loaded if a
 	 *            notification for a context root or context component is
@@ -69,19 +66,13 @@
 	 *             Thrown if the manager cannot connect to the notification
 	 *             server.
 	 */
-	public PeakNotificationManager(ODSModelManager modelManager, String url, String eventMediaType,
+	public PeakNotificationManager(ODSModelManager modelManager, QueryService queryService, String url,
 			boolean loadContextDescribable) throws NotificationException {
 		this.modelManager = modelManager;
-		loader = new NotificationEntityLoader(modelManager, loadContextDescribable);
+		loader = new NotificationEntityLoader(modelManager, queryService, loadContextDescribable);
 
 		try {
-			if (Strings.isNullOrEmpty(eventMediaType) || MediaType.APPLICATION_JSON.equalsIgnoreCase(eventMediaType)) {
-				this.eventMediaType = MediaType.APPLICATION_JSON_TYPE;
-			} else {
-				this.eventMediaType = ProtobufMessageBodyProvider.APPLICATION_PROTOBUF_TYPE;
-			}
-
-			client = ClientBuilder.newBuilder().register(SseFeature.class).register(ProtobufMessageBodyProvider.class)
+			client = ClientBuilder.newBuilder().register(SseFeature.class)
 					.register(JsonMessageBodyProvider.class).build();
 
 			endpoint = client.target(url).path("events");
@@ -101,14 +92,16 @@
 	@Override
 	public void register(String registration, NotificationFilter filter, NotificationListener listener)
 			throws NotificationException {
-		LOGGER.info("Starting registration for with name: " + registration);
+		LOGGER.info("Starting registration for with name: {}", registration);
 		
 		Response response = endpoint.path(registration).request().post(javax.ws.rs.client.Entity
-				.entity(ProtobufConverter.from(filter), ProtobufMessageBodyProvider.APPLICATION_PROTOBUF_TYPE));
+				.entity(ProtobufConverter.from(filter), MediaType.APPLICATION_JSON_TYPE));
 
 		if (response.getStatusInfo().getStatusCode() == Status.CONFLICT.getStatusCode()) {
-			LOGGER.info("A registration with the name already exists: " + response.readEntity(String.class));
-			LOGGER.info("Trying to reregister...");
+			if (LOGGER.isInfoEnabled()) {
+				LOGGER.info("A registration with the name already exists: {}", response.readEntity(String.class));
+				LOGGER.info("Trying to reregister...");
+			}
 			deregister(registration);
 			LOGGER.info("Deregisteration successful.");
 			register(registration, filter, listener);
@@ -121,13 +114,13 @@
 		}
 
 		try {
-			LOGGER.info("Requesting event input for " + registration);
+			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, eventMediaType);
+			EventProcessor processor = new EventProcessor(eventInput, listener, this, MediaType.APPLICATION_JSON_TYPE);
 
 			executor.submit(processor);
 
@@ -166,10 +159,10 @@
 
 		for (String registration : processors.keySet()) {
 			if (isDeregisterAll) {
-				LOGGER.debug("Deregistering '" + registration + "'.");
+				LOGGER.debug("Deregistering '{}'.", registration);
 				deregister(registration);
 			} else {
-				LOGGER.debug("Disconnecting '" + registration + "'.");
+				LOGGER.debug("Disconnecting '{}'.", registration);
 				close(registration);
 			}
 		}
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/ProtobufMessageBodyProvider.java b/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/ProtobufMessageBodyProvider.java
deleted file mode 100644
index 4fc177e..0000000
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/ProtobufMessageBodyProvider.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package org.eclipse.mdm.api.odsadapter.notification.peak;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.lang.reflect.Type;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.Produces;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-
-import com.google.protobuf.GeneratedMessage;
-import com.google.protobuf.Message;
-
-/**
- * MessageBodyProvider for handling protobuf payloads.
- * 
- * @since 1.0.0
- * @author Matthias Koller, Peak Solution GmbH
- *
- */
-@Provider
-@Consumes(ProtobufMessageBodyProvider.APPLICATION_PROTOBUF)
-@Produces(ProtobufMessageBodyProvider.APPLICATION_PROTOBUF)
-public class ProtobufMessageBodyProvider implements MessageBodyReader<Message>, MessageBodyWriter<Message> {
-	/**
-	 * application/x-protobuf
-	 */
-	public final static String APPLICATION_PROTOBUF = "application/x-protobuf";
-
-	/**
-	 * application/x-protobuf
-	 */
-	public final static MediaType APPLICATION_PROTOBUF_TYPE = new MediaType("application", "x-protobuf");
-
-	@Override
-	public boolean isReadable(final Class<?> type, final Type genericType, final Annotation[] annotations,
-			final MediaType mediaType) {
-		return Message.class.isAssignableFrom(type);
-	}
-
-	@Override
-	public Message readFrom(final Class<Message> type, final Type genericType, final Annotation[] annotations,
-			final MediaType mediaType, final MultivaluedMap<String, String> httpHeaders, final InputStream entityStream)
-			throws IOException {
-
-		try {
-			final Method newBuilder = type.getMethod("newBuilder");
-			final GeneratedMessage.Builder<?> builder = (GeneratedMessage.Builder<?>) newBuilder.invoke(type);
-
-			return builder.mergeFrom(entityStream).build();
-		} catch (Exception e) {
-			throw new WebApplicationException(e);
-		}
-	}
-
-	@Override
-	public long getSize(final Message m, final Class<?> type, final Type genericType, final Annotation[] annotations,
-			final MediaType mediaType) {
-		return m.getSerializedSize();
-	}
-
-	@Override
-	public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations,
-			final MediaType mediaType) {
-		return Message.class.isAssignableFrom(type);
-	}
-
-	@Override
-	public void writeTo(final Message m, final Class<?> type, final Type genericType, final Annotation[] annotations,
-			final MediaType mediaType, final MultivaluedMap<String, Object> httpHeaders,
-			final OutputStream entityStream) throws IOException {
-		m.writeTo(entityStream);
-	}
-}
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSAttribute.java b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSAttribute.java
index ca8a946..769aaef 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSAttribute.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSAttribute.java
@@ -14,11 +14,11 @@
 
 import org.asam.ods.ApplAttr;
 import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
 import org.eclipse.mdm.api.base.model.Enumeration;
 import org.eclipse.mdm.api.base.model.ValueType;
-import org.eclipse.mdm.api.base.query.Attribute;
-import org.eclipse.mdm.api.base.query.EntityType;
-import org.eclipse.mdm.api.base.query.Relation;
 import org.eclipse.mdm.api.odsadapter.utils.ODSUtils;
 
 /**
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSEntityFactory.java b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSEntityFactory.java
index 3f093b5..f609cd8 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSEntityFactory.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSEntityFactory.java
@@ -8,19 +8,26 @@
 
 package org.eclipse.mdm.api.odsadapter.query;
 
-import static org.eclipse.mdm.api.dflt.model.CatalogAttribute.VATTR_ENUMERATION_CLASS;
+import static org.eclipse.mdm.api.dflt.model.CatalogAttribute.VATTR_ENUMERATION_NAME;
 import static org.eclipse.mdm.api.dflt.model.CatalogAttribute.VATTR_SCALAR_TYPE;
 import static org.eclipse.mdm.api.dflt.model.CatalogAttribute.VATTR_SEQUENCE;
 
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
 import java.util.HashSet;
 import java.util.Optional;
 import java.util.Set;
 
+import org.eclipse.mdm.api.base.adapter.ChildrenStore;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.DefaultCore;
+import org.eclipse.mdm.api.base.adapter.EntityStore;
 import org.eclipse.mdm.api.base.model.AxisType;
+import org.eclipse.mdm.api.base.model.BaseEntity;
 import org.eclipse.mdm.api.base.model.ContextType;
-import org.eclipse.mdm.api.base.model.Core;
 import org.eclipse.mdm.api.base.model.Entity;
 import org.eclipse.mdm.api.base.model.EnumRegistry;
+import org.eclipse.mdm.api.base.model.Enumeration;
 import org.eclipse.mdm.api.base.model.EnumerationValue;
 import org.eclipse.mdm.api.base.model.Interpolation;
 import org.eclipse.mdm.api.base.model.ScalarType;
@@ -29,7 +36,6 @@
 import org.eclipse.mdm.api.base.model.User;
 import org.eclipse.mdm.api.base.model.ValueType;
 import org.eclipse.mdm.api.base.model.VersionState;
-import org.eclipse.mdm.api.base.query.DefaultCore;
 import org.eclipse.mdm.api.dflt.model.CatalogAttribute;
 import org.eclipse.mdm.api.dflt.model.EntityFactory;
 import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
@@ -81,6 +87,55 @@
 		this.modelManager = modelManager;
 		this.loggedInUser = loggedInUser;
 	}
+	
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Extracts the {@link Core} from an {@link Entity} instance. This method
+	 * effectively makes access to the Core of a BaseEntity publicly
+	 * available (by calling the corresponding protected method of
+	 * BaseEntityFactory, which is this class's superclass) to users of
+	 * ODSEntityFactory. 
+	 * 
+	 * @param entity
+	 *            The {@link Entity} from which to extract the {@link Core}.
+	 * @return The entity's {@link Core}.
+	 */
+	public static Core extract(Entity entity) {
+		if (entity instanceof BaseEntity) {
+			return getCore((BaseEntity) entity);
+		} else {
+			throw new IllegalArgumentException("Entity of type '" + entity.getClass().getSimpleName()
+					+ "' does not extend '" + BaseEntity.class.getName() + "'");
+		}
+	}
+
+	/**
+	 * Create an instance of a class implementing the {@link Entity} interface with
+	 * core as the instance's {@link Core}. This method effectively makes the
+	 * protected BaseEntity constructor publicly available (by calling the
+	 * corresponding protected method of BaseEntityFactory, which is this class's
+	 * superclass) to users of ODSEntityFactory.
+	 * 
+	 * @param clazz
+	 *            The class to instantiate, must implement the {@link Entity}
+	 *            interface.
+	 * @param core
+	 *            The {@link Core} to use for the newly created instance.
+	 * @return The newly created instance.
+	 */
+	@SuppressWarnings("unchecked")
+	public <T extends Entity> T createEntity(Class<T> clazz, Core core) {
+		if (BaseEntity.class.isAssignableFrom(clazz)) {
+			return (T) createBaseEntity(clazz.asSubclass(BaseEntity.class), core);
+		} else {
+			throw new IllegalArgumentException(
+					"Class '" + clazz.getSimpleName() + "' does not extend '" + BaseEntity.class.getName() + "'");
+		}
+
+	}
 
 	// ======================================================================
 	// Protected methods
@@ -109,6 +164,27 @@
 	protected <T extends Entity> Core createCore(Class<T> entityClass, ContextType contextType) {
 		return createCore(new Key<>(entityClass, contextType));
 	}
+		
+	/**
+	 * {@inheritDoc}
+	 */
+	public static final EntityStore getMutableStore(BaseEntity entity) {
+		return EntityFactory.getMutableStore(entity);
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	public static final EntityStore getPermanentStore(BaseEntity entity) {
+		return EntityFactory.getPermanentStore(entity);
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	public static final ChildrenStore getChildrenStore(BaseEntity entity) {
+		return EntityFactory.getChildrenStore(entity);
+	}
 
 	/**
 	 * {@inheritDoc}
@@ -130,16 +206,29 @@
 	 * {@inheritDoc}
 	 */
 	@Override
-	protected void validateEnum(Class<? extends EnumerationValue> enumClass) {
-		if (ENUM_CLASSES.contains(enumClass)) {
-			// given enumeration class is a default one, which is always
-			// supported
-			return;
+	protected void validateEnum(Enumeration<?> enumerationObj) {
+		EnumRegistry er = EnumRegistry.getInstance();
+		// check if enum is properly registered
+        if (er.get(enumerationObj.getName())==null) {
+		  throw new IllegalArgumentException("Given enum class '" + enumerationObj.getName() + "' is not supported.");
+        }
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected <T extends BaseEntity> T createBaseEntity(Class<T> clazz, Core core) {
+		try {
+			Constructor<T> constructor = clazz.getDeclaredConstructor(Core.class);
+			try {
+				return constructor.newInstance(core);
+			} catch (IllegalAccessException exc) {
+				return super.createBaseEntity(clazz, core);
+			}
+		} catch (NoSuchMethodException | InvocationTargetException | InstantiationException exc) {
+			throw new IllegalStateException(exc.getMessage(), exc);
 		}
-
-		// TODO check here for other enumeration classes introduced by modules
-
-		throw new IllegalArgumentException("Given enum class '" + enumClass.getSimpleName() + "' is not supported.");
 	}
 
 	// ======================================================================
@@ -161,12 +250,11 @@
 		core.getValues().get(Entity.ATTR_MIMETYPE).set(entityConfig.getMimeType());
 
 		if (CatalogAttribute.class.equals(entityConfig.getEntityClass())) {
-			core.getValues().put(VATTR_ENUMERATION_CLASS, ValueType.STRING.create(VATTR_ENUMERATION_CLASS));
+			core.getValues().put(VATTR_ENUMERATION_NAME, ValueType.STRING.create(VATTR_ENUMERATION_NAME));
 			core.getValues().put(VATTR_SCALAR_TYPE, ValueType.ENUMERATION.create(EnumRegistry.getInstance().get("ScalarType"), VATTR_SCALAR_TYPE));
 			core.getValues().put(VATTR_SEQUENCE, ValueType.BOOLEAN.create(VATTR_SEQUENCE));
 		}
 
 		return core;
 	}
-
 }
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSEntityType.java b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSEntityType.java
index 6fc22c6..44cdb96 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSEntityType.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSEntityType.java
@@ -26,11 +26,11 @@
 
 import org.asam.ods.ApplElem;
 import org.asam.ods.T_LONGLONG;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.adapter.RelationType;
 import org.eclipse.mdm.api.base.model.Enumeration;
-import org.eclipse.mdm.api.base.query.Attribute;
-import org.eclipse.mdm.api.base.query.EntityType;
-import org.eclipse.mdm.api.base.query.Relation;
-import org.eclipse.mdm.api.base.query.RelationType;
 import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
 
 /**
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSModelManager.java b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSModelManager.java
index 4d26e93..4a2df93 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSModelManager.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSModelManager.java
@@ -39,6 +39,9 @@
 import org.asam.ods.SelItem;

 import org.asam.ods.SelOrder;

 import org.asam.ods.T_LONGLONG;

+import org.eclipse.mdm.api.base.adapter.EntityType;

+import org.eclipse.mdm.api.base.adapter.ModelManager;

+import org.eclipse.mdm.api.base.adapter.Relation;

 import org.eclipse.mdm.api.base.model.Channel;

 import org.eclipse.mdm.api.base.model.ChannelGroup;

 import org.eclipse.mdm.api.base.model.ContextComponent;

@@ -59,10 +62,6 @@
 import org.eclipse.mdm.api.base.model.TestStep;

 import org.eclipse.mdm.api.base.model.Unit;

 import org.eclipse.mdm.api.base.model.User;

-import org.eclipse.mdm.api.base.query.EntityType;

-import org.eclipse.mdm.api.base.query.ModelManager;

-import org.eclipse.mdm.api.base.query.Query;

-import org.eclipse.mdm.api.base.query.Relation;

 import org.eclipse.mdm.api.dflt.model.CatalogAttribute;

 import org.eclipse.mdm.api.dflt.model.CatalogComponent;

 import org.eclipse.mdm.api.dflt.model.CatalogSensor;

@@ -89,8 +88,6 @@
 import org.slf4j.Logger;

 import org.slf4j.LoggerFactory;

 

-import com.highqsoft.corbafileserver.generated.CORBAFileServerIF;

-

 /**

  * ODS implementation of the {@link ModelManager} interface.

  *

@@ -99,19 +96,11 @@
  */

 public class ODSModelManager implements ModelManager {

 

-	// ======================================================================

-	// Class variables

-	// ======================================================================

-

 	private static final Logger LOGGER = LoggerFactory.getLogger(ODSModelManager.class);

 

-	// ======================================================================

-	// Instance variables

-	// ======================================================================

-

 	private final Map<String, EntityType> entityTypesByName = new HashMap<>();

 

-	private final CORBAFileServerIF fileServer;

+	

 	private final ORB orb;

 

 	private final Lock write;

@@ -122,10 +111,6 @@
 	private ApplElemAccess applElemAccess;

 	private AoSession aoSession;

 

-	// ======================================================================

-	// Constructors

-	// ======================================================================

-

 	/**

 	 * Constructor.

 	 *

@@ -133,13 +118,10 @@
 	 *            Used to activate CORBA service objects.

 	 * @param aoSession

 	 *            The underlying ODS session.

-	 * @param fileServer

-	 *            Used for file transfers.

 	 * @throws AoException

 	 *             Thrown on errors.

 	 */

-	public ODSModelManager(ORB orb, AoSession aoSession, CORBAFileServerIF fileServer) throws AoException {

-		this.fileServer = fileServer;

+	public ODSModelManager(ORB orb, AoSession aoSession) throws AoException {

 		this.aoSession = aoSession;

 		this.orb = orb;

 		applElemAccess = aoSession.getApplElemAccess();

@@ -149,34 +131,9 @@
 		write = reentrantReadWriteLock.writeLock();

 		read = reentrantReadWriteLock.readLock();

 

-		// initialization

 		initialize();

 	}

 

-	// ======================================================================

-	// Public methods

-	// ======================================================================

-

-	/**

-	 * Returns a new {@link ODSModelManager} with a new ODS co-session.

-	 *

-	 * @return The created {@code ODSModelManager} is returned.

-	 * @throws AoException

-	 *             Thrown on errors.

-	 */

-	public ODSModelManager newSession() throws AoException {

-		return new ODSModelManager(orb, getAoSession().createCoSession(), fileServer);

-	}

-

-	/**

-	 * Returns the {@link CORBAFileServerIF}.

-	 *

-	 * @return The {@code CORBAFileServerIF} is returned or null, if missing.

-	 */

-	public CORBAFileServerIF getFileServer() {

-		return fileServer;

-	}

-

 	/**

 	 * Returns the {@link ORB}.

 	 *

@@ -246,20 +203,6 @@
 	 * {@inheritDoc}

 	 */

 	@Override

-	public Query createQuery() {

-		read.lock();

-

-		try {

-			return new ODSQuery(getApplElemAccess());

-		} finally {

-			read.unlock();

-		}

-	}

-

-	/**

-	 * {@inheritDoc}

-	 */

-	@Override

 	public List<EntityType> listEntityTypes() {

 		read.lock();

 

@@ -405,10 +348,6 @@
 		}

 	}

 

-	// ======================================================================

-	// Private methods

-	// ======================================================================

-

 	/**

 	 * Initializes this model manager by caching the application model and

 	 * loading the {@link EntityConfig}s.

@@ -440,10 +379,9 @@
 				Enumeration<ODSEnum> enumdyn = new Enumeration<>(ODSEnum.class, eas.enumName);

 				EnumerationDefinition enumdef = applicationStructure.getEnumerationDefinition(eas.enumName);

 				String[] listItemNames = enumdef.listItemNames();

-				int ordinal = 0;

 				for (String item : listItemNames) {

+					int ordinal=enumdef.getItem(item);

 					enumdyn.addValue(new ODSEnum(item, ordinal));

-					ordinal++;

 				}

 				er.add(eas.enumName, enumdyn);

 			}

diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSQuery.java b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSQuery.java
index 0571d24..507265e 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSQuery.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSQuery.java
@@ -34,18 +34,18 @@
 import org.asam.ods.SelOrder;
 import org.asam.ods.SelValueExt;
 import org.asam.ods.T_LONGLONG;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
 import org.eclipse.mdm.api.base.model.Value;
 import org.eclipse.mdm.api.base.query.Aggregation;
-import org.eclipse.mdm.api.base.query.Attribute;
 import org.eclipse.mdm.api.base.query.Condition;
 import org.eclipse.mdm.api.base.query.DataAccessException;
-import org.eclipse.mdm.api.base.query.EntityType;
 import org.eclipse.mdm.api.base.query.Filter;
 import org.eclipse.mdm.api.base.query.FilterItem;
 import org.eclipse.mdm.api.base.query.JoinType;
 import org.eclipse.mdm.api.base.query.Query;
 import org.eclipse.mdm.api.base.query.Record;
-import org.eclipse.mdm.api.base.query.Relation;
 import org.eclipse.mdm.api.base.query.Result;
 import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
 import org.eclipse.mdm.api.odsadapter.utils.ODSUtils;
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSQueryService.java b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSQueryService.java
new file mode 100644
index 0000000..9e3a607
--- /dev/null
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSQueryService.java
@@ -0,0 +1,21 @@
+package org.eclipse.mdm.api.odsadapter.query;

+

+import org.eclipse.mdm.api.base.query.Query;

+import org.eclipse.mdm.api.base.query.QueryService;

+

+public class ODSQueryService implements QueryService {

+

+	private ODSModelManager modelManager;

+	

+	public ODSQueryService(ODSModelManager modelManager) {

+		this.modelManager = modelManager;

+	}

+	

+	/**

+	 * {@inheritDoc}

+	 */

+	@Override

+	public Query createQuery() {

+		return new ODSQuery(modelManager.getApplElemAccess());

+	}

+}

diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSRelation.java b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSRelation.java
index e200a1a..4da0adc 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSRelation.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSRelation.java
@@ -13,10 +13,10 @@
 import org.asam.ods.ApplAttr;
 import org.asam.ods.ApplRel;
 import org.asam.ods.DataType;
-import org.eclipse.mdm.api.base.query.Attribute;
-import org.eclipse.mdm.api.base.query.EntityType;
-import org.eclipse.mdm.api.base.query.Relation;
-import org.eclipse.mdm.api.base.query.RelationType;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.adapter.RelationType;
 import org.eclipse.mdm.api.odsadapter.utils.ODSUtils;
 
 /**
@@ -25,7 +25,7 @@
  * @since 1.0.0
  * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
  */
-final class ODSRelation implements Relation {
+public final class ODSRelation implements Relation {
 
 	// ======================================================================
 	// Instance variables
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/search/BaseEntitySearchQuery.java b/src/main/java/org/eclipse/mdm/api/odsadapter/search/BaseEntitySearchQuery.java
index b0e74f8..d299469 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/search/BaseEntitySearchQuery.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/search/BaseEntitySearchQuery.java
@@ -19,6 +19,9 @@
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
 import org.eclipse.mdm.api.base.model.ContextRoot;
 import org.eclipse.mdm.api.base.model.ContextType;
 import org.eclipse.mdm.api.base.model.Entity;
@@ -26,17 +29,15 @@
 import org.eclipse.mdm.api.base.model.TestStep;
 import org.eclipse.mdm.api.base.model.Value;
 import org.eclipse.mdm.api.base.query.Aggregation;
-import org.eclipse.mdm.api.base.query.Attribute;
 import org.eclipse.mdm.api.base.query.DataAccessException;
-import org.eclipse.mdm.api.base.query.EntityType;
 import org.eclipse.mdm.api.base.query.Filter;
 import org.eclipse.mdm.api.base.query.FilterItem;
 import org.eclipse.mdm.api.base.query.JoinType;
 import org.eclipse.mdm.api.base.query.Query;
-import org.eclipse.mdm.api.base.query.Relation;
+import org.eclipse.mdm.api.base.query.QueryService;
 import org.eclipse.mdm.api.base.query.Result;
-import org.eclipse.mdm.api.base.query.SearchQuery;
-import org.eclipse.mdm.api.base.query.Searchable;
+import org.eclipse.mdm.api.base.search.SearchQuery;
+import org.eclipse.mdm.api.base.search.Searchable;
 import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
 import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
 import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
@@ -60,7 +61,7 @@
 	private final Class<? extends Entity> entityClass;
 
 	private final ODSModelManager modelManager;
-
+	private final QueryService queryService;
 	// ======================================================================
 	// Constructors
 	// ======================================================================
@@ -75,9 +76,10 @@
 	 * @param rootEntityClass
 	 *            The root entity class of this search query.
 	 */
-	protected BaseEntitySearchQuery(ODSModelManager modelManager, Class<? extends Entity> entityClass,
+	protected BaseEntitySearchQuery(ODSModelManager modelManager, QueryService queryService, Class<? extends Entity> entityClass,
 			Class<? extends Entity> rootEntityClass) {
 		this.modelManager = modelManager;
+		this.queryService = queryService;
 		this.entityClass = entityClass;
 		this.rootEntityClass = rootEntityClass;
 
@@ -131,7 +133,7 @@
 	 */
 	@Override
 	public final List<Value> getFilterValues(Attribute attribute, Filter filter) throws DataAccessException {
-		Query query = modelManager.createQuery().select(attribute, Aggregation.DISTINCT).group(attribute);
+		Query query = queryService.createQuery().select(attribute, Aggregation.DISTINCT).group(attribute);
 
 		// add required joins
 		filter.stream().filter(FilterItem::isCondition).map(FilterItem::getCondition).forEach(c -> {
@@ -146,7 +148,7 @@
 	 */
 	@Override
 	public final List<Result> fetchComplete(List<EntityType> entityTypes, Filter filter) throws DataAccessException {
-		Query query = modelManager.createQuery().selectID(modelManager.getEntityType(entityClass));
+		Query query = queryService.createQuery().selectID(modelManager.getEntityType(entityClass));
 
 		// add required joins
 		entityTypes.stream().forEach(entityType -> {
@@ -162,7 +164,7 @@
 	 */
 	@Override
 	public final List<Result> fetch(List<Attribute> attributes, Filter filter) throws DataAccessException {
-		Query query = modelManager.createQuery().selectID(modelManager.getEntityType(entityClass));
+		Query query = queryService.createQuery().selectID(modelManager.getEntityType(entityClass));
 
 		// add required joins
 		attributes.stream().forEach(attribute -> {
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/search/ChannelGroupSearchQuery.java b/src/main/java/org/eclipse/mdm/api/odsadapter/search/ChannelGroupSearchQuery.java
index b551c55..4dc8110 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/search/ChannelGroupSearchQuery.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/search/ChannelGroupSearchQuery.java
@@ -8,13 +8,14 @@
 
 package org.eclipse.mdm.api.odsadapter.search;
 
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.Channel;
 import org.eclipse.mdm.api.base.model.ChannelGroup;
 import org.eclipse.mdm.api.base.model.Measurement;
 import org.eclipse.mdm.api.base.model.Test;
 import org.eclipse.mdm.api.base.model.TestStep;
-import org.eclipse.mdm.api.base.query.EntityType;
-import org.eclipse.mdm.api.base.query.SearchQuery;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchQuery;
 import org.eclipse.mdm.api.dflt.model.Pool;
 import org.eclipse.mdm.api.dflt.model.Project;
 import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
@@ -37,8 +38,8 @@
 	 * @param contextState
 	 *            The {@link ContextState}.
 	 */
-	ChannelGroupSearchQuery(ODSModelManager modelManager, ContextState contextState) {
-		super(modelManager, ChannelGroup.class, Project.class);
+	ChannelGroupSearchQuery(ODSModelManager modelManager, QueryService queryService, ContextState contextState) {
+		super(modelManager, queryService, ChannelGroup.class, Project.class);
 
 		// layers
 		addJoinConfig(JoinConfig.up(Pool.class, Project.class));
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/search/ChannelSearchQuery.java b/src/main/java/org/eclipse/mdm/api/odsadapter/search/ChannelSearchQuery.java
index c8e22fa..320be56 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/search/ChannelSearchQuery.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/search/ChannelSearchQuery.java
@@ -8,13 +8,14 @@
 
 package org.eclipse.mdm.api.odsadapter.search;
 
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.Channel;
 import org.eclipse.mdm.api.base.model.ChannelGroup;
 import org.eclipse.mdm.api.base.model.Measurement;
 import org.eclipse.mdm.api.base.model.Test;
 import org.eclipse.mdm.api.base.model.TestStep;
-import org.eclipse.mdm.api.base.query.EntityType;
-import org.eclipse.mdm.api.base.query.SearchQuery;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchQuery;
 import org.eclipse.mdm.api.dflt.model.Pool;
 import org.eclipse.mdm.api.dflt.model.Project;
 import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
@@ -36,8 +37,8 @@
 	 * @param contextState
 	 *            The {@link ContextState}.
 	 */
-	ChannelSearchQuery(ODSModelManager modelManager, ContextState contextState) {
-		super(modelManager, Channel.class, Project.class);
+	ChannelSearchQuery(ODSModelManager modelManager, QueryService queryService, ContextState contextState) {
+		super(modelManager, queryService, Channel.class, Project.class);
 
 		// layers
 		addJoinConfig(JoinConfig.up(Pool.class, Project.class));
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/search/JoinTree.java b/src/main/java/org/eclipse/mdm/api/odsadapter/search/JoinTree.java
index 8c8e885..1918b80 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/search/JoinTree.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/search/JoinTree.java
@@ -8,10 +8,10 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.Entity;
-import org.eclipse.mdm.api.base.query.EntityType;
 import org.eclipse.mdm.api.base.query.JoinType;
-import org.eclipse.mdm.api.base.query.SearchQuery;
+import org.eclipse.mdm.api.base.search.SearchQuery;
 
 /**
  * This class spans a dependency tree for conditional join statements is
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/search/MeasurementSearchQuery.java b/src/main/java/org/eclipse/mdm/api/odsadapter/search/MeasurementSearchQuery.java
index 538be58..298e20e 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/search/MeasurementSearchQuery.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/search/MeasurementSearchQuery.java
@@ -8,13 +8,14 @@
 
 package org.eclipse.mdm.api.odsadapter.search;
 
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.Channel;
 import org.eclipse.mdm.api.base.model.ChannelGroup;
 import org.eclipse.mdm.api.base.model.Measurement;
 import org.eclipse.mdm.api.base.model.Test;
 import org.eclipse.mdm.api.base.model.TestStep;
-import org.eclipse.mdm.api.base.query.EntityType;
-import org.eclipse.mdm.api.base.query.SearchQuery;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchQuery;
 import org.eclipse.mdm.api.dflt.model.Pool;
 import org.eclipse.mdm.api.dflt.model.Project;
 import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
@@ -37,8 +38,8 @@
 	 * @param contextState
 	 *            The {@link ContextState}.
 	 */
-	MeasurementSearchQuery(ODSModelManager modelManager, ContextState contextState) {
-		super(modelManager, Measurement.class, Project.class);
+	MeasurementSearchQuery(ODSModelManager modelManager, QueryService queryService, ContextState contextState) {
+		super(modelManager, queryService, Measurement.class, Project.class);
 
 		// layers
 		addJoinConfig(JoinConfig.up(Pool.class, Project.class));
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/search/MergedSearchQuery.java b/src/main/java/org/eclipse/mdm/api/odsadapter/search/MergedSearchQuery.java
index 1dc797d..a67e365 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/search/MergedSearchQuery.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/search/MergedSearchQuery.java
@@ -17,14 +17,14 @@
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.Value;
-import org.eclipse.mdm.api.base.query.Attribute;
 import org.eclipse.mdm.api.base.query.DataAccessException;
-import org.eclipse.mdm.api.base.query.EntityType;
 import org.eclipse.mdm.api.base.query.Filter;
 import org.eclipse.mdm.api.base.query.Result;
-import org.eclipse.mdm.api.base.query.SearchQuery;
-import org.eclipse.mdm.api.base.query.Searchable;
+import org.eclipse.mdm.api.base.search.SearchQuery;
+import org.eclipse.mdm.api.base.search.Searchable;
 
 /**
  * Merges 2 distinct search queries, where one queries context data as ordered
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchService.java b/src/main/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchService.java
index 2edaaf6..af80d3a 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchService.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchService.java
@@ -15,6 +15,8 @@
 import java.util.Map;
 import java.util.function.Function;
 
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.Channel;
 import org.eclipse.mdm.api.base.model.ChannelGroup;
 import org.eclipse.mdm.api.base.model.Entity;
@@ -23,16 +25,16 @@
 import org.eclipse.mdm.api.base.model.Test;
 import org.eclipse.mdm.api.base.model.TestStep;
 import org.eclipse.mdm.api.base.model.Value;
-import org.eclipse.mdm.api.base.query.Attribute;
 import org.eclipse.mdm.api.base.query.DataAccessException;
-import org.eclipse.mdm.api.base.query.EntityType;
 import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.QueryService;
 import org.eclipse.mdm.api.base.query.Result;
-import org.eclipse.mdm.api.base.query.SearchQuery;
-import org.eclipse.mdm.api.base.query.SearchService;
-import org.eclipse.mdm.api.base.query.Searchable;
+import org.eclipse.mdm.api.base.search.SearchQuery;
+import org.eclipse.mdm.api.base.search.SearchService;
+import org.eclipse.mdm.api.base.search.Searchable;
 import org.eclipse.mdm.api.dflt.model.Pool;
 import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.odsadapter.ODSContext;
 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.ODSModelManager;
@@ -50,31 +52,33 @@
 
 	private final Map<Class<? extends Entity>, SearchQuery> searchQueries = new HashMap<>();
 
-	private final ODSModelManager modelManager;
+	private final ODSContext context;
 	private final EntityLoader entityLoader;
 	private final String esHost;
 	private ODSFreeTextSearch freeTextSearch;
 
+	public static final String PARAM_ELASTIC_SEARCH_URL = "elasticsearch.url";
+
 	/**
 	 * Constructor.
 	 *
-	 * @param modelManager
-	 *            Used to retrieve {@link EntityType}s.
+	 * @param context
+	 *            Used to retrieve {@link ODSModelManager}.
 	 * @param entityLoader
 	 *            Used to load complete {@link Entity}s.
 	 */
-	public ODSSearchService(ODSModelManager modelManager, EntityLoader entityLoader, String host) {
-		this.modelManager = modelManager;
+	public ODSSearchService(ODSContext context, QueryService queryService, EntityLoader entityLoader) {
+		this.context = context;
 		this.entityLoader = entityLoader;
-		esHost = host;
-
-		registerMergedSearchQuery(Project.class, c -> new ProjectSearchQuery(modelManager, c));
-		registerMergedSearchQuery(Pool.class, c -> new PoolSearchQuery(modelManager, c));
-		registerMergedSearchQuery(Test.class, c -> new TestSearchQuery(modelManager, c));
-		registerMergedSearchQuery(TestStep.class, c -> new TestStepSearchQuery(modelManager, c));
-		registerMergedSearchQuery(Measurement.class, c -> new MeasurementSearchQuery(modelManager, c));
-		registerMergedSearchQuery(ChannelGroup.class, c -> new ChannelGroupSearchQuery(modelManager, c));
-		registerMergedSearchQuery(Channel.class, c -> new ChannelSearchQuery(modelManager, c));
+		esHost = context.getParameters().get(PARAM_ELASTIC_SEARCH_URL);
+		
+		registerMergedSearchQuery(Project.class, c -> new ProjectSearchQuery(context.getODSModelManager(), queryService, c));
+		registerMergedSearchQuery(Pool.class, c -> new PoolSearchQuery(context.getODSModelManager(), queryService, c));
+		registerMergedSearchQuery(Test.class, c -> new TestSearchQuery(context.getODSModelManager(), queryService, c));
+		registerMergedSearchQuery(TestStep.class, c -> new TestStepSearchQuery(context.getODSModelManager(), queryService, c));
+		registerMergedSearchQuery(Measurement.class, c -> new MeasurementSearchQuery(context.getODSModelManager(), queryService, c));
+		registerMergedSearchQuery(ChannelGroup.class, c -> new ChannelGroupSearchQuery(context.getODSModelManager(), queryService, c));
+		registerMergedSearchQuery(Channel.class, c -> new ChannelSearchQuery(context.getODSModelManager(), queryService, c));
 	}
 
 	/**
@@ -114,7 +118,7 @@
 	 * {@inheritDoc}
 	 */
 	@Override
-	public <T extends Entity> Map<T, Result> fetchComplete(Class<T> entityClass, List<EntityType> entityTypes,
+	public <T extends Entity> List<T> fetchComplete(Class<T> entityClass, List<EntityType> entityTypes,
 			Filter filter) throws DataAccessException {
 		return createResult(entityClass, findSearchQuery(entityClass).fetchComplete(entityTypes, filter));
 	}
@@ -123,7 +127,7 @@
 	 * {@inheritDoc}
 	 */
 	@Override
-	public <T extends Entity> Map<T, Result> fetch(Class<T> entityClass, List<Attribute> attributes, Filter filter)
+	public <T extends Entity> List<T> fetch(Class<T> entityClass, List<Attribute> attributes, Filter filter)
 			throws DataAccessException {
 		return createResult(entityClass, findSearchQuery(entityClass).fetch(attributes, filter));
 	}
@@ -139,7 +143,7 @@
 			return Collections.emptyList();
 		}
 
-		EntityType entityType = modelManager.getEntityType(entityClass);
+		EntityType entityType = context.getODSModelManager().getEntityType(entityClass);
 		Map<String, Result> recordsByEntityID = new HashMap<>();
 		for (Result result : findSearchQuery(entityClass).fetch(attributes, mergedFilter)) {
 			recordsByEntityID.put(result.getRecord(entityType).getID(), result);
@@ -229,7 +233,7 @@
 		Filter freeTextResultsFilter = Filter.or();
 		for (Map.Entry<Class<? extends Entity>, List<String>> entry : fetchIds(query).entrySet()) {
 			if (!entry.getValue().isEmpty()) {
-				freeTextResultsFilter.ids(modelManager.getEntityType(entry.getKey()), entry.getValue());
+				freeTextResultsFilter.ids(context.getODSModelManager().getEntityType(entry.getKey()), entry.getValue());
 			}
 		}
 
@@ -245,14 +249,13 @@
 	 *            Entity class of the loaded {@code Entity}s.
 	 * @param results
 	 *            The queried {@code Result}s.
-	 * @return All Results are returned in a Map, which maps entities to the
-	 *         corresponding results.
+	 * @return All loaded entities are returned as a {@link List}.
 	 * @throws DataAccessException
 	 *             Thrown if unable to load the {@code Entity}s.
 	 */
-	private <T extends Entity> Map<T, Result> createResult(Class<T> entityClass, List<Result> results)
+	private <T extends Entity> List<T> createResult(Class<T> entityClass, List<Result> results)
 			throws DataAccessException {
-		EntityType entityType = modelManager.getEntityType(entityClass);
+		EntityType entityType = context.getODSModelManager().getEntityType(entityClass);
 		Map<String, Result> recordsByEntityID = new HashMap<>();
 		for (Result result : results) {
 			recordsByEntityID.put(result.getRecord(entityType).getID(), result);
@@ -263,7 +266,7 @@
 			resultsByEntity.put(entity, recordsByEntityID.get(entity.getID()));
 		}
 
-		return resultsByEntity;
+		return new ArrayList<>(resultsByEntity.keySet());
 	}
 
 	/**
@@ -293,7 +296,7 @@
 	 */
 	private void registerMergedSearchQuery(Class<? extends Entity> entityClass,
 			Function<ContextState, BaseEntitySearchQuery> factory) {
-		searchQueries.put(entityClass, new MergedSearchQuery(modelManager.getEntityType(entityClass), factory));
+		searchQueries.put(entityClass, new MergedSearchQuery(context.getODSModelManager().getEntityType(entityClass), factory));
 	}
 
 	private void initFreetextSearch() throws DataAccessException {
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/search/PoolSearchQuery.java b/src/main/java/org/eclipse/mdm/api/odsadapter/search/PoolSearchQuery.java
index 4878e2f..b31d952 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/search/PoolSearchQuery.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/search/PoolSearchQuery.java
@@ -8,13 +8,14 @@
 
 package org.eclipse.mdm.api.odsadapter.search;
 
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.Channel;
 import org.eclipse.mdm.api.base.model.ChannelGroup;
 import org.eclipse.mdm.api.base.model.Measurement;
 import org.eclipse.mdm.api.base.model.Test;
 import org.eclipse.mdm.api.base.model.TestStep;
-import org.eclipse.mdm.api.base.query.EntityType;
-import org.eclipse.mdm.api.base.query.SearchQuery;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchQuery;
 import org.eclipse.mdm.api.dflt.model.Pool;
 import org.eclipse.mdm.api.dflt.model.Project;
 import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
@@ -36,8 +37,8 @@
 	 * @param contextState
 	 *            The {@link ContextState}.
 	 */
-	PoolSearchQuery(ODSModelManager modelManager, ContextState contextState) {
-		super(modelManager, Pool.class, Project.class);
+	PoolSearchQuery(ODSModelManager modelManager, QueryService queryService, ContextState contextState) {
+		super(modelManager, queryService, Pool.class, Project.class);
 
 		// layers
 		addJoinConfig(JoinConfig.up(Pool.class, Project.class));
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/search/ProjectSearchQuery.java b/src/main/java/org/eclipse/mdm/api/odsadapter/search/ProjectSearchQuery.java
index 54e3a74..6a2c0fa 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/search/ProjectSearchQuery.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/search/ProjectSearchQuery.java
@@ -8,13 +8,14 @@
 
 package org.eclipse.mdm.api.odsadapter.search;
 
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.Channel;
 import org.eclipse.mdm.api.base.model.ChannelGroup;
 import org.eclipse.mdm.api.base.model.Measurement;
 import org.eclipse.mdm.api.base.model.Test;
 import org.eclipse.mdm.api.base.model.TestStep;
-import org.eclipse.mdm.api.base.query.EntityType;
-import org.eclipse.mdm.api.base.query.SearchQuery;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchQuery;
 import org.eclipse.mdm.api.dflt.model.Pool;
 import org.eclipse.mdm.api.dflt.model.Project;
 import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
@@ -36,8 +37,8 @@
 	 * @param contextState
 	 *            The {@link ContextState}.
 	 */
-	ProjectSearchQuery(ODSModelManager modelManager, ContextState contextState) {
-		super(modelManager, Project.class, Project.class);
+	ProjectSearchQuery(ODSModelManager modelManager, QueryService queryService, ContextState contextState) {
+		super(modelManager, queryService, Project.class, Project.class);
 
 		// layers
 		addJoinConfig(JoinConfig.down(Project.class, Pool.class));
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/search/SearchableNode.java b/src/main/java/org/eclipse/mdm/api/odsadapter/search/SearchableNode.java
index 72218f6..0756cbf 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/search/SearchableNode.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/search/SearchableNode.java
@@ -13,8 +13,8 @@
 import java.util.List;
 import java.util.stream.Collectors;
 
-import org.eclipse.mdm.api.base.query.EntityType;
-import org.eclipse.mdm.api.base.query.Searchable;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.search.Searchable;
 
 /**
  * Implementation of the {@link Searchable} interface for use in search queries
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/search/TestSearchQuery.java b/src/main/java/org/eclipse/mdm/api/odsadapter/search/TestSearchQuery.java
index 8208d4a..c3fef23 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/search/TestSearchQuery.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/search/TestSearchQuery.java
@@ -8,13 +8,14 @@
 
 package org.eclipse.mdm.api.odsadapter.search;
 
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.Channel;
 import org.eclipse.mdm.api.base.model.ChannelGroup;
 import org.eclipse.mdm.api.base.model.Measurement;
 import org.eclipse.mdm.api.base.model.Test;
 import org.eclipse.mdm.api.base.model.TestStep;
-import org.eclipse.mdm.api.base.query.EntityType;
-import org.eclipse.mdm.api.base.query.SearchQuery;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchQuery;
 import org.eclipse.mdm.api.dflt.model.Pool;
 import org.eclipse.mdm.api.dflt.model.Project;
 import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
@@ -36,8 +37,8 @@
 	 * @param contextState
 	 *            The {@link ContextState}.
 	 */
-	TestSearchQuery(ODSModelManager modelManager, ContextState contextState) {
-		super(modelManager, Test.class, Project.class);
+	TestSearchQuery(ODSModelManager modelManager, QueryService queryService, ContextState contextState) {
+		super(modelManager, queryService, Test.class, Project.class);
 
 		// layers
 		addJoinConfig(JoinConfig.up(Pool.class, Project.class));
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/search/TestStepSearchQuery.java b/src/main/java/org/eclipse/mdm/api/odsadapter/search/TestStepSearchQuery.java
index aeb91e7..7ffe2c0 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/search/TestStepSearchQuery.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/search/TestStepSearchQuery.java
@@ -8,13 +8,14 @@
 
 package org.eclipse.mdm.api.odsadapter.search;
 
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.Channel;
 import org.eclipse.mdm.api.base.model.ChannelGroup;
 import org.eclipse.mdm.api.base.model.Measurement;
 import org.eclipse.mdm.api.base.model.Test;
 import org.eclipse.mdm.api.base.model.TestStep;
-import org.eclipse.mdm.api.base.query.EntityType;
-import org.eclipse.mdm.api.base.query.SearchQuery;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchQuery;
 import org.eclipse.mdm.api.dflt.model.Pool;
 import org.eclipse.mdm.api.dflt.model.Project;
 import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
@@ -37,8 +38,8 @@
 	 * @param contextState
 	 *            The {@link ContextState}.
 	 */
-	TestStepSearchQuery(ODSModelManager modelManager, ContextState contextState) {
-		super(modelManager, TestStep.class, Project.class);
+	TestStepSearchQuery(ODSModelManager modelManager, QueryService queryService, ContextState contextState) {
+		super(modelManager, queryService, TestStep.class, Project.class);
 
 		// layers
 		addJoinConfig(JoinConfig.up(Pool.class, Project.class));
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/BaseStatement.java b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/BaseStatement.java
index 4322cfd..74eb9b8 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/BaseStatement.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/BaseStatement.java
@@ -9,17 +9,15 @@
 package org.eclipse.mdm.api.odsadapter.transaction;
 
 import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.util.Collection;
 
 import org.asam.ods.AoException;
 import org.asam.ods.ApplElemAccess;
-import org.eclipse.mdm.api.base.model.BaseEntity;
-import org.eclipse.mdm.api.base.model.Core;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.Entity;
 import org.eclipse.mdm.api.base.query.DataAccessException;
-import org.eclipse.mdm.api.base.query.EntityType;
+import org.eclipse.mdm.api.base.query.QueryService;
 import org.eclipse.mdm.api.odsadapter.query.ODSEntityType;
 import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
 
@@ -32,22 +30,6 @@
 abstract class BaseStatement {
 
 	// ======================================================================
-	// Class variables
-	// ======================================================================
-
-	private static final Method GET_CORE_METHOD;
-
-	static {
-		try {
-			GET_CORE_METHOD = BaseEntity.class.getDeclaredMethod("getCore");
-			GET_CORE_METHOD.setAccessible(true);
-		} catch (NoSuchMethodException | SecurityException e) {
-			throw new IllegalStateException(
-					"Unable to load 'getCore()' in class '" + BaseEntity.class.getSimpleName() + "'.", e);
-		}
-	}
-
-	// ======================================================================
 	// Instance variables
 	// ======================================================================
 
@@ -94,22 +76,6 @@
 	// ======================================================================
 
 	/**
-	 * Returns the {@link Core} of given {@link Entity}.
-	 *
-	 * @param entity
-	 *            The {@code Entity} whose {@code Core} will be returned.
-	 * @return The {@code Core} is returned.
-	 */
-	protected Core extract(Entity entity) {
-		try {
-			return (Core) GET_CORE_METHOD.invoke(entity);
-		} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-			throw new IllegalArgumentException("Entity of type '" + entity.getClass().getSimpleName()
-					+ "' does not extend '" + BaseEntity.class.getName() + "'", e);
-		}
-	}
-
-	/**
 	 * Returns the {@link ODSTransaction}.
 	 *
 	 * @return The {@code ODSTransaction} is returned.
@@ -128,6 +94,16 @@
 	}
 
 	/**
+	 * Returns the {@link QueryService}.
+	 *
+	 * @return The {@code QueryService} is returned.
+	 */
+	protected QueryService getQueryService() {
+		return transaction.getContext().getQueryService()
+				.orElseThrow(() -> new ServiceNotProvidedException(QueryService.class));
+	}
+	
+	/**
 	 * Returns the {@link ApplElemAccess}.
 	 *
 	 * @return The {@code ApplElemAccess} is returned.
@@ -135,9 +111,11 @@
 	 *             Thrown in case of errors.
 	 */
 	protected ApplElemAccess getApplElemAccess() throws AoException {
-		return transaction.getModelManager().getApplElemAccess();
+		return transaction.getContext().getODSModelManager().getApplElemAccess();
 	}
 
+
+	
 	/**
 	 * Returns the associated {@link EntityType}.
 	 *
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/CatalogManager.java b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/CatalogManager.java
index 6d688ed..af8b2ee 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/CatalogManager.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/CatalogManager.java
@@ -26,14 +26,16 @@
 import org.asam.ods.BaseStructure;
 import org.asam.ods.DataType;
 import org.asam.ods.RelationRange;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.model.ContextType;
 import org.eclipse.mdm.api.base.model.Entity;
 import org.eclipse.mdm.api.base.model.Unit;
 import org.eclipse.mdm.api.base.query.DataAccessException;
-import org.eclipse.mdm.api.base.query.EntityType;
 import org.eclipse.mdm.api.base.query.Filter;
 import org.eclipse.mdm.api.base.query.ComparisonOperator;
 import org.eclipse.mdm.api.base.query.Query;
+import org.eclipse.mdm.api.base.query.QueryService;
 import org.eclipse.mdm.api.base.query.Result;
 import org.eclipse.mdm.api.dflt.model.CatalogAttribute;
 import org.eclipse.mdm.api.dflt.model.CatalogComponent;
@@ -536,7 +538,9 @@
 			EntityType source = entry.getKey();
 			EntityType target = transaction.getModelManager().getEntityType(source.getName().replace("Cat", "Tpl"));
 
-			Query query = transaction.getModelManager().createQuery().selectID(target).join(source, target);
+			Query query = transaction.getContext().getQueryService()
+					.orElseThrow(() -> new ServiceNotProvidedException(QueryService.class))
+					.createQuery().selectID(target).join(source, target);
 
 			List<Result> results = query.fetch(Filter.and()
 					.add(ComparisonOperator.IN_SET.create(source.getIDAttribute(), collectInstanceIDs(entry.getValue()))));
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/DeleteStatement.java b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/DeleteStatement.java
index 12ae06e..56f146a 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/DeleteStatement.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/DeleteStatement.java
@@ -22,6 +22,8 @@
 
 import org.asam.ods.AoException;
 import org.asam.ods.T_LONGLONG;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
 import org.eclipse.mdm.api.base.model.Channel;
 import org.eclipse.mdm.api.base.model.ContextRoot;
 import org.eclipse.mdm.api.base.model.ContextType;
@@ -33,11 +35,9 @@
 import org.eclipse.mdm.api.base.model.TestStep;
 import org.eclipse.mdm.api.base.model.Value;
 import org.eclipse.mdm.api.base.query.DataAccessException;
-import org.eclipse.mdm.api.base.query.EntityType;
 import org.eclipse.mdm.api.base.query.Filter;
 import org.eclipse.mdm.api.base.query.JoinType;
 import org.eclipse.mdm.api.base.query.Query;
-import org.eclipse.mdm.api.base.query.Relation;
 import org.eclipse.mdm.api.base.query.Result;
 import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
 import org.eclipse.mdm.api.odsadapter.query.ODSEntityType;
@@ -128,7 +128,7 @@
 			return 0;
 		}
 
-		Query query = getModelManager().createQuery().selectID(entityType);
+		Query query = getQueryService().createQuery().selectID(entityType);
 		for (Relation relation : entityType.getChildRelations()) {
 			if (useAutoDelete && AUTO_DELETABLE.contains(relation.getTarget().getName())) {
 				continue;
@@ -208,7 +208,7 @@
 					continue;
 				}
 
-				Query contextQuery = getModelManager().createQuery();
+				Query contextQuery = getQueryService().createQuery();
 				contextQuery.selectID(contextRoot, measurement);
 				contextQuery.join(contextRoot, measurement);
 
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/InsertStatement.java b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/InsertStatement.java
index 6bb58ad..798b92b 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/InsertStatement.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/InsertStatement.java
@@ -21,7 +21,10 @@
 import org.asam.ods.AoException;
 import org.asam.ods.ElemId;
 import org.asam.ods.T_LONGLONG;
-import org.eclipse.mdm.api.base.model.Core;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
 import org.eclipse.mdm.api.base.model.Deletable;
 import org.eclipse.mdm.api.base.model.Entity;
 import org.eclipse.mdm.api.base.model.FileLink;
@@ -30,14 +33,12 @@
 import org.eclipse.mdm.api.base.model.TestStep;
 import org.eclipse.mdm.api.base.model.Value;
 import org.eclipse.mdm.api.base.query.Aggregation;
-import org.eclipse.mdm.api.base.query.Attribute;
 import org.eclipse.mdm.api.base.query.DataAccessException;
-import org.eclipse.mdm.api.base.query.EntityType;
 import org.eclipse.mdm.api.base.query.Filter;
 import org.eclipse.mdm.api.base.query.Query;
 import org.eclipse.mdm.api.base.query.Record;
-import org.eclipse.mdm.api.base.query.Relation;
 import org.eclipse.mdm.api.base.query.Result;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityFactory;
 import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
 import org.eclipse.mdm.api.odsadapter.utils.ODSUtils;
 import org.slf4j.Logger;
@@ -93,7 +94,7 @@
 	 */
 	@Override
 	public void execute(Collection<Entity> entities) throws AoException, DataAccessException, IOException {
-		entities.stream().map(this::extract).forEach(this::readEntityCore);
+		entities.stream().map(ODSEntityFactory::extract).forEach(this::readEntityCore);
 		execute();
 	}
 
@@ -264,7 +265,7 @@
 		EntityType test = getModelManager().getEntityType(Test.class);
 		Relation parentRelation = testStep.getRelation(test);
 
-		Query query = getModelManager().createQuery().select(parentRelation.getAttribute())
+		Query query = getQueryService().createQuery().select(parentRelation.getAttribute())
 				.select(testStep.getAttribute(Sortable.ATTR_SORT_INDEX), Aggregation.MAXIMUM)
 				.group(parentRelation.getAttribute());
 
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/ODSTransaction.java b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/ODSTransaction.java
index 989771e..7a56c1f 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/ODSTransaction.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/ODSTransaction.java
@@ -22,10 +22,11 @@
 
 import org.asam.ods.AoException;
 import org.eclipse.mdm.api.base.Transaction;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.massdata.WriteRequest;
 import org.eclipse.mdm.api.base.model.Channel;
 import org.eclipse.mdm.api.base.model.ContextRoot;
-import org.eclipse.mdm.api.base.model.Core;
 import org.eclipse.mdm.api.base.model.Deletable;
 import org.eclipse.mdm.api.base.model.Entity;
 import org.eclipse.mdm.api.base.model.FileLink;
@@ -35,11 +36,11 @@
 import org.eclipse.mdm.api.base.model.Value;
 import org.eclipse.mdm.api.base.model.ValueType;
 import org.eclipse.mdm.api.base.query.DataAccessException;
-import org.eclipse.mdm.api.base.query.EntityType;
 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.TemplateAttribute;
+import org.eclipse.mdm.api.odsadapter.ODSContext;
 import org.eclipse.mdm.api.odsadapter.filetransfer.Transfer;
 import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
 import org.eclipse.mdm.api.odsadapter.utils.ODSUtils;
@@ -54,10 +55,6 @@
  */
 public final class ODSTransaction implements Transaction {
 
-	// ======================================================================
-	// Class variables
-	// ======================================================================
-
 	// TODO: it should be possible to a attach a progress listener
 	// -> progress notification updates while uploading files
 	// -> any other useful informations?!
@@ -65,17 +62,13 @@
 
 	private static final Logger LOGGER = LoggerFactory.getLogger(ODSTransaction.class);
 
-	// ======================================================================
-	// Instance variables
-	// ======================================================================
-
 	// this one is stored in case of application model modifications
-	private final ODSModelManager parentModelManager;
-
+	private final ODSContext parentContext;
+	
 	// this one is used to access the application model and execute queries
 	// instance is decoupled from its parent
-	private final ODSModelManager modelManager;
-
+	private final ODSContext context;
+	
 	// only for logging
 	private final String id = UUID.randomUUID().toString();
 
@@ -95,10 +88,6 @@
 
 	private CatalogManager catalogManager;
 
-	// ======================================================================
-	// Constructors
-	// ======================================================================
-
 	/**
 	 * Constructor.
 	 *
@@ -111,19 +100,15 @@
 	 * @throws AoException
 	 *             Thrown if unable to start a co-session.
 	 */
-	public ODSTransaction(ODSModelManager parentModelManager, Entity entity, Transfer transfer) throws AoException {
-		this.parentModelManager = parentModelManager;
+	public ODSTransaction(ODSContext parentContext, Entity entity, Transfer transfer) throws AoException {
+		this.parentContext = parentContext;
 		this.entity = entity;
 		this.transfer = transfer;
-		modelManager = parentModelManager.newSession();
-		modelManager.getAoSession().startTransaction();
+		context = parentContext.newContext();
+		context.getAoSession().startTransaction();
 		LOGGER.debug("Transaction '{}' started.", id);
 	}
 
-	// ======================================================================
-	// Public methods
-	// ======================================================================
-
 	/**
 	 * {@inheritDoc}
 	 */
@@ -336,7 +321,7 @@
 	@Override
 	public void commit() throws DataAccessException {
 		try {
-			modelManager.getAoSession().commitTransaction();
+			context.getAoSession().commitTransaction();
 
 			// commit succeed -> apply changes in entity cores
 			modified.forEach(Core::apply);
@@ -348,7 +333,7 @@
 
 			if (catalogManager != null) {
 				// application model has been modified -> reload
-				parentModelManager.reloadApplicationModel();
+				parentContext.getODSModelManager().reloadApplicationModel();
 			}
 
 			LOGGER.debug("Transaction '{}' committed.", id);
@@ -375,7 +360,7 @@
 			String virtualID = "0";
 			created.forEach(c -> c.setID(virtualID));
 
-			modelManager.getAoSession().abortTransaction();
+			context.getAoSession().abortTransaction();
 
 			LOGGER.debug("Transaction '{}' aborted.", id);
 		} catch (AoException e) {
@@ -385,10 +370,6 @@
 		}
 	}
 
-	// ======================================================================
-	// Package methods
-	// ======================================================================
-
 	/**
 	 * Once {@link #abort()} is called instance ID of given {@link Core} will be
 	 * reset to {@code 0} which indicates a virtual {@link Entity}, not yet
@@ -413,14 +394,23 @@
 	}
 
 	/**
+	 * Returns the {@link ODSContext}.
+	 *
+	 * @return The {@code ODSContext} is returned.
+	 */
+	ODSContext getContext() {
+		return context;
+	}
+
+	/**
 	 * Returns the {@link ODSModelManager}.
 	 *
 	 * @return The {@code ODSModelManager} is returned.
 	 */
 	ODSModelManager getModelManager() {
-		return modelManager;
+		return context.getODSModelManager();
 	}
-
+	
 	/**
 	 * Returns the {@link UploadService}.
 	 *
@@ -430,22 +420,18 @@
 	 */
 	UploadService getUploadService() throws DataAccessException {
 		if (uploadService == null) {
-			if (modelManager.getFileServer() == null) {
+			if (context.getFileServer() == null) {
 				throw new DataAccessException("CORBA file server is not available.");
 			}
 
 			// upload service starts a periodic session refresh task -> lazy
 			// instantiation
-			uploadService = new UploadService(modelManager, entity, transfer);
+			uploadService = new UploadService(context, entity, transfer);
 		}
 
 		return uploadService;
 	}
 
-	// ======================================================================
-	// Private methods
-	// ======================================================================
-
 	/**
 	 * Returns the {@link CatalogManager}.
 	 *
@@ -494,7 +480,7 @@
 	private <T extends Entity> void executeStatements(Function<EntityType, BaseStatement> statementFactory,
 			Collection<T> entities) throws AoException, DataAccessException, IOException {
 		Map<EntityType, List<Entity>> entitiesByType = entities.stream()
-				.collect(Collectors.groupingBy(modelManager::getEntityType));
+				.collect(Collectors.groupingBy(context.getODSModelManager()::getEntityType));
 		for (Entry<EntityType, List<Entity>> entry : entitiesByType.entrySet()) {
 			statementFactory.apply(entry.getKey()).execute(entry.getValue());
 		}
@@ -503,17 +489,13 @@
 	/**
 	 * Closes the co-session of this transaction.
 	 */
-	private void closeSession() {
-		try {
-			if (catalogManager != null) {
-				catalogManager.clear();
-			}
-
-			modelManager.close();
-			LOGGER.debug("Transaction '{}' closed.", id);
-		} catch (AoException e) {
-			LOGGER.error("Unable to close transaction '" + id + "' due to: " + e.reason, e);
+	private void closeSession() {		
+		if (catalogManager != null) {
+			catalogManager.clear();
 		}
+
+		context.close();
+		LOGGER.debug("Transaction '{}' closed.", id);
 	}
 
 }
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UpdateStatement.java b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UpdateStatement.java
index d2ecb04..ea597b6 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UpdateStatement.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UpdateStatement.java
@@ -21,18 +21,19 @@
 import org.asam.ods.AIDNameValueSeqUnitId;
 import org.asam.ods.AoException;
 import org.asam.ods.T_LONGLONG;
-import org.eclipse.mdm.api.base.model.Core;
-import org.eclipse.mdm.api.base.model.Core.EntityStore;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.EntityStore;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
 import org.eclipse.mdm.api.base.model.Deletable;
 import org.eclipse.mdm.api.base.model.Entity;
 import org.eclipse.mdm.api.base.model.FileLink;
 import org.eclipse.mdm.api.base.model.FilesAttachable;
 import org.eclipse.mdm.api.base.model.Value;
-import org.eclipse.mdm.api.base.query.Attribute;
 import org.eclipse.mdm.api.base.query.DataAccessException;
-import org.eclipse.mdm.api.base.query.EntityType;
-import org.eclipse.mdm.api.base.query.Relation;
 import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityFactory;
 import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
 import org.eclipse.mdm.api.odsadapter.utils.ODSUtils;
 import org.slf4j.Logger;
@@ -101,7 +102,7 @@
 	@Override
 	public void execute(Collection<Entity> entities) throws AoException, DataAccessException, IOException {
 		for (Entity entity : entities) {
-			readEntityCore(extract(entity));
+			readEntityCore(ODSEntityFactory.extract(entity));
 		}
 
 		// TODO tracing progress in this method...
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UploadService.java b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UploadService.java
index bd441ce..ebb9880 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UploadService.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UploadService.java
@@ -13,14 +13,14 @@
 import java.util.concurrent.TimeUnit;
 
 import org.asam.ods.AoException;
-import org.eclipse.mdm.api.base.FileService.ProgressListener;
+import org.eclipse.mdm.api.base.file.FileService.ProgressListener;
 import org.eclipse.mdm.api.base.model.Entity;
 import org.eclipse.mdm.api.base.model.FileLink;
 import org.eclipse.mdm.api.base.model.Value;
 import org.eclipse.mdm.api.dflt.model.TemplateAttribute;
+import org.eclipse.mdm.api.odsadapter.ODSContext;
 import org.eclipse.mdm.api.odsadapter.filetransfer.CORBAFileService;
 import org.eclipse.mdm.api.odsadapter.filetransfer.Transfer;
-import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
 
 /**
  * Manages new or removed externally linked files.
@@ -51,20 +51,20 @@
 	/**
 	 * Constructor.
 	 *
-	 * @param modelManager
+	 * @param context
 	 *            Used for setup.
 	 * @param entity
 	 *            Used for security checks.
 	 * @param transfer
 	 *            The transfer type.
 	 */
-	UploadService(ODSModelManager modelManager, Entity entity, Transfer transfer) {
-		fileService = new CORBAFileService(modelManager, transfer);
+	UploadService(ODSContext context, Entity entity, Transfer transfer) {
+		fileService = new CORBAFileService(context, transfer);
 		this.entity = entity;
 
 		scheduler.scheduleAtFixedRate(() -> {
 			try {
-				modelManager.getAoSession().getName();
+				context.getAoSession().getName();
 			} catch (AoException e) {
 				/*
 				 * NOTE: This is done to keep the parent transaction's session
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/WriteRequestHandler.java b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/WriteRequestHandler.java
index ba7810a..e378af6 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/WriteRequestHandler.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/WriteRequestHandler.java
@@ -17,14 +17,14 @@
 import java.util.stream.IntStream;
 
 import org.asam.ods.AoException;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.DefaultCore;
+import org.eclipse.mdm.api.base.adapter.EntityType;
 import org.eclipse.mdm.api.base.massdata.WriteRequest;
-import org.eclipse.mdm.api.base.model.Core;
 import org.eclipse.mdm.api.base.model.Entity;
 import org.eclipse.mdm.api.base.model.Value;
 import org.eclipse.mdm.api.base.model.ValueType;
 import org.eclipse.mdm.api.base.query.DataAccessException;
-import org.eclipse.mdm.api.base.query.DefaultCore;
-import org.eclipse.mdm.api.base.query.EntityType;
 import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
 
 /**
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverter.java b/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverter.java
index ed53910..986e6af 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverter.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverter.java
@@ -8,9 +8,12 @@
 
 package org.eclipse.mdm.api.odsadapter.utils;
 
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
 import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -29,6 +32,7 @@
 import org.asam.ods.T_DCOMPLEX;
 import org.asam.ods.T_ExternalReference;
 import org.asam.ods.T_LONGLONG;
+import org.eclipse.mdm.api.base.adapter.Attribute;
 import org.eclipse.mdm.api.base.model.DoubleComplex;
 import org.eclipse.mdm.api.base.model.FileLink;
 import org.eclipse.mdm.api.base.model.FloatComplex;
@@ -37,7 +41,6 @@
 import org.eclipse.mdm.api.base.model.ScalarType;
 import org.eclipse.mdm.api.base.model.Value;
 import org.eclipse.mdm.api.base.model.ValueType;
-import org.eclipse.mdm.api.base.query.Attribute;
 import org.eclipse.mdm.api.base.query.DataAccessException;
 import org.eclipse.mdm.api.odsadapter.query.ODSAttribute;
 
@@ -56,13 +59,17 @@
 	private static final Map<Integer, DateTimeFormatter> ODS_DATE_FORMATTERS = new HashMap<>();
 
 	static {
-		ODS_DATE_FORMATTERS.put(4, DateTimeFormatter.ofPattern("yyyy"));
-		ODS_DATE_FORMATTERS.put(6, DateTimeFormatter.ofPattern("yyyyMM"));
+		ODS_DATE_FORMATTERS.put(4, new DateTimeFormatterBuilder().appendPattern("yyyy").parseDefaulting(ChronoField.MONTH_OF_YEAR, 1).parseDefaulting(ChronoField.DAY_OF_MONTH, 1).toFormatter());
+		ODS_DATE_FORMATTERS.put(6, new DateTimeFormatterBuilder().appendPattern("yyyyMM").parseDefaulting(ChronoField.DAY_OF_MONTH, 1).toFormatter());
 		ODS_DATE_FORMATTERS.put(8, DateTimeFormatter.ofPattern("yyyyMMdd"));
 		ODS_DATE_FORMATTERS.put(10, DateTimeFormatter.ofPattern("yyyyMMddHH"));
 		ODS_DATE_FORMATTERS.put(12, DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
 		ODS_DATE_FORMATTERS.put(14, DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
-		ODS_DATE_FORMATTERS.put(17, DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
+		/*
+		 * JDK-8031085: DateTimeFormatter won't parse dates with custom format "yyyyMMddHHmmssSSS"
+		 * @see http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8031085
+		 */
+		ODS_DATE_FORMATTERS.put(17, new DateTimeFormatterBuilder().appendPattern("yyyyMMddHHmmss").appendValue(ChronoField.MILLI_OF_SECOND, 3).toFormatter());
 	}
 
 	// ======================================================================
@@ -910,7 +917,12 @@
 		}
 
 		try {
-			return LocalDateTime.parse(input, formatter);
+			if (input.length() <= 8) {
+				// Java does not accept a bare date as DateTime, so we are using LocalDate instead of LocalDateTime
+				return LocalDate.parse(input, formatter).atStartOfDay();
+			} else {
+				return LocalDateTime.parse(input, formatter);
+			}
 		} catch (DateTimeParseException e) {
 			throw new IllegalArgumentException("Invalid ODS date: " + input, e);
 		}
@@ -1114,7 +1126,8 @@
 		if (input == null) {
 			return new T_ExternalReference("", "", "");
 		}
-		return new T_ExternalReference(input.getDescription(), input.getMimeType().toString(), input.getRemotePath());
+		String remotePath=input.isRemote() ? input.getRemotePath() : "";
+		return new T_ExternalReference(input.getDescription(), input.getMimeType().toString(), remotePath);
 	}
 
 	/**
diff --git a/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSUtils.java b/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSUtils.java
index 1185c66..1f69761 100644
--- a/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSUtils.java
+++ b/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSUtils.java
@@ -12,6 +12,7 @@
 import org.asam.ods.DataType;
 import org.asam.ods.SelOpcode;
 import org.asam.ods.SelOperator;
+import org.eclipse.mdm.api.base.adapter.RelationType;
 import org.eclipse.mdm.api.base.model.ContextType;
 import org.eclipse.mdm.api.base.model.ValueType;
 import org.eclipse.mdm.api.base.query.Aggregation;
@@ -19,7 +20,6 @@
 import org.eclipse.mdm.api.base.query.JoinType;
 import org.eclipse.mdm.api.base.query.ComparisonOperator;
 import org.eclipse.mdm.api.base.query.BooleanOperator;
-import org.eclipse.mdm.api.base.query.RelationType;
 
 /**
  * Utility class provides bidirectional mappings for ODS types
diff --git a/src/test/java/org/eclipse/mdm/api/odsadapter/JoinTest.java b/src/test/java/org/eclipse/mdm/api/odsadapter/JoinTest.java
index a4694d9..62714a8 100644
--- a/src/test/java/org/eclipse/mdm/api/odsadapter/JoinTest.java
+++ b/src/test/java/org/eclipse/mdm/api/odsadapter/JoinTest.java
@@ -1,357 +1,350 @@
-/*

- * Copyright (c) 2016 Peak Solution GmbH

- * All rights reserved. This program and the accompanying materials

- * are made available under the terms of the Eclipse Public License v1.0

- * which accompanies this distribution, and is available at

- * http://www.eclipse.org/legal/epl-v10.html

- */

-

-package org.eclipse.mdm.api.odsadapter;

-

-import static org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory.PARAM_NAMESERVICE;

-import static org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory.PARAM_PASSWORD;

-import static org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory.PARAM_SERVICENAME;

-import static org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory.PARAM_USER;

-import static org.junit.Assert.assertEquals;

-

-import java.util.HashMap;

-import java.util.List;

-import java.util.Map;

-

-import org.eclipse.mdm.api.base.ConnectionException;

-import org.eclipse.mdm.api.base.model.Channel;

-import org.eclipse.mdm.api.base.model.ChannelGroup;

-import org.eclipse.mdm.api.base.model.Measurement;

-import org.eclipse.mdm.api.base.model.Test;

-import org.eclipse.mdm.api.base.model.TestStep;

-import org.eclipse.mdm.api.base.query.DataAccessException;

-import org.eclipse.mdm.api.base.query.EntityType;

-import org.eclipse.mdm.api.base.query.Filter;

-import org.eclipse.mdm.api.base.query.ModelManager;

-import org.eclipse.mdm.api.base.query.SearchService;

-import org.eclipse.mdm.api.dflt.EntityManager;

-import org.eclipse.mdm.api.dflt.model.EntityFactory;

-import org.junit.AfterClass;

-import org.junit.BeforeClass;

-import org.junit.Ignore;

-import org.slf4j.Logger;

-import org.slf4j.LoggerFactory;

-

-/**

- * JoinType test

- *

- * @since 1.0.0

- * @author jst, Peak Solution GmbH

- */

-@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 JoinTest {

-	private static final Logger LOGGER = LoggerFactory.getLogger(JoinTest.class);

-

-	private static final String NAME_SERVICE = "corbaloc::1.2@%s:%s/NameService";

-

-	private static final String USER = "sa";

-	private static final String PASSWORD = "sa";

-

-	private static EntityManager entityManager;

-	private static EntityFactory entityFactory;

-

-	@BeforeClass

-	public static void setUpBeforeClass() throws ConnectionException {

-		String nameServiceHost = System.getProperty("host");

-		String nameServicePort = System.getProperty("port");

-		String serviceName = System.getProperty("service");

-

-		if (nameServiceHost == null || nameServiceHost.isEmpty()) {

-			throw new IllegalArgumentException("name service host is unknown: define system property 'host'");

-		}

-

-		nameServicePort = nameServicePort == null || nameServicePort.isEmpty() ? String.valueOf(2809) : nameServicePort;

-		if (nameServicePort == null || nameServicePort.isEmpty()) {

-			throw new IllegalArgumentException("name service port is unknown: define system property 'port'");

-		}

-

-		if (serviceName == null || serviceName.isEmpty()) {

-			throw new IllegalArgumentException("service name is unknown: define system property 'service'");

-		}

-

-		Map<String, String> connectionParameters = new HashMap<>();

-		connectionParameters.put(PARAM_NAMESERVICE, String.format(NAME_SERVICE, nameServiceHost, nameServicePort));

-		connectionParameters.put(PARAM_SERVICENAME, serviceName + ".ASAM-ODS");

-		connectionParameters.put(PARAM_USER, USER);

-		connectionParameters.put(PARAM_PASSWORD, PASSWORD);

-

-		entityManager = new ODSEntityManagerFactory().connect(connectionParameters);

-		entityFactory = entityManager.getEntityFactory()

-				.orElseThrow(() -> new IllegalStateException("Entity manager factory not available."));

-	}

-

-	@AfterClass

-	public static void tearDownAfterClass() throws ConnectionException {

-		if (entityManager != null) {

-			entityManager.close();

-		}

-	}

-

-	@org.junit.Test

-	public void findTestFromTestStepId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(TestStep.class);

-

-		List<Test> list = searchService.fetch(Test.class, Filter.idOnly(et, "37"));

-

-		assertEquals(1, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findTestFromMeasurementId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(Measurement.class);

-

-		List<Test> list = searchService.fetch(Test.class, Filter.idOnly(et, "65"));

-

-		assertEquals(1, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findTestFromChannelGroupId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(ChannelGroup.class);

-

-		List<Test> list = searchService.fetch(Test.class, Filter.idOnly(et, "80"));

-

-		assertEquals(1, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findTestFromChannelId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(Channel.class);

-

-		List<Test> list = searchService.fetch(Test.class, Filter.idOnly(et, "302"));

-

-		assertEquals(1, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findTestStepFromTestId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(Test.class);

-

-		List<TestStep> list = searchService.fetch(TestStep.class, Filter.idOnly(et, "28"));

-

-		assertEquals(1, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findTestStepFromMeasurementId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(Measurement.class);

-

-		List<TestStep> list = searchService.fetch(TestStep.class, Filter.idOnly(et, "65"));

-

-		assertEquals(1, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findTestStepFromChannelGroupId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(ChannelGroup.class);

-

-		List<Test> list = searchService.fetch(Test.class, Filter.idOnly(et, "80"));

-

-		assertEquals(1, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findTestStepFromChannelId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(Channel.class);

-

-		List<TestStep> list = searchService.fetch(TestStep.class, Filter.idOnly(et, "302"));

-

-		assertEquals(1, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findMeasurementFromTestId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(Test.class);

-

-		List<Measurement> list = searchService.fetch(Measurement.class, Filter.idOnly(et, "28"));

-

-		assertEquals(9, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findMeasurementFromTestStepId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(TestStep.class);

-

-		List<Measurement> list = searchService.fetch(Measurement.class, Filter.idOnly(et, "37"));

-

-		assertEquals(9, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findMeasurementFromChannelGroupId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(ChannelGroup.class);

-

-		List<Measurement> list = searchService.fetch(Measurement.class, Filter.idOnly(et, "80"));

-

-		assertEquals(1, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findMeasurementFromChannelId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(Channel.class);

-

-		List<Measurement> list = searchService.fetch(Measurement.class, Filter.idOnly(et, "302"));

-

-		assertEquals(1, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findChannelGroupFromTestId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(Test.class);

-

-		List<ChannelGroup> list = searchService.fetch(ChannelGroup.class, Filter.idOnly(et, "28"));

-

-		assertEquals(14, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findChannelGroupFromTestStepId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(TestStep.class);

-

-		List<ChannelGroup> list = searchService.fetch(ChannelGroup.class, Filter.idOnly(et, "37"));

-

-		assertEquals(14, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findChannelGroupFromMeasurementId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(Measurement.class);

-

-		List<ChannelGroup> list = searchService.fetch(ChannelGroup.class, Filter.idOnly(et, "65"));

-

-		assertEquals(2, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findChannelGroupFromChannelId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(Channel.class);

-

-		List<ChannelGroup> list = searchService.fetch(ChannelGroup.class, Filter.idOnly(et, "302"));

-

-		assertEquals(2, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findChannelFromTestId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(Test.class);

-

-		List<Channel> list = searchService.fetch(Channel.class, Filter.idOnly(et, "28"));

-

-		assertEquals(43, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findChannelFromTestStepId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(TestStep.class);

-

-		List<Channel> list = searchService.fetch(Channel.class, Filter.idOnly(et, "37"));

-

-		assertEquals(43, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findChannelFromMeasurementId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(Measurement.class);

-

-		List<Channel> list = searchService.fetch(Channel.class, Filter.idOnly(et, "65"));

-

-		assertEquals(2, list.size());

-		System.out.println(list.size());

-	}

-

-	@org.junit.Test

-	public void findChannelFromChannelGroupId() throws DataAccessException {

-		ModelManager modelManager = entityManager.getModelManager().get();

-		SearchService searchService = entityManager.getSearchService().get();

-

-		EntityType et = modelManager.getEntityType(ChannelGroup.class);

-

-		List<Channel> list = searchService.fetch(Channel.class, Filter.idOnly(et, "80"));

-

-		assertEquals(2, list.size());

-		System.out.println(list.size());

-	}

-

-}

+/*
+ * Copyright (c) 2016 Peak Solution GmbH
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.eclipse.mdm.api.odsadapter;
+
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_NAMESERVICE;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_PASSWORD;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_SERVICENAME;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_USER;
+import static org.junit.Assert.assertEquals;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.search.SearchService;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+
+/**
+ * JoinType test
+ *
+ * @since 1.0.0
+ * @author jst, Peak Solution GmbH
+ */
+@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 JoinTest {
+
+	private static final String NAME_SERVICE = "corbaloc::1.2@%s:%s/NameService";
+
+	private static final String USER = "sa";
+	private static final String PASSWORD = "sa";
+
+	private static ApplicationContext context;
+
+	@BeforeClass
+	public static void setUpBeforeClass() throws ConnectionException {
+		String nameServiceHost = System.getProperty("host");
+		String nameServicePort = System.getProperty("port");
+		String serviceName = System.getProperty("service");
+
+		if (nameServiceHost == null || nameServiceHost.isEmpty()) {
+			throw new IllegalArgumentException("name service host is unknown: define system property 'host'");
+		}
+
+		nameServicePort = nameServicePort == null || nameServicePort.isEmpty() ? String.valueOf(2809) : nameServicePort;
+		if (nameServicePort == null || nameServicePort.isEmpty()) {
+			throw new IllegalArgumentException("name service port is unknown: define system property 'port'");
+		}
+
+		if (serviceName == null || serviceName.isEmpty()) {
+			throw new IllegalArgumentException("service name is unknown: define system property 'service'");
+		}
+
+		Map<String, String> connectionParameters = new HashMap<>();
+		connectionParameters.put(PARAM_NAMESERVICE, String.format(NAME_SERVICE, nameServiceHost, nameServicePort));
+		connectionParameters.put(PARAM_SERVICENAME, serviceName + ".ASAM-ODS");
+		connectionParameters.put(PARAM_USER, USER);
+		connectionParameters.put(PARAM_PASSWORD, PASSWORD);
+
+		context  = new ODSContextFactory().connect(connectionParameters);
+	}
+
+	@AfterClass
+	public static void tearDownAfterClass() throws ConnectionException {
+		if (context != null) {
+			context.close();
+		}
+	}
+
+	@org.junit.Test
+	public void findTestFromTestStepId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(TestStep.class);
+
+		List<Test> list = searchService.fetch(Test.class, Filter.idOnly(et, "37"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findTestFromMeasurementId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Measurement.class);
+
+		List<Test> list = searchService.fetch(Test.class, Filter.idOnly(et, "65"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findTestFromChannelGroupId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(ChannelGroup.class);
+
+		List<Test> list = searchService.fetch(Test.class, Filter.idOnly(et, "80"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findTestFromChannelId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Channel.class);
+
+		List<Test> list = searchService.fetch(Test.class, Filter.idOnly(et, "302"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findTestStepFromTestId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Test.class);
+
+		List<TestStep> list = searchService.fetch(TestStep.class, Filter.idOnly(et, "28"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findTestStepFromMeasurementId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Measurement.class);
+
+		List<TestStep> list = searchService.fetch(TestStep.class, Filter.idOnly(et, "65"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findTestStepFromChannelGroupId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(ChannelGroup.class);
+
+		List<Test> list = searchService.fetch(Test.class, Filter.idOnly(et, "80"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findTestStepFromChannelId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Channel.class);
+
+		List<TestStep> list = searchService.fetch(TestStep.class, Filter.idOnly(et, "302"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findMeasurementFromTestId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Test.class);
+
+		List<Measurement> list = searchService.fetch(Measurement.class, Filter.idOnly(et, "28"));
+
+		assertEquals(9, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findMeasurementFromTestStepId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(TestStep.class);
+
+		List<Measurement> list = searchService.fetch(Measurement.class, Filter.idOnly(et, "37"));
+
+		assertEquals(9, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findMeasurementFromChannelGroupId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(ChannelGroup.class);
+
+		List<Measurement> list = searchService.fetch(Measurement.class, Filter.idOnly(et, "80"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findMeasurementFromChannelId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Channel.class);
+
+		List<Measurement> list = searchService.fetch(Measurement.class, Filter.idOnly(et, "302"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findChannelGroupFromTestId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Test.class);
+
+		List<ChannelGroup> list = searchService.fetch(ChannelGroup.class, Filter.idOnly(et, "28"));
+
+		assertEquals(14, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findChannelGroupFromTestStepId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(TestStep.class);
+
+		List<ChannelGroup> list = searchService.fetch(ChannelGroup.class, Filter.idOnly(et, "37"));
+
+		assertEquals(14, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findChannelGroupFromMeasurementId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Measurement.class);
+
+		List<ChannelGroup> list = searchService.fetch(ChannelGroup.class, Filter.idOnly(et, "65"));
+
+		assertEquals(2, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findChannelGroupFromChannelId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Channel.class);
+
+		List<ChannelGroup> list = searchService.fetch(ChannelGroup.class, Filter.idOnly(et, "302"));
+
+		assertEquals(2, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findChannelFromTestId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Test.class);
+
+		List<Channel> list = searchService.fetch(Channel.class, Filter.idOnly(et, "28"));
+
+		assertEquals(43, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findChannelFromTestStepId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(TestStep.class);
+
+		List<Channel> list = searchService.fetch(Channel.class, Filter.idOnly(et, "37"));
+
+		assertEquals(43, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findChannelFromMeasurementId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Measurement.class);
+
+		List<Channel> list = searchService.fetch(Channel.class, Filter.idOnly(et, "65"));
+
+		assertEquals(2, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findChannelFromChannelGroupId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(ChannelGroup.class);
+
+		List<Channel> list = searchService.fetch(Channel.class, Filter.idOnly(et, "80"));
+
+		assertEquals(2, list.size());
+		System.out.println(list.size());
+	}
+
+}
diff --git a/src/test/java/org/eclipse/mdm/api/odsadapter/ODSAdapterTest.java b/src/test/java/org/eclipse/mdm/api/odsadapter/ODSAdapterTest.java
index e04002e..9d7790d 100644
--- a/src/test/java/org/eclipse/mdm/api/odsadapter/ODSAdapterTest.java
+++ b/src/test/java/org/eclipse/mdm/api/odsadapter/ODSAdapterTest.java
@@ -1,370 +1,426 @@
-package org.eclipse.mdm.api.odsadapter;

-

-import static org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory.PARAM_NAMESERVICE;

-import static org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory.PARAM_PASSWORD;

-import static org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory.PARAM_SERVICENAME;

-import static org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory.PARAM_USER;

-import static org.junit.Assert.fail;

-

-import java.time.LocalDateTime;

-import java.util.ArrayList;

-import java.util.Collection;

-import java.util.Collections;

-import java.util.HashMap;

-import java.util.List;

-import java.util.Locale;

-import java.util.Map;

-import java.util.Optional;

-import java.util.UUID;

-import java.util.function.Function;

-import java.util.stream.Collectors;

-import java.util.stream.IntStream;

-

-import org.eclipse.mdm.api.base.ConnectionException;

-import org.eclipse.mdm.api.base.Transaction;

-import org.eclipse.mdm.api.base.massdata.WriteRequest;

-import org.eclipse.mdm.api.base.massdata.WriteRequestBuilder;

-import org.eclipse.mdm.api.base.model.AxisType;

-import org.eclipse.mdm.api.base.model.Channel;

-import org.eclipse.mdm.api.base.model.ChannelGroup;

-import org.eclipse.mdm.api.base.model.ContextRoot;

-import org.eclipse.mdm.api.base.model.ContextType;

-import org.eclipse.mdm.api.base.model.Deletable;

-import org.eclipse.mdm.api.base.model.Entity;

-import org.eclipse.mdm.api.base.model.Measurement;

-import org.eclipse.mdm.api.base.model.PhysicalDimension;

-import org.eclipse.mdm.api.base.model.Quantity;

-import org.eclipse.mdm.api.base.model.ScalarType;

-import org.eclipse.mdm.api.base.model.Test;

-import org.eclipse.mdm.api.base.model.TestStep;

-import org.eclipse.mdm.api.base.model.Unit;

-import org.eclipse.mdm.api.base.model.ValueType;

-import org.eclipse.mdm.api.base.query.DataAccessException;

-import org.eclipse.mdm.api.dflt.EntityManager;

-import org.eclipse.mdm.api.dflt.model.CatalogComponent;

-import org.eclipse.mdm.api.dflt.model.EntityFactory;

-import org.eclipse.mdm.api.dflt.model.Pool;

-import org.eclipse.mdm.api.dflt.model.Project;

-import org.eclipse.mdm.api.dflt.model.TemplateComponent;

-import org.eclipse.mdm.api.dflt.model.TemplateRoot;

-import org.eclipse.mdm.api.dflt.model.TemplateTest;

-import org.eclipse.mdm.api.dflt.model.TemplateTestStep;

-import org.junit.AfterClass;

-import org.junit.BeforeClass;

-import org.junit.Ignore;

-import org.slf4j.Logger;

-import org.slf4j.LoggerFactory;

-

-@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 ODSAdapterTest {

-

-	/*

-	 * ATTENTION: ==========

-	 *

-	 * To run this test make sure the target service is running a MDM default

-	 * model and any database constraint which enforces a relation of Test to a

-	 * parent entity is deactivated!

-	 */

-

-	private static final Logger LOGGER = LoggerFactory.getLogger(ODSAdapterTest.class);

-

-	private static final String NAME_SERVICE = "corbaloc::1.2@%s:%s/NameService";

-

-	private static final String USER = "sa";

-	private static final String PASSWORD = "sa";

-

-	private static EntityManager entityManager;

-	private static EntityFactory entityFactory;

-

-	@BeforeClass

-	public static void setUpBeforeClass() throws ConnectionException {

-		String nameServiceHost = System.getProperty("host");

-		String nameServicePort = System.getProperty("port");

-		String serviceName = System.getProperty("service");

-

-		if (nameServiceHost == null || nameServiceHost.isEmpty()) {

-			throw new IllegalArgumentException("name service host is unknown: define system property 'host'");

-		}

-

-		nameServicePort = nameServicePort == null || nameServicePort.isEmpty() ? String.valueOf(2809) : nameServicePort;

-		if (nameServicePort == null || nameServicePort.isEmpty()) {

-			throw new IllegalArgumentException("name service port is unknown: define system property 'port'");

-		}

-

-		if (serviceName == null || serviceName.isEmpty()) {

-			throw new IllegalArgumentException("service name is unknown: define system property 'service'");

-		}

-

-		Map<String, String> connectionParameters = new HashMap<>();

-		connectionParameters.put(PARAM_NAMESERVICE, String.format(NAME_SERVICE, nameServiceHost, nameServicePort));

-		connectionParameters.put(PARAM_SERVICENAME, serviceName + ".ASAM-ODS");

-		connectionParameters.put(PARAM_USER, USER);

-		connectionParameters.put(PARAM_PASSWORD, PASSWORD);

-

-		entityManager = new ODSEntityManagerFactory().connect(connectionParameters);

-		entityFactory = entityManager.getEntityFactory()

-				.orElseThrow(() -> new IllegalStateException("Entity manager factory not available."));

-	}

-

-	@AfterClass

-	public static void tearDownAfterClass() throws ConnectionException {

-		if (entityManager != null) {

-			entityManager.close();

-		}

-	}

-

-	@org.junit.Test

-	public void runtTestScript() throws DataAccessException {

-		List<CatalogComponent> catalogComponents = createCatalogComponents();

-		List<TemplateRoot> templateRoots = createTemplateRoots(catalogComponents);

-		List<TemplateTestStep> templateTestSteps = createTemplateTestSteps(templateRoots);

-		TemplateTest templateTest = createTemplateTest(templateTestSteps);

-		PhysicalDimension physicalDimension = entityFactory.createPhysicalDimension("any_physical_dimension");

-		Unit unit = entityFactory.createUnit("any_unit", physicalDimension);

-		Quantity quantity = entityFactory.createQuantity("any_quantity", unit);

-

-		Transaction transaction = entityManager.startTransaction();

-		try {

-			create(transaction, "catalog components", catalogComponents);

-			create(transaction, "template roots", templateRoots);

-			create(transaction, "template test steps", templateTestSteps);

-			create(transaction, "template test", Collections.singletonList(templateTest));

-			create(transaction, "physical dimension", Collections.singletonList(physicalDimension));

-			create(transaction, "unit", Collections.singletonList(unit));

-			create(transaction, "quantity", Collections.singletonList(quantity));

-

-			transaction.commit();

-		} catch (RuntimeException e) {

-			transaction.abort();

-			fail("Unable to create test data due to: " + e.getMessage());

-		}

-

-		List<Project> projects = Collections.emptyList();

-		try {

-			projects = createTestData(templateTest, quantity);

-		} catch (DataAccessException | RuntimeException e) {

-			e.printStackTrace();

-		}

-

-		transaction = entityManager.startTransaction();

-		try {

-			// delete in reverse order!

-			if (!projects.isEmpty()) {

-				delete(transaction, "projects and their children", projects);

-			}

-

-			delete(transaction, "quantity", Collections.singletonList(quantity));

-			delete(transaction, "unit", Collections.singletonList(unit));

-			delete(transaction, "physical dimension", Collections.singletonList(physicalDimension));

-			delete(transaction, "template test", Collections.singletonList(templateTest));

-			delete(transaction, "template test steps", templateTestSteps);

-			delete(transaction, "template roots", templateRoots);

-			delete(transaction, "catalog components", catalogComponents);

-

-			transaction.commit();

-		} catch (RuntimeException e) {

-			transaction.abort();

-			fail("Unable to delete test data due to: " + e.getMessage());

-		}

-

-		if (projects.isEmpty()) {

-			fail("Was unable to create test data.");

-		}

-	}

-

-	private List<Project> createTestData(TemplateTest templateTest, Quantity quantity) throws DataAccessException {

-

-		Project project = entityFactory.createProject("simple_project");

-		Pool pool = entityFactory.createPool("simple_pool", project);

-

-		List<Test> tests = createTests(2, pool, templateTest);

-

-		// create measurement test data

-		List<WriteRequest> writeRequests = new ArrayList<>();

-		for (Test test : tests) {

-			for (TestStep testStep : test.getCommissionedTestSteps()) {

-				Optional<TemplateTestStep> templateTestStep = TemplateTestStep.of(testStep);

-				ContextRoot[] contextRoots = new ContextRoot[0];

-				if (templateTestStep.isPresent()) {

-					contextRoots = templateTestStep.get().getTemplateRoots().stream()

-							.map(templateRoot -> entityFactory.createContextRoot(templateRoot))

-							.toArray(ContextRoot[]::new);

-				}

-				for (int i = 1; i < 3; i++) {

-					Measurement measurement = entityFactory.createMeasurement("measurement_" + i, testStep,

-							contextRoots);

-

-					// create channels

-					List<Channel> channels = new ArrayList<>();

-					for (int j = 0; j < 9; j++) {

-						channels.add(entityFactory.createChannel("channel_ " + j, measurement, quantity));

-					}

-

-					// create channel group

-					ChannelGroup channelGroup = entityFactory.createChannelGroup("group", 10, measurement);

-					writeRequests.addAll(createMeasurementData(measurement, channelGroup, channels));

-				}

-			}

-		}

-

-		Transaction transaction = entityManager.startTransaction();

-		try {

-			create(transaction, "project and pool with tests based on teamplates with measurements and mass data",

-					Collections.singleton(project));

-

-			transaction.writeMeasuredValues(writeRequests);

-			transaction.commit();

-			return Collections.singletonList(project);

-		} catch (DataAccessException | RuntimeException e) {

-			e.printStackTrace();

-			transaction.abort();

-		}

-

-		return Collections.emptyList();

-	}

-

-	private List<WriteRequest> createMeasurementData(Measurement measurement, ChannelGroup channelGroup,

-			List<Channel> channels) {

-		// set length of the channel value sequence

-		List<WriteRequest> writeRequests = new ArrayList<>();

-

-		// populate channel value write requests - one per channel

-		Collections.sort(channels, (c1, c2) -> c1.getName().compareTo(c2.getName()));

-

-		WriteRequestBuilder wrb = WriteRequest.create(channelGroup, channels.get(0), AxisType.X_AXIS);

-		writeRequests.add(wrb.implicitLinear(ScalarType.FLOAT, 0, 1).independent().build());

-

-		wrb = WriteRequest.create(channelGroup, channels.get(1), AxisType.Y_AXIS);

-		writeRequests.add(wrb.explicit()

-				.booleanValues(new boolean[] { true, true, false, true, true, false, true, false, false, false })

-				.build());

-

-		wrb = WriteRequest.create(channelGroup, channels.get(2), AxisType.Y_AXIS);

-		writeRequests.add(wrb.explicit().byteValues(new byte[] { 5, 32, 42, 9, 17, 65, 13, 8, 15, 21 }).build());

-

-		wrb = WriteRequest.create(channelGroup, channels.get(3), AxisType.Y_AXIS);

-		writeRequests.add(

-				wrb.explicit().integerValues(new int[] { 423, 645, 221, 111, 675, 353, 781, 582, 755, 231 }).build());

-

-		wrb = WriteRequest.create(channelGroup, channels.get(4), AxisType.Y_AXIS);

-		writeRequests.add(wrb.explicit()

-				.stringValues(new String[] { "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10" }).build());

-

-		LocalDateTime now = LocalDateTime.now();

-		wrb = WriteRequest.create(channelGroup, channels.get(5), AxisType.Y_AXIS);

-		writeRequests

-				.add(wrb.explicit()

-						.dateValues(new LocalDateTime[] { now, now.plusDays(1), now.plusDays(2), now.plusDays(3),

-								now.plusDays(4), now.plusDays(5), now.plusDays(6), now.plusDays(7), now.plusDays(8),

-								now.plusDays(9) })

-						.build());

-

-		wrb = WriteRequest.create(channelGroup, channels.get(6), AxisType.Y_AXIS);

-		writeRequests.add(wrb.explicit().byteStreamValues(new byte[][] { { 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 }, { 9, 10 },

-				{ 11 }, { 12, 13, 14 }, { 15, 16 }, { 17, 18, 19, 20 }, { 21, 22 }, { 23 } }).build());

-

-		wrb = WriteRequest.create(channelGroup, channels.get(7), AxisType.Y_AXIS);

-		writeRequests.add(wrb.implicitConstant(ScalarType.SHORT, Short.MAX_VALUE).build());

-

-		wrb = WriteRequest.create(channelGroup, channels.get(8), AxisType.Y_AXIS);

-		writeRequests.add(wrb.implicitSaw(ScalarType.FLOAT, 0, 1, 4).build());

-

-		return writeRequests;

-	}

-

-	private static void delete(Transaction transaction, String key, Collection<? extends Deletable> entities)

-			throws DataAccessException {

-		LOGGER.info(">>>>>>>>>>>>>>>>> deleting " + key + "...");

-		long start = System.currentTimeMillis();

-		transaction.delete(entities);

-		LOGGER.info(">>>>>>>>>>>>>>>>> " + key + " deleted in " + (System.currentTimeMillis() - start) + " ms");

-	}

-

-	private static void create(Transaction transaction, String key, Collection<? extends Entity> entities)

-			throws DataAccessException {

-		LOGGER.info(">>>>>>>>>>>>>>>>> creating " + key + "...");

-		long start = System.currentTimeMillis();

-		transaction.create(entities);

-		LOGGER.info(">>>>>>>>>>>>>>>>> " + key + " written in " + (System.currentTimeMillis() - start) + " ms");

-	}

-

-	private List<Test> createTests(int count, Pool pool, TemplateTest templateTest) {

-		return IntStream.range(1, ++count)

-				.mapToObj(i -> entityFactory.createTest("simple_test_" + i, pool, templateTest))

-				.collect(Collectors.toList());

-	}

-

-	private TemplateTest createTemplateTest(List<TemplateTestStep> templateTestSteps) {

-		TemplateTest templateTest = entityFactory.createTemplateTest("tpl_test");

-		templateTestSteps.forEach(tts -> {

-			entityFactory.createTemplateTestStepUsage(UUID.randomUUID().toString(), templateTest, tts);

-		});

-		return templateTest;

-	}

-

-	private List<TemplateTestStep> createTemplateTestSteps(List<TemplateRoot> templateRoots) {

-		// make sure each context type is given only once

-		templateRoots.stream().collect(Collectors.toMap(TemplateRoot::getContextType, Function.identity()));

-

-		List<TemplateTestStep> templateTestSteps = new ArrayList<>();

-		TemplateTestStep templateTestStep1 = entityFactory.createTemplateTestStep("tpl_test_step_1");

-		templateRoots.forEach(tr -> templateTestStep1.setTemplateRoot(tr));

-		templateTestSteps.add(templateTestStep1);

-		TemplateTestStep templateTestStep2 = entityFactory.createTemplateTestStep("tpl_test_step_2");

-		templateRoots.forEach(tr -> templateTestStep2.setTemplateRoot(tr));

-		templateTestSteps.add(templateTestStep2);

-

-		return templateTestSteps;

-	}

-

-	private List<TemplateRoot> createTemplateRoots(List<CatalogComponent> catalogComponents) {

-		Map<ContextType, List<CatalogComponent>> groups = catalogComponents.stream()

-				.collect(Collectors.groupingBy(CatalogComponent::getContextType));

-

-		List<TemplateRoot> templateRoots = new ArrayList<>();

-		groups.forEach((contextType, catalogComps) -> {

-			TemplateRoot templateRoot = entityFactory.createTemplateRoot(contextType,

-					"tpl_" + toLower(contextType.name()) + "_root");

-			// create child template components for template root

-			catalogComps.forEach(catalogComp -> {

-				TemplateComponent templateComponent = entityFactory

-						.createTemplateComponent("tpl_" + catalogComp.getName() + "_parent", templateRoot, catalogComp);

-				entityFactory.createTemplateComponent("tpl_" + catalogComp.getName() + "_child", templateComponent,

-						catalogComp);

-			});

-

-			templateRoots.add(templateRoot);

-		});

-

-		return templateRoots;

-	}

-

-	private List<CatalogComponent> createCatalogComponents() {

-		List<CatalogComponent> catalogComponents = new ArrayList<>();

-		catalogComponents.add(createCatalogComponent(ContextType.UNITUNDERTEST));

-		catalogComponents.add(createCatalogComponent(ContextType.TESTSEQUENCE));

-		catalogComponents.add(createCatalogComponent(ContextType.TESTEQUIPMENT));

-		return catalogComponents;

-	}

-

-	private CatalogComponent createCatalogComponent(ContextType contextType) {

-		CatalogComponent catalogComponent = entityFactory.createCatalogComponent(contextType,

-				toLower(contextType.name()));

-

-		entityFactory.createCatalogAttribute("string", ValueType.STRING, catalogComponent);

-		entityFactory.createCatalogAttribute("date", ValueType.DATE, catalogComponent);

-		entityFactory.createCatalogAttribute("long", ValueType.LONG, catalogComponent);

-		entityFactory.createCatalogAttribute("file_link", ValueType.FILE_LINK, catalogComponent);

-		entityFactory.createCatalogAttribute("file_link_array", ValueType.FILE_LINK_SEQUENCE, catalogComponent);

-		entityFactory.createCatalogAttribute("scalar_type", ScalarType.class, catalogComponent);

-

-		return catalogComponent;

-	}

-

-	private static String toLower(String name) {

-		return name.toLowerCase(Locale.ROOT);

-	}

-

-}

+package org.eclipse.mdm.api.odsadapter;
+
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_NAMESERVICE;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_PASSWORD;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_SERVICENAME;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_USER;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.Transaction;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.massdata.WriteRequest;
+import org.eclipse.mdm.api.base.massdata.WriteRequestBuilder;
+import org.eclipse.mdm.api.base.model.AxisType;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.ContextComponent;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.EnumRegistry;
+import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.MimeType;
+import org.eclipse.mdm.api.base.model.PhysicalDimension;
+import org.eclipse.mdm.api.base.model.Quantity;
+import org.eclipse.mdm.api.base.model.ScalarType;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.model.Unit;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.model.ValueType;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.search.SearchService;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.eclipse.mdm.api.dflt.EntityManager;
+import org.eclipse.mdm.api.dflt.model.CatalogComponent;
+import org.eclipse.mdm.api.dflt.model.EntityFactory;
+import org.eclipse.mdm.api.dflt.model.Pool;
+import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.dflt.model.TemplateComponent;
+import org.eclipse.mdm.api.dflt.model.TemplateRoot;
+import org.eclipse.mdm.api.dflt.model.TemplateTest;
+import org.eclipse.mdm.api.dflt.model.TemplateTestStep;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@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 ODSAdapterTest {
+
+	/*
+	 * ATTENTION: ==========
+	 *
+	 * To run this test make sure the target service is running a MDM default
+	 * model and any database constraint which enforces a relation of Test to a
+	 * parent entity is deactivated!
+	 */
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(ODSAdapterTest.class);
+
+	private static final String NAME_SERVICE = "corbaloc::1.2@%s:%s/NameService";
+
+	private static final String USER = "sa";
+	private static final String PASSWORD = "sa";
+
+	private static ApplicationContext context;
+	private static EntityManager entityManager;
+	private static EntityFactory entityFactory;
+
+	@BeforeClass
+	public static void setUpBeforeClass() throws ConnectionException {
+		String nameServiceHost = System.getProperty("host");
+		String nameServicePort = System.getProperty("port");
+		String serviceName = System.getProperty("service");
+
+		if (nameServiceHost == null || nameServiceHost.isEmpty()) {
+			throw new IllegalArgumentException("name service host is unknown: define system property 'host'");
+		}
+
+		nameServicePort = nameServicePort == null || nameServicePort.isEmpty() ? String.valueOf(2809) : nameServicePort;
+		if (nameServicePort == null || nameServicePort.isEmpty()) {
+			throw new IllegalArgumentException("name service port is unknown: define system property 'port'");
+		}
+
+		if (serviceName == null || serviceName.isEmpty()) {
+			throw new IllegalArgumentException("service name is unknown: define system property 'service'");
+		}
+
+		Map<String, String> connectionParameters = new HashMap<>();
+		connectionParameters.put(PARAM_NAMESERVICE, String.format(NAME_SERVICE, nameServiceHost, nameServicePort));
+		connectionParameters.put(PARAM_SERVICENAME, serviceName + ".ASAM-ODS");
+		connectionParameters.put(PARAM_USER, USER);
+		connectionParameters.put(PARAM_PASSWORD, PASSWORD);
+
+		context  = new ODSContextFactory().connect(connectionParameters);
+		entityManager = context.getEntityManager()
+				.orElseThrow(() -> new ServiceNotProvidedException(EntityManager.class));
+		entityFactory = context.getEntityFactory()
+				.orElseThrow(() -> new IllegalStateException("Entity manager factory not available."));
+	}
+
+	@AfterClass
+	public static void tearDownAfterClass() throws ConnectionException {
+		if (context != null) {
+			context.close();
+		}
+	}
+	
+	/* FIXME this test requires that there is a teststep with id 2, that has a unitundertest component called "filetest",
+	 * that has an empty filelink attribute "myextref" and a string attrinute "attr1".
+	 * remove the comment at org.junit.Test if you fulfill these requirements  
+	 */
+	//@org.junit.Test
+	public void changeFile() throws Exception {
+		String idteststep = "2";
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType etteststep = modelManager.getEntityType(TestStep.class);
+		Transaction transaction;
+
+		transaction = entityManager.startTransaction();
+		
+		try {
+			List<TestStep> mealist;
+			mealist = searchService.fetch(TestStep.class, Filter.idOnly(etteststep, idteststep));
+			assertEquals(1, mealist.size());
+			TestStep ts = mealist.get(0);
+			Map<ContextType, ContextRoot> loadContexts = ts.loadContexts(entityManager, ContextType.UNITUNDERTEST);
+			ContextRoot contextRoot = loadContexts.get(ContextType.UNITUNDERTEST);
+			Optional<ContextComponent> contextComponent = contextRoot.getContextComponent("filetest");
+			Value value = contextComponent.get().getValue("myextref");
+			contextComponent.get().getValue("attr1").set("val4711");
+			FileLink fl=FileLink.newRemote("", new MimeType(""), "");
+			FileLink fl2 = (FileLink)value.extract();
+			assertEquals(fl2,fl);
+			List<BaseEntity> toUpdate=new ArrayList<>();
+			toUpdate.add(contextComponent.get());
+            transaction.update(toUpdate);
+            transaction.commit();
+		} catch (RuntimeException e) {
+			transaction.abort();
+			throw e;
+		}
+	}
+
+	@org.junit.Test
+	public void runtTestScript() throws DataAccessException {
+		List<CatalogComponent> catalogComponents = createCatalogComponents();
+		List<TemplateRoot> templateRoots = createTemplateRoots(catalogComponents);
+		List<TemplateTestStep> templateTestSteps = createTemplateTestSteps(templateRoots);
+		TemplateTest templateTest = createTemplateTest(templateTestSteps);
+		PhysicalDimension physicalDimension = entityFactory.createPhysicalDimension("any_physical_dimension");
+		Unit unit = entityFactory.createUnit("any_unit", physicalDimension);
+		Quantity quantity = entityFactory.createQuantity("any_quantity", unit);
+
+		Transaction transaction = entityManager.startTransaction();
+		try {
+			create(transaction, "catalog components", catalogComponents);
+			create(transaction, "template roots", templateRoots);
+			create(transaction, "template test steps", templateTestSteps);
+			create(transaction, "template test", Collections.singletonList(templateTest));
+			create(transaction, "physical dimension", Collections.singletonList(physicalDimension));
+			create(transaction, "unit", Collections.singletonList(unit));
+			create(transaction, "quantity", Collections.singletonList(quantity));
+
+			transaction.commit();
+		} catch (RuntimeException e) {
+			transaction.abort();
+			e.printStackTrace();
+			fail("Unable to create test data due to: " + e.getMessage());
+		}
+
+		List<Project> projects = Collections.emptyList();
+		try {
+			projects = createTestData(templateTest, quantity);
+		} catch (RuntimeException e) {
+			e.printStackTrace();
+		}
+
+		transaction = entityManager.startTransaction();
+		try {
+			// delete in reverse order!
+			if (!projects.isEmpty()) {
+				delete(transaction, "projects and their children", projects);
+			}
+
+			delete(transaction, "quantity", Collections.singletonList(quantity));
+			delete(transaction, "unit", Collections.singletonList(unit));
+			delete(transaction, "physical dimension", Collections.singletonList(physicalDimension));
+			delete(transaction, "template test", Collections.singletonList(templateTest));
+			delete(transaction, "template test steps", templateTestSteps);
+			delete(transaction, "template roots", templateRoots);
+			delete(transaction, "catalog components", catalogComponents);
+
+			transaction.commit();
+		} catch (RuntimeException e) {
+			transaction.abort();
+			fail("Unable to delete test data due to: " + e.getMessage());
+		}
+
+		if (projects.isEmpty()) {
+			fail("Was unable to create test data.");
+		}
+	}
+
+	private List<Project> createTestData(TemplateTest templateTest, Quantity quantity) throws DataAccessException {
+
+		Project project = entityFactory.createProject("simple_project");
+		Pool pool = entityFactory.createPool("simple_pool", project);
+
+		List<Test> tests = createTests(2, pool, templateTest);
+
+		// create measurement test data
+		List<WriteRequest> writeRequests = new ArrayList<>();
+		for (Test test : tests) {
+			for (TestStep testStep : test.getCommissionedTestSteps()) {
+				Optional<TemplateTestStep> templateTestStep = TemplateTestStep.of(testStep);
+				ContextRoot[] contextRoots = new ContextRoot[0];
+				if (templateTestStep.isPresent()) {
+					contextRoots = templateTestStep.get().getTemplateRoots().stream()
+							.map(templateRoot -> entityFactory.createContextRoot(templateRoot))
+							.toArray(ContextRoot[]::new);
+				}
+				for (int i = 1; i < 3; i++) {
+					Measurement measurement = entityFactory.createMeasurement("measurement_" + i, testStep,
+							contextRoots);
+
+					// create channels
+					List<Channel> channels = new ArrayList<>();
+					for (int j = 0; j < 9; j++) {
+						channels.add(entityFactory.createChannel("channel_ " + j, measurement, quantity));
+					}
+
+					// create channel group
+					ChannelGroup channelGroup = entityFactory.createChannelGroup("group", 10, measurement);
+					writeRequests.addAll(createMeasurementData(measurement, channelGroup, channels));
+				}
+			}
+		}
+
+		Transaction transaction = entityManager.startTransaction();
+		try {
+			create(transaction, "project and pool with tests based on teamplates with measurements and mass data",
+					Collections.singleton(project));
+
+			transaction.writeMeasuredValues(writeRequests);
+			transaction.commit();
+			return Collections.singletonList(project);
+		} catch (DataAccessException e) {
+			e.printStackTrace();
+			transaction.abort();
+		}
+
+		return Collections.emptyList();
+	}
+
+	private List<WriteRequest> createMeasurementData(Measurement measurement, ChannelGroup channelGroup,
+			List<Channel> channels) {
+		// set length of the channel value sequence
+		List<WriteRequest> writeRequests = new ArrayList<>();
+
+		// populate channel value write requests - one per channel
+		Collections.sort(channels, (c1, c2) -> c1.getName().compareTo(c2.getName()));
+
+		WriteRequestBuilder wrb = WriteRequest.create(channelGroup, channels.get(0), AxisType.X_AXIS);
+		writeRequests.add(wrb.implicitLinear(ScalarType.FLOAT, 0, 1).independent().build());
+
+		wrb = WriteRequest.create(channelGroup, channels.get(1), AxisType.Y_AXIS);
+		writeRequests.add(wrb.explicit()
+				.booleanValues(new boolean[] { true, true, false, true, true, false, true, false, false, false })
+				.build());
+
+		wrb = WriteRequest.create(channelGroup, channels.get(2), AxisType.Y_AXIS);
+		writeRequests.add(wrb.explicit().byteValues(new byte[] { 5, 32, 42, 9, 17, 65, 13, 8, 15, 21 }).build());
+
+		wrb = WriteRequest.create(channelGroup, channels.get(3), AxisType.Y_AXIS);
+		writeRequests.add(
+				wrb.explicit().integerValues(new int[] { 423, 645, 221, 111, 675, 353, 781, 582, 755, 231 }).build());
+
+		wrb = WriteRequest.create(channelGroup, channels.get(4), AxisType.Y_AXIS);
+		writeRequests.add(wrb.explicit()
+				.stringValues(new String[] { "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10" }).build());
+
+		LocalDateTime now = LocalDateTime.now();
+		wrb = WriteRequest.create(channelGroup, channels.get(5), AxisType.Y_AXIS);
+		writeRequests
+				.add(wrb.explicit()
+						.dateValues(new LocalDateTime[] { now, now.plusDays(1), now.plusDays(2), now.plusDays(3),
+								now.plusDays(4), now.plusDays(5), now.plusDays(6), now.plusDays(7), now.plusDays(8),
+								now.plusDays(9) })
+						.build());
+
+		wrb = WriteRequest.create(channelGroup, channels.get(6), AxisType.Y_AXIS);
+		writeRequests.add(wrb.explicit().byteStreamValues(new byte[][] { { 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 }, { 9, 10 },
+				{ 11 }, { 12, 13, 14 }, { 15, 16 }, { 17, 18, 19, 20 }, { 21, 22 }, { 23 } }).build());
+
+		wrb = WriteRequest.create(channelGroup, channels.get(7), AxisType.Y_AXIS);
+		writeRequests.add(wrb.implicitConstant(ScalarType.SHORT, Short.MAX_VALUE).build());
+
+		wrb = WriteRequest.create(channelGroup, channels.get(8), AxisType.Y_AXIS);
+		writeRequests.add(wrb.implicitSaw(ScalarType.FLOAT, 0, 1, 4).build());
+
+		return writeRequests;
+	}
+
+	private static void delete(Transaction transaction, String key, Collection<? extends Deletable> entities)
+			throws DataAccessException {
+		LOGGER.info(">>>>>>>>>>>>>>>>> deleting " + key + "...");
+		long start = System.currentTimeMillis();
+		transaction.delete(entities);
+		LOGGER.info(">>>>>>>>>>>>>>>>> " + key + " deleted in " + (System.currentTimeMillis() - start) + " ms");
+	}
+
+	private static void create(Transaction transaction, String key, Collection<? extends Entity> entities)
+			throws DataAccessException {
+		LOGGER.info(">>>>>>>>>>>>>>>>> creating " + key + "...");
+		long start = System.currentTimeMillis();
+		transaction.create(entities);
+		LOGGER.info(">>>>>>>>>>>>>>>>> " + key + " written in " + (System.currentTimeMillis() - start) + " ms");
+	}
+
+	private List<Test> createTests(int count, Pool pool, TemplateTest templateTest) {
+		return IntStream.range(1, ++count)
+				.mapToObj(i -> entityFactory.createTest("simple_test_" + i, pool, templateTest))
+				.collect(Collectors.toList());
+	}
+
+	private TemplateTest createTemplateTest(List<TemplateTestStep> templateTestSteps) {
+		TemplateTest templateTest = entityFactory.createTemplateTest("tpl_test");
+		templateTestSteps.forEach(tts -> {
+			entityFactory.createTemplateTestStepUsage(UUID.randomUUID().toString(), templateTest, tts);
+		});
+		return templateTest;
+	}
+
+	private List<TemplateTestStep> createTemplateTestSteps(List<TemplateRoot> templateRoots) {
+		// make sure each context type is given only once
+		templateRoots.stream().collect(Collectors.toMap(TemplateRoot::getContextType, Function.identity()));
+
+		List<TemplateTestStep> templateTestSteps = new ArrayList<>();
+		TemplateTestStep templateTestStep1 = entityFactory.createTemplateTestStep("tpl_test_step_1");
+		templateRoots.forEach(tr -> templateTestStep1.setTemplateRoot(tr));
+		templateTestSteps.add(templateTestStep1);
+		TemplateTestStep templateTestStep2 = entityFactory.createTemplateTestStep("tpl_test_step_2");
+		templateRoots.forEach(tr -> templateTestStep2.setTemplateRoot(tr));
+		templateTestSteps.add(templateTestStep2);
+
+		return templateTestSteps;
+	}
+
+	private List<TemplateRoot> createTemplateRoots(List<CatalogComponent> catalogComponents) {
+		Map<ContextType, List<CatalogComponent>> groups = catalogComponents.stream()
+				.collect(Collectors.groupingBy(CatalogComponent::getContextType));
+
+		List<TemplateRoot> templateRoots = new ArrayList<>();
+		groups.forEach((contextType, catalogComps) -> {
+			TemplateRoot templateRoot = entityFactory.createTemplateRoot(contextType,
+					"tpl_" + toLower(contextType.name()) + "_root");
+			// create child template components for template root
+			catalogComps.forEach(catalogComp -> {
+				TemplateComponent templateComponent = entityFactory
+						.createTemplateComponent("tpl_" + catalogComp.getName() + "_parent", templateRoot, catalogComp);
+				entityFactory.createTemplateComponent("tpl_" + catalogComp.getName() + "_child", templateComponent,
+						catalogComp);
+			});
+
+			templateRoots.add(templateRoot);
+		});
+
+		return templateRoots;
+	}
+
+	private List<CatalogComponent> createCatalogComponents() {
+		List<CatalogComponent> catalogComponents = new ArrayList<>();
+		catalogComponents.add(createCatalogComponent(ContextType.UNITUNDERTEST));
+		catalogComponents.add(createCatalogComponent(ContextType.TESTSEQUENCE));
+		catalogComponents.add(createCatalogComponent(ContextType.TESTEQUIPMENT));
+		return catalogComponents;
+	}
+
+	private CatalogComponent createCatalogComponent(ContextType contextType) {
+		CatalogComponent catalogComponent = entityFactory.createCatalogComponent(contextType,
+				toLower(contextType.name()));
+
+		entityFactory.createCatalogAttribute("string", ValueType.STRING, catalogComponent);
+		entityFactory.createCatalogAttribute("date", ValueType.DATE, catalogComponent);
+		entityFactory.createCatalogAttribute("long", ValueType.LONG, catalogComponent);
+		entityFactory.createCatalogAttribute("file_link", ValueType.FILE_LINK, catalogComponent);
+		entityFactory.createCatalogAttribute("file_link_array", ValueType.FILE_LINK_SEQUENCE, catalogComponent);
+		EnumRegistry er = EnumRegistry.getInstance();
+		entityFactory.createCatalogAttribute("scalar_type", er.get(EnumRegistry.SCALAR_TYPE), catalogComponent);
+
+		return catalogComponent;
+	}
+
+	private static String toLower(String name) {
+		return name.toLowerCase(Locale.ROOT);
+	}
+
+}
diff --git a/src/test/java/org/eclipse/mdm/api/odsadapter/RelationTest.java b/src/test/java/org/eclipse/mdm/api/odsadapter/RelationTest.java
new file mode 100755
index 0000000..5098e11
--- /dev/null
+++ b/src/test/java/org/eclipse/mdm/api/odsadapter/RelationTest.java
@@ -0,0 +1,182 @@
+/*

+ * Copyright (c) 2017 Florian Schmitt and others

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ */

+

+package org.eclipse.mdm.api.odsadapter;

+

+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_NAMESERVICE;

+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_PASSWORD;

+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_SERVICENAME;

+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_USER;

+import static org.junit.Assert.assertEquals;

+import static org.junit.Assert.assertNotNull;

+

+import java.util.ArrayList;

+import java.util.HashMap;

+import java.util.List;

+import java.util.Map;

+

+import org.eclipse.mdm.api.base.ConnectionException;

+import org.eclipse.mdm.api.base.ServiceNotProvidedException;

+import org.eclipse.mdm.api.base.Transaction;

+import org.eclipse.mdm.api.base.adapter.EntityStore;

+import org.eclipse.mdm.api.base.adapter.EntityType;

+import org.eclipse.mdm.api.base.adapter.ModelManager;

+import org.eclipse.mdm.api.base.model.Measurement;

+import org.eclipse.mdm.api.base.model.ParameterSet;

+import org.eclipse.mdm.api.base.query.Filter;

+import org.eclipse.mdm.api.base.query.QueryService;

+import org.eclipse.mdm.api.base.query.Record;

+import org.eclipse.mdm.api.base.query.Result;

+import org.eclipse.mdm.api.base.search.SearchService;

+import org.eclipse.mdm.api.dflt.ApplicationContext;

+import org.eclipse.mdm.api.dflt.EntityManager;

+import org.eclipse.mdm.api.odsadapter.query.ODSEntityFactory;

+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;

+import org.eclipse.mdm.api.odsadapter.search.RelationSearchQuery;

+import org.junit.AfterClass;

+import org.junit.BeforeClass;

+import org.junit.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 RelationTest {

+

+	/*

+	 * ATTENTION: ==========

+	 *

+	 * To run this test make sure the target service is running a MDM default

+	 * model and any database constraint which enforces a relation of Test to a

+	 * parent entity is deactivated!

+	 */

+

+	private static final String NAME_SERVICE = "corbaloc::1.2@%s:%s/NameService";

+

+	private static final String USER = "sa";

+	private static final String PASSWORD = "sa";

+

+	private static ApplicationContext context;

+	private static EntityManager entityManager;

+	private static ModelManager modelManager;

+	private static QueryService queryService;

+	private static SearchService searchService;

+	

+	@BeforeClass

+	public static void setUpBeforeClass() throws ConnectionException {

+		String nameServiceHost = System.getProperty("host");

+		String nameServicePort = System.getProperty("port");

+		String serviceName = System.getProperty("service");

+

+		if (nameServiceHost == null || nameServiceHost.isEmpty()) {

+			throw new IllegalArgumentException("name service host is unknown: define system property 'host'");

+		}

+

+		nameServicePort = nameServicePort == null || nameServicePort.isEmpty() ? String.valueOf(2809) : nameServicePort;

+		if (nameServicePort == null || nameServicePort.isEmpty()) {

+			throw new IllegalArgumentException("name service port is unknown: define system property 'port'");

+		}

+

+		if (serviceName == null || serviceName.isEmpty()) {

+			throw new IllegalArgumentException("service name is unknown: define system property 'service'");

+		}

+

+		Map<String, String> connectionParameters = new HashMap<>();

+		connectionParameters.put(PARAM_NAMESERVICE, String.format(NAME_SERVICE, nameServiceHost, nameServicePort));

+		connectionParameters.put(PARAM_SERVICENAME, serviceName + ".ASAM-ODS");

+		connectionParameters.put(PARAM_USER, USER);

+		connectionParameters.put(PARAM_PASSWORD, PASSWORD);

+

+		context  = new ODSContextFactory().connect(connectionParameters);

+		entityManager = context.getEntityManager()

+				.orElseThrow(() -> new ServiceNotProvidedException(EntityManager.class));

+		modelManager = context.getModelManager()

+				.orElseThrow(() -> new ServiceNotProvidedException(ModelManager.class));

+		queryService = context.getQueryService()

+				.orElseThrow(() -> new ServiceNotProvidedException(QueryService.class));

+		searchService = context.getSearchService()

+				.orElseThrow(() -> new IllegalStateException("Search service not available."));

+	}

+

+	@AfterClass

+	public static void tearDownAfterClass() throws ConnectionException {

+		if (context != null) {

+			context.close();

+		}

+	}

+	

+	

+	

+	/**

+	 * changes a relation between instances. There needs to exist a MeaResult of id 1101 and a ParameterSet of id

+	 * 1102 which will be related after running this test.

+	 * If these don't exist, please leave the following line commented, or the test will fail.  

+	 * @throws Exception 

+	 */

+	@org.junit.Test

+	public void changeRelation() throws Exception {

+		String idmea = "1101";

+		String idparamset = "1002";

+

+		EntityType etmeasurement = modelManager.getEntityType(Measurement.class);

+		EntityType etparamset = modelManager.getEntityType(ParameterSet.class);

+		Transaction transaction;

+

+		transaction = entityManager.startTransaction();

+

+		try {

+			List<Measurement> mealist;

+			// we use the searchService to fetch a measurement. Please note, that we

+			// use the per default defined method to fetch the measurement.

+			// This does not load any related ParameterSets! But

+			// we don't care at this point, because we just want to change 

+			// the related ParameterSet to a new one, not look at

+			// the existing relations.

+			mealist = searchService.fetch(Measurement.class, Filter.idOnly(etmeasurement, idmea));

+			assertEquals(1, mealist.size());

+			Measurement mea = mealist.get(0);

+

+			// load the parameter set which we want to relate to our measurment.

+			// again we don't care for any preexisting relations.

+			List<ParameterSet> paramsetlist = new ArrayList<>();

+			ParameterSet paramset = entityManager.load(ParameterSet.class, idparamset);

+			paramsetlist.add(paramset);

+			// Note: we can only set relations in the mutable store (which

+			// doesn't include parent-child-relations)

+			EntityStore store = ODSEntityFactory.getMutableStore(paramset);

+			store.set(mea);

+			assertEquals(store.get(Measurement.class), mea);

+

+			transaction.update(paramsetlist);

+			transaction.commit();

+

+			// reload from database and check if relation is consistent with

+			// expectations

+			// first we need to build our own SearchQuery, because the

+			// predefined ones don't include ParameterSet as stated above.

+			RelationSearchQuery mq = new RelationSearchQuery((ODSModelManager) modelManager,

+					queryService);

+			// the SearchQuery defines how to join measurement and parameterset,

+			// but we also have to declare that we want to fetch the related

+			// measurement

+			List<EntityType> fetchList = new ArrayList<>();

+			fetchList.add(etmeasurement);

+			List<Result> fetch = mq.fetchComplete(fetchList, Filter.idOnly(etparamset, idparamset));

+			assertEquals(fetch.size(), 1);

+			

+			// now we can check that the new relation is there as expected

+			Record record = fetch.get(0).getRecord(etmeasurement);

+			assertNotNull(record);

+			assertEquals(record.getID(), idmea);

+

+		} catch (RuntimeException e) {

+			transaction.abort();

+			throw e;

+		}

+

+	}

+	}

diff --git a/src/test/java/org/eclipse/mdm/api/odsadapter/notification/peak/PeakNotificationTest.java b/src/test/java/org/eclipse/mdm/api/odsadapter/notification/peak/PeakNotificationTest.java
index d84ab21..bb33a12 100644
--- a/src/test/java/org/eclipse/mdm/api/odsadapter/notification/peak/PeakNotificationTest.java
+++ b/src/test/java/org/eclipse/mdm/api/odsadapter/notification/peak/PeakNotificationTest.java
@@ -1,9 +1,9 @@
 package org.eclipse.mdm.api.odsadapter.notification.peak;
 
-import static org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory.PARAM_NAMESERVICE;
-import static org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory.PARAM_PASSWORD;
-import static org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory.PARAM_SERVICENAME;
-import static org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory.PARAM_USER;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_NAMESERVICE;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_PASSWORD;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_SERVICENAME;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_USER;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.mockito.Mockito.times;
@@ -34,15 +34,14 @@
 import org.eclipse.mdm.api.base.notification.NotificationException;
 import org.eclipse.mdm.api.base.notification.NotificationFilter;
 import org.eclipse.mdm.api.base.notification.NotificationListener;
-import org.eclipse.mdm.api.base.notification.NotificationManager;
+import org.eclipse.mdm.api.base.notification.NotificationService;
 import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
 import org.eclipse.mdm.api.dflt.EntityManager;
 import org.eclipse.mdm.api.dflt.model.EntityFactory;
-import org.eclipse.mdm.api.odsadapter.ODSEntityManager;
-import org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory;
-import org.eclipse.mdm.api.odsadapter.ODSNotificationManagerFactory;
-import org.eclipse.mdm.api.odsadapter.notification.peak.EventProcessor;
-import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.ODSContext;
+import org.eclipse.mdm.api.odsadapter.ODSContextFactory;
+import org.eclipse.mdm.api.odsadapter.notification.ODSNotificationServiceFactory;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Ignore;
@@ -92,8 +91,9 @@
 	private static final String NOTIFICATION_USER = "sa";
 	private static final String NOTIFICATION_PASSWORD = "sa";
 
+	private static ApplicationContext context;
 	private static EntityManager entityManager;
-	private static NotificationManager notificationManager;
+	private static NotificationService notificationManager;
 
 	@BeforeClass
 	public static void setUpBeforeClass() throws ConnectionException {
@@ -103,24 +103,22 @@
 		connectionParameters.put(PARAM_USER, USER);
 		connectionParameters.put(PARAM_PASSWORD, PASSWORD);
 
-		entityManager = new ODSEntityManagerFactory().connect(connectionParameters);
+		context = new ODSContextFactory().connect(connectionParameters);
 
 		Map<String, String> notificationParameters = new HashMap<>();
-		notificationParameters.put(ODSNotificationManagerFactory.PARAM_SERVER_TYPE,
-				ODSNotificationManagerFactory.SERVER_TYPE_PEAK);
-		notificationParameters.put(ODSNotificationManagerFactory.PARAM_URL, NOTIFICATION_URL);
-		notificationParameters.put(ODSEntityManagerFactory.PARAM_USER, NOTIFICATION_USER);
-		notificationParameters.put(ODSEntityManagerFactory.PARAM_PASSWORD, NOTIFICATION_PASSWORD);
-		notificationParameters.put(ODSNotificationManagerFactory.PARAM_EVENT_MEDIATYPE, "application/json");
+		notificationParameters.put(ODSNotificationServiceFactory.PARAM_SERVER_TYPE,
+				ODSNotificationServiceFactory.SERVER_TYPE_PEAK);
+		notificationParameters.put(ODSNotificationServiceFactory.PARAM_URL, NOTIFICATION_URL);
+		notificationParameters.put(ODSContextFactory.PARAM_USER, NOTIFICATION_USER);
+		notificationParameters.put(ODSContextFactory.PARAM_PASSWORD, NOTIFICATION_PASSWORD);
 
-		notificationManager = new ODSNotificationManagerFactory().create((ODSEntityManager) entityManager,
-				notificationParameters);
+		notificationManager = new ODSNotificationServiceFactory().create(context, notificationParameters);
 	}
 
 	@AfterClass
 	public static void tearDownAfterClass() throws ConnectionException, NotificationException {
-		if (entityManager != null) {
-			entityManager.close();
+		if (context != null) {
+			context.close();
 		}
 
 		if (notificationManager != null) {
@@ -219,7 +217,7 @@
 
 		assertThat("Parent test not found!", !tests.isEmpty());
 
-		Optional<EntityFactory> entityFactory = entityManager.getEntityFactory();
+		Optional<? extends EntityFactory> entityFactory = context.getEntityFactory();
 		if (!entityFactory.isPresent()) {
 			throw new IllegalStateException("Entity factory not present!");
 		}
@@ -246,7 +244,7 @@
 
 		AoSession session = null;
 		try {
-			session = ((ODSModelManager) entityManager.getModelManager().get()).getAoSession().createCoSession();
+			session = ((ODSContext) context).getAoSession().createCoSession();
 
 			ApplicationElement aeUUT = session.getApplicationStructure().getElementsByBaseType("AoUnitUnderTest")[0];
 
@@ -284,7 +282,7 @@
 
 		AoSession session = null;
 		try {
-			session = ((ODSModelManager) entityManager.getModelManager().get()).getAoSession().createCoSession();
+			session = ((ODSContext) context).getAoSession().createCoSession();
 
 			ApplicationElement aeTyre = session.getApplicationStructure().getElementByName("tyre");
 
diff --git a/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearchTest.java b/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearchTest.java
index 05070c5..eb99de7 100644
--- a/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearchTest.java
+++ b/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearchTest.java
@@ -4,6 +4,7 @@
 import static org.junit.Assert.assertTrue;

 import static org.mockito.Matchers.any;

 import static org.mockito.Matchers.anyCollection;

+import static org.mockito.Matchers.anyCollectionOf;

 import static org.mockito.Mockito.mock;

 import static org.mockito.Mockito.when;

 

@@ -126,7 +127,7 @@
 	@Test(expected = IllegalStateException.class)

 	public void illegalLoadRequest_niceExceptionIsThrown() throws DataAccessException, InterruptedException {

 		loader = mock(EntityLoader.class);

-		when(loader.loadAll(any(Key.class), anyCollection())).thenThrow(new DataAccessException(""));

+		when(loader.loadAll(any(), anyCollectionOf(String.class))).thenThrow(new DataAccessException(""));

 		createExampleIndex("TestStep", "mdm2", "asdf");

 		ODSFreeTextSearch fts2 = new ODSFreeTextSearch(loader, "mdm2", HOST);

 

diff --git a/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchServiceTest.java b/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchServiceTest.java
index af37982..b1228fa 100644
--- a/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchServiceTest.java
+++ b/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchServiceTest.java
@@ -1,160 +1,221 @@
-package org.eclipse.mdm.api.odsadapter.search;

-

-import static org.assertj.core.api.Assertions.assertThat;

-import static org.assertj.core.api.Assertions.tuple;

-import static org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory.PARAM_NAMESERVICE;

-import static org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory.PARAM_PASSWORD;

-import static org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory.PARAM_SERVICENAME;

-import static org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory.PARAM_USER;

-

-import java.util.Arrays;

-import java.util.Collections;

-import java.util.HashMap;

-import java.util.Map;

-

-import org.assertj.core.api.iterable.Extractor;

-import org.assertj.core.groups.Tuple;

-import org.eclipse.mdm.api.base.ConnectionException;

-import org.eclipse.mdm.api.base.model.TestStep;

-import org.eclipse.mdm.api.base.query.EntityType;

-import org.eclipse.mdm.api.base.query.Filter;

-import org.eclipse.mdm.api.base.query.FilterItem;

-import org.eclipse.mdm.api.base.query.ModelManager;

-import org.eclipse.mdm.api.base.query.BracketOperator;

-import org.eclipse.mdm.api.base.query.ComparisonOperator;

-import org.eclipse.mdm.api.base.query.BooleanOperator;

-import org.eclipse.mdm.api.dflt.EntityManager;

-import org.eclipse.mdm.api.odsadapter.ODSEntityManagerFactory;

-import org.junit.AfterClass;

-import org.junit.BeforeClass;

-import org.junit.Ignore;

-import org.junit.Test;

-import org.mockito.Mockito;

-

-import com.google.common.collect.ImmutableMap;

-

-@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 ODSSearchServiceTest {

-

-	/*

-	 * ATTENTION: ==========

-	 *

-	 * To run this test make sure the target service is running a MDM default

-	 * model and any database constraint which enforces a relation of Test to a

-	 * parent entity is deactivated!

-	 */

-

-	private static final String NAME_SERVICE = "corbaloc::1.2@%s:%s/NameService";

-

-	private static final String USER = "sa";

-	private static final String PASSWORD = "sa";

-

-	private static EntityManager entityManager;

-	private static ModelManager modelManager;

-

-	@BeforeClass

-	public static void setUpBeforeClass() throws ConnectionException {

-		String nameServiceHost = System.getProperty("host");

-		String nameServicePort = System.getProperty("port");

-		String serviceName = System.getProperty("service");

-

-		if (nameServiceHost == null || nameServiceHost.isEmpty()) {

-			throw new IllegalArgumentException("name service host is unknown: define system property 'host'");

-		}

-

-		nameServicePort = nameServicePort == null || nameServicePort.isEmpty() ? String.valueOf(2809) : nameServicePort;

-		if (nameServicePort == null || nameServicePort.isEmpty()) {

-			throw new IllegalArgumentException("name service port is unknown: define system property 'port'");

-		}

-

-		if (serviceName == null || serviceName.isEmpty()) {

-			throw new IllegalArgumentException("service name is unknown: define system property 'service'");

-		}

-

-		Map<String, String> connectionParameters = new HashMap<>();

-		connectionParameters.put(PARAM_NAMESERVICE, String.format(NAME_SERVICE, nameServiceHost, nameServicePort));

-		connectionParameters.put(PARAM_SERVICENAME, serviceName + ".ASAM-ODS");

-		connectionParameters.put(PARAM_USER, USER);

-		connectionParameters.put(PARAM_PASSWORD, PASSWORD);

-

-		entityManager = new ODSEntityManagerFactory().connect(connectionParameters);

-		modelManager = entityManager.getModelManager()

-				.orElseThrow(() -> new IllegalStateException("No ModelManager available!"));

-	}

-

-	@AfterClass

-	public static void tearDownAfterClass() throws ConnectionException {

-		if (entityManager != null) {

-			entityManager.close();

-		}

-	}

-

-	private Extractor<FilterItem, Tuple> filterExtractors = new Extractor<FilterItem, Tuple>() {

-

-		@Override

-		public Tuple extract(FilterItem f) {

-			return tuple(f.isBooleanOperator() ? f.getBooleanOperator() : null,

-					f.isCondition() ? f.getCondition().getAttribute().getName() : null,

-					f.isCondition() ? f.getCondition().getComparisonOperator() : null,

-					f.isCondition() ? f.getCondition().getValue().extract() : null,

-					f.isBracketOperator() ?f.getBracketOperator() : null);

-		}

-	};

-

-	@Test

-	public void testGetMergedFilter() throws Exception {

-

-		ODSSearchService service = Mockito.spy((ODSSearchService) entityManager.getSearchService()

-				.orElseThrow(() -> new IllegalStateException("No SearchService available!")));

-

-		Mockito.doReturn(ImmutableMap.of(TestStep.class, Arrays.asList("10"))).when(service)

-				.fetchIds(Mockito.anyString());

-

-		EntityType testStep = modelManager.getEntityType(TestStep.class);

-

-		assertThat(service.getMergedFilter(Filter.idOnly(testStep, "11"), "query")).hasSize(7)

-				.extracting(filterExtractors).containsExactly(tuple(null, null, null, null, BracketOperator.OPEN),

-						tuple(null, "Id", ComparisonOperator.EQUAL, "10"),

-						tuple(null, null, null, null, BracketOperator.CLOSE),

-						tuple(BooleanOperator.AND, null, null, null, null),

-						tuple(null, null, null, null, BracketOperator.OPEN),

-						tuple(null, "Id", ComparisonOperator.IN_SET, new String[] { "10" }, null),

-						tuple(null, null, null, null, BracketOperator.CLOSE));

-	}

-

-	@Test

-	public void testGetMergedFilterNoAttributeFilter() throws Exception {

-		ODSSearchService service = Mockito.spy((ODSSearchService) entityManager.getSearchService().get());

-

-		Mockito.doReturn(ImmutableMap.of(TestStep.class, Arrays.asList("10"))).when(service)

-				.fetchIds(Mockito.anyString());

-

-		assertThat(service.getMergedFilter(Filter.and(), "query")).extracting(filterExtractors)

-				.containsExactly(tuple(null, "Id", ComparisonOperator.IN_SET, new String[] { "10" }));

-	}

-

-	@Test

-	public void testGetMergedFilterNoFreetextResult() throws Exception {

-		ODSSearchService service = Mockito.spy((ODSSearchService) entityManager.getSearchService().get());

-

-		Mockito.doReturn(Collections.emptyMap()).when(service).fetchIds(Mockito.anyString());

-

-		EntityType testStep = modelManager.getEntityType(TestStep.class);

-

-		assertThat(service.getMergedFilter(Filter.idOnly(testStep, "11"), "")).extracting(filterExtractors)

-				.containsExactly(tuple(null, "Id", ComparisonOperator.EQUAL, "11"));

-	}

-

-	@Test

-	public void testGetMergedFilterNoAttributeFilterAndNoFreetextResult() throws Exception {

-		ODSSearchService service = Mockito.spy((ODSSearchService) entityManager.getSearchService().get());

-

-		Mockito.doReturn(Collections.emptyMap()).when(service).fetchIds(Mockito.anyString());

-

-		assertThat(service.getMergedFilter(Filter.and(), null)).isEmpty();

-

-		assertThat(service.getMergedFilter(Filter.and(), "")).isEmpty();

-	}

-}

+package org.eclipse.mdm.api.odsadapter.search;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_NAMESERVICE;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_PASSWORD;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_SERVICENAME;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_USER;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.assertj.core.api.iterable.Extractor;
+import org.assertj.core.groups.Tuple;
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.Transaction;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.EntityStore;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.ParameterSet;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.BooleanOperator;
+import org.eclipse.mdm.api.base.query.BracketOperator;
+import org.eclipse.mdm.api.base.query.ComparisonOperator;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.FilterItem;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.query.Record;
+import org.eclipse.mdm.api.base.query.Result;
+import org.eclipse.mdm.api.base.search.SearchService;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.eclipse.mdm.api.dflt.EntityManager;
+import org.eclipse.mdm.api.dflt.model.Pool;
+import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.odsadapter.ODSContextFactory;
+import org.eclipse.mdm.api.odsadapter.ODSEntityManager;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.search.JoinTree.JoinConfig;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.mockito.Mockito;
+
+import com.google.common.collect.ImmutableMap;
+
+@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 ODSSearchServiceTest {
+
+	/*
+	 * ATTENTION: ==========
+	 *
+	 * To run this test make sure the target service is running a MDM default
+	 * model and any database constraint which enforces a relation of Test to a
+	 * parent entity is deactivated!
+	 */
+
+	private static final String NAME_SERVICE = "corbaloc::1.2@%s:%s/NameService";
+
+	private static final String USER = "sa";
+	private static final String PASSWORD = "sa";
+
+	private static ApplicationContext context;
+	private static EntityManager entityManager;
+	private static ModelManager modelManager;
+	private static QueryService queryService;
+	private static SearchService searchService;
+	
+	@BeforeClass
+	public static void setUpBeforeClass() throws ConnectionException {
+		String nameServiceHost = System.getProperty("host");
+		String nameServicePort = System.getProperty("port");
+		String serviceName = System.getProperty("service");
+
+		if (nameServiceHost == null || nameServiceHost.isEmpty()) {
+			throw new IllegalArgumentException("name service host is unknown: define system property 'host'");
+		}
+
+		nameServicePort = nameServicePort == null || nameServicePort.isEmpty() ? String.valueOf(2809) : nameServicePort;
+		if (nameServicePort == null || nameServicePort.isEmpty()) {
+			throw new IllegalArgumentException("name service port is unknown: define system property 'port'");
+		}
+
+		if (serviceName == null || serviceName.isEmpty()) {
+			throw new IllegalArgumentException("service name is unknown: define system property 'service'");
+		}
+
+		Map<String, String> connectionParameters = new HashMap<>();
+		connectionParameters.put(PARAM_NAMESERVICE, String.format(NAME_SERVICE, nameServiceHost, nameServicePort));
+		connectionParameters.put(PARAM_SERVICENAME, serviceName + ".ASAM-ODS");
+		connectionParameters.put(PARAM_USER, USER);
+		connectionParameters.put(PARAM_PASSWORD, PASSWORD);
+
+		context  = new ODSContextFactory().connect(connectionParameters);
+		entityManager = context.getEntityManager()
+				.orElseThrow(() -> new ServiceNotProvidedException(EntityManager.class));
+		modelManager = context.getModelManager()
+				.orElseThrow(() -> new ServiceNotProvidedException(ModelManager.class));
+		queryService = context.getQueryService()
+				.orElseThrow(() -> new ServiceNotProvidedException(QueryService.class));
+		searchService = context.getSearchService()
+				.orElseThrow(() -> new IllegalStateException("Search service not available."));
+	}
+
+	@AfterClass
+	public static void tearDownAfterClass() throws ConnectionException {
+		if (context != null) {
+			context.close();
+		}
+	}
+	
+	final class MeasurementSearchQuery extends BaseEntitySearchQuery {
+
+		/**
+		 * Constructor.
+		 *
+		 * @param modelManager
+		 *            Used to load {@link EntityType}s.
+		 * @param contextState
+		 *            The {@link ContextState}.
+		 */
+		MeasurementSearchQuery(ODSModelManager modelManager, QueryService queryService, ContextState contextState) {
+			super(modelManager, queryService, ParameterSet.class, Project.class);
+
+			// layers
+			addJoinConfig(JoinConfig.up(Pool.class, Project.class));
+			addJoinConfig(JoinConfig.up(Test.class, Pool.class));
+			addJoinConfig(JoinConfig.up(TestStep.class, Test.class));
+			addJoinConfig(JoinConfig.up(Measurement.class, TestStep.class));
+			addJoinConfig(JoinConfig.up(ParameterSet.class, Measurement.class));
+			addJoinConfig(JoinConfig.down(Measurement.class, Channel.class));
+			addJoinConfig(JoinConfig.down(Measurement.class, ChannelGroup.class));
+
+			// context
+			addJoinConfig(contextState);
+		}
+
+	}
+		
+	private Extractor<FilterItem, Tuple> filterExtractors = new Extractor<FilterItem, Tuple>() {
+
+		@Override
+		public Tuple extract(FilterItem f) {
+			return tuple(f.isBooleanOperator() ? f.getBooleanOperator() : null,
+					f.isCondition() ? f.getCondition().getAttribute().getName() : null,
+					f.isCondition() ? f.getCondition().getComparisonOperator() : null,
+					f.isCondition() ? f.getCondition().getValue().extract() : null,
+					f.isBracketOperator() ?f.getBracketOperator() : null);
+		}
+	};
+
+	@org.junit.Test
+	public void testGetMergedFilter() throws Exception {
+
+		ODSSearchService service = Mockito.spy((ODSSearchService) searchService);
+
+		Mockito.doReturn(ImmutableMap.of(TestStep.class, Arrays.asList("10"))).when(service)
+				.fetchIds(Mockito.anyString());
+
+		EntityType testStep = modelManager.getEntityType(TestStep.class);
+
+		assertThat(service.getMergedFilter(Filter.idOnly(testStep, "11"), "query")).hasSize(7)
+				.extracting(filterExtractors).containsExactly(tuple(null, null, null, null, BracketOperator.OPEN),
+						tuple(null, "Id", ComparisonOperator.EQUAL, "10"),
+						tuple(null, null, null, null, BracketOperator.CLOSE),
+						tuple(BooleanOperator.AND, null, null, null, null),
+						tuple(null, null, null, null, BracketOperator.OPEN),
+						tuple(null, "Id", ComparisonOperator.IN_SET, new String[] { "10" }, null),
+						tuple(null, null, null, null, BracketOperator.CLOSE));
+	}
+
+	@org.junit.Test
+	public void testGetMergedFilterNoAttributeFilter() throws Exception {
+		ODSSearchService service = Mockito.spy((ODSSearchService) searchService);
+
+		Mockito.doReturn(ImmutableMap.of(TestStep.class, Arrays.asList("10"))).when(service)
+				.fetchIds(Mockito.anyString());
+
+		assertThat(service.getMergedFilter(Filter.and(), "query")).extracting(filterExtractors)
+				.containsExactly(tuple(null, "Id", ComparisonOperator.IN_SET, new String[] { "10" }));
+	}
+
+	@org.junit.Test
+	public void testGetMergedFilterNoFreetextResult() throws Exception {
+		ODSSearchService service = Mockito.spy((ODSSearchService) searchService);
+
+		Mockito.doReturn(Collections.emptyMap()).when(service).fetchIds(Mockito.anyString());
+
+		EntityType testStep = modelManager.getEntityType(TestStep.class);
+
+		assertThat(service.getMergedFilter(Filter.idOnly(testStep, "11"), "")).extracting(filterExtractors)
+				.containsExactly(tuple(null, "Id", ComparisonOperator.EQUAL, "11"));
+	}
+
+	@org.junit.Test
+	public void testGetMergedFilterNoAttributeFilterAndNoFreetextResult() throws Exception {
+		ODSSearchService service = Mockito.spy((ODSSearchService) searchService);
+
+		Mockito.doReturn(Collections.emptyMap()).when(service).fetchIds(Mockito.anyString());
+
+		assertThat(service.getMergedFilter(Filter.and(), null)).isEmpty();
+
+		assertThat(service.getMergedFilter(Filter.and(), "")).isEmpty();
+	}
+}
diff --git a/src/test/java/org/eclipse/mdm/api/odsadapter/search/RelationSearchQuery.java b/src/test/java/org/eclipse/mdm/api/odsadapter/search/RelationSearchQuery.java
new file mode 100755
index 0000000..4ccb327
--- /dev/null
+++ b/src/test/java/org/eclipse/mdm/api/odsadapter/search/RelationSearchQuery.java
@@ -0,0 +1,62 @@
+/*

+ * Copyright (c) 2017 Florian Schmitt and others

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ */

+

+package org.eclipse.mdm.api.odsadapter.search;

+

+import org.eclipse.mdm.api.base.adapter.EntityType;

+import org.eclipse.mdm.api.base.model.Channel;

+import org.eclipse.mdm.api.base.model.ChannelGroup;

+import org.eclipse.mdm.api.base.model.Measurement;

+import org.eclipse.mdm.api.base.model.ParameterSet;

+import org.eclipse.mdm.api.base.model.Test;

+import org.eclipse.mdm.api.base.model.TestStep;

+import org.eclipse.mdm.api.base.query.QueryService;

+import org.eclipse.mdm.api.dflt.model.Pool;

+import org.eclipse.mdm.api.dflt.model.Project;

+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;

+import org.eclipse.mdm.api.odsadapter.search.JoinTree.JoinConfig;

+

+/**

+ * This class is used as a helper to the tests in org.eclipse.mdm.api.odsadapter.RelationTest

+ * It needs to be here, because BaseEntitySearchQuery is declared as protected

+ * in the org.eclipse.mdm.api.odsadapter.search package. 

+ * It makes some sense to leave it protected in that way, because implementing a BaseEntitySearchQuery

+ * requires understanding of the underlying data model which   

+ * The RelationTest requires that the related parametersets to a measurement are

+ * loaded. This class provides a JoinConfig which allows this to happen by defining

+ * the way the entities in question have to be joined. 

+ * If we wouldn't join the ParameterSet in, the related

+ * entities would not be loaded, and it would be impossible to determine whether there

+ * are any related ParameterSets or not.

+ *

+ */

+public final class RelationSearchQuery extends BaseEntitySearchQuery {

+

+	/**

+	 * Constructor.

+	 *

+	 * @param modelManager

+	 *            Used to load {@link EntityType}s.

+	 * @param contextState

+	 *            The {@link ContextState}.

+	 */

+	public RelationSearchQuery(ODSModelManager modelManager, QueryService queryService) {

+		super(modelManager, queryService, ParameterSet.class, Project.class);

+

+		// layers

+		addJoinConfig(JoinConfig.up(Pool.class, Project.class));

+		addJoinConfig(JoinConfig.up(Test.class, Pool.class));

+		addJoinConfig(JoinConfig.up(TestStep.class, Test.class));

+		addJoinConfig(JoinConfig.up(Measurement.class, TestStep.class));

+		addJoinConfig(JoinConfig.up(ParameterSet.class, Measurement.class));

+		addJoinConfig(JoinConfig.down(Measurement.class, Channel.class));

+		addJoinConfig(JoinConfig.down(Measurement.class, ChannelGroup.class));

+

+	}

+

+}
\ No newline at end of file
diff --git a/src/test/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverterTest.java b/src/test/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverterTest.java
new file mode 100644
index 0000000..2478683
--- /dev/null
+++ b/src/test/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverterTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2017 Peak Solution GmbH
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.eclipse.mdm.api.odsadapter.utils;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.time.LocalDateTime;
+
+import org.asam.ods.TS_UnionSeq;
+import org.asam.ods.TS_ValueSeq;
+import org.eclipse.mdm.api.odsadapter.query.ODSAttribute;
+import org.junit.Test;
+
+public class ODSConverterTest {
+
+	@Test
+	public void testFromODSValueSeqODSDateYear() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("2017"));
+
+		verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 1, 1, 0, 0)));
+	}
+
+	@Test
+	public void testFromODSValueSeqODSDateMonth() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("201710"));
+
+		verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 1, 0, 0)));
+	}
+
+	@Test
+	public void testFromODSValueSeqODSDate() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("20171004"));
+
+		verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 4, 0, 0)));
+	}
+
+	@Test
+	public void testFromODSValueSeqODSDateHour() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("2017100412"));
+
+		verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 4, 12, 0)));
+	}
+
+	@Test
+	public void testFromODSValueSeqODSDateMinute() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("201710041213"));
+
+		verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 4, 12, 13)));
+	}
+
+	@Test
+	public void testFromODSValueSeqODSDateSecond() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("20171004121314"));
+
+		verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 4, 12, 13, 14, 0)));
+	}
+
+	@Test
+	public void testFromODSValueSeqODSDateMillisecond() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("20171004121314123"));
+
+		verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 4, 12, 13, 14, 123_000_000)));
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testFromODSValueSeqInvalidLength() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("201710041"));
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testFromODSValueSeqInvalidMonth() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, "", getTS_ValueSeqFromDates("20171304"));
+	}
+
+	private TS_ValueSeq getTS_ValueSeqFromDates(String... dates) {
+		TS_UnionSeq u = new TS_UnionSeq();
+		u.dateVal(dates);
+		return new TS_ValueSeq(u, new short[] { 15 });
+	}
+}