How to consume OSGi service from OSGi HTTP Service - osgi

I have a bundle A which exposes the following service:
In OSGI-INF/config.xml
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
name="com.example.MyService" modified="updated" immediate="true">
<implementation class="com.example.impl.MyServiceImpl"/>
<service>
<provide interface="com.example.MyService"/>
</service>
</scr:component>
Next step, I want to consume this service from a servlet in bundle B.
What I do is the following:
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
BundleContext bundleContext = (BundleContext) getServletContext().getAttribute("osgi-bundlecontext");
if (bundleContext != null) {
// Here MyService is the service exposed as declarative service
MyService myService = getService(bundleContext, MyService.class);
if(myService != null) {
// I want to invoke some method declared in MyService interface
myService.invokeMyServiceMethod();
}
}
}// end of doPost
protected <T> T getService(BundleContext bundleContext, Class<T> type) {
ServiceReference<T> serviceRef = bundleContext.getServiceReference(type);
if (serviceRef == null) {
return null;
}
T service = bundleContext.getService(serviceRef);
return service;
}// end of getService method
As services in OSGi come and go, is it correct to assume that even if the check for non null reference in doPost method passes, the next statement myService.invokeMyServiceMethod() will not throw NPE?
How can I guarantee that I will always get a valid reference to MyService from service registry?
If this is not the correct way of getting service reference from Http Service, what is the correct one?
I am using Equinox as OSGi implementation.
Cheers,
Boris

I think you've missed a few bits of declarative services (DS) :-) The whole idea of DS that you specify your dependencies in the XML (or MUCH MUCH better with the annotations). This is how the servlet should look like:
#Component(provide=Servlet.class)
public class MyServlet extends HttpServlet {
T myService;
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
myService.invokeMyServiceMethod();
}
#Reference
T setT(T t) {
myService =t;
}
}
The only thing required is to ensure you have Apache Felix's Http Whiteboard bundle installed (yes, it works fine on Equinox, the beauty of standards). This bundle watches any Servlet services being registered and adds them to the Http Service. Since DS ensures that your component is not registered until it has the myService, you myService is guaranteed to be non-null. This is called the DS static mode: all your dependencies are satisfied before you get called.
If you're brave, you could declare the setT method to be dynamic. Then your component would be registered even if there is no T service. E.g. allows you to tell the caller there is no service. This is called the dynamic mode.
The used annotations are standard DS. They are processed by bnd and turned into the XML. This works in maven, gradle, etc. but best of all of course in bndtools.

Related

init method in jersey jax-rs web service

I'm new with jax-rs and have build a web service with jersey and glassfish.
What I need is a method, which is called once the service is started. In this method I want to load a custom config file, set some properties, write a log, and so on ...
I tried to use the constructor of the servlet but the constructor is called every time a GET or POST method is called.
what options I have to realize that?
Please tell, if some dependencies are needed, give me an idea how to add it to the pom.xml (or else)
There are multiple ways to achieve it, depending on what you have available in your application:
Using ServletContextListener from the Servlet API
Once JAX-RS is built on the top of the Servlet API, the following piece of code will do the trick:
#WebListener
public class StartupListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
// Perform action during application's startup
}
#Override
public void contextDestroyed(ServletContextEvent event) {
// Perform action during application's shutdown
}
}
Using #ApplicationScoped and #Observes from CDI
When using JAX-RS with CDI, you can have the following:
#ApplicationScoped
public class StartupListener {
public void init(#Observes
#Initialized(ApplicationScoped.class) ServletContext context) {
// Perform action during application's startup
}
public void destroy(#Observes
#Destroyed(ApplicationScoped.class) ServletContext context) {
// Perform action during application's shutdown
}
}
In this approach, you must use #ApplicationScoped from the javax.enterprise.context package and not #ApplicationScoped from the javax.faces.bean package.
Using #Startup and #Singleton from EJB
When using JAX-RS with EJB, you can try:
#Startup
#Singleton
public class StartupListener {
#PostConstruct
public void init() {
// Perform action during application's startup
}
#PreDestroy
public void destroy() {
// Perform action during application's shutdown
}
}
If you are interested in reading a properties file, check this question. If you are using CDI and you are open to add Apache DeltaSpike dependencies to your project, considering having a look at this answer.

Which #Scope should I choose for a stateful(?) #Service

