Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » EMF » Unique ID's for each Type/Class, with references
Unique ID's for each Type/Class, with references [message #1739047] Wed, 27 July 2016 08:33 Go to next message
Rolf Theunissen is currently offline Rolf TheunissenFriend
Messages: 260
Registered: April 2012
Senior Member
Hi,

I am trying to make en Ecore-model generated from an xsd. This xsd contains ID-like attributes, and references from one element to another element which need to be resolved based on these ID's. So far, I am using 'ecore:id' and 'ecore:reference' attributes, this works as expected.

However, there are multiple types defined that have an ID, and the ID is unique for each type, not unique for all types. For instance, there can be a Node with id '1' and a Edge with an id '1'. This is not supported by EMF out of the box. Is there a way to allow unique ID's for each type, and resolve references based on these ID's?

Kind Regards,
Rolf

Re: Unique ID's for each Type/Class, with references [message #1739067 is a reply to message #1739047] Wed, 27 July 2016 10:15 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 33141
Registered: July 2009
Senior Member
Rolf,

No immediate obvious way to achieve that comes to mind. It if maps to
an EAttribute with iD true, the resource will validate as invalid when
there is more than one object with that ID, so even that's already a
problem.


On 27.07.2016 10:33, Rolf Theunissen wrote:
> Hi,
>
> I am trying to make en Ecore-model generated from an xsd. This xsd
> contains ID-like attributes, and references from one element to
> another element which need to be resolved based on these ID's. So far,
> I am using 'ecore:id' and 'ecore:reference' attributes, this works as
> expected.
>
> However, there are multiple types defined that have an ID, and the ID
> is unique for each type, not unique for all types. For instance, there
> can be a Node with id '1' and a Edge with an id '1'. This is not
> supported by EMF out of the box. Is there a way to allow unique ID's
> for each type, and resolve references based on these ID's?
>
> Kind Regards,
> Rolf
>


Ed Merks
Professional Support: https://www.macromodeling.com/
Re: Unique ID's for each Type/Class, with references [message #1739101 is a reply to message #1739067] Wed, 27 July 2016 14:14 Go to previous messageGo to next message
Rolf Theunissen is currently offline Rolf TheunissenFriend
Messages: 260
Registered: April 2012
Senior Member
I was trying to override all calls to 'EcoreUtil.getID(...)', within the generated Validator and Resource, to prefix the ID with the class name. But it seams like that at least 'setValueFromId' in 'XMLHandler' should be modified to fix the resolving of references during the load of the document.
Re: Unique ID's for each Type/Class, with references [message #1739106 is a reply to message #1739101] Wed, 27 July 2016 14:28 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 33141
Registered: July 2009
Senior Member
Rolf,

Yes, it has a broad impact to break the assumption that an ID is
unique. It's really not an ID, so best not to treat it like one. It
is probably best to specialize the serialization/desesrialization logic.


On 27.07.2016 16:14, Rolf Theunissen wrote:
> I was trying to override all calls to 'EcoreUtil.getID(...)', within
> the generated Validator and Resource, to prefix the ID with the class
> name. But it seams like that at least 'setValueFromId' in
> 'XMLHandler' should be modified to fix the resolving of references
> during the load of the document.


Ed Merks
Professional Support: https://www.macromodeling.com/
Re: Unique ID's for each Type/Class, with references [message #1739425 is a reply to message #1739106] Mon, 01 August 2016 08:42 Go to previous messageGo to next message
Rolf Theunissen is currently offline Rolf TheunissenFriend
Messages: 260
Registered: April 2012
Senior Member
I managed to get it working, by dropping the usage of ID's, and tweaking the serialization/deserialization of the XMLResourceImpl together with custom getEObjectByID logic, see below.

It seems a bit strange to me that the deserialization from a string reference to an custom 'URI-fragment' must be implemented in the XMLHandler, while the serialization from a reference to a string can be implemented in the XMLHelper. I would have expected an method in the XMLHelper which would be called for the conversion from string to URI-fragment/ID, or I misunderstood the API.

Kind regards,
Rolf

