The Concept behind Region Bundle Projects

About Dynamic Bundle Projects

This is a description of the concept behind an implementation of a bundle manager, named the InPlace Activator, handling the life cycle and relationship between OSGi bundles and  Eclipse bundle source projects.

The use case is that when you save your bundle project, the save triggers a build, which automatically triggers an update loading the new compiled source into a bundle, and finally executes (start) the bundle on the platform where the source project resides.

This feature – Compile and Run on Save – brings a new dynamic programming environment normally associated with interpreted languages, where each repetitive save/compile/run cycle should be a smooth and fast one step user experience.

The Bundle Project and the Workspace Region

A bundle project has the following characteristics:

  • Is a member of a workspace region, where the set of region bundle projects is a subset of the projects in a workspace.
  • For a project to be a member in a region, and thus called a bundle project, the following must be satisfied:
    • Has the java and plug-in nature enabled, implying the presence of a manifest file.
    • The project is open and accessible.
    • There is an unconditional one-to-one bidirectional relationship between the project and its bundle.
    • A shared key (symbolic name and version) and a common location identifier must represent the implemented relationship between the project and the bundle.

All other workspace projects (e.g. pure java projects, closed projects, C++ projects, …) and external bundles (e.g. jar bundles) are excluded from the region.

The relationship between Workspace, Region, Bundle Projects and External Bundles is illustrated in the following simplified figure:

Workspace Region

Region Membership

Bundle source projects can enter and leave a region. This happens when a project is Created or Deleted. A project is Created when imported, opened or created manually (usually by using the Plug-in Project wizard or a template) and Deleted when closed or deleted from the workspace. Update and Rename does not alter the membership status in a region. This covers all CRUD operations on a project related to its region membership.

Activating a Region and its Bundle Projects

A region is activated when at least one of its projects are activated. An activated project is assigned a bundle-project nature, binding a behavioral and structural relationship between the project and its bundle. Right after the assignment of the first project, its associated bundle is resolved and all deactivated project members are installed. When the last project in the region is deactivated, its nature is removed and all the bundle projects in the region are uninstalled.

In a deactivated workspace region all actions on projects are ignored, except for updating any displayed (e.g. in a property page) status information (e.g. renaming a project) about bundle projects.

Execute and Isolate Project Operations and Bundle Commands

CRUD operations can affect the membership of a project in a region and the state (activated or deactivated) of a region. In the same manner, a bundle command can change the state of a bundle project and thus the state of a region.

Uninstalling a bundle project from an external source (e.g. the Host OSGi Console) in an activated region violates the consistency of an activated region where all deactivated bundles must be in state installed and activated bundles must be resolved. In such cases, actions are taken to maintain the consistency.

The following rules apply for project operations and bundle commands in an activated region:

  • It is allowed to Refresh, Update, Start and Stop activated bundle projects. These commands does not affect the state of an activated region
  • It is not allowed to Resolve a deactivated bundle project. This implies that all commands that require a resolved bundle will be unavailable. It requires a resolved bundle to Start  and Stop a deactivated bundle project. Refresh and Update are allowed on installed (deactivated bundle projects) bundles.
  • It is not permitted to uninstall a bundle in an activated region. When uninstalling a bundle project, activated or deactivated, the region must either be deactivated or the uninstalled bundle must be installed (deactivated bundle project) or resolved (activated bundle project) to maintain the definition of an activated region.
  • If a project is created by importing or opening it, and the project is in an activated (has the bundle-project nature enabled) mode in a deactivated region, the region is activated and the activated bundle project is resolved. If the bundle project is in a deactivated mode the bundle project is installed.
  • If an activated bundle project is deleted by closing or deleting it and the bundle project is the last activated project in the region, the region is deactivated.

When deactivated, the region is passive and does not respond to any bundle commands. This defines a behavioral border between region bundles and external bundles where bundle commands are isolated to an activated region and any external bundle command in a deactivated region is allowed.

Composite Bundle Commands

Based on the concept of a region, a set of composite bundle commands should follow naturally.

Activate is a composite command, enabling the bundle-project nature before installing, resolving and starting a bundle project. If this is the first activated project, all remaining deactivated bundle projects are installed. In the same manner Deactivate, disables the bundle-project nature and unresolves the activated project moving the bundle project to state installed. If this is the last activated project, all bundle projects are uninstalled and refreshed.

