Kushan Kushan - 1 month ago 10
Javascript Question

change Dom element based on firebase admin value events

I have a simple HTML page printed out inside a Servlet. Here I have setup firebase admin sdk and have set a value event listener for a path.

When the events fire, I wish to change a Div element and display the results there.

EDIT: The listener does work on further testing with logs.

But I still do not know how to reflect the changes inside the div element as the Listeners are Asynchronous. That's most likely why the script isn't working.

Can someone please guide me as to what I should do. The code is as follows:

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.auth.FirebaseCredentials;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;

@WebServlet("/WebWaitlistViewServelet")
public class WebWaitlistViewServelet extends HttpServlet {
private static final long serialVersionUID = 1L;

public WebWaitlistViewServelet() {
super();
}

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

PrintWriter pw = response.getWriter();

try {

String cityName=request.getParameter("city");

String restId = request.getParameter("restid");

String userId = request.getParameter("userid");

if(cityName == null || restId == null || userId == null){
System.out.println("Error getting values");
return;
}else{
System.out.println(cityName+" "+restId+" "+userId);
}


pw.println("<HTML>");

pw.println("<HEAD>");

pw.println("<script>");

pw.println("function changePosition(position){ document.getElementById(\"positionInList\").innerHTML = position };");

pw.println("function changeTimeTillTurn(timetillturn){ document.getElementById(\"timeTillTurn\").innerHTML = timetillturn };");

pw.println("function showTimeTillTurn(){ document.getElementById(\"timeDiv\").style.display = \"visible\" };");

pw.println("function hideTimeTillTurn(){ document.getElementById(\"timeDiv\").style.display = \"hidden\" };");

pw.println("</script>");

pw.println("</HEAD>");

pw.println("<BODY>");

pw.println("<DIV align=\"center\">");

pw.println("<B>Your position in the waitlist is:</B>");

pw.println("</DIV><br/>");

pw.println("<DIV id=\"positionInList\" align=\"center\" style=\"color:blue\">");

pw.println("Loading...");

pw.println("</DIV><br/>");

pw.println("<DIV id=\"timeDiv\" align=\"center\">");

pw.println("<B>Approximate time till your turn is: </B><span id=\"timeTillTurn\" style=\"color:blue\">Loading...</span>");

pw.println("</DIV>");

pw.println("<BODY>");

pw.println("</HTML>");

pw.flush();


InputStream is = getServletContext().getResourceAsStream("/WEB-INF/firebaseauth/firebase_admin_sdk_key.json");

// Initialize the app with a service account, granting admin privileges
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredential(FirebaseCredentials.fromCertificate(is))
.setDatabaseUrl("https://restaurantrepo.firebaseio.com")
.build();
try {
FirebaseApp.initializeApp(options);
} catch (Exception e) {
//
}



// As an admin, the app has access to read and write all data, regardless of Security Rules
DatabaseReference waitlistRef = FirebaseDatabase.getInstance().getReference().child(cityName).child(restId).child("waitlist");

Comparator<WaitlistedPerson> sortComparator = new Comparator<WaitlistedPerson>() {
@Override
public int compare(WaitlistedPerson lhs, WaitlistedPerson rhs) {
//sort ascending... the bigger the time entered, the later the person has joined... thus the higher the time entered the lower the position
//on waitlist
if(lhs.getTimeentered()<rhs.getTimeentered()){
//if time entered is lower, keep the person higher in the list
return -1;
}else if(lhs.getTimeentered()==rhs.getTimeentered()){
//if the time entered is the same, there are two cases possible
//1.. one person is remotely entered and one has entered at the resto POS... in this case, give priority to POS entered user
//2.. both people have remotely entered ... in this case, give preference to the person with lowest userid (he/she started using our app earlier)
//
//cases that will never happen are
//1.. two people with same userid entered remotely at same time .. can't happen as a second entry simply overwrites the old entry
//2.. two people with same time entered at POS ... can't happen as the resto host can only enter one party at a time..
if(!lhs.isRemotelyEntered() && rhs.isRemotelyEntered()){
//Log.d("FragmentCreate","lhs userid "+lhs.getUserid()+" lhs remotelyentered "+lhs.isRemotelyEntered());
//Log.d("FragmentCreate","rhs userid "+rhs.getUserid()+" rhs remotelyentered "+rhs.isRemotelyEntered());
return -1;
}else if(lhs.isRemotelyEntered() && rhs.isRemotelyEntered()){
//return the lowest user id
//userid is of format Uxx ... so get the xx part begining from index 1 of the string and get the number
int lhsuserid = Integer.parseInt(lhs.getUserid().substring(1));
int rhsuserid = Integer.parseInt(rhs.getUserid().substring(1));

//Log.d("FragmentCreate"," The userids are lhsuserid "+lhsuserid+" rhsuserid"+rhsuserid);

//Do not get tempted to use String compareto function as this will give wrong results
// U11 will get priority over U4 in string compareto due to 1 being lexicographically smaller
//Thus never use lexicographical sorting ever.

//The user ids can never be equal as two remotely entered users will never have two entries (can't... it's impossible due to firebase)

if(lhsuserid<rhsuserid){
return -1;
}else if(lhsuserid==rhsuserid){
//can never happen in real life... two remotely entered users can never have same id ever... just made for safeguard
return 0;
}else{
return 1;
}

}else if(!lhs.isRemotelyEntered() && !rhs.isRemotelyEntered()){
//both entered at POS and have same time
//can never happen in real life...
//made this just for testing scenarios in case i screw up and give wrong inputs
return 0;
}else{
//Log.d("FragmentCreate","lhs userid "+lhs.getUserid()+" lhs remotelyentered "+lhs.isRemotelyEntered());
//Log.d("FragmentCreate","rhs userid "+rhs.getUserid()+" rhs remotelyentered "+rhs.isRemotelyEntered());
return 1;
}
}else{
return 1;
}
}
};

ArrayList<WaitlistedPerson> listOfPeople = new ArrayList<>();

ValueEventListener eventListener = new ValueEventListener(){

@Override
public void onCancelled(DatabaseError error) {
pw.println("<script>hideTimeTillTurn();</script>");
pw.println("<script>changePosition('Sorry, some error occured');</script>");
System.out.println("Sorry. some error occured");
}

@Override
public void onDataChange(DataSnapshot dataSnapshot) {

int positionCounter=0;

if(dataSnapshot.getChildrenCount()==1 || dataSnapshot.getChildrenCount() == 0 ){
//Log.d("FragmentCreate","This indicates that the restaurant probably closed down and removed all customers from the list");
pw.println("<script>hideTimeTillTurn();</script>");
pw.println("<script>changePosition('You are no longer in the waitlist');</script>");
System.out.println("You are no longer in the waitlist");
}else{

if(dataSnapshot.hasChild(userId)){

double averageWaitTime=0.0d;

long timeEnteredInMillis=0;

listOfPeople.clear();

Iterable<DataSnapshot> peopleInList = dataSnapshot.getChildren();

for(DataSnapshot currentPerson : peopleInList){

if(currentPerson.getKey().equals("dummy")){
continue;
}

if(currentPerson.getKey().equals(userId)){
//This is our node.... break the loop and enjoy using the counter
averageWaitTime = currentPerson.child("averagewaittimeperparty").getValue(Double.class);
timeEnteredInMillis = currentPerson.child("timeentered").getValue(Long.class);
listOfPeople.add(new WaitlistedPerson(currentPerson));
}else{
listOfPeople.add(new WaitlistedPerson(currentPerson));
}

}

//sort the list using our custom comparator and the get the index

Collections.sort(listOfPeople,sortComparator);

//find the position of the user now

for(WaitlistedPerson person : listOfPeople){
++positionCounter;
if(person.getUserid().equals(userId)){
break;
}
}

double timetillturn = Math.round(averageWaitTime * ((double)positionCounter));

long timeShouldComeAt = timeEnteredInMillis + (long)(timetillturn*60000);

Date timeWhenTurnArrives = new Date(timeShouldComeAt);

SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");

pw.println("<script>showTimeTillTurn();</script>");
pw.println("<script>changePosition('"+positionCounter+"');</script>");
pw.println("<script>changeTimeTillTurn('"+sdf.format(timeWhenTurnArrives)+"');</script>");
System.out.println(positionCounter+" "+sdf.format(timeWhenTurnArrives));

}else{
pw.println("<script>hideTimeTillTurn();</script>");
pw.println("<script>changePosition('You are no longer in the waitlist');</script>");
System.out.println("You are no longer in the waitlist");

}

}

}

};

waitlistRef.addValueEventListener(eventListener);

} catch (Exception e) {
e.printStackTrace();
}finally{
try {
pw.close();
} catch (Exception e) {
//do nothing here
}
}


}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}

}

Answer Source

So i managed to solve this using a JSP instead of a Servelet.

In either case, the solution was to tranfer all the logic to a JavaScript function. Then calling the said function on body load.

onload=callthefunction()

The firebase listeners were converted from java to the JavaScript version:

on()
off()

This way there is need to call ajax or anything and the elements that need to be changed can be directly altered from JavaScript