I have this code,
#WebServlet(value="/initializeResources", loadOnStartup=1)
public class InitializeResources extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("HEREEEE");
}
}
But the servlet doesn't start when the web application is started.
How use load on startup on Servlet Annotation?
My Servlet API is 3.0 and I use Tomcat 7
With you current code, you need to do a GET request for see the output HEREEEE.
If you want to do something on the startup of the servlet (i.e. the element loadOnStartup with value greater or equal to zero, 0), you need put the code in a init method or in the constructor of the servlet:
#Override
public void init() throws ServletException {
System.out.println("HEREEEE");
}
It may be more convenient to use a listener to start a resource in the application scope (in the ServletContext).
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
#WebListener
public class InitializeListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("On start web app");
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("On shutdown web app");
}
}
For an example, see my answer for the question Share variables between JAX-RS requests.
#WebServlet(name="InitializeResources", urlPatterns="/initializeResources", loadOnStartup=1)
urlPatterns to be ensure that the web conatainer finds the servlet path.
When loadOnStartup is specified for a Servlet, the container would only load and pre-instantiate an instance of your Servlet ready to process any GET/POST requests that may come. This by itself wouldn't cause doGet() or doPost() to get fired because an actual client request hasn't come for processing yet. So, what's its use then?
Well, loadOnStartup is typically used for Servlets that have heavy initialization code; say, they may make a JNDI call to get hold of a resource or a Database call to populate a local data structure with some backend values. In the absence of loadOnStartup the very first client request could be painfully slow because of all this extra initialization stuff and hence pre-instantiating it makes sense.
Now, your custom initialization code (JNDI, JDBC) would go in an overriden GenericServlet#init() method which is called by the servlet container to indicate to a servlet that it's being placed into service.
Related
I have set up an embedded Jetty server with a filter to add some headers to every request.
MainHandler mainHandler = new MainHandler();
ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
servletContextHandler.setContextPath("/application");
servletContextHandler.setHandler(mainHandler);
servletContextHandler.setAllowNullPathInfo(true);
servletContextHandler.addFilter(MyFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST, DispatcherType.INCLUDE, DispatcherType.FORWARD));
Mainhandler is the class which processes the requests.
The init() method of the filter is called, but not the doFilter() Method thus my filter is not applied. I tried it with "/application/something".
Can anybody help me please?
Don't mix Handlers and ServletContextHandler's like that.
That's not what the ServletContextHandler.setHandler(Handler) is for.
Change your MainHandler to extend from HttpServlet and add it to the ServletContextHandler.addServlet().
Your MainHandler is preventing correct dispatch of the request into the ServletContextHandler.
This is because ServletContextHandler.setHandler() is for the management of things outside of the ServletContext and the specific request chain (such as session management, security management, gzip encoding management, request logging management, etc), not for actually processing a request and producing a response within that ServletContext. The ServletContextHandler.setHandler() is meant for managing state and scope within an exchange (request, response, inputs, outputs, sessions, security, etc), with all valid implementations being a ScopedHandler that is ServletContext, Context, and ServletContextHandler aware.
Look at this example of the official documentation:
package org.eclipse.jetty.embedded;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
public class MinimalServlets
{
public static void main( String[] args ) throws Exception
{
// Create a basic jetty server object that will listen on port 8080.
// Note that if you set this to port 0 then a randomly available port
// will be assigned that you can either look in the logs for the port,
// or programmatically obtain it for use in test cases.
Server server = new Server(8080);
// The ServletHandler is a dead simple way to create a context handler
// that is backed by an instance of a Servlet.
// This handler then needs to be registered with the Server object.
ServletHandler handler = new ServletHandler();
server.setHandler(handler);
// Passing in the class for the Servlet allows jetty to instantiate an
// instance of that Servlet and mount it on a given context path.
// IMPORTANT:
// This is a raw Servlet, not a Servlet that has been configured
// through a web.xml #WebServlet annotation, or anything similar.
handler.addServletWithMapping(HelloServlet.class, "/*");
// Start things up!
server.start();
// The use of server.join() the will make the current thread join and
// wait until the server is done executing.
// See
// http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#join()
server.join();
}
#SuppressWarnings("serial")
public static class HelloServlet extends HttpServlet
{
#Override
protected void doGet( HttpServletRequest request,
HttpServletResponse response ) throws ServletException,
IOException
{
response.setContentType("text/html");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println("<h1>Hello from HelloServlet</h1>");
}
}
}
I need access to the ServletContext to use the getRealPath() method on some files that are in my WEB-INF directory. However, the class I need to do this work in is a non-CDI class that is used for some backend processing based on a request made earlier from JAX-RS. How can I get the ServletContext outside of the lifecycle of the JAX-RS request?
I'm using Wildfly 10, if that changes the way I would go about this
The trick is to load a servlet at the startup of the Java EE application, see #WebServlet annotation. The Servlet.init() method is invoked upon startup of the container, which we will leverage to work with ServletContext, in this case calling getRealPath() and storing returned value into static variable. You may access the value from the rest of your app by calling RealPathServlet.getRealPath().
#WebServlet(value="/real-path", loadOnStartup=1)
public class RealPathServlet extends HttpServlet {
private static String realPath;
public void init(ServletConfig config) throws ServletException {
super.init(config);
realPath = config.getServletContext().getRealPath("yolo");
Logger.getLogger(ContextPathServlet.class.getName()).info("Real path is " + realPath);
}
public static getRealPath() {
return realPath;
}
...
}
I have a WebApplication on Websphere 8.5.5.8, one (more or less empty) EAR Project which contains my WAR Project.
In my main Servlet, which is loaded on startup, i do some checks, if everything is alright.
If its not, I'm throwing a javax.servlet.ServletException.
My expectation is, that Websphere would recognize that there is a Problem and abort the startup of my application so its not usable at all.
What actually happens is, Websphere just logs that Exception away with only Waring level, the Exception is even in another File, not in the Log itself:
[06.04.16 07:42:27:229 CEST] 0000004c FfdcProvider W com.ibm.ws.ffdc.impl.FfdcProvider logIncident FFDC1003I: FFDC-Vorfall an C:\IBM\WAS8.5\profiles\AppSrv01\logs\ffdc\server1_bb44715_16.04.06_07.42.27.2056702894000999712166.txt com.ibm.ws.webcontainer.servlet.ServletInstance.init 259 erstellt.
Then my Application is started anyways so its available to use with a Browser. People of course then start using it and recognize later, that that there is a Problem. After digging in Log files, it comes out that the startup failed.
Question:
What can i do to make Websphere abort the Startup Process?
Is there maybe a Special kind of Exception i could throw?
I tried
javax.servlet.ServletException
javax.servlet.UnavailableException
java.lang.Error
I found this in the IBM Forums, which indicates, that my expected behavior would violate the JEE Spec, which wouldn't make much sense for me.
I tried a javax.servlet.ServletContextListener as mentioned here, one Plus is, that i'll get a error Message in the log, but the Application still starts.
As mentioned here I tried the Startup Beans. The solution posted there is not working for me, those proprietary startup beans are not allowed in a WAR, and they're are also Deprecated. I only have a EAR Project, since Websphere/RAD is forcing me to use one in my local environment. On Test/Production Systems, only the WAR is used.
If i use the startup beans defined by EJB 3.1:
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;
#Singleton
#Startup
public class MyStartupBean {
public boolean start() {
System.out.println("MyStartupBean.start()");
return false;
}
public void stop(){
System.out.println("MyStartupBean.stop()");
}
#PostConstruct
public void postConstruct() {
System.out.println("MyStartupBean.postConstruct()");
}
}
The start() method doesn't get called, i only see the postConstruct() message in my log. Throwing an Exception in postConstruct() wont abort the startup process.
So far, i only came up with an Workaround (inspired by the comment of Jason Faust in https://stackoverflow.com/a/1337927/5072526):
Have a static flag, and if the initialization has completed correctly, set it to true.
Use a Filter to check that flag and output an Error if its false, so at least the Application dosen't seem usable when the Startup failed:
public class HealthCheckFilter implements Filter{
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if(AppBridge.isStartupFinished()) {
chain.doFilter(request, response);
}else {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setCharacterEncoding(AppConstants.ENCODING);
httpResponse.setContentType("text/plain");
httpResponse.setStatus(500);
PrintWriter out = httpResponse.getWriter();
out.write("Startup failed");
}
}
/* Methods init(FilterConfig filterConfig) and destroy() ommitted*/
}
I did a simple test, and executed my test servlet below from different browsers and command line tools. Regardless where I execute it, it displays the same "hohoho time". I am absolutly fine with this, I just want to know two things:
a) if I can rely on this on different versions of tomcat (today I use version 7.54)
b) does this mean a servlet is never executed parallel in different threads (i.e. two users are requesting the very same servlet at the very same time)
#WebServlet(name="test servlet 2", urlPatterns={"/test2"}, loadOnStartup=1)
public class Test2 extends HttpServlet {
private String test = "baaa .. :-(";
#Override
public void init(ServletConfig config) throws ServletException {
DEBUG("Server starts");
this.test = "hohoho " + System.currentTimeMillis();
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletOutputStream out = resp.getOutputStream();
out.write(test.getBytes());
out.flush();
out.close();
}
}
Indeed servlet container creates only one instance of each servlet. This helps you to hold state in servlet member variables. This however does not mean that servlet container cannot use the same servlet instance to process serveral requests simultaneously. This is what servlet contains (including Tomcat) does. Therefore your servlet must be thread safe. Please refer to this article for details: http://tutorials.jenkov.com/java-servlets/servlet-concurrency.html
I have below view on your question.
a) Yes,atleast from tomcat 7 onwards.For tomcat 6(annotation support),you will have to check the specs.
b) Regarding execution in parallel thread,servlet not threadsafe by default,to ensure thread safety,Servlet service() method should not access any member variables, unless these member variables are thread safe themselves.
For more on thread safety : Servlet Thread Safety
There is only one instance of each HttpServlet and its init() method is only called once when the HttpServlet is constructed. However the doGet() is called in a different thread for each request and can happen in parallel.
I'm working on some Java EE application which has to find some data in HashMap. The problem is that I want to load this HashMap to Tomcat only once - when Tomcat starts and I don't know how to do this. Could you give me some tips?
I suppose you want to load HashMap actually before when your web application start.
The ServletContextListener is what you want. It will make your code run before the web application is start.
Assuming that you want to load this HashMap only for one web application you can do it when container loads all settings for your app (after it reads web.xml file). To do this you can create class which implements ServletContextListener.
In its contextInitialized method create HashMap you are interested in, and add it as attribute to ServletContext. There can be only one ServletContext instance for one web application and this instance is available to all servlets/jsp so they can later get that attribute with map you set earlier.
Example:
class ContextListenerImpl implements ServletContextListener {
#Override
public void contextDestroyed(ServletContextEvent sce) {
//can be empty for now
}
#Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext sc = sce.getServletContext();
//... here you can create and initialize your HashMap
//when map is ready add it as attribute to servlet context
sc.setAttribute("mySpecialMap", map);
}
}
You can get this map in servlets like
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//...
Map<Your,Types> map = (Map<Your,Types>) getServletContext()
.getAttribute("mySpecialMap");
//...
}
Oh, and one important thing: lets not forget to add this listener to your web application. So you will have to add
<listener>
<listener-class>full.name.of.ContextListenerImpl</listener-class>
</listener>
to your web.xml file.