Xtext Editors within Sirius Diagrams – the Best of both Worlds!

tl;dr: Altran’s Xtext / Sirius Integration provides the full Xtext experience for Sirius direct editors (a.k.a. pressing F2 in diagram) and properties editors. It’s highly configurable, well-documented, and released under EPL 2. I presented it at EclipseCon 2018. We intend to contribute this to the Sirius project.

Example of Xtext’s error checking and auto-completion support within Sirius diagram figure

Continue reading

First Eclipse DemoCamp in Eindhoven: A Great Start and Even Greater Community

Yesterday, we held the first Eclipse DemoCamp ever in Eindhoven, at the Altran office. About 40 people from a dozen different companies joined in and enjoyed the nice dinner buffet.

Marc Vloemans of Eclipse Foundation kicked off the DemoCamp with a short introduction: DemoCamps are about showing the great work members of the Eclipse community contribute – committers and users alike. Marc emphasized the possibilities of sharing the work between different groups and projects, vastly simplified by the Open Source concept.

Next up was Karsten Thoms of itemis. He swept the audience with an awesome intro – go see it if you have the chance, for example at the DemoCamp Bonn next week or (most probably) EclipseCon Europe in October! Without spoiling the fun, let’s say it gave A New Hope …

Karsten reported on the many changes he and more than 100 other community members contributed to the Eclipse Platform for the Photon Release Train. He showed lots of examples of the general speed improvements of Eclipse Photon. Also, the Run Configuration’s “Add all required Plug-ins” button finally fulfills its promise!

Marc Hamilton explained Altran’s approach for real-world complex modeling environments based on half a dozen Eclipse technologies. At the end, there is always some software produced. Using a modeling approach, most of the actual software production is pushed to generators, while the engineers focus on describing the issue at hand in domain-specific languages.

Marc showed how EMF, OCL, QVTo, Acceleo, EGF, Xtext, and Sirius are used, and listed the advantages, drawbacks and a wishlist for each technology.

During the break, we had the opportunity to pick up stickers provided by Karsten and discuss with other members of the community.

After the break, we enjoyed the talk of Mélanie Bats, arriving directly from Obeo in Toulouse. She showed new features of Sirius 6, most prominently the ELK layout integration and the magic connector tool to auto-select applicable connections.

Furthermore, she gave an outlook on the future of Sirius both within Eclipse and in the Web. She envisioned a Graphical Server Protocol akin to the Language Server Protocol to federate diagramming providers from the clients.

Last but not least, Holger Schill of itemis presented the new features of Xtext 2.14. He reported on the huge effort required to get Xtext fully compatible with Java 9, 10, and Junit 5 in all supported environments – and there are plenty! Other notable enhancements include code mining support (showing additional information within the editor without changing the file) and support for new Project / File wizards. The latter ones do not only create plain wizards, but provide a rich API to create customized wizards without the usual hassle of creating SWT dialogs.

We presented a small gift to all the speakers, who spread the word in the community on their own expenses — Huge thanks to Marc, Karsten, Marc, Mélanie, and Holger!

Lots of community members stayed to discuss the presentations and talk to the creators of the technology we use every day.

We enjoyed the DemoCamp a lot. We’re looking forward to have even more talks, topics, and attendees next time!

Eclipse DemoCamp Photon in Eindhoven on July 4: Platform, Sirius, Xtext, and more!

tl;dr: Altran organizes the first Eclipse DemoCamp in Eindhoven to celebrate the Photon Release Train on July 4, 17:00 hrs. Register today! We have Mélanie Bats of Obeo talking about Sirus 6, our own Marc Hamilton summarizing lessons learned from 10 years worth of MDE projects, and itemis’ Karsten Thoms and Holger Schill reporting about the latest features of Eclipse Platform 4.8 and Xtext 2.14, respectively.

After hosting the Sirius Day in April, we’re already looking at the next Eclipse event at Altran Netherlands: We’ll host the first Eclipse DemoCamp in Eindhoven to celebrate the Photon Release Train on July 4, 17:00 hrs.