I'm new to Spring.
I'm working on a library project which depends on spring-context.
#Scope(value = "##?")
#Service
public class MyService {
#PostConstruct private void constructed() {
}
#PreDestroying private void destroying() {
resource.clear();
}
public void doSome() throws IOException {
// try{}finally{} is not the case
resource = getSome();
doSome(resource); // may throw an IOException
resource.clear();
}
private transient MyResource resource;
}
I want to free the resource in every time this instance being destroyed.
According to #Scope, there four options that I can choose.
ConfigurableBeanFactory.SCOPE_SINGLETON
ConfigurableBeanFactory.SCOPE_PROTOTYPE
WebApplicationContext.SCOPE_REQUEST
WebApplicationContext.SCOPE_SESSION
I found that WebApplicationContext is not available from my dependency tree. (I'm not depends on spring-webmvc)
I'm planning to choose ConfigurableBeanFactory.SCOPE_PROTOTYPE.
Is it true that the scope I choose will make MyService safe? I mean any two or more clients can't be injected with the same service instance? Will the Spring container take care of it?
Indeed, Request, Session, Global-session and Application scopes are only available within Web aware application context.
Singleton (single instance per Spring container) is a default scope used by Spring, so using prototype scope will guarantee that new instance will be created and returned to the client, so yes Prototype is what you need in this case.

Jersey and HK2 ServiceLocator

I'm trying to initialize some components in my Jersey application in the Application constructor (the thing that inherits from ResourceConfig) . It looks like this
public Application(#Context ServletContext context,
#Context ServiceLocator locator)...
When I try to use the locator at any point, I still can't create instances of things that I have registered in an AbstractBinder using the locator.create(MyThing.class) method.
I'm certain that they are bound correctly because they are injected properly into my resource classes via the #inject field annotation.
The difference is that the Jersey/HK2 framework is instantiating my resource classes (as expected, since they're in my package scan path), but I can not seem to leverage the ServiceLocator through code.
My ultimate goal is to have other non-jersey classes injected when they have the #Inject attribute, eg. I have a worker class that needs to be injected with the configured database access layer. I want to say
locator.Create(AWorker.class)
and have it injected.
How do I get the real ServiceLocator that will inject everything I've already registered/bound with my Binder? (Or should I be using something other than ServiceLocator?)
I am going to assume you are starting up a servlet and have a class extending org.glassfish.jersey.server.ResourceConfig and your bindings are correctly registered (e.g. using a Binder and registerInstances). If you then want to access the ServiceLocator in order to perform additional initialization, you have two choices:
One approach is to register a ContainerLifecycleListener (as seen here in this post):
// In Application extends ResourceConfig constructor
register(new ContainerLifecycleListener() {
#Override
public void onStartup(final Container container) {
// access the ServiceLocator here
final ServiceLocator serviceLocator = container.getApplicationHandler().getInjectionManager().getInstance(ServiceLocator.class);
// Perform whatever with serviceLocator
}
#Override
public void onReload(final Container container) {
/* ... */}
#Override
public void onShutdown(final Container container) {
/* ... */}
});
The second approach is to use a Feature, which can also be auto-discovered using #Provider:
#Provider
public final class StartupListener implements Feature {
private final ServiceLocator sl;
#Inject
public ProvisionStartupListener(final ServiceLocator sl) {
this.sl = sl;
}
#Override
public boolean configure(final FeatureContext context) {
// Perform whatever action with serviceLocator
return true;
}
How are you starting up your container? If you are using ApplicationHandler, you can just call:handler.getServiceLocator(). The ServiceLocator is, indeed, what you want to be using to access your dependencies.
If you are starting up a servlet, I found that the best way to get access to the service locator was to have a Jersey feature set it on my startup class:
private static final class LocatorSetFeature implements Feature {
private final ServiceLocator scopedLocator;
#Inject
private LocatorSetFeature(ServiceLocator scopedLocator) {
this.scopedLocator = scopedLocator;
}
#Override
public boolean configure(FeatureContext context) {
locator = this.scopedLocator; // this would set our member locator variable
return true;
}
}
The feature would just be registered with our resource config with config.register(new LocatorSetFeature()).
It would be important to tie in startup of other components based on the lifecycle of your container, so this still feels a bit hacky. You might consider adding those classes as first class dependencies in the HK2 container and simply injecting the appropriate dependencies into your third party classes (using a Binder, for example).

Problems injecting a BayeuxService into another class with annotations

I have a web app that is using Bayeux to handle Comet connections. I initialize a BayeuxServer and tie it into Spring annotations and it all works fine, listening on selected channels and responding.
I have a Jersey annotated class and an annotated Bayeux service as shown below. The idea is I wanted to be able to control resources via Rest from an individual web app, and then right after the resource is changed, do a server push via Comet to all other applicable clients to tell them to update their information.
Here is the problem: A Bayeux Service is created when the webapp is deployed, setting up proper channels to listen on and monitoring clients. There should only be one instance of this. When Jersey attempts to use the Bayeux service it creates a whole new service, when it should be using the original one. This new service doesn't have the BayeuxServer properly injected so I can't access client information through it.
It makes since that this should be doable, but I don't seem to understand how to inject these things properly via annotations. Can anyone point me in the right direction?
Jersey Annotated Class:
#Path("JsonTest")
public class JsonTest {
#Context
Request request;
#Context
UriInfo uriInfo;
#Context
ResourceContext resourceContext;
protected final Logger log = Logger.getLogger(getClass());
public JsonTest() {
}
#DELETE
#Path("{id}")
public void deleteJson(#PathParam("id") String id) {
JsonTestDao.instance.getModel().remove(id);
log.info("Deleted Json..." + id);
log.info("New json: " + JsonTestDao.instance.getModel().toString());
JsonTestService jsonTestService = resourceContext.getResource(JsonTestService.class);
jsonTestService.sendUpdate();
}
}
BayeuxService:
#Named
// Singleton here didn't seem to make a difference
#Service
public class JsonTestService {
protected final Logger log = Logger.getLogger(getClass());
#Inject
private BayeuxServer bayeux;
#Session
private ServerSession serverSession;
#PostConstruct
public void init() {
log.info("Initializing JsonTest Bayeux HelloService...");
log.info("Current sessions are: " + bayeux.getSessions().toString());
}
#Listener("/cometd/JsonTest")
public void jsonTestHandler(ServerSession remote, ServerMessage.Mutable message) {
}
public void sendUpdate() {
//bayeux.newMessage(); // Need a method that the Jersey class can call to notify changes
log.info("Bayeux server should be sending an update now...");
}
#PreDestroy
public void destroy() {
log.info("Destroying JsonTest Bayeux HelloService...");
}
}
See Jersey and spring integration - bean Injections are null at runtime.
Another question I asked. Both of these stem from the same problem involving properly setting the Jersey dependency and integrating it with spring.

EasyMock object for unit testing involving scope="request" bean

I am trying to add some Unit Testing to some of our companies code. Yes, I know it should already be there, but not everyone seems to have the same view of unit testing that I do.
However, I have come against a bit of a stopper for me. Admittedly, my Java, Spring and Unit Testing knowledge are not all that they should be. My problem is this though:
I have added a unit test to my code, which tests a class. This class includes a bean which has scope="request", and when it tries to instantiate the bean it throws an exception:
java.lang.IllegalStateException: No Scope registered for scope 'request'
I believe this is because I don't have a HttpServletRequest object, but I don't know how to create a mock one of these and also I don't know how, once created, to add this Mock Object to the unit test so that it resolves this problem.
Below is a cut down version of the code involved, which I believe includes all of the details that are part of this problem.
How can I get this to work?
#Test
public void handleRequest() {
try {
Message<?> outMessage = (Message<?>) response.handleRequest(map);
} catch (Exception e) {
assertNotNull(e);
}
outMessage.getPayload().toString());
}
public class upddResponse extends AbstractResponseTransform {
#SuppressWarnings("unchecked")
public Message<?> handleRequest(Map<String, Message<?>> messages) throws Exception {
super.addEnvironmentDetails(serviceResponseDocument.getServiceResponse());
}
public abstract class AbstractResponseTransform implements ResponseTransform,
ApplicationContextAware {
private ApplicationContext applicationContext;
private MCSResponseAggregator mcsResponseAggregator;
public ServiceResponseType addEnvironmentDetails(ServiceResponseType serviceResponse) throws Exception {
try {
mcsResponseAggregator = (MCSResponseAggregator) applicationContext
.getBean("mcsResponseAggregator");
}
catch (Exception ex) {
}
}
}
public interface ResponseTransform extends Transform {
public Message<?> handleRequest(Map<String, Message<?>> messages)
throws Exception;
}
<bean id="mcsResponseAggregator" class="com.company.aggregator.MCSResponseAggregator" scope="request" />
You need a WebApplicationContext to handle beans with: scope="request"
I recommend to use stub objects with Spring integration tests and use EasyMock without Spring when you test a class isolated.
You can use mocks within the Spring Context:
but that will not solve your problem as it will not make Spring understand scope="request". You can create your own implementation of the request scope, but I'm getting the feeling that you're better off not going through all this trouble.
The easy way out would be to override your request scoped bean in a little test context. You're technically not testing the original context then, but you will be done a lot quicker.
Spring 3.2 comes with support for this. See "Spring MVC Test Framework"

Resources