Spray Developer Guide
2
Spray – A quick way of creating Graphiti
Developer Guide
Authors: Jos Warmer, Karsten Thoms, Joerg Reichert
Contents
1. Spray - A quick way of creating Graphiti1. Target Runtime Framework2. Reference Implementation3. Framework Development4. Language Development5. Code Generation6. Testing7. User Interface
2. Setting up the developer environment1. Source Control2. Developer IDE
1. Prebuild IDE2. Manual Feature Installation3. Installing through P2 director launch config4. Troubleshooting
3. Workspace Setup1. Target Platform2. Team Project Set3. Initial Build4. Workspace Preferences5. Add Spray task repository to Eclipse6. Add Spray Jenkins connector to Eclipse7. Add Spray Git repository to Eclipse
4. Target Platform3. The Spray DSL Infrastructure
1. Postprocessed generated Ecore Metamodels4. Spray Generator
1. Reference Implementation2. Indentation3. Import Organizing4. Modularity
1. Template Methods2. Hook Templates3. Generated Code
5. Code Documentation1. Overridden Methods
5. Graphiti
3
6. Project Setup1. Naming2. Source Management3. Adding a new Plugin project
1. Manifest2. build.properties3. Project Specific Settings4. Build5. Project Set
4. Dependency Management1. Imported Packages2. Allowed dependencies
5. Plugin Development1. plugin.xml
7. Build Management1. Built within Eclipse
1. Generate DSL implementation2. Build documentation
2. Spray Maven Build1. Maven @settings.xml@2. Build Spray projects3. Build target platform repository4. Disable execution of UI tests
3. Parent POM1. Plugin Management
4. Profiles1. Repository selection profiles2. Modules selection profiles3. Static code analysis profiles
5. Version management1. Setting Spray version2. Setting Xtext version
8. Continuous Integration1. Introduction2. Build Jobs
1. Job @spray-ci-build@2. Job @spray-docs-build@3. Job @spray-ci-targetplatform@4. Job @spray-distrobuilder@5. Job @spray-ci-experimental@
3. Job configuration1. Headless UI tests
4. Administration9. Release Process
1. Distrobuilder10.Testing
1. Test Projects2. Test aspects
1. Testing using the Spray DSL Editor enviroment2. Testing the generated Graphiti editor
3. Test approaches1. JUnit tests2. Mocking3. Xtext tests4. JUnit plug-in tests
4
5. UI tests6. Measuring test coverage7. Test data organization8. Generator template tests
4. Spray Language Tests5. Runtime Tests
11.Code quality1. Code coverage2. SonarQube
12.Examples1. Established examples
1. Business Model (Mod4j)2. Heat Exchanger (LWC 2012)3. BPMN 2.04. Petri Nets
2. Examples in early state1. Forms2. Statemachine (Fowler DSL)3. Nassi-Shneiderman-Diagram4. Feature Modeling
3. Examples only for testing1. Containment2. Goals
4. Ideas for future example projects1. Taipan2. Mindmap3. Game Of Life4. Chess5. Component diagram6. Sequence diagram7. Floor plan
13.Issue Tracking1. Tracking System2. Git Commit Message
14.Requirements Engineering15.Troubleshooting
1. Moved classes not visible in runtime workspace16.How To
1. Dependencies2. Update Maven plugin versions3. Resolve "Discouraged access" warnings4. Target Platform
1. Updating .target files5. Release Management
1. Release Script2. Custom Ant Tasks3. File upload to Google Code4. Setting version5. Dry run6. Roll back7. Maven repositories
5
General rules for designing Spray
Target Runtime Framework
The target graphical modeling framework of Spray is Graphiti. Though other runtimes might be possible to describewith the DSLs, this is not the primary goal.
Reference Implementation
All proposed features that should be covered by code generation must be also covered by ReferenceImplementation code. This reference code must be developed in a way that it can be fully generated fromReference Models.
The quality of this reference code is crucial.
Framework Development
Although Graphiti has already a strong API it will be necessary to create framework classes also for Spray. TheSpray framework API should be developed in a way that it will be potentially proposed to Graphiti as enhancementrequests.
The framework layer of Spray should be as small as possible and as large as required.
Language Development
The DSLs developed in Spray should follow best practices in Language Design.
• Keep it simple: creating a simple Graphiti editor should be straightforward and quick to do• More advanced features may not break the previous rule. They should be additive in the sense that you won’t
see them if yo don’t need them.• The Spray DSL does not need to enable everything possible with Graphiti. For advanced features, users will
always be able to directly use the Graphiti API and combine such handwritten code with generated code.• If a language is hard to parse it is also likely hard to understand.• Separation of concerns: If different concerns must be described in a DSL, it might require different DSLs
Code Generation
• Code Generator is designed to enable mixing generated code with handwritten code without losing thepossibility for code generation.
• Code Generator uses the generation gap pattern to give maximum flexibility to mix handwritten code withgenerated code.
• The Code Generator must be executable standalone (Maven, Ant, Commandline) without an Eclipse installation• The Code Generator should be extensible by the user without the need to change the original plugin sources
Testing
All features of the DSLs will be covered by models that will be tested by unit tests.
User Interface
• The UI should help the user to do common actions
6
Setting up the developer environment
Source Control
We are using Git as source management system. The primary repository location is: https://code.google.com/a/eclipselabs.org/p/spray/
See http://code.google.com/a/eclipselabs.org/p/spray/source/checkout for details.
You can new clone Git from the command line or use Eclipse, which is explained in a later section of this guide.
Developer IDE
Prebuild IDE
Spray provides an Eclipse distribution with all features that are required to develop Spray. Downloadthe distribution for your operating system here: https://spray.ci.cloudbees.com/job/spray-distrobuilder/lastSuccessfulBuild/artifact/devtools/org.eclipselabs.spray.dev.distrobuilder/target/dist
The IDE contains the following features:
• Eclipse Platform• Eclipse SDK• PDE
• Collaboration Tools• EGit - Eclipse team provider for Git• Mylyn• Mylyn Connector for Google Code• Workspace Mechanic• Mylyn WikiText
• Software Build• Maven Integration for Eclipse (m2e)• Mylyn Builds
• Eclipse Modeling• EMF – Eclipse Modeling Framework• Xtext• Xtend• Xtext Antlr• Graphiti• Zest SDK• MWE – Modeling Workflow Engine• MWE2
• Testing Tools• SWT Bot• xtext-utils unittesting• Xpect
• Quality Assurance Tools• EclEmma Java Code Coverage• Copyright Wizard
• UI Builder• SWT Designer• Window Builder
Manual Feature Installation
If you wish to install the Spray IDE features onto your existing Eclipse installation, configure the required updatesites and install the features mentioned above. The update sites used to install the features required to develop
7
Spray can be imported in your IDE. As a base take any Eclipse 4.x distribution. Then open workspace preferencesInstall / Update -> Available Software Site and click the Import button. When you already cloned the Sprayrepository, then choose the file
<path to your locally cloned Spray Git repository>/org.eclipselabs.spray.devenv/updatesites-spray-dev.xml
otherwise import the file from the CI server:
https://spray.ci.cloudbees.com/job/spray-ci-build/lastSuccessfulBuild/artifact/devtools/org.eclipselabs.spray.devenv/updatesites-spray-dev.xml
This XML file will add all required update sites to visit later when installing the plug-ins for the developmentenvironment.
Now install the features with the Eclipse Update Manager (Help -> Install New Software).
Installing through P2 director launch config
For convenience there is a launch config install-devenv-4.2.launch in project org.eclipselabs.spray.devenv.Right-click this launch config, then choose Run As / install-devenv-4.2. Choose the base directory of your Eclipse4.2 installation. You must not start the config from the Eclipse instance you want to update, take any other Eclipse.
Troubleshooting
If you have already installed one of the above mentioned features you might experience problems installing thenewer features. In this case uninstall the features in question before (Eclipse / About Eclipse / Installation Details /Installed Software -> Uninstall).
For example, if you need to upgrade Xtext, uninstall all Xtext features, and the install Xtext SDK again with InstallNew Software.
Workspace Setup
Target Platform
For plugin development it is important to work against a fixed set of plugins. While the IDE provides a good default,since it is build from the defined features in the required versions, the actual target platform may differ slightly.
Spray maintains two Target Definitions (.target files), which can be found in the releng/org.eclipselabs.spray.targetplatform project:
• spray-<EclipseMainRelease>.target: (<EclipseMainRelease> currently is @kepler) Definesthe target platform against the remote repositories where the required features are hosted. While it should itperfectly valid to use this target definition, it takes more time to resolve the plugins from the repositories. Alsothis target definition might break when the referenced repositories do not contain the listed feature versionsanymore. This happens with features that are build frequently. Especially when the main Eclipse release isclose the target changes often.
• spray-ci.target: (Recommended) Using the target definition mentioned above Spray builds a dedicatedtarget platform repository on the Cloudbees Jenkins server. This repository stays consistent until the repositoryis rebuild using an updated target. For developers it is usually the right Target Platform to use.
Open the preferences and set „Spray CI Target” in Plug-in Development / Target Platform.
8
Team Project Set
You can use our predefined team project set file to get the Spray projects into your workspace. This willautomatically clone the Git repository and mport the projects.
• File > Import... > Team/Team Project Set, Next• URL: http://spray.eclipselabs.org.codespot.com/git/devtools/
org.eclipselabs.spray.devenv/projectSet.psf, Finish
When creating a new workspace make sure to set the following settings:
Initial Build
When the projects are checked out initially, several projects will not be compilable. This is because the projectsrequire generated sources, which are not checked in. To trigger the generation we make a full build. Runthe launch configuration releng/org.eclipselabs.spray.distribution/launch/spray builddefault.launch or on the command line in project org.eclipselabs.spray.distribution call "mvnclean install -s settings.xml".
Workspace Preferences
The Workspace Mechanic is a useful tool to manage common preferences for setting up workspaces.It basically scans configured directories for preference files (*.epf). These settings are provided in theorg.eclipselabs.spray.devenv project.
To configure the settings directory open the Workspace Preferences and go to Workspace Mechanic. On thepreference page, add a new task source. Take the absolute path to the org.eclipselabs.spray.devenv/preferences directory.
9
After closing the preferences dialog the Workspace Mechanic will scan the configuration from the devenv directory.A hover dialog will pop up in the bottom right corner and remind to you to fix the workspace setup.
Click on „View and correct configuration issues” and fix the setup.
In org.eclipselabs.spray.devenv there is a Java formatter configuration formatter.xml used in thisproject.Apply this formatter before committing anything.
Add Spray task repository to Eclipse
• Window > Show View > Other... > Mylyn/Task Repositories• Open context menu in Task Repositories view > Add task repositories...• Google Code, Next
• URL: Paste http://code.google.com/a/eclipselabs.org/p/spray/• Label: Spray• unselect Anonymous, if you later want to push code• enter your Google Account credentials (now use as password your Google Mail password, not the Google
Code Password), Finish
10
• Add New Query• use predefined query > Open issues
11
• Window > Show View > Other... > Mylyn/Task List
Add Spray Jenkins connector to Eclipse
• Window > Show View > Other... > Mylyn/Builds• Click on the first of the icons in the right of the view header > Hudson (supports Jenkins), Next
• Server: https://spray.ci.cloudbees.com• Label: Spray• select Anonymous• click on Refresh button• select job "spray-ci-build"• Finish
• click on spray-ci-build to show the current job status
Add Spray Git repository to Eclipse
This will clone the Spray repository into your Eclipse workspace folder, create a number of working sets and addthe projects to the working sets. To see the working sets go to the „View menu” icon of the Package Explorer andselect Working Sets as Top Level Elements.
12
If you want to specify the location where to clone the Spray repository locally do the following:
• File > Git/Projects from Git• Add• <Path to your locally cloned Git repository>, Next• Search, OK
If you had cloned the Spray repository locally and want to use that repository:
• File > Git/Projects from Git• Clone• Paste https://code.google.com/a/eclipselabs.org/p/spray/ in the URI field and add your Google Account user
name and your GoogleCode.com password (if your are logged in at the Spray Google Code site, click theProfiles link in the upper right corner and then go to the Settings tab) , Next
• select all branches, Next• select your local path to store the Git repository clone, Finish
If you want to apply the Spray workset configuration without being forced to clone the Spray repository again, youcan copy devtools/org.eclipselabs.spray.devenv/workingsets.xml to </path/to/workspace/.metadata>/.plugins/org.eclipse.ui.workbench/workingsets.xml
Target Platform
We are targeting for Eclipse Kepler. A target platform definitionis provided in releng/org.eclipselabs.spray.targetplatform/spray.target. To set this targetplatform:
• Import the project from path releng/org.eclipselabs.spray.targetplatform• Open Workspace properties, go to Plug-in Development / Target Platform• Here you should see Spray Target Platform. Check it and press Apply.
• As alternative you can also use the locally built target platform by Add... -> Nothing -> Name: Local SprayTarget, Add... -> Directory, Next -> Location: <your local path to the cloned Spray git repository>/releng/org.eclipselabs.spray.repository/target/repository.
13
The target platform contains the following features
• Eclipse Platform SDK 4.3.0 - http://download.eclipse.org/eclipse/updates/4.3• PDE – Eclipse Plug-in Developement Environment 3.9.0 - http://download.eclipse.org/releases/kepler• EMF – Eclipse Modeling Framework SDK 2.9.0 - http://download.eclipse.org/releases/kepler• EMF – Eclipse Modeling Framework SDK 2.9.0 - http://download.eclipse.org/releases/kepler• GEF – Graphical Editing Framework SDK 3.9.0 - http://download.eclipse.org/releases/kepler• Zest 1.5.0 - http://download.eclipse.org/releases/kepler• Graphiti SDK 0.10.0 - http://download.eclipse.org/graphiti/updates/0.10.0• MWE2 Language & Runtime SDK 2.4.0 - http://download.eclipse.org/modeling/tmf/xtext/updates/composite/
releases/• Xtext SDK 2.4.0 - http://download.eclipse.org/modeling/tmf/xtext/updates/composite/releases/• Xtend SDK 2.4.2 - http://download.eclipse.org/modeling/tmf/xtext/updates/composite/releases/• Xtext Antlr 2.0.0 - http://download.itemis.com/updates/releases/2.0.0/• xtext-utils unittesting - http://xtext-utils.eclipselabs.org.codespot.com/git.distribution/releases/unittesting-0.9.x
14
• Xpect 0.1.0 - http://www.xpect-tests.org/updatesite/nightly/• SWT Bot - http://download.eclipse.org/technology/swtbot/snapshots/
Distributions with Eclipse Kepler + Xtext 2.x can be found here: http://download.itemis.com/distros/
15
The Spray DSL Infrastructure
This secting will contain information about
• mapping to the DSL concepts to Graphiti concepts• implementation of expressions• scoping• model interferer• usage of injection• etc.
Postprocessed generated Ecore Metamodels
To avoid serialization problems it is sometimes needed to change the default values of attributes, or the Serializermight not distuinguish a not set value from a value that matches the default value (e.g. 0.0 for a double). If themetamodel is inferred there might be the need to postprocess the inferred metamodel and adjust it. This is done byan implementation of IXtext2EcorePostProcessor. The Generator component of the language must use thepostprocessor implementation. Due to Maven the specialized Generator component and the postprocessor must bein a separate dependent module, since the classes must be compiled before they can be used from the workflow.Therefore these classes reside in the org.eclipselabs.spray.runtime.xtext plugin.
16
Spray Generator
Explanation of the Spray Xtend2 templates implementation and design decisions (architecture), how does(different) models and their combination with the templates map to the generated artifacts (what should be theexpected output)
Reference Implementation
All proposed features that should be covered by code generation must be also covered by ReferenceImplementation code. This reference code must be developed in a way that it can be fully generated fromReference Models.
The quality of this reference code is crucial.
Indentation
All Xtend templates should use 4 spaces instead of tabs. Please check your template Xtend code for occurancesof the tab character.
You can visualize them in your workspace by setting the preference option General / Editors / Text Editors / Showwhitespace characters.
To replace all tabs in the current file open the Find/Replace dialog and enter (values without the ' character, this isjust used here to visualize the whitespaces)
• Find: '\t'• Replace with: ' '• Check option "Regular expressions"
Import Organizing
Import statements that must be computed from classes used within generated code must be evaluated beforeactually printing out the class. To do so, we use a similar pattern like in Xtext’s Domainmodel Example: Use anImport organizer, evaluate the class body with all qualified type names, and after evaluating it print out the classheader with the collected dynamic imports and the body afterwards.
This requires the following pattern in the Xtend classes:
• Derive template class from FileGenerator• Inject extension NamingExtensions
class DiagramTypeProvider extends FileGenerator { @Inject extension NamingExtensions naming
• Implement mainFile() with the following steps:• Print class header and package statement• Add static imports• Add // MARKER_IMPORT. This will denote the position where dynamic imports will inserted.• Print the class body content
def mainFile(Diagram diagram, String className) ''' «header(this)» package «diagram_package()»; import org.eclipse.graphiti.dt.AbstractDiagramTypeProvider;
17
import org.eclipse.graphiti.tb.IToolBehaviorProvider; // MARKER_IMPORT «body» '''
• Use the extension function shortName on any qualified name. It will print out the simple name of the qualifiedclass name and collects the qualified name for the import manager.
«metaClass.javaInterfaceName.shortName» // javaInterfaceName computes the qualified class name of an EClass interface // prints out 'IFeatureProvider'"org.eclipse.graphiti.features.IFeatureProvider".shortName
Modularity
Template Methods
The templates should be organized into reasonable small template definition methods. Usually a good separation isto provide a template for each generated method, which are called when generating a class body.
def mainFile (MetaClass metaClass, String className) ''' ... public class «className» extends AbstractCreateFeature { ... «generate_canCreate(metaClass)» «generate_create(metaClass)» «generate_createModelElement(metaClass)» «generate_getCreateImageId(metaClass)» «generate_hasDoneChanges(metaClass)» «generate_canUndo(metaClass)» } ''' def generate_canCreate (MetaClass metaClass) ''' «overrideHeader()» public boolean canCreate(ICreateContext context) { ... } '''
When the implementation of a template method grows too large, or is separatable into a sequence of logical parts,the template should delegate to subtemplate methods again.
This makes the template code more maintainable, and allows users later to override smaller parts of the generatorif customization is needed.
Hook Templates
To allow insertion of additional fields, constants, methods etc. in (Java) class bodies by subclassed templates,the base class FileGenerator offers the hook template methods generate_additionalFields() and
18
generate_additionalMethods(). These methods should be called in a class body template. The user thencan override these methods to insert additional code without the need to override the class template itself.
def mainFile(MetaReference reference, String className) ''' ... public abstract class «className» extends AbstractUpdateFeature { «generate_additionalFields(reference)» // call hook template public «className»(IFeatureProvider fp) { super(fp); } «generate_canUpdate(reference)» ... «generate_additionalMethods(reference)» // call hook template } '''
Generated Code
Also generated methods should not grow too large. The user should be able to override smaller methods in theextensions files. To be able to do this, the generated methods in base classes should mostly be public or protected,and not static nor final.
When appropriate, callback methods should be generated where it is likely for the user to make changes withoutthe need to override a complete method. For example, when creating a connection, the user might want todecorate it.
Example (AddReferenceAsConnection.xtend):
def mainFile(MetaReference reference, String className) ''' ... public class «className» extends AbstractAddFeature { ... «generate_add(reference)» // generate callback method «generate_decorateConnection(reference)» } ''' def generate_add (MetaReference reference) ''' ... public PictogramElement add(IAddContext context) { ... // call callback method in generated code decorateConnection (addConContext, connection); } '''
// template for callback method def generate_decorateConnection (MetaReference reference) ''' /** * Override this method to decorate the created connection */ protected void decorateConnection (IAddConnectionContext context, Connection connection) {} '''
19
Code Documentation
Overridden Methods
If a method from a base class is overridden by generated code, the method should declare the \@Overrideannotation and the {@inheritDoc} Javadoc annotation. To shorten this, «overrideHeader» generates thenecessary code.
Xtend Template:
«overrideHeader» public void myMethod (...)
Generated code:
/** * {@inheritDoc} */ @Override public void myMethod (...)
20
Graphiti
This secting will contain information about
• the generated Graphiti code• additional static platform artifacts• architecture• concepts of how to make the generated code adaptable
21
Project Setup
Things to consider when developing Spray projects.
Naming
Base package / Bundle ID Prefix: org.eclipselabs.spray
Source Management
• Generated sources are not checked in• The following resources must be added to .gitignore for each plugin
• src-gen• target• bin• plugin.xml_gen• xtend-gen
• Experimental features must be added on a branch until stabilized. This branch may be shared on the remoterepository if it is of interest of other developers to contribute or review the changes.
Adding a new Plugin project
Manifest
• Add a plugin.properties
# /**# * <copyright># * Copyright (c) 2013 The Spray Project.# * All rights reserved. This program and the accompanying materials# * are made available under the terms of the Eclipse Public License v1.0# * which accompanies this distribution, and is available at# * http://www.eclipse.org/legal/epl-v10.html# *# * Contributors:# * Spray Project Team# * </copyright># */# NLS_MESSAGEFORMAT_VAR pluginName = ADD DESCRIPTIONproviderName = Eclipselabs Spray
• Open MANIFEST.MF, change/add entries (exchange 0.3.0 by current development version from other plugins)
Bundle-Name: %pluginNameBundle-Vendor: %providerNameBundle-Version: 0.3.0.qualifierBundle-Localization: plugin
build.properties
Include the following files/directories, if they exist
• Binary Build
22
• plugin.properties• feature.properties• icons/• images/
• Source Build• pom.xml• launch/• */*.launch• log4j.properties
Project Specific Settings
To avoid confusion between different platforms and workspaces common settings should be defined as projectspecific settings. Those settings are checked in and thus shared.
• Resource: Text file encoding: Other / UTF-8• Resource: New text file delimiter: Other / Unix• Java Code Style -> Formatter:
• Check "Enable project specific settings"• select Active Profile "`spray_eclipse_formatter`"
• Java Editor -> Save Actions• Check "Enable project specific settings"• Check "Perform the selected actions on save"• Check „Format source code” / "Format all lines"• Check "Organize imports"
Build
• Copy the pom.xml from org.eclipselabs.spray.generator.graphiti. Exchange the plugin’s name in<artifactId>org.eclipselabs.spray.generator.graphiti</artifactId> by the project’s name.
• Open releng/org.eclipselabs.spray.distribution/pom.xml and add the plugin as additionalmodule
Project Set
Open the team project sets (*.psf) and add the project
• To <provider> section• To one of the working sets
Dependency Management
Imported Packages
Required Bundle is sometimes a too tight dependency binding. It does not allow to exchange the implementingbundle, which sometimes might be desired. The following packages should imported instead of adding its bundlesto the Required Bundles:
• org.eclipse.xtext.xbase.lib• org.eclipse.xtext.xtend2.lib• org.apache.log4j• org.apache.commons.logging• com.ibm.icu
Allowed dependencies
Some rules of plugin dependencies should be considered:
23
• A project created with Spray:• must not be dependent on Spray DSL• can depend on org.eclipselabs.spray.runtime.* plugins
• Spray runtime plugins must be separated the dependent underlying technology:• org.eclipselabs.spray.runtime.graphiti depends on Graphiti, but not on others like Xtext• org.eclipselabs.spray.runtime.xtext depends on Xtext, but not on others like Graphiti
Plugin Development
plugin.xml
Xtext generates a plugin.xml just once, on second generator execution it creates a plugin.xml_gen. Thisis because Xtext’s generator cannot merge changes into the plugin.xml and manual modifications might beintended. Differences between both files must be merged manually.
The plugin.xml file is quite large and it can become difficult to decide, which differences are produced by thegenerator and which are manual changes. In order to identify the intended changes these places must be markedin the code by comments <!-- SPRAY BEGIN -->...<!-- SPRAY END -->. Example:
<extension point="org.eclipse.ui.preferencePages"> <!-- SPRAY BEGIN --><!-- adding category --> <page category="org.eclipselabs.spray.xtext.Spray" class="org.eclipselabs.spray.styles.ui.StyleExecutableExtensionFactory:org.eclipse.xtext.ui.editor.preferences.LanguageRootPreferencePage" id="org.eclipselabs.spray.styles.Style" name="Style Language"> <keywordReference id="org.eclipselabs.spray.styles.ui.keyword_Style"/> </page> <!-- SPRAY END -->
24
Build Management
Built within Eclipse
As developer you will usually work just with the projects in the workspace and do not care about how Spray isbuilt from command-line or on the continuous integration server. But also here you will face some build steps thatrequire your manual work.
Typically there are launch configurations (files with .launch extension) that facilitate these tasks.
Generate DSL implementation
After a clean checkout it is required to run the workflows to produce implementation code in a specific order:
• org.eclipselabs.spray.styles/GenerateStyles.mwe2.launch• org.eclipselabs.spray.shapes/GenerateShapes.mwe2.launch• org.eclipselabs.spray.mm/GenerateSprayMM.mwe2.launch• org.eclipselabs.spray.xtext/GenerateSpray.mwe2.launch
Build documentation
The documentation is generated using Ant. You will find the following launch configurations to create thedocuments:
• Developer doc: org.eclipselabs.spray.doc.dev/org.eclipselabs.spray.doc.dev generate-help-build.xml.launch
• User doc: org.eclipselabs.spray.doc.user/org.eclipselabs.spray.doc.user generate-help-build.xml.launch
Spray Maven Build
Spray is using Maven Tycho for building. You need a Maven 3 installation. Usually you should have m2e installed,which has a Maven 3 installation embedded. If you want to run builds from command-line get a Maven distributionand add the bin folder to system path.
Maven settings.xml
The common Maven settings are located at devtools/org.eclipselabs.spray.distribution/settings.xml. This settings file configures the remote repositories that Spray needs (not everything is availablethrough Maven Central) the server settings for deployment onto the Cloudbees Repository.
The password in settings.xml have been encrypted, and you need a proper settings-security.xml file,which is owned by Karsten Thoms. If you have deployment rights you can set your own credentials, or ask Karstento provide it to you via personal mail.
See the Maven Password Encryption Guide for more details.
Build Spray projects
Configure the environment variable MAVEN_OPTS to value "-XX:MaxPermSize=150m -Xmx768m".
Builds are run from the /releng/org.eclipselabs.spray.distribution directory. Open a command-linewindow here.
mvn clean install
Maven will download all required artifacts and plugins automatically and at the end you should get
[INFO] Reactor Summary:[INFO]
25
[INFO] org.eclipselabs.spray.targetplatform .............. SUCCESS [0.156s][INFO] org.eclipselabs.spray.parent ...................... SUCCESS [0.065s][INFO] org.eclipselabs.spray.generator.common ............ SUCCESS [5.482s][INFO] org.eclipselabs.spray.styles.mm ................... SUCCESS [6.128s][INFO] org.eclipselabs.spray.shapes.mm ................... SUCCESS [7.426s][INFO] org.eclipselabs.spray.mm .......................... SUCCESS [6.414s][INFO] org.eclipselabs.spray.runtime.graphiti ............ SUCCESS [0.766s][INFO] org.eclipselabs.spray.runtime.xtext ............... SUCCESS [3.782s][INFO] org.eclipselabs.spray.styles ...................... SUCCESS [22.686s][INFO] org.eclipselabs.spray.shapes ...................... SUCCESS [27.211s][INFO] org.eclipselabs.spray.xtext ....................... SUCCESS [24.618s][INFO] org.eclipselabs.spray.generator.graphiti .......... SUCCESS [8.607s][INFO] org.eclipselabs.spray.runtime.xtext.ui ............ SUCCESS [0.777s][INFO] org.eclipselabs.spray.styles.ui ................... SUCCESS [1.594s][INFO] org.eclipselabs.spray.shapes.ui ................... SUCCESS [1.874s][INFO] org.eclipselabs.spray.xtext.ui .................... SUCCESS [5.017s][INFO] org.eclipselabs.spray.generator.graphiti.ui ....... SUCCESS [0.289s][INFO] org.eclipselabs.spray.runtime.graphiti.xtext ...... SUCCESS [0.197s][INFO] org.eclipselabs.spray.runtime.graphiti.zest ....... SUCCESS [0.140s][INFO] org.eclipselabs.spray.styles.generator ............ SUCCESS [2.091s][INFO] org.eclipselabs.spray.styles.generator.ui ......... SUCCESS [0.313s][INFO] org.eclipselabs.spray.shapes.generator ............ SUCCESS [14.417s][INFO] org.eclipselabs.spray.shapes.generator.ui ......... SUCCESS [0.322s][INFO] org.eclipselabs.spray.tychohelpers ................ SUCCESS [0.166s][INFO] org.eclipselabs.spray.examples.petrinet.domain .... SUCCESS [0.323s][INFO] org.eclipselabs.spray.examples.petrinet ........... SUCCESS [12.172s][INFO] org.eclipselabs.spray.examples.bpmn.domain ........ SUCCESS [0.548s][INFO] org.eclipselabs.spray.examples.bpmn ............... SUCCESS [17.480s][INFO] org.eclipselabs.spray.testhelper .................. SUCCESS [0.280s][INFO] org.eclipselabs.spray.styles.tests ................ SUCCESS [21.491s][INFO] org.eclipselabs.spray.shapes.tests ................ SUCCESS [14.735s][INFO] Eclipselabs Spray ................................. SUCCESS [0.005s][INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS
The target platform for this build is computed from the one build at Cloudbees. You can build this repository alsolocally and use it. To do this build the target platform repository (see next section) and activate the profile local-build.
mvn clean install -Dlocal-build
Build target platform repository
In directory /releng/org.eclipselabs.spray.distribution execute:
mvn clean install -Pmodules-targetplatform
This first build will create a p2 repository, which serves as a local target platform repository. The repository containsall bundles and features that are required to build the Spray projects. This build has only to be executed when thetarget platform changes.
Maven will download all required artifacts and plugins automatically and at the end you should get
[INFO] Reactor Summary:[INFO][INFO] org.eclipselabs.spray.targetplatform .............. SUCCESS [0.211s][INFO] org.eclipselabs.spray.parent ...................... SUCCESS [0.174s]
26
[INFO] org.eclipselabs.spray.repository.parent ........... SUCCESS [0.050s][INFO] org.eclipselabs.spray.releng.repository ........... SUCCESS [38.918s][INFO] Eclipselabs Spray ................................. SUCCESS [0.004s][INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS[INFO] ------------------------------------------------------------------------[
In directory releng/org.eclipselabs.spray.repository/target/repository an Eclipse P2 repositoryis built, which contains all plugins and sources.
Disable execution of UI tests
The build executes UI tests developed with SWTBot by default. If you want to skip executing these tests, add theskip-ui-tests property:
mvn -Dskip-ui-tests clean install
Parent POM
Spray’s Parent POM can be found at releng/org.eclipselabs.spray.parent/pom.xml.
Plugin Management
All Maven Plugins that are used in the build are declared in the <pluginManagement> section. Plugin versionsare only managed here, module POMs must not specify any plugin version! If a common configuration can bedefined for a plugin, this configuration is already added to the plugin in the plugin management section.
To check for possible updates run frequently
mvn versions:display-plugin-updates
Profiles
Repository selection profiles
Profile local-build
This profile will select the locally built target platform repository to resolve dependencies. When activated it is notrequired to query the remote target platform repository, which boosts the startup time of the build. It requires thatthe local target platform repository was materialized before (see „Build target platform repository”).
The profile is activated by the presence of the property local-build. To activate it set the property.
When testing target platform updates before making them effective for all users and builds it is recommended tobuild the target platform repository locally and test the build against it by activating this profile.
mvn -Dlocal-build ...
When this profile is activated the profile remote-build gets deactivated.
Profile remote-build
This profile is activated by default. The target platform will be computed from the remotely build target platformrepository on the Cloudbees server. Since the target platform repository is already an aggregated one
Modules selection profiles
Spray contains a lot of sub projects. Running a build over all projects is usually not feasible, since it is a long-running task. Thus the user will usually activate one profile that selects a sub set of modules.
27
The profiles are defined in /releng/org.eclipselabs.spray.distribution/pom.xml.
Profile modules-default
The modules-default is activated by default, i.e. the user does not have to specify anything. The containedmodules are:
• all plugins from the /plugins directory• all plugin tests from the /tests directory• example „Businessdomain DSL” from /examples/one• example „Petrinet” from /examples/petrinet• example „LWC2012” from /examples/lwc2012• example „BPMN 2.0” from /examples/bpmn2.0
Profile withoutExamplesAndTestProjects
Use case: You have done changes to the DSL and/or the generators and just want to check if all runtime, DSL andgenerator projects can be compiled.Activating this profile will only build all runtime, DSL and generator projects.As adapting tests and examples to this changes should happen in a second step there is no need to execute themnow.
Profile onlyExamplesAndTests
Use case: You are sure that all runtime, DSL and generator projects do compile and you are now working onadapting, fixing and extending tests as well as the example projects that are also effected by the changes then youshould use this profile.
Profile modules-targetplatform
With activating this profile the target platform is build locally, i.e. all required features and plug-ins to compilethe Spray code base will be downloaded into /releng/org.eclipselabs.spray.repository/target/repositoryWith using the profile local-build in conjunction with a profile like modules-default oronlyExamplesAndTests you can build the Spray projects offline (otherwise the P2 repository from theCloudbees Jenkins job will be used).
Profile modules-assembly
Use this profile to build the Spray feature and update site project (this profile will also build the developer featureproject and developer update site project). This profile will only build successfully if the runtime, DSL, generator,tests and example projects have been built before.
Profile modules-docs
Activating this profile will exclusively built the developer as well as the user documentation, i.e. transform the textilefiles to HTML and PDF.
Profile modules-all
This profile builds all Spray projects.
Static code analysis profiles
Profile sonarLocal
This profile contains the connection data for your local Sonar database as well as the URL of your local Sonarserver instance. You may adapt these to your own needs.
28
To learn more about Sonar (now called SonarQube) have a look at the offical site
Profile sonarRemote
This profile contains the connection data for a remote running Sonar server and Sonar database, e.g. hosted onAmazon EC2. You may adapt these to your own needs.
Profile codeCoverage
With passing this profile the code and test coverage measurement is activated. JaCoCo as tool is used. This profileconfigures where the measured data is accumulated and where Sonar should look to derive its coverage reports.
To learn more about JaCoCo see here
Version management
Setting Spray version
The Ant script org.eclipselabs.spray.distribution/scripts/build.xml contains a goal namedset-version, which allows to set the global Spray release version. A launch config has been added to thelaunch folder of the project. When executed it will replace all version identifiers. The changes are not committedthen yet.
It is recommended to have no uncommitted changes in your Git repo before executing this script.
Setting Xtext version
For Spray it is important that only the version of Xtext is installed against it was build. Xtext guaranteescompatibility on the micro version number, but for an increment in the minor version number there is no guaranteethat Spray will run on it. Thus we constraint the usage of Xtext in dependencies to the current minor version range.This is done in the MANIFEST.MF Require-Bundle section with the modifier bundle-version. For example, toallow Xtext version 2.4.x the version constraint string is
require-bundle="[2.4.0,2.5.0)"
This includes the range from 2.4.0 (inclusive) until 2.5.0 (exclusive).
The build.xml script contains a target set-version-xtext which replaces bundle-version constraints bythe given input.
29
Continuous Integration
Introduction
We use Cloudbees' DEV@Cloud as infrastructure for a Continuous Integration build. The location of the CI systemis https://spray.ci.cloudbees.com/
Build Jobs
Job spray-ci-build
Build URL: https://spray.ci.cloudbees.com/job/spray-ci-build/
Pulls branch master of the Git repository every 15 minutes. Build mail messages are sent to [email protected]. To receive build mails register to the spray-build Google Group.
Job spray-docs-build
Runs the generation of documentation. The latest build is archived and linked on the Spray project homepage.
• Build URL: https://spray.ci.cloudbees.com/job/spray-docs-build/• Git Branch: kepler• Activated profiles: skip-ui-tests remote-build-snapshot modules-docs• Deactivated profiles: modules-default• Schedule: midnight
Job spray-ci-targetplatform
Build URL: https://spray.ci.cloudbees.com/job/spray-ci-targetplatform/
This job has got no automatic trigger. A developer who did changes to the target platform definition (i.e. *.target fileand category.xml) is responsible to trigger this job manually after checking in those changes. Build mail messagesare sent to [email protected]. To receive build mails register to the spray-build GoogleGroup.
The artifacts of this job is the P2 repository that is used by the spray-ci-build.
Job spray-distrobuilder
Build URL: https://spray.ci.cloudbees.com/job/spray-distrobuilder/
This job has got no automatic trigger. This job produces Spray RCP products for Windows, Linux and MacOS eachfor 64bit architecture only.
The build configuration is based on Tom Schindl’s DistroBuilder
Job spray-ci-experimental
Build URL: https://spray.ci.cloudbees.com/job/spray-ci-experimental/
Pulls branch experimental of the Git repository every 15 minutes. Build mail messages are sent to [email protected]. To receive build mails register to the spray-build Google Group.
You can push your repository state any time to the experimental branch if you want to test things on the buildthat might break it, like when changing the build configuration or introducing new dependencies.
30
Job configuration
Headless UI tests
A build on the Cloudbees Jenkins service cannot start an UI. To execute the UI tests anyway Xvnc server is startedwithin the build. Additionally the metacity window manager is started as a pre-build step with Shell execution. Therequired hints to solve this issue were found in the blog entry How to run UI tests on hudson.eclipse.org server (ona server without a window manager activated by default)
Administration
The Cloudbees builds are administered by Karsten Thoms and Joerg Reichert. To request changes, add an issueand set the Label „Component-Build”.
31
Release Process
Follow these steps if you want to release a new version of Spray.
An ant script org.eclipselabs.spray.distribution/scripts/build.xml is prepared to execute allnecessary steps. You will need to have checkout out the spray.distribution git repository as a siblingdirectory to your main Spray repository; the process copies and uploads artifacts within this repository.
• Pull the latest state from the repository.• Open a command-line and go to the releng/org.eclipselabs.spray.distribution/scripts
directory• Call git status to make sure that you have no pending changes open.• (Optional) Perform mvn clean install to check that the main build would perform without error. The script
will invoke this also, but you just make sure that you don’t have to rollback changes in the case of failures.• Execute from this directory the build.xml script.
ant release
• If something went wrong during the build call ant release-rollback. This will drop the created branchesand switches back to the main branch. You may have to call this twice when the build failed after a successfulMaven build.
• Go to the Downloads page and remove the „Featured” tag from the artifacts of the older release, then add the„Deprecated” tag.
• Announce the release on the [email protected] mailing list
Distrobuilder
The Spray Developer IDE is created with the Distrobuilder toolkit from Tom Schindl. This tool creates Eclipsedistributions based on existing distributions and installs a set of features from existing p2 repositories with the p2director application.
The distrobuilder toolkit is providing a Java API and an Ant task. Spray is calling this Ant script from Maven.We do not use Ant directly, since on the Cloudbees server we cannot add custom Ant task easily to the Antdistribution used on the Jenkins build server. But with Maven, we can call Ant with a custom classpath with Mavendependencies. Since the distrobuilder’s jar is not available on a public repository, we have uploaded it to a privaterepository at Cloudbees.
The distribution build is described by just a single Maven POM in the projectorg.eclipselabs.spray.dev.distrobuilder. The POM mainly executes the maven-antrun-plugin. Inthe called Ant script the following tasks are done:
• Declare the custom distrobuilder Ant taskat.bestsolution.releng.distrobuilder.ant.DistroBuilderTaskDef
• Create the directory structure required for the Distrobuilder as described in the README• Download and unpack the p2 director• Download Eclipse SDKs for Windows, Mac OSX and Linux• Call the Distrobuilder. Configure the update sites to get software from and the installable units to install from
there.
<builder builddirectory="${project.build.directory}/build" p2directorexecutable="${project.build.directory}/director/director" targetdirectory="${basedir}/targets" staticreposdirectory="${basedir}/repos" distdirectory="${project.build.directory}/dist" appname="Spray" version="${project.version}">
<updatesite url="http://download.eclipse.org/modeling/tmf/xtext/updates/composite/releases/" />
32
<installunit name="org.eclipse.emf.mwe2.language.sdk.feature.group" version="2.3.0.v201206120758" /> <installunit name="org.eclipse.emf.mwe2.runtime.sdk.feature.group" version="2.3.0.v201206110920" /> <installunit name="org.eclipse.xtext.sdk.feature.group" version="2.3.1.v201208210947" /> <installunit name="org.eclipse.xtext.xtend2.sdk.feature.group" version="2.3.1.v201208210947" /> <installunit name="org.eclipse.xtext.xtend2.m2e.feature.group" version="2.3.1.v201208210947" />
To build the distributions simply go to the org.eclipselabs.spray.dev.distrobuilder directory and call
mvn -s settings.xml clean package
The resulting distributions can then be found in the directory target/dist.
33
Testing
Test Projects
All test projects can be found in the repository in the tests folder.
Test aspects
There are several aspects of Spray that have to be covered by tests:
Testing using the Spray DSL Editor enviroment
Testing the wizard
• Does the Spray wizard offer the expected configuration options?• Does the Spray wizard produce a project with the expected configuration?
• plugin.xml• MANIFEST.MF• source folders• created diagram and domain model with the expected file extensions• does the properties file exist and contain the expected values
Testing the Spray DSL editor
• Is the imported domain model resolved?• Do changes in the DSL editor trigger the code generation?• Are semantic errors marked and probably even quick fixes offered for them (producing the expected change)?• Do the proposals work?
• Are the predefined DSL templates for e.g. containers and connections offered?• Is the color picker shown?• Is access provided to JVM types in the class path?
• Do cross references inside the DSL work (e.g. referencing an already defined behavior group)?• Does the formatter produce the expected output?• After save, is the DSL serialized correctly and can it be parsed afterwards?
Testing the generated code
• Are all expected artifact generated for a given DSL?• correct package?• correct name?• base class as well as gap class generated?• expected file content?
• Does the generated code compile?• Is a warning dialog shown, when it is tried to edit a generated file?• Is there a context menu entry for moving a gap class from src-gen to src and does it work?• Is a gap class not regenerated when it has been moved to src?
Testing the generated Graphiti editor
• Can the Graphiti editor runtime be started out of the generated code?• Can a new diagram with the expected diagram be created?• Does the generated Graphiti editor provide its expected abilities in compliance to what has been defined in the
DSL?• Can all workflows when using the generated Graphiti editor run through without failure?
34
• Does the palette contains all expected elements in the expected palette compartments?• Creating elements: Does the domain model file contain a corresponding object with the expected properties
after an element has been created in the diagram editor?• Adding elements: Is the expected graphical representation with the expected properties created in the diagram
model after the element from the palette has been selected and droped in the editor?• Removing elements: Is the graphical representation removed without removing the domain element?• Updating elements: Are changes to the domain object done outside the diagram editor recognized in the
diagram editor?• Deleting elements: Are the graphical representation as well as the domain element are deleted from their
models?• Resizing and layouting: Does the diagram elements have the expected coordinates after resizing (e.g. when a
rectangle is resized, the contained text is aligned, too)?• Constraints: Are the constraints applied when creating, adding, moving and resizing diagram elements (e.g. no
connection allowed between certain objects)?• Context buttons and menus: Are the expected context buttons and context menu entries available at the
diagram elements?• Properties View: Is the properties view shown when clicking on diagram elements and does it show the
expected fields containing the expected values?• Is the editor shown as dirty when there are changes in the diagram?• When saved, are all changes persisted in the diagram file as well as in the domain model file and then the editor
is not shown as dirty?
Test approaches
JUnit tests
• should be used when a functionality can be tested without the need to start an Eclipse instance (as they do notneed a certain state only reachable by a running Eclipse)
• this of kind test should be preferred• we use JUnit4• common test logic should be factored out, so that the actual test method states only the test parameters and
passes them to a common test executer method, this makes the tests more readable• following the suggestions of the XUnit Test Pattern book, the name of a test method should contain
• test as prefix• the name of the method to test, e.g. testGetSomething• optional the condition under that the test is executed, e.g. testGetSomething_WhenNullIsPassed• optional the expected result, e.g. testGetSomething_WhenNullIsPassed__NullExpected
• the instance of the class to to test should be declared as global variable and assigned in a with @Beforeannotated setup method
• in a Maven pom these test should be execute either with the Maven-Surefire plugin or as alternative with theTycho-Surefire plug-in, but then without the use of the UI test harness
• A Test Suite class AllUnitTests.java is provided in the main package of the test plugin that collects all testclasses which are executable as „plain” unit tests (i.e. no plugin test)
Mocking
• to improve the isolation of tests but also as a way to avoid the need of a running Eclipse in some cases it issensible to use a mocking framework to stub the interactions of the class to test
• we propose the use of Mockito in conjunction with Powermock as mocking framework, these librariesare exported by the plug-in org.eclipselabs.spray.testhelper and should be added to the MANIFEST.MFdependencies of the test plug-in if it want to use these mocking frameworks
• with Mockito you can stub interfaces as well as classes and put them in place of the classes the class undertest would usually interact with, you can specify which values should be returned when a method of the stubbedclass is called with certain parameters
• with Powermock the abilities of Mockito are extended to support mocking e.g. static method calls as well asconstructor calls
35
• as most classes in Spray uses Google Guice injection, it is easy to inject the stubbed classes in place of the realclasses, in all other cases sub classing the class to test may be an option
Xtext tests
• tests that exercises Xtext based classes should define the Xtext runner at the class header:@RunWith(XtextRunner.class)
• to replace the default injection configuration define a custom injection provider and also declare it in the headerof the test class: @InjectWith(SprayTestsInjectorProvider.class)
• after that you are able inject the classes inside the test class itself as well as use them in the classes to test• to ease the writting of tests for Xtext based code, the xtext-utils are used• beside checking the parsing and serializing of DSL models you can also test things like scoping and validation• for further insight in how to test Xtext DSLs also checkout Moritz Eysholdt’s presentation covering that topic• Xtext tests can be executed headless, i.e. as JUnit tests• The test cases are added to the AllUnitTests.java test suite
JUnit plug-in tests
• in some cases it inevitable to start up an Eclipse instance to be able to execute tests successfully, as thesetests depend on state only available in a running Eclipse (e.g. state is set by the Activator of the plug-in or thetest queries the existing perspectives)
• some error states are not reproducable as JUnit test but only in a JUnit plug-in test (e.g. being able to import thedomain model)
• some other error states only occur in a Eclipse RCP product having the Spray feature installed (e.g.build.properties does not include all required files)
• in a Maven pom these test should be execute with the Tycho-Surefire plug-in with setting the use of the UI testharness to true
• note that those non headless tests will not work on the Jenkins build server hosted by CloudBees, as this hoston Linux machine, so their execution is disable there
• A Test Suite class AllPluginTests.java is provided in the main package of the test plugin that collects alltest classes which must be executed as plugin tests.
UI tests
• as extension of JUnit plug-in tests UI tests executes operations a user would do usually manually, e.g. openmenus, clicking on buttons, but also dragging elements in the Graphiti editor, do resize and so on
• we currently use SWT Bot, to define those tests, in contrast to a tool like WindowTester it is not able to recordinteractions with the UI, so you have to program those interactions by your own
• UI tests tend to be brittle and are hard to read and maintain, so they should be use when the functionality to testcannot be coverage by other test means• depend on the performance of the Computer where they are executed (reactions too slow or too fast, have to
work with sleeps and cope with threading issues)• behave sometimes different on different platforms (UI elements cannot be found that have been found in a
test run under a different operating system)• The test cases are added to the AllPluginTests.java test suite
Measuring test coverage
• there has been added support of measuring code coverage in the Eclipse development environment as well asin the Maven build with using EMMA
• there are class loading issues when the code to instrument by EMMA uses Google Guice injection, so testcoverage is currently mostly measure only for the test code that is excecuted but not for the code that isexercised by the test code (that would be actually the more interesting code coverage to measure)
Test data organization
• example domain models are provided in the model folder of the test plug-in
36
• the test models are named, numbered and organized in different packages to better associate them with thetests that uses them
• for smaller tests it may sufficient to build up the test models with using the generated EMF factory class insteadof providing extra test models
• the test models can be used to compare expected and actual output, e.g. when testing the Spray DSL formatter• beside the test DSLs there can be also expected generator artifacts provided to be used in output comparison
assertions
Generator template tests
• beside testing the generated code by executing it and check its behavior, it is sometimes more sensible toadditional provide tests for generator templates and helper methods, to be able to spot more easily where arefailures in the generator logic, as some of those failures only occur under certain circumstances
• so instead of executing the hole generator with a bunch of different models, single templates and helpermethods can be execute with several variations of model parts only applicable to the template or helper methodto test and verify their outputs
• you can check fault-tolerant does the templates and extensions act to invalid or incomplete model data
Spray Language Tests
The Spray Language is tested in project org.eclipselabs.spray.xtext.tests. This project makes use ofthe xtext-utils unittesting framework. These tests use example models that are read and processed and cover thefollowing topics:
• Parsing of the models• Resolving cross references / scoping• Validation• Formatter• Serializing
Test models are kept below the /model folder. The examples should be as minimal as possible to demonstrateand test a language feature. This is especially important for debugging, since effort for debugging grows with thesize of models.
The main test class is org.eclipselabs.spray.xtext.tests.ModelTests. The initialization part
@RunWith(XtextRunner2.class)@InjectWith(SprayTestsInjectorProvider.class)public class ModelTests extends XtextTest { @Before public void before() { super.before(); suppressSerialization(); EPackage.Registry.INSTANCE.put(GenModelPackage.eNS_URI, GenModelPackage.eINSTANCE); EcorePlugin.getEPackageNsURIToGenModelLocationMap().put(BusinessDomainDslPackage.eNS_URI, URI.createURI("classpath:/mod4j/BusinessDomainDsl.genmodel")); }
...}
A test method is simply invoking the testFile() method and passes the file under test. If additional resourcesare required to resolve cross references (typically at least the Ecore file used as metamodel) these are passed asadditional arguments.
37
@Test public void test_20_color() { testFile("testcases/20-color.spray", "mod4j/BusinessDomainDsl.ecore"); }
See also the slides Test-Driven Development of Xtext DSLs.
Runtime Tests
The Spray generator components tests can be found in projectorg.eclipselabs.spray.generator.graphiti.tests.
38
Code quality
There are some tools to measure the code quality.
Code coverage
EclEMMA, now called JaCoCo (Java Code Coverage), is a tool to measure code and test coverage.These measures delivery hints of code that is not executed while running the application (code coverage) resp. thatis not executed when running all tests (test coverage).So it can give hint where is unused code or tests are missing.
As generated code is not of interest when measuring code coverage, those code should be excluded. As codecoverage only looks at the compiled classes it cannot separate between src and src-gen, so you have to use nameschemes:
In Coverage View you can see the coverage percents for packages, classes and methods.
39
If you click on one of the classes the code parts that have been executed are highlighted in green. Yellowhighlighting marks code branches that have been not executed in all combinations. Red parts of the code havebeen never executed.
SonarQube
Sonar (now called SonarQube is a tool to measure code quality metrics over time. It consists of a web server and aassociated database. There exists also an Eclipse plug-in so you can stay in your favorite IDE.
Just download the Sonar server distribution, unpack it and follow the installation guide
Here also the configuration of Sonar in Maven is explained.
To install the Eclipse plug-in follow „this guide”: http://docs.codehaus.org/display/SONAR/Installing+SonarQube+in+Eclipse
In following there are some screenshots documenting the usage of Sonar. Please note that these screenshotshave been made in April 2012, so the current Sonar release may differ in some spots.
Register your set up Sonar server in the Eclipse preferences:
40
41
42
You can match you projects with those already known at the server. This works only if a Maven build with havingthe Sonar profile activated has been run through (and this way already published some data).
43
There are several views provided by the Eclipse Sonar plug-in that display the graphs you can find on the webserver, too:
Inside the Java classes markers are created for issues identified by the Sonar analysis:
44
The actual global configuration of Sonar have to be done on the web server:
45
46
47
Examples
Examples help in several ways: they
• demonstrate the abilities of Spray to potential users• could be a starting point for developing own Spray projects• assist developers to test the current Spray code base
Established examples
The following example projects are mature although there are still things to be improved.
Business Model (Mod4j)origin: Mod4j Business Domain Model DSL
kind: boxes and lines / compartments
description: Modeling of class diagrams (with classes, associationsbetween classes, inheritence relations, attributes (name+ type) and rules assigned to classes)
Heat Exchanger (LWC 2012)origin: Piping & Instrumentation Domain Model (pdf)
kind: boxes and lines / complex shapes and styling
description: Modeling of technical construction plans
48
BPMN 2.0origin: OMG BPMN 2.0 Spec (pdf), see also BPMN 2.0 EMF
meta model and BPMN 2.0 modeler
kind: boxes and lines / complex shapes and styling
description: Workflow modeling
49
Petri Netsorigin: Petri Net Markup Language (PNML, ISO/IEC 15909)
kind: boxes and lines / compartments
description: Modeling of execution behavior of distributed systems
50
Examples in early state
The following example projects are still in development and do not yet deliver the value they should.
Formsorigin: home grown
kind: compartments
description: Modeling of UI forms (textfields, buttons, ...)
Statemachine (Fowler DSL)origin: Martin Fowler’s Statemachine DSL Example
kind: boxes and lines
description: Modeling states and transitions between states triggeredby events.
51
Nassi-Shneiderman-Diagramorigin: Structogram, initial input from user forum
kind: compartments
description: Modeling of a program flow in form of structuredflowcharts.
52
Feature Modelingorigin: Staged Configuration Through Specialization and Multi-
Level Configuration of Feature Models (pdf), see alsoFeature Modeling plug-in and EMF feature model
kind: boxes and lines / line decoration
description: Modeling product line configurations
53
Examples only for testing
The following example projects are purely for testing and do not serve a higher purpose.
Containmentorigin: input from user forum
kind: boxes
description: Modeling of EClasses that become containments to itsdomain model root.
54
Goalsorigin: input from user forum
kind: boxes and lines
description: Testing the usage of the different connection modes.
Ideas for future example projects
In the following only ideas for possible example projects are listed.
Taipanorigin: GMF example
kind: boxes and lines / containment
55
description: Modeling of shipping routes
Mindmaporigin: GMF example
kind: boxes and lines
description: Visually structuring ideas.
Game Of Lifeorigin: Wikipedia, Bitstorm Java Applet
kind: shapes / simulation
description: Simulation.
Chessorigin: Graphiti example
kind: shapes / compartments
description: Testing moving rules.
Component diagramorigin: UML component diagrams
kind: Boxes and lines.
description: Modeling the components of a software system, e.g. theplug-in structure of the Spray project.
Sequence diagramorigin: UML sequence diagrams
kind: Boxes and lines.
description: Modeling interaction scenarios (e.g. method callsequences). Testing lines connected to lines.
Floor planorigin: Sweet Home 3D
kind: shapes / compartments
description: Modeling complex structures with complex shapes.
56
Issue Tracking
Tracking System
We use the Issue Tracking System from Google Code: http://code.google.com/a/eclipselabs.org/p/spray/issues/list
For keeping up to date with incoming new issues resp. changes to existing issues each developer should subscribeto the RSS feed
Git Commit Message
The tracking system allows automated linking of commits to the Git Repository with the Issue Tickets whenfollowing name conventions. When fixing an issue use a commit message with this format
fixed issue#<issuenumber>: <message>
Google Code will link the commit in the issue and set it to status Fixed.
57
Requirements Engineering
Additional to the issue tracking we started to manage end user level requirements / use cases with an extra tool:Yakindu requirements
The sources of the requirements specification is checked in on the GIT branch "yakindu_requirements"
With Yakindu requirements we can describe requirements, use cases, entities, UI forms, UI flows and statetransitions with Xtext based integrated DSLs. There is provided a live graphical preview of the use case flows.
Out of this models you can generate HTML and PDF requirements specification reports as well as a work breakdown structure Excel sheet.
58
Please note that the Spray requirements specification is currently in a very early stage (only rudimentary usecases, entities models just transformed from the existing Ecores and so too technical for a user centered view).
The latest generated PDF requirements specification report can be downloaded from here
59
Troubleshooting
Moved classes not visible in runtime workspace
You might experience that if you move a class in the development workspace this class might not be visible in theruntime workspace. This means you might have uncompilable code in the runtime workspace then, although the„missing” class must be definetely there. You can verify this behavior if you open up the Plugin Dependencies ofthe project in the package explorer. Classes from plugins from the development workspace are linked with theirclasses folder (usually /bin or /target/classes). Open up the path where you should find the class in doubt. If it is notthere, you are facing the issue mentioned here.
There are 2 options to solve it: Clean the workspace before start (check option in the run configuration). But thisremoves all projects from the runtime workspace. The other alternative is to open the build path of the project inruntime workspace, go to the Libraries tab, remove „Plug-in Dependencies”, save, add „Plug-in Dependencies”again. The classes should be there again.
60
How To
In the following sections certain details about the development environment and implementation details areexplained in detail.
Dependencies
How to manage dependencies.
Update Maven plugin versions
Go to directory releng/org.eclipselabs.spray.distribution and check for plugin updates :
mvn versions:display-plugin-updates
When the report shows some plugin updates or non-configured versions then change this in the parent POMreleng/org.eclipselabs.spray.parent/pom.xml.
Resolve „Discouraged access” warnings
Access rules assure that restricted API ist not used accidently. But sometimes we need to access API that is notpublicfor downstream plugins. This is especially the case for non-final API of Xtext like Xbase.
You will see annoying warnings like these:
Discouraged access: The type XExpression is not accessible due to restriction on required projectorg.eclipselabs.spray.generator.graphiti
To resolve them we need to configure access rules. Open the Java Build Path, go to the Libraries folder and openthe „Plug-in Dependencies tree”. Then select „Access Rules” and press Edit.
Add a rule with resolution „Accessible” for pattern „org/eclipse/xtext/xbase/**” (or the package you need).
61
Target Platform
Updating .target files
Maintenance of the target platform is an important, but also annoying task. The tooling for defining and maintainingTarget Definition files is quite bad.
Especially when building against nightly builds of features we have to update the target platform frequently. It oftenhappens then that versions of Installable Units are not available anymore. Then one has to figure out what versionare existing on the given repositories and update the .target files.
To make this task easier a tool is provided in plugin org.eclipselabs.spray.dev.pde. The headless Eclipseapplication org.eclipselabs.spray.dev.pde.targetPlatformUpdater reads a given .target files andqueries the repositories defined in the file for their installable units and the available versions. Then it picks thelatest version and updates the document. The document is then written to original file, or to a new file.
To invoke this application create a launch config for applicationorg.eclipselabs.spray.dev.pde.targetPlatformUpdater and pass the arguments ‚srcUrl’ (required)and ‚targetUrl’ (optional).
62
The console output looks like follows:
INFO: Parsing target definitionINFO: Reading repository http://download.itemis.com/updates/releases/2.0.0/INFO: Updating IU versionsINFO: Reading repository http://download.eclipse.org/releases/keplerINFO: Updating IU versions
63
INFO: Found newer version for IU org.eclipse.sdk.feature.group. Updating from 4.3.0.v20130526-2205 to 4.3.0.v20130530-1801INFO: Found newer version for IU org.eclipse.pde.feature.group. Updating from 3.9.0.v20130526-2000 to 3.9.0.v20130530-1553INFO: Found newer version for IU org.eclipse.emf.sdk.feature.group. Updating from 2.9.0.v20130527-0426 to 2.9.0.v20130603-0742INFO: Found newer version for IU org.eclipse.graphiti.sdk.plus.feature.feature.group. Updating from 0.10.0.v20130529-0649 to 0.10.0.v20130605-1155INFO: Found newer version for IU org.eclipse.swt. Updating from 3.102.0.v20130522-1423 to 3.102.0.v20130530-1600INFO: Reading repository http://download.eclipse.org/modeling/tmf/xtext/updates/composite/releasesINFO: Updating IU versionsINFO: Reading repository http://download.eclipse.org/technology/swtbot/snapshots/INFO: Updating IU versionsINFO: Reading repository http://xtext-utils.eclipselabs.org.codespot.com/git.distribution/releases/unittesting-0.9.xINFO: Updating IU versionsINFO: Reading repository http://www.xpect-tests.org/updatesite/nightly/INFO: Updating IU versionsINFO: Found newer version for IU org.xpect.sdk.feature.group. Updating from 0.1.0.201305311135 to 0.1.0.201306110942INFO: Reading repository http://download.eclipse.org/tools/orbit/downloads/drops/R20130517111416/repository/INFO: Updating IU versionsINFO: Updating XML documentINFO: Writing XML document to file:/Users/thoms/git/spray/spray/releng/org.eclipselabs.spray.targetplatform/spray-kepler-updated.target
Release Management
Release Script
Spray has an Ant build script to support the release process. It is located at releng/org.eclipselabs.spray.distribution/scripts/build.xml. The script makes use of two property filesto store required settings for the build:
• release.properties: Defines the current version of Spray (version_main) and the next version(version_next). Further defines local paths and Maven options.
• user.properties: Defines user credentials that are required to upload files. This file won’t be checked in(marked in .gitignore), since the user password is unencrypted here.
Custom Ant Tasks
Fetching libraries
When it is required to use custom ant tasks we have the problem that we cannot put them in the library folder of theAnt distribution at Cloudbees. There we only can assume to have a basic Ant distribution. All additional tasks mustbe made available by referencing their Jars in the classpath of the <taskef> definition.
To avoid the need to check in those jars we are fetching them from the internet using the Ant Get task . Thus theyare downloaded in the -fetch-dependencies target to a private library folder like follows:
<target name="-fetch-dependencies" description="downloads additional jars for task definitions"> <mkdir dir="lib" />
64
<get src="http://ant-googlecode.googlecode.com/files/ant-googlecode-0.0.3.jar" dest="lib/ant-googlecode.jar" skipexisting="true" /> ... </target>
The files are just fetched once, so the download does not happen always. Targets that declare tasks with<taskdef> need to depend on -fetch-dependencies.
Task compositeSite
This task adds a release to the files compositeArtifacts.xml and compositeContent.xml of the compositeupdate site in the spray.distribution repository.
File upload to Google Code
For uploading the resulting files to the Downloads section on the Spray project homepage we make use of the ant-googlecode Ant task. Since Spray is hosted et Eclipselabs it needs specialized setup, which is described on thisWiki page .
The upload of files to the project homepage is defined in the release-promote-gcupload target.
<taskdef classname="net.bluecow.googlecode.ant.GoogleCodeUploadTask" classpath="lib/ant-googlecode.jar" name="gcupload" /><gcupload username="${gc.user}" password="${gc.password}" projectname="spray" uploadUrl="https://uploads.code.google.com/a/eclipselabs.org/upload/spray" ignoreSslCertificateHostname="true" filename="${repository_root}/docs/org.eclipselabs.spray.doc.dev/docs/pdf/SprayDeveloperGuide.pdf" targetfilename="SprayDeveloperGuide-${version_main}.pdf" summary="Spray ${version_main} Developer Guide" labels="Featured, Type-Docs, OpSys-All" />
Setting version
The target set-version queries the user for the version to set for the current and next Spray release. The valuesentered will be stored in the release.properties file, which is read by the script on executing.
The values entered here will be taken to make replacements in the artifacts. This is done by search & replace usingregular expressions. Note that there is Tycho Versions Plugin which is meant to be used in such a context, but weare not using it. In the past we experienced problems using this plugin, especially it was not that easy to do thereplacements in all places that we need.
Dry run
The release.properties file contains a property dryrun. When set to true any upload action will not beperformed. What actually would be performed is printed out as a message with prefix ***DRYRUN***.
However, the script still commits to the repository. But since this all happens locally this can be rolled back. Seenext section for details.
Roll back
During the performance of a release, especially when evolving the release process, many things can go wrong.The release script creates a tag named release-init before doing any modifications to the repository. To resetthe repository to this state call the release-rollback target.
65
Maven repositories
Cloudbees provides a snapshot and release Maven repository for each project. The repository are accessible viaWebDAV, so they can be mounted on your local system. The URLs are:
• https://<USER>@repository-spray.forge.cloudbees.com/release• https://<USER>@repository-spray.forge.cloudbees.com/snapshot
These repositories are configured in the <distributionManagement> section of the Parent POM.