Paul, you are right. I think there is a bug in the implementation of SingleServiceTracker used to bind service references in commands. The filter is used for the listener but is ignored when retrieving the serviceReference.
For example: If the command starts and the services are available, it will use the first service matching the class and ignore the filter. If the command starts and no service is available, the listener will be called when one service matches the filter. When one matches, SingleServiceTracker.findMatchingReference will be called and the filter is ignored. João Assunção Email: joao.assun...@exploitsys.com Mobile: +351 916968984 Phone: +351 211933149 Web: www.exploitsys.com On Thu, Jul 16, 2020 at 1:42 AM Paul Spencer <paulspen...@mindspring.com> wrote: > Martin, > Parenthesis in the @Reference, > org.apache.karaf.shell.api.action.lifecycle.Reference, for the Command did > not change the results, this the wrong service was returned. Parenthesis > are required for the > @Reference,org.osgi.service.component.annotations.Reference, in the > @Component. > > Details below. > > *** > * From command that uses the RedColor service > * Parenthesis did not return the correct ColorService. > *** > import org.apache.karaf.shell.api.action.Action; > import org.apache.karaf.shell.api.action.Command; > import org.apache.karaf.shell.api.action.lifecycle.Reference; > import org.apache.karaf.shell.api.action.lifecycle.Service; > > import com.example.service.ColorService; > > @Service > @Command(scope = "color", name = "get-red", description = "Get Red > Service") > public class DisplayRedServiceCommand implements Action { > > @Reference(filter = "(color=red)") > private ColorService colorService; > > *** > * Output from Command that get a RedColor service > *** > karaf@root()> color:get-red > Color = BLUE > > *** > * Component the defines the RedColor service > *** > import org.osgi.service.component.annotations.Activate; > import org.osgi.service.component.annotations.Component; > import org.osgi.service.component.annotations.Deactivate; > import org.osgi.service.component.annotations.Modified; > import org.slf4j.Logger; > import org.slf4j.LoggerFactory; > > import com.example.service.ColorService; > > @Component(immediate = true, property = "color=red") > public class RedColorService implements ColorService { > private final Logger log = LoggerFactory.getLogger(getClass()); > > *** > * Component that uses the RedColor Service > *** > import org.osgi.service.component.annotations.Activate; > import org.osgi.service.component.annotations.Component; > import org.osgi.service.component.annotations.Deactivate; > import org.osgi.service.component.annotations.Modified; > import org.osgi.service.component.annotations.Reference; > import org.slf4j.Logger; > import org.slf4j.LoggerFactory; > > import com.example.service.ColorService; > import com.example.service.GenericColorService; > > @Component(immediate = true, property = "color=all") > public class AllColorService implements GenericColorService { > private final Logger log = LoggerFactory.getLogger(getClass()); > > @Reference(target = "(color=red)") > private ColorService redColorService; > > @Reference(target = "(color=green)") > private ColorService greenColorService; > @Reference(target = "(color=blue)") > private ColorService blueColorService; > > @Override > public String getColor() { > StringBuffer colors = new StringBuffer(); > colors.append(redColorService.getColor()); > colors.append(", "); > colors.append(greenColorService.getColor()); > colors.append(", "); > colors.append(blueColorService.getColor()); > return colors.toString(); > } > > *** > * Command that get a two color service > *** > import org.apache.karaf.shell.api.action.Action; > import org.apache.karaf.shell.api.action.Command; > import org.apache.karaf.shell.api.action.lifecycle.Reference; > import org.apache.karaf.shell.api.action.lifecycle.Service; > > import com.example.secondService.TwoColorService; > > @Service > @Command(scope = "yellow", name = "yellow", description = "Get Yellow > Service") > public class DisplayYellowServiceCommand implements Action { > > @Reference > private TwoColorService colorService; > > @Override > public Object execute() throws Exception { > System.out.println("Color = " + colorService.getColor()); > return null; > } > > *** > * Output from Command that get a two color service > *** > karaf@root()> yellow:yellow > Color = RED, GREEN > > > *** > * Component that produces a two color service > *** > import org.osgi.service.component.annotations.Activate; > import org.osgi.service.component.annotations.Component; > import org.osgi.service.component.annotations.Deactivate; > import org.osgi.service.component.annotations.Modified; > import org.osgi.service.component.annotations.Reference; > import org.slf4j.Logger; > import org.slf4j.LoggerFactory; > > import com.example.secondService.TwoColorService; > import com.example.service.ColorService; > > @Component(immediate = true, property = "2color=yellow") > public class YellowColorService implements TwoColorService { > private final Logger log = LoggerFactory.getLogger(getClass()); > > @Reference(target = "(color=red)") > private ColorService redColorService; > @Reference(target = "(color=green)") > private ColorService greenColorService; > > @Override > public String getColor() { > StringBuffer colors = new StringBuffer(); > colors.append(redColorService.getColor()); > colors.append(", "); > colors.append(greenColorService.getColor()); > return colors.toString(); > } > > Paul Spencer > > > > On Jul 15, 2020, at 3:12 PM, Martin Lichtin <lich...@yahoo.com> wrote: > > > > Yes that should work. You need the parenthesis. > > The code is doing something like > > > > String filterString = '(' + Constants.OBJECTCLASS + '=' > + clazz.getName() + ')'; > > if (filter != null && !filter.isEmpty()) { > > filterString = "(&" + filterString + filter + ')'; > > } > > > > On 15.07.2020 18:06, João Assunção wrote: > >> Hello all, > >> > >> Have you tried to use an LDAP filter expression? Instead of > *color=red* try *(color=red). *(I haven't tried this myself) > >> > >> João Assunção > >> > >> Email: joao.assun...@exploitsys.com <mailto: > joao.assun...@exploitsys.com> > >> Mobile: +351 916968984 > >> Phone: +351 211933149 > >> Web: www.exploitsys.com <http://www.exploitsys.com> > >> > >> > >> > >> > >> On Mon, Jul 13, 2020 at 6:33 PM Paul Spencerx <p...@intekon.com > <mailto:p...@intekon.com>> wrote: > >> > >> JB, > >> What is the status of your checking? > >> > >> @Reference for commands is not working for me either. I have > included related code and output from Karaf below. > >> > >> *** > >> * Testing commands > >> *** > >> karaf@root()> color --help > >> SUBSHELL > >> color > >> > >> COMMANDS > >> color:get-any Get any Service > >> color:get-blue Get Blue Service > >> color:get-green Get Green Service > >> color:get-red Get Red Service > >> karaf@root()> color:get-red > >> Color = BLUE > >> karaf@root()> color:get-red > >> Color = BLUE > >> karaf@root()> color:get-red > >> Color = BLUE > >> karaf@root()> color:get-any > >> Color = BLUE > >> karaf@root()> color:get-green > >> Color = BLUE > >> karaf@root()> > >> > >> *** > >> * Available Color Services > >> *** > >> karaf@root()> services -p 165 > >> > >> Karaf Service sandbox (165) provides: > >> ------------------------------------- > >> color = blue > >> component.id <http://component.id> = 9 > >> component.name <http://component.name> = > com.example.service.internal.BlueColorService > >> objectClass = [com.example.service.ColorService] > >> service.bundleid = 165 > >> service.id <http://service.id> = 193 > >> service.scope = bundle > >> ---- > >> color = green > >> component.id <http://component.id> = 10 > >> component.name <http://component.name> = > com.example.service.internal.GreenColorService > >> objectClass = [com.example.service.ColorService] > >> service.bundleid = 165 > >> service.id <http://service.id> = 194 > >> service.scope = bundle > >> ---- > >> color = red > >> component.id <http://component.id> = 11 > >> component.name <http://component.name> = > com.example.service.internal.RedColorService > >> objectClass = [com.example.service.ColorService] > >> service.bundleid = 165 > >> service.id <http://service.id> = 195 > >> service.scope = bundle > >> karaf@root()> > >> > >> *** > >> * Example command source code > >> *** > >> package com.example.command.internal; > >> > >> import org.apache.karaf.shell.api.action.Action; > >> import org.apache.karaf.shell.api.action.Command; > >> import org.apache.karaf.shell.api.action.lifecycle.Reference; > >> import org.apache.karaf.shell.api.action.lifecycle.Service; > >> > >> import com.example.service.ColorService; > >> > >> @Service > >> @Command(scope = "color", name = "get-red", description = "Get Red > Service") > >> public class DisplayRedServiceCommand implements Action { > >> > >> @Reference(filter = "color=red") > >> private ColorService colorService; > >> > >> @Override > >> public Object execute() throws Exception { > >> System.out.println("Color = " + > colorService.getColor()); > >> return null; > >> } > >> > >> } > >> > >> *** > >> * Example Service source code > >> *** > >> package com.example.service.internal; > >> > >> import org.osgi.service.component.annotations.Component; > >> > >> import com.example.service.ColorService; > >> > >> @Component(immediate = true, property = "color=red") > >> public class RedColorService implements ColorService { > >> > >> @Override > >> public String getColor() { > >> return "RED"; > >> } > >> > >> } > >> > >> > >> Paul Spencer > >> > >> > >> > On Mar 12, 2020, at 9:41 AM, Alex Soto <alex.s...@envieta.com > <mailto:alex.s...@envieta.com>> wrote: > >> > > >> > Just to clarify, when I say it does not work, I mean that the > injected service is not the correct one matching the filter expression. > >> > > >> > Best regards, > >> > Alex soto > >> > > >> > > >> > > >> > > >> >> On Mar 12, 2020, at 9:24 AM, Jean-Baptiste Onofre < > j...@nanthrax.net <mailto:j...@nanthrax.net>> wrote: > >> >> > >> >> Hi, > >> >> > >> >> Let me check, but AFAIR, I have a test about that and it seems to > work. > >> >> > >> >> I will create a Jira to double check. > >> >> > >> >> Regards > >> >> JB > >> >> > >> >>> Le 12 mars 2020 à 14:23, Alex Soto <alex.s...@envieta.com > <mailto:alex.s...@envieta.com>> a écrit : > >> >>> > >> >>> I see, but it is not working for me… > >> >>> > >> >>> The PR does not update > org.apache.karaf.shell.impl.action.command.ManagerImpl#instantiate, > shouldn’t this method be updated also to inject the appropriate service > when the command is instantiated? (See code fragment I pasted earlier) > >> >>> > >> >>> > >> >>> Best regards, > >> >>> Alex soto > >> >>> > >> >>> > >> >>> > >> >>> > >> >>>> On Mar 12, 2020, at 9:07 AM, Jean-Baptiste Onofre < > j...@nanthrax.net <mailto:j...@nanthrax.net>> wrote: > >> >>>> > >> >>>> Hi Alex, > >> >>>> > >> >>>> You can find the change I did about that here: > >> >>>> > >> >>>> https://github.com/apache/karaf/pull/992 > >> >>>> > >> >>>> Regards > >> >>>> JB > >> >>>> > >> >>>>> Le 12 mars 2020 à 14:02, Alex Soto <alex.s...@envieta.com > <mailto:alex.s...@envieta.com>> a écrit : > >> >>>>> > >> >>>>> Thanks, JB > >> >>>>> > >> >>>>> But it doesn’t seem to work for Karaf 4.2.8. > >> >>>>> I am not familiar with the internals of Karaf code, but I > spotted the following in > org.apache.karaf.shell.impl.action.command.ManagerImpl.instantiate of > org.apache.karaf.shell.core-4.2.8.jar: > >> >>>>> > >> >>>>> Reference ref = field.getAnnotation(Reference.class); > >> >>>>> if (ref != null) { > >> >>>>> GenericType type = new > GenericType(field.getGenericType()); > >> >>>>> Object value; > >> >>>>> if (type.getRawClass() == List.class) { > >> >>>>> Set<Object> set = new HashSet<>(); > >> >>>>> > set.addAll(registry.getServices(type.getActualTypeArgument(0).getRawClass())); > >> >>>>> if (registry != this.dependencies) { > >> >>>>> > set.addAll(this.dependencies.getServices(type.getActualTypeArgument(0).getRawClass())); > >> >>>>> } > >> >>>>> value = new ArrayList<>(set); > >> >>>>> } else { > >> >>>>> value = > registry.getService(type.getRawClass()); > >> >>>>> if (value == null && registry != > this.dependencies) { > >> >>>>> value = > this.dependencies.getService(type.getRawClass()); > >> >>>>> } > >> >>>>> } > >> >>>>> if (!allowCustomServices && value == null > && !ref.optional()) { > >> >>>>> throw new IllegalStateException("No > service matching " + field.getType().getName()); > >> >>>>> } > >> >>>>> field.setAccessible(true); > >> >>>>> field.set(instance, value); > >> >>>>> } > >> >>>>> > >> >>>>> Maybe this is not the relevant piece of code, but I do not see > that the filter attribute is being used to look up the service. > >> >>>>> > >> >>>>> > >> >>>>> Best regards, > >> >>>>> Alex soto > >> >>>>> > >> >>>>> > >> >>>>> > >> >>>>> > >> >>>>>> On Mar 12, 2020, at 12:50 AM, Jean-Baptiste Onofre < > j...@nanthrax.net <mailto:j...@nanthrax.net>> wrote: > >> >>>>>> > >> >>>>>> Hi, > >> >>>>>> > >> >>>>>> Yes, it’s to "select" the service you want to use. > >> >>>>>> > >> >>>>>> I did the change because previously it wasn’t possible to > select, meaning that if you had several services (with the same interface) > available, it took the first one. > >> >>>>>> > >> >>>>>> Now, you can specify the LDIF filter to select the exact > service you want to inject. > >> >>>>>> > >> >>>>>> Regards > >> >>>>>> JB > >> >>>>>> > >> >>>>>>> Le 11 mars 2020 à 20:03, Alex Soto <alex.s...@envieta.com > <mailto:alex.s...@envieta.com>> a écrit : > >> >>>>>>> > >> >>>>>>> Is the filter attribute in annotation > org.apache.karaf.shell.api.action.lifecycle.Reference used to filter the > injected service on Service attributes? > >> >>>>>>> > >> >>>>>>> Best regards, > >> >>>>>>> Alex soto > >> >>>>>>> > >> >>>>>>> > >> >>>>>>> > >> >>>>>>> > >> >>>>>> > >> >>>>> > >> >>>> > >> >>> > >> >> > >> > > >> > >