Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » EMF » Adding attributes to model elements in XMI?
Adding attributes to model elements in XMI? [message #1138834] Tue, 15 October 2013 11:01 Go to next message
Alan DW is currently offline Alan DWFriend
Messages: 119
Registered: March 2012
Senior Member
Hello everyone,

I'm facing a situation where I need to store additional metadata for every EObject in my XMI. Since this has to work for arbitrary EObjects, I cannot simply use EAnnotations, since they require EModelElements, which I do not have.

Therefore, I thought that maybe it is possible to add another attribute to every element in the XMI in a similar way as the XMI-ID is stored in an extrinsic Map<EObject, String> within the resource. I basically just need another such Map<EObject, String> to store my own metadata for every element. The problem is: how do I correctly add it to the process such that its contents are written on save and restored on load?


I'd be grateful for any advice, it's the first time I'm really dealing with resources in such detail.

Thanks,


Alan

[Updated on: Tue, 15 October 2013 11:04]

Report message to a moderator

Re: Adding attributes to model elements in XMI? [message #1138919 is a reply to message #1138834] Tue, 15 October 2013 12:06 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 33140
Registered: July 2009
Senior Member
Alan,

That's a little bit like what
org.eclipse.emf.ecore.xmi.XMLResource.OPTION_RECORD_UNKNOWN_FEATURE
does. Stuff that can't be put into the model is record "on the sided"
and reinjected when the model is saved....


On 15/10/2013 1:01 PM, Alan DW wrote:
> Hello everyone,
>
> I'm facing a situation where I need to store additional metadata for
> every EObject in my XMI. Since this has to work for arbitrary
> EObjects, I cannot simply use EAnnotations, since they require
> EModelElements, which I do not have.
> Therefore, I thought that maybe it is possible to add another
> attribute to every element in the XMI in a similar way as the XMI-ID
> is stored externally in a Map<EObject, String> within the resource. I
> basically just need another such Map<EObject, String> to store my own
> metadata for every element. The problem is: how do I correctly add it
> to the process such that its contents are written on save and restored
> on load?
>
>
> I'd be grateful for any advice, it's the first time I'm really dealing
> with resources in such detail.
>
> Thanks,
>
>
> Alan
>


Ed Merks
Professional Support: https://www.macromodeling.com/
Re: Adding attributes to model elements in XMI? [message #1140400 is a reply to message #1138834] Wed, 16 October 2013 10:30 Go to previous messageGo to next message
Alan DW is currently offline Alan DWFriend
Messages: 119
Registered: March 2012
Senior Member
Hi Ed,

thanks for your quick response. This does indeed look like a solution to my problem. However, I'm having a hard time to find any documentation on how to actually use this on the internet. I've found this post of your's (the last one in the thread) which illustrates on how to load an unknown feature. Sadly, the link to the documentation PDF you posted there points into nothingness now because of the switch from SVN to GIT repositories... Also, I need to create AnyType instances programmatically as well. I have already created a custom subclass of XMIResource (I needed a custom subclass anyways) and I'd like to add a pair of methods like this:


/**
* Returns the value of the given unknown feature for the given object.
* @param obj The EObject to which the feature is attached
* @param featureName The name of the unknown feature to retrieve
* @return The value of the feature for the given EObject, or null if not set.
*/
public String getUnknownFeature(EObject obj, String featureName){
// I think what needs to be done here is a lookup for the AnyType instance
// in the EObjectExtensionMap and then use the right property of the AnyType
// instance to retrieve the desired String. However, the AnyType has the
// three (not very intention-revealing) properties "anyAttribute", "mixed"
// and "any". I must admit that I don't know what to make of those...

}

/**
* Sets the value of the given unknown feature for the given object.
* @param obj The object to attach the unknown feature value to
* @param featureName The name of the unknown feature to assign a value to
* @param value The string value to assign as the value of the unknown feature
*/
public void setUnknownFeature(EObject obj, String featureName, String value){
// Most likely this method would have to construct an AnyType instance
// and set the right properties. There are the two methods
// "recordUnknownFeature" and its helper "setAttribValue" in XMLHandler,
// but since this method resides in my XMIResource subclass, I don't have
// access to either of those.

}


... but I don't really see how to implement either of those. I've already checked my EMF Bible, but I couldn't spot any information about this topic at a first quick look through the persistence chapter.


I really have a dire need for this in my project and I'd be glad for any help.

Thanks,


Alan
Re: Adding attributes to model elements in XMI? [message #1140417 is a reply to message #1140400] Wed, 16 October 2013 10:42 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 33140
Registered: July 2009
Senior Member
Alan,

Comments below.

On 16/10/2013 12:30 PM, Alan DW wrote:
> Hi Ed,
>
> thanks for your quick response. This does indeed look like a solution
> to my problem. However, I'm having a hard time to find any
> documentation on how to actually use this on the internet.
Yes, you won't find much.
> I've found http://www.eclipsezone.com/eclipse/forums/t57094.html (the
> last one in the thread) which illustrates on how to load an unknown
> feature. Sadly, the link to the documentation PDF you posted there
> points into nothingness now because of the switch from SVN to GIT
> repositories...
:-(
> Also, I need to create AnyType instances programmatically as well.
Yes, and that's quite a complex beast. This article should help.

http://www.theserverside.com/news/1364302/Binding-XML-to-Java

> I have already created a custom subclass of XMIResource (I needed a
> custom subclass anyways) and I'd like to add a pair of methods like this:
>
>
> /**
> * Returns the value of the given unknown feature for the given object.
> * @param obj The EObject to which the feature is attached
> * @param featureName The name of the unknown feature to retrieve
> * @return The value of the feature for the given EObject, or null if
> not set.
> */
> public String getUnknownFeature(EObject obj, String featureName){
> // I think what needs to be done here is a lookup for the AnyType
> instance
> // in the EObjectExtensionMap and then use the right property of
> the AnyType
> // instance to retrieve the desired String. However, the AnyType
> has the
> // three (not very intention-revealing) properties "anyAttribute",
> "mixed"
> // and "any". I must admit that I don't know what to make of those...
> }
Whether the thing was an element verses and attribute in the XML will
determine which of these two is populated. You might want to look in
both of them. You can use the more detailed information from the
article I provided or do something like iterate over both feature maps
looking for a feature map entry with a feature with the matching name
(keeping in mind that the XML could have features with the matching name
as both elements and attributes from many different namespaces).
>
> /**
> * Sets the value of the given unknown feature for the given object.
> * @param obj The object to attach the unknown feature value to
> * @param featureName The name of the unknown feature to assign a
> value to
> * @param value The string value to assign as the value of the unknown
> feature
> */
> public void setUnknownFeature(EObject obj, String featureName, String
> value){
> // Most likely this method would have to construct an AnyType instance
> // and set the right properties. There are the two methods
> // "recordUnknownFeature" and its helper "setAttribValue" in
> XMLHandler,
> // but since this method resides in my XMIResource subclass, I
> don't have
> // access to either of those.
> }
>
You should first check if an AnyType exists in the map already and reuse
it, and if not, create one. Then you can use the information from the
article to demand create a feature that you use to populate an entry in
the feature map...
>
> .. but I don't really see how to implement either of those. I've
> already checked my EMF Bible, but I couldn't spot any information
> about this topic at a first quick look through the persistence chapter.
>
>
> I really have a dire need for this in my project and I'd be glad for
> any help.
No doubt you'll have more questions later when you have more real code
written.
>
> Thanks,
>
>
> Alan


Ed Merks
Professional Support: https://www.macromodeling.com/
Re: Adding attributes to model elements in XMI? [message #1140439 is a reply to message #1140417] Wed, 16 October 2013 11:01 Go to previous messageGo to next message
Alan DW is currently offline Alan DWFriend
Messages: 119
Registered: March 2012
Senior Member
Hello again,

thanks for your support - I'm reading the article now. I've been able to find the Feature Map Paper again and it already brought me a couple of steps further. I'm back to reading the article now.

Thanks a lot,


Alan
Re: Adding attributes to model elements in XMI? [message #1141042 is a reply to message #1140439] Wed, 16 October 2013 19:59 Go to previous messageGo to next message
Alan DW is currently offline Alan DWFriend
Messages: 119
Registered: March 2012
Senior Member
Hi,

I've read through your article now and also downloaded the provided source code. The article contained a lot of interesting insights for me and I *thought* that I had understood what I've read, so I tried to add a custom save method in my XMIResource subclass which looks like this:


	
public void save(final Map options) throws IOException {
                // this is the structure I'm trying to build (including multiplcities)
                // indentations indicate containment.
		// DocumentRoot [1]
		// - Container : AnyType [1]
		// -- Annotation : AnyType [0..*]
		// --- TargetID : String [1]
		// --- Entry : AnyType [0..*]
		// ---- Key : String [1]
		// ---- Value : String [1]
		options.put(XMLResource.OPTION_RECORD_UNKNOWN_FEATURE, Boolean.TRUE);
		ExtendedMetaData extendedMetaData = new BasicExtendedMetaData(this.getResourceSet().getPackageRegistry());
		options.put(XMLResource.OPTION_EXTENDED_META_DATA, extendedMetaData);
		// add the required properties
		EStructuralFeature rootFeature = extendedMetaData.demandFeature(null, "root", true);
		EClass rootClass = rootFeature.getEContainingClass();
		EObject documentRoot = EcoreUtil.create(rootClass);
		EMap xmlnsPrefixMap = (EMap) documentRoot.eGet(extendedMetaData.getXMLNSPrefixMapFeature(rootClass));
		xmlnsPrefixMap.put(this.NAMESPACE_PREFIX, this.NAMESPACE_URI);
		AnyType container = XMLTypeFactory.eINSTANCE.createAnyType();
		documentRoot.eSet(rootFeature, container);
		EStructuralFeature entryFeature = extendedMetaData.demandFeature(this.NAMESPACE_URI, "entry", true);
		EStructuralFeature targetIDFeature = extendedMetaData.demandFeature(this.NAMESPACE_URI, "targetID", false);
		EStructuralFeature propretyValueFeature = extendedMetaData.demandFeature(this.NAMESPACE_URI, "propertyValue",
				false);
		EStructuralFeature propertyNameFeature = extendedMetaData.demandFeature(this.NAMESPACE_URI, "propertyName",
				false);
		EStructuralFeature annotationsFeature = extendedMetaData.demandFeature(this.NAMESPACE_URI, "annotations", true);
		for (Entry<EObject, Map<String, String>> entry : this.unknownFeatureMap.entrySet()) {
			EObject eObject = entry.getKey();
			Set<Entry<String, String>> propertyValueSet = entry.getValue().entrySet();
			AnyType annotation = XMLTypeFactory.eINSTANCE.createAnyType();
			String eObjectID = this.getID(eObject);
			annotation.getMixed().add(targetIDFeature, eObjectID);
			for (Entry<String, String> propertyValuePair : propertyValueSet) {
				String propertyName = propertyValuePair.getKey();
				String propertyValue = propertyValuePair.getValue();
				AnyType mapEntry = XMLTypeFactory.eINSTANCE.createAnyType();
				mapEntry.getMixed().set(propertyNameFeature, propertyName);
				mapEntry.getMixed().set(propretyValueFeature, propertyValue);
				annotation.getMixed().add(entryFeature, mapEntry);
			}
			container.getMixed().add(annotationsFeature, annotation);
		}
		this.getContents().add(documentRoot);
		super.save(options);
	}



... where "this.unknownFeatureMap" is a custom map with two keys mapping to a value, in this case an EObject (the target) and a String (the property name) mapping to a single string (the property value).

However, when I run this, the XMI looks no different than before, in other words: my construction does not show up in any form in the XMI.

Am I missing something in particular? I somehow can't get rid of the feeling that I'm overkilling this and that there must be an easier way...


Best regards,


Alan


EDIT: Sorry, it was my fault. I've overwritten save(Map options), but called the save method which takes an output stream. My bad.


EDIT2: I'm running the correct code now, however, I get this error:

java.lang.RuntimeException: Invalid entry feature 'DocumentRoot.targetID'

... in this line:

annotation.getMixed().add(targetIDFeature, eObjectID);

Any idea why? The pattern is essentially the same as in the tutorial.

[Updated on: Wed, 16 October 2013 20:21]

Report message to a moderator

Re: Adding attributes to model elements in XMI? [message #1141658 is a reply to message #1141042] Thu, 17 October 2013 05:51 Go to previous message
Ed Merks is currently offline Ed MerksFriend
Messages: 33140
Registered: July 2009
Senior Member
Alan,

Comments below.

On 16/10/2013 9:59 PM, Alan DW wrote:
> Hi,
>
> I've read through your article now and also downloaded the provided
> source code. The article contained a lot of interesting insights for
> me and I *thought*
:-) This supposed for XML Schema features in Ecore is rather complex
because the whole concept is rather complex...
> that I had understood what I've read, so I tried to add a custom save
> method in my XMIResource subclass which looks like this:
>
>
>
> public void save(final Map options) throws IOException {
> // this is the structure I'm trying to build (including
> multiplcities)
> // indentations indicate containment.
> // DocumentRoot [1]
> // - Container : AnyType [1]
> // -- Annotation : AnyType [0..*]
> // --- TargetID : String [1]
> // --- Entry : AnyType [0..*]
> // ---- Key : String [1]
> // ---- Value : String [1]
> options.put(XMLResource.OPTION_RECORD_UNKNOWN_FEATURE,
> Boolean.TRUE);
> ExtendedMetaData extendedMetaData = new
> BasicExtendedMetaData(this.getResourceSet().getPackageRegistry());
> options.put(XMLResource.OPTION_EXTENDED_META_DATA,
> extendedMetaData);
> // add the required properties
> EStructuralFeature rootFeature =
> extendedMetaData.demandFeature(null, "root", true);
> EClass rootClass = rootFeature.getEContainingClass();
> EObject documentRoot = EcoreUtil.create(rootClass);
You're creating a document root...
> EMap xmlnsPrefixMap = (EMap)
> documentRoot.eGet(extendedMetaData.getXMLNSPrefixMapFeature(rootClass));
> xmlnsPrefixMap.put(this.NAMESPACE_PREFIX, this.NAMESPACE_URI);
And populating namespace prefixes specifically...
> AnyType container = XMLTypeFactory.eINSTANCE.createAnyType();
> documentRoot.eSet(rootFeature, container);
> EStructuralFeature entryFeature =
> extendedMetaData.demandFeature(this.NAMESPACE_URI, "entry", true);
> EStructuralFeature targetIDFeature =
> extendedMetaData.demandFeature(this.NAMESPACE_URI, "targetID", false);
> EStructuralFeature propretyValueFeature =
> extendedMetaData.demandFeature(this.NAMESPACE_URI, "propertyValue",
> false);
> EStructuralFeature propertyNameFeature =
> extendedMetaData.demandFeature(this.NAMESPACE_URI, "propertyName",
> false);
> EStructuralFeature annotationsFeature =
> extendedMetaData.demandFeature(this.NAMESPACE_URI, "annotations", true);
> for (Entry<EObject, Map<String, String>> entry :
> this.unknownFeatureMap.entrySet()) {
> EObject eObject = entry.getKey();
> Set<Entry<String, String>> propertyValueSet =
> entry.getValue().entrySet();
> AnyType annotation =
> XMLTypeFactory.eINSTANCE.createAnyType();
> String eObjectID = this.getID(eObject);
> annotation.getMixed().add(targetIDFeature, eObjectID);
> for (Entry<String, String> propertyValuePair :
> propertyValueSet) {
> String propertyName = propertyValuePair.getKey();
> String propertyValue = propertyValuePair.getValue();
> AnyType mapEntry =
> XMLTypeFactory.eINSTANCE.createAnyType();
> mapEntry.getMixed().set(propertyNameFeature,
> propertyName);
> mapEntry.getMixed().set(propretyValueFeature,
> propertyValue);
> annotation.getMixed().add(entryFeature, mapEntry);
> }
> container.getMixed().add(annotationsFeature, annotation);
> }
> this.getContents().add(documentRoot);
Hmmm. I don't see any uses of
org.eclipse.emf.ecore.xmi.XMLResource.getEObjectToExtensionMap() to
record information ...
> super.save(options);
> }
>
>
>
> .. where "this.unknownFeatureMap" is a custom map with two keys
> mapping to a value, in this case an EObject (the target) and a String
> (the property name) mapping to a single string (the property value).
I would expect that information to be recorded in
org.eclipse.emf.ecore.xmi.XMLResource.getEObjectToExtensionMap(), so
your convenience methods for getting and setting the annotations would
not have storage of their own but rather use this map, and use the ideas
above to manage the AnyType instance managed by that map.
>
> However, when I run this, the XMI looks no different than before, in
> other words: my construction does not show up in any form in the XMI.
Is it really an XMIResourceImpl? The multiple root objects should have
an impact for that. For XMLResourceImpl, only one root object is
supported. Of course this whole approach of add another root object
isn't what I had in mind, but if that's a possible alternative you could
most certainly model your annotations as some kind of map that you store
along side the annotated model...
>
> Am I missing something in particular? I somehow can't get rid of the
> feeling that I'm overkilling this and that there must be an easier way...
It looks like you understand how to use the AnyType, so if just manage
those instances in getEObjectToExtensionMap, the serializer should save
them and the deserializer should repopulate them...
>
>
> Best regards,
>
>
> Alan


Ed Merks
Professional Support: https://www.macromodeling.com/
Previous Topic:saveModel deletes the model
Next Topic:[CDO] Define fine grained object access with CDO security model ?
Goto Forum:
  


Current Time: Tue Apr 23 10:47:30 GMT 2024

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

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

Back to the top