public class GexfResourceImpl extends XMLResourceImpl {
	protected Map<String, EObject> idToNodeContentMap = new HashMap<String, EObject>();;
	protected Map<String, EObject> idToEdgeContentMap = new HashMap<String, EObject>();;

	/**
	 * Creates an instance of the resource. 
	 * <!-- begin-user-doc --> 
	 * <!-- end-user-doc -->
	 * 
	 * @param uri
	 *            the URI of the new resource.
	 * @generated
	 */
	public GexfResourceImpl(URI uri) {
		super(uri);
	}

	@Override
	protected EObject getEObjectByID(String id) {
		if (id.charAt(0) == '[') {
			int index = id.indexOf('=');
			if (index > 0) {
				String type = id.substring(1, index);
				String tid = id.substring(index + 1, id.length() - 1);
				if (type.equals("node")) {
					EObject eObject = idToNodeContentMap.get(tid);
					if (eObject != null) {
						return eObject;
					}

					EObject result = null;
					for (TreeIterator<EObject> i = getAllProperContents(getContents()); i.hasNext();) {
						eObject = i.next();
						if (eObject instanceof NodeContent) {
							String nodeId = ((NodeContent) eObject).getId().toString();
							if (nodeId != null) {
								// TODO make robust for changed Id-values in NodeContent; Add notification listener?
								idToNodeContentMap.put(nodeId, eObject);
								if (result == null && nodeId.equals(tid)) {
									result = eObject;
								}
							}
						}
					}
					return result;
				} else if (type.equals("edge")) {
					EObject eObject = idToEdgeContentMap.get(tid);
					if (eObject != null) {
						return eObject;
					}

					EObject result = null;
					for (TreeIterator<EObject> i = getAllProperContents(getContents()); i.hasNext();) {
						eObject = i.next();
						if (eObject instanceof EdgeContent) {
							String edgeId = ((EdgeContent) eObject).getId().toString();
							if (edgeId != null) {
								// TODO make robust for changed Id-values in EdgeContent; Add notification listener?
								idToEdgeContentMap.put(edgeId, eObject);
								if (result == null && edgeId.equals(tid)) {
									result = eObject;
								}
							}
						}
					}
				}
			}
		}
		return super.getEObjectByID(id);
	}

	@Override
	protected XMLHelper createXMLHelper() {
		return new XMLHelperImpl(this) {
			@Override
			public String getHREF(EObject obj) {
				if (obj instanceof NodeContent) {
					return ((NodeContent) obj).getId().toString();
				} else if (obj instanceof EdgeContent) {
					return ((EdgeContent) obj).getId().toString();
				}
				return super.getHREF(obj);
			}
		};
	}

	@Override
	protected XMLLoad createXMLLoad() {
		return new XMLLoadImpl(createXMLHelper()) {
			@Override
			protected DefaultHandler makeDefaultHandler() {
				return new SAXXMLHandler(resource, helper, options) {
					@Override
					protected void setValueFromId(EObject object, EReference eReference, String ids) {
						if (eReference.getEReferenceType() == GexfPackage.Literals.NODE_CONTENT) {
							ids = "[node=" + ids + ']';
						} else if (eReference.getEReferenceType() == GexfPackage.Literals.EDGE_CONTENT) {
							ids = "[edge=" + ids + ']';
						}
						super.setValueFromId(object, eReference, ids);
					}
				};
			}
		};
	}

}
Re: Unique ID's for each Type/Class, with references [message #1739747 is a reply to message #1739425] Mon, 01 August 2016 09:24 Go to previous message
Ed Merks is currently offline Ed MerksFriend
Messages: 33141
Registered: July 2009
Senior Member
Rolf,

What can I say? That "API" has a 17 year history behind it and has
"evolved" so many times (with binary compatibility even for protected
methods and field being necessary) that it's just not pretty (and never
really was).

