Partner – Microsoft – NPI EA (cat = Baeldung)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Microsoft – NPI EA (cat= Spring Boot)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, you can get started over on the documentation page.

And, you can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Orkes – NPI EA (cat=Spring)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag=Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – MongoDB – NPI EA (tag=MongoDB)
announcement - icon

Traditional keyword-based search methods rely on exact word matches, often leading to irrelevant results depending on the user's phrasing.

By comparison, using a vector store allows us to represent the data as vector embeddings, based on meaningful relationships. We can then compare the meaning of the user’s query to the stored content, and retrieve more relevant, context-aware results.

Explore how to build an intelligent chatbot using MongoDB Atlas, Langchain4j and Spring Boot:

>> Building an AI Chatbot in Java With Langchain4j and MongoDB Atlas

Partner – LambdaTest – NPI EA (cat=Testing)
announcement - icon

Accessibility testing is a crucial aspect to ensure that your application is usable for everyone and meets accessibility standards that are required in many countries.

By automating these tests, teams can quickly detect issues related to screen reader compatibility, keyboard navigation, color contrast, and other aspects that could pose a barrier to using the software effectively for people with disabilities.

Learn how to automate accessibility testing with Selenium and the LambdaTest cloud-based testing platform that lets developers and testers perform accessibility automation on over 3000+ real environments:

Automated Accessibility Testing With Selenium

1. Introduction

Several Java mission-critical and middleware applications have some hard technological requirements.

Some have to support hot deploy, so as not to disrupt the running services – and others have to be able to work with different versions of the same package for the sake of supporting external legacy systems.

The OSGi platforms represent a viable solution to support this kind of requirements.

The Open Service Gateway Initiative is a specification defining a Java-based component system. It’s currently managed by the OSGi Alliance, and its first version dates back to 1999.

Since then, it has proved to be a great standard for component systems, and it’s widely used nowadays. The Eclipse IDE, for instance, is an OSGi-based application.

In this article, we’ll explore some basic features of OSGi leveraging the implementation provided by Apache.

2. OSGi Basics

In OSGi, a single component is called a bundle.

Logically, a bundle is a piece of functionality that has an independent lifecycle – which means it can be started, stopped and removed independently.

Technically, a bundle is just a jar file with a MANIFEST.MF file containing some OSGi-specific headers.

The OSGi platform provides a way to receive notifications about bundles becoming available or when they’re removed from the platform. This will allow a properly designed client to keep working, maybe with degraded functionality, even when a service it depends on, is momentarily unavailable.

Because of that, a bundle has to explicitly declare what packages it needs to have access to and the OSGi platform will start it only if the dependencies are available in the bundle itself or in other bundles already installed in the platform.

3. Getting the Tools

We’ll start our journey in OSGi by downloading the latest version of Apache Karaf from this link. Apache Karaf is a platform that runs OSGi-based applications; it’s based on the Apache‘s implementation of OSGi specification called Apache Felix.

Karaf offers some handy features on top of Felix that will help us in getting acquainted with OSGi, for example, a command line interface that will allow us to interact with the platform.

To install Karaf, you can follow the installation instruction from the official documentation.

4. Bundle Entry Point

To execute an application in an OSGi environment, we have to pack it as an OSGi bundle and define the application entry point, and that’s not the usual public static void main(String[] args) method.

So, let’s start by building an OSGi- based “Hello World” application.

We start setting up a simple dependency on the core OSGi API:

<dependency>
    <groupId>org.osgi</groupId> 
    <artifactId>org.osgi.core</artifactId>
    <version>6.0.0</version>
    <scope>provided</scope>
</dependency>

The dependency is declared as provided because it will be available in the OSGi runtime, and the bundle doesn’t need to embed it.

Let’s now write the simple HelloWorld class:

public class HelloWorld implements BundleActivator {
    public void start(BundleContext ctx) {
        System.out.println("Hello world.");
    }
    public void stop(BundleContext bundleContext) {
        System.out.println("Goodbye world.");
    }
}

BundleActivator is an interface provided by OSGi that has to be implemented by classes that are entry points for a bundle.

The start() method is invoked by the OSGi platform when the bundle containing this class is started. On the other hand stop() is invoked before just before the bundle is stopped.

Let’s keep in mind that each bundle can contain at most one BundleActivator. The BundleContext object provided to both methods allows interacting with the OSGi runtime. We’ll get back to it soon.

