/* * 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 com.google.firebase.FirebaseApp; import com.google.firebase.database.DatabaseException; import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.connection.ConnectionAuthTokenProvider; import com.google.firebase.database.connection.ConnectionContext; import com.google.firebase.database.connection.HostInfo; import com.google.firebase.database.connection.PersistentConnection; import com.google.firebase.database.core.persistence.NoopPersistenceManager; import com.google.firebase.database.core.persistence.PersistenceManager; import com.google.firebase.database.logging.LogWrapper; import com.google.firebase.database.logging.Logger; import com.google.firebase.database.utilities.DefaultRunLoop; import java.util.List; import java.util.concurrent.ScheduledExecutorService; public class Context { private static final long DEFAULT_CACHE_SIZE = 10 * 1024 * 1024; protected Logger logger; protected EventTarget eventTarget; protected AuthTokenProvider authTokenProvider; protected RunLoop runLoop; protected String persistenceKey; protected List<String> loggedComponents; protected String userAgent; protected Logger.Level logLevel = Logger.Level.INFO; protected boolean persistenceEnabled; protected long cacheSize = DEFAULT_CACHE_SIZE; protected FirebaseApp firebaseApp; private PersistenceManager forcedPersistenceManager; private boolean frozen = false; private boolean stopped = false; private Platform platform; private static ConnectionAuthTokenProvider wrapAuthTokenProvider( final AuthTokenProvider provider) { return new ConnectionAuthTokenProvider() { @Override public void getToken(boolean forceRefresh, final GetTokenCallback callback) { provider.getToken( forceRefresh, new AuthTokenProvider.GetTokenCompletionListener() { @Override public void onSuccess(String token) { callback.onSuccess(token); } @Override public void onError(String error) { callback.onError(error); } }); } }; } private Platform getPlatform() { if (platform == null) { if (GaePlatform.isActive()) { GaePlatform gaePlatform = new GaePlatform(firebaseApp); gaePlatform.initialize(); platform = gaePlatform; } else { platform = new JvmPlatform(firebaseApp); } } return platform; } public boolean isFrozen() { return frozen; } public boolean isStopped() { return stopped; } synchronized void freeze() { if (!frozen) { frozen = true; initServices(); } } public void requireStarted() { if (stopped) { restartServices(); stopped = false; } } private void initServices() { // Do the logger first, so that other components can get a LogWrapper ensureLogger(); // Cache platform getPlatform(); ensureUserAgent(); //ensureStorage(); ensureEventTarget(); ensureRunLoop(); ensureSessionIdentifier(); ensureAuthTokenProvider(); } private void restartServices() { eventTarget.restart(); runLoop.restart(); } void stop() { stopped = true; eventTarget.shutdown(); runLoop.shutdown(); } protected void assertUnfrozen() { if (isFrozen()) { throw new DatabaseException( "Modifications to DatabaseConfig objects must occur before they are in use"); } } public List<String> getOptDebugLogComponents() { return this.loggedComponents; } public Logger.Level getLogLevel() { return this.logLevel; } public Logger getLogger() { return this.logger; } public LogWrapper getLogger(String component) { return new LogWrapper(logger, component); } public LogWrapper getLogger(String component, String prefix) { return new LogWrapper(logger, component, prefix); } public ConnectionContext getConnectionContext() { return new ConnectionContext( this.getLogger(), wrapAuthTokenProvider(this.getAuthTokenProvider()), this.getExecutorService(), this.isPersistenceEnabled(), FirebaseDatabase.getSdkVersion(), this.getUserAgent()); } PersistenceManager getPersistenceManager(String firebaseId) { // TODO[persistence]: Create this once and store it. if (forcedPersistenceManager != null) { return forcedPersistenceManager; } if (this.persistenceEnabled) { PersistenceManager cache = platform.createPersistenceManager(this, firebaseId); if (cache == null) { throw new IllegalArgumentException( "You have enabled persistence, but persistence is not supported on " + "this platform."); } return cache; } else { return new NoopPersistenceManager(); } } public boolean isPersistenceEnabled() { return this.persistenceEnabled; } public long getPersistenceCacheSizeBytes() { return this.cacheSize; } // For testing void forcePersistenceManager(PersistenceManager persistenceManager) { this.forcedPersistenceManager = persistenceManager; } public EventTarget getEventTarget() { return eventTarget; } public RunLoop getRunLoop() { return runLoop; } public String getUserAgent() { return userAgent; } public String getPlatformVersion() { return getPlatform().getPlatformVersion(); } public String getSessionPersistenceKey() { return this.persistenceKey; } public AuthTokenProvider getAuthTokenProvider() { return this.authTokenProvider; } public PersistentConnection newPersistentConnection( HostInfo info, PersistentConnection.Delegate delegate) { return getPlatform().newPersistentConnection(this, this.getConnectionContext(), info, delegate); } private ScheduledExecutorService getExecutorService() { RunLoop loop = this.getRunLoop(); if (!(loop instanceof DefaultRunLoop)) { // TODO: We really need to remove this option from the public DatabaseConfig // object throw new RuntimeException("Custom run loops are not supported!"); } return ((DefaultRunLoop) loop).getExecutorService(); } private void ensureLogger() { if (logger == null) { logger = getPlatform().newLogger(this, logLevel, loggedComponents); } } private void ensureRunLoop() { if (runLoop == null) { runLoop = platform.newRunLoop(this); } } private void ensureEventTarget() { if (eventTarget == null) { eventTarget = getPlatform().newEventTarget(this); } } private void ensureUserAgent() { if (userAgent == null) { userAgent = buildUserAgent(getPlatform().getUserAgent(this)); } } private void ensureAuthTokenProvider() { if (authTokenProvider == null) { authTokenProvider = getPlatform().newAuthTokenProvider(this.getExecutorService()); } } private void ensureSessionIdentifier() { if (persistenceKey == null) { persistenceKey = "default"; } } private String buildUserAgent(String platformAgent) { StringBuilder sb = new StringBuilder() .append("Firebase/") .append(Constants.WIRE_PROTOCOL_VERSION) .append("/") .append(FirebaseDatabase.getSdkVersion()) .append("/") .append(platformAgent); return sb.toString(); } }