Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » EMF » How to access/set xsi:schemaLocation via API?
How to access/set xsi:schemaLocation via API? [message #1782855] Fri, 02 March 2018 14:20 Go to next message
Stefan John is currently offline Stefan JohnFriend
Messages: 17
Registered: March 2018
Junior Member
Hi,

as the topic states I try to find a way to set the xsi:schemaLocation of EMF models when serializing them to XMI. The application for this is, that I have to save models to a common location, thereby invalidating the original schemaLocation which contains the relative path to their .ecore file.

Currently, I use:
Map<Object,Object> options = new HashMap<Object,Object>();
options.put(XMIResource.OPTION_SCHEMA_LOCATION, Boolean.TRUE);
resource.save(options)


So, generating the schemaLocation attribute is not a problem. But I can't find a way to change its content.

As a side note:
I would dislike to use a file or platform URI to directly link to the .ecore file.

Best wishes,
Stefan
Re: How to access/set xsi:schemaLocation via API? [message #1782963 is a reply to message #1782855] Mon, 05 March 2018 16:56 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7655
Registered: July 2009
Senior Member
Hi

Generally EMF uses what it knows, so the schemaLocation is set by what is in memory. If you want something different you can try trick EMF by invoking Resource.setURI(...) judiciously, but I find that when you trick EMF, it often retaliates by biting a colleague very hard.

"platform:/..." sounds like a much better idea, but since you have a common area, "http:/..." nsURIs seems like an even better idea, possibly using the URI map.

You've told us very little about your application so I must guess.

I would recommend that your common area has its models published via plugin extension points so that everything is referenced by an nsURI. Modelling applications that just read the models should work fine. You just need to ensure that you have appropriate URI mappings in place in your model creation applications so that they work compatibly. Debug your readers first, then debug your writers. A successful Validate action within the Sample Ecore Model Editor is a very good arbiter as to whether you have a readable file or not.

Regards

Ed Willink
Re: How to access/set xsi:schemaLocation via API? [message #1783058 is a reply to message #1782963] Wed, 07 March 2018 10:08 Go to previous messageGo to next message
Stefan John is currently offline Stefan JohnFriend
Messages: 17
Registered: March 2018
Junior Member
Thank you for your advice so far, Ed!

Unfortunately, I did not work a lot with extensions in Eclipse, yet. So, I am not aware of how these might be used to dynamically register a meta model in the registry of a running Eclipse (which I believe would be a requisite for making use of the "http:/.." nsURIs in our use case).

I should give a bit more information about the application (MDEOptimiser, maybe you've heard of it).
Given an Eclipse project with a meta model (as .ecore), an instance (with an "http:/.." nsURI and a relative schemaLocation pointing to the .ecore) and some configuration files, the application performs a search based optimisation of the instance model. The app can be run in batch mode, i.e., multiple optimisations runs can be performed one application run.

The optimisation results (optimised instance models) are written to a separate experiments folder in the original Eclipse project, with a separate sub-folder for each run. Afterwards, the folder structure in the project will look like this:
project
 --- input
      --- metaModel.ecore
      --- instanceModel.xmi    
 --- results
      --- run1
           --- optimisedModel.xmi
      ---run2
           --- optimisedModel.xmi

The user should now be able to open the optimised models with the Sample Reflective Ecore Editor. Obviously, the schemaLocation of the results does not point to the meta model anymore. The "http:/.." nsURI doesn't help me either because the meta model is not loaded in the registry after the app finished.

The easiest way to allow opening of the optimised models would have been to adapt their relative schemaLocation.

If the extension solution you had in mind still fits this scenario, could you probably elaborate on this a bit more or give me a hint on how this might work?

Best wishes,
Stefan

Re: How to access/set xsi:schemaLocation via API? [message #1783074 is a reply to message #1783058] Wed, 07 March 2018 10:50 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7655
Registered: July 2009
Senior Member
Hi

"Obviously, the schemaLocation of the results does not point to the meta model anymore" is not obvious to me at all. I see no reason why the simple EMF usage of create files and save them, then load them fails. You have not moved files so there is no need to lie about their location.

I don't see your (independent) common location that prompted me to suggest using nsURIs. All your files are located below project so simple relative names should work fine.

It looks as if your attempt to specify a schemaLocation is the wrong fix for the wrong problem and so makes it harder to see what your real problem is.

My best guess is that you are mixing access mechanisms so that relative navigation fails. Use just one mechanism so that everything is relative to an absolute location where you started. i.e. do not open metamodel.ecore by nsURI.

Regards

Ed Willink
Re: How to access/set xsi:schemaLocation via API? [message #1783134 is a reply to message #1783074] Thu, 08 March 2018 12:14 Go to previous messageGo to next message
Stefan John is currently offline Stefan JohnFriend
Messages: 17
Registered: March 2018
Junior Member
Hi Ed,

sorry for the confusion. Upon your reply, I spent quite some time fiddling around with different ways of creating, loading, changing and saving resources and realized that I still have missed to give you necessary information.

The result models are not created from scratch by the application. If that would be the case, I could register the ecore file with the correct relative path (see code below).

In our application, the result models are generated by inplace model transformations applied to the input model. For that reason, the result models contain the same relative schemaLocation path as the input model.

In my example above, the input model would have a schemaLocation with the relative path metaModel.ecore (the meta model is in the same directory). The resulting optimised models will carry the same schemaLocation. However, in order to load them properly, the relative path should be ../../input/metaModel.ecore.

If you still see some misconceptions on my side regarding the use of EMF, feel free to shove me to the right direction.

Best wishes,
Stefan

EDIT:
The code below shows a bad way to solve the problem. Refer to attached file of my next post for a better solution and an example of the problem.

Minimal working example for creating a result model with correct relative schemaLocation:
public class Example {
	
	public static void main(String[] args) {
		ResourceSet rs = new ResourceSetImpl();
		Map<String, Object> map = rs.getResourceFactoryRegistry().getExtensionToFactoryMap();
		map.put("ecore", new EcoreResourceFactoryImpl());
		map.put("xmi", new XMIResourceFactoryImpl());
		
		String basePath = new File("results/run1").getAbsolutePath() + File.separatorChar;
		URI baseUri = URI.createFileURI(basePath);	
		rs.setURIConverter(new ExtensibleURIConverterImpl() {
			@Override
			public URI normalize(URI uri) {
				if (uri.isFile() && uri.isRelative() && baseUri!=null) {
					return uri.resolve(baseUri);
				} else {
					return super.normalize(uri);
				}
			}	
		});		
		
		URI ecoreUri = URI.createFileURI("../../input/metaModel.ecore");
		Resource r = rs.getResource(ecoreUri, true);
		EPackage metamodel = (EPackage)r.getContents().get(0);
		rs.getPackageRegistry().put(metamodel.getNsURI(), metamodel);		
		
		EClassifier classmodel = metamodel.getEClassifier("ClassModel");
		EObject modelroot = metamodel.getEFactoryInstance().create((EClass)classmodel);
		
		URI outputPath = URI.createFileURI("offspring.xmi");
		Resource resource = rs.createResource(outputPath);
		resource.getContents().clear();
		resource.getContents().add(modelroot);
		Map<Object,Object> options = new HashMap<Object,Object>();		
		options.put(XMIResource.OPTION_SCHEMA_LOCATION, Boolean.TRUE);
		
		try {
			resource.save(options);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
}

[Updated on: Fri, 09 March 2018 15:01]

Report message to a moderator

Re: How to access/set xsi:schemaLocation via API? [message #1783139 is a reply to message #1783134] Thu, 08 March 2018 12:34 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7655
Registered: July 2009
Senior Member
Hi

Sorry. A minimal working example has imports included and all referenced files and preferably a JUnit test case (that fails). This is most conveniently packaged as a zipped project folder. Attempting to recreate all the information you do not provide is often counterproductive.

I note that "../../input/metaModel.ecore" traverses outside the "project" that your second message suggested contained everything, so you may be back on the complicated case that I first provided suggestions before.

If you provide something that is unambiguously what is causing you trouble you may get a more helpful answer,.

Regards

Ed Willink

Regards

Ed Willink

Re: How to access/set xsi:schemaLocation via API? [message #1783146 is a reply to message #1783139] Thu, 08 March 2018 13:52 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 33137
Registered: July 2009
Senior Member
Certainly looking at the code, I can see you're doing bad things. You should not need to specialize the URI converter. You should not ever create a resource using a relative URI, so don't ever do URI.createFileURI("../../input/metaModel.ecore") but rather use URI.createFileURI(new File("URI.createFileURI("../../input/metaModel.ecore").getAbsolutePath()). Generally if all resources are loaded with absolute URIs then the serializer will save references between them that are relative whenever possible/sensible and the deserializer will resolve each relative URI against the absolute URI of the containing resource. All will work nicely and properly, exactly the same way that hrefs in HTML work. If you have resource's with relative URIs, then cross references can't be make relative and relative references can't be resolved properly, which will then make you feel compelled to hack the URI converter. Don't do that.

Ed Merks
Professional Support: https://www.macromodeling.com/
Re: How to access/set xsi:schemaLocation via API? [message #1783150 is a reply to message #1783146] Thu, 08 March 2018 14:19 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 33137
Registered: July 2009
Senior Member
Note that is there is some need/reason to change how URIs are deresolved/resolved by the serializer/deserializer that's the job of a org.eclipse.emf.ecore.xmi.XMLResource.URIHandler as specified by the org.eclipse.emf.ecore.xmi.XMLResource.OPTION_URI_HANDLER. For example in org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl.createResource(URI) you'll see result.getDefaultSaveOptions().put(XMLResource.OPTION_URI_HANDLER, new URIHandlerImpl.PlatformSchemeAware()) to ensure that a relative path is not created between platform:/resource URIs and platform:/plugin URIs; it would have been better if the platform team had specified "resource" and "plugin" not as the first segment but as the URI's authority instead, i.e., as platform://resource and platform://plugin.

Ed Merks
Professional Support: https://www.macromodeling.com/
Re: How to access/set xsi:schemaLocation via API? [message #1783246 is a reply to message #1783146] Fri, 09 March 2018 14:54 Go to previous message
Stefan John is currently offline Stefan JohnFriend
Messages: 17
Registered: March 2018
Junior Member
Your comments made me dig deeper into the internals and code of EMF than I had planned before. This took me quite a while but I am sure the return of investment will be worth it.

Using absolute paths, for all resources really solved my problem. I wasn't aware of the fact, that EMF is able to resolve the correct relative schemaLocations in that case.

I also agree that a working example in this context should be provided as an archive. The file appended to this post contains an Eclipse project with executable classes for the discussed problem as well as two solutions to it. I deleted the file added to the last post to avoid confusion.

In my defense, I need to admit that up until now I mainly used Henshin which wraps a lot of the EMF way of creating resources. Actually, the code above is kind of a one-to-one copy of what is done in Henshin (which is a rather mature tool), so I didn't challenge it too much. I will, however, raise a follow up question on the Henshin mailing list to see whether or not action has to be taken.

To my knowledge, using the custom URIConverter shown in my last post all relative URIs will be resolved to absolute URIs before a resource is serialized/deserialized. What I did not know is that the XMLHelper (which resolves the schemaLocation) never seems to get in touch with the URIConverter.

Thanks to both of you! I highly appreciate your commitment to the forum. Nice to have such prominent people in a domain help others out.

Best wishes,
Stefan
Previous Topic:Copy some containments from the referenced object to the referring object
Next Topic:[jet] Controlling the template path
Goto Forum:
  


Current Time: Fri Apr 19 08:17:33 GMT 2024

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

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

Back to the top