On 01.08.2016 10:42, Rolf Theunissen wrote:
> I managed to get it working, by dropping the usage of ID's, and
> tweaking the serialization/deserialization of the XMLResourceImpl
> together with custom getEObjectByID logic, see below.
>
> It seems a bit strange to me that the deserialization from a string
> reference to an custom 'URI-fragment' must be implemented in the
> XMLHandler, while the serialization from a reference to a string can
> be implemented in the XMLHelper. I would have expected an method in
> the XMLHelper which would be called for the conversion from string to
> URI-fragment/ID, or I misunderstood the API.
>
> Kind regards,
> Rolf
>
>
> public class GexfResourceImpl extends XMLResourceImpl {
> protected Map<String, EObject> idToNodeContentMap = new
> HashMap<String, EObject>();;
> protected Map<String, EObject> idToEdgeContentMap = new
> HashMap<String, EObject>();;
>
> /**
> * Creates an instance of the resource. * <!-- begin-user-doc
> --> * <!-- end-user-doc -->
> * * @param uri
> * the URI of the new resource.
> * @generated
> */
> public GexfResourceImpl(URI uri) {
> super(uri);
> }
>
> @Override
> protected EObject getEObjectByID(String id) {
> if (id.charAt(0) == '[') {
> int index = id.indexOf('=');
> if (index > 0) {
> String type = id.substring(1, index);
> String tid = id.substring(index + 1, id.length() - 1);
> if (type.equals("node")) {
> EObject eObject = idToNodeContentMap.get(tid);
> if (eObject != null) {
> return eObject;
> }
>
> EObject result = null;
> for (TreeIterator<EObject> i =
> getAllProperContents(getContents()); i.hasNext();) {
> eObject = i.next();
> if (eObject instanceof NodeContent) {
> String nodeId = ((NodeContent)
> eObject).getId().toString();
> if (nodeId != null) {
> // TODO make robust for changed
> Id-values in NodeContent; Add notification listener?
> idToNodeContentMap.put(nodeId, eObject);
> if (result == null &&
> nodeId.equals(tid)) {
> result = eObject;
> }
> }
> }
> }
> return result;
> } else if (type.equals("edge")) {
> EObject eObject = idToEdgeContentMap.get(tid);
> if (eObject != null) {
> return eObject;
> }
>
> EObject result = null;
> for (TreeIterator<EObject> i =
> getAllProperContents(getContents()); i.hasNext();) {
> eObject = i.next();
> if (eObject instanceof EdgeContent) {
> String edgeId = ((EdgeContent)
> eObject).getId().toString();
> if (edgeId != null) {
> // TODO make robust for changed
> Id-values in EdgeContent; Add notification listener?
> idToEdgeContentMap.put(edgeId, eObject);
> if (result == null &&
> edgeId.equals(tid)) {
> result = eObject;
> }
> }
> }
> }
> }
> }
> }
> return super.getEObjectByID(id);
> }
>
> @Override
> protected XMLHelper createXMLHelper() {
> return new XMLHelperImpl(this) {
> @Override
> public String getHREF(EObject obj) {
> if (obj instanceof NodeContent) {
> return ((NodeContent) obj).getId().toString();
> } else if (obj instanceof EdgeContent) {
> return ((EdgeContent) obj).getId().toString();
> }
> return super.getHREF(obj);
> }
> };
> }
>
> @Override
> protected XMLLoad createXMLLoad() {
> return new XMLLoadImpl(createXMLHelper()) {
> @Override
> protected DefaultHandler makeDefaultHandler() {
> return new SAXXMLHandler(resource, helper, options) {
> @Override
> protected void setValueFromId(EObject object,
> EReference eReference, String ids) {
> if (eReference.getEReferenceType() ==
> GexfPackage.Literals.NODE_CONTENT) {
> ids = "[node=" + ids + ']';
> } else if (eReference.getEReferenceType() ==
> GexfPackage.Literals.EDGE_CONTENT) {
> ids = "[edge=" + ids + ']';
> }
> super.setValueFromId(object, eReference, ids);
> }
> };
> }
> };
> }
>
> }
>


Ed Merks
Professional Support: https://www.macromodeling.com/
Re: Unique ID's for each Type/Class, with references [message #1741967 is a reply to message #1739106] Mon, 01 August 2016 08:42 Go to previous message
Rolf Theunissen is currently offline Rolf TheunissenFriend
Messages: 260
Registered: April 2012
Senior Member
I managed to get it working, by dropping the usage of ID's, and tweaking the serialization/deserialization of the XMLResourceImpl together with custom getEObjectByID logic, see below.

