Posts mit dem Label xtext werden angezeigt. Alle Posts anzeigen
Posts mit dem Label xtext werden angezeigt. Alle Posts anzeigen

Sonntag, 20. November 2011

Xtext Serialization: Challenges serializing enums.

For the Xtext based modelling tool chain to model objective c (iPhone, iPad) applications for orderbird I needed to manipulate an Xtext model programmatically and serialize it back to disk.
I did encounter some challenges while serializing enums and want to share my experience in this post.

Here is a snippet of the grammar I am using for the well known use case of entity modelling:

EntityModel:
    (entities += Entity)*
;

Entity:
    (annotations+=Annotation)*
    'entity' name=ID '{' '}'
;

Annotation:
    '@' option=ConfigOption (':' value=ConfigValue)?
;   

enum ConfigOption:
    persistency
;   
   
enum ConfigValue:
    CoreData | FMDB
;

So, entities can be annotated to determine with which technology they will be stored persistently.

At first glance, serialization does not seem to be a hassle. Having an IResourceSetProvider, I can get the model from its XtextResource:

@Inject
private IResourceSetProvider provider;

private EntityModel loadEntityModelFromFile(IFile file) {
       
    ResourceSet xrs   = provider.get(file.getProject());
    URI uri           = URI.createPlatformResourceURI(file.getFullPath().toString(), true);
    Resource resource = xrs.getResource(uri, true);
    EntityModel em    = (EntityModel)resource.getContents().get(0);
   
    return em;
}

Now I can programmatically change the model and then serialize it back to disk by saving it in a XtextResource:

private void save(EntityModel em) {
   
    ResourceSet xrs  = provider.get(getProject());
    XtextResource xr =
        (XtextResource) xrs.getResource
                (URI.createPlatformResourceURI(getModelPath(), true) , true);
   
    xr.getContents().set(0, em);
               
    Map options = new HashMap();
    SaveOptions.defaultOptions().addTo(options);
    xr.save(options);
}

Serializing this model:

@persistency:CoreData
entity Foo {}

I get:

@persistencyentity Foo {}

The ConfigOption is missing! Hmmm, why? Xtext somehow assumes the ConfigOption to be transient (not serializable).

The Xtext documentation says "The default transient value service considers a model element to be transient if it is unset or equals its default value." and "By default, EMF returns false for eIsSet(..) if the value equals the default value."

Looking at the generated java code for the ecore meta model, the 'CoreData' literal is defined as the default:

/*
 * @generated
 */
public class AnnotationImpl extends EObjectImpl implements Annotation {
    //...   
   
    protected static final ConfigValue VALUE_EDEFAULT = ConfigValue.CORE_DATA;
    protected ConfigValue value                       = VALUE_EDEFAULT;
   
    //...
}

In order to tell Xtext which model elements can be considered as (non) transient, an instance of ITransientValueService has to be specified in your DSL's guice runtime module. This seems to be an easy task: Inherit from DefaultTransientValueService and overwrite isTransient(…) to yield the correct semantics:

public class DataDslTransientValueService extends DefaultTransientValueService {
   
    @Override
    public boolean isTransient(EObject owner, EStructuralFeature feature, int index) {
        if (owner instanceof Annotation && DataDslPackage.ANNOTATION__VALUE == feature.getFeatureID()) {
            return false;
        }
        return super.isTransient(owner, feature, index);
    }
}

… and hook it into the guice module:

public Class bindITransientValueService() {
    return DataDslTransientValueService.class;
}

Damn! Still the same errorneous output:

@persistencyentity Foo {}

A little bit of code archeology and debugging reveals that Xtext has two distinct hierarchies of the ITransientValueService interface.
One in the package org.eclipse.xtext.parsetree.reconstr and the other in the package org.eclipse.xtext.serializer.sequencer.

My DataDslTransientValueService implemented org.eclipse.xtext.parsetree.reconstr.ITransientValueService. But this does not seem to be sufficient. Thus, I also implemented org.eclipse.xtext.serializer.sequencer.ITransientValueService:

