I have a portlet in which I connect to a database and display some data. When auto-refresh is enabled, I would like to load data from db and then refresh the page (jsp) every X seconds.
However, altough I do udnerstand how timers and tasks work, I dont quite get how to make them work in a portlet.
I tried two different approaches but none of them works as I expected. This is the first one using Thread.sleep(xxx); function
public void displayLog(final ActionRequest actionRequest,
final ActionResponse actionResponse) throws IOException,
PortletException {
do {
manager.setLastID(0);
redirectToLog(actionRequest, actionResponse);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} while(manager.isAutoRefresh().equals("y"));
}
Here is the redirect function:
public void redirectToLog(ActionRequest actionRequest,
ActionResponse actionResponse) throws IOException, PortletException {
// load messages and display them
manager.loadFromDB();
// in case of error, redirect to error page
if (manager.isConnError()) {
actionResponse.setRenderParameter("jspPage",
"/html/visual/error.jsp");
return;
}
// redirect
actionRequest.setAttribute("messages", manager.getMessages());
actionRequest.setAttribute("refresh", manager.isAutoRefresh());
actionRequest.setAttribute("serviceFilter", manager.getServiceFilter());
actionResponse
.setRenderParameter("jspPage", "/html/visual/display.jsp");
}
The code gets executed every 3 seconds (if I put some print statements there, I can see taht it calls this function). However, I dont get redirected to the jsp page. Instead, it just "freezes" and does this while loop forever.
I tried also second approach using timers:
class LogDbTask extends TimerTask {
private DbManager manager;
private PortletVisual portlet;
private ActionRequest actionRequest;
private ActionResponse actionResponse;
public LogDbTask(PortletVisual portlet, ActionRequest actionRequest, ActionResponse actionResponse) {
this.portlet = portlet;
this.actionRequest = actionRequest;
this.actionResponse = actionResponse;
manager = portlet.getManager();
}
public void run() {
if (manager.isAutoRefresh().equals("y")) {
try {
manager.setLastID(0);
portlet.redirectToLog(actionRequest, actionResponse);
} catch (IOException e) {
e.printStackTrace();
} catch (PortletException e) {
e.printStackTrace();
}
} else {
//Stop Timer.
this.cancel();
}
}
}
which I call using
Timer timer = new Timer("LogDbTimer");
LogDbTask task = new LogDbTask(this, actionRequest, actionResponse);
timer.schedule(task, 0, 3000);
but the problem stays the same - I never get to the jsp page, altough this function is being called repeatedly. I am not an expert on portelts, nor multi-threaded applications. What am I doing wrong? Is there some easy way to fix this?
Sorry for exhausting question - I tried to put some code examples in there. I will try to specify the quaestion more properly if not understood...
The Thread.sleep approach keeps "freezing" because the portlet never gets to render a view. It sits in the loop and never actually returns a page to display to the user.
The timer task approach is also flawed in its design. The user's browser has to make a page request for the portlet code to send anything back to the user. This essentially means that the TimerTask might execute but by the time it does the response has already been sent to the user and you can't update the page any more.
I would suggest moving the timer logic to the client side. You can write some JavaScript to poll the portlet using AJAX and a resourceURL using a timer there. Your serveResource method could just return the refreshed data and then update the view in JavaScript. This helps prevent a full page refresh to reduce server load and make the page refresh more efficiently.
The only other option you have is to use a page refresh HTML metatag or a JavaScript timer to have the browser do a full page refresh whenever you want the page to update. That reduces the complexity of avoiding the need for AJAX but I think is a less performant and less elegant solution.