How to create multiple instances of osgi service without using DS annotations - java

I have created an Osgi service. I want to create a new instance of my service each time the service request comes.
Code look likes this -
#Component(immediate=true)
#Service(serviceFactory = true)
#Property(name = EventConstants.EVENT_TOPIC, value = {DEPLOY, UNDEPLOY })
public class XyzHandler implements EventHandler {
private Consumer consumer;
public static setConsumer(Consumer consumer) {
this.consumer = consumer;
}
#Override
public void handleEvent(final Event event) {
consumer.notify();
}
}
public class Consumer {
private DataSourceCache cache;
public void notify() {
updateCache(cache);
System.out.println("cache updated");
}
public void updateCache(DataSourceCache cache) {
cache = null;
}
}
In my Consumer class, I want to access the service instance of XyzHandler & set the attribute consumer. Also I would like to have a new service instance of XyzHandler created every time for each request.
I found few articles where it is mentioned that using osgi declarative service annotations this can be achieved.
OSGi how to run mutliple instances of one service
But I want to achieve this without using DS 1.3.
How can I do this without using annotations or how can it be done using DS 1.2?

To me this looks like a case of having asked a question based on what you think the answer is rather than describing what you're trying to achieve. If we take a few steps back then a more elegant solution exists.
In general injecting objects into stateful services is a bad pattern in OSGi. It forces you to be really careful about the lifecycle, and risks memory leaks. From the example code it appears as though what you really want is for your Consumer to get notified when an event occurs on an Event Admin topic. The easiest way to do this would be to remove the XyzHandler from the equation and make the Consumer an Event Handler like this:
#Component(property= { EventConstants.EVENT_TOPIC + "=" + DEPLOY,
EventConstants.EVENT_TOPIC + "=" + UNDEPLOY})
public class Consumer implements EventHandler {
private DataSourceCache cache;
#Override
public void handleEvent(final Event event) {
notify();
}
public void notify() {
updateCache(cache);
System.out.println("cache updated");
}
public void updateCache(DataSourceCache cache) {
cache = null;
}
}
If you really don't want to make your Consumer an EventHandler then it would still be easier to register the Consumer as a service and use the whiteboard pattern to get it picked up by a single XyzHandler:
#Component(service=Consumer.class)
public class Consumer {
private DataSourceCache cache;
public void notify() {
updateCache(cache);
System.out.println("cache updated");
}
public void updateCache(DataSourceCache cache) {
cache = null;
}
}
#Component(property= { EventConstants.EVENT_TOPIC + "=" + DEPLOY,
EventConstants.EVENT_TOPIC + "=" + UNDEPLOY})
public class XyzHandler implements EventHandler {
// Use a thread safe list for dynamic references!
private List<Consumer> consumers = new CopyOnWriteArrayList<>();
#Reference(cardinality=MULTIPLE, policy=DYNAMIC)
void addConsumer(Consumer consumer) {
consumers.add(consumer);
}
void removeConsumer(Consumer consumer) {
consumers.remove(consumer);
}
#Override
public void handleEvent(final Event event) {
consumers.forEach(this::notify);
}
private void notify(Consumer consumer) {
try {
consumer.notify();
} catch (Exception e) {
// TODO log this?
}
}
}
Using the whiteboard pattern in this way avoids you needing to track which XyzHandler needs to be created/destroyed when a bundle is started or stopped, and will keep your code much cleaner.

It sounds like your service needs to be a prototype scope service. This was introduced in Core R6. DS 1.3, from Compendium R6, includes support for components to be prototype scope services.
But DS 1.2 predates Core R6 and thus has no knowledge or support for prototype scope services.

Related

Spring boot - task on startup preventing application interface exposure