5. Building a Bundle

Let’s modify the pom.xml and make it an actual OSGi bundle.

First of all, we have to explicitly state that we’re going to build a bundle, not a jar:

<packaging>bundle</packaging>

Then we leverage the maven-bundle-plugin, courtesy of the Apache Felix community, to package the HelloWorld class as an OSGi bundle:

<plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <version>3.3.0</version>
    <extensions>true</extensions>
    <configuration>
        <instructions>
            <Bundle-SymbolicName>
                ${pom.groupId}.${pom.artifactId}
            </Bundle-SymbolicName>
            <Bundle-Name>${pom.name}</Bundle-Name>
            <Bundle-Version>${pom.version}</Bundle-Version>
            <Bundle-Activator>
                com.baeldung.osgi.sample.activator.HelloWorld
            </Bundle-Activator>
            <Private-Package>
                com.baeldung.osgi.sample.activator
            </Private-Package>            
        </instructions>
    </configuration>
</plugin>

In the instructions section, we specify the values of the OSGi headers we want to include in the bundle’s MANIFEST file.

Bundle-Activator is the fully qualified name of the BundleActivator implementation that will be used to start and stop the bundle, and it refers to the class we’ve just written.

Private-Package is not an OSGi header, but it’s used to tell the plugin to include the package in the bundle but not make it available to other ones. We can now build the bundle with the usual command mvn clean install.

6. Installing and Running the Bundle

Let’s start Karaf by executing the command:

<KARAF_HOME>/bin/karaf start

where <KARAF_HOME> is the folder where Karaf is installed. When the prompt of the Karaf console appears we can execute the following command to install the bundle:

> bundle:install mvn:com.baeldung/osgi-intro-sample-activator/1.0-SNAPSHOT
Bundle ID: 63

This instructs Karaf to load the bundle from the local Maven repository.

In return Karaf prints out the numeric ID assigned to the bundle that depends on the number of bundles already installed and may vary. The bundle is now just installed, we can now start it with the following command:

> bundle:start 63
Hello World

“Hello World” immediately appears as soon the bundle is started. We can now stop and uninstall the bundle with:

> bundle:stop 63
> bundle:uninstall 63

“Goodbye World” appears on the console, accordingly to the code in the stop() method.

7. An OSGi Service

Let’s go on writing a simple OSGi service, an interface that exposes a method for greeting people:

package com.baeldung.osgi.sample.service.definition;
public interface Greeter {
    public String sayHiTo(String name);
}

Let’s write an implementation of it that is a BundleActivator too, so we’ll be able to instantiate the service and register it on the platform when the bundle is started:

package com.baeldung.osgi.sample.service.implementation;
public class GreeterImpl implements Greeter, BundleActivator {

    private ServiceReference<Greeter> reference;
    private ServiceRegistration<Greeter> registration;

    @Override
    public String sayHiTo(String name) {
        return "Hello " + name;
    }

    @Override 
    public void start(BundleContext context) throws Exception {
        System.out.println("Registering service.");
        registration = context.registerService(
          Greeter.class, 
          new GreeterImpl(), 
          new Hashtable<String, String>());
        reference = registration
          .getReference();
    }

    @Override 
    public void stop(BundleContext context) throws Exception {
        System.out.println("Unregistering service.");
        registration.unregister();
    }
}

We use the BundleContext as a mean of requesting the OSGi platform to register a new instance of the service.

We should also provide the type of the service and a map of the possible configuration parameters, which aren’t needed in our simple scenario. Let’s now proceed with the configuration of the maven-bundle-plugin:

<plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <extensions>true</extensions>
    <configuration>
        <instructions>
            <Bundle-SymbolicName>
                ${project.groupId}.${project.artifactId}
            </Bundle-SymbolicName>
            <Bundle-Name>
                ${project.artifactId}
            </Bundle-Name>
            <Bundle-Version>
                ${project.version}
            </Bundle-Version>
            <Bundle-Activator>
                com.baeldung.osgi.sample.service.implementation.GreeterImpl
            </Bundle-Activator>
            <Private-Package>
                com.baeldung.osgi.sample.service.implementation
            </Private-Package>
            <Export-Package>
                com.baeldung.osgi.sample.service.definition
            </Export-Package>
        </instructions>
    </configuration>
</plugin>

It’s worth noting that only the com.baeldung.osgi.sample.service.definition package has been exported this time, through the Export-Package header.

