| chapter:AdvancedFeatures[Advanced Features] |
| |
| In this chapter we describe some advanced features. |
| |
| section:BuildingWithMaven[Building with Maven] |
| |
| We provide Maven artifacts in Maven Central that allows you to compile the Parsley DSL sources |
| with Maven/Tycho, using the e[xtext-maven-plugin]. |
| |
| This is a typical configuration (a complete example can be found here: |
| link[http://git.eclipse.org/c/emf-parsley/org.eclipse.emf-parsley.git/tree/examples/org.eclipse.emf.parsley.examples.maven][http://git.eclipse.org/c/emf-parsley/org.eclipse.emf-parsley.git/tree/examples/org.eclipse.emf.parsley.examples.maven]): |
| |
| code[ |
| <plugin> |
| <groupId>org.eclipse.xtext</groupId> |
| <artifactId>xtext-maven-plugin</artifactId> |
| <version>${xtext-version}</version> |
| <executions> |
| <execution> |
| <goals> |
| <goal>generate</goal> |
| </goals> |
| </execution> |
| </executions> |
| <configuration> |
| <languages> |
| <language> |
| <setup>org.eclipse.emf.parsley.dsl.EmfParsleyDslStandaloneSetup</setup> |
| <outputConfigurations> |
| <outputConfiguration> |
| <outputDirectory>${basedir}/emfparsley-gen</outputDirectory> |
| </outputConfiguration> |
| </outputConfigurations> |
| </language> |
| </languages> |
| </configuration> |
| <dependencies> |
| <dependency> |
| <groupId>org.eclipse.emf.parsley</groupId> |
| <artifactId>org.eclipse.emf.parsley.dsl.standalone</artifactId> |
| <version>${parsley-version}</version> |
| </dependency> |
| </dependencies> |
| </plugin> |
| ] |
| |
| section:Testing[Testing Framework] |
| |
| We provide some utility classes for testing e[EMF Parsley] components in the feature |
| "EMF Parsley Junit4 Support". By deriving from one of the abstract classes in our |
| testing bundle, you will be able to write tests that are meant to be run as Junit test, |
| that is to say, NOT as Plug-in Junit tests. Thus, you will not need a running Eclipse product |
| to execute such tests: they will be much faster. Indeed, many parts of Parsley can |
| be tested even without a running Eclipse. |
| |
| ul[ |
| item[codeRef[org.eclipse.emf.parsley.junit4.AbstractEmfParsleyTest]: this provides |
| a few utility methods, e.g., for creating an codeRef[com.google.inject.Injector].] |
| item[codeRef[org.eclipse.emf.parsley.junit4.AbstractEmfParsleyShellBasedTest]: this allows |
| to run Junit tests that require a codeRef[org.eclipse.swt.widgets.Display] and a |
| codeRef[org.eclipse.swt.widgets.Shell].] |
| item[codeRef[org.eclipse.emf.parsley.junit4.AbstractEmfParsleyControlBasedTest]: an extension |
| of the previous class for tests that also require databinding capabilities, e.g., |
| tests for codeRef[org.eclipse.swt.widgets.Control] elements; this provides many assert |
| methods for several kinds of controls, such as e[assertCheckbox], e[assertCombo], etc.] |
| ] |
| |
| We use these classes for testing most of our classes; you might want to have a look |
| at the project e[org.eclipse.emf.parsley.tests] for some usage examples. |
| |
| section:Eclipse4[Eclipse 4.x] |
| |
| Instead of using the Extension Point mechanism, EMF Parsley leverages from DSL and Google Guice Injection. |
| |
| Because of this, it is very easy to use it with Eclipse 4.x (e4). |
| |
| ol[] |
| |
| e[First Example Setup] |
| |
| If you followed the steps described in section ref:FirstExample[First Example] you will have already |
| what we need to begin. Otherwise the following wizard will bring you to that point. |
| |
| ol[ |
| item[File -> New... -> Example...] |
| item[from Category "EMF Parsley Examples", select "EMF Parsley First Example"] |
| item[press Next and Finish] |
| ] |
| |
| You will end up with three plug-ins: |
| |
| ul[ |
| item[org.eclipse.emf.parsley.examples.firstexample (the EMF Parsley example plug-in)] |
| item[org.eclipse.emf.examples.library (the model plug-in)] |
| item[org.eclipse.emf.examples.library.edit (the model.edit plug-in)] |
| ] |
| |
| As a reminder, in section ref:FirstExample[First Example] we reached the point where we launched a second Eclipse |
| instance (but, of course, just defining a product you could have a standalone 3.x application) with a |
| view (called "My Library Tree Form") that allowed to manage the model. |
| |
| ol[] |
| |
| e[Preparing for a pure e4 Application] |
| |
| What we will do now is starting from the previous step and create an e4 Application (on top of |
| the previous plug-ins) that gets to the same result, but now with a pure e4 Part. |
| |
| In order to do this we need to export the e["org.eclipse.emf.parsley.examples.firstexample"] package from the first plug-in. |
| |
| ol[] |
| |
| e[Create an e4 Application] |
| |
| Now let's create a new, empty, e4 application, e.g. e["org.eclipse.emf.parsley.examples.firstexample.application"] |
| (you can find details on how to create e4 applications in link[http://www.rcp-vision.com/?p=4694&lang=en][our |
| tutorials]). |
| |
| Create a Part and ensure that the application starts. |
| |
| ol[] |
| |
| e[Using a TreeComposite into an e4 Part] |
| |
| In the just created plug-in we need dependencies from the previous plug-ins: so open the e[org.eclipse.emf.parsley.examples.firstexample.application/MANIFEST.MF] file, go to e[Dependencies] |
| tab and add the three previous plug-ins. Add also e["org.eclipse.emf.parsley"] plug-in. |
| Don't forget to add the previous, and the required plug-ins, also to the Product. |
| |
| Open the Part java class and make the following changes: |
| |
| code[Java][ |
| // Use these imports during Organizing Imports operation |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.swt.widgets.Composite; |
| |
| // The part implements IMenuListener for context menu handling |
| public class MyEclipse4Part { |
| |
| //the EMF Parley composite for showing a tree and a detail form |
| private TreeFormComposite treeFormComposite; |
| //the EMF Resource |
| private Resource resource; |
| //URI for EMF Resource |
| private URI uri = URI.createFileURI(System.getProperty("user.home") |
| + "/MyLibrary.library"); |
| |
| ] |
| |
| |
| Modify the e[@PostConstruct] method with this code: |
| |
| code[Java][ |
| @PostConstruct |
| public void postConstruct(Composite parent) { |
| // Guice injector |
| private Injector injector = FirstexampleInjectorProvider.getInjector(); |
| |
| // The EditingDomain is needed for context menu and drag and drop |
| EditingDomain editingDomain = injector.getInstance(EditingDomain.class); |
| |
| ResourceLoader resourceLoader = injector.getInstance(ResourceLoader.class); |
| //load the resource |
| resource = resourceLoader.getResource(editingDomain, uri).getResource(); |
| |
| TreeFormFactory treeFormFactory = injector.getInstance(TreeFormFactory.class); |
| //create the tree-form composite |
| treeFormComposite = treeFormFactory.createTreeFormComposite(parent, SWT.BORDER); |
| |
| // Guice injected viewer context menu helper |
| ViewerContextMenuHelper contextMenuHelper = injector.getInstance(ViewerContextMenuHelper.class); |
| // Guice injected viewer drag and drop helper |
| ViewerDragAndDropHelper dragAndDropHelper = injector.getInstance(ViewerDragAndDropHelper.class); |
| |
| // set context menu and drag and drop |
| contextMenuHelper.addViewerContextMenu(treeFormComposite.getViewer(), editingDomain); |
| dragAndDropHelper.addDragAndDrop(treeFormComposite.getViewer(), editingDomain); |
| |
| //update the composite |
| treeFormComposite.update(resource); |
| } |
| ] |
| |
| The Google Guice Injector (not to be confused with the Eclipse e4 Injector) is retrieved |
| using the injector provider class generated by the DSL compiler |
| (see also ref:InjectorProvider[Obtaining the Injector]). |
| |
| If you now run the application you will be able to manage the model: |
| |
| img[images/07-eclipse4-part.png][][ ][] |
| |
| but you will notice that it is not possible to persist the changes to the model. |
| |
| ol[] |
| |
| e[Adding the dirty state and Save command] |
| |
| In order to allow persisting the model changes we have to add the dirty state handling to the part and |
| the Save command to the application. |
| Let's start with adding the following attribute to the part |
| |
| code[Java][ |
| @Inject |
| MDirtyable dirty; |
| ] |
| |
| add to e[@PostConstruct] method the following code in order to update the dirty state |
| |
| code[Java][ |
| editingDomain.getCommandStack().addCommandStackListener( |
| new CommandStackListener() { |
| public void commandStackChanged(EventObject event) { |
| if (dirty != null) |
| dirty.setDirty(true); |
| } |
| }); |
| ] |
| |
| and add the e[@Persist] method, which will be called when the part is saved |
| |
| code[Java][ |
| @Persist |
| public void save(MDirtyable dirty) throws IOException { |
| resource.save(null); |
| if (dirty != null) { |
| dirty.setDirty(false); |
| } |
| } |
| ] |
| |
| and, in the end, add the e[Save] handler along with the correspondent e[Command] and e[Menu] |
| (you can find how to create handlers, commands and menus in an e4 applications in link[http://www.rcp-vision.com/?p=4972&lang=en][our |
| tutorials]) |
| |
| code[Java][ |
| import javax.inject.Named; |
| |
| public class SaveHandler { |
| |
| @Execute |
| void execute(EPartService partService, @Named(IServiceConstants.ACTIVE_PART) MPart part) { |
| partService.savePart(part, false); |
| } |
| } |
| ] |
| |
| section:RAP[RAP] |
| |
| As you may know link[http://eclipse.org/rap/][RAP (Remote Application Platform)] is a technology that allows you to run an Eclipse RCP application over the web. |
| |
| In order to obtain this goal you have to setup a specific RAP Target Platform, for instance the one that RAP itself provides once you install it. |
| |
| However when you want to use an Eclipse RCP framework over the RAP Platform, you generally have to deal with |
| dependencies, since not all Eclipse frameworks are ready-to-use with RAP, especially those related with the SWT layer. |
| |
| EMF Parsley provides a proper RAP Target Platform that allows you to start leveraging Parsley potentials to the web the same way you have |
| learned to do with desktop (RCP) development. |
| |
| ol[] |
| |
| e[Installing the RAP Tools] |
| |
| To begin with, you need to install the RAP Tools into the IDE. |
| This can be accomplished with the following steps: |
| ol[ |
| item[Help -> Install New Software ...] |
| item[select the main Eclipse Update site] |
| item[expand category "Web, XML, Java EE and OSGi Enterprise Development"] |
| item[select "RAP Tools" and complete the installation, restarting the IDE at the end] |
| item[after IDE restarts just close the Welcome page] |
| ] |
| |
| |
| ol[] |
| |
| e[Setup the EMF Parsley RAP Target Platform] |
| |
| After having installed EMF Parsley as described link[https://www.eclipse.org/emf-parsley/download.html][here] and |
| created a new workspace, you can setup the EMF Parsley RAP Target Platform in the following way: |
| ol[ |
| item[File -> New... -> Example...] |
| item[from Category "EMF Parsley Examples", select "EMF Parsley RAP Target Platform Example"] |
| item[press Next and Finish] |
| item[open the Target Definition file e[emf-parsely-rap.target]] |
| item[wait until the "Resolving Target Definition" job is done (check the status bar)] |
| item[when finished, click on hyperlink "Set as Target Platform"] |
| ] |
| |
| You will end up with a RAP-enabled workspace, enhanced by EMF and Parsley! |
| |
| |
| ol[] |
| |
| e[Running the Parsley RAP UI Example] |
| |
| Here is the fastest way to get a working web application with all the stuff put togheter: |
| ol[ |
| item[File -> New... -> Example...] |
| item[from Category "EMF Parsley Examples", select "EMF Parsley RAP Example"] |
| item[press Next and Finish] |
| item[expand plug-in e["org.eclipse.emf.parsley.examples.rap.ui"]] |
| item[right-click "Emf_Parsley_RAP_UI_Example.launch" and click "Run as" "Emf_Parsley_RAP_UI_Example"] |
| ] |
| |
| What you will get is a web application that allows you to interact with the model instance as you would |
| do in a desktop (RCP) environment. |
| |
| img[images/08-rap-ui-example-running.png][][ ][] |
| |
| In this web application you can see two views: |
| ul[ |
| item[the one on the left is a read-only view; it just reflects the model content, but it does not react to changes (the classic Eclipse dirty indicator is not triggered |
| by changes) and you are not able to save. Its model is created in class e[org.eclipse.emf.parsley.examples.rap.ui.GuiceModule.CustomResourceManager] |
| and is not persisted] |
| item[the view on the right is instead a Saveable view and therefore it not only triggers the dirty state after |
| a change, but also allows you to save the modifications with the automatic dirty state reset. Its model |
| is persisted in file e[System.getProperty("java.io.tmpdir")+"/My.model")] ] |
| ] |
| |
| Of course, since this is a web application, you can also open a browser on another pc or device on the same network and type the address, |
| replacing 127.0.0.1 with the IP of the machine where the application was launched. |
| |
| ol[] |
| |
| e[Running the Parsley RAP CDO Example] |
| |
| The EMF default XMI persistence is certainly very handy to start with, but as soon as you want a more |
| production-ready EMF persistence architecture, well, link[http://wiki.eclipse.org/CDO][CDO] is for sure the way to go. |
| In fact with CDO you basically have an EMF model instance shared between clients, that also allows the |
| clients to be synchronized with the model changes. |
| |
| |
| In this example, in order to keep things simple, we will use CDO with an in-memory store (MEMStore) whose contents will be lost once the server is stopped. |
| However CDO can be configured for usage with RDBMS, Object-oriented or NO-SQL databases (see link[http://eclipse.org/cdo/documentation/][here] for details) |
| |
| |
| To start with we need a CDO Server running and we can obtain it with an example plugin that can be used |
| both in an RCP and in a RAP workspace. |
| |
| ol[ |
| item[File -> New... -> Example...] |
| item[from Category "EMF Parsley Examples", select "EMF Parsley CDO Server Example"] |
| item[press Next and Finish] |
| item[expand plug-in e["org.eclipse.emf.parsley.examples.cdo.server"]] |
| item[right-click "CDOServerExample.launch" and click "Run as" "CDOServerExample"] |
| item[a message on the Console e["Repository\[demo\] started!"] informs that the CDO Server instance |
| is started!] |
| ] |
| |
| Now we can create the web application that will use the CDO server just started. |
| |
| ol[ |
| item[File -> New... -> Example...] |
| item[from Category "EMF Parsley Examples", select "EMF Parsley RAP CDO Example"] |
| item[press Next and Finish] |
| ] |
| |
| The plug-in projects created are: |
| |
| ul[ |
| item[the Model (org.eclipse.emf.parsley.examples.cdo.model)] |
| item[a Parsley plug-in with a TreeForm (org.eclipse.emf.parsley.examples.cdo.treeform)] |
| item[the webapp (org.eclipse.emf.parsley.examples.cdo.rap)] |
| ] |
| |
| Then let's start the application |
| |
| ol[ |
| item[expand plug-in e["org.eclipse.emf.parsley.examples.cdo.rap"]] |
| item[right-click "EMF-Parsley_Library_RAP.launch" and click "Run as" "EMF-Parsley_Library_RAP"] |
| ] |
| |
| If you happen to see this |
| |
| img[images/08-rap-refresh.png][][ ][] |
| |
| just press the refresh button and should see the following |
| |
| img[images/08-rap-cdo-1.png][][ ][] |
| |
| Now feel free to open the same address from more browsers window (yes, on different machines or devices, possibly) |
| and see the power of this technology stack at work! |
| |
| img[images/08-rap-cdo-2.png][][ ][] |
| |
| |
| |
| |