Does Sling allow Component Filters configured to target only certain resource types? - osgi

I've found Sling's ability to associate Servlets with certain resource types, selectors and extentions, methods really useful in component development.
Now I'm starting to look into the ComponentFilterChain & would like to create filters that only register against certain resource types, in the same way as Servlets above.
From the Example filters on the Sling project, I see that there's a pattern property that you can apply for particular paths, though it feels like this limits the benefit of having components.
Really what I'm looking for is an equivalent property to sling.servlet.resourceType that I can annotate my Filter with so that only certain components enter this filter as part of the component filter chain, rather than having to check the component resourceType/superResourceType within the Filter.
Is this possible with Sling filters? Or is there an equivalent approach that can be used?

Out of the box, there's no way to associate servlet Filters with Sling resource types. Composing OSGi services, maybe using sling:resourceType values set as service properties, should allow you to provide similar functionality.

As of Apache Sling 2.6.14, there is an option to associate Sling Filters with resource types.
The property you need to add to your OSGi service to achieve this is sling.filter.resourceTypes.
There's a set of annotations available that make the job easier.
From the Sling Documentation
//...
import org.apache.sling.servlets.annotations.SlingServletFilter;
import org.apache.sling.servlets.annotations.SlingServletFilterScope;
import org.osgi.service.component.annotations.Component;
#Component
#SlingServletFilter(scope = {SlingServletFilterScope.REQUEST},
suffix_pattern = "/suffix/foo",
resourceTypes = {"foo/bar"},
pattern = "/content/.*",
extensions = {"txt","json"},
selectors = {"foo","bar"},
methods = {"GET","HEAD"})
public class FooBarFilter implements Filter {
// ... implementation
}

Related

Set a ListMoveChange filter when using OptaPlanner Spring Boot starter

We are using the OptaPlanner Spring Boot starter to create a vehicle routing problem solver based on the example in the OptaPlanner quickstarts:
https://github.com/kiegroup/optaplanner-quickstarts/tree/stable/use-cases/vehicle-routing
So we do not have an solveConfig.xml file. We would like to define a filter for ListChangeMoves but it's not clear how we would register this without using an XML file. We have tried using a solverConfig.xml e.g.
<localSearch>
<unionMoveSelector>
<listChangeMoveSelector>
<filterClass>my.filter.Class</filterClass>
</listChangeMoveSelector>
</unionMoveSelector>
</localSearch>
But this is not working. Is there an example of setting up a filter for list moves?
This is a XML solver config using a a swap move selector and a change move selector with move filtering:
<constructionHeuristic/>
<localSearch>
<unionMoveSelector>
<changeMoveSelector>
<filterClass>org.acme.vehiclerouting.solver.ChangeMoveSelectorFilter</filterClass>
</changeMoveSelector>
<swapMoveSelector/>
</unionMoveSelector>
</localSearch>
If you don't want to use swap moves, then you don't need the union move selector and the configuration can be simplified to:
<constructionHeuristic/>
<localSearch>
<changeMoveSelector>
<filterClass>org.acme.vehiclerouting.solver.ChangeMoveSelectorFilter</filterClass>
</changeMoveSelector>
</localSearch>
A few comments:
I'm including the CH phase because it is necessary in a typical case. See OptaPlanner terminates immediately if I add constructionHeuristic config for an explanation.
The ChangeMoveSelector is automatically configured to produce ListChangeMoves if the planning entity has a #PlanningListVariable. There is no <listChangeMoveSelector> config element.
More information including how to implement the move selection filter can be found in the documentation.
UPDATE: No XML configuration
It's possible to inject SolverConfig, modify it and then use it to create other objects, for example Solver, SolverManager, and ScoreManager.
The code would look something like this:
#Component
class MyService {
// Don't inject these.
private final SolverManager<VrpSolution, Long> solverManager;
private final ScoreManager<VrpSolution, HardSoftScore> scoreManager;
// But inject the SolverConfig.
public MyService(SolverConfig solverConfig) {
// And instantiate SolverManager and ScoreManager manually.
this.solverManager = SolverManager.<VrpSolution, Long>create(
solverConfig.withPhaseList(Arrays.asList(
new ConstructionHeuristicPhaseConfig(),
new LocalSearchPhaseConfig().withMoveSelectorConfig(
new ChangeMoveSelectorConfig()
.withFilterClass(MyFilter.class)))));
this.scoreManager = ScoreManager.create(SolverFactory.create(solverConfig));
}
}
Pros:
SolverConfig will be initialized by OptaPlannerAutoConfiguration (from optaplanner-spring-boot-starter) before it's injected into your component. That means:
The solution and entity classes will be auto-discovered and you don't have to specify them (which you have to in solverConfig.xml).
You can use application.properties to do minor solver config tweaks, for example set time-spent termination.
Cons:
You have to create Solver,SolverManager, and ScoreManager instances manually. Specifically, you can't have a #Bean method producing an instance of one of the types above because that would deactivate OptaPlannerAutoConfiguration, which creates the SolverConfig bean.

How to map service factory PIDs to their `ObjectClassDefinition`