Dynamic Bundle Projects

In this context, dynamic means that a bundle should respond to changes in its corresponding source project. A detour is to uninstall and then install, resolve and start an activated bundle after its project has been built. The composite Reset command does exactly this, although its purpose is to manually request for a clean region state.

When first activated, any changes in the project is captured and is reflected in the running instance of the bundle. The solution is to use the OSGi Update command, which in many ways is a composite command in itself, unresolving the bundle before it is updated. Activated bundle projects are by default updated automatically behind the scenes in concert with the Automatic Build option when a project is saved. This is accomplished by utilizing the bundle-project nature and the OSGi resolver hook. To control the update frequency of a bundle project there is an option to update the bundle manually from the UI after it has been built.

Bundle Closures and Dependencies

When the IDE starts up and shuts down bundles are resolved/started and stopped/unresolved in dependency order. The order is configurable by setting start levels, assigning lazy activation policies on bundles and the like. For bundle projects, this must be handled continuously when source projects are changed and when entering and leaving a region. Bundle projects enter a region at IDE startup and when Created and leaves a region at shutdown and when Deleted. Changed projects stay in the region by being updated and returning to the same state as before update, but may introduce new dependencies (e.g. adding a package to the Import-Package header).

The set of bundle projects in a region contains one or more partitions or closures, where each partition is a directed acyclic graph and the dependency relation between bundle projects in the graph is defined by different (e.g. Import-Package and Require-Bundle directives) headers in the manifest file. Depending on the direction and scope of a dependency a partial dependency order of bundle projects is constructed to be included in a bundle operation to execute. Thus it is possible to traverse and sort the set of region bundle projects in dependency (e.g. requiring or providing) order, based on a random set of initial bundle projects.

As mentioned, a closure defines a subset of dependent bundle projects in a region. For instance, a Requiring Closure is constructed from an initial set of bundles that directly and indirectly (transitive) requires capabilities from other bundle projects in a region. Inversely, the Providing Closure is constructed from an initial set of bundles containing bundles that directly and indirectly (transitive) provides capabilities to this initial set of  bundle projects in a region.

Dependencies between uninstalled bundle projects are obtained by examining the manifest file of each bundle project or utilizing the Eclipse resource API to obtain this information. For installed and resolved bundles – that is in an activated region -, the OSGi wiring API is used.

In principle, the only type of closure that exist between region bundles and other external (non member) bundles (e.g. jar bundles) is the Requiring Closure. Therefore, external bundles, does not require, but only provide capabilities to region bundle projects. This defines a structural dependency border between region bundle projects and external bundles.

The InPlace Bundle Activator

The definition of a behavioral and a structural boundary for a region as a set and bundle projects as members provides a simple model for implementing a bundle manager. The heavy lifting is done by the Eclipse API’s grounded on the Equinox OSGi implementation which provides the mechanisms to manage OSGi bundle projects as components in a dynamic way.

Thanks for reading

Dynamic Bundles in Eclipse

Activating, or starting, a bundle while you are in the middle of an Eclipse session is both tempting and scary at the same time. It offers some great possibilities and at the same time it may mess up things in your IDE.

What about installing and uninstalling jar bundles without restarting your IDE or just run your source plug-in project in the same instance of Eclipse as you code without spawning a new instance each time you do a minor change in your project.  This will obviously save time and give you a tighter coupling between the source project and its running instance.

This feature – Compile and Run on Save – brings a new dynamic programming environment normally associated with interpreted languages, where each repetitive save/compile/run cycle is a smooth and fast one step user experience. The scenario is that when you save your plug-in project, the save triggers a build which then automatically triggers an update loading the new compiled source which then ultimately shows up in the current runtime instance of the plug-in in the IDE. Is this possible? Yes, but with a few limitations and some things to watch up for.

The first and most fundamental requirement is that plug-ins must be dynamic aware. This question is answered in an excellent way in Chris Aniszczyk article on dynamic aware bundles. In short this means that resources allocated on behalf of or by an activated bundle should be released when the bundle is stopped or unresolved.

The second question is whether Eclipse itself as an IDE is ready for dynamic bundles. How does Eclipse behave when bundles are activated and deactivated during a session?

