0

I have this processRequest(..) method in a Servlet class, where I am checking user's email and password in isLoginSuccessful(..) method using ChildEventListener of Firebase and want to redirect the user to home.jsp if true or back to index.jsp if false. But the boolean loginSuccess in this isLoginSuccessful(..) method returns false, hence redirect back to index.jsp then returns true. Means isLoginSuccessful(..) gets interrupted. How to fix this?

processRequest() method :

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

    response.setContentType("text/html;charset=UTF-8");
    out = response.getWriter();

    // initialize firebaseapp
    FirebaseAppProvider.getFirebaseApp(getServletContext());

    // email password from textbox
    String user_email = request.getParameter("loginEmail");
    String user_password = request.getParameter("loginPassword");

    boolean loginSuccessful = isLoginSuccessful(user_email, user_password, response);

    if (loginSuccessful) {
        System.out.println("login if");
        response.sendRedirect("home.jsp");
    } else {
        System.out.println("login else");
        out.println("Login Failed");
        response.sendRedirect("index.jsp#download");
    }      

}

isLoginSuccessful() method :

 boolean loginSuccess = false;
private  boolean isLoginSuccessful(String userEmail, String userPassword, HttpServletResponse response) {

    FirebaseDatabase dbFire = FirebaseDatabase.getInstance();
    DatabaseReference dbRefUsers = dbFire.getReference().child("Users");     

    System.out.println("isLoginSuccessful method called");        

    dbRefUsers.orderByChild("user_email").equalTo(userEmail).addChildEventListener(new ChildEventListener() {

        @Override
        public void onChildAdded(DataSnapshot ds, String string) {

            System.out.println("on Child added called");

            User user = ds.getValue(User.class);
            boolean pwTrue = (userPassword.equals(user.getUser_password()));

                if (pwTrue) {
                    System.out.println("if onChildAdded called");
                    loginSuccess =true;                      
                    System.out.println("loginSuccess = " + loginSuccess);
                } else {
                    System.out.println("else onChildAdded called");
                  loginSuccess = false;
                }
        }

        @Override
        public void onChildChanged(DataSnapshot ds, String string) {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }

        @Override
        public void onChildRemoved(DataSnapshot ds) {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }

        @Override
        public void onChildMoved(DataSnapshot ds, String string) {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }

        @Override
        public void onCancelled(DatabaseError de) {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }
    });

    System.out.println("loginSuccess = " + loginSuccess);

    return loginSuccess;
}

Console logs

Info:   isLoginSuccessful method called
Info:   loginSuccess = false
Info:   login else
Info:   on Child added called
Info:   if onChildAdded called
Info:   loginSuccess = true 

What is getting happened :

  1. processRequest() gets called

  2. isLoginSuccessful() gets called where loginSuccess is false

3.if statement from processRequest() gets called

  1. isLoginSuccessful() gets called again where loginSuccess is true now.

What I want is :

  1. processRequest() gets called

  2. isLoginSuccessful() gets called one time where loginSuccess is true

3.if statement from processRequest() gets called

Ssubrat Rrudra
  • 870
  • 8
  • 20
  • 1
    Data is loaded from Firebase asynchronously. This means that your `onChild...` methods run after the `return loginSuccess` does. Try running your code in a debugger and you'll see. For solutions, see https://stackoverflow.com/questions/33203379/setting-singleton-property-value-in-firebase-listener (the `Semaphore` approach might actually work here), and https://stackoverflow.com/questions/50434836/getcontactsfromfirebase-method-return-an-empty-list/50435519#50435519 – Frank van Puffelen Jan 30 '19 at 15:37
  • You are right. I have also provided the logs from console. onChild methods run after return loginSuccess. I have checked the other question you recommended. So the appropriate solution is using addValueEventListener? – Ssubrat Rrudra Jan 30 '19 at 16:54
  • The type of listener makes no difference, they're all called asynchronously. Your code will need to deal with this asynchronous nature and the linked questions show examples of how to do that. I highly recommend reading a bit more about asynchronous APIs before continuing, as they're incredibly common when calling modern Cloud APIs. – Frank van Puffelen Jan 30 '19 at 16:59
  • I think I have dealt with this in Android using AsyncTask but here I am using firebase admin SDK for java servelet. I have also tried putting the if statement of processRequest() method inside onChildAdded() but there HttpServletResponse is generating NullPointerException. I found that HttpServletResponse object can hold the data only one level deep. I am not sure about and I don't know why this is happening. I am very new to Java Servlet. – Ssubrat Rrudra Jan 30 '19 at 17:10
  • I can't make the "why this is happening" any clearer than in my first comment and in the linked questions: the `return` statement runs before the `onChildAdded`, so you're just return the default value. You will need to move the code that needs the data from the database (so the calls to `response.sendRedirect()`) *into* the `onChildAdded`, so that they are run *after* the data is available from the database. – Frank van Puffelen Jan 30 '19 at 17:44
  • I have tried this too. And response.sendDirect() is showing NullPointerException when put in onChildAdded(). As I mentioned in my previous answer that I think HttpServletResponse can't hold its data inside deep nested code blocks. – Ssubrat Rrudra Jan 30 '19 at 17:51
  • I think using interface suggested by you in another question can solve this issue. – Ssubrat Rrudra Jan 30 '19 at 18:01
  • Calling response.sendRedirect() inside onCallback() method of custom MyCallback interface is doing nothing as I was afraid about it. response(HttpServletResponse) doesn't get called more than one level deep code block. – Ssubrat Rrudra Jan 30 '19 at 18:22
  • Hmm... that sounds unexpected, although it's hard to say without seeing the code. You might want to either open a new question with the [minimal code that reproduces the problem](http://stackoverflow.com/help/mcve) with your new approach (as you're now beyond it being just a lack of knowing about asynchronous behavior). – Frank van Puffelen Jan 30 '19 at 18:47
  • Using Semaphore has resolved the issue. Thank you Frank for your support to the community. – Ssubrat Rrudra Jan 31 '19 at 07:33

0 Answers0