Categories: Programming, Java, OSGi
Overview
The Eclipse Rich Client Platform (aka RCP) is a framework for creating graphical applications consisting of multiple nested windows, menubars, etc.
The Eclipse IDE is just one of the kinds of applications that can be built on the RCP. Actually, Eclipse RCP’s architecture is a core with plugins, and what functionality the end application provides (Java IDE, C++ IDE, report designer, stock management tool, etc) is simply a matter of which plugins are present.
The architecture behind Eclipse has gone through several revisions; the change from version 3 to version 4 was a major one. The Eclipse4 (aka E4) architecture has proved very successful, and how it is put together is rather interesting. This article looks at some of the principles behind the framework. The topics of building and testing Eclipse RCP applications are also briefly discussed.
There are many books and articles on Eclipse; this article is intended to cover the “big picture” so that information elsewhere which focuses on particular details can be understood in context.
The draft version of this article covered many architectural features of Eclipse as I was unable to find any documentation on Eclipse at that level. As it was almost finished, I found an excellent article on Eclipse architecture by Kim Moir which presents similar information. Moir is an expert on this topic, while I am certainly not, so I suggest you read that article first.
The content below may be useful for a developer creating an EclipseRCP-based application or a plugin for use with the Eclipse IDE.
Background
Eclipse has always had a “core plus plugins” architecture that allowed the system to be extended.
The E3 architecture (ie Eclipse v3.x) introduced a major change, using OSGi for the plugin architecture rather than the previous Eclipse-specific plugin framework. This change also included a new system for provisioning (selecting, downloading and installing) OSGi-based plugins, called P2.
The E4 architecture (ie Eclipse v4.x) introduced additional significant changes: extensive dependency injection and an application model (a datastructure representing the high-level user-interface layout).
The first release of an Eclipse IDE based on E4 was “Juno”, in June 2012. As of late 2015, Eclipse has reached version 4.5 - ie is still based on the same general architecture as the first 4.0 release.
The OSGi core (Eclipse Equinox) provides dynamic loading of modules (plugins), dynamic lookup of services, etc. If you are not familiar with OSGi, then I suggest reading this article on OSGi first. If you are not familiar with the Eclipse P2 plugin manager, then you should also read this article on P2.
The “bootstrap code” used to start an Eclipse-based application (including the Eclipse IDE) does little more than load the Equinox and P2 libraries, and pass it a P2 “features” file. P2 scans its local repository of OSGi bundles (jarfiles) to find the required packages, and invokes the OSGi “loadBundle” method in Equinox to load the required jarfiles.
Building a custom application on Eclipse RCP v4 therefore involves:
- implementing one or more custom plugins (ie OSGi bundles which use Eclipse APIs or Eclipse annotations);
- writing one or more feature configuration files;
- defining an application model (as an XML file);
- and generating the “executable product”, which is just a simple wrapper that starts the eclipse core with the specified application model and features.
The Eclipse IDE - an Initial Overview
An Eclipse IDE install includes a “feature” configuration file that defines a “workbench feature” as a specific set of plugins (osgi bundles, ie jarfiles) which provide UI classes and other helpers useful for an IDE-like application. Plugins which are intended to be used as part of an IDE usually make significant use of the workbench APIs.
The same Eclipse RCP framework used to build the Eclipse IDE can be used to build other similar applications. The concept of an application model, plugins, UI parts, dockable windows, perspectives, etc. are all reusable - just the standard editor and view classes are specific for code-development, and they are implemented as plugins that do not need to be loaded.
RCP applications which are not “IDEs” typically do not use the workbench plugins (ie don’t load the workbench feature).
The release of E3 included backwards compatibility support so that older Eclipse-based code could still run. The E4 release has similar backwards-compatibility code for E3. Sadly, many books, sites and much documentation out there still recommends old approaches for which there are improved solutions.
As noted previously, Eclipse 3.x+ is built on a standard OSGi framework. Sadly, while Eclipse has been under heavy development, so has OSGi. As a consequence of this, and also due to the need for backwards compatibility with earlier Eclipse code, there are a number of Eclipse-specific APIs which duplicate functionality available in standard OSGi.
Further implementation details about the Eclipse IDE are discussed later.
Eclipse Plugins and Features - an Initial Overview
An Eclipse plugin is an OSGi bundle, ie a jarfile with an OSGi-compatible META-INF/MANIFEST.MF. The jarfile usually also contains an Eclipse-specific META-INF/plugin.xml.
A plugin is the smallest deployable unit. A feature is a set of 1 or more plugins. A feature definition has an associated “url” pointing to the repository from which plugins associated with this feature can be downloaded.
A product is the eclipse core (ie the plugin loader) plus one or more features. This is then an “executable” application.
Plugins may contain code or data (eg helppages, icons..).
Just about every single feature or plugin depends on plugin “org.eclipse.core.runtime”.
A feature may “import” a plugin (ie declare a dependency on it), or “provide” a plugin. The “provide” form should be used when this feature is the only way the plugin can be installed; “import” is used when some other feature is expected to provide the bundle.
OSGi also supports the concept of “fragments”, which are jars that are “optional extensions” to real bundles; when the referenced bundle is loaded, the associated fragments will also be loaded. But a fragment can’t be loaded on its own. Bundle fragments are often used in Eclipse RCP.
A plugin can (via its metadata) add options to menubars, icons to toolbars, handlers that get triggered on specific “hot key” sequences, etc. This makes each plugin truly “optional” and self-contained; new functionality can be added without editing any “core framework” code or configuration. I am not aware of any other UI framework that supports such modularity.
Plugin Loading
When the Eclipse RCP framework launches, the P2 “provisioning” layer tells the OSGi layer (Equinox) which jarfiles to load. Equinox analyses the MANIFEST.MF and plugin.xml files:
- For each “Require-Bundle” and “Require-Package” declaration in the MANIFEST.MF, the framework verifies that the bundle or package is available. If not, then the plugin is disabled (not yet runnable).
- When the plugin.xml defines an “extension”, then the extension-point-provider is notified that another extension is available for it; an example is the menu extension which allows a plugin to define new menus and menu-items that the MenuBarManager will then automatically integrate into the app-wide menubar. An “extension point” provides similar functionality to the Whiteboard pattern.
- When the MANIFEST.MF contains a Service-Component entry then the specified dependency-injection configuration file is registered with the OSGi Service Component Runtime (SCR). This will instantiate the specified class (service) as soon as its dependencies are available.
- When the MANIFEST.MF contains a Bundle-Activator entry then the specified class is instantiated and invoked.
Together, this functionality allows a plugin jarfile to automatically integrate itself into the surrounding framework.
This is mostly standard OSGi behaviour - except for the “extension point” behaviour of plugin.xml files. See the section on the “application model” for more information about extension points in E4.
In general, Bundle-Activator entries are discouraged because they require the classes in the plugin jarfile (OSGi bundle) to be loaded and initialised, which can take some time. An Eclipse RCP application (and an Eclipse IDE in particular) can have many plugins, some of which the user may rarely use; it is a shame to initialise every one of them on each startup. The plugin.xml is designed so that the supporting classes only need to be loaded if that menu option is selected by the user. Various other options are available to delay initialisation of plugins until actually accessed.
The Eclipse Modelling Framework (EMF)
EMF is a compile-time code generator; you declare a class and a set of properties and EMF then generates a matching Java code.
The concepts of EMF are important to understand as the UI of an Eclipse-based application can be defined via an application model - a tree of EMF objects representing menus, views, editors, etc.
Benefits of EMF:
- it can generate appropriate Factory classes for the modelled types.
- it can generate efficient serialization/deserialization code that does not depend on reflection.
- it can generate helper classes that are an alternative to using Java native reflection/introspection.
- it can ensure all property setters generate change-notification events (including changing the contents of properties that are collections - ie the properties hold a subclass of the desired collection-type which trigger change notifications).
- an EMF model can be used for purposes other than code-generation, eg generating database schemas corresponding to the model or generating documentation.
- an EMF model is not language-specific; the same model can be used to generate code (eg for serialization/deserialization) in multiple languages
Serialization is particularly important in an OSGi environment, as external deserialization mechanisms such as JAXB don’t work well when the classes being created/introspected are private to an OSGi bundle. It is more reliable for the objects themselves to provide a serialization method that they then internally implement - and in the case of deserialization, for the Java package to provide appropriate factory methods.
The change-notification facility can be used for many purposes, including implementing undo/redo support, sending just object diffs across a network, and driving database persistence (knowing which fields have changed).
Drawbacks:
- code generation never works well with IDEs (ie hand-written classes stored under version control which refer to generated classes will not compile until the generation phase has completed)
- the generated classes have strange base-classes from the EMF library
- collection fields in the generated classes are of strange types such as EList
- it is difficult to add real logic to generated classes; they are anemic domain models
- defining classes through a graphical UI (click, click, click) is far slower than defining them directly in Java
The Eclipse Application Model
The Eclipse application model is a datastructure which models the application user interface in a “high level” way. Like a tree of widgets, or an HTML dom, it represents parent/child relations between windows. However:
- it does not hold UI details below the level of a part; each part implementation uses traditional SWT/JFace components to build its detailed UI directly
- it holds information about some things that are not directly “renderable”, eg “command handlers” and hotkey-mappings (see below);
- it holds templates for part windows (see PartDescriptors below)
- it holds templates for dialog windows
An initial application model (xml format) is read from a file to create the application’s default state on startup, similar to how loading an HTML file results in a DOM being built. And just as Javascript can modify the DOM of an HTML document at runtime, the eclipse application model can be manipulated by Java plugins at runtime (eg to add/remove/move windows).
The application model includes:
- the main menubar, with its default entries.
- a list of windows, starting from the global window. Windows have children, which may be layout components; for example the PartSashContainer implements either a horizontal or vertical tiled layout, while the PartStack container provides a tab-like layout (where child components are stacked on top of each other).
- a list of global “command handlers” that can be triggered via menu-options, shortcut keys, etc.
- a list of top-level PartDescriptors, which are sort of “templates” or “factories” for Java classes implementing editors or views. These define:
- how to instantiate the various windows (eg ant configuration editor, junit executor).
- what menu-entries should be added when such a part is “active”, and what shortcut-key handler classes should be installed.
Runtime code uses the PartDescriptors to “instantiate a part” based on a descriptor, ie create the part implementation and its appropriate child objects and wire them together using injection. These are commonly used when multiple instances of a part can be opened, eg multiple java-code-editor windows.
The application model also holds template-definitions for standard application dialog windows; code can instantiate these standard windows without needing to know the exact implementing class (which is configured in the template).
The code that loads/handles/renders the application model is itself defined as an Eclipse feature : “org.eclipse.e4.rcp”. You can find the definition of this feature in your $(ECLIPSE_HOME)/features/org.eclipse.e4.rcp_{version}/feature.xml file.
The classes for nodes (objects) in the Eclipse application model happen to have been defined using EMF (and the concrete implementations generated by EMF). As noted in the section on EMF, the emf project provides an “emf.liveeditor” editor part which can browse any tree of EMF-generated objects (using the EMF introspection data). Therefore the standard “emf.liveeditor” part can be used to browse the application model; if the e4 tools plugin has been installed then alt-shift-F9 brings up the liveeditor on the current Eclipse application (rather like firebug can explore the DOM tree for firefox’s chrome itself). Note that the types in the application model are not extensible by the user. However these types point to “implementations” for handlers, views, editors, etc. which live in OSGi plugins.
Not all components in the application model are necessarily rendered at the same time; some may be marked “hidden”. As an example, within a parent “Perspective Stack”, typically only one of the child perspectives (ie set of windows) is rendered. Some menu items might also be hidden depending upon application context.
A “presentation engine” creates the widgets that correspond to the EMF application model; the default engine uses SWT. This separation theoretically allows significantly different renderings of the same application model.
As is usual with EMF, the application model objects are “simple data transfer” representations, without any significant logic. In the model-view-controller structure, they act as the model that is updated as the user moves windows, opens new perspectives, etc. Almost all logic related to the model is held outside, in the “controllers” which are recreated on application startup.
The application model is not used just at application startup; code can gain access to the MApplication object which is the current model (usually by dependency injection), and then modify its properties. Adding a new MWindow child to the application will display a new window for example. Adding an MPart to the child list of an MWindow already in the application model will insert a new view or editor into an existing window.
The primary benefit of an Application Model is that a view or editor can in many cases be implemented without using any eclipse-specific interfaces or types - just plain SWT/JFace logic. The application model effectively acts as the binding from the eclipse-specific world to the implementations. A “part definition” in the application model may contain the name of a class that implements that part; when that item in the application model must be rendered then the specified class is instantiated. Dependency injection and annotations are heavily used to allow the application-model and implementations to integrate properly.
In the previous E3 architecture (without an Application Model), views/editors/commandhandlers/etc must implement eclipse-specific interfaces.
Avoiding heavy use of eclipse-specific types in plugin code makes the code more portable/reusable elsewhere, and more easily unit-testable.
Eclipse plugins can define “application model fragments” which get merged into the main application model, eg to add menu items to the global toolbar. This is the E4 equivalent of the earlier “extension point” mechanism. See later for more information on this.
Dependency Injection
Eclipse has (sadly) invented its own kind of dependency-injection framework. Injection is available:
- on components created by the application model
- on components defined declaratively in plugin.xml or SCR files
- programmatically via interface IEclipseContext
When instantiating an object given a class-name and a base “context”, Eclipse uses introspection to look for standard javax.inject annotations on constructors, fields and methods, and then searches for matching objects in the context. The context depends (not surprisingly) on the circumstances which triggered creation of the class; each part typically has a context which is used when creating children of that part.
If the injection annotation does not specify a “name”, then the fully-qualified name of the required type is used as a key to look up the necessary object. If a name is specified, then that is used as the key.
In a slightly unusual twist on injection, Eclipse keeps track of values injected into fields (and methods?), and if they change, then injects the new value into existing objects.
Lookup is done by following a chain of MContext objects until the first match is found; the root context is the set of OSGi services; parent windows and perspectives have their own MContext objects (and therefore can override the definition for a specific name). For example, injecting an object of type @Composite will always pass the parent container of the part.
Eclipse dependency injection also supports standard lifecycle annotations such as @PostConstruct, @PreDestroy, @Focus, @Persist (save-file), @PersistState. To avoid requiring plugin code to extend Eclipse interfaces, other interesting annotations are supported such as @Execute (command handler), @EventTopic (subscribe to events). If the annotated methods declare parameters, then they are located as for dependency injection.
See:
Eclipse Rendering
Eclipse has always used the SWT graphics toolkit rather than Swing or AWT. It also extensively uses the JFaces library which adds functionality on top of SWT.
Application model objects often have an associated SWT widget, and parts create SWT widgets which are children of the SWT widget of their parent application model object.
Commands and Handlers
A “command” is simply data that specifies an abstract action that can be performed, eg “save”. Menu options specify a command to run, as do keybindings, toolbars, etc. A command has no “implementation”; it is really just an object with a unique string id. The string can be anything, but is by convention structured like a java package-name. There are a set of standard command-strings, such as “org.eclipe.ui.file.exit” which should be used to indicate a “quit application” command.
A command is then mapped to a “handler” class via a handler declaration in the Application Model; when the command is “triggered”, the handler is executed.
The standard set of commands is defined in org.eclipse.ui.IWorkbenchCommandConstants
.
Using commands is optional; it is possible to connect a menu-item, toolbar-icon, or hotkey directly to a Handler that should be executed. Using a command simply allows the same handler to be invoked via multiple paths.
Event Brokers
Eclipse has its own built-in event-broker (even though OGSi already has one). See IEventBroker.
The event broker can be useful for coordinating various components within an application, eg an update in one custom window could post an event which other components can subscribe to.
Eclipse RAP
The RAP project implements a new set of UI widgets which have exactly the same interfaces as the original “native” SWT/JFace widgets, but which instead generate HTML and javascript, and which implement “listener callbacks” via AJAX calls from client browser to server. This is a significant amount of work for the RAP team, but does allow web-enabled applications to be developed using the same approach as for RCP applications. In fact, with a little care it is possible to implement an application that can be compiled against either the native widget-set or the RAP widget-set.
Compiling with RAP generates a .war-file that can be deployed inside a servlet container! HTTP requests are mapped into the same callbacks that the custom plugins would get in a desktop environment.
RAP is not as efficient as a native-for-the-web application; the SWT/JFace APIs were designed for an environment where listener callbacks are cheap. An RAP application will therefore not scale up to large numbers of concurrent users, and it is more heavily affected by high latency between client and server. Nevertheless, in appropriate deployment environments it does function well, and makes it reasonably easy to build sophisticated multi-window-style applications.
Unfortunately the initial development of RAP development, though open-source, was primarily driven by one company. How up-to-date the RAP libraries are with respect to new Eclipse releases varies significantly depending upon that company’s priorities. Development of RAP for E4 was long delayed. However from information on the project, it appears that RAP is now available for E4, and is considered a “core” project now.
Updating and Adding Features
Eclipse includes the P2 provisioning platform, ie a “bundle management” library. Its primary function is to take a set of “desired plugins” and determine which other plugins must also be loaded to satisfy their transitive requirements. This is a non-trivial problem, given that dependencies can be expressed on java packages rather than bundles, can include version-ranges, and other constraints.
P2 is used on each boot to select the set of plugins that are “loadable” by the OSGi container from the pool of available bundles. The same library can be used to determine which plugins from a remote repository are installable (and which additional plugins are required).
Due to the use of OSGi, new plugins can also (usually) be loaded while an application is running, and sometimes be unloaded without having to restart the application (depending on how well the code has been written).
See this article for more information on p2.
Oomph!
Eclipse caches plugins under its install directory. Each workspace then specifies the plugins it needs. With a workspace active, new plugins can be downloaded and installed, which puts the jarfiles into the install-wide cache and then enables them just in the current workspace. Other existing workspaces are not altered.
It is good that other workspaces don’t get updated (each is independently “locked” to a set of plugins at specific versions). However on the negative side, this means that bugfixes/upgrades don’t get applied until the user selects “update” in each workspace.
What is more problematic is setting up the set of plugins for each workspace. A new workspace will by default inherit all available plugins.
This is why there are separate download-bundles for eclipse-for-jse, eclipse-for-jee, eclipse-for-c, etc. Not only are the appropriate plugins included, they are also enabled.
The number of different eclipse download bundles has been growing to an unmanageable value. In addition, the “autoupdate” feature of Eclipse is somewhat flaky, particularly between major releases. When a major release comes out, it is generally better to download a whole new distribution and start from scratch.
The oomph project is a tool which takes a config-file specifying the desired set of eclipse plugins, and then builds an appropriate system. This has been used to create a generic “eclipse installer”, where the initial download is just enough to get oomph running, and then the user chooses an appropriate configuration and oomph downloads and enables the appropriate plugins. Yes, this is roughly what the builtin eclipse installer should be doing anyway, but apparently oomph does it better. Like the builtin installer, most of the hard work is done by the “p2 director” module.
Oomph also integrates into a running eclipse application to “track” the installation/update of any plugins. It is therefore possible to “export” the current state of an Eclipse environment as a new oomph config-file, which others can then use to replicate the same setup.
Oomph is not just for eclipse-ide users; it is also useful for anyone building an eclipse-rcp application.
Sadly, the official oomph documentation is extremely poor, and has been for a long while.
See:
- Eclipse.org: Oomph
- Winklerweb: Creating Custom Installations with Oomph
- Eclipse wiki: oomph authoring
Extension Points
The plugin.xml file allows the developer to specify “extension points” and “extensions”. These are roughly equivalent to use of the whiteboard-pattern in OSGi, ie:
- an extension-point represents some service which wants to _find all other services implementing interface X; and
- an extension specifies a service that provides interface X.
This provides “dynamic discovery” of all services of a specific type. One standard use is to find all plugins that wish to register a menu item; there is an official extension-point for registering menu items and any plugin which wants to provide a menu-item when loaded then puts a matching “extension” element in its plugin.xml file.
The recommended way to use extension-points in E4 is for the plugin to use something like the following to enhance the global application model:
<extension id="id" point="org.eclipse.e4.workbench.model">
<fragment uri="fragment.e4xmi"/>
<processor beforefragment=”true” class=”...”>
</extension>
The org.eclipse.e4.workbench.model extension-point is a generic way of inserting data into the global application model. The specified fragment then specifies a sequence of elements to insert, and uses an xml-element-id from the global application model to specify where they are to be inserted. As alternative, a processor-class can be instantiated to modify the application model programmatically. This allows menu-items, parts, and any other item supported by the application model to be integrated. In E3, there were many different extension-points for integrating with the surrounding environment.
In E3, extension-points were simply a generic “whiteboard” mechanism for one plugin to “find” (or be notified of) all other plugins that support a particular interface. This functionality still exists in addition to the application model approach above.
Inactive Menu and Toolbar Items
The toolbar/menus defined in an E4 application model (or E3-style in the plugin.xml) may include items which are not relevant at all times. The definitions therefore include an optional “is-active” test clause; this is evaluated at appropriate times (eg when focus changes).
Eclipse IDE-specific features
Overview
This section looks at some features within the Eclipse IDE relevant for the development of standalone Eclipse-RCP applications, or for development of additional plugins intended for use within the Eclipse IDE.
See:
The Eclipse Plugin Development Environment (PDE)
Eclipse plugins are best developed using the help of the “E4 Plugin Development Tools” (installable in the usual manner). The IDE menu option “File|New” now has a “Plugin-Product” option that launches a wizard to configure a new project for development of a plugin. If you choose “RCP application” within the wizard, you will also need to have the RCP support installed.
When a new “plugin project” is created in the Eclipse IDE using the PDE, the following standard Eclipse-IDE files are created:
- dot-project - a standard Eclipse IDE file that specifies how the project is displayed within the IDE (name, etc), which plugins to use to build the code (eg JavaBuilder)
- dot-classpath - a standard Eclipse IDE file that specifies which libraries to put on the classpath during compilation. Additional items will be added based on the target, and the set of required pugins defined within the IDE. When launching the application from within the IDE, the launch configuration specifies additional libraries.
- dot-settings - directory containing per-ide-plugin configuration such as window layouts
- build.properties - specifies additional resources to be included when building a “deployable product”. Also specifies compiler-related settings like target JVM version and arbitrary compiler-args.
and the following plugin-project-specific files are created:
-
{projname}.product
- specifies which components to include when building a “standalone executable” containing this plugin. Also defines the “branding” (css, icons, etc) to be applied. - MANIFEST.MF - contains standard OSGi attributes such as the plugin’s unique id, its version, and a list of other plugins that are required at runtime
- plugin.xml - used at runtime by the Equinox framework to provide information about a plugin (jarfile) when it is loaded. In effect, an eclipse-specific extension of the MANIFEST.MF.
- Application.e4xmi - the application model, ie a user-interface definition as XML which is loaded at runtime. The E4 tools provide help working with these.
A plugin always has a list of other plugins it depends on. The developer enters this information via the MANIFEST.MF editor. Sadly, Eclipse duplicates this information in several other files:
- the dot-product file
- the launch configuration
In a somewhat odd design-choice, the editor for the MANIFEST.MF, “plugin.xml” and build.properties files have been unified; clicking on any of these files opens the same editor window. That editor window has tabs; the “overview” and “dependencies” tabs generally edit the MANIFEST.MF file while the “extensions” and “extension points” tabs edit the plugin.xml file and the “build” tab edits the build.properties file. The editor also has tabs to edit/view these three files in their “raw” format.
When developing software that consists of multiple plugins, then a separate “feature project” needs to be created. This project consists primarily of a “feature.xml” file which lists the plugins and other features that belong together in this “feature”. Options are available to generate a standalone executable, or to “publish” this configuration to a P2 repository.
Targets
When a plugin project is created, it will be compiled against a large number of supporting eclipse libraries. But which ones/versions? The answer is that by default they are the ones used by the current eclipse IDE. However a target can be selected which defines a different release of those Eclipse libraries (eg so development can occur against a stable release even when developers upgrade their IDE).
The target can be selected via menu “Window|Preferences|Plugin Development|Target Platform”. The nicest option is to select “empty” initially, then select a “software site” and point to any eclipse IDE release of your choice.
This of course affects only those libraries specified with version=”0.0.0”, ie undefined.
Eclipse IDE Project Natures
An Eclipse IDE project can have zero or more natures. A nature is basically a set of tools that get executed during the build process. As example, when a project has the “java nature”, then the java builder plugin will be invoked whenever a build is triggered.
See:
Building (Tycho etc)
Compiling the source-code and building “deployable” artifacts can be done interactively through the Eclipse IDE user interface.
Right-clicking on the project and selecting “plugin tools|create ant buildfile” will create an Ant “build.xml” file which references all the relevant dependencies and invokes the eclipse java compiler appropriately. Note that this Ant buildfile references files from the local Eclipse IDE installation, ie is not generally reusable.
The tycho project is a set of tools that allow an Eclipse plugin project to be built from Maven, without requiring any local Eclipse installation. Artifacts required during a Tycho build are retrieved from an Eclipse P2 repository. Tycho defines a set of new artifact packaging types, eg eclipse-plugin or eclipse-feature. A pomfile for a tycho build typically has no <dependencies>
section, instead deducing dependency information from the MANIFEST.MF.
The original solution that the Eclipse developers recommended for “headless builds” of the kind done by automated systems was called “releng” (Release Engineering), and is documented here. IMO, that’s pretty scary crazy stuff - tycho (for all its flaws) is a far more industry-standard way to do “headless builds”. In particular, trying to version-control the configuration of a complete Eclipse IDE install is difficult.
Some Maven repository managers have extensions that support P2 repositories, ie such repository managers can be used from Tycho builds rather than having a separate P2 repository. The commercial Nexus Pro includes p2 support by default. AFAICT, the open-source Nexus OSS version can also support P2 repositories; it just requires installing the plugins as listed in the documentation. The Eclipse Nexus Unzip Plugin also looks interesting; it is a nexus plugin that adds a new repository type suitable for P2 artifacts.
Although building plugin projects with Maven is non-trivial (requires Tycho), building standard (non-plugin) projects with Maven is straightforward; developing the maven pom.xml
is mostly a separate step from developing/compiling the code within the Eclipse IDE. Alternatively, the “m2e” plugins can be installed into the Eclipse IDE which then replaces the normal Eclipse interactive build-tools with calls to maven instead, resulting in a more consistent result between interactive and batch builds.
One significant issue with eclipse/maven integration is that maven requires artifact version-numbers to be absolute or end in “.snapshot”. Eclipse-P2 does not support the concept of “snapshot” artifact versions, instead assigning a “build version” (incrementing integer per compilation) or datestamp. In the Eclipse IDE, artifacts without absolute version-numbers are shown in form “1.2.3.qualifier”, where the literal text “qualifier” gets replaced automatically during the build process. Eclipse also shows “unspecified version numbers” as “0.0.0”.
Deploying a Plugin
To add a plugin to an existing Eclipse installation, a plugin jarfile can simply be unzipped in the appropriate location under the Eclipse install directory. However this only works if all plugins required by this plugin have already been installed.
A more elegant alternative is to upload the new plugin to a P2 repository, and then use the Eclipse “Help|Install New Software” menu to specify the location of that P2 repository and then select the plugin.
Unit and Integration Testing
An Eclipse plugin project can contain JUnit tests in the normal manner; such tests validate the behaviour of individual classes or small sets of classes.
Eclipse also provides an interesting variant of integration testing driven by JUnit. Tests can be written as a bundle fragment (ie in a separate project), and these tests can then be executed within a running eclipse container. This verifies the interaction of the plugin under test with the whole Eclipse framework.
Other Items
It appear that the Eclipse Wazaabi project is trying to extend the application model concept down into the parts themselves, where code (or a graphical editor) creates an application-model-like tree consisting of abstract containers, buttons, etc. A “viewer” then renders this model using SWT, GWT, RAP, or any other similar widget toolkit. This project is currently under development.
Useful Term Definitions
Terms:
- Editor: a single window that can render a particular file in a user-friendly way, and support modifying it
- View: a single window that concentrates mostly on displaying data (but not a specific file), eg a filesystem navigation view
- Perspective: a top-level graphical layout component, holding a set of editor and view windows.
- Working set: a collection of files or directories. A file can belong to multiple working sets.
- Application Model: a datastructure holding definitions for the initial window layout, menu items, command-handlers, etc.
- Plugin Development Environment (PDE): an Eclipse IDE with the necessary plugins to develop plugins (used for RCP development too)
Note that the word “part” is used for either an editor or a view; they are fairly similar from the eclipse application’s point of view.
References
- AOSABook: eclipse - an excellent description of Eclipse architecture up to v4.0
- Vogella: Eclipse RCP 4 RCP - Tutorial
- Eclipse 4.0 news - includes some information on the “rearchitecture” of Eclipse into its 4.x form
- EclipseSource: E4 Tutorial
- Tom Schindl: E4 tutorial
- Eclipse Tutorial