These two questions are the topics of the rest of this blog. A bundle manager plug-in called InPlace Activator is provided (which can be downloaded at the end of this blog) to gain some experience, using dynamics in Eclipse. Despite the garbage collection problem and some other challenges in Eclipse, the future seems to be dynamic for plug-ins and bundles.

A Dynamic Component Model

The OSGi framework specification forms the basis of the Eclipse runtime. OSGi is a module system that implements a dynamic component model. Bundles can be installed, resolved, started, stopped, updated and uninstalled without requiring a reboot of the framework or as in this case a restart of the IDE hosting the very same framework.

This implies that Eclipse, beyond being compliant with the OSGi framework specification, could support the dynamics of bundles from within the IDE without rebooting. For this to work both OSGi bundles and plug-ins must be dynamic aware. The Eclipse stack is, but third party plug-ins and bundles may not be. OSGi bundles should, and are more and more, implemented with dynamics in mind.

Bundles and Plug-ins

In most cases it is not necessary to distinguish between plug-ins and bundles, but we need it here to pinpoint at which layer in the Eclipse stack limitations have been identified. OSGi was designed with dynamics in mind. Eclipse implemented OSGi as part of its stack as from version 3.0 but was initially designed for static plug-ins.  Static in this context means that it is assumed that plug-ins are installed and started at startup of Eclipse and stopped and uninstalled at shutdown.  The following simplified figure illustrates the difference between a plug-in and a bundle.

A plug-in is always a bundle but a bundle is not always the same as a plug-in.  A bundle first becomes a plug-in when it depends on the Eclipse core runtime plug-in (org.eclipse.core.runtime) and other plug-ins indirectly through the Eclipse runtime plug-in.  If the bundle in addition make contributions to the workbench it also becomes dependent on the standard UI framework plug-in (org.eclipse.ui) and its derivates.  A pure OSGi bundle is only dependent on the OSGi framework (and the JRE).

Limitations have been found in plug-ins that make contributions to the workbench using the command and action set extension points. No known limitations have been found when using the Eclipse core runtime or OSGi bundles.

What are the limitations?

Limitations identified so far are in the top layer and related to action sets and the command framework. Others may of course exist, and probably do, so any feedback on undiscovered bugs in this category is more than welcome.

The Eclipse stack is as mentioned dynamic aware but there are some issues concerning dynamic updates of IDE UI elements and navigation. Contexts definitions for action sets are not always updated after bundles are resolved dynamically. A workaround is implemented in the InPlace Activator for actions sets (See Bug 295662)  when plug-ins using the command framework is resolved and unresolved dynamically.

There is also a problem in the menu manager in version 3.x when dynamically populating changes committed in the Customize Perspective dialog (you bring it up from the Window | Customize Perspective  … menu entry) after a plug-in using the command framework has been dynamically resolved.

Lastly, if you plan to activate plug-ins that makes contributions to the workbench using extensions, version 3.7-3.8 is recommended. Plug-ins activated dynamically works as expected in version 4.x except for its lack of responsiveness to dynamic updates of the Eclipse UI. Please see Bug 405107.

Stale References

A general issue in OSGi is the absence of separate object spaces to isolate bundles. For bundles that are not dynamic aware this leads to inconsistencies when bundles are stopped. The IDE or in general any platform cannot ensure that objects from a stopped bundle will no longer be referenced by active code (stale references) leading to memory retention and inconsistencies (e.g., utilization of invalid cached data) that can introduce faults in the system. The same applies to extension points which is constructed on top of OSGi with its own dynamic plugin mechanism.

Give it a try!

The InPlace Activatior plug-in is a dynamic bundle manager that allows you to activate, update and deactivate plug-ins and bundles on the fly from within the IDE. To give it a try, install the InPlace Activator plug-in and activate any of your plug-in source projects or create a new plug-in or a pure OSGi bundle from the plug-In creation wizard and activate the created project in-place. Try changing some source and build the project. The changes should then be reflected in the newly updated bundle as long as the bundle is activated.

If you work with bundles that are dependent on each other they will be activated and deactivated in dependency order to avoid stale refrences. But most important is the responsibility of the developer to avoid stale references through best coding practices.

Hopefully a dynamic environment where bundles come and go will in the near future be the natural way of thinking, and not the exception.