package com.google.firebase.cloud; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import com.google.api.gax.core.FixedCredentialsProvider; import com.google.cloud.firestore.Firestore; import com.google.cloud.firestore.FirestoreOptions; import com.google.common.base.Strings; import com.google.firebase.FirebaseApp; import com.google.firebase.ImplFirebaseTrampolines; import com.google.firebase.internal.FirebaseService; import com.google.firebase.internal.NonNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * {@code FirestoreClient} provides access to Google Cloud Firestore. Use this API to obtain a * <a href="https://googlecloudplatform.github.io/google-cloud-java/google-cloud-clients/apidocs/com/google/cloud/firestore/Firestore.html">{@code Firestore}</a> * instance, which provides methods for updating and querying data in Firestore. * * <p>A Google Cloud project ID is required to access Firestore. FirestoreClient determines the * project ID from the {@link com.google.firebase.FirebaseOptions} used to initialize the underlying * {@link FirebaseApp}. If that is not available, it examines the credentials used to initialize * the app. Finally it attempts to get the project ID by looking up the GOOGLE_CLOUD_PROJECT and * GCLOUD_PROJECT environment variables. If a project ID cannot be determined by any of these * methods, this API will throw a runtime exception. */ public class FirestoreClient { private static final Logger logger = LoggerFactory.getLogger(FirestoreClient.class); private final Firestore firestore; private FirestoreClient(FirebaseApp app) { checkNotNull(app, "FirebaseApp must not be null"); String projectId = ImplFirebaseTrampolines.getProjectId(app); checkArgument(!Strings.isNullOrEmpty(projectId), "Project ID is required for accessing Firestore. Use a service account credential or " + "set the project ID explicitly via FirebaseOptions. Alternatively you can also " + "set the project ID via the GOOGLE_CLOUD_PROJECT environment variable."); FirestoreOptions userOptions = ImplFirebaseTrampolines.getFirestoreOptions(app); FirestoreOptions.Builder builder = userOptions != null ? userOptions.toBuilder() : FirestoreOptions.newBuilder(); this.firestore = builder // CredentialsProvider has highest priority in FirestoreOptions, so we set that. .setCredentialsProvider( FixedCredentialsProvider.create(ImplFirebaseTrampolines.getCredentials(app))) .setProjectId(projectId) .build() .getService(); } /** * Returns the Firestore instance associated with the default Firebase app. Returns the same * instance for all invocations. The Firestore instance and all references obtained from it * becomes unusable, once the default app is deleted. * * @return A non-null <a href="https://googlecloudplatform.github.io/google-cloud-java/google-cloud-clients/apidocs/com/google/cloud/firestore/Firestore.html">{@code Firestore}</a> * instance. */ @NonNull public static Firestore getFirestore() { return getFirestore(FirebaseApp.getInstance()); } /** * Returns the Firestore instance associated with the specified Firebase app. For a given app, * always returns the same instance. The Firestore instance and all references obtained from it * becomes unusable, once the specified app is deleted. * * @param app A non-null {@link FirebaseApp}. * @return A non-null <a href="https://googlecloudplatform.github.io/google-cloud-java/google-cloud-clients/apidocs/com/google/cloud/firestore/Firestore.html">{@code Firestore}</a> * instance. */ @NonNull public static Firestore getFirestore(FirebaseApp app) { return getInstance(app).firestore; } private static synchronized FirestoreClient getInstance(FirebaseApp app) { FirestoreClientService service = ImplFirebaseTrampolines.getService(app, SERVICE_ID, FirestoreClientService.class); if (service == null) { service = ImplFirebaseTrampolines.addService(app, new FirestoreClientService(app)); } return service.getInstance(); } private static final String SERVICE_ID = FirestoreClient.class.getName(); private static class FirestoreClientService extends FirebaseService<FirestoreClient> { FirestoreClientService(FirebaseApp app) { super(SERVICE_ID, new FirestoreClient(app)); } @Override public void destroy() { try { instance.firestore.close(); } catch (Exception e) { logger.warn("Error while closing the Firestore instance", e); } } } }