I'm trying to understand how to control dependency injection in OSGi (specifically Apache Felix as used in Adobe Experience Manager (AEM)). I have a servlet with an #Reference annotation on a field that references an interface -- in my case, it represents a secure document signing provider. I have an implementation class that implements the interface, and it's automatically injected into the servlet.
In the servlet:
#Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private DocumentSigningProvider signingProvider;
...
URL redirectUrl = signingProvider.Sign(...);
and my implementation class:
#Component(metatype=true)
#Service
#Property(name = "service.ranking", intValue = 1000)
public class DocumentSigningProviderDocuSignImpl implements DocumentSigningProvider {
If I write a second implementation, I can control which one is injected via the service.ranking value -- highest number wins. If no ranking is declared on any of the implementations, the oldest wins.
So far, so good -- except that to change the values I need to recompile and redeploy. I need to control this at runtime, or via a configuration file that's tied to the environment or "runmode". I can't see how to do that.
Since the #Component declares metatype=true, #Property annotations within the class generate a control in the OSGi console's GUI. I can use that GUI to change values at runtime. But the service.ranking is declared in an #Property on the class itself, and it doesn't appear to generate a control in the GUI.
In addition, configuration files named after the class provide default values at runtime, and I can have a different config file for each environment or "runmode". This would work for me too; in one environment I can configure a mock implementation, and use a "real" implementation in another environment. But again, these config files seem to work for #Property declarations inside the class, but not on the class.
I've read a number of threads here about this subject but none touch on exposing service.ranking in the OSGi GUI or in config files.
Is there any way to control which class is injected without modifying, re-compiling and re-deploying source code?
In declarative services you can override any service property at runtime by providing a config for the component and setting the property.
So setting service.ranking=1 or similar should actually work.
One thing to note. By default declarative services binds to the first available service and stays with it. So if you want to make sure a service with a higher ranking is used even if it comes later than the one with the lower ranking then you need this option on the consumer side:
#Reference(policyOption=ReferencePolicyOption.GREEDY)
This makes sure DS switches the service if a better one comes later.
If you want to be more specific what service to use on the consumer side you can also use a filter at runtime.
target.signingProvider=(myproperty=myvalue)
I have collected some more hints here.
Related
I have a component declared using the #Component annotation, in which there is a set of methods that implement communication with another api, in my product there are operations that are prohibited for a user with an anonymous id. I want to create an annotation, for example #ProhibitedForAnonym, which, every time the method is called, will check the ID of the anonymous customer, with the ID in the method parameter and throw an error if the IDs match. But I don't understand how to do annotation processing in OSGI, maybe some kind of interceptor?
There is no general interception framework in OSGi. However, you could do interception in the following ways:
Don't. Personally, I feel that since we've lambdas a code-based solution has won hands on over a 'magic' annotation check. It is about the same number of characters but a lambda based call allows me to single step, provide context to the security check, does not suffer from the THIS problem, is testable, and requires no complex framework with lots of bug opportunities.
Use the byte code weaving support in OSGi. You need to register a weaver early and then weave any class that has these annotations. You can take a look at https://github.com/aQute-os/biz.aQute.osgi.util/tree/master/biz.aQute.trace for an example of how to use the byte code weaver. Make sure your weaver is there first. If you use bndtools you can add it to the -runpath to run before anybody else. Or use start levels.
Use proxying. You can 'hide' and original service with the Service Hooks and then register a proxy. In the proxy you can then do the annotation check. This also requires that this code runs first and cannot be updated. I think the spec has an example of this
You might want to read: https://www.aqute.biz/appnotes/interceptors.html
That's one more attempt to make a dig at the theme "there is no order of OSGI bundles activation".
I have 4 services (bundles) which implement the same interface DataProvider meaning they implement it literally and also have it as service = { DataProvider.class } at their #Component annotations. This interface provides something like diagnostic data from these services. I want to collect this data from all 4 services and to print it on the GUI, which is also an OSGI bundle in my big framework. In order to do that I created such a reference in my GUI bundle:
#Reference
private volatile List<DataProvider> dataProvider;
and then I want to iterate over that list and append to the GUI's textframe everything I need.
The problem is that at the moment when GUI bundle starts, only two of four services are activated, so my list will contain only two service objects instead of all four and print only them. The last two services are loaded after my GUI Bundle has been already activated, because they also wait until their own references become fully satisfied (where some network operations are done, so it takes some time, around 10 seconds). Of course I want my GUI to show the diagnostic data from all 4 services. What could I do for that?
I tried to add policyOption = ReferencePolicyOption.GREEDY to the #Reference annotation, I expected it would force to reactivate GUI bundle each time this List<DataProvider> dataProvider receives a new member, but no, it didn't happen.
P.S. yes there is certainly a straightforward solution: just to add Thread.sleep() to the GUI Bundle with some appropriate value, so to the time of awakening the discussed above list will be full. But this is really bad thing, I don't want the user waits like 10 seconds before GUI appears, not to speak about the situations, when something goes wrong.
You can specify the minimum cardinality in the configuration. In your case, this is specified with the dataProvider.minimum.cardinality property in the configuration for your component. (See section 112.6.2.2 Minimum Cardinality Property.)
package com.example;
#Component
public class Diagnostics {
#Reference
List<DataProvider> dataProvider;
}
So then you need to add a configuration record for PID com.example.Diagnostics:
dataProvider.minimum.cardinality = 4
This model of using configuration works very well with the Configurator Specification. With this specification, you can specify the configuration of an application in a bundle.
Alternatively, you can create 4 references and distinguish the services by a property, using the target annotation method to specify a filter.
The question is old hat - what is a proper design to support a configuration file or system configurations across our system? I've identified the following requirements:
Should be able to reload live and have changes picked up instantly with no redeploying
For software applications that rely on the same, e.g., SQL or memcached credentials, should be possible to introduce the change in an isolated place and deploy in one swoop, even if applications are on separate machines in separate locations
Many processes/machines running the same application supported
And the parts of this design I am struggling with:
Should each major class take its own "Config" class as an input parameter to the constructor? Should there be a factory responsible for instantiating with respect to the right config? Or should each class just read from its own config and reload somewhat automatically?
If class B derives from class A, or composes around it, would it make sense for the Config file to be inherited?
Say class A is constructed by M1 and M2 (M for "main") and M1 is responsible for instantiating a resource. Say the resource relies on MySQL credentials that I expect to be common between M1 and M2, is there a way to avoid the tradeoff of break ownership and put in A's config v. duplicate the resource across M1 and M2's config?
These are the design issues I'm dealing with right now and don't really know the design patterns or frameworks that work here. I'm in Java so any libraries that solve this are very welcome.
You may want to check out Apache Commons Config, which provides a wide range of features. You can specify multiple configuration sources, and arrange these into a hierarchy. One feature of particular interest is the provision for Configuration Events, allowing your components to register their interest in configuration changes.
The goal of changing config on the fly is seductive, but requires some thought around the design. You need to manage those changes carefully (e.g. what happens if you shrink queue sizes - do you throw away existing elements on the queue ?)
Should each major class take its own "Config" class as an input parameter to the constructor?
No, that sounds like an awful design which would unnecessarily overcomplicate a lot of code. I would recommend you to implement a global Configuration class as a singleton. Singleton means that there is only one configuration object, which is a private static variable of your Configuration class and can be acquired with a public static getInstance() method whenever it is needed.
This configuration object should store all configuration parameters as key/value pairs.
Say I have a class with a few fields all marked with a custom annotation. In my case it is #inject, because this is being used for dependency injection. How can I run a method in a separate class each time that annotation is used in my a class? In other words, each time a class is loaded the annotation runs a method that will collect the field data and in turn set the field.
I already have the entire system set up for collecting the resources, but I need some direction on how to actually run that code when the class with #inject annotation is loaded. Is this something that can be done by defining some sort of method in the annotation interface that performs the data collection?
My initial thought is to use a custom class loader, but I don't want to have to set the class loader when I use this jar in other projects. Is there a way to set a custom class loader programmatically for specific classes at runtime? I'm already doing a lot of pre-runtime reflection stuff and i'll already know which classes need to be loaded with a custom loader. Its just a matter of not knowing or if its even possible to set a custom loader on a class from within the code.
Can a classloader even be used to perform tasks such as pre-populating fields, or am I running off on a wrong tangent here? I just need a little direction on the most common way this type of thing is done (pre-populating class fields at runtime).
I was overthinking this problem. You cannot actually run code automatically prior to loading a class (unless its a servlet filter etc). In my situation the answer was to create an instance based on a specific class that already held the resource data I needed. Similar to how Google's Guice does it.
See this question for more insight: How does Guice Populate Annotated Fields
You can use injectors from Google Guice or Spring Framework.
I have a simple problem: I want to configure an object differently based on whether the object is instantiated within a servlet container, or whether it is instantiated in a stand alone app.
The object is a database connection, and I care about setting query timeouts.
The first solution that I can come up with is:
if (insideServletContainer(this.getClass().getClassLoader()) {
/// do some servlet specific config
}
else {
/// do some standalone config
}
The question is, of course, can I write a reliable method of telling whether the class was loaded within a servlet container. It feels like a hack at best.
The second option is to assume that the default case is a stand alone instantiation, set defaults based on stand-alone configuration, and override them within the servlet context.
So, to sum up my question is: Do you know of a good/reliable mechanism if the class was loaded from within a servlet container? If not, I will have to take the second route.
Nick
This seems like a really bad idea. Instead, why don't you allow the class to take parameters, then let the container or app configure it appropriately?
Setting aside whether or not this is a good idea, I'd suggest looking up java:comp/env, which is only going to be available in an EE server:
try {
new InitialContext().lookup("java:comp/env");
/// do some servlet specific config
} catch (NamingException ex) {
/// do some standalone config
}
An alternate way to do this sort of thing is to have the configuration injected into this class by some sort of bootstrap loader.
In a standalone version, this would be done by the main() method (or something called from it).
In a webapp version, this would be done by a listener or filter invoked configured within the web.xml.
Dependency injection is useful here as it removes the need for your application to check these sorts of things; instead the application is given what it needs.
I would recommend Dependency Injection like #matt b.
As a second option, if it is only the simple case you described and you don't want to add or learn a DI framework to support this feature. You can accomplish the same thing as your current code by using a properties file to load different value based on the environment. You can simply use a different file for each environment and supply a VM arg to indicate which environment you are running.
db_prop.dev
db_prop.stalone
dp_prop.int
db_prop.prod
Then you can load by resource
"db_prop." + System.getProperty("runtime.env")