Access ServletContext resources in CDI Extension - java

I'm facing the following situation: I have written a CDI extension, with which I want to programatically register additional beans into the BeanManager. I've already implemented the extension and registered in in the META-INF/services folder. Everything works fine so far and I can trace the container calling this method:
public class TestCdiExtension implements Extension {
public void observeAfterBeanDiscovery(#Observes AfterBeanDiscovery event, BeanManager manager) {
// Code goes here
}
}
My problem now is this: To determine which beans should be registered, I need access to the ServletContext of the current web application in which CDI is running.
I understand that you can use CDI completely without a servlet environment, so there is no hard link. However: How can I do the job of registering additional beans depending on what's in the ServletContext?
Is using an extension the correct way at all? Is there any other (better?) solution of doing this?

Related

Get ServletContext in EnvironmentPostProcessor

I'm trying to get ServletContext in the class which is implementing EnvironmentPostProcessor. ServletContext is required to get the war filename. Based on war file name I get properties from a database and will set to properties to user later in the applications.
I'm not using Embedded Container but WildFly Server
public class ClEnvironment implements EnvironmentPostProcessor, ServletContextAware, ServletContextInitializer
But it's not working.
You can’t get the ServletContext in an EnvironmentPostProcessor. The post-processors are loaded from spring.factories very early in the application’s lifecycle. With an embedded servlet container that happens long before the container has been started and the ServletContext is available.
This may be an XY problem. Perhaps you could ask another question that explains what you are trying to do. There may be another way to do it that does not require access to the ServletContext in an environment post-processor.

What is the equivalent of `transport-guarantee` when I register a Servlet in a BundleActivator without using web.xml?

