Java ServletContext - java

I have a JSP web site, not Spring MVC, and it has a config file web.xml.
There are a couple of settings within the web.xml file that I'd like to get.
However, I want to access those settings from within a class sitting in my Source Packages folder.
I know I can pass the ServletContect from the JSP to the class but I want to avoid this and just access the web.xml file from my class.
Is this possible?
EDIT
I have been looking at javax.servlet thinking what I want was in there but if it is I can't see it.

Using a javax.servlet.ServletContextListener implementation, that allows a singleton-like access to context:
package test.dummy;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;
public class ContextConfiguration implements ServletContextListener {
private static ContextConfiguration _instance;
private ServletContext context = null;
//This method is invoked when the Web Application
//is ready to service requests
public void contextInitialized(ServletContextEvent event) {
this.context = event.getServletContext();
//initialize the static reference _instance
_instance=this;
}
/*This method is invoked when the Web Application has been removed
and is no longer able to accept requests
*/
public void contextDestroyed(ServletContextEvent event) {
this.context = null;
}
/* Provide a method to get the context values */
public String getContextParameter(String key) {
return this.context.getInitParameter(key);
}
//now, provide an static method to allow access from anywere on the code:
public static ContextConfiguration getInstance() {
return _instance;
}
}
Set it up at web.xml:
<web-app>
<listener>
<listener-class>
test.dummy.ContextConfiguration
</listener-class>
</listener>
<servlet/>
<servlet-mapping/>
</web-app>
And use it from anywhere at the code:
ContextConfiguration config=ContextConfiguration.getInstance();
String paramValue=config.getContextParameter("parameterKey");

I think this is very close to your description: link.
Basically, you want to read parameters from web.xml programatically, right?

Hmmm... I am assuming that once your web app is up then you are not going to make any change in the web.xml....
Now what you can do is a create a servlet which loads on the startup and initialize a singleton class. You can use the following setting in your web.xml.
<servlet>
<description></description>
<display-name>XMLStartUp</display-name>
<servlet-name>XMLStartUp</servlet-name>
<servlet-class>com.test.servlets.XMLStartUp</servlet-class>
<init-param>
<param-name>log4j-init-file</param-name>
<param-value>WEB-INF/classes/log4j.properties</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
In tomcat if you set load-on-startup value 0, then it means that while loading it has got the highest priority. now in the servlets init method read all the init-parameters like this and set it in your singleton class.
String dummy= getInitParameter("log4j-init-file");

This is not easily possible and may not be an elegent solution. The only option I can suggest is to have your configuration options i a xml or properties file and put it in your WEB-INF/classes directory so you can look it up using ClassLoader.getResource or ClassLoader.getResourceAsStream
I know it may be a duplication of the configuration, but IMO its the elegent way.

I really don't like classes reading from web.xml... Why do you need that?
IMHO it would be easier, cleaner and by far much more manageable if you prepared a properties file and a manager class that reads from there.

Related

Spring 4: run some initialization code before application context refresh

I am using Spring 4 (not Spring Boot) in the web application. I need to run some initialization code before any of the beans in the application context would be created. I tried to create implementation of org.springframework.context.ApplicationContextInitializer and register it in spring.factories but was not picked up for some reason. How can I do it?
As it turned out implementing of org.springframework.context.ApplicationContextInitializer was a right way. Because in my project I do not use Spring MVC implementation of this initializer should be registered in web.xml instead of spring.factories. Here is an example:
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>my.company.MyContextInitializer</param-value>
</context-param>
This should work. If not, please post your code.
#Component
public class SampleBootstrap implements ApplicationListener<ContextRefreshedEvent> {
....
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
Do Something();
}
}

Make ServletContextListener spring aware

I am plugging in Spring to existing Java EE web Application. I have following lines in my web.xml:
<listener>
<listener-class>com.MyContextListener</listener-class>
</listener>
And Following MyContextListener class?
public class MyContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
//...
}
}
What should I do to make MyContextListener be managed by Spring?
Edited:
My assumption is: Spring should create all servlets and all web app infrastructure so everything happened in contextInitialized method of MyContextListener should be somehow handled by Spring. How can I achieve, by implementing some interface I suppose. Correct me if I am wrong. Thanks!
Well,
We had a similar scenario of configuring an exiting Jersey web services app to use Spring for dependency injection. Our Jersey webapp had extended ContextLoaderListener as follow
public class XServletContextListener extends ContextLoaderListener {
...
#Override
public void contextInitialized(ServletContextEvent arg0) {
super.contextInitialized(arg0);
....
}
#Override
public void contextDestroyed(ServletContextEvent arg0) {
super.contextDestroyed(arg0);
....
}
}
where ContextLoaderListener is
import org.springframework.web.context.ContextLoaderListener;
We included the jersey-spring bridge with all spring dependencies including applicationContext.xml as follow
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="com.xxx.*" />
....
....
</beans>
And obviously needed to make sure that XServletContextListener is included in the web.xml as follow
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>com.xxx.**.XServletContextListener</listener-class>
</listener>
Followed by servlet and its init-param values and servlet mapping. You can obviously adopt annotation config in place of xml confib in which case you would need to use WebListener annotation.
We use a variety of annotations such as
#Component for objects
#Service for services
#Repository for DAOs
#Controller for controllers/resources
#ContextConfiguration for tests
Everything is loaded and autowired by Spring framework.
What should I do to make MyContextListener be managed by Spring?
It depends on which configuration way you are using. Anyway, you should tell directly Spring to use the class you have declared. That could be done by the following way:
#WebListener
public class MyContextListener implements ServletContextListener { ... }
A class marked with this annotation (the Servlet 3.0 specification, 8.1.4) must implement one of these interfaces
HttpSessionAttributeListener
HttpSessionListener
ServletContextAttributeListener
ServletContextListener (+)
ServletRequestAttributeListener
ServletRequestListener
HttpSessionIdListener
that it actually does.
Personally, I prefer a meta-annotation based approach which makes my configuration shorter and more concise.
Spring should create all servlets and all web app infrastructure so everything happened in contextInitialized method of MyContextListener should be somehow handled by Spring.
Yes, Spring will do it for you if you provide some information which could help it to register / configure / create / manage an instance.
The information may be either meta-information (a template that tells how to create an instance, like BeanDefinitions) or a completed instance itself (usually, it gets passed programmatically that, in turn, leads to writing a huge amount of code).
How can I achieve, by implementing some interface I suppose.
You are implementing an interface to make your listener a listener (a class that describes specific methods which will be called at some points of time). Spring, itself, is responsible for guaranteeing such calls at those points of time, placing an object in the existing web infrastructure before.
Either annotate the class with #WebListener or the method with #Bean
Annotate where you create a new instance of MyContextListener with #Bean if using Java Configs with Spring Boot.

