Jason Saruulo
Jason Saruulo

Reputation: 1897

How to wait for (Firebase) callbacks in AWS lambda?

I was looking for some similar questions but as far as I know none of them are Java related. I want to call a AWS lambda function within which I am connecting to a Firebase database. The problem is that the handler executes before I get the needed data from Firebase.

@Override
public String handleRequest(Request input, Context context) {
    try {
        FileInputStream serviceAccountInputStream = new FileInputStream(FIREBASE_SERVICE_ACCOUNT_CREDENTIALS_PATH);

        FirebaseOptions options = new FirebaseOptions.Builder()
                .setCredential(FirebaseCredentials.fromCertificate(serviceAccountInputStream))
                .setDatabaseUrl(FIREBASE_DATABASE_URL)
                .build();
        FirebaseApp.initializeApp(options);

        DatabaseReference ref = FirebaseDatabase
                .getInstance()
                .getReference("users/" + input.getUid());
        ref.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                System.out.print(dataSnapshot);
                // TODO: Do computations on data and return results
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                System.out.print("Canceled");
                // TODO: Return error
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }
    // TODO: Return computed results
    return "This could be the start of something new.";
}

I need to read data from the Firebase database, do some computations with it and return the computed results to the user. How can I achieve this? :)

Upvotes: 1

Views: 608

Answers (1)

Andrew Robinson
Andrew Robinson

Reputation: 356

You can wait for the async code to finish by using a CountDownLatch.

Before calling the async code you create the CountDownLatch:

final CountDownLatch countDownLatch = new CountDownLatch(1);

Then at the end of the callback methods you count down the latch:

countDownLatch.countDown();

Then after the async method you wait for the CountDownLatch to be counted down:

waitForCountdownLatch(countDownLatch);

private static void waitForCountdownLatch(CountDownLatch countDownLatch) {
    try {
        countDownLatch.await();
    } catch (InterruptedException e) {
        log.error(e);
        e.printStackTrace();
    }
}

So with your code it would be:

@Override
public String handleRequest(Request input, Context context) {

    final CountDownLatch countDownLatch = new CountDownLatch(1);
    final Object[] singleValue = new Object[1];
    final DatabaseError[] firebaseError = new DatabaseError[1];

    try {
        FileInputStream serviceAccountInputStream = new FileInputStream(FIREBASE_SERVICE_ACCOUNT_CREDENTIALS_PATH);

        FirebaseOptions options = new FirebaseOptions.Builder()
                .setCredential(FirebaseCredentials.fromCertificate(serviceAccountInputStream))
                .setDatabaseUrl(FIREBASE_DATABASE_URL)
                .build();
        FirebaseApp.initializeApp(options);

        DatabaseReference ref = FirebaseDatabase
                .getInstance()
                .getReference("users/" + input.getUid());

        ref.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                System.out.print(dataSnapshot);
                Object snapshotValue = dataSnapshot.getValue();
                if(snapshotValue != null) {
                    singleValue[0] = snapshotValue;
                }
                countDownLatch.countDown();
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                System.out.print("Canceled");
                firebaseError0] = databaseError;
                countDownLatch.countDown();
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
        countDownLatch.countDown();
    }

    waitForCountdownLatch(countDownLatch);
    if(firebaseError[0] != null) {
        System.out.print(firebaseError[0].toException().getMessage());
    }
    if(singleValue[0] != null) {
        // do something with result
    }
    return "This could be the start of something new.";
}

private void waitForCountdownLatch(CountDownLatch countDownLatch) {
    try {
        countDownLatch.await();
    } catch (InterruptedException e) {
        log.error(e);
        e.printStackTrace();
    }
}

Upvotes: 1

Related Questions