Getting references of a factory service (OSGI - AEM Context) - osgi

I am trying to get references to a factory service I created (in AEM 6.4.6) and am failing. Here is the code (Did try searching for similar ones, but did not find a direct answer. I might not have searched enough or what i am doing might be completely wrong.. Looking forward to responses from experts).
Update 3: (Update 1 and 2 at the end) - This is a question on how i can get it using references. However would also be great if experts can share other methods.
Service code (in the first bundle)
public interface GodaDataServiceFactory {
List<GodaDataBean> getData();
}
Service Impl Code (Another bundle - Second bundle, Note its a factory)
#Component(
service = GodaDataServiceFactory.class,
factory = "GodaDataServiceFactory",
configurationPolicy = ConfigurationPolicy.REQUIRE
)
#Designate(ocd = GodaDataServiceFactoryConfig.class, factory = true)
public class GodaDataServiceFactoryJcrImpl implements GodaDataServiceFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(GodaDataServiceFactoryJcrImpl.class);
#Override
public List<GodaDataBean> getData() {
return null;
}
}
Snaps of the configs
Reference
Option 1 (Direct reference):
#Reference(target = "(sample=test)")
private GodaDataServiceFactory godaDataServiceFactory;
Option 2 (Indirect using bind and unbind)
#Reference(
name = "godaDataServiceFactory",
cardinality = ReferenceCardinality.MULTIPLE,
policy = ReferencePolicy.DYNAMIC,
bind = "bindGodaDataServiceFactory",
unbind = "unbindGodaDataServiceFactory")
List<GodaDataServiceFactory> godaDataServiceFactoryList = new ArrayList<>();
protected synchronized void bindGodaDataServiceFactory(final GodaDataServiceFactory config) {
LOGGER.info("Goda config factory: {}", config);
godaDataServiceFactoryList.add(config);
}
protected synchronized void unbindGodaDataServiceFactory(final GodaDataServiceFactory config) {
godaDataServiceFactoryList.remove(config);
}
None of this seems to work. In the first case godaDataServiceFactory, it is null. The second case, the list is always empty. Note that the consumer is a servlet.
My GitHub Repos
Consumer -> https://github.com/GodaProjects/aem646
API -> https://github.com/GodaProjects/api
API IMPL -> https://github.com/GodaProjects/apiImplJcr
Update 1:
For option 1, The servlet remains unsatisfied.
Reference godaDataServiceFactory
Unsatisfied
Service Name: com.goda.core.services.GodaDataServiceFactory
Target Filter: (sample=test)
Cardinality: 1..1
Policy: static
Policy Option: reluctant
No Services bound
For the second option,the list remains empty
Update 2
Consumer project is created using Archetype 13 (has the servlet which consumes the factory service) -> https://github.com/GodaProjects/aem646
API project is created using Archetype 18 (has the API interface for the factory) -> https://github.com/GodaProjects/api
API IMPL project is created using Archetype 18 (has the implementation for the API which is in the API project) -> https://github.com/GodaProjects/apiImplJcr

I think i got it. The root cause of the issue seemed to be having the same package structure in 3 separate bundles (aem652, api and apiJcrImpl have the same package com.goda.core). This qualifies in to the realm of split bundles which is discouraged by OSGi anyway. Also the behavior was a lot unpredictable. It was looking for classes from one bundle in another where it does does not exist and was throwing "classnotfound"s. Got really confusing. Anyway its clearing that they were masking each other in a pattern, which I neither had time nor energy to figure out. Suffice to say, what i did was not very prudent. So here goes. this is the solution.
Edit:
Consumer https://github.com/GodaProjects/aem652
API https://github.com/GodaProjects/api
API Impl https://github.com/GodaProjects/apiImplJcr

Related

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.

Dependency Injection with dynamically instanciated class with Spring Boot

I'm trying to develop a spring-boot application which offer the possibility for the user to create and call some simple workflows.
The steps of the workflows are already written (they all extends the same class), and, when the user create a workflow, he/she just pick which steps he wants to include in his it. The steps and the workflows are saved in a database.
My problem comes when the user call the workflow: I want to instanciate dynamically each step using the class loader but with the dependencies injected by spring!
Here is an example of a plug-in:
public class HelloWorldStepPlugin extends StepPlugin {
private static final Logger LOG = LogManager.getLogger();
#Autowired
private HelloWorldRepository repository;
public HelloWorldStepPlugin() {
super(HelloWorldStepPlugin.class.getSimpleName());
}
#Override
public void process() {
LOG.info("Hello world!");
this.repository.findAll(); // <= throw a NullPointerException because this.repository is null
}
}
Here is how I execute a Workflow (in another class):
ClassLoader cl = getClass().getClassLoader();
for (Step s : workflow.getSteps()) {
StepPlugin sp = (StepPlugin) cl.loadClass(STEP_PLUGIN_PACKAGE + s.getPlugin()).newInstance();
sp.process();
}
How can I do to have my HelloWorldRepository injected by Spring?
Is there a much better approach to do what I intend to?
I suggest you declare your steps as prototype beans. Instead of saving class names in the database, save bean names. Then get the steps and the plugins from the spring context (i.e. using getBean()).

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 how to run mutliple instances of one service

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.

Resources