OSGi how to run mutliple instances of one service - osgi

Is it possible to run multiple instance of the same service in the osgi framework?
More specific, I need to start multiple instances of a service, but each instance should recieve different parameters. This is because the services have similar functionality. But instead of writing a service for every variation, I want to reuse one implementing class.
I've already found the registerService method in the framework api.
ServiceRegistration<?> registration = bundlecontext.registerService(
className, class, null);
however, i seem to create only one instance of each class. Is there a workaround for this?
preferably something like
ServiceRegistration<?> registration = bundlecontext.registerService(
className + "#" + (++counter), new classInstance(), null);

Note that using Declarative Services with the corresponding annotations makes this quite easy, here's an excerpt from the Apache Sling codebase (ConfiguredFeature.java):
#Component(
name = "org.apache.sling.featureflags.Feature",
metatype = true,
configurationFactory = true,
policy = ConfigurationPolicy.REQUIRE)
#Service
public class ConfiguredFeature implements Feature {
#Property(label = "Name", description = "Short name of this feature")
private static final String NAME = "name";
private String name;
#Activate
private void activate(final Map<String, Object> configuration) {
this.name = PropertiesUtil.toString(configuration.get(NAME), "");
}
...
}
Using configurationFactory = true and policy = ConfigurationPolicy.REQUIRE causes one instance of this service to be created for each corresponding OSGi configuration, which is a natural way of creating multiple instances.

You could create a ManagedServiceFactory. The factory can register a new service for each configuration set in Configuration Admin.
I have a simple example here which uses Felix DependencyManager to register the component: https://github.com/paulbakker/osgicourse/tree/master/greeterfactory/src/greeterfactory

You have the parameters slightly wrong, or at least misleading:
ServiceRegistration<?> registration = bundlecontext.registerService(
className, class, null);
The second parameter to registerService is an object, not a class. This is an object you instantiate yourself. You can create as many as you like, in whatever way you like, before passing them to OSGi.
However if you are doing this with externally-supplied configuration data, should look into Declarative Services and their ability to receive config from the OSGi Configuration Admin service.
UPDATE
Taking another look at your question, I see the counter that you tried to add to the class name. This is not required and in fact not permitted either. Just call registerService multiple times.

Related

Spring inject component into non-spring managed interface/abstract class and its subclasses

TLDR: I need an interface/abstract class and all classes implementing it to have access to a Spring managed bean. Can Spring inject a bean into an interface/abstract-class and its subclasses simply via #Autowired ?
I am working on an API built with Spring Webflux + Cloud Gateway that depending on the cookie JWT authorized party, identifies the User's policy group and assign an Attribute ENUM "InterfaceID" to the ServerWebExchange via exchange.getAttribute().put("InterfaceID",InterfaceID.A) after the JWT is validated, and currently uses "InterfaceID" to represent the different groups of users/different interface the user entered from.
JWTValidationFilter.java [Current]
switch(JWTValidator.validate(jwt).get("AZP")){
//if user is from company A or its partners
case "a":
case "aa":
exchange.getAttribute().put(InterfaceID.COMPANY_A_ACCESS);
break;
case "b":
exchange.getAttribute().put(InterfaceID.NORMAL_ACCESS);
...
}
For certain API endpoints (say /api/getSessionDocument), different "InterfaceID" fetches data from different DB/apis, as well as have different permission checking on top of that.
RequestController.java [Current]
#Autowired
APICallerUtil apiCallerUtil;
switch(exchange.getAttribute.get(InterfaceID)){
case "NORMAL_ACCESS":
apiCallerUtil.getDataFromApiA();
break;
case "COMPANY_A_ACCESS":
// call api B but check for permission from api D first
...
}
The endpoint's controller now has another switch statement, and to many code analyzers this have been a code smell. I have been trying to refactor this entire bit of code to use polymorphism to handle the different "getSessionDocument" flows, but i run into issues regarding the injection of util classes that calls specific APIs.
APICallerUtil.java class, exisiting class from the project, would prefer not to refactor this.
#Component
public class APICallerUtil{
#Value("${some uri to some API}") //different by environment and therefore cant be static final
private String uri1;
#Value("${some auth to some API}") //confidential
private String uri1AuthHeader;
//...
public JSONObject getDataFromApiA(String somekey){ //cant be static since uri1 is not static
//Some code that uses uri1 and apache httpclient
return data;
}
...
}
IBaseAccess.java
interface IBaseAccess{
default Mono<JSONObject> getSesssionDocument(ServerWebExchange e){return Mono.error("not implemented");}
}
RequestController.java [new]
#Autowired
APICallerUtil apiCallerUtil;
return exchange.getAttribute.get(InterfaceID).getSessionDocument(exchange);
NormalAccess.java
public class NormalAccess implements IBaseAccess{
//can i autowire APICallerUtil here?
//use constructor to pass the Util class reference here?
Mono<JSONObject> getSesssionDocument(ServerWebExchange e){
//need to call ApiA here
//need to call ApiC here
}
}
NormalAccess needs to call APICaller.getDataFromApiA(), but it needs a reference to the Spring managed instance of APICaller. What would be the "correct" way to pass the reference/autowire API caller into NormalAccess, or even better IBaseAccess (so that the implementing classes can use the Util bean)?
JWTValidationFilter.java [new]
switch(JWTValidator.validate(jwt).get("AZP")){
//if user is from company A or its partners
case "a":
case "aa":
exchange.getAttribute().put("InterfaceID",new CompanyAAccess(/*pass the util class here?*/));
break;
case "b":
exchange.getAttribute().put("InterfaceID",new NormalAccess(/*pass the util class here?*/));
...
}
I have tried several methods, but either I lack the knowledge on the specific Spring feature, or that method is deeemed a bad design choice by some, including:
Making the methods and fields in APICallerUtil static, via suggestions from Spring: How to inject a value to static field? and Assigning private static final field member using spring injection , then the Access classes can call the static methods.
Creating a contructor for IBaseAccess that consumes the APICallerUtil reference and store it inside. The JWTfilter would hold an autowired APICallerUtil and pass it in when the attribute is assigned.
Create a static class that provides the application context and Access classes use applicationContext.getBean("APICallerUtil"); to obtain the bean.
Use the #Configurable annotation? I could not find much documentation on how this works for interfaces/abstract-class.
I understand that there might not exist an absolute answer for this question, but regardless I'd like suggestion/feedback on which of these approaches are viable/good. Especailly concerning whether the APIUtil class should be static or not.

