We have a Java servlet acting as dispatcher for a web app. For each request a database connection is created and then committed / rolled back at the end of the request depending on whether the action was successful or not. It looks something like:
public class WebDispatcher extends HttpServlet {
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
Connection conn = null;
try {
// Create connection
} catch(.....) {
} finally {
// Commit / Rollback connection
}
}
}
The problem occurs when there is an exception. For example if they don't have access to a certain action the dispatcher has to redirect them. It does this by using a request dispatcher.
} catch(RoleAuthorizationException rae) {
request.getRequestDispatcher(.....).forward(request, response);
}
I had assumed that 'finally' would be called but it doesn't seem to be in this case. With each exception we end up losing a connection in the pool. As a workaround we are closing the connection with each exception but why isn't finally being called?
Finally is always called (oracle docs):
The finally block always executes when the try block exits.
Check if there is an exception being thrown in the finally block (before the connection is closed).
See also this answer.
Related
We have a class we've written which opens up a connection to a server. When you're done with it, you need to either tell it to commit if everything was successful, or tell it to rollback if something went wrong. So right now we have a lot of spots in our code that look like this:
OurConnectionClass conn = null;
try {
conn = OurConnectionClass(parameters);
// Do some stuff here...
conn.commit();
} catch (Throwable t) {
if (conn != null) {
conn.rollback();
}
throw t;
}
If you forget to commit or rollback, there's no immediate issues, but eventually you exhaust a connection pool and then have to figure out where you made a mistake.
I'd like to find a way so OurConnectionClass implements AutoClosable, so I could do somsething like this instead:
try (OurConnectionClass conn = new OurConnectionClass(parameters)) {
// Do some stuff here...
}
I feel like there has to be a way to do this, but I'm not seeing it. AutoCloseable only calls a close method, with no arguments passed to it. As far as I can see, there's no way to know whether close is being called because the end of the try block was successfully reached or because an exception was thrown.
When executing this snippet.
try (OurConnectionClass conn = new OurConnectionClass(parameters)) {
// Do some stuff here...
conn.commit();
}
OurConnectionClass.close() will always be called after an instance is created. So you can just add some logic to check if a commit was made. E.g. with a boolean flag. With that you could then check in the close() method if the connection should be closed peacefully or it should rollback:
public class OurConnectionClass implements AutoCloseable{
private boolean committed; // initialized to false
public void commit(){
// commit
committed = true;
}
public void close() throws Exception{
if(!committed){
// rollback
}
}
}
I think the semantic you want is that the transaction is rolled back in close, unless the code which uses OurConnectionClass explicit calls OurConnectionClass.commit().
Then you don't have any problem, because your close method, then just need to test if there is an open transaction. And if there is roll it back, and log an error.
Do both!
try (OurConnectionClass conn = new OurConnectionClass(parameters)) {
// Do some stuff here...
conn.commit();
} catch (Throwable t) {
conn.rollback();
throw t;
}
The closeable is still auto-closed (in the implicit finally block) if stuff explodes.
BTW, it would be better to throw a domain exception:
throw new MyStuffExploded(t);
because re-throwing the connection exception lets implementation details leak out via the method contract, which is a form of coupling, which is bad.
I would like to first forward to the view "/WEB-INF/views/searchResult.jsp" and then process Calculator.lookUp(Type, Place) in the background.
Currently Calculator.lookUp(Type, Place) is processed first, and only once this method is finished is the user forwarded to "/WEB-INF/views/searchResult.jsp".
Thanks for the help!
#WebServlet(urlPatterns="/search.do")
public class SrchServlet extends HttpServlet{
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
String Type = request.getParameter("Type");
String Place = request.getParameter("Place");
request.setAttribute("Type", Type);
request.setAttribute("Place", Place);
//I want the forward to searchResult.jsp to occur
request.getRequestDispatcher("/WEB-INF/views/searchResult.jsp").forward(
request, response);
//and then in backend for the below method to run
Calculator.lookUp(Type, Place);
}
}
Some remarks if you do not like async requests. First, a forward is definitive: you give the hand to the other servlet and next instruction (if any) will never be executed. You need to include the JSP if you want to proceed in sequence. And a trick allows to cause the response to be sent to the client immediately while allowing processing in the servlet: just close the response output writer or stream.
Your code could simply become:
//I want the include searchResult.jsp
request.getRequestDispatcher("/WEB-INF/views/searchResult.jsp").include(
request, response);
// cause the response to be sent to the client
try {
response.getOutputStream().close(); // if the OutputStream was used
}
catch(IllegalStateException e) {
response.getWriter().close(); // if the Writer was used
}
//and then in backend for the below method to run
Calculator.lookUp(Type, Place);
}
I could never find whether this was explicitely allowed per servlet specification, by I can confirm that Tomcat supports it.
No need for any #Asinc...
Try using below code to make your method async but the Type and Place (just in point variable names should start with small letters) both variable should be final:
Runnable task = new Runnable() {
#Override
public void run() {
try {
Calculator.lookUp(Type, Place);// here Place and Type both variable should be final
} catch (Exception ex) {
// handle error which cannot be thrown back
}
}
};
new Thread(task, "ServiceThread").start();
As of I know the below is the better way to solve your problem.
Declare the logic which you need to execute as part of background process in an asynchronous method by declaring the method as,
#Asynchronous / #Async
Remember, Asynchronous method will not return anything that mean return type is void. If you need to return some values, you can return Future. Read more about Asynchronous process.
I defined a servlet(map it to /index) and rewrite the doPost method like this :
private Object lock = new Object();
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("start");
synchronized(lock) {
try {
lock.wait(15000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.notifyAll();
}
}
when the first request comes in, it prints 'start' then waits at lock.wait(15000);
then the second request comes, and it should be blocked at synchronized(lock); as i thought. But the fact is the second request is blocked out of the doPost method. After the first request goes lock.notifyAll(); then the second request comes into doPost method and prints 'start'.
I found this only happens when two requests query the exactly same url. Is this the way that Tomcat handles for multi-thread ?? I am so confused..
Only the doPost and doGet method of the servlet are thread safe, means for each thread they are invoked independently. The class itself is instantiated only once.
In the code above you are acquiring lock on class variable which will be shared across all request, hence you are getting that locked per request.
To get your expected behaviour move your 'Objectinstantiation insidedoPost` method.
Is it possible to take an HTTPServletRequest away from its thread, dissolve this thread (i.e. bring it back to the pool), but keep the underlying connection with the browser working, until I get the results from a time-consuming operation (say, processing an image)? When the return data are processed, another method should be called asynchronously, and be given the request as well as the data as parameters.
Usually, long pooling functions in a pretty blocking fashion, where the current thread is not dissolved, which reduces the scalability of the server-side app, in terms of concurrent connections.
Yes, you can do this with Servlet 3.0
Below is the sample to write the alert every 30 secs(not tested).
#WebServlet(async =“true”)
public class AsyncServlet extends HttpServlet {
Timer timer = new Timer("ClientNotifier");
public void doGet(HttpServletRequest req, HttpServletResponse res) {
AsyncContext aCtx = request.startAsync(req, res);
// Suspend request for 30 Secs
timer.schedule(new TimerTask(aCtx) {
public void run() {
try{
//read unread alerts count
int unreadAlertCount = alertManager.getUnreadAlerts(username);
// write unread alerts count
response.write(unreadAlertCount);
}
catch(Exception e){
aCtx.complete();
}
}
}, 30000);
}
}
Below is the sample to write based on an event. The alertManager has to be implemented which notifies AlertNotificationHandler when client has to be alerted.
#WebServlet(async=“true”)
public class AsyncServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res) {
final AsyncContext asyncCtx = request.startAsync(req, res);
alertManager.register(new AlertNotificationHandler() {
public void onNewAlert() { // Notified on new alerts
try {
int unreadAlertCount =
alertManager.getUnreadAlerts();
ServletResponse response = asyncCtx.getResponse();
writeResponse(response, unreadAlertCount);
// Write unread alerts count
} catch (Exception ex) {
asyncCtx.complete();
// Closes the response
}
}
});
}
}
Yes, it's possible using Servlet spec ver. 3.0. Implementation I can recommend is Jetty server. See here.
Had I looked into the Java SE6 documentation sooner on Context and InitialContext, I would've seen that there is a close() method for each.
So now I wonder, do I need to call the close() method on the Context/InitialContext objects?
Here is a snippet of my typical servlet code and how the Context/InitialContext object is used.
public class MyTypicalServlet extends HttpServlet {
//thread safe
DataSource ds;
String FilePath;
public void init(ServletConfig config) throws ServletException {
super.init(config);
try {
final Context ctx = new InitialContext();
ds = (DataSource) ctx.lookup("java:comp/env/jdbc/myDB");
FilePath = getServletContext().getInitParameter("FilePath");
} catch (NamingException e) {
throw new ServletException("Unable to find datasource: " + e.getMessage(), e);
}
}
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
{
doPost(req,res);
}
public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
{
//...a bunch of code
}
}//class
It's a good habit to get into. For example, I always make sure to close my InputStream classes, even if I'm using a ByteArrayInputStream, where the close() method is a no-op. That way, if I change it to some other implementation later, it's one less thing to have to change as well.
Same case here - if you call close(), you'll be more compatible with any JNDI implementation.
The close method allows releasing resources used by the context instead of waiting for the GC to release them. It would perhaps be useful for a context needing an open connection to, for example, a database or an external system. But I'm pretty sure it isn't useful for the java:comp/env context. Anyway, I've never seen any code closing them.