Is it possible to somehow in Spring boot application achieve some startup procedure that blocks every exposure of endpoints (and possibly other application public interfaces) until the startup procedure is completed?
I mean something like
#Component
public class MyBlockingStartupRunner implements ApplicationRunner {
#Override
public void run(ApplicationArguments args) {
// doing some task, calling external API, processing return values, ...
startTask();
// at this point app should be available for rest calls, scheduled tasks etc.
someObject.appIsReadyToGo(); // alternatively app would be ready at the end of the method
}
}
Problem with this approach of using ApplicationRunner is there might be some API calls to the server that I am unable to serve and therefore I would need to add some check at every API endpoint to prevent this. Or, alternatively, create some interceptor that would "block" all public communication and which would probably read some property from some service which tells it if app is ready or not. But thats not the approach I would like and I wonder if Spring implemented this somehow.
If it is acceptable to run your start-up tasks before the web server instance has started at all, you could use SmartLifecycle to add a start task.
#Component
class MyStartup implements SmartLifecycle {
private final ServletWebServerApplicationContext ctx;
private final Log logger = LogFactory.getLog(MyStartup.class);
#Autowired
MyStartup(ServletWebServerApplicationContext ctx) {
this.ctx = ctx;
}
#Override
public void start() {
logger.info("doing start stuff: " + ctx.getWebServer());
startTask();
}
#Override
public void stop() {}
#Override
public boolean isRunning() {
return false;
}
#Override
public int getPhase() {
return 100;
}
}
Because the task runs before the web server has started (rather than blocking access) this might be a different approach.

How to use blocking queue in Spring Boot?

