I am trying to create an UI component that allow the user to customize the timeout of sessions. So I created a servlet as below:
public class SessionTimeoutServlet extends AbstractBaseServlet {
private static final long serialVersionUID = 2567293974465204729L;
public static final String REQUEST_TIMEOUT_PARAMETR_NAME = "timeout";
private static final String TIMEOUT_TYPE_INIT_PARAMETER_NAME = "timeoutType";
private static final String WEB_TYPE_TIMEOUT = "web";
private static final String WEBSERVICE_TYPE_TIMEOUT = "webService";
@EJB(mappedName = SessionSettingsRemote.BEAN_NAME)
private SessionSettingsRemote sessionSettingsBean;
@PostConstruct
public void initTimeout() {
try {
String timeoutType = getServletContext().getInitParameter(TIMEOUT_TYPE_INIT_PARAMETER_NAME);
if (WEBSERVICE_TYPE_TIMEOUT.equals(timeoutType)) {
setCustomTimeout(sessionSettingsBean.getSessionSettingsDTO().getWebServiceSessionTimeoutInterval());
} else if (WEB_TYPE_TIMEOUT.equals(timeoutType)) {
setCustomTimeout(sessionSettingsBean.getSessionSettingsDTO().getWebSessionTimeoutInterval());
} else {
setCustomTimeout(30);
}
} catch (ApplicationException e) {
setCustomTimeout(30);
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int timeout = Integer.parseInt(request.getParameter(REQUEST_TIMEOUT_PARAMETR_NAME));
setCustomTimeout(timeout);
}
public static void setCustomTimeout(int customTimeout) {
SessionManagerListener.setCustomTimeout(customTimeout);
}
}
However, when I deploy this on GlassFish, I get below exception.
Caused by: java.lang.IllegalStateException: ServletConfig has not been initialized
at javax.servlet.GenericServlet.getServletContext(GenericServlet.java:199)
at com.accedian.ems.uiapplication.server.servlets.SessionTimeoutServlet.initTimeout(SessionTimeoutServlet.java:33)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl$3.run(InjectionManagerImpl.java:766)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.invokeLifecycleMethod(InjectionManagerImpl.java:760)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.inject(InjectionManagerImpl.java:531)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.injectInstance(InjectionManagerImpl.java:141)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.injectInstance(InjectionManagerImpl.java:127)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.createManagedObject(InjectionManagerImpl.java:347)
at com.sun.enterprise.web.WebContainer.createServletInstance(WebContainer.java:991)
at com.sun.enterprise.web.WebModule.createServletInstance(WebModule.java:2130)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1404)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1381)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5732)
I have used getServletConfig()
before getServletContext()
but it was null
. So why is my config and context are not properly set ?
Servlets predate managed beans and annotations and all the fancy stuff you see since Java EE 6. Previously, you have to explicitly implement a predefined abstract/template method in order to perform a task at a certain moment in the lifecycle.
For servlets, in order to hook on its initialization the same way you'd use @PostConstruct
on a "normal" managed bean, you have to override the predefined GenericServlet#init()
method.
@Override
public void init() {
// ...
}
The getServletContext()
will be available there.
If you pay attention to the GenericServlet
javadoc, you'll notice that there's also an init(ServletConfig)
. It's however strongly recommended to not use that method, but use init()
instead. The default implementation of init(ServletConfig)
namely takes care that the ServletContext
is properly set. You'd have to mind calling super.init(config)
to not make the same mistake. As a historical note, see that the canonical name of a @PostConstruct
method as you see on managed beans, "init", is inherited from exactly this Servlet API.
In case you wonders, the @PreDestroy
equivalent is the GenericServlet#destroy()
method.
@Override
public void destroy() {
// ...
}