@SuppressWarnings("restriction")
public class SequencerTransientValueService extends TransientValueService {
   
    public ValueTransient isValueTransient(EObject semanticObject, EStructuralFeature feature) {
        if (semanticObject instanceof Annotation && DataDslPackage.ANNOTATION__VALUE == feature.getFeatureID()) {
            return ValueTransient.NO;
        }
       
        return super.isValueTransient(semanticObject, feature);
    }
}

My DSL's guice runtime module contains these two bindings for ITransientValueService:

public Class bindITransientValueService() {
    return DataDslTransientValueService.class;
}
   
public Class bindITransientValueService2() {
    return SequencerTransientValueService.class;
}

And finally the serialization yields the correct result!


As you might have noticed I annotated the SequencerTransientValueService with @SuppressWarnings("restriction"). The class org.eclipse.xtext.serializer.sequencer.TransientValueService seems not be intended for public use. But obviously it is required to get the serialization to work correctly.


At the time of writing this post, I also realized that my grammar's enum ConfigOption only has one literal that is defined as default and should thus not be serialized by default. But in my implementations of the two ITransientValueService interfaces I only specified ConfigValue to be non-transient. However, ConfigOption is serialized without adding the corresponding semantics to the implementations of the ITransientValueService. Maybe this is due to the Annotation's option attribute not being optional in the grammar as the value attribute is. And maybe I should study the Xtext documentation in more detail. Maybe ..

Regards,

steven

Dienstag, 18. Oktober 2011

Xtext Objective C Formatter/Beautifier

This post shows how I integrated uncrustify into Xtext. At the end of this post you will be able to package uncrustify with your language UI plugin and run uncrustify as part of a MWE2 workflow (the described approach was tested with Xtext 2.0 on Mac OS X 10.7).

First, you have to get uncrustify. Unpack it, run ./configure and then make. The binary is located in the src/ folder and is named uncrustify - what a surprise. Create a folder formatting/ in your language's UI plugin. Copy the binary into this folder. To tell uncrustify how to format the code we have to supply it with a config file. A config file for objective c can be found here. Download this file and put it into the formatting/ folder. Besides the binary and a config file we need a shell script that runs uncrustify. Create a file formatSource.sh in formatting/. The shell script looks like this:
#! /bin/sh

touch files.txt
find . -name "*.[hm]" > files.txt

while read line; do
./uncrustify_osx -l OC -c ./uncrustify_obj_c.cfg --no-backup $line
done < files.txt  
rm files.txt 
This script will look for *.h and *.m files recursively down from its location, run over them, and format them without creating a backup copy.

Now that we have the necessary files for running uncrustify ... oh well ... we must be able to run uncrustify from within java. For executing shell scripts from within a java process - welcome platform dependency - check out my ShellCommandExecutor. This class is also used for making the shell script formatSource.sh executable after copying it to a language project:
private void copyFormattingFiles(final IProject project){
 Bundle bundle = SystemDslActivator.getInstance().getBundle();
 IPath scriptPath = copyFile("formatting/formatSource.sh"     , "formatSource.sh",      project, bundle);
 IPath binaryPath = copyFile("formatting/uncrustify_osx",       "uncrustify_osx",       project, bundle);

 copyFile("formatting/uncrustify_obj_c.cfg", "uncrustify_obj_c.cfg", project, bundle);

 //make script and binary executable
 try {
  ShellCommandExecutor.execute("chmod", "+x", scriptPath.toString());
  ShellCommandExecutor.execute("chmod", "+x", binaryPath.toString());
 } catch (Exception e) {
  //TODO: write to error log
 }
}
The above method can be found in this class. The execution of formatSource.sh in a MWE2 workflow component looks like this:
public class ObjectiveCFormatter extends org.eclipse.emf.mwe.core.lib.AbstractWorkflowComponent2{

private static final String SCRIPT_PATH = "./formatSource.sh";

@Override
protected void invokeInternal(WorkflowContext ctx, ProgressMonitor monitor, Issues issues) {
try{
 CommandResult cr = ShellCommandExecutor.execute(SCRIPT_PATH, new String[]{});

 if (cr.success){
  System.out.println("Formatting complete!");
 } else{
  issues.addError(cr.output);
 }
}catch (Exception e){
 issues.addError(e.getMessage());
}
}
}
If you add this component after your objective c generator in your workflow all *.h and *.m files will be formatted as described by the uncrustify objective c config file.