In OSGi R6 I desire to programmatically validate user-supplied String configuration properties plus a service factory PID against what is supported by whatever configurable #Component (or ManagedServiceFactory) that declares it configures this PID, e.g. #Component(configurationPid=some.service.factory.pid, ...). Additionally, I want to somehow convert valid String properties to their appropriate property types. Looking through the OSGi Compendium, it seems the Metatype Service is what I'm looking for.
If that's correct, given the following:
Applicable components uses component property types to specify their configuration
Component property types are annotated with #ObjectClassDefinition
Components are annotated with #Designate, mapping it to the applicable #ObjectClassDefinition
Is this the most straightfoward way to map factory PIDs to their ObjectClassDefinition:
Call BundleContext.getBundles(). For each bundle, call MetaTypeService.getMetaTypeInformation(Bundle).
For each returned MetaTypeInformation call MetaTypeInformation.getFactoryPids() and filter on the factory PIDs I care about.
For applicable MetaTypeInformation, call MetaTypeInformation.getObjectClassDefinition(String, String) to obtain the ObjectClassDefinition, using either a default or specific locale.
(Tangential, the above seems expensive to perform each time, so caching bundle IDs, mapping them to associated factory PIDs, and keeping the cache up-to-date somehow seems appropriate.)
Or, is there some other OSGi magic that can be programmatically queried with a service factory PID, which returns something that gets to some ObjectClassDefinition quicker than the above process?
Update 1
Stepping back, I'm writing a CRUD-wrapper around ConfigurationAdmin for each of my configurable components. I'm trying to avoid createFoo, deleteFoo, updateFoo, createBar, ... My application happens to be amenable to URIs. So my working approach was to use Metatype Service, pass in a parsed URI query (Map<String, List<String>>), and then utilize Metatype Service to validate and reconstruct these values, circling back to the OP. (On the side, seems like a not-pretty hack to me.)
Another approach was to use aQute.bnd.annotations.metatype.Configurable.createConfigurable(Class, Map), which I preferred more! Until I saw this bnd GitHub comment:
The bnd metatype annotations are deprecated in bnd 3.2 and will be removed in bnd 4.0. These annotations are replaced by the OSGi metatype annotations.
So I didn't want to rely on that package if it's going away soon. I looked at what Felix does and didn't want to use their equivalent Configurable class. I'm all ears on different approaches!
Update 2
Reducing this more, I'd like to validate potentially user-supplied key/values configuration properties to ensure they're applicable for some configuration pid, prior to calling ConfigurationAdmin.createFactoryConfig. Maybe this is overkill?
I once created a class that takes the configuration class, creates a proxy, and then uses this proxy to get the name of the method and the type. It was used something like this:
ConfigHelper<Config> helper = new ConfigHelper( Config.class, "my.pid");
int port = helper.get().port(); // get the configuration
helper.set( helper.get().port(), 1000);
helper.update();
The proxy you get from the get would record the method when one of the methods is called. On the set method it would use the last called proxy method to identify the property. It would then convert the given value to the property type based on the method's return value. The bnd converter is ideal for this but I think Felix now has a standard OSGi converter. (Which is based on the ideas of the bnd converter.)
The method name is then used as the property. The name mangling necessary is defined in an OSGi spec. This allows you to use underscores, Java keywords, and dotted names.
So this would allow you to roundtrip configurations. No worry about the types, they will automatically fall in their place.
Updated This is updated after I understood the question better
Updated 2 Added an example at https://github.com/aQute-os/biz.aQute.osgi.util/tree/master/biz.aQute.osgi.configuration.util

#Reference from Servlet Filter

I am writing a Servlet Filter and would like to use one of my Liferay components using #Reference:
package my.filter;
import my.Compo;
import org.osgi.service.component.annotations.Reference;
public class MyFilter implements Filter {
#Override
public void doFilter(...) {
compo.doTheThing();
}
#Reference(unbind = "-")
protected my.Compo compo;
}
I get this Java compilation error:
annotation type not applicable to this kind of declaration
What am I doing wrong?
Is it maybe impossible to achieve this?
As tipped by Miroslav, #Reference can only be used in an OSGi component, and a servlet filter is not one.
The solution in Liferay 7 is to develop a filter component.
The procedure to do so is explained at http://www.javasavvy.com/liferay-dxp-filter-tutorial/
You can make a simple filer like: https://www.e-systems.tech/blog/-/blogs/filters-in-liferay-7 and http://www.javasavvy.com/liferay-dxp-filter-tutorial/
But you can also use regular filters, as long you configure you Liferay webapp for that -> there are two consequences if you use regular filters though: you will be out of osgi application and you will have to keep track of this whenever you update your bundle. That is why you should not go with regular implementation. (just complementing the OP answer with the underlining reason to avoid the initial track)

How to list resolvedDataSources from AbstractRoutingDataSource?

I implemented Dynamic DataSource Routing using Spring Boot (JavaConfig) to add and switch new DataSources in runtime.
I implemented AbstractRoutingDataSource and I need access to all resolvedDataSources that is a private property. How can I do it?
I actually don't know why that field has not been made protected to let implementing classes access the data sources set. Regarding your questions two options come into my mind.
Option 1:
Copy the code of AbstractRoutingDataSource into a class of your own. Then you can expose the resolvedDataSources simply by a getter. This should work as long as the configuration relies on the interface AbstractDataSource and not AbstractRoutingDataSource.
Option 2
Pick the brute force way by accessing the field via Reflection API

Configurable Component Scan

Is there a way to make the component scan configurable externally or through an intermediate resolver class? My requirement is that a common library should include one or more of other smaller facilities (each having their own controller, services etc.) depending on whether those are "configured" or needed - e.g. in application properties.
The closest I can see a possibility of designing this is to declare a #Configuration class in the common library and keep it in the component scan class path (always). In this class I need some way to say that the following are the allowed scan paths (based on how downstream projects have configured their application properties).
Seems like TypeFilter custom implementation should do it. But how do I read application properties from inside the type filter implementation (annotation takes only the .class, so Spring must be initializing it.
Any other ways? Thanks!
Regards,
Arnab.
This document describes how to create your own Auto-Configuration. It allows you to read properties and utilize several variations of #Conditional annotation.

Resources