We’ll start off at 17:00 hrs with a small dinner, so we all can enjoy the talks without starving. Afterwards, we have a very exiting list of speakers:

  • Mélanie Bats, CTO of Obeo, will tell us about What’s new in Sirius 6.

    Major Changes in Sirius 6:

    • Sirius now supports an optional integration with ELK for improved diagram layouts: specifiers can configure which ELK algorithm and parameters should be used for each of their diagrams, directly inside the VSM (ticket #509070). This is still considered experimental in 6.0.

    • A new generic edge creation tool is now available on all Sirius diagrams. With it, end users no longer have to select a specific edge creation tool in the palette, but only to choose the source and target elements (ticket #528002).

    • Improved compatibility with Xtext with an important bug fix (ticket #513407). This is a first step towards a better integration with Xtext, more fixes and improvements will come during the year.

    • It is now possible for specifiers to configure the background color of each diagram. Like everything else in Sirius, the color can be dynamic and reflect the current state of the model. (ticket #525533).

    • When developing a new modeler, it is now possible to reload the modeler’s definition (.odesign) from an Eclipse runtime if the definition has changed in the host that launched the runtime. This is similar to “hot code replace” in Java, but for VSMs, and avoids stopping/restarting a new runtime on each VSM change (ticket #522407).

    • In the VSM editor, when editing an interpreted expression which uses custom Java services, it is now possible to navigate directly to a service’s source code using F3 (ticket #471900).

    A more visual overview can be found in the Obeo blog.

  • Altran’s own Marc Hamilton shares Altran’s experience developing MDE applications with Eclipse technology.

    Altran Netherlands develops Eclipse-based model-driven applications for its customers for several years.
    In this talk, we share our experience with different modeling technologies like Acceleo, OCL, QVTo, EGF, Sirius, Xtext, and others.

  • What’s new in Xtext 2.14 will be presented by Xtext committer of itemis, Holger Schill.

    Major Changes in Xtext 2.14:

    • Java 9 and 10 Support
    • JUnit 5 Support
    • New Grammar Annotations
    • Create Action Quickfix
    • Code Mining Support
    • New Project and File Wizard
    • Improved Language Server Support
    • Performance Improvements

    Please check the Release Notes for details.

  • Yet another overview by Karsten Thoms, of itemis with his talk Approaching Light Speed – News from the Eclipse Photon Platform.

    The Eclipse Photon simultaneous release comes this year with a plethora of new features and improvements that will continue the Eclipse IDE keeping the #1 flexible, scalable and most performing IDE!

    This session will give a guided tour through the new features and changes in Eclipse Photon. Due to the vast amount of noteworthy stuff the focus of this talk is on the Eclipse Platform Project, covering JDT only roughly. You will see usability improvements, useful new API for platform developers and neat features for users. Besides visible changes, the platform project team has paid special attention on stability, performance and resource consumption tuning. In this talk, I will give some insights how the team has worked on that.

    Come and see the incredible achievements the platform team and its growing number of contributors made to bring you the best Eclipse IDE ever!

More talks are in discussion. Please propose your talk to us; we’d be especially happy to include more local speakers in the lineup.

We’ll have a break and some get-together afterwards, so there is plenty of opportunity to get in touch with the speakers and your fellow Eclipse enthusiasts in the region.

The DemoCamp will take place at the Altran office in Eindhoven. Please refer to the Eclipse wiki for all details and register now to secure your spot at the first Eclipse DemoCamp in Eindhoven!

High-Performance Interpreters for JetBrains MPS

tl;dr An interpreter framework prototype based on GraalVM / Truffle shows two orders of magnitude better performance than the previous implementation. Vote for Java Annotation Processor support in MPS to help this effort.

Overview

At the great MPS Meetup last week in Munich I had a chance to give a talk on the MPS Interpreter Framework I worked on at itemis. The slides are available, and the talk was recorded.
We had an enthusiastic audience with lots of questions. This skewed my timing a bit, thus I could only spend a few minutes on my latest experiments in this field: A new take on the interpreter framework, based on GraalVM / Truffle. Meinte Boersma inspired this blog post to add more details — thanks a lot for the motivation, Meinte!

To shortly recap the first part of my talk: Interpreters are easy to implement, especially if an MPS language avoids the usual boilerplate and integration in the typesystem gets rid of instanceof and casting orgies. This is pretty much the the state of the existing Interpreter Framework, which is used in a lot of real-world projects (e.g. KernelF or at the Dutch tax office).

This leaves us with one big drawback of interpreters: Usually, their performance is pretty bad. Enter GraalVM!
GraalVM is a highly optimized just-in-time-compiler for Java. It also provides an API to the code running on the JVM, and thus can be leveraged by Truffle.
Truffle is a library to implement high-performance interpreters, it uses all the tricks in the book: AST rewriting, partial evaluation, polymorphic inline caches, …, you name it. This leads to pretty impressive performance, like 90 % of the hand-optimized V8 JavaScript engine. Truffle makes use of GraalVM, but also runs on a regular JVM.
Another part of GraalVM ecosystem is called Polyglot. It allows interaction and optimization across languages, e.g. starting a JavaScript program, calling an R routine, which calls Ruby, which uses JavaScript, and all of this without data serialization or performance drawback.
Incidentally, Oracle released GraalVM 1.0 this week. We might see a lot more traction in this field.

Based on the first non-representative, non-exhaustive tests, GraalVM delivers big time:

  • Truffle runs within MPS, but on a regular JVM (i.e. without GraalVM JIT).
  • Legacy is the existing interpreter framework within MPS.
  • Graal skewed runs Truffle within MPS on a GraalVM JIT. I must have messed up something there, as the performance should be better than pure Truffle. Also, MPS itself felt quite sluggish with this configuration.
  • Graal extrapolated uses the stand-alone version (outside MPS) as a comparison what should be achievable.

Please note that the test program was quite basic, probably leading to overly optimistic results. However, I used a pretty old version of GraalVM (shipped with JDK9 on Windows) and Truffle (0.30), and reportedly newer versions perform a lot better. So in total, I think we can expect two orders of magnitude better performance.

Technical Details

GraalVM

GraalVM is available in a special build of Java8 on Linux and Mac. Java9 on Windows and Mac and Java10 on Linux also contain a (probably outdated) version of GraalVM.

As my current development environment is on Windows, I first tried to build the source version of GraalVM on Windows. I finally got it built, but the resulting java.exe segfaulted even on java.exe -version.
The next best way was to get MPS running on Java9. If we’re using Java8 for compilation and Java9 only as a runtime environment, we only need a few adjustments to the MPS sources. I put my hack on github. Be warned: it contains a few hard-coded local paths!

Truffle

Truffle relies on Java Annotation Processors, a standardized way to extend the Java compiler.
MPS internally uses the Eclipse java compiler, which fully supports annotation processors. The Eclipse java compiler also supports both the IntelliJ compiler infrastructure and the Java standard for calling compilers, but MPS uses a hand-knitted interface to the compiler without annotation processor support. I opened a Feature request for MPS to support Annotation Processors, so please upvote if you’re interested in high-performance interpreters.
My aforementioned hack also contains changes to enable the required annotation processors within MPS.

TruffleInterpreter Language

I started the language from scratch for several reasons:

  • The existing Interpreter language was the first thing I implemented in MPS, and I learned a lot since then.
  • The interpreter should become its own language aspect, thus requiring considerable changes anyway.
  • Understanding Truffle and generating the correct code for it is hard enough, I didn’t want to add the burden of non-fitting abstractions.
  • We need quite some additional information for the new backend.

Obviously, I kept the nice parts regarding concise syntax and typesystem integration.

I did not spend much time yet on beautifying the language, but I think the general idea is already recognizable.

As a playground, I implemented SimpleLanguage as shipped with Truffle in both MPS interpreter frameworks. (Please find screenshots of the complete interpreters at the end of this post.)

Let’s look at a few examples from both interpreters:

  • Invoke Expression
    Invoke maps quite directly.

    Legacy

    Truffle

  • Plus Expression
    Plus is also similar, but we can spot some differences:

    • Mixtures of types are handled automatically by Truffle
    • Truffle adds programmatic type guards for the String overload

    Legacy

    Truffle

  • Typemapping
    The actual typemapping is very similar. However, Truffle needs to know about the run-time (aka interpretation-time) typesystem including type checks, type casts, and implicit casts.

    Legacy

    Truffle

The Truffle variant contains a few more hints only accessible via inspector.

I guess a converter from legacy to Truffle interpreters should be feasible, but the result might not run out-of-the-box.

Implementation

The implementation faced three main issues:

  • Generating the correct code for Truffle

    Truffle is very picky about what code it accepts, e.g. some fields must be final, but others must not. There seems no way for annotation processors to emit messages during compilation. Thus, we generate some code, and it either works or not, without any hints (in some cases we pass the compilation steps and get hints during execution).

  • Providing the generated truffle interpreter to the Truffle runtime

    Truffle expects all its languages to be available in its classpath at startup.
    So currently, we cannot change the interpreters after the first invocation of any (!) interpreter.
    There might be a way to add languages at runtime, but my hunch is this would get us into never-ending classloading issues. See below for thoughts on a better approach.

  • Running annotation processors the same time as the regular compilation

    The code generated by MPS contains calls to classes only generated by Truffle’s annotation processors, so we have to execute both in the same step.
    Re-implementing Truffle’s generators in MPS is also not an option, both from their size and complexity.

    This picture compares the input MPS Concepts mentioned in the interpreter, Java source files generated by MPS, and produced Java classes

    A small snippet of the Truffle-generated code. Who wants to tell me where I took it from?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    private Object executeGeneric_generic1(VirtualFrame frameValue, int state) {
      Object leftValue_ = this.left_.executeGeneric(frameValue);
      Object rightValue_ = this.right_.executeGeneric(frameValue);
      if ((state & 2) != 0 && leftValue_ instanceof Long) {
        long leftValue__ = (Long)leftValue_;
        if (rightValue_ instanceof Long) {
          long rightValue__ = (Long)rightValue_;

          try {
            return this.specialization(leftValue__, rightValue__);
          } catch (ArithmeticException var14) {
            Lock lock = this.getLock();
            lock.lock();

            try {
              this.exclude_ |= 1;
              this.state_ &= -3;
            } finally {
              lock.unlock();
            }

            return this.executeAndSpecialize(leftValue__, rightValue__);
          }
        }
      }

      if ((state & 4) != 0 && SLxTypesGen.isImplicitBigInteger((state & 48) >>> 4, leftValue_)) {
        BigInteger leftValue__ = SLxTypesGen.asImplicitBigInteger((state & 48) >>> 4, leftValue_);
        if (SLxTypesGen.isImplicitBigInteger((state & 192) >>> 6, rightValue_)) {
          BigInteger rightValue__ = SLxTypesGen.asImplicitBigInteger((state & 192) >>> 6, rightValue_);
          return this.specialization(leftValue__, rightValue__);
        }
      }

      if ((state & 8) != 0 && this.guardSpecialization(rightValue_, leftValue_)) {
        return this.specialization(leftValue_, rightValue_);
      } else {
        CompilerDirectives.transferToInterpreterAndInvalidate();
        return this.executeAndSpecialize(leftValue_, rightValue_);
      }
    }

Lifecycle

  1. We start by defining our Language SimpleLanguage as usual. As an example, we define a concept SlPlus.
  2. We create a TruffleInterpreter for SimpleLanguage. In the interpreter, we create the evaluator for SlPlus.
  3. The generator of TruffleInterpreter turns the evaluator for SlPlus into a Java class named SlPlusNode that inherits from TruffleNode.
  4. Once we want to evaluate our instance model of SimpleLanguage, the TruffleInterpreter framework converts all instances of SlPlus (i.e. MPS nodes of concept SlPlus) into instances of SlPlusNode (i.e. Java objects of class SlPlusNode).
  5. The TruffleInterpreter framework invokes the TruffleRuntime on the recently created SlPlusNode object.
  6. We can retrieve the result of our interpretation, e.g. a java.lang.Long object, from TruffleRuntime.

Truffle requires all evaluated nodes to be TruffleNodes to do its magic.
This implies some overhead to convert MpsNodes into TruffleNodes, but allows us to execute the interpreter without model access afterwards. We can even run the interpreter in a different thread and update our editor once the calculation is done.

Language Interoperability

The Polyglot part of GraalVM allows arbitrary mixture of languages. The prototype contains an example to call JavaScript:

(You have to know this joke!)

Polyglot supports language interoperability with complex types, but I didn’t implement this yet in this prototype.

Future Work

Turn Prototype into Production Code
This blog post is about a prototype, meant to explore the possibilities, pitfalls and benefits. It breaks quickly if you try something different. It does not implement all features of Truffle. The generator does not need to be rewritten from scratch, but needs a serious overhaul. The language is too close to Truffle specifics, and thus hard to use if you don’t know about Truffle.

Interpreter Language Aspect
Interpreters should be a separate language aspect, the same way as typesystem or constraints. At the MPS Meetup we agreed that executing your models is highly valuable in lots of domains; a language aspect emphasizes this importance.
Also, having a language aspect should improve integration with the rest of the MPS ecosystem and ease classloading for interpreters.

One Interpreter for all Languages
The current implementation registers every interpreter as its own Truffle language; the idea was to leverage Polyglot for language interaction. However, this leads to classloading issues.

An alternative would be to look at interpreters similar to editors: In MPS, we have a standard editor for all concepts. If we need to, we can provide other editors triggered by editor hints. Similarly, we could have one standard language (from a Truffle point of view), and all interpreters contribute to this standard Truffle language. We might register a few secondary Truffle languages by default, so we don’t have to restart MPS as soon as anybody wants to use an “interpreter hint”.

This should maintain MPS language extensibility, as any MPS language can contribute standard interpreters for any concept, or might register secondary interpreters with an “interpreter hint”.

I’m not sure yet what to do about nodes without any known interpreter. We might want to ignore them, or traverse their subnodes to find something we can interpret.

Fine-tuning MpsNode → TruffleNode Conversion

The current implementation converts an arbitrary selection of MpsNodes into TruffleNodes prior to invoking the interpreter. We could think of other approaches:

  • Convert the starting node and all contained and related nodes up to a specific depth; At the end of each branch, we’d insert a “ReloadNode” to convert more nodes once it’s needed.
  • We could keep the converted TruffleNodes in memory and update them on any changes to the underlying MpsNodes (aka “Shadow model”).
  • It should be feasible to make our TruffleNodes serializable. Thus, we could save and reload them on MPS restart, or even execute them outside MPS.

Typesystem Integration
As mentioned above, the Truffle interpreter needs to know a lot about runtime types. At least for some of the information, we might be able to infer it from the MPS typesystem aspect.

Scoping Integration
If our interpreted language had nested scopes, maybe even including shadowing, the interpreter needs to know this. We might be able to infer this knowledge from the MPS constraints aspect.

DSL for Objects
Polyglot supports direct interaction between different languages on complex types. I only scratched this topic yet, but so far this seems to be very exiting both to interact with non-MPS Truffle languages (GraalVM ships with implementations of JavaScript, R, and Ruby) and to enable language composition at runtime.

Truffle bases the interaction on a concept called Shapes; I’m pretty sure there could be a DSL to ease their usage.

Debugger Integration
For smaller interpreted programs, something similar to the Trace Explorer available for the legacy Interpreter could be very useful.

GraalVM supports exposing the interpreted program via the standard JVM debugging APIs, including breakpoints and introspection. Contrary to popular belief, a Java program can debug itself, as long as the debugger and the target (i.e. interpreter) run in different threads. So we might be able to use the debugging UI included in MPS (as inherited from IntelliJ) to debug our interpreted program. A long time ago, I wrote a proof-of-concept of this idea for the legacy Interpreter, so we know we can get to the appropriate APIs.

Ahead-of-Time Compilation Support
A yet unmentioned part of GraalVM is called Sulong: An ahead-of-time-compiler for Truffle languages. I have no experience with Sulong, so I can only guess about its possibilities.
Especially in combination with serializable TruffleNodes this might lead to production-ready performance outside of MPS, thus rendering a separate implementation of the same logic in a generator obsolete.
Edit: I mixed up Sulong and SubstrateVM, as Oleg points out in the comments.

Appendix: Complete Interpreters

Legacy

Truffle

Do we need Eclipse Commons?

tl;dr Vote at https://github.com/enikao/eclipse-commons/issues/1 in favor or against creating an Eclipse Commons (akin to Apache Commons) project.

Rationale

Have you ever done an Eclipse / EMF project without implementing this code?

1
2
3
4
5
6
7
8
public static IResource toIResource(URI uri) {
    if (uri.isPlatformResource()) {
        return ResourcesPlugin.getWorkspace().getRoot()
            .findMember(uri.toPlatformString(true));
    }
   
    return null;
}

I haven’t. And I’m tired of writing this code over and over again. Especially as I usually need more than one take to get it right (for example, the version above does not handle URIs pointing to non-existing IResources).

It already has been implemented several times. But I don’t want to introduce complex dependencies for reusing these implementations.

There are lots of other commonly reused code snippets, like

  • java.net.URIorg.eclipse.emf.common.util.URI
  • In an JUnit test, wait for the workspace to be ready
  • Create an IStatus without breaking your fingers

I therefore propose an Eclipse Commons project. This project would collect small utilities with minimal additional dependencies for common reuse.

Counter-Arguments

Allow me to anticipate some counter-arguments.

This code should be in the original project!

Yes, it should. But it is not. Some reasons might be personal preferences by the maintainers (“This code snippet is too short to be useful”), contextual arguments (“An URI cannot be generically represented as an IResource”), or no actual original project (where would the JUnit extensions go?).
(Please note that these are hypothetical reasons, not based on concrete experience.)

We don’t want to repeat the npm desaster with tiny snippets!

I envision Eclipse Commons to be hosted by the Eclipse Foundation (obviously). Therefore, no code that has been in there can just disappear.

This seems like an arbitrary collection of code. Who decides what is in, what is out of scope?

I propose a two-step approach. First, there is a “pile” repository (better name highly appreciated) where almost anything can be proposed. For each new proposal, we would have a vote. Every proposal that passes a threshold of votes (details tbd) and meets the required quality is accepted in Eclipse Commons.
Deployable artifacts are only created from the Eclipse Commons repository.

We definitely do not want to re-implement functionality that’s available on a similar level, like Apache Commons or Google Guava.

That’s chaos! Who creates order?

Besides some sanitation, I would not enforce any “grand scheme of things”. I’d guess Eclipse Commons would contain a quite diverse code base, therefore we don’t need central coordination. Also, there might not be any one party with enough insight into all parts of Eclipse Commons.

If a sizable chunk of code for a common topic agglomerates, it’s a good sign that the original project is really missing something and should adopt this chunk of code. This implies there is a party capable of bringing order to that chunk.

Also, Eclipse Commons should not be misused as a dump for large code base(s) that really should be their own project.

Thoughts on Implementation

Dependencies

Eclipse Commons should be separated in different plug-ins, guided by having the least possible dependencies. We might have one plug-in org.eclipse.commons.emf only depending on org.eclipse.core.runtime, org.eclipse.core.resources, and org.eclipse.emf.*. Another one might be org.eclipse.commons.junit depending only on core Eclipse and JUnit plug-ins, etc.

We should have strict separation between UI and non-UI dependent code. Where applicable, we should separate OSGi-dependent code from OSGi-independent implementations (as an example, a class EcoreUtil2 might go to the plug-in org.eclipse.commons.emf.standalone, as EMF can be used without OSGi).

As these plug-ins are meant solely for reuse, they should re-export any dependencies required to use them. We must avoid “class hierarchy incomplete” or “indirectly required” errors for Eclipse Commons users.

Versioning and Evolution

I propose semantic versioning. Regarding version x.y.z, we increase y every time some new proposal is migrated from “pile”. We reset z for every y increment to 0, and increase z for maintenance and bug fixes. x might be increased when code chunks are moved to an original project or one of our dependencies changes (see below). Every JavaDoc must contain @since for fine-grained versioning.

We should be “forever” (i.e. the foreseeable future) backwards-compatible, so we avoid any issues with upgrading. If code chunks are moved to an original project, this code should still be available within Eclipse Commons, but should be marked as @deprecated. Removing these chunks would require Eclipse Commons users to move to the newest version of the original project, but they might be not be able to do this. For the same reason, we cannot delegate from the (now deprecated) Eclipse Commons implementation to the original project.

I’m not sure what to do if a new proposal required a major change in our dependencies. As example, the existing plug-in org.eclipse.commons.emf might depend on org.eclipse.emf in version 2.3, but the new proposal required changes only introduced in EMF v2.6. We might want to go through with such a change, or create a separate plug-in with stricter dependencies.

Required Quality

I think the bar for entering “pile” should be rather low. This allows voting how useful the addition might be to others, and also allows community effort in reaching the desired quality. As we expect more or less independent utilities, improvements by others than the original authors should be easily possible without much required ramp-up.

On the other hand, code that enters Eclipse Commons must be pretty good. We want to keep this “forever”, and don’t want to spend the next year cleaning up after a have-backed once-off addition. This includes thorough documentation and tests.

We should care for naming, especially symmetry in naming. Having two methods IResource UriUtils.toIResource(URI) and URI IResourceTool.asUri(IResource) is highly undesirable.

Next Steps

I created a (temporary) repository at https://github.com/enikao/eclipse-commons, including a (hopefully) thorough implementation of aforementioned utility method.

What do you think of Eclipse Commons? Would you use it? Contribute? Help in maintaining it? How many votes should be the “pile” → Eclipse Commons threshold? And what would be a better name than “pile”?
Please leave your votes and comments at github.

If there was sufficient interest, the next step would be an Eclipse Incubation Project proposal.

Combine Xcore, Xtend, Ecore, and Maven

Update: Christian found a workaround for compiling code that references Ecore types. We adjusted the article.

Lots of thanks to Christian for figuring this out together.

The complete example is available on github.

Also, we included all the files as Listings at the end of the article. They are heavily commented.

Objective

Inside an Eclipse plugin, we have EMF models defined in both Xcore and Ecore, using types from each other. Also, we have a Helper Xtend class that’s called from Xcore and uses types from the same model. We want to build the Eclipse Plugin with Maven. We also don’t want to commit any generated sources (from Xtend, Xcore, or Ecore).

Issue

Usually, we would use xtend-maven-plugin to build the Xtend classes, xtext-maven-plugin to build the Xcore model, and MWE2 to build the Ecore model.

However, we have a cyclic compile-time dependency between AllGreetings calling GreetingsHelper.compileAllGreetings() which receives a parameter of type AllGreetings. We also have a cyclic dependency between AllGreetings calling GreetingsHelper.compileAllPersons() and using IPerson type.

Solution

Java (and Xtend) can solve such cycles in general, but only if they process all members at the same time. Thus, we need to make sure both Xtend and Xcore are generated within the same Maven plugin.

We didn’t find a way to include the regular Ecore generator in the same step, so we keep this in a separate MWE2-based Maven plugin.

For generating persons.ecore, we call an MWE2 workflow from Maven via exec-maven-plugin. The workflow itself gets a bit more complicated, as we use INamedElement from base.xcore as a supertype to IPerson inside persons.ecore. Thus, we need to ensure that base.xcore is loaded, available, and can be understood by the Ecore generator.

Afterwards, we use xtext-maven-plugin to generate both Xtend and the two Xcore models. To do this, we need to include all the required languages and dependencies into one single plugin in our maven pom.

The first version could not compile GreetingsHelper.compileAllPersons() because it referenced types from persons.ecore, and these could not be resolved by the EMF validator. As a workaround, we disabled the validator in the workflow.

Remarks

  • We developed this using Eclipse Mars.2.
  • The example project should be free of errors and warnings, and builds in all of Eclipse, MWE2, and Maven.

    In Maven, you might see some warnings due to an Xtext bug. It should not have any negative impact.

  • When creating the Ecore file, make sure only to use built-in types (like EString) from http://www.eclipse.org/emf/2002/Ecore. They may be listed several times.
  • In our genmodel file, Eclipse tends to replace this way of referring to platform:/resource/org.eclipse.emf.ecore/model/Ecore.genmodel#//ecore by something like ../../org.eclipse.emf.ecore/model/Ecore.genmodel#//ecore. This would lead to ConcurrentModificationException in xtext-maven-plugin or MWE2, or “The referenced packages ”{0}” and ”{1}” have the same namespace URI and cannot be checked at the same time.” when opening the GenModel editor.

    In this case, open the genmodel file with a text editor and use the platform:/resource/org.eclipse.emf.ecore/model/Ecore.genmodel#//ecore form in the genmodel:GenModel#usedGenPackages attribute. Sadly, this needs to be fixed every time the Genmodel Editor saves the file.

  • The Xcore builder inside Eclipse automatically picks up the latest EMF complianceLevel, leading to Java generics support in generated code. The maven plugin does not use the latest complianceLevel, thus we need to set it explicitly.
  • The modelDirectory setting in both Xcore and Ecore seem to be highly sensitive to leading or trailing slashes. We found it safest not to have them at all.
  • Using all the involved generators (MWE2, Xcore, Xtend, …) requires quite a few dependencies for our plugin. As a neat trick, we can define them in build.properties rather than MANIFEST.MF. This way, they are available at build time, but do not clog our run-time classpath. As we can see on the right, they are also listed separately in the Eclipse dependency editor.
  • maven-clean-plugin seems to be quite sensitive how its filesets are described. Even when disregarding the .dummy.txt entries in our pom, the *-gen directories were only cleaned if we listed them in separate fileset entries.
  • The workflow should reside within an Eclipse source folder. To separate it from real sources, we created a new source folder named workflow.

Listings

Project Layout

GreetingsHelper.xtend

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package de.nikostotz.xtendxcoremaven.greetings.helper

import de.nikostotz.xtendxcoremaven.greetings.AllGreetings

class GreetingsHelper {
    // This method is called from greetings.xcore and has AllGreetings as parameter type,
    // thus creating a dependency circle
    def static String compileAllGreetings(AllGreetings it) {
        var totalSize = 0
        // We access the AllGreetings.getGreetings() method in two different ways
        // (for-each-loop and map) to demonstrate different error messages if we omit
        // 'complianceLevel="8.0"' in greetings.xcore
        for (greeting : it.getGreetings()) {
            totalSize = totalSize + greeting.getMessage().length
        }
       
        '''
        Greetings:
            «it.getGreetings().map[greeting | greeting.getMessage()].join(", ")»
        '
''
    }
   
    def static String compileAllPersons(AllGreetings it) {
        // AllGreetings.getPersons() refers to type IPerson, which is defined in Ecore.
        // This only works if we disable the validator in the MWE2 workflow.
        '''
        Hello Humans:
            «it.getPersons().map[person | person.describeMyself()].join(", ")»
        '
''
    }
}

base.xcore

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@GenModel(
    // This sets the target directory where to put the generated classes.
    // Make sure NOT to start or end with a slash!
    // Doing so would lead to issues either with Eclipse builder, MWE2 launch, or Maven
    modelDirectory="de.nikostotz.xtendxcoremaven/xcore-gen",

    // required to fix an issue with xcore (see https://www.eclipse.org/forums/index.php/t/367588/)
    operationReflection="false"
)
package de.nikostotz.xtendxcoremaven.base

// This enables usage of the @GenModel annotation above. The annotation would work without
// this line in Eclipse, but Maven would fail.
// (WorkflowInterruptedException: Validation problems: GenModel cannot be resolved.)
annotation "http://www.eclipse.org/emf/2002/GenModel" as GenModel

interface INamedElement {
    String name
}

persons

persons.ecore

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
< ?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="persons" nsURI="de.nikostotz.xtendxcoremaven.persons" nsPrefix="persons">
  <eclassifiers xsi:type="ecore:EClass" name="IPerson" abstract="true" interface="true"
     eSuperTypes="base.xcore#/EPackage/INamedElement">
    <eoperations name="describeMyself" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"></eoperations>
  </eclassifiers>
  <eclassifiers xsi:type="ecore:EClass" name="Human" eSuperTypes="#//IPerson">
    <estructuralfeatures xsi:type="ecore:EAttribute" name="knownHumanLanguages" upperBound="-1"
       eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"></estructuralfeatures>
  </eclassifiers>
  <eclassifiers xsi:type="ecore:EClass" name="Developer" eSuperTypes="#//IPerson">
    <estructuralfeatures xsi:type="ecore:EAttribute" name="knownProgrammingLanguages"
       upperBound="-1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"></estructuralfeatures>
  </eclassifiers>
</ecore:epackage>

persons.genmodel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
< ?xml version="1.0" encoding="UTF-8"?>
<genmodel:genmodel xmi:version="2.0"
    xmlns:xmi="http://www.omg.org/XMI" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
    xmlns:genmodel="http://www.eclipse.org/emf/2002/GenModel"
    modelDirectory="de.nikostotz.xtendxcoremaven/emf-gen" modelName="Persons"
    importerID="org.eclipse.emf.importer.ecore" complianceLevel="8.0"
    copyrightFields="false" importOrganizing="true"
    usedGenPackages="base.xcore#/1/base platform:/resource/org.eclipse.emf.ecore/model/Ecore.genmodel#//ecore">
    <!-- Eclipse tends to replace this way of referring to the Ecore genmodel
        by something like "../../org.eclipse.emf.ecore/model/Ecore.genmodel#//ecore".
        This would lead to ConcurrentModificationException in xtext-maven-plugin
        or MWE2, or "The referenced packages ''{0}'' and ''{1}'' have the same namespace
        URI and cannot be checked at the same time."
when opening the GenModel editor. -->

    <foreignmodel>persons.ecore</foreignmodel>
    <genpackages prefix="Persons" basePackage="de.nikostotz.xtendxcoremaven.persons"
        disposableProviderFactory="true" ecorePackage="persons.ecore#/">
        <genclasses image="false" ecoreClass="persons.ecore#//IPerson">
            <genoperations ecoreOperation="persons.ecore#//IPerson/describeMyself"></genoperations>
        </genclasses>
        <genclasses ecoreClass="persons.ecore#//Human">
            <genfeatures createChild="false"
                ecoreFeature="ecore:EAttribute persons.ecore#//Human/knownHumanLanguages"></genfeatures>
        </genclasses>
        <genclasses ecoreClass="persons.ecore#//Developer">
            <genfeatures createChild="false"
                ecoreFeature="ecore:EAttribute persons.ecore#//Developer/knownProgrammingLanguages"></genfeatures>
        </genclasses>
    </genpackages>
</genmodel:genmodel>

greetings.xcore

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@GenModel(
    modelDirectory="de.nikostotz.xtendxcoremaven/xcore-gen",
    operationReflection="false",
   
    // This enables Java generics support in EMF (starting with version 6.0).
    // If omitted, we'd get a "Validation Problem: The method or field message is undefined" in Maven
    // because AllGreetings.getGreetings() would return an EList instead of an EList<greeting>, thus
    // we cannot know about the types of the list elements and whether they have a 'message' property.
    // In other cases, this leads to error messages like "Cannot cast Object to Greeting".
    complianceLevel="8.0"
)

package de.nikostotz.xtendxcoremaven.greetings

// referring to Ecore
import de.nikostotz.xtendxcoremaven.persons.persons.IPerson

// referring to Xtend
import de.nikostotz.xtendxcoremaven.greetings.helper.GreetingsHelper

annotation "http://www.eclipse.org/emf/2002/GenModel" as GenModel

class AllGreetings {
    contains IPerson[] persons
    contains Greeting[] greetings
   
    op String compileAllGreetings() {
        // calling Xtend inside Xcore
        GreetingsHelper.compileAllGreetings(this)
    }
   
    op String compileAllPersons() {
        // calling Xtend inside Xcore
        GreetingsHelper.compileAllPersons(this)
    }
}

class Greeting {
    String message
    refers IPerson person
}

MANIFEST.MF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: de.nikostotz.xtendxcoremaven;singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-ClassPath: .
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Bundle-Activator: de.nikostotz.xtendxcoremaven.XtendXcoreMavenActivator
Require-Bundle: org.eclipse.core.runtime,
org.eclipse.emf.ecore;visibility:=reexport,
org.eclipse.xtext.xbase.lib,
org.eclipse.emf.ecore.xcore.lib
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Export-Package: de.nikostotz.xtendxcoremaven.greetings.impl,
de.nikostotz.xtendxcoremaven.greetings.util,
de.nikostotz.xtendxcoremaven.base,
de.nikostotz.xtendxcoremaven.base.impl,
de.nikostotz.xtendxcoremaven.base.util,
de.nikostotz.xtendxcoremaven.persons.persons,
de.nikostotz.xtendxcoremaven.persons.persons.impl,
de.nikostotz.xtendxcoremaven.persons.persons.util
Bundle-ActivationPolicy: lazy

build.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#

bin.includes = .,\
               model/,\
               META-INF/,\
               plugin.xml,\
               plugin.properties
jars.compile.order = .
source.. = src/,\
           emf-gen/,\
           xcore-gen/,\
           xtend-gen/
src.excludes = workflow/
output.. = bin/
# These work the same as entries in MANIFEST.MF#Require-Bundle, but only at build time, not run-time
additional.bundles = org.eclipse.emf.mwe2.launch,\
                     org.apache.log4j,\
                     org.apache.commons.logging,\
                     org.eclipse.xtext.ecore,\
                     org.eclipse.emf.codegen.ecore.xtext,\
                     org.eclipse.emf.ecore.xcore,\
                     org.eclipse.xtend.core,\
                     org.eclipse.emf.codegen.ecore,\
                     org.eclipse.emf.mwe.core,\
                     org.eclipse.emf.mwe.utils,\
                     org.eclipse.emf.mwe2.lib

generateGenModel.mwe2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
module GenerateGenModel

var projectName = "de.nikostotz.xtendxcoremaven"
var rootPath = ".."

Workflow {
    // This configures the supported model types for EcoreGenerator.
    // Order is important.
    // Should be the same list as in Reader below.
    bean = org.eclipse.emf.ecore.xcore.XcoreStandaloneSetup {}
    bean = org.eclipse.xtend.core.XtendStandaloneSetup {}
    bean = org.eclipse.xtext.ecore.EcoreSupport {}
    bean = org.eclipse.emf.codegen.ecore.xtext.GenModelSupport {}
   
    bean = org.eclipse.emf.mwe.utils.StandaloneSetup {
        // Required for finding the platform contents (Ecore.ecore, Ecore.genmodel, ...) under all circumstances
        platformUri = "${rootPath}"
       
        // Required for finding above mentioned models inside their Eclipse plugins
        scanClassPath = true
    }
       
    // As persons.ecore refers to a type inside base.xcore (IPerson extends INamedElement),
    // we need to load base.xcore before we can generate persons.ecore.
    component = org.eclipse.xtext.mwe.Reader {
        // This configures the supported model types for this Reader.
        // Order is important.
        // Should be the same list as beans above.
        register = org.eclipse.emf.ecore.xcore.XcoreStandaloneSetup {}
        register = org.eclipse.xtend.core.XtendStandaloneSetup {}
        register = org.eclipse.xtext.ecore.EcoreSupport {}
        register = org.eclipse.emf.codegen.ecore.xtext.GenModelSupport {}
       
        // This asks the Reader to read all models it understands from these directories (and sub-directories).
        path = "model"
        path = "src"
       
        // Put the models inside a ResourceSet that's accessible by the EcoreGenerator.
        loadFromResourceSet =  {}
       
        // This is a workaround to get GreetingsHelper.compileAllPersons() compiled.
        validate = org.eclipse.xtext.mwe.Validator.Disabled {}
    }
   
    // Generate persons.ecore (via persons.genmodel).
    component = org.eclipse.emf.mwe2.ecore.EcoreGenerator {
        genModel = "platform:/resource/${projectName}/model/persons.genmodel"
        srcPath = "platform:/resource/${projectName}/emf-gen"
    }
}

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelversion>4.0.0</modelversion>
    <groupid>de.nikostotz.xtendxcoremaven</groupid>
    <version>1.0.0-SNAPSHOT</version>
    <artifactid>de.nikostotz.xtendxcoremaven</artifactid>

    <properties>
        <project .build.sourceEncoding>UTF-8</project>

        <!-- Java version, will be honored by Xcore / Xtend -->
        <maven .compiler.source>1.8</maven>
        <maven .compiler.target>1.8</maven>

        <!-- Xtend / Xcore -->
        <core -resources-version>3.7.100</core>
        <eclipse -text-version>3.5.101</eclipse>
        <emf -version>2.12.0</emf>
        <emf -common-version>2.12.0</emf>
        <emf -codegen-version>2.11.0</emf>
        <xtext -version>2.10.0</xtext>
        <ecore -xtext-version>1.2.0</ecore>
        <ecore -xcore-version>1.3.1</ecore>
        <ecore -xcore-lib-version>1.1.100</ecore>
        <emf -mwe2-launch-version>2.8.3</emf>
    </properties>

    <dependencies>
        <dependency>
            <groupid>org.eclipse.emf</groupid>
            <artifactid>org.eclipse.emf.common</artifactid>
            <version>${emf-common-version}</version>
        </dependency>
        <dependency>
            <groupid>org.eclipse.emf</groupid>
            <artifactid>org.eclipse.emf.ecore</artifactid>
            <version>${emf-version}</version>
        </dependency>
        <dependency>
            <groupid>org.eclipse.emf</groupid>
            <artifactid>org.eclipse.emf.ecore.xcore.lib</artifactid>
            <version>${ecore-xcore-lib-version}</version>
        </dependency>
        <dependency>
            <groupid>org.eclipse.xtext</groupid>
            <artifactid>org.eclipse.xtext.xbase.lib</artifactid>
            <version>${xtext-version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupid>org.apache.maven.plugins</groupid>
                <artifactid>maven-compiler-plugin</artifactid>
                <version>3.3</version>
            </plugin>

            <plugin>
                <artifactid>maven-clean-plugin</artifactid>
                <version>2.6.1</version>
                <configuration>
                    <filesets>
                        <fileset>
                            <excludes>
                                <exclude>.dummy.txt</exclude>
                            </excludes>
                            <directory>emf-gen</directory>
                        </fileset>
                        <fileset>
                            <excludes>
                                <exclude>.dummy.txt</exclude>
                            </excludes>
                            <directory>xtend-gen</directory>
                        </fileset>
                        <fileset>
                            <excludes>
                                <exclude>.dummy.txt</exclude>
                            </excludes>
                            <directory>xcore-gen</directory>
                        </fileset>
                    </filesets>
                </configuration>
            </plugin>

            <!-- Adds the generated sources to the compiler input -->
            <plugin>
                <groupid>org.codehaus.mojo</groupid>
                <artifactid>build-helper-maven-plugin</artifactid>
                <version>1.9.1</version>
                <executions>
                    <execution>
                        <id>add-source</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>add-source</goal>
                        </goals>
                        <configuration>
                            <!-- This should be in sync with xtext-maven-plugin//source-roots,
                                except for /model directory -->
                            <sources>
                                <source />${basedir}/emf-gen
                                <source />${basedir}/xcore-gen
                                <source />${basedir}/xtend-gen
                            </sources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <!-- Generates the Ecore model via MWE2 -->
            <plugin>
                <groupid>org.codehaus.mojo</groupid>
                <artifactid>exec-maven-plugin</artifactid>
                <version>1.4.0</version>
                <executions>
                    <execution>
                        <id>mwe2Launcher</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <mainclass>org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher</mainclass>
                    <arguments>
                        <argument>${project.basedir}/workflow/generateGenModel.mwe2</argument>
                        <argument>-p</argument>
                        <argument>rootPath=${project.basedir}/..</argument>
                    </arguments>
                    <classpathscope>compile</classpathscope>
                    <includeplugindependencies>true</includeplugindependencies>
                    <cleanupdaemonthreads>false</cleanupdaemonthreads><!-- see https://bugs.eclipse.org/bugs/show_bug.cgi?id=475098#c3 -->
                </configuration>
                <dependencies>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.mwe2.launch</artifactid>
                        <version>${emf-mwe2-launch-version}</version>
                    </dependency>

                    <dependency>
                        <groupid>org.eclipse.xtext</groupid>
                        <artifactid>org.eclipse.xtext.xtext</artifactid>
                        <version>${xtext-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.text</groupid>
                        <artifactid>org.eclipse.text</artifactid>
                        <version>${eclipse-text-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.core</groupid>
                        <artifactid>org.eclipse.core.resources</artifactid>
                        <version>${core-resources-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.xtend</groupid>
                        <artifactid>org.eclipse.xtend.core</artifactid>
                        <version>${xtext-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.xtext</groupid>
                        <artifactid>org.eclipse.xtext.ecore</artifactid>
                        <version>${xtext-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.xtext</groupid>
                        <artifactid>org.eclipse.xtext.xbase</artifactid>
                        <version>${xtext-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.codegen.ecore.xtext</artifactid>
                        <version>${ecore-xtext-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.common</artifactid>
                        <version>${emf-common-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.ecore</artifactid>
                        <version>${emf-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.ecore.xmi</artifactid>
                        <version>${emf-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.codegen</artifactid>
                        <version>${emf-codegen-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.codegen.ecore</artifactid>
                        <version>${emf-codegen-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.ecore.xcore</artifactid>
                        <version>${ecore-xcore-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.ecore.xcore.lib</artifactid>
                        <version>${ecore-xcore-lib-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.text</groupid>
                        <artifactid>org.eclipse.text</artifactid>
                        <version>${eclipse-text-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.core</groupid>
                        <artifactid>org.eclipse.core.resources</artifactid>
                        <version>${core-resources-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.xtend</groupid>
                        <artifactid>org.eclipse.xtend.core</artifactid>
                        <version>${xtext-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.xtext</groupid>
                        <artifactid>org.eclipse.xtext.ecore</artifactid>
                        <version>${xtext-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.xtext</groupid>
                        <artifactid>org.eclipse.xtext.xbase</artifactid>
                        <version>${xtext-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.codegen.ecore.xtext</artifactid>
                        <version>${ecore-xtext-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.common</artifactid>
                        <version>${emf-common-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.ecore</artifactid>
                        <version>${emf-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.ecore.xmi</artifactid>
                        <version>${emf-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.codegen</artifactid>
                        <version>${emf-codegen-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.codegen.ecore</artifactid>
                        <version>${emf-codegen-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.ecore.xcore</artifactid>
                        <version>${ecore-xcore-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.ecore.xcore.lib</artifactid>
                        <version>${ecore-xcore-lib-version}</version>
                    </dependency>
                </dependencies>
            </plugin>

            <!-- Generates the Xtend and Xcore models -->
            <plugin>
                <groupid>org.eclipse.xtext</groupid>
                <artifactid>xtext-maven-plugin</artifactid>
                <version>${xtext-version}</version>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <languages>
                        <language>
                            <setup>org.eclipse.xtext.ecore.EcoreSupport</setup>
                        </language>
                        <language>
                            <setup>org.eclipse.emf.codegen.ecore.xtext.GenModelSupport</setup>
                        </language>
                        <language>
                            <setup>org.eclipse.xtend.core.XtendStandaloneSetup</setup>
                            <outputconfigurations>
                                <outputconfiguration>
                                    <outputdirectory>${project.basedir}/xtend-gen</outputdirectory>
                                </outputconfiguration>
                            </outputconfigurations>
                        </language>
                        <language>
                            <setup>org.eclipse.emf.ecore.xcore.XcoreStandaloneSetup</setup>
                            <outputconfigurations>
                                <outputconfiguration>
                                    <outputdirectory>${project.basedir}/xcore-gen</outputdirectory>
                                </outputconfiguration>
                            </outputconfigurations>

                        </language>
                    </languages>
                    <!-- This should be in sync with build-helper-maven-plugin//sources,
                        except for /model directory -->
                    <sourceroots>
                        <root>${basedir}/src</root>
                        <root>${basedir}/emf-gen</root>
                        <!-- Note that we include the /model path here although it's not part
                            of the source directories in Eclipse or Maven -->
                        <root>${basedir}/model</root>
                    </sourceroots>
                    <!-- This does not work currently, as we can see by the missing lambda
                        in generated code for GreetingsHelper.compileAllGreetings(). It does work,
                        however, for xtend-maven-plugin. (see https://github.com/eclipse/xtext-maven/issues/11)-->
                    <javasourceversion>1.8</javasourceversion>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupid>org.eclipse.text</groupid>
                        <artifactid>org.eclipse.text</artifactid>
                        <version>${eclipse-text-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.core</groupid>
                        <artifactid>org.eclipse.core.resources</artifactid>
                        <version>${core-resources-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.xtend</groupid>
                        <artifactid>org.eclipse.xtend.core</artifactid>
                        <version>${xtext-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.xtext</groupid>
                        <artifactid>org.eclipse.xtext.ecore</artifactid>
                        <version>${xtext-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.xtext</groupid>
                        <artifactid>org.eclipse.xtext.xbase</artifactid>
                        <version>${xtext-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.codegen.ecore.xtext</artifactid>
                        <version>${ecore-xtext-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.common</artifactid>
                        <version>${emf-common-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.ecore</artifactid>
                        <version>${emf-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.ecore.xmi</artifactid>
                        <version>${emf-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.codegen</artifactid>
                        <version>${emf-codegen-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.codegen.ecore</artifactid>
                        <version>${emf-codegen-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.ecore.xcore</artifactid>
                        <version>${ecore-xcore-version}</version>
                    </dependency>
                    <dependency>
                        <groupid>org.eclipse.emf</groupid>
                        <artifactid>org.eclipse.emf.ecore.xcore.lib</artifactid>
                        <version>${ecore-xcore-lib-version}</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
</project>

.gitignore

1
2
3
4
5
bin/*
target
emf-gen/*
xcore-gen/*
xtend-gen/*

DemoCamp Mars in Stuttgart: Great People, Talks, and Food

SpeakersWe had a nice DemoCamp in Stuttgart for Eclipse Mars Release train. About 50 people had a great time alongside great food.

The full agenda, including links to all slides, can be found in the Eclipse Wiki.

MatthiasThe first talk by Matthias Zimmermann showed the Business Application Framework Scout, especially the new features of Mars and the upcoming next release.

MartinAfterwards, Martin Schreiber presented their experience with Tycho and some practical solutions.

JinyingJinying Yu gave an overview of the CloudScale project. It analyzes, estimates and simulates the scalability of a software system, especially for moving it to a cloud service.

MarcoAfter some refreshments and discussions during the break, Marco Eilers impressed with an Xtend interpreter, including tracing between the input model of a transformation and the resulting model or text – in both directions!

MiroThe next talk by Miro Spönemann showed the current state of Xtext on the Web and in IntelliJ. As Miro is the lead developer of the Web variant, he could easily answer all questions in-depth.

HaraldFinally, Harald Mackamul gave an overview of the APP4MC project. They extend the findings of Amalthea project to multi- and many-core systems.

We finished the DemoCamp with more discussions, food, and beer.

I’d like to thank all the great speakers and the attendees for making this DemoCamp fun as ever.

Eclipse DemoCamp 2015 “Mars” at University Stuttgart Vaihingen on July 1st, 17:45 hrs

Right on the heels of this year’s Eclipse “Mars” release, we will again run a DemoCamp in Stuttgart. It will take place

on

Wednesday, July 1st, 2015
17:45 hrs

at

Stuttgart University in Stuttgart-Vaihingen
Informatik Building
Universitätsstraße 38
70569 Stuttgart
Room Hörsaal 38.03

Details around the DemoCamp can be found at
https://wiki.eclipse.org/Eclipse_DemoCamps_Mars_2015/Stuttgart

As usual, admission is free, but please register at the above URL to help us plan the event.

Demos will include

  • Eclipse Scout: What’s new with Mars
  • Maven Tycho in practice
  • Interpreting Xtend: How to do it and why
  • Xtext for other platforms – Integration in IntelliJ IDEA and web applications
  • CloudScale Method for Analysing Scalability, Elasticity and Effieciency Engineering
  • APP4MC – a new Eclipse project proposal

Meet the IoT, Dependency Management, the local Eclipse Community and more at the DemoCamp Luna in Stuttgart!

DemoCampStuttgartSmall
On July 2nd, the Eclipse DemoCamp for the Luna release train will take place at the Stuttgart University, Vaihingen campus. You will see demos on several Internet-of-Things projects, including HTML5 device UIs build with Franca, using MQTT and Paho to connect Webpages, and an extensible C for developing embedded software. In addition, there will be demos on modern software translation with Jabylon, Eclipse usability, and package dependency diagnosis. There will be plenty of time, food and drinks to get in touch with speakers and members of the local Eclipse Community in general.

Detailed information can be found at: https://wiki.eclipse.org/Eclipse_DemoCamps_Luna_2014/Stuttgart

Eclipse Demo Camp Kepler Stuttgart Retrospective

Welcome!

Welcome!

We had a great DemoCamp in Stuttgart. About sixty people crowded the room and welcomed every beverage the hotel could come up with.

The room just sufficed

The room just sufficed

Please refer to the Eclipse Wiki for abstracts, slides and additional links for all demos.

Andreas Sewe shows Hippie Code Completion

Andreas Sewe shows Hippie Code Completion

Andreas Sewe demonstrated Code Recommenders, including their newest feature called Hippie Code Completion. He explained the various ways Eclipse supports the developer with code proposals. After a quick recap of already available Code Recommenders features we saw how Hippie Code Completion collects code patterns live during input and distills proposals on the spot.

Jan Stamer on Eclipse Gemini

Jan Stamer on Eclipse Gemini

Jan Stamer gave an overview of Eclipse Gemini, the Eclipse implementation of OSGi Enterprise specification. He compared OSGi Enterprise to Java EE and showed implementation examples for database access, JPA, and dependency injection.

Dominik Obermaier connects anything via Eclipse Paho

Dominik Obermaier connects anything via Eclipse Paho

Dominik Obermaier swapped his slot with the Contracts for Java talk. He demonstrated Eclipse Paho, the umbrella project for machine-to-machine (M2M) protocols. He argued for MQTT as lightweight, low-bandwith, and fault-tolerant protocol suited for small systems. He implemented live a publisher and subscriber of MQTT messages within a few lines of code.

Sebastian Zarnekow in passion about Xtend

Sebastian Zarnekow in passion about Xtend

Sebastian Zarnekow demonstrated Xtend, aka Java on steroids. He began by writing a simple list processing example in Java style. Step by step, he refactored the code using Xtend features, thus becoming far more concise and readable. Finally, he gave a crash course on one of Xtend’s newest features, Active Annotations: Sebastian live developed an Annotation to enable logging on any class.

I had been warned that once we opened the windows, the air conditioning would shut down. After stepping outside and back into the room, I decided in favor of at least some oxygen, taking the risk on the air conditioning. Unfortunately, the warning came true, and we had an increasingly hot second term.

Andreas Graf shows a dozen Eclipse projects combined to allow Function Oriented Development

Andreas Graf shows a dozen Eclipse projects combined to allow Function Oriented Development

Andreas Graf demonstrated the current state of an automotive research project. As an example, he picked the seemingly simple car function of start-stop system to save fuel at a traffic light. He explaind how this function concerns lots of different car subsystems. Most likely, they are provided by different external suppliers and managed by different internal departments. The research project IMES combines lots of Open Source and some commercial Eclipse based projects to tackle this complexity. Andreas showed this combination to enable advanced concepts like traceability, feature and variant modelling, and impact analysis.

Hagen Buchwald explains Stefan Schürle's demonstration of Contracts for Java

Hagen Buchwald explains Stefan Schürle’s demonstration of Contracts for Java

Stefan Schürle stood in for Florian Meyerer to demonstrate Contracts for Java together with Hagen Buchwald. Hagen started by explaining the basic ideas of contracts. Every step Hagen explained, Stefan implemented within the C4J framework. The demo application provided a student’s bank account, guarded by contracts to disallow debit.

Timo Kehrer explains SiLift

Timo Kehrer explains SiLift

Timo Kehrer explained SiLift, the Eclipse implementation of his concept how to compare/merge models on a meaningful level. He focused on edit operations as basic blocks rather than model modifications. Timo illustrated how SiLift can detect the changes of some edit operations automatically; more complex examples need to be described by the developer. He spent quite some time on putting the concept into usable tools.

Sorry Ed, I forgot to take a picture (-:

Sorry Ed, I forgot to take a picture (-:

Ed Merks concluded the sessions with his “first non-modelling talk in the last ten years”, as he put it. He told about his experience on improving Java performance in two customer projects. He learned not to trust anything and to be paranoid about common knowledge, each and any measurement, experts, and even oneself. He showed how to establish some baseline by looking for the quickest action one environment can measure (limited by timer resolution) and the fastest operations a JVM is capable. On this baseline, he wrote a simple framework to work on more complex cases. The extended slides offer much more detail than Ed was able to squeeze into the 20 minute slot.

After more than three hours of new and exciting ideas, combined with a jungle-like climate in the room, both the speakers and the audience rushed for the buffet and more cool drinks. We had a relaxed evening with lots of interesting discussions, leaving the premises just about midnight.

My special thanks go to all the speakers, arriving from all over Germany on their own expenses to show us their Cool Stuff™.

I appreciate all our guests participating in the DemoCamp and the survey we sent. We got more than 50 per cent response rate — thank you! The survey resulted in a favor for short slots in English. The demo vs. presentation question came out more closely, with advantage for a mixed program.