Simple Injector: Register Conditional vs RegisterSingleton

Context: I am trying to capture multiple events in our api using serilog and the elastic search sink, these events include: GET actions(regular web api flow) as well as login attempts (Owin).
I am registering serilog like this:
container.RegisterConditional(
typeof(ICustomLogger),
c => typeof(CustomLogger<>).MakeGenericType(
c.Consumer?.ImplementationType ?? typeof(object)),
Lifestyle.Singleton,
c => true);
I am doing this for Owin registration:
app.Use(async (context, next) =>
{
using (var scope = container.BeginExecutionContextScope())
{
await next.Invoke();
}
});
Then when I call container.Verify(); the logger constructor gets called(as expected).
However when I call the logger from my OAuthAuthorizationServerProvider implementation like this:
var logger = ObjectFactory.GetInstance<ICustomLogger>(); the constructor gets called again, meaning the singleton is not really a singleton anymore, I am totally aware of the service locator antipattern(don't really have much time to refactor that piece right now), what is interesting is that if I change the logger registration to the following (getting rid of the type piece) then only one instance is created:
container.RegisterSingleton(typeof(ICustomLogger), typeof(CustomLogger))
The reason why I am trying to use the first option is because I want to be able to use .ForContext(typeof(T)); for serilog, and in case you are wondering how I am registering the ObjectFactory piece here it is:
Class:
public static class ObjectFactory
{
public static Container container;
public static void SetContainer(Container container)
{
ObjectFactory.container = container;
}
public static T GetInstance<T>() where T : class
{
return container.GetInstance<T>();
}
}
Registration(from my main bootstrapper):
ObjectFactory.SetContainer(container);
So my main question is: Why is only one instance created with RegisterSingleton but multiple are created with RegisterConditional and Lifestyle.Singleton?
The reason multiple instances are created has nothing to do with the fact that you are using your ObjectFactory, but simply because different closed versions of CustomLogger<T> are created:
A CustomLogger<object> is created when resolved as root type (by calling GetInstance<ICustomLogger>()
A CustomLogger<Service1> is created when ICustomLogger is injected into Service1.
Because a CustomLogger<object> is a different type than a CustomLogger<Service1>, it is impossible to have just one instance for both types. They both have to be created. This might seem weird, but consider these two classes:
public class Service1
{
public Service1(ICustomLogger logger) { }
}
public class Service2
{
public Service2(ICustomLogger logger) { }
}
At runtime, considering these two definitions, you want to create object graphs similar to the following:
var s1 = new Service1(new CustomLogger<Service1>());
var s2 = new Service2(new CustomLogger<Service2>());
In the above case, the CustomLoggers are not cached and are, therefore, effectively transients. You might try to rewrite this to the following, but that would not be the same:
ICustomLogger logger = new CustomLogger<Service1>();
var s1 = new Service1(logger);
var s2 = new Service2(logger);
Now both service get the same single instance. However, this means that Service2 gets a CustomLogger<Service1> which is not what you configured. You configured the dependency to be this:
typeof(CustomLogger<>).MakeGenericType(c.Consumer.ImplementationType)
Consequence of this is that when Service2 starts to log, it will look like if the messages are coming from Service1. This would likely be incorrect behavior. Otherwise, you could have simply called RegisterSingleton<ICustomLogger, CustomLogger<Service1>>().
This all means that the Singleton guarantee for a RegisterConditional that uses an implementation-type factory (as in your example) only holds for the specified closed generic type.
Note that RegisterConditional isn't the only part in Simple Injector where you see this behavior. The following registrations do have the same effect:
container.RegisterSingleton(typeof(IFoo<>), typeof(Foo<>));
container.RegisterDecorator(typeof(IFoo<>), typeof(FooDecorator<>), Lifestyle.Singleton);
In both these cases multiple instances of closed generic versions of Foo<T> and FooDecorator<T> can be created, but Simple Injector guarantees that there is only one instance of every closed-generic version of Foo<T>. With RegisterDecorator<T>, however, even that is not guaranteed. Consider this example:
container.Collection.Append<ILogger, Logger1>(Lifestyle.Singleton);
container.Collection.Append<ILogger, Logger2>(Lifestyle.Singleton);
container.RegisterDecorator<ILogger, LoggerDecorator>(Lifestyle.Singleton);
In this case, a collection of ILogger components is registered where each ILogger element will be wrapped with a LoggerDecorator. Because a LoggerDecorator can only depend on either Logger1 or Logger2, but not both, Simple Injector will have to create a new LoggerDecorator instance for each element. If the LoggerDecorator would be cached as a true Singleton, this would be the result:
private static ILogger logger = new LoggerDecorator(new Logger1());
private static loggers = new[] { logger, logger };
As there is only 1 single LoggerDecorator, this decorator depends on Logger1, which means that the collection of loggers only has two elements that both point to the same Logger1 instance. There is no Logger2.
This information is reflected in the following Simple Injector documentation sections:
Aspect-Oriented Programming - Applying Lifestyles to Decorators
Lifetime Management - Generics and Lifetime Management

camunda bpnm spring boot activity delegates matching is not working

I downloaded the sample provided for spring micro services orchestration from GITHUB
it works as the details given in the description, but now I am trying t build my own workflow and not able to map how the call flow(code gets exectued) from one activity to other activity.
In the bpnm guide it shows the first activity name as Retrieve Shopping Cart and second one as Validate Address but when I start the workflow with rest call from the below code
public class ShoppingCartRestController {
#Autowired
private ProcessEngine camunda;
#RequestMapping(value = "/{scId}/submit", method = RequestMethod.POST)
public ResponseEntity<?> placeOrderPOST(#PathVariable("scId") String scId) {
ProcessContext context = new ProcessContext();
submitShoppingCart(scId, context);
if (context.getError() != null) {
return new ResponseEntity<>(context.getError(), HttpStatus.FORBIDDEN);
}
return new ResponseEntity<>(context.getResponse(), HttpStatus.OK);
}
private ProcessInstance submitShoppingCart(String scId, ProcessContext context) {
return camunda.getRuntimeService().startProcessInstanceByKey(//
"submitShoppingCart", //
Variables //
.putValue(ProcessConstants.VAR_SC_ID, scId).putValue(ProcessConstants.VAR_CTX, context));
}
}
from the above I am not able to get how it delegates to retrieve address and in turn that delegates to validate address and so on to end the flow ?
And how the process is linked from submitShoppingCart.bpmn (Name in this and Actual classes are not matching ?
Question 2 first: java api and process match via the processes technical id.
you see it in the "startProcessInstanceByKey" call: submitShoppingCart is the technical id of the process. In The modeller, you find it at the very top of the properties panel.
Question 1: The camunda Java API links service Tasks to execution via JavaDelegate interfaces. So for each service task, there is a class that implements what should happen in its execute(DelegateExecution execution) method.
In spring projects, these delegates are in general referred to by their bean names ... in your example, the "Retrieve Shopping Card" service is backed by the ${retrieveShoppingCartActivity} delegate. By convention, the bean name equals the class name, so look for RetrieveShoppingCartActivity to see what's inside.

autowire a Spring bean based on the value of a property

nI am developing a Spring MVC web app using Spring 3.2. We will deploy the web app to different customers. Each customer may use one of several implementations of a service interface.
It's possible that the customer may need to reset these values, so we can't just hard-wire the implementation into the application, it needs to be externally configurable.
We are already using customer-specific property files that for setting simple properties such as Strings, numbers etc, but I'm asking how to set a particular implementation of an interface.
E.g.,
class MyClass {
// this is straightforward
#Value("${customer.propertyInPropertyFile}")
private String customerSpecificString;
// how to set the correct implementation for each customer?
private ISomeService service;
}
If there are 4 implementations of ISomeService, we can't autowire, or explicitly set a bean, as this will then be set in the compiled code - and it needs to be configurable after the application is deployed ( it would be OK to restart the application though if need be)..
Does anyone know how to do this? Would this better be performed using Spring EL, or profiles?
Thanks!
So, as I wanted to used Java configuration, I used the following solution:
#Configuration
#Profile("prod")
#EnableAsync
public class ProductionConfig extends BaseConfig
// inject property value which identifies theimplementation to use
Value("${service.impl}")
private String serviceName;
#Bean()
public IRepository repository() {
IRepository rc = null;
if(StringUtils.isEmpty(serviceName)){
rc = new Impl1();
} else if ("sword-mets".equals(serviceName)){
rc = new Impl2();
} else {
rc = new Impl3();
}
log.info("Setting in repository implementation " + rc);
return rc;
}
So, this isn't quite as clean as the suggested reply using aliases - the Config class needs to know about all the possible implementation classes - but is simple and avoids having to use the XML config just for this bean.

OSGi force bundle start twice with different configurations

I'm using embedded Felix in my application. Application can potentially deal with lot of plugins that exposes similar interface IFoo. There is default an implementation FooImpl Hopefully for most plugins default FooImpl can be used with specific configuration files.
I would like dynamically install and start the same bundle (with FooImpl) when new configuration file appears. I've reviewed already FileInstall but have no idea how to apply it there.
UPDATE: Deployment sequence. The jar containing FooImpl and IFoo is stable, but I need hot-deploy of new instances that are result of uploading new .cfg file to scope of FileInstall. So desired is very simple - user uploads .cfg, new service (instance of FooImpl) is appeared.
Using Factory Configurations would allow you to create different instances of FooImpl based on different configurations.
For example in Declarative Services you can create a component like
import org.apache.felix.scr.annotations.*;
import org.apache.sling.commons.osgi.PropertiesUtil;
#Component(metatype = true,
name = FooImpl.SERVICE_PID,
configurationFactory = true,
specVersion = "1.1",
policy = ConfigurationPolicy.REQUIRE)
public class FooImpl implements IFoo
{
//The PID can also be defined in interface
public static final String SERVICE_PID = "com.foo.factory";
private static final String DEFAULT_BAR = "yahoo";
#Property
private static final String PROP_BAR = "bar";
#Property(intValue = 0)
static final String PROP_RANKING = "ranking";
private ServiceRegistration reg;
#Activate
public void activate(BundleContext context, Map<String, ?> conf)
throws InvalidSyntaxException
{
Dictionary<String, Object> props = new Hashtable<String, Object>();
props.put("type", PropertiesUtil.toString(config.get(PROP_BAR), DEFAULT_BAR));
props.put(Constants.SERVICE_RANKING,
PropertiesUtil.toInteger(config.get(PROP_RANKING), 0));
reg = context.registerService(IFoo.class.getName(), this, props);
}
#Deactivate
private void deactivate()
{
if (reg != null)
{
reg.unregister();
}
}
}
Key points here being
You use a component of type configurationFactory
In the activate method you read the config and then based on that register a service
In deactivate you explicitly unregister the service
End users would then create config file with name <pid>-<some name>.cfg. Then DS would then activate the component.
Then you can create multiple instances by creating configuration (using File Install like) file with name <pid>-<some name>.cfg like com.foo.factory-type1.cfg
Refer to JdbcLoginModuleFactory and its associated config for one such example.
If you want to achieve the same via plain OSGi then you need to register a ManagedServiceFactory. Refer to JaasConfigFactory for one such example.
Key points here being
You register a ManagedServiceFactory instance with configuration PID as the service property
In the ManagedServiceFactory(String pid, Dictionary properties) callback register instances of FooImpl based on the config properties
Sounds like you want to only have one bundle with FooImpl installed but have it register multiple IFoo services, one for each configuration. Look at Declarative Services and use factory configurations with Config Admin to establish the multiple configurations for the DS component.

Resources