Assuming, You have already gone through the blog – AEM OSGi: All you need to know!, time to learn more about the OSGi Bundles. In the previous blog, I had just touched the topic, here, I will explain it in detail.
Bundles are the basic units of modularity in OSGi. Each bundle is essentially a JAR file containing Java classes, resources, and a manifest file. The manifest file contains metadata about the bundle, such as its version, dependencies, and the packages it exports or imports.
In a nutshell, OSGi achieves the said modularity with the help of Bundles.
What are the Key Components of a Bundle?
- Manifest File: This XML file describes the bundle’s metadata, including its name, version, dependencies, exported packages, and imported packages.
- Java Classes: The actual code that implements the bundle’s functionality.
- Resources: Additional files like configurations, templates, and images.
How do Bundles Interact?
- Dependency Management: Bundles can declare dependencies on other bundles. OSGi ensures that these dependencies are resolved correctly before the bundle starts.
- Service Registry: Bundles can register services they provide and consume services offered by other bundles. This promotes loose coupling and dynamic interactions.
- Lifecycle Management: Bundles have a lifecycle that includes installation, starting, stopping, and updating. OSGi manages these transitions.
What lifecycle does a bundle typically have?
In OSGi, a bundle goes through a well-defined lifecycle, managed by the OSGi framework. The lifecycle of a bundle typically includes the following states:
Installed -> Resolved -> Starting -> Active -> Stopping -> Uninstalled
1. Installed
- Description: The bundle has been installed into the OSGi environment, but its dependencies have not yet been resolved. At this stage, the OSGi framework is aware of the bundle, but it cannot be used because it has not been started yet.
- Implications: The bundle’s code is not yet executing, and it has not been linked with any of its required dependencies.
2. Resolved
- Description: The OSGi framework has resolved the bundle’s dependencies, meaning all required classes and packages that the bundle needs are available and linked. The bundle is ready to be started.
- Implications: The bundle is now in a state where it can be started, but it is not active yet. If the bundle’s dependencies cannot be resolved, it will remain in the “Installed” state.
3. Starting
- Description: The bundle is in the process of starting. The OSGi framework calls the
start()
method of the bundle’sBundleActivator
class if it has one. - Implications: During this phase, the bundle can execute code to initialize resources, register services, or perform other startup tasks. The bundle is not yet fully active until the
start()
method completes successfully.
4. Active
- Description: The bundle is fully active and running. It can now provide services to other bundles, and its classes and resources are available for use by other parts of the application.
- Implications: This is the main operational state for a bundle, where it performs its intended functions. The bundle remains in this state until it is stopped.
5. Stopping
- Description: The bundle is in the process of stopping. The OSGi framework calls the
stop()
method of the bundle’sBundleActivator
class. - Implications: During this phase, the bundle should release any resources it holds, unregister any services it has registered, and perform cleanup tasks. The bundle is transitioning out of the active state.
6. Uninstalled
- Description: The bundle has been removed from the OSGi environment. It is no longer available for use, and its resources have been released.
- Implications: Once in this state, the bundle cannot be reactivated unless it is re-installed into the OSGi framework.
Bundle State Transitions
- Installed → Resolved: When all dependencies of the bundle are satisfied.
- Resolved → Starting: When the
start()
method is called on the bundle. - Starting → Active: When the
start()
method completes successfully. - Active → Stopping: When the
stop()
method is called on the bundle. - Stopping → Resolved: When the
stop()
method completes successfully. - Resolved → Installed: When the bundle’s dependencies are no longer satisfied.
- Installed/Resolved/Active → Uninstalled: When the bundle is removed from the OSGi environment.
Bundle Lifecycle Summary
In a nutshell, the bundle lifecycle can be summarized as –
- Installed: The bundle is installed in the OSGi environment but is not yet usable.
- Resolved: All dependencies are resolved, and the bundle is ready to be started.
- Starting: The bundle is in the process of starting, and running its initialization code.
- Active: The bundle is fully running and providing its services.
- Stopping: The bundle is in the process of stopping and cleaning up resources.
- Uninstalled: The bundle is removed from the OSGi environment and is no longer available.
These questions are usually asked in AEM developer-level interviews. It’s good to have a grasp of this information to impress the interviewer. 🙂
What is the difference between a normal jar file and a Bundle jar file
Feature | Normal JAR | OSGi Bundle |
---|---|---|
Metadata | No special file | META-INF/MANIFEST.MF with OSGi headers |
Modularity | Not modular | Modular with package and service boundaries |
Lifecycle Management | No built-in management | Dynamic management by OSGi framework |
Dependency Management | Classpath based | OSGi service registry and package imports/exports |
Service Registry | No service registry | Can register and use services |
Versioning | No explicit support | Supports versioning of bundles and packages |
How do you create dependencies between bundle A and bundle B?
To create dependencies between Bundle A and Bundle B in OSGi, follow these steps:
- Export Packages in Bundle B:
- Bundle B needs to specify which packages it provides. This is done in the
MANIFEST.MF
file using theExport-Package
header.
Export-Package: com.example.service
- Bundle B needs to specify which packages it provides. This is done in the
- Import Packages in Bundle A:
- Bundle A needs to declare its dependency on the packages provided by Bundle B. This is done in the
MANIFEST.MF
file using theImport-Package
header.
Import-Package: com.example.service
- Bundle A needs to declare its dependency on the packages provided by Bundle B. This is done in the
- Ensure Proper Versioning:
- Both bundles should include version information in the
Export-Package
andImport-Package
headers to manage compatibility.
Export-Package: com.example.service; version="1.0.0" Import-Package: com.example.service; version="[1.0.0,2.0.0)"
- Both bundles should include version information in the
- Deploy and Start Bundles:
- Deploy both bundles to the OSGi container. Bundle A can only start successfully if Bundle B is also installed and resolved, as it depends on the packages provided by Bundle B.
- Service Dependencies (if applicable):
- If Bundle A relies on services provided by Bundle B, Bundle A should use OSGi service registry mechanisms (e.g.,
ServiceReference
) to bind to the services exposed by Bundle B.
- If Bundle A relies on services provided by Bundle B, Bundle A should use OSGi service registry mechanisms (e.g.,
Sample OSGi Bundle Manifest File
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: com.example.mybundle
Bundle-Version: 1.0.0
Bundle-Activator: com.example.mybundle.Activator
Import-Package: org.osgi.framework
Export-Package: com.example.mybundle.api
What are the specific entries that need to be done in the pom.xml file to use bundles in AEM?
Uber-jar Dependency
<dependencies>
<!-- Example: AEM API dependencies -->
<dependency>
<groupId>com.adobe.aem</groupId>
<artifactId>uber-jar</artifactId>
<version>6.5.0</version>
<scope>provided</scope>
</dependency>
<!-- Add other dependencies as needed -->
</dependencies>
Plugin changes
<build>
<plugins>
<!-- Apache Felix Maven Bundle Plugin -->
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>5.1.2</version>
<extensions>true</extensions>
<configuration>
<instructions>
<!-- OSGi metadata like Export/Import-Package -->
<Export-Package>com.example.mybundle.*</Export-Package>
<Import-Package>*</Import-Package>
</instructions>
</configuration>
</plugin>
<!-- Apache Sling Maven Plugin -->
<plugin>
<groupId>org.apache.sling</groupId>
<artifactId>maven-sling-plugin</artifactId>
<version>2.2.0</version>
</plugin>
</plugins>
</build>
Repository changes
<repositories>
<repository>
<id>adobe-public-releases</id>
<url>https://repo.adobe.com/nexus/content/groups/public/</url>
</repository>
</repositories>
I have tried to add almost all the /details in this blog related to bundles. Hope this is helpful.
Further Reference
- https://experienceleague.adobe.com/en/docs/experience-manager-65/content/implementing/deploying/configuring/web-console#bundles
- Checkout our other blogs on similar knowledge on Working with AEM
Feel free to share your thoughts on this topic in the comments section below 👇 We would be happy to hear and discuss the same 🙂