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 |
Rolf Theunissen 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 |
Ed Merks 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 #1739425 is a reply to message #1739106] |
Mon, 01 August 2016 08:42 |
Rolf Theunissen 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 |
Ed Merks 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 |
Rolf Theunissen 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 |
Ed Merks 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/
|
|
|
Goto Forum:
Current Time: Thu Apr 25 22:30:38 GMT 2024
Powered by FUDForum. Page generated in 0.03914 seconds
|