1.1. Overview
OSGi is a specification of a service and module platform in Java at runtime. The OSGi specification has several parts, the core of the OSGi specification defines a component and service model. This component model allows to activate, de-activate, update and de-install existing components and services and to install new components / services dynamically.
The smallest unit of modularization in OSGi is a bundle. OSGi defines a registry which bundles can use to publish services or register to other services.
The key features of OSGi can get summarized as:
-
Modularization
-
Runtime Dynamic
-
Service Orientation
In the authors personal opinion the strongest feature of OSGi is that you can define which package of your Java Projects should be visible to other Java projects. This way you can effectively control which Java classes in these projects can be used, e.g. define your API.
OSGi has several implementations, for example Knopflerfish OSGi or Apache Felix. Eclipse Equinox is currently the reference implementation of the OSGi specification.
Eclipse Equinox is the runtime environment on which the Eclipse IDE and Eclipse RCP application are based. In Eclipse the smallest unit of modularization is a plugin. The terms plugin and bundle are (almost) interchangable. An Eclipse plugin is also an OSGi bundle and vice versa.
The OSGi specification defines the OSGi bundle as the unit of modularization. A bundle is a cohesive, self-contained unit, which explicitly define its dependencies to other modules / services and explicitly defines its external API.
OSGi bundles are .jar files with additional meta information. This meta information is stored in the folder "META-INF" in the file "MANIFEST.MF". MANIFEST.MF is part of a standard jar specification. Any non-OSGI runtime will ignore the OSGI metadata. Therefore OSGi bundles can be used without restriction in non-OSGi Java environments.
Each bundle has a symbolic name which is defined via the property "Bundle-SymbolicName" in the MANIFEST.MF. Convention is that this name starts with the reverse domain name of the author of the bundle, e.g. "de.vogella.myfirstbundle".
Each bundle has also a version number in the property "Bundle-Version". This version number and the symbolic name uniquely identify a bundle in OSGi. The OSGi runtime can load the same bundle with different version numbers.
Via MANIFEST.MF a bundle can define its dependency to other bundles and services. A bundle can define that it depends on a certain version (or a range) of another bundle, e.g. bundle A can define that it depends on bundle C in version 2.0, while bundle B defines that it depends on version 1.0 of bundle C.
If a class wants to use a class from another bundles this dependency must be defined in the MANIFEST.MF, otherwise you will receive a ClassNotFound Exception. This restriction is enforced via a specific OSGi classloader.
MANIFEST.MF also defines the Java classes which should be available to other bundles as public API. This definition is done based on the packages name. Classes which are not exported via the MANIFEST.MF are not visible to other bundles. This restriction is enforced in OSGi via a special Java class loader. Access to the restricted classes is not possible, also not via reflection.
A bundles can register and use services in OSGi. OSGi provides therefore a central registry for this purpose. A service is defined by a Java interface (POJI - plain old Java interface).
Access to the service registry is performed via the class BundleContext. OSGi injects the BundleContext into each bundle during the startup of the bundle. A bundle can also register itself to the BundleContext ServiceEvents which are for example triggered if a new service is installed or de-installed.
OSGi is responsible for the dependency management between the bundles. These dependencies can be divided into:
-
Bundle (Package) Dependencies
-
Service Dependencies
OSGi reads the manifest.mf of a bundle during the installation of the plugin and ensures that all dependent bundles are also loaded if the bundle is activated. If the dependencies are not meet then the bundle is not loaded. Bundle / package dependencies are based on dependencies between standard Java objects and in case OSGi can not resolve all dependencies this results in a ClassNotFoundException.
As service in OSGi can be dynamically started and stopped, therefore the bundles must manage these dependencies themselves. The bundles can use the service listeners to get informed if a services is stared or stopped.
With the installation of a bundle in the OSGi runtime this bundle is persisted in a local bundle cache. The OSGi runtime is then trying to resolve all dependencies of the bundle. If all required dependencies are resolved the bundle is in the status "RESOLVED" otherwise it is in the status "INSTALLED". If several bundles exists which would satisfy the dependency then the bundle with the highest version is taking. If the version are the same then the bundle with the lowest ID is taken. If the bundle is started its status is "STARTING". Afterwards it is "ACTIVE".
The following is an example of a MANIFEST.MF.
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Popup Plug-in
Bundle-SymbolicName: de.vogella.rcp.intro.commands.popup; singleton:=true
Bundle-Version: 1.0.0
Bundle-Activator: de.vogella.rcp.intro.commands.popup.Activator
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
0 comments:
Post a Comment