0
votes

I have 2 screens in my JSF 2.0 application. Screen 1 searches for students and lists students in a table. The student name in the results table is a link to the student details page (screen 2).

My managed bean:

@SessionScoped
public class TestController {
private Student studentOnUI; // Student being viewed on the UI 
// synchronized public getters and setters
public String viewStudentAction(String studentId) {
    this.studentOnUI = getStudentFromDB( studentId );   
    return "studentDetailedPage";
}
public synchronized String clearSearchAction() {
    this.studentOnUI = null;
    return "studentSearchPage";
}

screen 1 xhtml snippet

<!-- search fields -->
<h:commandButton  
    value="Clear Search"
    action="#{testController.clearSearchAction()}"/>
<!-- Search button -->
<!-- search results table -->

Screen 2 xhtml snippet

<h:outputText value="#{testController.studentOnUI.name}" />
<h:dataTable 
  value="#{testController.studentOnUI.subjects}"
  var="subject">
  <h:outputText value="#{subject.score}"/>
</h:dataTable>

I face the following issue:

  1. After running search, user clicks on a student name (to move into screen 2)
  2. When the render response phase of screen 2 is in progress (which has EL references to testController.studentOnUI), He clicks on clear button (without waiting for the first request to complete). Now the thread handling the clear request sets testController.studentOnUI to null and the first thread that is in render response phase throws NullPointerException when it evaluates

    {testController.studentOnUI.*}.

Although the managed bean handles synchronization (correctly?) it does not solve the concurrency issue here because, the following could happen

  1. Thread 1 (handling request to navigate to screen 2) - evaluates #{testController.studentOnUI.name} and happily renders the value. And then exits the testController.getStudentOnUI() synchronized method. So thread 1 no longer has the lock on the controller instance (in session scope). context switch happens.
  2. Thread 2 (handling request to clear search results) - does testController.studentOnUI = null in clearSearchAction(). context switch happens.
  3. Thread 1 - evaluates the next EL in the page (#{testController.studentOnUI.subjects}) and throws a NullPointerException (as testController.studentOnUI is now null).

Appreciate any pointers on what I am doing wrong with this approach or if a different approach needs to be adopted here.

1
what's a screen? you use 2 tabs in the browser? or is it more like a wizard?Balázs Németh
By screen I meant a page. There are no tabs or wizards. The user clicks link 1 on page 1 (in the student table to navigate to the student detailed page) and before the response is complete, clicks on link 2 on page 1.Babu

1 Answers

0
votes

this is really strange behaviour but then i would rather disable the link on the first page with JavaScript to make it "unclickable". try with jQuery:

1 button: $('#button').attr("disabled", true);

2 link: $('a.something').click(function(e) { e.preventDefault(); });

I'm not sure about the synchronization in the backing bean since the JSF Controller has to put the lock on your Student object, not the clear method. Am I wrong?