525536: make access to entitystores possible and improve documentation and examples for relations
Change-Id: I75c2f2385eade9d25c1dee4626b7d9f20d6e9fdb
Signed-off-by: Florian Schmitt <florian.schmitt@atos.net>
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 f014bee..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
@@ -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/query/ODSEntityFactory.java b/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSEntityFactory.java
index 39e0008..117b241 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
@@ -19,7 +19,9 @@
import java.util.Set;
import org.eclipse.mdm.api.base.adapter.DefaultCore;
+import org.eclipse.mdm.api.base.core.ChildrenStore;
import org.eclipse.mdm.api.base.core.Core;
+import org.eclipse.mdm.api.base.core.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;
@@ -162,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}
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..e14b583
--- /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.EntityType;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.core.EntityStore;
+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/search/ODSSearchServiceTest.java b/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchServiceTest.java
index e7c1a75..372e173 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
@@ -48,6 +48,7 @@
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;
@@ -151,77 +152,7 @@
}
}
-
- /**
- * 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;
- mealist = searchService.fetch(Measurement.class, Filter.idOnly(etmeasurement, idmea));
- assertEquals(1, mealist.size());
- Measurement mea = mealist.get(0);
-
- List<ParameterSet> paramsetlist = new ArrayList<>();
- ParameterSet paramset = entityManager.load(ParameterSet.class, idparamset);
- paramsetlist.add(paramset);
-
- // FIXME: the API should expose the getCore method so that we don't
- // need to use introspection
- // to access the core.
- Method GET_CORE_METHOD;
- 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);
- }
- Core core = (Core) GET_CORE_METHOD.invoke(paramset);
- // Note: we can only set relations in the mutable store (which
- // doesn't include parent-child-relations)
- EntityStore store = core.getMutableStore();
- store.set(mea);
- assertEquals(core.getMutableStore().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
- MeasurementSearchQuery mq = new MeasurementSearchQuery((ODSModelManager) modelManager,
- queryService,
- ContextState.MEASURED);
- List<EntityType> fetchList = new ArrayList<>();
- fetchList.add(etmeasurement);
- List<Result> fetch = mq.fetchComplete(fetchList, Filter.idOnly(etparamset, idparamset));
- assertEquals(fetch.size(), 1);
- Record record = fetch.get(0).getRecord(etmeasurement);
- assertNotNull(record);
- assertEquals(record.getID(), idmea);
-
- } catch (RuntimeException | IllegalAccessException | InvocationTargetException e) {
- transaction.abort();
- throw e;
- }
-
- }
-
+
private Extractor<FilterItem, Tuple> filterExtractors = new Extractor<FilterItem, Tuple>() {
@Override
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