Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » URIImport of a non-xtext resource and referencing of its declared objects
URIImport of a non-xtext resource and referencing of its declared objects [message #1110772] Tue, 17 September 2013 06:07 Go to next message
Fabian Meyer is currently offline Fabian Meyer
Messages: 6
Registered: September 2013
Junior Member
Hi,

I'm trying to write a grammar to define rules over entities of an existing domain model. My grammar defines the structure of the entities and rules, so that the corresponding ECore model is generated. It also allows the definition of URIImports, where instances of the existing domain model can be imported, so that the therein defined entities can be used in the rules.

That's exactly where I'm stuck. There's already an API to read the domain model, hence my idea was to write a custom IResourceServiceProvider, which handles the imported files and creates instances of the generated ECore classes. I started writing a dummy resource service, which simply returns true for the file extension of the domain model and does not contain any further logic. I edited my workflow and removed the comments for

fragment = scoping.ImportURIScopingFragment auto-inject {}

			fragment = validation.ValidatorFragment auto-inject {
				composedCheck = "org.eclipse.xtext.validation.ImportUriValidator"
				composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator"
			}


It seems like my custom resource provider is not injected into the framework. I added a breakpoint in the "canHandle(URI uri)" method, but it's never hit and I get a "An internal error occurred during: "Xtext validation".
java.lang.IllegalStateException: No IResourceServiceProvider found in registry for uri ..." in my editor.

[Updated on: Thu, 19 September 2013 09:46]

Report message to a moderator

Re: URIImport of a non-xtext resource and referencing of it's declared objects [message #1110876 is a reply to message #1110772] Tue, 17 September 2013 08:50 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian Dietrich
Messages: 6126
Registered: July 2009
Senior Member
Hi,

yes if you want to reference something you need an iresourceserviceprovider for that.
have a look at http://christiandietrich.wordpress.com/2011/07/17/xtext-2-0-and-uml/
Re: URIImport of a non-xtext resource and referencing of it's declared objects [message #1110914 is a reply to message #1110876] Tue, 17 September 2013 09:52 Go to previous messageGo to next message
Fabian Meyer is currently offline Fabian Meyer
Messages: 6
Registered: September 2013
Junior Member
Hi,

thanks for the hint, but the problem is, that my domain model is proprietary and does not have a xtext grammar or an ECore model. The grammar of my rule language contains the structure of the entities defined in the domain model. Now I just want to read the information from the domain model (defined as an URIImport), and create ECore instances.

The problem is, that my IResourceServiceProvider is no associated with the file extension, as it seems. I don't know where to configure it. To bind the new provider, I simply added this to the RuntimeModule:

public Class<? extends IResourceServiceProvider> bindIResourceServiceProvider() {
		return test.CustomResourceServiceProvider.class;
	}
Re: URIImport of a non-xtext resource and referencing of it's declared objects [message #1110946 is a reply to message #1110914] Tue, 17 September 2013 10:39 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian Dietrich
Messages: 6126
Registered: July 2009
Senior Member
Hi,

so your stuff is not ecore based? how can you then reference it ???

this wont be reference / imports by means of Xtext / Import Uri mechanism.
Re: URIImport of a non-xtext resource and referencing of it's declared objects [message #1111523 is a reply to message #1110946] Wed, 18 September 2013 06:35 Go to previous messageGo to next message
Fabian Meyer is currently offline Fabian Meyer
Messages: 6
Registered: September 2013
Junior Member
My domain model is not ecore-based, but I want to wrap the defined entities into as objects of ECore classes of my DSL. Maybe it's easier to understand if I give you a short example:

You have, let's say, a set of Excel sheets. Every sheet contains a list of cars. Now you want to write a DSL, importing a subset of the sheets and referencing the cars.

CarLikeModel:
	(imports+=Import)*
	(elements+=CarLike)*
;

CarLike:
	'I like' car=[Car]
;

Car:
	name=ID
;

Import:
	'import' importURI=STRING;


The editor is generated and now you want to start using your existing sheets. You have e.g. two sheets in your workspace

"Mercedes.xslx"
---------------------
A-Class
C-Class


"BMW.xslx"
---------------------
1-Series
3-Series


and want to create a CarLikeLanguage instance, referencing some of the cars.

import "Mercedes.xslx"
import "BMW.xslx"

I like C-Class
I like 3-Series


To solve the references, I need to have some kind of adapter, which uses an existing library(e.g. Apache POI) to open the imported resources and creates Car objects for every defined car. I don't want to edit the imported files, I just want to use them as a kind of "car library".

I'm new to Xtext and EMF, but my understanding was, that I could simply implement an IResourceServiceProvider as part of my CarLikeLanguage project, register it for the "xslx" file extension and return instances of the generated Car interface for each car type is read from the sheet, when someone calls the e.g. "getExportedObjects" method. I implemented the provider and bound it to Djuce in my RuntimeModule. But I don't know how to register it for the file extension, so that the IResourceServiceProvider.Registry returny my ResourceServiceProviderr.
Re: URIImport of a non-xtext resource and referencing of it's declared objects [message #1111546 is a reply to message #1111523] Wed, 18 September 2013 07:13 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian Dietrich
Messages: 6126
Registered: July 2009
Senior Member
Hi if you want to do custom stuff you cannot reuse importuri which is
ecore based. Sure there is no possibility to emfify the existing
stuff?

--
Need training, onsite consulting or any other kind of help for Xtext?
Go visit http://xtext.itemis.com or send a mail to xtext at itemis dot de
Re: URIImport of a non-xtext resource and referencing of it's declared objects [message #1112361 is a reply to message #1111546] Thu, 19 September 2013 09:45 Go to previous messageGo to next message
Fabian Meyer is currently offline Fabian Meyer
Messages: 6
Registered: September 2013
Junior Member
Well, it finally works! It was kind of hard to achieve for someone without EMF and Xtext knowledge...

I will give you a short overview how my solution works (maybe someone else has the same use case):

I started from scratch and created a "CarModel" EMF-Project. Therein, I created a simple ECore model for the cars

<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0" xmlns:xmi="http_://www.omg.org/XMI" xmlns:xsi="http_://www.w3.org/2001/XMLSchema-instance"
    xmlns:ecore="http_://www.eclipse.org/emf/2002/Ecore" name="car" nsURI="http_://xtext.org/test/Car" nsPrefix="car">
  <eClassifiers xsi:type="ecore:EClass" name="Car">
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" lowerBound="1" eType="ecore:EDataType http_://www.eclipse.org/emf/2002/Ecore#//EString"
        iD="true"/>
  </eClassifiers>
</ecore:EPackage>


and a genmodel to generate my model code. Next, I created a "CarResourceFactory" Plugin-Project, which imports my model project and contains the resource loading mechanism for the proprietary ".cars" format.

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.Resource.Factory;

public class CarResourceFactory implements Factory {
	@Override
	public Resource createResource(final URI uri) {
		return new CarResource(uri);
	}
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
import org.xtext.test.car.Car;
import org.xtext.test.car.CarFactory;

public class CarResource extends ResourceImpl {

	public CarResource(URI uri) {
		super(uri);
	}

	@Override
	protected void doLoad(InputStream inputStream, Map<?, ?> options) throws IOException {

		InputStreamReader reader = new InputStreamReader(inputStream);
		BufferedReader buf = new BufferedReader(reader);

		String s = buf.readLine();
		String[] cars = s.split(",");

		for (String car : cars) {
			Car carObj = CarFactory.eINSTANCE.createCar();
			carObj.setName(car);

			getContents().add(carObj);
		}
	}
}


<plugin>
   <extension
         point="org.eclipse.emf.ecore.extension_parser">
      <parser
            class="org.xtext.test.car.resource.CarResourceFactory"
            type="cars">
      </parser>
   </extension>
</plugin>


Next, I created a "CarResourceServiceProvider" Plugin-Project, as a wrapper between my ECore objects and Xtext. Here's where I had most of my problems. It's not so easy to use the existing Xtext implementation for e.g. the Resource Description Manager, because it depends on the injections of Djuce. Hence, I had to do some trial and error to find a solution, without having to implement the whole description mechanism on my own:

import java.util.Collection;
import java.util.Collections;
import java.util.List;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.naming.IQualifiedNameProvider;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.parser.IEncodingProvider;
import org.eclipse.xtext.resource.IResourceDescription;
import org.eclipse.xtext.resource.IResourceDescription.Delta;
import org.eclipse.xtext.resource.IResourceDescription.Manager;
import org.eclipse.xtext.resource.IResourceDescriptions;
import org.eclipse.xtext.resource.IResourceServiceProvider;
import org.eclipse.xtext.resource.impl.DefaultResourceDescription;
import org.eclipse.xtext.resource.impl.DefaultResourceDescriptionDelta;
import org.eclipse.xtext.resource.impl.DefaultResourceDescriptionStrategy;
import org.eclipse.xtext.resource.impl.SimpleResourceDescriptionsBasedContainerManager;
import org.eclipse.xtext.util.CancelIndicator;
import org.eclipse.xtext.validation.CheckMode;
import org.eclipse.xtext.validation.IResourceValidator;
import org.eclipse.xtext.validation.Issue;
import org.xtext.test.car.Car;

public class CarResourceServiceProvider implements IResourceServiceProvider {

	final org.eclipse.xtext.resource.IContainer.Manager containerManager = new SimpleResourceDescriptionsBasedContainerManager();

	@Override
	public boolean canHandle(URI uri) {
		return uri.fileExtension().equals("cars");
	}

	@Override
	public <T> T get(Class<T> t) {
		try {
			return t.newInstance();
		} catch (Throwable e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public IResourceValidator getResourceValidator() {
		return new IResourceValidator() {
			@Override
			public List<Issue> validate(Resource resource, CheckMode mode, CancelIndicator indicator) {
				return Collections.emptyList();
			}
		};
	}

	@Override
	public org.eclipse.xtext.resource.IContainer.Manager getContainerManager() {
		return containerManager;
	}

	@Override
	public IEncodingProvider getEncodingProvider() {
		throw new UnsupportedOperationException();
	}

	@Override
	public Manager getResourceDescriptionManager() {
		return new Manager() {

			@Override
			public boolean isAffected(Collection<Delta> deltas, IResourceDescription candidate,
					IResourceDescriptions context) throws IllegalArgumentException {
				return false;
			}

			@Override
			public boolean isAffected(Delta delta, IResourceDescription candidate) throws IllegalArgumentException {
				return false;
			}

			@Override
			public Delta createDelta(IResourceDescription oldDescription, IResourceDescription newDescription) {
				return new DefaultResourceDescriptionDelta(oldDescription, newDescription);
			}

			@Override
			public IResourceDescription getResourceDescription(Resource resource) {
				DefaultResourceDescriptionStrategy strat = new DefaultResourceDescriptionStrategy();
				strat.setQualifiedNameProvider(new IQualifiedNameProvider.AbstractImpl() {

					@Override
					public QualifiedName getFullyQualifiedName(EObject obj) {
						return QualifiedName.create(((Car) obj).getName());
					}
				});

				return new DefaultResourceDescription(resource, strat);
			}
		};
	}
}


<plugin>
   <extension
         point="org.eclipse.xtext.extension_resourceServiceProvider">
      <resourceServiceProvider
            class="org.xtext.test.car.resource.CarResourceServiceProvider"
            uriExtension="cars">
      </resourceServiceProvider>
   </extension>
</plugin>


The next step was the actual Xtext project and the grammar. I created a new "CarLanguage" Xtext project, added the model project as dependency, added imports for the existing model to the mwe2 workflow

bean = StandaloneSetup {
	scanClassPath = true
	platformUri = "${runtimeProject}/.."
	registerGeneratedEPackage = "org.eclipse.xtext.xbase.XbasePackage"
	registerGeneratedEPackage = "org.xtext.test.car.CarPackage"
	registerGenModelFile = "platform:/resource/org.eclipse.xtext.xbase/model/Xbase.genmodel"
	registerGenModelFile = "platform:/resource/org.xtext.test.CarModel/Car.genmodel"
}


and defined my grammar

grammar org.xtext.test.CarLanguage with org.eclipse.xtext.common.Terminals

generate carLanguage "http_://www.xtext.org/test/CarLanguage"
import "http_://xtext.org/test/Car" as car

Model:
	imports+=Import+
	likes+=CarLike+;
	
Import:
	'import' importURI=STRING
;	

CarLike:
	'I like' ref = [car::Car];


I had to add the Xtext project nature to my model project, otherwise Xtext wasn't able to resolve the ECore model.

It finally worked and I was able to start my inner-Eclipse and create domain model files and a grammar instance:

BMW.cars
Series3,Series5


Mercedes.cars
CClass,EClass


Test.carlike
import "Mercedes.cars" 
import "BMW.cars"

I like CClass
I like EClass
I like Series3
I like Series5


There are still some minor problems, when Xtext is trying to create org.eclipse.xtext.ui.validation.IResourceUIValidatorExtension and org.eclipse.xtext.ui.editor.hover.IEObjectHoverProvider instances, using the get-method of my ResourceServiceProvider, but it works!

(had to add some "_" to the URLs, because the forum won't let me post it otherwise)
Re: URIImport of a non-xtext resource and referencing of it's declared objects [message #1112367 is a reply to message #1112361] Thu, 19 September 2013 09:53 Go to previous messageGo to next message
Fabian Meyer is currently offline Fabian Meyer
Messages: 6
Registered: September 2013
Junior Member
If anyone is interested in the source code, here are the exported eclipse projects.
Re: URIImport of a non-xtext resource and referencing of its declared objects [message #1114766 is a reply to message #1110772] Mon, 23 September 2013 03:10 Go to previous messageGo to next message
Fabian Meyer is currently offline Fabian Meyer
Messages: 6
Registered: September 2013
Junior Member
I still have one problem with the external models. My importURI doesn't work correctly, as it seems. My understanding was, that URIs, referenced by the importURI feature, are automatically added to the resource set of the project. At the moment, importing a URI doesn't have any effect. If the external model is part of my project, its declared objects are referable by my source file. If they are not part of my project and I add an import to my source file, they are not loaded.

I activate the ImportUriValidator and the ImportURIScopingFragment fragments in my workflow.
Re: URIImport of a non-xtext resource and referencing of its declared objects [message #1114772 is a reply to message #1114766] Mon, 23 September 2013 03:17 Go to previous message
Christian Dietrich is currently offline Christian Dietrich
Messages: 6126
Registered: July 2009
Senior Member
Hi yes, import uri is for visibility only. Thus the referenced file
should be at least in the workspace. (Or on class path if it is a
java project)

--
Need training, onsite consulting or any other kind of help for Xtext?
Go visit http://xtext.itemis.com or send a mail to xtext at itemis dot de
Previous Topic:Value Converters in Xtext
Next Topic:XPECT testing
Goto Forum:
  


Current Time: Wed Jul 23 14:24:44 EDT 2014

Powered by FUDForum. Page generated in 0.02234 seconds