I have a Sling model class containing a reference to a service of mine:
#OSGiService
PlanService planService;
This service has a reference to ResourceResolverFactory, to get a ResourceResolver with the "admin user":
#Reference
private ResourceResolverFactory resolverFactory;
I'm writing a unit test to test adaptTo on my model class. I'm trying to inject the reference to PlanService like this:
#Rule
public final OsgiContext osgiContext = new OsgiContext();
osgiContext.registerInjectActivateService(new PlanServiceImpl());
But I don't know how to inject the reference to the ResourceResolverFactory.
I've tried like this:
osgiContext.registerInjectActivateService(new MockResourceResolverFactory());
But I get this error:
org.apache.sling.testing.mock.osgi.NoScrMetadataException: No OSGi SCR metadata found in classpath at OSGI-INF/org.apache.sling.testing.resourceresolver.MockResourceResolverFactory.xml
I couldn't find in the documentation and among all the mocking options available how to inject this service and get the reference automatically. Any help would be very helpful, thank you!
EDIT:
Thanks to Jérémie's answer, the ResourceResolverFactory is injected in the PlanService. However, I'm now facing this issue:
[main] WARN org.apache.sling.models.impl.ModelAdapterFactory - Required properties [c.r.o.c.s.j.PlanService c.r.o.c.m.Plan.planService] on model class class c.r.o.c.m.Plan were not able to be injected.
I've tried to use the same line than for the ResourceResolverFactory:
osgiContext.registerService(PlanService.class, new PlanServiceImpl());
And also to add
MockModelAdapterFactory mockModelAdapterFactory = new MockModelAdapterFactory();
mockModelAdapterFactory.addModelsForPackage("c.r.o.c.m");
osgiContext.registerService(ModelAdapterFactory.class, mockModelAdapterFactory);
But it's still the same problem...
EDIT 2: registering it with SlingContext instead of OsgiContext fixed the issue:
#Rule
public final SlingContext slingContext = new SlingContext(ResourceResolverType.RESOURCERESOLVER_MOCK);
#Mock
PlanService planServiceMock;
slingContext.registerService(PlanService.class, planServiceMock);
Try this:
osgiContext.registerService(ResourceResolverFactory.class, new MockResourceResolverFactory());
The Javadoc of the OsgiContext is here
I had the same issue, than I used the guide on https://sling.apache.org/documentation/development/osgi-mock.html and I made in the following way. Now it works for me:
BundleContext bundleContext = MockOsgi.newBundleContext();
//register the service
bundleContext.registerService(OtherService.class.getName(), new OtherService(), null);
// get service instance
ServiceReference ref = bundleContext.getServiceReference(OtherService.class.getName());
OtherService service = (OtherService)bundleContext.getService(ref);
Try cleaning and building your project before you test.
For example,
gradlew clean build test
Related
I'm building a Quarkus app which handles http requests with resteasy and calls another api with restclient and I need to propagate a header and add another one on the fly so I added a class that implements ClientHeadersFactory.
Here's the code:
#ApplicationScoped
public abstract class MicroServicesHeaderHandler implements ClientHeadersFactory {
#Inject
MicroServicesConfig config;
#Override
public MultivaluedMap<String, String> update(MultivaluedMap<String, String> incomingHeaders,
MultivaluedMap<String, String> clientOutgoingHeaders) {
// Will be merged with outgoing headers
return new MultivaluedHashMap<>() {{
put("Authorization", Collections.singletonList("Bearer " + config.getServices().get(getServiceName()).getAccessToken()));
put("passport", Collections.singletonList(incomingHeaders.getFirst("passport")));
}};
}
protected abstract String getServiceName();
My issue is that the injection of the config doesn't work. I tried both with #Inject and #Context, as mentioned in the javadoc of ClientHeadersFactory. I also tried to make the class non abstract but it doesn't change anything.
MicroServicesConfig is a #Startup bean because it needs to be initialized before Quarkus.run() is called, otherwise the hot reload doesn't work anymore, since it's required to handle requests.
Here's the code FYI:
#Getter
#Startup
#ApplicationScoped
public final class MicroServicesConfig {
private final Map<String, MicroService> services;
MicroServicesConfig(AKV akv, ABS abs) {
// some code to retrieve an encrypted file from a secure storage, decrypt it and initialize the map out of it
}
It appears to be an issue with ClientHeadersFactory because if I inject my bean in my main class (#QuarkusMain), it works. I'm then able to assign the map to a public static map that I can then access from my HeaderHandler with Application.myPublicStaticMap but that's ugly so I would really prefer to avoid that.
I've searched online and saw several people having the same issue but according to this blogpost, or this one, it should work as of Quarkus 1.3 and MicroProfile 3.3 (RestClient 1.4) and I'm using Quarkus 1.5.2.
Even the example in the second link doesn't work for me with the injection of UriInfo so the issue doesn't come from the bean I'm trying to inject.
I've been struggling with this for weeks and I'd really like to get rid of my workaround now.
I'm probably just missing something but it's driving me crazy.
Thanks in advance for your help.
This issue has finally been solved in Quarkus 1.8.
Suppose I have following code to define someBean:
#Bean
public SomeInterface someBean() {
return new SomeInterfaceImpl();
}
I want to get the interface type, namelySomeInterface, of this bean only from spring container at runtime. I tried the following code, but I found the def object knows nothing about SomeInterface.
ApplicationContext container = new AnnotationConfigApplicationContext...
BeanDefinition def = container.getBeanDefinition("someBean");
Is it possible to get it only from the container object? If possible, please tell me how. Thanks in advance.
I have a straightforward test case. I have a controller which has a parameter of a type Spring doesn't support by default, so I wrote a custom resolver.
I create the mock mvc instance I'm using like so:
mvc = MockMvcBuilders.standaloneSetup(controller).setCustomArgumentResolvers(new GoogleOAuthUserResolver()).build();
However, Spring is also registering almost 30 other argument resolvers, one of which is general enough that it is getting used to resolve the argument before mine. How can I set or sort the resolvers so that mine is invoked first?
This worked for me without reflection:
#RequiredArgsConstructor
#Configuration
public class CustomerNumberArgumentResolverRegistration {
private final RequestMappingHandlerAdapter requestMappingHandlerAdapter;
#PostConstruct
public void prioritizeCustomArgumentResolver () {
final List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>(Objects.requireNonNull(requestMappingHandlerAdapter.getArgumentResolvers()));
argumentResolvers.add(0, new CustomerNumberArgumentResolver());
requestMappingHandlerAdapter.setArgumentResolvers(argumentResolvers);
}
}
The issue was that the People class the Google OAuth library I am using extends Map and the mock servlet API provides no way to manipulate the order in which the handlers are registered.
I ended up using reflection to reach into the mocks guts and remove the offending handler.
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.
I need to get the messageSource in a class in src\groovy. This class is used in UrlMappings.groovy, and at the stage I'm using this class the application is not completely started yet.
Currently I'm using the following and it works:
MessageSource messageSource = ApplicationHolder.application.mainContext.getBean('messageSource')
String message = messageSource.getMessage("code", null, "default", locale)
But the ApplicationHolder is deprecated, is there a way to achieve the same goal without using ApplicationHolder?
//I'm using Grails 2.0.1
From my limited experience, I found that the simplest approach to get the messageSource in a POGO is simply:
Holders.applicationContext.getBean("messageSource")
The other approaches I tried (implementing MessageSourceAware or adding #Component/#Autowired annotations) caused other complications.
try this:
grails.util.GrailsWebUtil.currentApplication().mainContext.messageSource
The recommended way seems to be http://burtbeckwith.com/blog/?p=1017
I.e. create a singleton bean in src/groovy which implements ApplicationContextAware, and then configure it's factoryMethod attribute in grails-app/conf/spring/resources.groovy.
I never like using Singletons which is what Holders, GrailsWebUtil, etc are doing. Instead you can just have grailsApplication injected in your service by doing:
class SomeService {
def grailsApplication
...
}
Then use that to get a message rendered:
String message = grailsApplication.mainContext.getMessage(err, Locale.getDefault()).
Viola take any FieldError, ObjectError, or code and render a message from it.