/*
* Copyright 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.firebase.database.core;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.firebase.FirebaseApp;
import com.google.firebase.ImplFirebaseTrampolines;
import com.google.firebase.database.util.GAuthToken;
import com.google.firebase.internal.AuthStateListener;
import com.google.firebase.internal.GetTokenResult;
import com.google.firebase.internal.NonNull;
import com.google.firebase.tasks.OnCompleteListener;
import com.google.firebase.tasks.Task;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
public class JvmAuthTokenProvider implements AuthTokenProvider {
private final ScheduledExecutorService executorService;
private final FirebaseApp firebaseApp;
public JvmAuthTokenProvider(FirebaseApp firebaseApp, ScheduledExecutorService executorService) {
this.executorService = executorService;
this.firebaseApp = firebaseApp;
}
private static String wrapOAuthToken(FirebaseApp firebaseApp, GetTokenResult result) {
String oauthToken = result.getToken();
if (oauthToken == null) {
// This shouldn't happen in the actual production SDK, but can happen in tests.
return null;
} else {
Map<String, Object> authVariable = firebaseApp.getOptions().getDatabaseAuthVariableOverride();
GAuthToken googleAuthToken = new GAuthToken(oauthToken, authVariable);
return googleAuthToken.serializeToString();
}
}
@Override
public void getToken(boolean forceRefresh, final GetTokenCompletionListener listener) {
ImplFirebaseTrampolines.getToken(firebaseApp, forceRefresh)
.addOnCompleteListener(
this.executorService,
new OnCompleteListener<GetTokenResult>() {
@Override
public void onComplete(@NonNull Task<GetTokenResult> task) {
if (task.isSuccessful()) {
listener.onSuccess(wrapOAuthToken(firebaseApp, task.getResult()));
} else {
listener.onError(task.getException().toString());
}
}
});
}
@Override
public void addTokenChangeListener(TokenChangeListener listener) {
ImplFirebaseTrampolines.addAuthStateChangeListener(firebaseApp, wrap(listener));
}
@Override
public void removeTokenChangeListener(TokenChangeListener listener) {
ImplFirebaseTrampolines.removeAuthStateChangeListener(firebaseApp, wrap(listener));
}
private AuthStateListener wrap(TokenChangeListener listener) {
return new TokenChangeListenerWrapper(listener, firebaseApp, executorService);
}
/**
* Wraps a TokenChangeListener instance inside a FirebaseApp.AuthStateListener. Equality
* comparisons are delegated to the TokenChangeListener so that listener addition and removal will
* work as expected in FirebaseApp.
*/
private static class TokenChangeListenerWrapper implements AuthStateListener {
private final TokenChangeListener listener;
private final FirebaseApp firebaseApp;
private final ScheduledExecutorService executorService;
TokenChangeListenerWrapper(
TokenChangeListener listener,
FirebaseApp firebaseApp,
ScheduledExecutorService executorService) {
this.listener = checkNotNull(listener, "Listener must not be null");
this.firebaseApp = checkNotNull(firebaseApp, "FirebaseApp must not be null");
this.executorService = checkNotNull(executorService, "ExecutorService must not be null");
}
@Override
public void onAuthStateChanged(final GetTokenResult tokenResult) {
// Notify the TokenChangeListener on database's thread pool to make sure that
// all database work happens on database worker threads.
executorService.execute(
new Runnable() {
@Override
public void run() {
listener.onTokenChange(wrapOAuthToken(firebaseApp, tokenResult));
}
});
}
@Override
public int hashCode() {
return listener.hashCode();
}
@Override
public boolean equals(Object obj) {
return obj != null
&& obj instanceof TokenChangeListenerWrapper
&& ((TokenChangeListenerWrapper) obj).listener.equals(listener);
}
}
}