I am running Servlets in an OSGI environment, specifically, I use Karaf with Pax Web / Jetty.
I was happily using the BundleActivator to instantiate servlets and register them with the HttpService. What I like about it is that it gives me a very straightforward way to handle dependency injection by wiring up a ServiceTracker.
However, for some things I can only find documentation about how to set them up via the classical web.xml configuration. Specifically, I miss an equivalent for the transport-guarantee instruction, i. e. a way to tell the HttpService that on certain URLs, it should insist on HTTPS and redirect the client if necessary.
Alternatively, if I can use the web.xml descriptor file as usual, but still get a convenient and simple way to wire up the servlet to my OSGi services, I would be fine with that.
Right now I'd say it's a web.xml only feature. Might want to open a new Feature Request. Regarding Injection of OSGi services in Servlets. If you combine your application with Pax CDI you are able to inject OSGi services by CDI means.
#WebServlet(urlPatterns = "/myServlet")
public class MyServlet extends HttpServlet {
#Inject
#OsgiService
private AnotherService service;
...

Spring NON MVC project configuration - Best Practices

I am going to work on a Java project and want to use Spring IOC for bean management.
This is not a web project but just a simple java project that will give me a jar file at the end.
My questions is that, in my application i want to use Spring IoC to get instances of classes to call their respective methods. For the purpose i need to get the spring context using
CalenderDao calenderDao = (CalenderDao) ApplicationContextUtils
.getApplicationContext().getBean("calenderDao");
calenderDao.getCalenderUpdate();
Now if i need this bean in some other class too , i will copy and paste the same thing there as well like.
CalenderDao calenderDao = (CalenderDao) ApplicationContextUtils
.getApplicationContext().getBean("calenderDao");
calenderDao.getCalenderUpdate();
My question here is that, do i need to create a ApplicationContext in each file to get a bean throughout the application. Or is there any alternate and best thing to perform. And if i am doing the thing like this way how can use setter injection or constructor injection in application.
In web apps this is quit simple we loads the context one time and everything works fine, but how to do this in non web where we don't have web.xml file to instantiate the context.
Please help how beans are managed in non web project using spring.
Spring is not just designed for web apps.
Just because it's not a web application you dont need to fall back to "provider style". You do not need a web.xml to initialize an application context.
Use your main method to create an application context and work with your beans as you would do for a webapp. You can use autowiring and all the gadgets of spring.
Once the context is initialized call your main class to start your application, for example with the help of the refresh event. From there on you have (almost) no need to use getBean.
Obviously you dont have session and request scope, but singleton and prototype are available.
Just take a look at the spring docs.
Wherever you require ApplicationContext in your application, implement that class with ApplicationContextAware interface.
Say here
public class CalenderService implements ApplicationContextAware{
private ApplicationContext context;//declare this so you can use it
}
As it is interface you need to overide its method
public void setApplicationContext(ApplicationContext context){
this.context=context; // here ApplicationContext gets injected.
}

JBoss AS 7 - After Startup initialization

Is there any way to catch an event/implements a Class, or something like that, to detect that JBoss (AS7) is up and running and all applications has been deployed ?
I made a StartupServlet (which extends HttpServlet) because i need to call a local web service to initialize the system. But because my application is not fully deployed my call for the web service (in the StartupServlet) ends in a "404 Not Found error".
I tried to use a <listener>...</listener> on the web.xml but it's not working.
You can try using a Startup EJB, like explained here:
#Singleton
#Startup
public class StartupBean {
#PostConstruct
private void startup() { ... }
#PreDestroy
private void shutdown() { ... }
}
However the bean will not detect whether your applications are deployed, only that the current application - the one containing the bean - is deployed and started. Since the #PostConstruct method is called very early, you cannot rely on any other beans or services being available.
EDIT: Jboss also has a native management API. AFAIK it can also be used to query deployments. Unfortunately it's documentation is not really impressive, but perhaps you can figure it out.
According to my understanding, you do not need to detect when all application was deployed, you need to understand only if your application was deployed. To do it you should define ServletContextListener:
http://docs.oracle.com/javaee/5/api/javax/servlet/ServletContextListener.html#contextInitialized%28javax.servlet.ServletContextEvent%29
Than you can catch when it deployed:
public void contextInitialized(ServletContextEvent sce)
{
servletContext = sce.getServletContext();
}

How to get a 'JBoss service' with CDI in JMX with AS6?

I'm currently migrating a JBoss service class from AS5.1 to AS6 (not going to AS7 for a variety of reasons).
For AS5.1, the service implements a {serviceName}MBean and has a jboss-service.xml with attribute values. It's packaged in a jboss-sar, which is packaged in an EAR to be deployed. When deployed, the service fields are populated with the values from jboss-service.xml, and the service is automatically registered into JMX.
I would like to achieve the same thing using AS6, but would like the service to support CDI - so I'd like its new #Inject injection points to be satisfied. I need these to be satisfied in the object registered with JMX, so that methods called via JMX can reference injected fields, but I'm struggling to achieve this.
I've had to package the service in a jar, instead of a jboss-sar, for classloader reasons, but let's say it's otherwise unchanged. When deployed to AS6, all works as before - service goes into JMX, values from XML propagate to the object. However, the instance created does not have its CDI injection points satisfied, and neither does the object registered in JMX.
If I annotate the service class with #Startup and #javax.ejb.Singleton, but keep its interface and the jboss-service.xml, the object registered into JMX still does not have its CDI injection points satisfied. However if I programmattically deregister that bean, and re-register the instance in a #PostConstruct method, then the bean in JMX DOES have its injection points satisfied. However that bean no longer has the values specified in the jboss-service.xml.
So how can I get the best of both worlds? CDI and the usual JBoss service behaviour? What is the correct way to implement a JBoss service with CDI? I've been unable to find documentation on this. Hope someone can help.
Thanks,
Ben
As a worst-case fallback, you should be able to use the CDI extension API to get your service to be injected. I don't think you would need to write a fully-fledged extension, but if you have an initialisation hook in the service object, you can do this (lifted with minor editing from the docs, not compiled or tested):
public static <T> void inject(T object) {
BeanManager beanManager = (BeanManager)new InitialContext().lookup("java:comp/BeanManager");
AnnotatedType<T> type = beanManager.createAnnotatedType(object.getClass());
InjectionTarget<T> it = beanManager.createInjectionTarget(type);
CreationalContext ctx = beanManager.createCreationalContext(null);
it.inject(object, ctx);
it.postConstruct(object);
}
Basically, any object to that method will get injected. All the usual CDI annotations should work. Hopefully.
As mentioned in the comments above, it seems Tom's right - there's no 'nice' way of created a CDIed, JMX bean in one go, you either have to put your JMX bean in CDI, as is suggested above, or put you CDIed bean into JMX. We tried the former, but it appears the BeanManager isn't bound to JNDI at the point the service starts up.
So instead we went with CDI bean -> JMX. We're creating the services as Singleton EJBs, so their injection points are satisfied, and they then get registered/unregistered to JMX in their PostConstruct/PreDestroy methods, using German Escobar's excellent CDI portable extension (germanescobar.net/2010/01/cdi-portable-extension-jmx.html, community.jboss.org/thread/148750 is also helpful).
May try to use ApplicationScoped beans and get them to start by observing a ContainerInitialized(?) event, however, as we don't need all the features of an EJB. Haven't tried that yet, mind...

Categories