I am trying to use BlockingQueue inside Spring Boot. My design was like this: user submit request via a controller and controller in turn puts some objects onto a blocking queue. After that the consumer should be able to take the objects and process further.
I have used Asnyc, ThreadPool and EventListener. However with my code below I found consumer class is not consuming objects. Could you please help point out how to improve?
Queue Configuration
#Bean
public BlockingQueue<MyObject> myQueue() {
return new PriorityBlockingQueue<>();
}
#Bean
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(3);
executor.setQueueCapacity(10);
executor.setThreadNamePrefix("Test-");
executor.initialize();
return executor;
}
Rest Controller
#Autowired
BlockingQueue<MyObject> myQueue;
#RequestMapping(path = "/api/produce")
public void produce() {
/* Do something */
MyObject myObject = new MyObject();
myQueue.put(myObject);
}
Consumer Class
#Autowired
private BlockingQueue<MyObject> myQueue;
#EventListener
public void onApplicationEvent(ContextRefreshedEvent event) {
consume();
}
#Async
public void consume() {
while (true) {
try {
MyObject myObject = myQueue.take();
}
catch (Exception e) {
}
}
}
Your idea is using Queue to store messages, consumer listens to spring events and consume.
I didn't see your code have actually publish the event, just store them in queue.
If you want to use Spring Events, producers could like this:
#Autowired
private ApplicationEventPublisher applicationEventPublisher;
public void doStuffAndPublishAnEvent(final String message) {
System.out.println("Publishing custom event. ");
CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
applicationEventPublisher.publishEvent(customSpringEvent);
}
check this doc
If you still want to use BlockingQueue, your consumer should be a running thread, continuously waiting for tasks in the queue, like:
public class NumbersConsumer implements Runnable {
private BlockingQueue<Integer> queue;
private final int poisonPill;
public NumbersConsumer(BlockingQueue<Integer> queue, int poisonPill) {
this.queue = queue;
this.poisonPill = poisonPill;
}
public void run() {
try {
while (true) {
Integer number = queue.take(); // always waiting
if (number.equals(poisonPill)) {
return;
}
System.out.println(Thread.currentThread().getName() + " result: " + number);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
could check this code example
#Async doesn't actually start a new thread if the target method is called from within the same object instance, this could be the problem in your case.
Also note that you need to put #EnableAsync on a config class to enable the #Async annotation.
See Spring documentation: https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#scheduling-annotation-support
The default advice mode for processing #Async annotations is proxy which allows for interception of calls through the proxy only. Local calls within the same class cannot get intercepted that way. For a more advanced mode of interception, consider switching to aspectj mode in combination with compile-time or load-time weaving.
In the end I came up with this solution.
Rest Controller
#Autowired
BlockingQueue<MyObject> myQueue;
#RequestMapping(path = "/api/produce")
public void produce() {
/* Do something */
MyObject myObject = new MyObject();
myQueue.put(myObject);
Consumer.consume();
}
It is a little bit weird because you have to first put the object on queue yourself then consume that object by yourself. Any suggestions on improvement is highly appreciated.

Calling Spring controller method without going to internet

tldr: Is there a way to make an internal request (using the method's path) without going to the internet?
--
Why do I need it? I have a project which receives many events. The decision of who will handle each event is made by a Controller. So I have something similar to this:
#RestController
#RequestMapping("/events")
public class EventHandlerAPI {
#Autowired
private EventAHandler eventAhandler;
#Autowired
private EventBHandler eventBhandler;
#PostMapping("/a")
public void handleEventA(#RequestBody EventA event) {
eventAhandler.handle(id, event);
}
#PostMapping("/b")
public void handleEventB(#RequestBody EventB event) {
eventBhandler.handle(id, event);
}
}
We recently added support to receive events through a Queue service. It sends to us the payload and the event class. Our decision is to let both interfaces working (rest and queue). The solution to avoid code duplication was to keep the Controller choosing which handler will take care of the event. The code nowadays is similar to this:
#Configuration
public class EventHandlerQueueConsumer {
#Autowired
private EventHandlerAPI eventHandlerAPI;
private Map<Class, EventHandler> eventHandlers;
#PostConstruct
public void init() {
/* start listen queue */
declareEventHandlers();
}
private void declareEventHandlers() {
eventHandlers = new HashMap<>();
eventHandlers.put(EventAHandler.class, (EventHandler<EventAHandler>) eventHandlerAPI::handleEventA);
eventHandlers.put(EventBHandler.class, (EventHandler<EventBHandler>) eventHandlerAPI::handleEventB);
}
private void onEventReceived(AbstractEvent event) {
EventHandler eventHandler = eventHandlers.get(event.getClass());
eventHandler.handle(event);
}
private interface EventHandler<T extends AbstractEvent> {
void handle(T event);
}
}
This code works, but it doesn't let the controller choose who will handle the event (our intention). The decision is actually being made by the map.
What I would like to do was to invoke the controller method through it's request mapping without going to the internet. Something like this:
#Configuration
public class EventHandlerQueueConsumer {
// MADE UP CLASS TO SHOW WHAT I WANT
#Autowired
private ControllerInkover controllerInvoker;
#PostConstruct
public void init() { /* start listen queue */ }
private void onEventReceived(AbstractEvent event) {
controllerInvoker.post(event.getPath(), new Object[] { event });
}
}
This way is much cleaner and let all the decisions be made by the controller.
I've researched a lot and didn't found a way to implement it. Debugging spring, I found how he routes the request after the DispatcherServlet, but all the spring internals uses HttpServletRequest and HttpServletResponse :(
Is there a way to make an internal request (using the method's path) without going to the internet?
They are classes of the same application
Then it should easy enough.
1) You can call your own API on http(s)://localhost:{port}/api/{path} using RestTemplate utility class. This is preferred way, since you'll follow standard MVC pattern. Something like:
restTemplate.exchange(uri, HttpMethod.POST, httpEntity, ResponseClass.class);
2) If you don't want to invoke network connection at all, then you can either use Spring's internal to find the mapping/method map or use some reflection to build custom
map upon controller's startup. Then you can pass your event/object to the method from the map in a way shown in your mock-up class. Something like:
#RequestMapping("foo")
public void fooMethod() {
System.out.println("mapping = " + getMapping("fooMethod")); // you can get all methods/mapping in #PostContruct initialization phase
}
private String getMapping(String methodName) {
Method methods[] = this.getClass().getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName() == methodName) {
String mapping[] = methods[i].getAnnotation(RequestMapping.class).value();
if (mapping.length > 0) {
return mapping[mapping.length - 1];
}
}
}
return null;
}

Guice service dependencies

I have three guava Services which get started by a guava ServiceManager asynchronously.
The first service is the database connection pool which needs to start fully before the second/third service can successfully process incoming messages. Obviously with these being started asynchronously, the database may not have fully started before the second/third service starts to process a message, which will lead to exceptions.
What is the desired pattern here?
I can inject the database service into the other services and call the awaitRunning() method in the service startup, but then I will suffer the same issue when the ServiceManager is shutdown.
I believe guice does not have an out-of-the-box mechanism for this. Spring e.g. has a depends-on attribute that can define some ordering. There are frameworks that give you this with guice as well (e.g. dropwizard guicey implements an order annotation). This is however fairly simple to solve.
The approach is to use multibindings to define a manager for all dependency classes. This I will call Managed (adopted from jetty). The interface will implement an ordering. We then use a manager that starts all the services one by one in a well defined order (can also be used for shutdown if wanted).
See my code example here:
public class ExecutionOrder {
public static void main(String[] args) {
Injector createInjector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
Multibinder<Managed> multiBinder = Multibinder.newSetBinder(binder(), Managed.class);
multiBinder.addBinding().to(Service1.class);
multiBinder.addBinding().to(Service2.class);
bind(ManagedManager.class).in(Singleton.class);
}
});
createInjector.getInstance(ManagedManager.class); // start it
}
public interface Managed extends Comparable<Managed> {
public default void start() {}
public default int getOrder() { return 0;}
#Override
default int compareTo(Managed o) {
return Integer.compare(getOrder(), o.getOrder());
}
}
public static class ManagedManager {
#Inject
public ManagedManager(final Set<Managed> managed) {
managed.stream().sorted().forEach(Managed::start);
}
}
public static class Service1 implements Managed {
#Override
public void start() {
System.out.println("Started Service 1");
}
#Override
public int getOrder() {
return 1;
}
}
public static class Service2 implements Managed {
#Override
public void start() {
System.out.println("Started Service 2");
}
#Override
public int getOrder() {
return 2;
}
}
}
My - admittedly stupidly named - ManagedManager is injected by guice with all Managed interfaces, using guice's multibindings (see the module I initialise). I then sort that and call start.
The start method would be where you initialise your services (e.g. your database connection). By overwriting the getOrder() method you can define which service is started at which point.
That way you get a well defined startup behaviour and you can adapt the interface to have a well defined shutdown behaviour as well.
I hope this helps,
Artur

