Thursday, December 23, 2010

Fixing EMF/Ecore/XMI Resource loading error: Package with URI ... not found

Most of the users of EMF (developers or adopters alike) have seen this message at least once; and most probably wondered what was going on :).

This error message indicates that the package which NsURI is '*' hasn't been registered in the Package registry. Most of the time, that means you either a) launched your program standalone and didn't register the package correctly or b) you haven't installed the plug-in that provides that metamodel.

With Acceleo, encountering this exception is even more likely than normal, as the launch configuration for our generations allow for both standalone or plug-in generations. Selecting standalone without registering the needed package will inevitably lead to this error.

Solving it is easy : it is a matter of registering the needed packages (and, optionally, resource factories). How is it done? Here is the most classic example with UML :

Package with uri 'http://www.eclipse.org/uml2/2.1.0/UML' not found.
What do I need to do for my UML model to be loadable :
EPackage.Registry.INSTANCE.put(UMLPackage.eNS_URI, UMLPackage.eINSTANCE);
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(UMLResource.FILE_EXTENSION, UMLResource.Factory.INSTANCE);

The same goes for every metamodel you might need, simply change UMLPackage by XxxPackage according to your metamodel. The Resource Factory is mandatory for UML, but your metamodel might not need one (in that case you can ignore this line if you don't have a custom factory.) For loading an XMI model, use:

Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("xmi", new XMIResourceFactoryImpl()");

For loading from a ResourceSet, use code similar to the following:

ResourceSet rset = new ResourceSetImpl();
rset.getPackageRegistry().put(DealerPackage.eNS_URI, DealerPackage.eINSTANCE);
rset.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xmi", new XMIResourceFactoryImpl());
Resource resource = rset.createResource(URI.createFileURI("/path/to/model/YahooDealer.xmi"));
resource.load(null);
dealer = (YahooDealerImpl)resource.getContents().get(0);
...

The different is the calls to the global Package Registry and Resource Factory Registry are replaced with the local registries provided by the ResourceSet.

You need these two lines to be before the point where your model is loaded. For Acceleo, this is done in the generated Java launcher : simply change the implementation of the registerPackages and registerResourceFactories method to add these needed lines.

The above post is copied mostly verbatim from  http://eclipsemde.blogspot.com/2010/06/package-with-uri-not-found.html

UPDATE: It wouldn't be cool if I haven't added something else, so here goes...

In an Eclipse application (non-standalone Java), EMF registers packages using extension point named org.eclipse.emf.ecore.generated_package (I've searched but unfortunately, the extension point reference documentation for this seems unavailable from the web!) that your plugin declares.

A sample plugin.xml that declares two EMF model packages:

   <extension point="org.eclipse.emf.ecore.generated_package">
      <package
            class="com.abispulsa.AbispulsaPackage"
            genModel="model/abispulsa.genmodel"
            uri="http://www.abispulsa.com/model/1.0"/>
      <package
            class="com.abispulsa.dealer.DealerPackage"
            genModel="model/AbispulsaDealer.genmodel"
            uri="http://www.abispulsa.com/dealer/1.0">
      </package>
   </extension>

This would be useful for readers unfamiliar with EMF to know where the package registration is done.

Especially if you change your metamodel's nsURI, you have to the change the registration here too. (and also the edit and editors if you have generated them... check out the plugin.xml files on the respective plugins.)

4 comments:

  1. I am impressed by how many posts you can turn over each day, you are making the rest of us look bad. :) But please make it explicit when you are copying someone else's post. The reference at the end is too subtle: it suggests your post is based on information from that post, not a verbatim copy of that post, which it actually is.

    ReplyDelete
  2. @Rafael thank you for the motivating words.

    I'm still learning and I'm blogging mainly just to keep internal notes to myself, but I guess what I have discovered might be useful for others too.

    That's why in most posts I try to put code examples directly from my running code, so that readers can see how Eclipse/EMF code look concretely. Maybe it's just me, but I spend more time understanding code examples that use A, B, foo, bar, or other placeholder names than the ones that use concrete names (even if the examples aren't complete, i.e. just snippets).

    I also try to include import statements as I usually waste time searching for the proper package/bundle. (when already depend on the right bundle, getting the package is easy. but without the right bundle, still need to find the package/class. The Plug-ins view help with this, but not many people know it, I didn't know before... perhaps I should short-blog about it ;-)

    Anyway, I've updated the article to reflect that fact. Actually I added some stuff regarding ResourceSet, but doesn't feel like blockquote-ing 90% of the article.

    I've also added some stuff regarding EMF extension point.

    ReplyDelete
  3. i have a question about load xmi to parse. I only get null when I use this: Model model = (Model) EcoreUtil.getObjectByType(inputResource.getContents(), UMLPackage.eINSTANCE.getModel() ); inputResource is like resource here. I see Could you help me with that. Thank you very much.

    ReplyDelete
  4. AWESOME work. And amazing assortment of tools to work... Really great!!
    RS Gold


    Buy diablo 3 gold

    ReplyDelete