regards,

steven

Donnerstag, 5. November 2009

Xtext, Supply Chains, Mobile Ad-hoc Networks, and IT-Entrepreneurship

My third semester at the HPI has started!
This is a list of themes that will catch my attention during this semester:



Protocol Compiler and Middleware

Together with Richard we will implement a middleware for The Wire Protocol in Java, and a protocol compiler. The protocol compiler will read a specification of a TWP protocol and generate code that implements the specified protocol on the basis of our middleware. The compiler will be built upon Xtext.


Tracking of pharmaceutical products in supply chains

This is my first research activity at the chair of Hasso Plattner, the founder of the HPI. I will investigate the efficient tracing of pharmaceuticals from production to the end-consumer. The goal of such a tracing is the verification of the authenticity of pharmaceuticals. So, if you are at the pharmacy, a pharmaceutical's way from the producer to your hands can be followed completely, and thus preventing you from taking pills produced in some of your neighbour's basement.
Actual tracing mechanisms are too slow and I hope to find a way to make them faster.
The exact title of my work is: "Algorithms and Data Structures for Data Capturing and Data Retrieval in the Context of EPC Discovery Services".


Mobile Ad-hoc networks for embedded systems with AUTOSAR

In the seminar Advanced Software Engineering for Embedded Systems I will develop an infrastructure for mobile ad-hoc networks for autonomous robots. The development will be based on AUTOSAR.


Linking in Xtext

The focus of my work for the seminar Software Design will be the linking-feature of Xtext. I will take a deep dive into the Xtext code to fully understand how the linker works. This should not be a big burden because I am already used to the (almost uncommented ;) )code written by Xtext developers since my google summer of code project in 2008. After arising from the depths of the Xtext code I will conduct some experiments and thrill the world with Xtext's capabilities :D.


IT-Entrepreneurship

Last but not least I will write a business plan with Daniel and Toni. The cool thing about this seminar is that we are taught by Rouven Westphal. Rouven is a ... at Hasso Plattner Ventures (HPV). HPV is a venture capital fund founded by - surpise :) - Hasso Plattner.
So, Rouven's every day business is judging business plans; opposed to last year's teacher Prof. Wagner who took a too heavy weight theoretical approach to entrepreneurship - Prof. Wagner basically had no entrpreneurial spirit.
Our first business idea is about increasing sales for food retailers. We think of a web platform that gives consumers access to retailers' shelfs in the digital world. Consumers create recipes that can be accessed by other consumers on their mobile devices in the store. The first effect is an increased shopping experience for customers: everything that is needed for a recipe is in one store - they do not have to go to a different store. And here comes the side door for retailers: if a retailer's stock is for instance full of salad that needs to be sold in one day and would be thrown away at the end of the day, the retailer places a special offer as a salad-recipe on the web-platform. This recipe will appear before any other recipe on customer's mobile devices when they enter the store. This has the effect that not only the salad is sold but also the other ingredients like cottage cheese, tomates, bread, and other stuff you need for a good salad.
But these days I am thinking more and more about the iPhone as a platform for (IT-)Entrepreneurs. So many fellows are talking about iPhone App development - I never heard so many it-people talking about ONE platform for a basis for (fast) revenue. It's like a gold rush! And if there is a gold rush, invest in gold picks and shovels! But more to that in a later post.