From 83b3e119789898dea1774098f43574edc1b52ece Mon Sep 17 00:00:00 2001 From: Juergen Albert Date: Sat, 31 Aug 2024 12:33:44 +0200 Subject: [PATCH] adds option to overwrite ID Attribute Signed-off-by: Juergen Albert --- .project | 11 ++++ Jenkinsfile | 4 +- cnf/build.bnd | 4 +- cnf/central.mvn | 4 +- org.gecko.emf.mongo/launch.bndrun | 15 +++-- .../src/org/gecko/emf/mongo/MongoUtils.java | 6 +- .../src/org/gecko/emf/mongo/Options.java | 61 +++++++++++++++++ .../codecs/builder/DBObjectBuilderImpl.java | 2 +- .../codecs/builder/EObjectBuilderImpl.java | 2 +- .../src/org/gecko/emf/mongo/package-info.java | 2 +- .../emf/mongo/streams/MongoOutputStream.java | 19 +++--- .../MongoConfiguratorIntegrationTest.java | 65 +++++++++++++++++++ .../test.bndrun | 14 ++-- org.gecko.emf.repository.mongo/bnd.bnd | 2 +- .../impl/AbstractEMFMongoRepository.java | 19 ++++-- org.gecko.emf.repository.tests/test.bndrun | 13 ++-- .../emf/repository/DefaultEMFRepository.java | 2 +- .../repository/helper/RepositoryHelper.java | 20 ++++-- 18 files changed, 208 insertions(+), 57 deletions(-) create mode 100644 .project diff --git a/.project b/.project new file mode 100644 index 0000000..486c5b9 --- /dev/null +++ b/.project @@ -0,0 +1,11 @@ + + + _ + + + + + + + + diff --git a/Jenkinsfile b/Jenkinsfile index 0de2e59..245f34c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -30,13 +30,13 @@ pipeline { sh "cp -r cnf/release/* $JENKINS_HOME/repo.gecko/snapshot/org.gecko.persistence" } } - stage('Gitlab branch release') { + stage('Gitlab branch Build') { when { branch 'gitlab' } steps { echo "I am building on ${env.JOB_NAME}" - sh "./gradlew clean build release --info --stacktrace -Dmaven.repo.local=${WORKSPACE}/.m2" + sh "./gradlew clean build release --info --stacktrace -Dmaven.repo.local=${WORKSPACE}/.m2 --no-daemon" sh "mkdir -p $JENKINS_HOME/repo.gecko/snapshot/org.gecko.emf.persistence_gitlab" sh "rm -rf $JENKINS_HOME/repo.gecko/snapshot/org.gecko.emf.persistence_gitlab/*" sh "cp -r cnf/release/* $JENKINS_HOME/repo.gecko/snapshot/org.gecko.emf.persistence_gitlab" diff --git a/cnf/build.bnd b/cnf/build.bnd index 5ac3817..798b0eb 100644 --- a/cnf/build.bnd +++ b/cnf/build.bnd @@ -13,8 +13,8 @@ dimcBaselining: true mavenCentral: true github-project: org.gecko.emf.persistence -base-version: 6.1.1 -repository-base-version: 9.3.0.${tstamp}-SNAPSHOT +base-version: 6.2.0 +repository-base-version: 9.4.0.${tstamp}-SNAPSHOT # Maven Central Group-Id # For Geckoprojects the groupid must start with org.geckoprojects diff --git a/cnf/central.mvn b/cnf/central.mvn index 32912df..d448d0e 100644 --- a/cnf/central.mvn +++ b/cnf/central.mvn @@ -142,8 +142,8 @@ org.freemarker:freemarker:2.3.32 org.geckoprojects.bnd:org.gecko.bnd.dimc.library:1.5.0 org.geckoprojects.bnd:org.gecko.bnd.jacoco.library:1.5.0 org.geckoprojects.bnd:org.gecko.bnd.osgitest.library:1.5.0 -org.geckoprojects.emf:org.gecko.emf.osgi.bnd.library.workspace:6.0.2 -org.geckoprojects.emf:org.gecko.emf.osgi.example.model.basic:6.0.2 +org.geckoprojects.emf:org.gecko.emf.osgi.bnd.library.workspace:6.2.0 +org.geckoprojects.emf:org.gecko.emf.osgi.example.model.basic:6.2.0 org.geckoprojects.emf.utils:org.gecko.emf.collections:2.2.2 org.mongodb:mongo-java-driver:3.12.14 org.geckoprojects.emf:org.gecko.emf.pushstreams:1.0.15 diff --git a/org.gecko.emf.mongo/launch.bndrun b/org.gecko.emf.mongo/launch.bndrun index e139e58..2591983 100644 --- a/org.gecko.emf.mongo/launch.bndrun +++ b/org.gecko.emf.mongo/launch.bndrun @@ -10,20 +10,23 @@ org.apache.felix.gogo.runtime;version='[1.1.6,1.1.7)',\ org.apache.felix.gogo.shell;version='[1.1.4,1.1.5)',\ org.apache.felix.scr;version='[2.2.6,2.2.7)',\ - org.eclipse.emf.common;version='[2.28.0,2.28.1)',\ - org.eclipse.emf.ecore;version='[2.33.0,2.33.1)',\ - org.eclipse.emf.ecore.xmi;version='[2.18.0,2.18.1)',\ - org.gecko.emf.collections;version='[2.2.0,2.2.1)',\ org.gecko.emf.mongo.api;version=snapshot,\ org.gecko.emf.mongo.component;version=snapshot,\ - org.gecko.emf.osgi.api;version='[6.0.0,6.0.1)',\ org.gecko.mongo.osgi.component;version=snapshot,\ org.mongodb.mongo-java-driver;version='[3.12.14,3.12.15)',\ org.osgi.service.component;version='[1.5.1,1.5.2)',\ org.osgi.service.log;version='[1.5.0,1.5.1)',\ org.osgi.service.metatype;version='[1.4.1,1.4.2)',\ org.osgi.util.function;version='[1.2.0,1.2.1)',\ - org.osgi.util.promise;version='[1.3.0,1.3.1)' + org.osgi.util.promise;version='[1.3.0,1.3.1)',\ + org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ + org.eclipse.emf.common;version='[2.29.0,2.29.1)',\ + org.eclipse.emf.ecore;version='[2.35.0,2.35.1)',\ + org.eclipse.emf.ecore.xmi;version='[2.36.0,2.36.1)',\ + org.gecko.emf.collections;version='[2.2.2,2.2.3)',\ + org.gecko.emf.osgi.component.minimal;version='[6.2.0,6.2.1)',\ + org.osgi.service.cm;version='[1.6.1,1.6.2)',\ + org.osgi.util.converter;version='[1.0.9,1.0.10)' -runrequires: \ osgi.identity;filter:='(osgi.identity=org.apache.felix.gogo.shell)',\ diff --git a/org.gecko.emf.mongo/src/org/gecko/emf/mongo/MongoUtils.java b/org.gecko.emf.mongo/src/org/gecko/emf/mongo/MongoUtils.java index 6dda3b6..632e2e0 100644 --- a/org.gecko.emf.mongo/src/org/gecko/emf/mongo/MongoUtils.java +++ b/org.gecko.emf.mongo/src/org/gecko/emf/mongo/MongoUtils.java @@ -42,7 +42,7 @@ public static Object getID(URI uri) throws IOException { if (uri.segmentCount() != 3) { throw new IOException("The URI is not of the form 'mongo:/database/collection/{id}"); } - String id = uri.segment(2); + String id = URI.decode(uri.segment(2)); // If the ID was specified in the URI, we first attempt to create a MongoDB ObjectId. If // that fails, we assume that the client has specified a non ObjectId and return the raw data. @@ -68,7 +68,7 @@ public static String getIDAsString(URI uri) throws IOException { if (uri.segmentCount() != 3) { throw new IOException("The URI is not of the form 'mongo:/database/collection/{id}"); } - String id = uri.segment(2); + String id = URI.decode(uri.segment(2)); return id; } @@ -82,7 +82,7 @@ public static String getIDAsString(URI uri) throws IOException { */ public static Object getIDWithValidURI(URI uri) { - String id = uri.segment(2); + String id = URI.decode(uri.segment(2)); // If the ID was specified in the URI, we first attempt to create a MongoDB ObjectId. If // that fails, we assume that the client has specified a non ObjectId and return the raw data. diff --git a/org.gecko.emf.mongo/src/org/gecko/emf/mongo/Options.java b/org.gecko.emf.mongo/src/org/gecko/emf/mongo/Options.java index cfc6a1e..cc2d892 100644 --- a/org.gecko.emf.mongo/src/org/gecko/emf/mongo/Options.java +++ b/org.gecko.emf.mongo/src/org/gecko/emf/mongo/Options.java @@ -11,10 +11,12 @@ *******************************************************************************/ package org.gecko.emf.mongo; +import java.util.List; import java.util.Map; import org.eclipse.emf.common.util.ECollections; import org.eclipse.emf.common.util.Enumerator; +import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; @@ -310,6 +312,23 @@ public interface Options { * */ String OPTION_COLLECTION_NAME = "COLLECTION_NAME"; + + /** + * An {@link EAttribute} to use as primary key instead of the ID Attribute + * + * Value type: {@link EAttribute} + */ + String OVERWRITE_PRIMARY_KEY_EATTRIBUTE = "OVERWRITE_PRIMARY_KEY_EATTRIBUTE"; + + /** + * A List of potential {@link EAttribute}s to use as primary key instead of the ID Attribute. + * The first {@link EAttribute} that fits the {@link EClass} to store will be used. + * + * If OVERWRITE_PRIMARY_KEY_EATTRIBUTE is set at the same time, it will be evaluated first. + * + * Value type: {@link List} of {@link EAttribute} + */ + String OVERWRITE_PRIMARY_KEY_EATTRIBUTES = "OVERWRITE_PRIMARY_KEY_EATTRIBUTES"; /** * Returns true, if the {@link Options#OPTION_USE_EXTENDED_METADATA} @@ -433,4 +452,46 @@ public static String getCollectionName(Map options) { return alias == null ? null : alias.toString(); } + public static EAttribute getIDAttribute(EClass eClass, Map options) { + if(options == null) { + return eClass.getEIDAttribute(); + } + + EAttribute idAttribute = (EAttribute) options.getOrDefault(OVERWRITE_PRIMARY_KEY_EATTRIBUTE, null); + if(idAttribute != null && idAttribute.getEContainingClass().isSuperTypeOf(eClass)) { + return idAttribute; + } + + Object attributesObject = options.getOrDefault(OVERWRITE_PRIMARY_KEY_EATTRIBUTES, null); + if(attributesObject != null) { + @SuppressWarnings("unchecked") + List attributes = (List) attributesObject; + int firstHit = -1; + for (int i = 0; i < attributes.size(); i++) { + EAttribute eAttribute = attributes.get(i); + EClass containingEClass = eAttribute.getEContainingClass(); + if(containingEClass == eClass) { + return eAttribute; + } + if(firstHit != -1 && eAttribute.getEContainingClass().isSuperTypeOf(eClass)) { + firstHit = i; + } + } + if(firstHit != -1) { + return attributes.get(firstHit); + } + } + + return eClass.getEIDAttribute(); + } + + public static boolean useIdAttributeAsPrimaryKey(Map options) { + Object value = options.getOrDefault(OPTION_USE_ID_ATTRIBUTE_AS_PRIMARY_KEY, null); + if(value == null) { + return false; + } else if(value instanceof String) { + return Boolean.parseBoolean((String) value); + } + return (boolean) value; + } } diff --git a/org.gecko.emf.mongo/src/org/gecko/emf/mongo/codecs/builder/DBObjectBuilderImpl.java b/org.gecko.emf.mongo/src/org/gecko/emf/mongo/codecs/builder/DBObjectBuilderImpl.java index f04cbda..7f82001 100644 --- a/org.gecko.emf.mongo/src/org/gecko/emf/mongo/codecs/builder/DBObjectBuilderImpl.java +++ b/org.gecko.emf.mongo/src/org/gecko/emf/mongo/codecs/builder/DBObjectBuilderImpl.java @@ -226,7 +226,7 @@ private void writeMongoIdAttribute(BsonWriter writer, EObject eObject){ Boolean useIdAttributeAsPrimaryKey = (Boolean) options.get(Options.OPTION_USE_ID_ATTRIBUTE_AS_PRIMARY_KEY); Object id = null; if (useIdAttributeAsPrimaryKey == null || useIdAttributeAsPrimaryKey) { - EAttribute idAttribute = eObject.eClass().getEIDAttribute(); + EAttribute idAttribute = Options.getIDAttribute(eObject.eClass(), options); if (idAttribute != null) { id = eObject.eGet(idAttribute); } diff --git a/org.gecko.emf.mongo/src/org/gecko/emf/mongo/codecs/builder/EObjectBuilderImpl.java b/org.gecko.emf.mongo/src/org/gecko/emf/mongo/codecs/builder/EObjectBuilderImpl.java index 5698502..ce78fd1 100644 --- a/org.gecko.emf.mongo/src/org/gecko/emf/mongo/codecs/builder/EObjectBuilderImpl.java +++ b/org.gecko.emf.mongo/src/org/gecko/emf/mongo/codecs/builder/EObjectBuilderImpl.java @@ -272,7 +272,7 @@ public EObject decodeObject(BsonReader reader, DecoderContext context, Resource } oid = oidValue.toString(); reader.readBsonType(); //set the reader to the state requried by the next step. - URI uri = baseUri.trimSegments(1).appendSegment(oid).trimQuery(); + URI uri = baseUri.trimSegments(1).appendSegment(URI.encodeSegment(oid, true)).trimQuery(); if(!resource.getURI().equals(uri)){ loadResource = factory.createResource(uri); if(resourceCache != null){ diff --git a/org.gecko.emf.mongo/src/org/gecko/emf/mongo/package-info.java b/org.gecko.emf.mongo/src/org/gecko/emf/mongo/package-info.java index 3853005..86c313a 100644 --- a/org.gecko.emf.mongo/src/org/gecko/emf/mongo/package-info.java +++ b/org.gecko.emf.mongo/src/org/gecko/emf/mongo/package-info.java @@ -1,3 +1,3 @@ -@org.osgi.annotation.versioning.Version("5.0.0") +@org.osgi.annotation.versioning.Version("5.1.0") @org.gecko.emf.mongo.annotations.RequireMongoEMF package org.gecko.emf.mongo; diff --git a/org.gecko.emf.mongo/src/org/gecko/emf/mongo/streams/MongoOutputStream.java b/org.gecko.emf.mongo/src/org/gecko/emf/mongo/streams/MongoOutputStream.java index 7231998..3d121ac 100644 --- a/org.gecko.emf.mongo/src/org/gecko/emf/mongo/streams/MongoOutputStream.java +++ b/org.gecko.emf.mongo/src/org/gecko/emf/mongo/streams/MongoOutputStream.java @@ -84,8 +84,7 @@ public MongoOutputStream(ConverterService converterService, MongoCollection collection) throws IOE List> bulk = new ArrayList<>(contents.size()); for (EObject eObject : contents) { - EAttribute idAttribute = eObject.eClass().getEIDAttribute(); + EAttribute idAttribute = Options.getIDAttribute(eObject.eClass(), mergedOptions); if(idAttribute == null && useIdAttributeAsPrimaryKey){ throw new IllegalStateException("EObjects have no ID Attribute to be used together with option " + Options.OPTION_USE_ID_ATTRIBUTE_AS_PRIMARY_KEY); @@ -186,7 +185,7 @@ private void saveMultipleObjects(MongoCollection collection) throws IOE if(forceInsert){ bulk.add(new InsertOneModel(eObject)); } else { - Bson updateFilter = createUpdateFilter(eObject); + Bson updateFilter = createUpdateFilter(eObject, idAttribute); bulk.add(new ReplaceOneModel(updateFilter, eObject, ReplaceOptions.createReplaceOptions(UPDATE_OPTIONS))); } } @@ -216,14 +215,13 @@ private void saveMultipleObjects(MongoCollection collection) throws IOE * @param collection the collection to save the object for * @throws IOException thrown on errors during saving */ - private void saveSingleObject(MongoCollection collection) throws IOException { + private void saveSingleObject(MongoCollection collection, EAttribute idAttribute) throws IOException { EObject eObject = resource.getContents().get(0); if(forceInsert){ collection.insertOne(eObject); } else { - Bson updateFilter = createUpdateFilter(eObject); + Bson updateFilter = createUpdateFilter(eObject, idAttribute); FindOneAndReplaceOptions farOptions = new FindOneAndReplaceOptions().upsert(true).returnDocument(ReturnDocument.AFTER); - EAttribute idAttribute = eObject.eClass().getEIDAttribute(); // Minimize the load by just adding projection for minimum set of attributes if (idAttribute != null) { String eClassKey = Options.getEClassKey((Map) mergedOptions); @@ -244,7 +242,7 @@ private void saveSingleObject(MongoCollection collection) throws IOExce } } - private Bson createUpdateFilter(EObject eObject) throws IOException { + private Bson createUpdateFilter(EObject eObject, EAttribute idAttribute) throws IOException { String idKey = "_id"; Object id = null; if (!useIdAttributeAsPrimaryKey) { @@ -252,7 +250,6 @@ private Bson createUpdateFilter(EObject eObject) throws IOException { if (pkId != null && !pkId.isEmpty()) { id = normalizeMongoId(pkId); } else { - EAttribute idAttribute = eObject.eClass().getEIDAttribute(); idKey = idAttribute == null ? "_id" : idAttribute.getName(); id = EcoreUtil.getID(eObject); } diff --git a/org.gecko.emf.repository.mongo.tests/src/org/gecko/emf/repository/mongo/tests/MongoConfiguratorIntegrationTest.java b/org.gecko.emf.repository.mongo.tests/src/org/gecko/emf/repository/mongo/tests/MongoConfiguratorIntegrationTest.java index 021c1dd..1ecece4 100644 --- a/org.gecko.emf.repository.mongo.tests/src/org/gecko/emf/repository/mongo/tests/MongoConfiguratorIntegrationTest.java +++ b/org.gecko.emf.repository.mongo.tests/src/org/gecko/emf/repository/mongo/tests/MongoConfiguratorIntegrationTest.java @@ -19,15 +19,20 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; +import java.util.Collections; import java.util.Dictionary; import java.util.Hashtable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EcorePackage; +import org.eclipse.emf.ecore.impl.EPackageImpl; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.util.EcoreUtil; +import org.gecko.emf.mongo.Options; import org.gecko.emf.osgi.ResourceSetFactory; import org.gecko.emf.osgi.constants.EMFNamespaces; import org.gecko.emf.osgi.example.model.basic.BasicFactory; @@ -159,6 +164,66 @@ public void testEMFMongoRepository(@InjectService(cardinality = 0) ServiceAware< assertTrue(mdpAware.isEmpty()); assertTrue(rsfAware.isEmpty()); } + + @Test + public void testEMFMongoRepositoryOptionOverwritePrimaryKey(@InjectService(cardinality = 0) ServiceAware mcpAware, + @InjectService(cardinality = 0) ServiceAware mdpAware, + @InjectService(cardinality = 0, filter = "(" + EMFRepository.PROP_ID + "=test1.test)") ServiceAware repoAware, + @InjectService(cardinality = 0, filter = "(&(" + EMFNamespaces.EMF_CONFIGURATOR_NAME + "=mongo)(" + EMFNamespaces.EMF_CONFIGURATOR_NAME + "=test1.test))") ServiceAware rsfAware) throws BundleException, InvalidSyntaxException, IOException, InterruptedException { + /** + * mongo.instances=test1 + * test1.baseUris=mongodb://localhost + * test1.databases=test + */ + + Dictionary configProperties = new Hashtable<>(); + configProperties.put("mongo.instances", "test1"); + configProperties.put("test1.baseUris", "mongodb://" + mongoHost); + configProperties.put("test1.databases", "test"); + +// String clientId = "test1.test"; + +// defaultCheck(); + + assertTrue(repoAware.isEmpty()); + assertTrue(mcpAware.isEmpty()); + assertTrue(mdpAware.isEmpty()); + assertTrue(rsfAware.isEmpty()); + + Configuration repositoryConfig = configAdmin.createFactoryConfiguration(EMFMongoConfiguratorConstants.EMF_MONGO_REPOSITORY_CONFIGURATOR_CONFIGURATION_NAME, "?"); + repositoryConfig.update(configProperties); + + rsfAware.waitForService(2000l); + mcpAware.waitForService(2000l); + mdpAware.waitForService(2000l); + + EMFRepository repository = repoAware.waitForService(2000l); + URI expected = URI.createURI("mongodb://test1/test/EPackage").appendSegment(URI.encodeSegment(BasicPackage.eINSTANCE.getNsURI(), true)).appendFragment(URI.encodeFragment(BasicPackage.eINSTANCE.getNsURI(), true)); + + URI uri = repository.createUri(BasicPackage.eINSTANCE, Collections.singletonMap(Options.OVERWRITE_PRIMARY_KEY_EATTRIBUTE, EcorePackage.Literals.EPACKAGE__NS_URI)); + System.out.println("EAttribute URI"); + System.out.println("========================================================="); + System.out.println(uri); + assertEquals(expected, uri); + + uri = repository.createUri(BasicPackage.eINSTANCE, Collections.singletonMap(Options.OVERWRITE_PRIMARY_KEY_EATTRIBUTES, Collections.singletonList(EcorePackage.Literals.EPACKAGE__NS_URI))); + System.out.println("EAttribute URI2"); + System.out.println("========================================================="); + System.out.println(uri); + assertEquals(expected, uri); + + EObject basicPackage = EcoreUtil.copy(BasicPackage.eINSTANCE); + repository.save(basicPackage, Collections.singletonMap(Options.OVERWRITE_PRIMARY_KEY_EATTRIBUTE, EcorePackage.Literals.EPACKAGE__NS_URI)); + repository.detach(basicPackage); + + EObject eObject = repository.getEObject(EcorePackage.Literals.EPACKAGE, BasicPackage.eINSTANCE.getNsURI(), Collections.singletonMap(Options.OVERWRITE_PRIMARY_KEY_EATTRIBUTE, EcorePackage.Literals.EPACKAGE__NS_URI)); + + assertNotNull(eObject); + assertEquals(EcorePackage.Literals.EPACKAGE, eObject.eClass()); + assertEquals(BasicPackage.eINSTANCE.getNsURI(), ((EPackageImpl) eObject).getNsURI()); + assertNotEquals(basicPackage, eObject); + assertNotEquals(BasicPackage.eINSTANCE, eObject); + } // @Test // public void testEMFMongoRepositoryPrototypeInstance() throws BundleException, InvalidSyntaxException, IOException, InterruptedException { diff --git a/org.gecko.emf.repository.mongo.tests/test.bndrun b/org.gecko.emf.repository.mongo.tests/test.bndrun index fc44f3d..b764fba 100644 --- a/org.gecko.emf.repository.mongo.tests/test.bndrun +++ b/org.gecko.emf.repository.mongo.tests/test.bndrun @@ -21,10 +21,6 @@ org.osgi.util.function;version='[1.2.0,1.2.1)',\ org.osgi.util.promise;version='[1.3.0,1.3.1)',\ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ - org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ - org.eclipse.emf.common;version='[2.28.0,2.28.1)',\ - org.eclipse.emf.ecore;version='[2.33.0,2.33.1)',\ - org.eclipse.emf.ecore.xmi;version='[2.18.0,2.18.1)',\ org.gecko.emf.collections;version='[2.2.2,2.2.3)',\ org.gecko.emf.mongo.component;version=snapshot,\ org.gecko.emf.repository.api;version=snapshot,\ @@ -36,13 +32,15 @@ net.bytebuddy.byte-buddy;version='[1.14.9,1.14.10)',\ net.bytebuddy.byte-buddy-agent;version='[1.14.9,1.14.10)',\ org.gecko.emf.repository.mongo.tests;version=snapshot,\ - org.gecko.mongo.osgi.api;version=snapshot,\ org.mockito.junit-jupiter;version='[4.11.0,4.11.1)',\ org.mockito.mockito-core;version='[4.11.0,4.11.1)',\ org.objenesis;version='[3.3.0,3.3.1)',\ org.opentest4j;version='[1.3.0,1.3.1)',\ org.osgi.test.common;version='[1.2.1,1.2.2)',\ org.osgi.test.junit5;version='[1.2.1,1.2.2)',\ - org.gecko.emf.osgi.api;version='[6.0.2,6.0.3)',\ - org.gecko.emf.osgi.component;version='[6.0.2,6.0.3)',\ - org.gecko.emf.osgi.example.model.basic;version='[6.0.2,6.0.3)' \ No newline at end of file + org.eclipse.emf.common;version='[2.29.0,2.29.1)',\ + org.eclipse.emf.ecore;version='[2.35.0,2.35.1)',\ + org.eclipse.emf.ecore.xmi;version='[2.36.0,2.36.1)',\ + org.gecko.emf.osgi.component.minimal;version='[6.2.0,6.2.1)',\ + org.gecko.emf.osgi.example.model.basic;version='[6.2.0,6.2.1)',\ + org.osgi.service.metatype;version='[1.4.1,1.4.2)' \ No newline at end of file diff --git a/org.gecko.emf.repository.mongo/bnd.bnd b/org.gecko.emf.repository.mongo/bnd.bnd index 52cba32..ae224c5 100644 --- a/org.gecko.emf.repository.mongo/bnd.bnd +++ b/org.gecko.emf.repository.mongo/bnd.bnd @@ -18,7 +18,7 @@ Bundle-Name: EMF Repository Mongo Bundle-Description: EMF Mongo Repository Implementation -Bundle-Version: 3.2.0.${tstamp}-SNAPSHOT +Bundle-Version: 3.3.0.${tstamp}-SNAPSHOT Provide-Capability: emf.repository;emf.repository=mongo Require-Capability: org.gecko.osgi.emf.persistence;filter:='(org.gecko.osgi.emf.persistence=mongo)' Private-Package: \ diff --git a/org.gecko.emf.repository.mongo/src/org/gecko/emf/repository/mongo/impl/AbstractEMFMongoRepository.java b/org.gecko.emf.repository.mongo/src/org/gecko/emf/repository/mongo/impl/AbstractEMFMongoRepository.java index 0f6186d..ed4da50 100644 --- a/org.gecko.emf.repository.mongo/src/org/gecko/emf/repository/mongo/impl/AbstractEMFMongoRepository.java +++ b/org.gecko.emf.repository.mongo/src/org/gecko/emf/repository/mongo/impl/AbstractEMFMongoRepository.java @@ -19,15 +19,16 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; import org.bson.types.ObjectId; import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.util.EcoreUtil; import org.gecko.collection.EReferenceCollection; import org.gecko.emf.mongo.Options; import org.gecko.emf.osgi.ResourceSetFactory; @@ -127,7 +128,12 @@ public T getEObject(EClass eClass, Object id, Map opti return null; } String eclassAlias = getCollectionName(eClass, options); - return getEObject(eclassAlias, id, options); + URI uri = createEClassUri(eclassAlias, options).appendSegment(URI.encodeSegment(id.toString(), true)); + EAttribute idAttribute = Options.getIDAttribute(eClass, options); + if(idAttribute.isID()) { + uri = uri.appendFragment(URI.encodeFragment(id.toString(), true)); + } + return getEObject(uri, options); } /* @@ -159,7 +165,10 @@ public URI createUri(EObject object, Map options) { if (object == null) { return null; } - String id = EcoreUtil.getID(object); + + EAttribute idAttribute = Options.getIDAttribute(object.eClass(), options); + + String id = idAttribute != null ? Objects.toString(object.eGet(idAttribute)) : null; URI uri = createMongoURI(object.eClass(), options); Object useId = options.get(Options.OPTION_USE_ID_ATTRIBUTE_AS_PRIMARY_KEY); @@ -173,12 +182,12 @@ public URI createUri(EObject object, Map options) { * the _id will be generated from the MongoDB */ if (useId == null || Boolean.TRUE.equals(useId)) { - uri = uri.appendSegment(id); + uri = uri.appendSegment(URI.encodeSegment(id, true)); } else { uri = uri.appendSegment(""); } if (id != null) { - uri = uri.appendFragment(id); + uri = uri.appendFragment(URI.encodeFragment(id, true)); } return uri; } diff --git a/org.gecko.emf.repository.tests/test.bndrun b/org.gecko.emf.repository.tests/test.bndrun index d46cb18..d8a9265 100644 --- a/org.gecko.emf.repository.tests/test.bndrun +++ b/org.gecko.emf.repository.tests/test.bndrun @@ -17,15 +17,12 @@ org.osgi.util.function;version='[1.2.0,1.2.1)',\ org.osgi.util.promise;version='[1.3.0,1.3.1)',\ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ - org.eclipse.emf.common;version='[2.28.0,2.28.1)',\ - org.eclipse.emf.ecore;version='[2.33.0,2.33.1)',\ org.gecko.emf.repository.api;version=snapshot,\ junit-jupiter-api;version='[5.10.1,5.10.2)',\ junit-jupiter-params;version='[5.10.1,5.10.2)',\ junit-platform-commons;version='[1.10.1,1.10.2)',\ net.bytebuddy.byte-buddy;version='[1.14.9,1.14.10)',\ net.bytebuddy.byte-buddy-agent;version='[1.14.9,1.14.10)',\ - org.eclipse.emf.ecore.xmi;version='[2.18.0,2.18.1)',\ org.gecko.emf.repository.tests;version=snapshot,\ org.mockito.junit-jupiter;version='[4.11.0,4.11.1)',\ org.mockito.mockito-core;version='[4.11.0,4.11.1)',\ @@ -33,10 +30,10 @@ org.opentest4j;version='[1.3.0,1.3.1)',\ org.osgi.test.common;version='[1.2.1,1.2.2)',\ org.osgi.test.junit5;version='[1.2.1,1.2.2)',\ - org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ - org.osgi.service.log;version='[1.5.0,1.5.1)',\ org.osgi.util.converter;version='[1.0.9,1.0.10)',\ org.gecko.emf.repository.file;version=snapshot,\ - org.gecko.emf.osgi.api;version='[6.0.2,6.0.3)',\ - org.gecko.emf.osgi.component;version='[6.0.2,6.0.3)',\ - org.gecko.emf.osgi.example.model.basic;version='[6.0.2,6.0.3)' \ No newline at end of file + org.eclipse.emf.common;version='[2.29.0,2.29.1)',\ + org.eclipse.emf.ecore;version='[2.35.0,2.35.1)',\ + org.eclipse.emf.ecore.xmi;version='[2.36.0,2.36.1)',\ + org.gecko.emf.osgi.component.minimal;version='[6.2.0,6.2.1)',\ + org.gecko.emf.osgi.example.model.basic;version='[6.2.0,6.2.1)' \ No newline at end of file diff --git a/org.gecko.emf.repository/src/org/gecko/emf/repository/DefaultEMFRepository.java b/org.gecko.emf.repository/src/org/gecko/emf/repository/DefaultEMFRepository.java index e157b58..c13bb2c 100644 --- a/org.gecko.emf.repository/src/org/gecko/emf/repository/DefaultEMFRepository.java +++ b/org.gecko.emf.repository/src/org/gecko/emf/repository/DefaultEMFRepository.java @@ -677,7 +677,7 @@ public T getEObject(String eClassName, Object id, Map logger.log(Level.SEVERE, "Error getting EObject without class name or id parameters"); return null; } - URI uri = createEClassUri(eClassName, options).appendSegment(id.toString()).appendFragment(id.toString()); + URI uri = createEClassUri(eClassName, options).appendSegment(URI.encodeSegment(id.toString(), true)).appendFragment(URI.encodeFragment(id.toString(), true)); return getEObject(uri, options); } diff --git a/org.gecko.emf.repository/src/org/gecko/emf/repository/helper/RepositoryHelper.java b/org.gecko.emf.repository/src/org/gecko/emf/repository/helper/RepositoryHelper.java index 8061898..191834f 100644 --- a/org.gecko.emf.repository/src/org/gecko/emf/repository/helper/RepositoryHelper.java +++ b/org.gecko.emf.repository/src/org/gecko/emf/repository/helper/RepositoryHelper.java @@ -22,6 +22,7 @@ import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.emf.ecore.util.InternalEList; import org.gecko.emf.repository.exception.ConstraintValidationException; /** @@ -75,7 +76,7 @@ private static Diagnostic checkForAttachedNonContainmentRefs(EObject eObject) { private static Diagnostic checkForAttachedNonContainmentRefs(EObject eObject, EReference reference) { if(reference != null && !reference.isContainment()) { - if(eObject.eIsProxy() || (eObject.eResource() != null && eObject.eResource().getResourceSet() != null)){ + if(eObject.eIsProxy() || (eObject.eResource() != null && eObject.eResource().getResourceSet() != null )){ return OK_INSTANCE; } else { return new BasicDiagnostic(Diagnostic.ERROR, eObject.toString() + " for reference " + reference.getName(), 42, "The Object is no Proxy and is not attached to any Resource/ResourceSet", null); @@ -96,11 +97,20 @@ private static Diagnostic checkForAttachedNonContainmentRefs(EObject eObject, ER if(r.isContainment()) { eos.stream().map(eo -> checkForAttachedNonContainmentRefs(eo, r)).map(eo->(Diagnostic) eo).forEach(chain::add); } else { - BasicEList list = (BasicEList) eos; - for(int i = 0 ; i < list.size(); i++) { - EObject eo = list.basicGet(i); - chain.add(checkForAttachedNonContainmentRefs(eo, r)); + if(eos instanceof BasicEList) { + BasicEList list = (BasicEList) eos; + for(int i = 0 ; i < list.size(); i++) { + EObject eo = list.basicGet(i); + chain.add(checkForAttachedNonContainmentRefs(eo, r)); + } + } else if(eos instanceof InternalEList) { + InternalEList list = (InternalEList) eos; + for(int i = 0 ; i < list.size(); i++) { + EObject eo = list.basicGet(i); + chain.add(checkForAttachedNonContainmentRefs(eo, r)); + } } + } return chain; } else {