It seems a bit strange to me that the deserialization from a string reference to an custom 'URI-fragment' must be implemented in the XMLHandler, while the serialization from a reference to a string can be implemented in the XMLHelper. I would have expected an method in the XMLHelper which would be called for the conversion from string to URI-fragment/ID, or I misunderstood the API.

Kind regards,
Rolf


public class GexfResourceImpl extends XMLResourceImpl {
protected Map<String, EObject> idToNodeContentMap = new HashMap<String, EObject>();;
protected Map<String, EObject> idToEdgeContentMap = new HashMap<String, EObject>();;

/**
* Creates an instance of the resource.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
*
* @param uri
* the URI of the new resource.
* @generated
*/
public GexfResourceImpl(URI uri) {
super(uri);
}

@Override
protected EObject getEObjectByID(String id) {
if (id.charAt(0) == '[') {
int index = id.indexOf('=');
if (index > 0) {
String type = id.substring(1, index);
String tid = id.substring(index + 1, id.length() - 1);
if (type.equals("node")) {
EObject eObject = idToNodeContentMap.get(tid);
if (eObject != null) {
return eObject;
}

EObject result = null;
for (TreeIterator<EObject> i = getAllProperContents(getContents()); i.hasNext();) {
eObject = i.next();
if (eObject instanceof NodeContent) {
String nodeId = ((NodeContent) eObject).getId().toString();
if (nodeId != null) {
// TODO make robust for changed Id-values in NodeContent; Add notification listener?
idToNodeContentMap.put(nodeId, eObject);
if (result == null && nodeId.equals(tid)) {
result = eObject;
}
}
}
}
return result;
} else if (type.equals("edge")) {
EObject eObject = idToEdgeContentMap.get(tid);
if (eObject != null) {
return eObject;
}

EObject result = null;
for (TreeIterator<EObject> i = getAllProperContents(getContents()); i.hasNext();) {
eObject = i.next();
if (eObject instanceof EdgeContent) {
String edgeId = ((EdgeContent) eObject).getId().toString();
if (edgeId != null) {
// TODO make robust for changed Id-values in EdgeContent; Add notification listener?
idToEdgeContentMap.put(edgeId, eObject);
if (result == null && edgeId.equals(tid)) {
result = eObject;
}
}
}
}
}
}
}
return super.getEObjectByID(id);
}

@Override
protected XMLHelper createXMLHelper() {
return new XMLHelperImpl(this) {
@Override
public String getHREF(EObject obj) {
if (obj instanceof NodeContent) {
return ((NodeContent) obj).getId().toString();
} else if (obj instanceof EdgeContent) {
return ((EdgeContent) obj).getId().toString();
}
return super.getHREF(obj);
}
};
}

@Override
protected XMLLoad createXMLLoad() {
return new XMLLoadImpl(createXMLHelper()) {
@Override
protected DefaultHandler makeDefaultHandler() {
return new SAXXMLHandler(resource, helper, options) {
@Override
protected void setValueFromId(EObject object, EReference eReference, String ids) {
if (eReference.getEReferenceType() == GexfPackage.Literals.NODE_CONTENT) {
ids = "[node=" + ids + ']';
} else if (eReference.getEReferenceType() == GexfPackage.Literals.EDGE_CONTENT) {
ids = "[edge=" + ids + ']';
}
super.setValueFromId(object, eReference, ids);
}
};
}
};
}

}
Re: Unique ID's for each Type/Class, with references [message #1741969 is a reply to message #1741967] Mon, 01 August 2016 09:24 Go to previous message
Ed Merks is currently offline Ed MerksFriend
Messages: 33141
Registered: July 2009
Senior Member
Rolf,

What can I say? That "API" has a 17 year history behind it and has
"evolved" so many times (with binary compatibility even for protected
methods and field being necessary) that it's just not pretty (and never
really was).