How to start a class before Spring has initialized?

Is there a way to execute a class before the Spring container has been initialized?
Basically, I have some resources which I have scattered across the jars that make up my application. Upon first the very first execution of the application, they won't be on the file system and people will need to be able to adjust these configuration files sometimes. So... instead of editing them and re-packaging, I would like to be able to copy all these resources outside the respective jars into an extracted directory structure where they could easily be changed. I have so far implemented this. However, I now need to be able to actually do this before Spring's container has been initialized so that they are present when Spring tries to initialize. How can this be done?
I would need to be able to do this both from a webapp perspective and in a JUnit test.
use a ServletContextListener:add the following to your web.xml before spring servelt.
<listener>
<listener-class>your.full.className.YourListener</listener-class>
</listener>
where YourListener looks like:
public class YourListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent evt) {
//execute anything here.
}
}

Does spring have a way to load up things when the application first loads? At a global level

Is there any spring specific way in the framework to perform initialization when MVC loads up?
Say I need to create global objects based on configuration files, is there a place to do this or do I just create my own servlet and do this in oninit?
What about standard #PostConstruct?
#Service
class AnySpringBean {
#PostConstruct
public void init() {
//run when bean is created
}
}
Works on #Controllers as well.
UPDATE: The more global place would be to subclass ContextLoaderListener) and override contextInitialized() and use it in web.xml (see user1076371 answer). I don't like this approach much, but at least the initialization is not tied to any Spring bean.
There is an ApplicationListener interface you can implement to hook into the startup completion event. I use this in my app to do things after I know Spring has finished starting up. I have a few different classes that I want to kick off background threads after the system is "up" and each implements this interface to do their particular post startup stuff.
It's sent after the app as a whole is done, but it's each listening spring bean that gets an event, so you'd could hook it into some existing bean or to create something like a PostStartupBean that exists only to implement this one method.
public void onApplicationEvent( ApplicationEvent applicationEvent )
{
if ( applicationEvent instanceof ContextRefreshedEvent )
{
..do stuff here..
}
}
Best thing would be to leave it to Spring. Add your global object beans (which could be singletons etc..) to your application context. Make sure Spring is initialized when the application is loaded by adding ContextLoaderListener to the web.xml.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4">
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
</web-app>
You can access your global objects from the WebApplicationContext anywhere in the application.

Is there a way to run a method/class only on Tomcat/Wildfly/Glassfish startup?

I need to remove temp files on Tomcat startup, the pass to a folder which contains temp files is in applicationContext.xml.
Is there a way to run a method/class only on Tomcat startup?
You could write a ServletContextListener which calls your method from the contextInitialized() method. You attach the listener to your webapp in web.xml, e.g.
<listener>
<listener-class>my.Listener</listener-class>
</listener>
and
package my;
public class Listener implements javax.servlet.ServletContextListener {
public void contextInitialized(ServletContext context) {
MyOtherClass.callMe();
}
}
Strictly speaking, this is only run once on webapp startup, rather than Tomcat startup, but that may amount to the same thing.
You can also use (starting Servlet v3) an annotated aproach (no need to add anything to web.xml):
#WebListener
public class InitializeListner implements ServletContextListener {
#Override
public final void contextInitialized(final ServletContextEvent sce) {
}
#Override
public final void contextDestroyed(final ServletContextEvent sce) {
}
}
I'm sure there must be a better way to do it as part of the container's lifecycle (edit: Hank has the answer - I was wondering why he was suggesting a SessonListener before I answered), but you could create a Servlet which has no other purpose than to perform one-time actions when the server is started:
<servlet>
<description>Does stuff on container startup</description>
<display-name>StartupServlet</display-name>
<servlet-name>StartupServlet</servlet-name>
<servlet-class>com.foo.bar.servlets.StartupServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

Categories