Thanks to this, OSGi will allow other bundles to invoke only the methods specified in the service interface. Package com.baeldung.osgi.sample.service.implementation is marked as private, so no other bundle will be able to access the members of the implementation directly.

8. An OSGi Client

Let’s now write the client. It simply looks up the service at startup and invokes it:

public class Client implements BundleActivator, ServiceListener {
}

Let’s implement the BundleActivator start() method:

private BundleContext ctx;
private ServiceReference serviceReference;

public void start(BundleContext ctx) {
    this.ctx = ctx;
    try {
        ctx.addServiceListener(
          this, "(objectclass=" + Greeter.class.getName() + ")");
    } catch (InvalidSyntaxException ise) {
        ise.printStackTrace();
    }
}

The addServiceListener() method allows the client to ask the platform to send notifications about the service that complies with the provided expression.

The expression uses a syntax similar to the LDAP’s one, and in our case, we’re requesting notifications about a Greeter service.

Let’s go on to the callback method:

public void serviceChanged(ServiceEvent serviceEvent) {
    int type = serviceEvent.getType();
    switch (type){
        case(ServiceEvent.REGISTERED):
            System.out.println("Notification of service registered.");
            serviceReference = serviceEvent
              .getServiceReference();
            Greeter service = (Greeter)(ctx.getService(serviceReference));
            System.out.println( service.sayHiTo("John") );
            break;
        case(ServiceEvent.UNREGISTERING):
            System.out.println("Notification of service unregistered.");
            ctx.ungetService(serviceEvent.getServiceReference());
            break;
        default:
            break;
    }
}

When some modification involving the Greeter service happens, the method is notified.

When the service is registered to the platform, we get a reference to it, we store it locally, and we then use it to acquire the service object and invoke it.

When the server is later unregistered, we use the previously stored reference to unget it, meaning that we tell the platform that we are not going to use it anymore.

We now just need to write the stop() method:

public void stop(BundleContext bundleContext) {
    if(serviceReference != null) {
        ctx.ungetService(serviceReference);
    }
}

Here again, we unget the service to cover the case in which the client is stopped before the service is being stopped. Let’s give a final look at the dependencies in the pom.xml:

<dependency>
    <groupId>com.baeldung</groupId>
    <artifactId>osgi-intro-sample-service</artifactId>
    <version>1.0-SNAPSHOT</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.osgi</groupId>
    <artifactId>org.osgi.core</artifactId>
    <version>6.0.0</version>
</dependency>

9. Client and Service

Let’s now install the client and service bundles in Karaf by doing:

> install mvn:com.baeldung/osgi-intro-sample-service/1.0-SNAPSHOT
Bundle ID: 64
> install mvn:com.baeldung/osgi-intro-sample-client/1.0-SNAPSHOT
Bundle ID: 65

Always keep in mind that the identifier numbers assigned to each bundle may vary.

Let’s now start the client bundle:

> start 65

Therefore, nothing happens because the client is active and it’s waiting for the service, that we can start with:

> start 64
Registering service.
Service registered.
Hello John

What happens is that as soon as the service’s BundleActivator starts, the service is registered to the platform. That, in turn, notifies the client that the service it was waiting for is available.

The client then gets a reference to the service and uses it to invoke the implementation delivered through the service bundle.

10. Conclusion

In this article, we explored the essential features of OSGi with a straightforward example that it’s enough to understand the potential of OSGi.

In conclusion, whenever we have to guarantee that a single application has to be updated without any disservice, OSGi can be a viable solution.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

Partner – Microsoft – NPI EA (cat = Baeldung)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Microsoft – NPI EA (cat = Spring Boot)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Orkes – NPI EA (cat = Spring)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag = Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Partner – MongoDB – NPI EA (tag=MongoDB)
announcement - icon

Traditional keyword-based search methods rely on exact word matches, often leading to irrelevant results depending on the user's phrasing.

By comparison, using a vector store allows us to represent the data as vector embeddings, based on meaningful relationships. We can then compare the meaning of the user’s query to the stored content, and retrieve more relevant, context-aware results.

Explore how to build an intelligent chatbot using MongoDB Atlas, Langchain4j and Spring Boot:

>> Building an AI Chatbot in Java With Langchain4j and MongoDB Atlas

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

eBook Jackson – NPI EA – 3 (cat = Jackson)