On 01.08.2016 10:42, Rolf Theunissen wrote:
> I managed to get it working, by dropping the usage of ID's, and
> tweaking the serialization/deserialization of the XMLResourceImpl
> together with custom getEObjectByID logic, see below.
>
> It seems a bit strange to me that the deserialization from a string
> reference to an custom 'URI-fragment' must be implemented in the
> XMLHandler, while the serialization from a reference to a string can
> be implemented in the XMLHelper. I would have expected an method in
> the XMLHelper which would be called for the conversion from string to
> URI-fragment/ID, or I misunderstood the API.
>
> Kind regards,
> Rolf
>
>
> public class GexfResourceImpl extends XMLResourceImpl {
> protected Map<String, EObject> idToNodeContentMap = new
> HashMap<String, EObject>();;
> protected Map<String, EObject> idToEdgeContentMap = new
> HashMap<String, EObject>();;
>
> /**
> * Creates an instance of the resource. * <!-- begin-user-doc
> --> * <!-- end-user-doc -->
> * * @param uri
> * the URI of the new resource.
> * @generated
> */
> public GexfResourceImpl(URI uri) {
> super(uri);
> }
>
> @Override
> protected EObject getEObjectByID(String id) {
> if (id.charAt(0) == '[') {
> int index = id.indexOf('=');
> if (index > 0) {
> String type = id.substring(1, index);
> String tid = id.substring(index + 1, id.length() - 1);
> if (type.equals("node")) {
> EObject eObject = idToNodeContentMap.get(tid);
> if (eObject != null) {
> return eObject;
> }
>
> EObject result = null;
> for (TreeIterator<EObject> i =
> getAllProperContents(getContents()); i.hasNext();) {
> eObject = i.next();
> if (eObject instanceof NodeContent) {
> String nodeId = ((NodeContent)
> eObject).getId().toString();
> if (nodeId != null) {
> // TODO make robust for changed
> Id-values in NodeContent; Add notification listener?
> idToNodeContentMap.put(nodeId, eObject);
> if (result == null &&
> nodeId.equals(tid)) {
> result = eObject;
> }
> }
> }
> }
> return result;
> } else if (type.equals("edge")) {
> EObject eObject = idToEdgeContentMap.get(tid);
> if (eObject != null) {
> return eObject;
> }
>
> EObject result = null;
> for (TreeIterator<EObject> i =
> getAllProperContents(getContents()); i.hasNext();) {
> eObject = i.next();
> if (eObject instanceof EdgeContent) {
> String edgeId = ((EdgeContent)
> eObject).getId().toString();
> if (edgeId != null) {
> // TODO make robust for changed
> Id-values in EdgeContent; Add notification listener?
> idToEdgeContentMap.put(edgeId, eObject);
> if (result == null &&
> edgeId.equals(tid)) {
> result = eObject;
> }
> }
> }
> }
> }
> }
> }
> return super.getEObjectByID(id);
> }
>
> @Override
> protected XMLHelper createXMLHelper() {
> return new XMLHelperImpl(this) {
> @Override
> public String getHREF(EObject obj) {
> if (obj instanceof NodeContent) {
> return ((NodeContent) obj).getId().toString();
> } else if (obj instanceof EdgeContent) {
> return ((EdgeContent) obj).getId().toString();
> }
> return super.getHREF(obj);
> }
> };
> }
>
> @Override
> protected XMLLoad createXMLLoad() {
> return new XMLLoadImpl(createXMLHelper()) {
> @Override
> protected DefaultHandler makeDefaultHandler() {
> return new SAXXMLHandler(resource, helper, options) {
> @Override
> protected void setValueFromId(EObject object,
> EReference eReference, String ids) {
> if (eReference.getEReferenceType() ==
> GexfPackage.Literals.NODE_CONTENT) {
> ids = "[node=" + ids + ']';
> } else if (eReference.getEReferenceType() ==
> GexfPackage.Literals.EDGE_CONTENT) {
> ids = "[edge=" + ids + ']';
> }
> super.setValueFromId(object, eReference, ids);
> }
> };
> }
> };
> }
>
> }
>


Ed Merks
Professional Support: https://www.macromodeling.com/
Previous Topic:Re: difference between &quot;eContents&quot; and &quot;eAllContents&quot;
Next Topic:[XCORE] ecore file generated in impl package
Goto Forum:
  


Current Time: Thu Apr 25 22:30:38 GMT 2024

Powered by FUDForum. Page generated in 0.03914 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top