How to abort Startup procedure on init-Exceptions - java

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*/
}

Related

Force deploy of web application to fail on Tomcat

We are researching the possibility to migrate some web JSF applications from Payara 5 to Tomcat 9 (TomEE 8). We are using Java 11 and Java EE 7/8. Our applications connect to a backend server using RMI. At the moment, with Payara 5, when the code that connects us to the backend server fails (exception is thrown because server is unavailable or credentials defined in web.xml are invalid), the deployment fails.
See this piece of code:
public class MainServlet extends HttpServlet {
//constructor, variables etc.
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
//read configurations from web.xml
try {
connectToBackendServer();
catch (Exception e) {
throw new UnavailableException("Cannot connect to Backend Server");
}
}
//other methods
}
The above piece of code makes the deployment fail on Payara 5, but Tomcat 9 allows the deployment. With Tomcat we notice that the backend is not ok by checking the logs or by trying the front-end and getting the errors. See the below picture where the NullPointerException is thrown by our connectToBackendServer() method.
We are fully aware that this is not the best approach as the backend may fail later, after the successful deployment, but at least we are covering the cases when the configuration from web.xml is wrong.
Can we achieve a similar functionality with Tomcat 9(TomEE 8)?
Thank you all in advance!
..
Move your logic to a ServletContextListener and throw a runtime exception from contextInitialized(). On many servers this will fail the deployment and any requests to the application will return error 500. The spec does not require this exact behaviour though, so the outcome is slightly different between servers.
This is an example implementation using a ServletContextListener that fails the deployment:
package com.example;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.annotation.WebListener;
#WebListener
public class ExampleServletContextListener implements ServletContextListener{
#Override
public void contextInitialized(ServletContextEvent e) {
try {
callThatFailsAndThrowsAnException();
catch (Exception e) {
throw new UnavailableException("Something went very wrong - I'm bailing out.");
}
}
#Override
public void contextDestroyed(ServletContextEvent e) {
/* Application shutdown */
}
}
#WebListener registers the context listener with the container. If you are using an older version of JakartaEE/JavaEE and the annotation is unavailable, you can register the context listener in web.xml instead.

Configure Response object for Rest Services inside a Jersey-Grizzly server, in OSGi container (CORS error prevention with Jersey 1x)

The last couple of days, I have been struggling with an issue. I've created a rest service hosted by a Grizzly server inside an OSGi container. Everything is working perfectly at this point.
Now, I want to add a header in every response.Not so complex or illogical right? Yet, I can't find a way to do it.
I have tried to:
1) Get the response object inside the rest functions as this question suggests (pretty textbook when you are not under OSGi).
2) Add a handler using the code above (in this case the service method is never called)
server.getServerConfiguration().addHttpHandler(
new HttpHandler() {
#Override
public void service(Request arg0, Response arg1)
throws Exception {
arg1.setHeader("Access-Control-Allow-Origin", "*");
}
});
I am using jersey-server/client/core 1.18.1 and grizzly2-server 1.18.1, hence i prefer a solution that can be applied in this version, but I am willing to update jar versions if it cannot be done in 1.18.x.
You could give a try to Jersey filters.
In a nutshell, you should create class implementing ContainerResponseFilter:
public class MyFilter implements ContainerResponseFilter {
#Override
public void filter(
ContainerRequest request,
ContainerResponse response
) throws IOException {
request.getHttpHeaders().add(<header name>, <header value>);
}
}
Then, you should register this filter in your Jersey server configuration.
Please, note, that this filter would be invoked on every response. To bind it only to specific resources, you could use annotation-binding, that is described here.
All other information you could find here.

Load On Start Up using Annotation in JAVA

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.

Java EE / Struts Exception Handling

I have started developing Java EE web applications mainly on Struts and Servlets. Most of the codes have a try catch block within Servlet or Struts Action class.
Is it a must to have try catch block for every servlet or action? The only advantages I saw with this kind of code template is stacktrace are log to application specified logging framework such as log4j.
If the runtime exception floats up, it will be printed on the server (Tomcat / Glassfish / Weblogic) logs instead.
public class HelloWorldAction extends Action{
public ActionForward execute(ActionMapping mapping,ActionForm form,
HttpServletRequest request,HttpServletResponse response)
throws Exception {
try {
// do all the processing here
} catch (Exception e) {
// log all exceptions
}
}
}
public class HelloWorldExample extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
try {
// do all the processing here
} catch (Exception e) {
// log all exceptions
}
}
}
Catching Exception is almost never what you really want to do. Hopefully it's obvious that it's not mandatory to always have a try/catch blockā€“it depends on what the underlying code is doing, and how you want to handle any exceptions it may throw.
Catching Exception eliminates the ability to use Struts' declarative exception handling.
I would recommend against using a filter to handle exceptions in Struts 1 since it already has a mechanism built in. If there are exceptions at the framework level they'll be displayed anyway, and they generally indicate a development, not runtime, issue.
I echo Andrea's sentiments: unless you have a Very Good Reason, learning Struts 1 isn't useful. Consider instead Struts 2 or Spring MVC for "traditional" framework development, or Play, Grails, JRuby on Rails, etc. for a more modern approach.
If you are looking for one place to do exception logging, you can create ServletFilter:
public class ExceptionLoggerFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) {
try {
filterChain.doFilter(req, res);
}
catch(Exception e) { // Log exception }
}
}
You shouldn't really have to catch exceptions everywhere unless you want to handle that particular exception in a special way. Most of the time it's just noise getting in the way for the "real" code. The important thing is that you log the exception and enough context information that you can figure out what caused the error. To the user, you should probably just display a general error page.
You can specify global exception in struts-config.xml. It catches unhandled exceptions all over the application.
You need to implement your own ExceptionHandler class. Then write code what to want to do.
4.5 Exception Handler
http://www.jajakarta.org/struts/struts1.2/documentation/ja/target/userGuide/building_controller.html

Naming Tomcat worker threads

Is there a simple way to change the default name that Tomcat gives its worker threads? Ideally, I'd like all the threads associated with a certain web application to have it in their name, perhaps as a prefix. For example, if I deploy app1.war and app2.war, I'd like all the threads for app1 to have app1 in their name.
From a forum, reposted here with a bit better formatting; a simple filter, that renames each thread to the request URI, in this example:
public class ThreadNameFilter implements javax.servlet.Filter {
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain fc) throws IOException, ServletException {
HttpServletRequest httpReq = (HttpServletRequest)req;
final Thread curThr = Thread.currentThread();
final String oldName = curThr.getName();
// change the name of the current thread to something related
// to the application (e.g. URI)
try {
curThr.setName(httpReq.getRequestURI());
fc.doFilter(req, resp);
} finally {
curThr.setName(oldName);
}
}
}
Threads are only temporarily "associated" with a particular webapp.
I can't imagine why this would be something useful at all:
Logging should include context information (e.g. what component is logging)
Profiling can easily reveal what code is being executed (and thus reveal the webapp that is "running")
Exceptions include full stack traces and can reveal what code was being executed (and thus reveal the webapp that was "running")
Long-running threads can be inspected via a thread-dump (and thus reveal the webapp that is "running" in the long-running request)

Categories

Resources