Meshing Acceleo with Xtext - eclipse

I am in the middle of an Acceleo Transformation aimed at producing code (i.e. Java) from an input UML model.
Some elements of this UML model (i.e. Activities Opaque actions) contain some text which is conform to an Xtext grammar and I'd like to get the equivalent AST Ecore representation in the Acceleo transformation.
To this end I have developed a Java class with a method which takes as input a string, containing the DSL excerpt, and produces an Ecore model conform to it (see http://www.eclipse.org/forums/index.php/m/901947/#msg_901947 for further details). I have tested it in a separate Java application and it seems it works properly.
I have therefore written a simple Acceleo module (i.e. getDSLModel) wrapping that java class and enabling me to get the Ecore model from the DSL textual representation.
Suppose my DSL (and the equivalent Ecore) consist of a root element named DSLModel containing a (0..*) number of DSLStatements (this is a simplification).
When in Acceleo I invoke the wrapper from a string, containing a correct DSL script, I have noticed it correctly returns a ModelImpl.
['statement1;statement2'.getDSLModel()/]
so the Java service and the Xtext parse is working.
However if I try to get the model statements, i.e.:
['statement1;statement2'.getDSLModel().statements/]
it returns an "invalid" string. So I can't use it in a for loop
I have therefore tried to call the eAllContents() OCL service from the model instance i.e.:
['statement1;statement2'.getDSLModel().eAllContents()/]
and it actually returns the list of statements. I do not understand why the features of the Ecore entities returned from the Xtext parser are not working properly.
Here is the Java service which turns a string into a instance of my DSL model (Ecore AST). I have tested it with an independent Java application and it works fine!
public class GetDSLModel {
public DSLModel getDSLModel(String expression){
DSLStandaloneSetupGenerated dslsas = new DSLStandaloneSetupGenerated();
Injector injector = dslsas.createInjectorAndDoEMFRegistration();
XtextResourceSet resourceSet = injector.getInstance(XtextResourceSet.class);
resourceSet.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE);
Resource resource = resourceSet.createResource(URI.createURI("dummy:/example.dsl"));
InputStream in = new ByteArrayInputStream(expression.getBytes());
try {
resource.load(in, resourceSet.getLoadOptions());
DSLModel model = (DSLModel) resource.getContents().get(0);
return model;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
Now I need the AST in the main Acceleo (UML2Text) transformation thus here is the Acceleo wrapper
[query public getDSLModel(str:String): DSLModel = (invoke('sfg.baleno.src.mloaders.GetDSLModel','getDSLModel(java.lang.String)',Sequence{str})).oclAsType(DSLModel)/]
here is what I get if run it
input: ['statement1;statement2'.getDSLModel()/]
output: mypackage.dsl.impl.DSLModelImpl#a1c7a
input: ['statement1;statement2'.getDSLModel().statements/] (Syntactically VALID)
output: invalid
input: ['statement1;statement2'.getDSLModel().eAllContents()/]
output: mypackage.dsl.impl.DSLStatement#e53202 (......
UPDATE
To the Java Class of the main Acceleo module I have added the following lines
#Override
public void initialize(EObject element, File folder, java.util.List<? extends Object> arguments) throws IOException { preInitialize();
super.initialize(element, folder, arguments);
}
#Override
public void initialize(URI modelURI, File folder, java.util.List<?> arguments) throws IOException {
preInitialize();
super.initialize(modelURI, folder, arguments);
}
protected void preInitialize() {
DSLStandaloneSetup.doSetup();
}
and
#Override
public void registerPackages(ResourceSet resourceSet) {
super.registerPackages(resourceSet);
if (!isInWorkspace(org.eclipse.uml2.uml.UMLPackage.class)) {
resourceSet.getPackageRegistry().put(org.eclipse.uml2.uml.UMLPackage.eINSTANCE.getNsURI(), org.eclipse.uml2.uml.UMLPackage.eINSTANCE);
}
if (!isInWorkspace(mypackages.DSLPackage.class)) {
resourceSet.getPackageRegistry().put(mypackages.DSLPackage.eINSTANCE.getNsURI(), mypackages.DSLPackage.eINSTANCE);
}
EcoreUtil.resolveAll(resourceSet);
}
but it still behaves the same.
UPDATE
At this link you temporary find a zipped file of an example EMF workspace containing an Acceleo and a XText project reproducing the issue. The weird thing is that if you run it as a Java application it works but if you run it as an Acceleo application it does not...
https://docs.google.com/open?id=0B2_ovo8IiZaZaXdNdFdPMTI4Yjg
In the top left corner you should find a File menu from which you can download the zip file.

I am unfortunately not that familiar with Xtext ... but I believe your problem lies in the way you load your dsl from within the java service : you are generating in the context of a running Eclipse ("acceleo application"), yet you load your model as if you were in standalone : new DSLStandaloneSetup, createInjector...
I believe that this way of loading your model gives you two instances of the Xtext metamodels and factories, making OCL fails to retrieve the feature "statements" when you try to obtain its values.
One possible way I can think of to bypass this would be to change your service to take an EObject of any sort as parameter and use its resource set to load your dsl (thus using the resource set you've initialized in the launcher, the one Acceleo uses, instead of your own) :
public DSLModel getDSLModel(String expression, EObject eObj){
ResourceSet rSet = eObj.eResource().getResourceSet();
[...]
}
With that, you should not need the second Xtext initialization you do from the service ... If it does not work tough, I don't really have a solution to propose other than to go to the Xtext forums and ask there how to make an application that can load a DSL and work both in standalone and in a pluginized environment.

Related

Eclipse plugin development - e4 part with input: instantiate input

Eclipse 4 does not have any notion of an editor, only parts. So how do we receive the file for our "editor" parts? I'm talking about an e4 equivalent of the IEditorPart.init method, and the IEditorInput it receives.
I've stumbled upon this example by Tom Schindl. He is able to inject the input in the part constructor. For the input object to be available for injection, it has to be instantiated in the IEclipseContext somehow. This article refers to Schindl's example, and leads me to consider the following approach: intercept "Open file" commands (if they exist) from the Eclipse platform, create an input instance for the "editor" part and put it in the context (IEcpliseContext.set(class, value)), and open the part with the EPartService.
So the question is: is this the right approach to creating an e4 "editor"? And is it possible to implement?
It is easier to put the input data in the part's transient data since it is tricky to get the data injected at the right point.
For something that behaves like an editor you will probably use a Part Descriptor so that you can create multiple parts from the single descriptor.
You would create the part using something like:
#Inject
EPartService partService;
// Create from part descriptor
MPart part = partService.createPart("part descriptor id");
// Set input in transient data
part.getTransientData().put("inputKey", inputData);
// Add to part stack
MPartStack partStack = ... stack you want to use
partStack.getChildren().add(part);
// Show
partService.showPart(part, PartState.ACTIVATE);
In your part code you get the transient data by injecting the MPart. For example in the constructur:
#Inject
public MyClass(MPart myPart)
{
Object input = part.getTransientData().get("inputKey");
....
}

EMF NotSerializableException

I build application in Java using EMF.
I use Java8 JDK.
All I need is persist instance of my model's class.
I run the code in debug mode on WildFly 10 server, remotely from Eclipse.
private String getXml(Audit audit) throws NeoflexException {
XMLResource res = new XMLResourceImpl();
res.getContents().add(audit);
StringWriter sw = new StringWriter();
try {
res.save(sw, null);
} catch (IOException e) {
throw new NeoflexException(e);
}
return sw.toString();
}
On serialization I get a NotSerializableException.
I see that generated Audit class isn't marked as Serializable.
I can not edit generated code, how ever, I also don't have option to mark this class in diagram as serializable.
As described here: https://www.eclipse.org/forums/index.php/t/261475/
I need to create an interface and derive it from serializable, but I don't have such option. See screenshot attached.
In general, EMF serializability is not bound to the ISerializable interface, but a containment hierarchy formed between the model elements. Furthermore, you should not make EMF interfaces extend the ISerializable inferface at all, as it is misleading (EMF model objects are not supposed to be serializable using the basic Java serialization).
Basically, the instances of your classes should for a containment tree: one object should be the root of the tree, and all other instances should be contained in it. Then you could save this entire containment hierarchy into a file by adding the model root into the resource.
Without knowing the concrete error message in the exception, my first tip would be to check whether the Audit element references some other model element, because if that element is referenced in a non-containment relation, than the serialization will fail.
To set a relation containment, edit your metamodel (Audit.ecore file) and set the property called containment true for the reference. However, you have to make sure that the containment subtree can be set up correctly: there is only a single model root element; all other elements can be reached by exactly one path of containment references from the model root. If an element is referenced by a cross-reference, it must also be included in the containment hierarchy in order for the EMF serialization (Resource.save) to work.
A further issue I see that you create the EMF Resource file manually, without any URI (that determines where you want to save your model) and without any resourceset (that is used to split your models into multiple files/resources with separate containment hierarchies).
In other words, you should create a ResourceSet instance, and use that to create your model Resource instances.
For more details, I suggest to check the basic and serialization specific tutorial at vogella.com.

Is it possible to use CDI interceptor to intercept method invocation from an Entity?

Team lead wants to writing some business methods inside of Entity class, such as following:
#Entity
public class SomeProcess extends SomeProcessBase implements Serializable {
#SomeInterceptor
public void start() {
//do some business logics
}
#SomeInterceptor
public void abort() {
// do some business logics
}
...
}
Can we use CDI interceptor mechanism to intercept non-contextual entity objects?
The answer is NO.
And the next direction for this is moving to BCEL.
After a few days study, i finally finished with BCEL to achieve method intercepting.
Rough Solution:
1. Using java instrument framework to transform byte code at class load time. Click Reference.
2. Transform byte code with a bytecode manipulation lib, such as ASM, Javassist, or BCEL. While transforming bytecode, manually writing target java file, and using some tool class provided by those libs to generate java code which can create byte codes from the target class file, after some encapsulation and boxing-and-unboxing and etc, then transform byte code part would be ready. BCEL provides BCELifier class to generate those java code, and the bytecode manipulation also mentioned some other tools for the other libs.
3. Try Lifecycle open source project on github.com, which provides Java based Lifecycle description language, it's kind of using Java to describe UML state machine with meta-driven style. And for method intercepting, please refer to BCELClassFileTransformer.java
4. Contact me for more help.

custom code generation in xtext

I am using Xtext do define a new language. I wish to generate code from this language, however I do not want to use the automatically suggested doGenerate function. Instead, I need to use a java code (not Xtend), that I can call from the build process.
Of course in that java code I want to be able to use the 'resource' that is passed to the original suggested function, so I can access all the information from the DSL's code.
I Believe by default the generator is implementation is an xtend file but there is nothing stopping you from changing this to a java file, you just need to override the binding in your [LanguageName]RuntimeModule class as follows:-
public class ExampleRuntimeModule extends com.example.AbstractExampleRuntimeModule {
#Override
public Class<? extends IGenerator> bindIGenerator() {
return YourOwnGenerator.class;
}
}
Where YourOwnGenerator should implement IGenerator.

GWT Dynamic loading using GWT.create() with String literals instead of Class literals

GWT.create() is the reflection equivalent in GWT,
But it take only class literals, not fully qualified String for the Class name.
How do i dynamically create classes with Strings using GWT.create()?
Its not possible according to many GWT forum posts but how is it being done in frameworks like Rocket-GWT (http://code.google.com/p/rocket-gwt/wiki/Ioc) and Gwittir (http://code.google.com/p/gwittir/wiki/Introspection)
It is possible, albeit tricky. Here are the gory details:
If you only think as GWT as a straight Java to JS, it would not work. However, if you consider Generators - Special classes with your GWT compiler Compiles and Executes during compilation, it is possible. Thus, you can generate java source while even compiling.
I had this need today - Our system deals with Dynamic resources off a Service, ending into a String and a need for a class. Here is the solutuion I've came up with - btw, it works under hosted, IE and Firefox.
Create a GWT Module declaring:
A source path
A Generator (which should be kept OUTSIDE the package of the GWT Module source path)
An interface replacement (it will inject the Generated class instead of the interface)
Inside that package, create a Marker interface (i call that Constructable). The Generator will lookup for that Marker
Create a base abstract class to hold that factory. I do this in order to ease on the generated source code
Declare that module inheriting on your Application.gwt.xml
Some notes:
Key to understanding is around the concept of generators;
In order to ease, the Abstract base class came in handy.
Also, understand that there is name mandling into the generated .js source and even the generated Java source
Remember the Generator outputs java files
GWT.create needs some reference to the .class file. Your generator output might do that, as long as it is referenced somehow from your application (check Application.gwt.xml inherits your module, which also replaces an interface with the generator your Application.gwt.xml declares)
Wrap the GWT.create call inside a factory method/singleton, and also under GWT.isClient()
It is a very good idea to also wrap your code-class-loading-calls around a GWT.runAsync, as it might need to trigger a module load. This is VERY important.
I hope to post the source code soon. Cross your fingers. :)
Brian,
The problem is GWT.create doen't know how to pick up the right implementation for your abstract class
I had the similar problem with the new GWT MVP coding style
( see GWT MVP documentation )
When I called:
ClientFactory clientFactory = GWT.create(ClientFactory.class);
I was getting the same error:
Deferred binding result type 'com.test.mywebapp.client.ClientFactory' should not be abstract
All I had to do was to go add the following lines to my MyWebapp.gwt.xml file:
<!-- Use ClientFactoryImpl by default -->
<replace-with class="com.test.mywebapp.client.ClientFactoryImpl">
<when-type-is class="com.test.mywebapp.client.ClientFactory"/>
</replace-with>
Then it works like a charm
I ran into this today and figured out a solution. The questioner is essentially wanting to write a method such as:
public <T extends MyInterface> T create(Class<T> clz) {
return (T)GWT.create(clz);
}
Here MyInterface is simply a marker interface to define the range of classes I want to be able to dynamically generate. If you try to code the above, you will get an error. The trick is to define an "instantiator" such as:
public interface Instantiator {
public <T extends MyInterface> T create(Class<T> clz);
}
Now define a GWT deferred binding generator that returns an instance of the above. In the generator, query the TypeOracle to get all types of MyInterface and generate implementations for them just as you would for any other type:
e.g:
public class InstantiatorGenerator extends Generator {
public String generate(...) {
TypeOracle typeOracle = context.getTypeOracle();
JClassType myTYpe= typeOracle.findType(MyInterface.class.getName());
JClassType[] types = typeOracle.getTypes();
List<JClassType> myInterfaceTypes = Collections.createArrayList();
// Collect all my interface types.
for (JClassType type : types) {
if (type.isInterface() != null && type.isAssignableTo(myType)
&& type.equals(myType) == false) {
myInterfaceTypes.add(type);
}
for (JClassType nestedType : type.getNestedTypes()) {
if (nestedType.isInterface() != null && nestedType.isAssignableTo(myType)
&& nestedType.equals(myTYpe) == false) {
myInterfaceTypes.add(nestedType);
}
}
}
for (JClassType jClassType : myInterfaceTypes) {
MyInterfaceGenerator generator = new MyInterfaceGenerator();
generator.generate(logger, context, jClassType.getQualifiedSourceName());
}
}
// Other instantiator generation code for if () else if () .. constructs as
// explained below.
}
The MyIntefaceGenerator class is just like any other deferred binding generator. Except you call it directly within the above generator instead of via GWT.create. Once the generation of all known sub-types of MyInterface is done (when generating sub-types of MyInterface in the generator, make sure to make the classname have a unique pattern, such as MyInterface.class.getName() + "_MySpecialImpl"), simply create the Instantiator by again iterating through all known subtypes of MyInterface and creating a bunch of
if (clz.getName().equals(MySpecialDerivativeOfMyInterface)) { return (T) new MySpecialDerivativeOfMyInterface_MySpecialImpl();}
style of code. Lastly throw an exception so you can return a value in all cases.
Now where you'd call GWT.create(clz); instead do the following:
private static final Instantiator instantiator = GWT.create(Instantiator.class);
...
return instantiator.create(clz);
Also note that in your GWT module xml, you'll only define a generator for Instantiator, not for MyInterface generators:
<generate-with class="package.rebind.InstantiatorGenerator">
<when-type-assignable class="package.impl.Instantiator" />
</generate-with>
Bingo!
What exactly is the question - i am guessing you wish to pass parameters in addition to the class literal to a generator.
As you probably already know the class literal passed to GWT.create() is mostly a selector so that GWT can pick and execute a generator which in the end spits out a class. The easist way to pass a parameter to the generator is to use annotations in an interface and pass the interface.class to GWT.create(). Note of course the interface/class must extend the class literal passed into GWT.create().
class Selector{
}
#Annotation("string parameter...")
class WithParameter extends Selector{}
Selector instance = GWT.create( WithParameter.class )
Everything is possible..although may be difficult or even useless. As Jan has mentioned you should use a generator to do that. Basically you can create your interface the generator code which takes that interface and compile at creation time and gives you back the instance. An example could be:
//A marker interface
public interface Instantiable {
}
//What you will put in GWT.create
public interface ReflectionService {
public Instantiable newInstance(String className);
}
//gwt.xml, basically when GWT.create finds reflectionservice, use reflection generator
<generate-with class="...ReflectionGenerator" >
<when-type-assignable class="...ReflectionService" />
</generate-with>
//In not a client package
public class ReflectionGenerator extends Generator{
...
}
//A class you may instantiate
public class foo implements Instantiable{
}
//And in this way
ReflectionService service = GWT.create(ReflectionService.class);
service.newInstance("foo");
All you need to know is how to do the generator. I may tell you that at the end what you do in the generator is to create Java code in this fashion:
if ("clase1".equals(className)) return new clase1();
else if ("clase2".equals(className)) return new clase2();
...
At the final I thought, common I can do that by hand in a kind of InstanceFactory...
Best Regards
I was able to do what I think you're trying to do which is load a class and bind it to an event dynamically; I used a Generator to dynamically link the class to the event. I don't recommend it but here's an example if it helps:
http://francisshanahan.com/index.php/2010/a-simple-gwt-generator-example/
Not having looked through the code of rocket/gwittir (which you ought to do if you want to find out how they did it, it is opensource after all), i can only guess that they employ deferred binding in such a way that during compile time, they work out all calls to reflection, and statically generate all the code required to implement those call. So during run-time, you cant do different ones.
What you're trying to do is not possible in GWT.
While GWT does a good job of emulating Java at compile time the runtime is of course completely different. Most reflection is unsupported and it is not possible to generate or dynamically load classes at runtime.
I had a brief look into code for Gwittir and I think they are doing their "reflection stuff" at compile time. Here: http://code.google.com/p/gwittir/source/browse/trunk/gwittir-core/src/main/java/com/totsp/gwittir/rebind/beans/IntrospectorGenerator.java
You might be able to avoid the whole issue by doing it on the server side. Say with a service
witch takes String and returns some sort of a serializable super type.
On the server side you can do
return (MySerializableType)Class.forName("className").newInstance();
Depending on your circumstances it might not be a big performance bottleneck.