Dynamic target for declarative service in OSGI

Given a consumer which uses a service, how can this consumer select a specific provider dynamically using declarative service ?
Example
Service.java
public interface Service {
public void do();
}
Provider1.java
public class Provider1 implements Service {
#Override
public void do(){
//a way
}
}
Provider2.java
public class Provider2 implements Service {
#Override
public void do(){
//another way
}
}
Consumer.java
public class Consumer {
private Service myService;
protected void bindService(Service s){ // Actually it's Provider1
myService = s;
}
protected void unbindService(Service s){
myService = null;
}
public void useThisKindOfService(String s){
// Do something crazy
}
}
So, what I would like it's instead of "Do something crazy", to find a way to reconfigure the consumer in order to release Provider1 and ask for Provider2.
Is it possible ?
Update related to "Duplicate Question"
OSGI/Felix Declarative services: How to filter the services to be bound
In my context I cannot use the declarative target because the value of the target has to be know at build time, in my case the target could be defined by a user at runtime.
Components of Declarative Services can be configured via ConfigurationAdmin. By doing that, the configuration of the component can be changed at runtime.
You can also change the configuration of myService.target via ConfigurationAdmin at runtime. If you do that, another reference will be bound to your component.
If the policy of the reference of your component is dynamic, the new reference will be bound without reactivating your component.
For more information, see the Declarative Services chapter of the OSGi Compendium specification.

Categories

Resources