Accessing Xtext's runtime EMF model - xtext

I created a DSL via Xtext and now I need to transform the models created in the editor into another model(s). I suppose the most straightforward way is to employ some kind of M2M transformation framework, but i need to access the model behind the textual file.
Question: how can I get a reference to the model?

The models created by Xtext have also a resource factory created for them. If you try to load the textual file as an EMF model, EMF will look for resource factories available for the extension of your textual file. From there, Xtext will transform the textual file in an EMF model and give EMF the model created. You can see this mechanism in action by right clicking on your textual file and selecting "open with" and "sample reflective ecore model editor". So something like this should work:
ResourceSet rs = new ResourceSetImpl();
Resource r = rs.getResource(uriOfYourTextualFile, true);
List<EObject> contentOfYourFile = r.getContents();

Related

Xtext: How to persist a DSL AST using XMI (or JSON)?

I'm currently trying to figure out how to "connect" an Xtext Language Server with an EMFCloud.ModelServer instance so each time a client (VS Code extension in my case) saves a custom DSL text file, the Language Server saves the AST as XMI (or JSON). So then later the model can be included in the Model Server workspace and other editors can react to changes on my model (XMI, JSON)
So far I've seen that the current Xtext LS version does nothing with the "textDocument/didSave" notifications:
#Override
public void didSave(DidSaveTextDocumentParams params) {
// nothing to do
}
I'd like to enhance my LS instance to provide logic to that method and persist the current AST to XMI/JSON.
So far I was able to see that there is a generator class which the doGenerate method is called when the save is triggered on client side. However, taking a look to the call hierarchy of that method, it seems that is called within a "code generation" process. The documentation found for this is always related to other language generation (i.e. Java or c++) and I'm not sure if this would be the right place also because it seems that the file URI is not accessible (as it is in the didSave method of the LS part)
As summary, is there a way to access the semantic model (AST) from the Language Server "didSave" operation?
Following the hints provided by Christian Dietrich, the Language Server uses a ProjectManager which is able to retrieve the XtextResource holding the semantic model for a specific model URI (i.e. the URI passed to the server from the editor). Basically:
XtextResource resource = (XtextResource) getWorkspaceManager().getProjectManager(uri).getResource(uri);
In order to get our model from the resource the following method is provided:
EList<EObject> modelObjects = resource.getContents();
At this point we can persist the semantic model via the EMF Model Server (i.e. by creating or modifying an existing model in the Model Server).

Creating a named model in Jena

Given that this introduction states that using named models is better practice than using the default model, I'm trying to add a named model to a dataset:
Dataset dataset = TDBFactory.createDataset("MyDataset");
System.out.println(dataset.containsNamedModel("MyNewModel"));
Model MyNewModel = ModelFactory.createDefaultModel();
dataset.begin(ReadWrite.WRITE);
dataset.addNamedModel("MyNewModel", MyNewModel);
dataset.commit();
System.out.println(dataset.containsNamedModel("MyNewModel"));
but this returns
false
false
(so it's obviously not adding the model!). I had a look through the docs, and there is a createMethod(String name) method. I've tried using this, but because it's in an Interface, java complains when I try an instantiate ModelMaker (Cannot instantiate the type ModelMaker) - and the docs don't show which classes implement which interface.
This leads to a couple of questions:
Is it actually best practice to use a named model in a dataset, rather than a default model?
How do I call the createModel method? In the more verbose documentation it says that ModelFactory contains a method createFileModelMaker(String) - but the java docs don't mention this method, and trying to call it predictably leads to The method createFileModelMaker(String) is undefined for the type ModelFactory!
MyNewModel is empty so there is nothing to add. addNamedModel means copy in the contents of one graph into a named on in the dataset.
In TDB, a named graph is held as quads (graph, subject, predicate, object). There is no separate graph management. If there is no quad for the named graph, then it is not in the dataset.

XPage Localization Process: How to translate properties files in bulk?

We have a huge project with more than 100 Custom Controls and XPages in place and now we intend to provide the project in multiple languages.
Localization in XPages, provides this beautiful and a very simple way to convert the entire project in the other language via the properties file. However, in our case, many custom controls are kind of carbon copies of others and many of the translations/keywords are the same, it becomes kind of redundant to change the same thing again and again.
So the question is, is there a simpler approach, where we can probably do a bulk of translation together? Something, where we can export the entire translation as one file and import it back?
Any suggestion/help in the right direction would really be appreciated.
Don't use XPage's build-in localization. It might work for a first translation but it's very difficult to maintain after (a lot of) changes in XPages.
Use a managed Java bean instead.
It manages own property files and implements Map interface.
You'd use the bean to get a string usually with EL.
Example:
Get name's label with str['name'] for following entry in property file
name=Name
Use java.text.MessageFormat for messages with data.
Create a method like getMessage(String name, Object arg1) in your bean.
Example:
Get the message for a missing view in JavaScript with
str.getMessage('message.view.not.found', viewName) for following entry in property file
message.view.not.found=Could not find view {0}
Another approach would be to use manually created property-files
Here an example for two languages:
First of all you have to create the following two files under Resources/Files
messages.properties
global.welcome = Willkommen {0} auf meiner Webseite
messages_en.properties
global.welcome = Welcome {0} on my website
Now you can reference your message properties on every place in your code
<xp:this.resources>
<xp:bundle src="/messages.properties" var="resMessage"></xp:bundle>
</xp:this.resources>
<xp:text escape="true" id="cfUser" themeId="Text.User">
<xp:this.value><![CDATA[${javascript:I18n.format(resMessage['global.welcome'], sessionScope.commonUserName)}]]></xp:this.value>
</xp:text>

Ant task for generating XSD from POJOs

Is there an ant task for generating an XSD from POJOs?
I'm presuming that you want to serialize a Java POJO object and then use XSD to validate the serialised XML data, or author new object instances which can instantiated via your de-serialization process.
Thing is Java XML serialization comes in two favours (Examples follow):
Xstream XML is dynamically generated from fixed object class description
XMLBeans Java classes dynamically generated from fixed XML Schema
Now perhaps you're using something else that combines both approaches?
What I'd recommend is create (or generate) an XSD based on the XML your object creates when serialized. Relatively speaking Java objects don't change that often and when they do a far great challenge is supporting multiple versions (Reading data encoded for the older version of your object). To address this challenge I'd recommend reading the following article for one possible solution:
http://java.dzone.com/articles/migrate-serialized-java

Generate columnheaders based on the DisplayName attribute?

When I generate a view from the List template I notice that the names of the columns are not based on the DisplayName() annotation. I know how to edit the list.tt code template but I have no idea how to retrieve the DisplayName attributes from the class properties.
The common way to get the DisplayName attribute is via reflection. The issue your going to have is .tt templates and reflection don't play nice together. Reflection relies on code being loaded into the AppDomain. Since .tt files don't actually load code you can't reflect over them.
More information about this issue, and a possible solution here:
http://www.olegsych.com/2007/12/how-to-use-t4-to-generate-decorator-classes/
MVC and Visual Studio must use some type of code inspection to generate some of the generated so I'd look along that path, maybe some crazy regex, if your not into solving the reflection issue.

Resources