diff --git a/bom/pom.xml b/bom/pom.xml index b0d4b19d..1245b542 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -154,6 +154,16 @@ quarkus-google-cloud-firebase-devservices-deployment ${project.version} + + io.quarkiverse.googlecloudservices + quarkus-google-cloud-firebase-realtime-database + ${project.version} + + + io.quarkiverse.googlecloudservices + quarkus-google-cloud-firebase-realtime-database-deployment + ${project.version} + io.quarkiverse.googlecloudservices quarkus-google-cloud-firestore diff --git a/docs/modules/ROOT/pages/firebase-database.adoc b/docs/modules/ROOT/pages/firebase-database.adoc new file mode 100644 index 00000000..2687b9fe --- /dev/null +++ b/docs/modules/ROOT/pages/firebase-database.adoc @@ -0,0 +1,76 @@ += Google Cloud Services - Firebase Admin + +This extension allows to inject a `com.google.cloud.firestore.Firestore` object inside your Quarkus application. + +This extension will pickup on any available `com.google.firebase.FirebaseApp` (see https://quarkiverse.github.io/quarkiverse-docs/quarkus-google-cloud-services/main/firebase-admin.html[Firebase Admin extension] for more info) to configure the Realtime Database. + +Be sure to have read the https://quarkiverse.github.io/quarkiverse-docs/quarkus-google-cloud-services/main/index.html[Google Cloud Services extension pack global documentation] before this one, it contains general configuration and information. + +== Bootstrapping the project + +First, we need a new project. Create a new project with the following command (replace the version placeholder with the correct one): + +[source, shell script] +---- +mvn io.quarkus:quarkus-maven-plugin:${quarkusVersion}:create \ + -DprojectGroupId=org.acme \ + -DprojectArtifactId=firebase-admin-quickstart \ + -Dextensions="resteasy-reactive-jackson,quarkus-google-cloud-firebase-realtime-database" +cd firebase-admin-quickstart +---- + +This command generates a Maven project, importing the Google Cloud Firebase Realtime Database extension.) + +If you already have your Quarkus project configured, you can add the `quarkus-google-cloud-firebase-realtime-database` extension to your project by running the following command in your project base directory: + +[source, shell script] +---- +./mvnw quarkus:add-extension -Dextensions="quarkus-google-cloud-firebase-realtime-database" +---- + +This will add the following to your pom.xml: + +[source, xml] +---- + + io.quarkiverse.googlecloudservices + quarkus-google-cloud-firebase-realtime-database + +---- + +== Some example + +This is an example usage of the extension: we create a REST resource with a single endpoint that creates a 'persons' collection, inserts three persons in it, then search for persons with last name Doe and returns them. + +[source,java] +---- +import javax.inject.Inject; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import com.google.firebase.database.FirebaseDatabase; + +@Path("/database") +public class RealtimeDatabaseResource { + + @Inject + FirebaseDatabase database; // Inject database + + @POST + @Consumes(MediaType.TEXT_PLAIN) + public void database(String data) { + var dbRef = firebaseDatabase.getReference("test"); + dbRef.setValueAsync(fields); + } +} +---- + +== Dev Service + +This extension uses the https://quarkiverse.github.io/quarkiverse-docs/quarkus-google-cloud-services/main/firebase-devservices.html[Firebase Devservices] extension to provide a Dev Service. Refer the documentation of this extension for more info. + +== Configuration Reference + +include::./includes/quarkus-google-cloud-firebase-realtime-database.adoc[] \ No newline at end of file diff --git a/docs/modules/ROOT/pages/includes/quarkus-google-cloud-firebase-realtime-database.adoc b/docs/modules/ROOT/pages/includes/quarkus-google-cloud-firebase-realtime-database.adoc new file mode 100644 index 00000000..f331d2d6 --- /dev/null +++ b/docs/modules/ROOT/pages/includes/quarkus-google-cloud-firebase-realtime-database.adoc @@ -0,0 +1,28 @@ +[.configuration-legend] +icon:lock[title=Fixed at build time] Configuration property fixed at build time - All other configuration properties are overridable at runtime +[.configuration-reference.searchable, cols="80,.^10,.^10"] +|=== + +h|[.header-title]##Configuration property## +h|Type +h|Default + +a| [[quarkus-google-cloud-firebase-realtime-database_quarkus-google-cloud-firebase-database-host-override]] [.property-path]##link:#quarkus-google-cloud-firebase-realtime-database_quarkus-google-cloud-firebase-database-host-override[`quarkus.google.cloud.firebase.database.host-override`]## + +[.description] +-- +Overrides the default service host. This is most commonly used for development or testing activities with a local Firebase Realtime Database emulator instance. + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_GOOGLE_CLOUD_FIREBASE_DATABASE_HOST_OVERRIDE+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_GOOGLE_CLOUD_FIREBASE_DATABASE_HOST_OVERRIDE+++` +endif::add-copy-button-to-env-var[] +-- +|string +| + +|=== + diff --git a/docs/modules/ROOT/pages/includes/quarkus-google-cloud-firebase-realtime-database_quarkus.google.adoc b/docs/modules/ROOT/pages/includes/quarkus-google-cloud-firebase-realtime-database_quarkus.google.adoc new file mode 100644 index 00000000..f331d2d6 --- /dev/null +++ b/docs/modules/ROOT/pages/includes/quarkus-google-cloud-firebase-realtime-database_quarkus.google.adoc @@ -0,0 +1,28 @@ +[.configuration-legend] +icon:lock[title=Fixed at build time] Configuration property fixed at build time - All other configuration properties are overridable at runtime +[.configuration-reference.searchable, cols="80,.^10,.^10"] +|=== + +h|[.header-title]##Configuration property## +h|Type +h|Default + +a| [[quarkus-google-cloud-firebase-realtime-database_quarkus-google-cloud-firebase-database-host-override]] [.property-path]##link:#quarkus-google-cloud-firebase-realtime-database_quarkus-google-cloud-firebase-database-host-override[`quarkus.google.cloud.firebase.database.host-override`]## + +[.description] +-- +Overrides the default service host. This is most commonly used for development or testing activities with a local Firebase Realtime Database emulator instance. + + +ifdef::add-copy-button-to-env-var[] +Environment variable: env_var_with_copy_button:+++QUARKUS_GOOGLE_CLOUD_FIREBASE_DATABASE_HOST_OVERRIDE+++[] +endif::add-copy-button-to-env-var[] +ifndef::add-copy-button-to-env-var[] +Environment variable: `+++QUARKUS_GOOGLE_CLOUD_FIREBASE_DATABASE_HOST_OVERRIDE+++` +endif::add-copy-button-to-env-var[] +-- +|string +| + +|=== + diff --git a/firebase-devservices/deployment/src/main/java/io/quarkiverse/googlecloudservices/firebase/deployment/FirebaseDevServiceProcessor.java b/firebase-devservices/deployment/src/main/java/io/quarkiverse/googlecloudservices/firebase/deployment/FirebaseDevServiceProcessor.java index 3f39cf72..9d8d46fd 100644 --- a/firebase-devservices/deployment/src/main/java/io/quarkiverse/googlecloudservices/firebase/deployment/FirebaseDevServiceProcessor.java +++ b/firebase-devservices/deployment/src/main/java/io/quarkiverse/googlecloudservices/firebase/deployment/FirebaseDevServiceProcessor.java @@ -37,7 +37,7 @@ public class FirebaseDevServiceProcessor { FirebaseEmulatorContainer.Emulator.FIREBASE_HOSTING, "quarkus.google.cloud.firebase.hosting.emulator-host", FirebaseEmulatorContainer.Emulator.CLOUD_FUNCTIONS, "quarkus.google.cloud.functions.emulator-host", FirebaseEmulatorContainer.Emulator.EVENT_ARC, "quarkus.google.cloud.eventarc.emulator-host", - FirebaseEmulatorContainer.Emulator.REALTIME_DATABASE, "quarkus.google.cloud.database.emulator-host", + FirebaseEmulatorContainer.Emulator.REALTIME_DATABASE, "quarkus.google.cloud.firebase.database.host-override", FirebaseEmulatorContainer.Emulator.CLOUD_FIRESTORE, "quarkus.google.cloud.firestore.host-override", FirebaseEmulatorContainer.Emulator.CLOUD_STORAGE, "quarkus.google.cloud.storage.host-override", FirebaseEmulatorContainer.Emulator.PUB_SUB, "quarkus.google.cloud.pubsub.emulator-host"); diff --git a/firebase-devservices/deployment/src/main/java/io/quarkiverse/googlecloudservices/firebase/deployment/testcontainers/FirebaseEmulatorContainer.java b/firebase-devservices/deployment/src/main/java/io/quarkiverse/googlecloudservices/firebase/deployment/testcontainers/FirebaseEmulatorContainer.java index 31c96003..02937f8e 100644 --- a/firebase-devservices/deployment/src/main/java/io/quarkiverse/googlecloudservices/firebase/deployment/testcontainers/FirebaseEmulatorContainer.java +++ b/firebase-devservices/deployment/src/main/java/io/quarkiverse/googlecloudservices/firebase/deployment/testcontainers/FirebaseEmulatorContainer.java @@ -1384,6 +1384,10 @@ private void writeOutputFrame(OutputFrame frame, Level level) { } private String getEmulatorEndpoint(Emulator emulator) { - return this.getHost() + ":" + emulatorPort(emulator); + var endpoint = this.getHost() + ":" + emulatorPort(emulator); + if (emulator.equals(Emulator.REALTIME_DATABASE)) { + endpoint = "http://" + endpoint; + } + return endpoint; } } diff --git a/firebase-realtime-database/deployment/pom.xml b/firebase-realtime-database/deployment/pom.xml new file mode 100644 index 00000000..22fb9879 --- /dev/null +++ b/firebase-realtime-database/deployment/pom.xml @@ -0,0 +1,71 @@ + + + + io.quarkiverse.googlecloudservices + quarkus-google-cloud-firebase-devservices-parent + 2.14.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + quarkus-google-cloud-firebase-realtime-database-deployment + Quarkus - Google Cloud Services - Firebase Realtime Database - Deployment + + + + io.quarkus + quarkus-core-deployment + + + io.quarkiverse.googlecloudservices + quarkus-google-cloud-common-deployment + + + io.quarkiverse.googlecloudservices + quarkus-google-cloud-firebase-realtime-database + + + + io.quarkiverse.googlecloudservices + quarkus-google-cloud-firebase-admin + + + io.quarkiverse.googlecloudservices + quarkus-google-cloud-firebase-admin-deployment + + + + + org.testcontainers + junit-jupiter + test + + + io.quarkus + quarkus-grpc-common + test + + + io.quarkiverse.googlecloudservices + quarkus-google-cloud-common-grpc + test + + + + + + maven-compiler-plugin + + + + io.quarkus + quarkus-extension-processor + ${quarkus.version} + + + + + + + + \ No newline at end of file diff --git a/firebase-realtime-database/deployment/src/main/java/io/quarkiverse/googlecloudservices/firebase/database/deployment/FirebaseDatabaseBuildSteps.java b/firebase-realtime-database/deployment/src/main/java/io/quarkiverse/googlecloudservices/firebase/database/deployment/FirebaseDatabaseBuildSteps.java new file mode 100644 index 00000000..1a6ea44c --- /dev/null +++ b/firebase-realtime-database/deployment/src/main/java/io/quarkiverse/googlecloudservices/firebase/database/deployment/FirebaseDatabaseBuildSteps.java @@ -0,0 +1,22 @@ +package io.quarkiverse.googlecloudservices.firebase.database.deployment; + +import io.quarkiverse.googlecloudservices.firebase.database.FirebaseDatabaseProducer; +import io.quarkus.arc.deployment.AdditionalBeanBuildItem; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.FeatureBuildItem; + +public class FirebaseDatabaseBuildSteps { + + private static final String FEATURE = "google-cloud-firebase-realtime-database"; + + @BuildStep + public FeatureBuildItem feature() { + return new FeatureBuildItem(FEATURE); + } + + @BuildStep + public AdditionalBeanBuildItem producer() { + return new AdditionalBeanBuildItem(FirebaseDatabaseProducer.class); + } + +} diff --git a/firebase-realtime-database/pom.xml b/firebase-realtime-database/pom.xml new file mode 100644 index 00000000..0e7b2abc --- /dev/null +++ b/firebase-realtime-database/pom.xml @@ -0,0 +1,20 @@ + + + + io.quarkiverse.googlecloudservices + quarkus-google-cloud-services-parent + 2.14.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + quarkus-google-cloud-firebase-realtime-database-parent + Quarkus - Google Cloud Services - Firebas Realtime Database + pom + + + runtime + deployment + + + \ No newline at end of file diff --git a/firebase-realtime-database/runtime/pom.xml b/firebase-realtime-database/runtime/pom.xml new file mode 100644 index 00000000..44889148 --- /dev/null +++ b/firebase-realtime-database/runtime/pom.xml @@ -0,0 +1,60 @@ + + + + io.quarkiverse.googlecloudservices + quarkus-google-cloud-firebase-realtime-database-parent + 2.14.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + quarkus-google-cloud-firebase-realtime-database + Quarkus - Google Cloud Services - Firebase Realtime Database - Runtime + Use Google Cloud Firebase + + + + io.quarkiverse.googlecloudservices + quarkus-google-cloud-common + + + + io.quarkiverse.googlecloudservices + quarkus-google-cloud-firebase-admin + + + + + + + io.quarkus + quarkus-extension-maven-plugin + ${quarkus.version} + + + + extension-descriptor + + compile + + ${project.groupId}:${project.artifactId}-deployment:${project.version} + + + + + + + maven-compiler-plugin + + + + io.quarkus + quarkus-extension-processor + ${quarkus.version} + + + + + + + \ No newline at end of file diff --git a/firebase-realtime-database/runtime/src/main/java/io/quarkiverse/googlecloudservices/firebase/database/FirebaseDatabaseConfig.java b/firebase-realtime-database/runtime/src/main/java/io/quarkiverse/googlecloudservices/firebase/database/FirebaseDatabaseConfig.java new file mode 100644 index 00000000..f27d8142 --- /dev/null +++ b/firebase-realtime-database/runtime/src/main/java/io/quarkiverse/googlecloudservices/firebase/database/FirebaseDatabaseConfig.java @@ -0,0 +1,24 @@ +package io.quarkiverse.googlecloudservices.firebase.database; + +import java.util.Optional; + +import io.quarkus.runtime.annotations.ConfigPhase; +import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; + +/** + * Root configuration class for Google Cloud Firebase Realtime database setup. + * + */ +@ConfigMapping(prefix = "quarkus.google.cloud.firebase.database") +@ConfigRoot(phase = ConfigPhase.RUN_TIME) +public interface FirebaseDatabaseConfig { + + /** + * Overrides the default service host. + * This is most commonly used for development or testing activities with a local Firebase Realtime Database emulator + * instance. + */ + Optional hostOverride(); + +} diff --git a/firebase-realtime-database/runtime/src/main/java/io/quarkiverse/googlecloudservices/firebase/database/FirebaseDatabaseProducer.java b/firebase-realtime-database/runtime/src/main/java/io/quarkiverse/googlecloudservices/firebase/database/FirebaseDatabaseProducer.java new file mode 100644 index 00000000..8091c234 --- /dev/null +++ b/firebase-realtime-database/runtime/src/main/java/io/quarkiverse/googlecloudservices/firebase/database/FirebaseDatabaseProducer.java @@ -0,0 +1,34 @@ +package io.quarkiverse.googlecloudservices.firebase.database; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Default; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import com.google.firebase.FirebaseApp; +import com.google.firebase.database.FirebaseDatabase; + +/** + * Producer for the {@link FirebaseDatabase}. + */ +@ApplicationScoped +public class FirebaseDatabaseProducer { + + @Inject + FirebaseApp firebaseApp; + + @Inject + FirebaseDatabaseConfig config; + + @Produces + @Singleton + @Default + public FirebaseDatabase firebaseDatabase() { + if (config.hostOverride().isPresent()) { + return FirebaseDatabase.getInstance(firebaseApp, config.hostOverride().get()); + } else { + return FirebaseDatabase.getInstance(firebaseApp); + } + } +} diff --git a/firebase-realtime-database/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/firebase-realtime-database/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 00000000..cb7250b8 --- /dev/null +++ b/firebase-realtime-database/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,17 @@ +--- +name: "Google Cloud Firebase Realtime Database" +artifact: ${project.groupId}:${project.artifactId}:${project.version} +metadata: + keywords: + - "realtime database" + - "firebase" + - "google cloud" + - "gcloud" + - "gcp" + categories: + - "cloud" + - "data" + guide: "https://quarkiverse.github.io/quarkiverse-docs/quarkus-google-cloud-services/main/firebase-realtime-database.html" + status: "experimental" + config: + - "quarkus.google.cloud.firebase.database" diff --git a/integration-tests/firebase/pom.xml b/integration-tests/firebase/pom.xml index 0833face..095d97d4 100644 --- a/integration-tests/firebase/pom.xml +++ b/integration-tests/firebase/pom.xml @@ -26,6 +26,10 @@ io.quarkiverse.googlecloudservices quarkus-google-cloud-firebase-devservices + + io.quarkiverse.googlecloudservices + quarkus-google-cloud-firebase-realtime-database + io.quarkiverse.googlecloudservices quarkus-google-cloud-firestore diff --git a/integration-tests/firebase/src/main/java/io/quarkiverse/googlecloudservices/it/firebase/FirebaseResource.java b/integration-tests/firebase/src/main/java/io/quarkiverse/googlecloudservices/it/firebase/FirebaseResource.java index 3d084f66..207d9bf0 100644 --- a/integration-tests/firebase/src/main/java/io/quarkiverse/googlecloudservices/it/firebase/FirebaseResource.java +++ b/integration-tests/firebase/src/main/java/io/quarkiverse/googlecloudservices/it/firebase/FirebaseResource.java @@ -14,6 +14,7 @@ import com.google.cloud.firestore.Firestore; import com.google.cloud.pubsub.v1.Publisher; +import com.google.firebase.database.FirebaseDatabase; import com.google.protobuf.ByteString; import com.google.pubsub.v1.PubsubMessage; @@ -29,6 +30,9 @@ public class FirebaseResource { @Inject QuarkusPubSub quarkusPubSub; + @Inject + FirebaseDatabase firebaseDatabase; + Publisher publisher; public void init(@Observes StartupEvent event) throws IOException { @@ -48,15 +52,23 @@ public void createData(String data) throws InterruptedException, ExecutionExcept var fields = Map.of("test", msgData); col.document("test").create(fields).get(); + + var dbRef = firebaseDatabase.getReference("test"); + dbRef.setValue(fields, (err, ref) -> { + if (err == null) { + // Not pretty, but we just let the consumer timeout. + consumer.ack(); + } + + synchronized (monitor) { + monitor.notify(); + } + }); + } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } - consumer.ack(); - - synchronized (monitor) { - monitor.notify(); - } }); subscriber.startAsync().awaitRunning(); @@ -80,6 +92,7 @@ public Response getData() throws ExecutionException, InterruptedException { if (iter.hasNext()) { var docRef = iter.next(); var snapshot = docRef.get().get(); + return Response.ok(snapshot.getString("test")).build(); } else { return Response.status(Response.Status.NOT_FOUND).build(); diff --git a/integration-tests/firebase/src/main/resources/application.properties b/integration-tests/firebase/src/main/resources/application.properties index 1e24c613..7fdb657a 100644 --- a/integration-tests/firebase/src/main/resources/application.properties +++ b/integration-tests/firebase/src/main/resources/application.properties @@ -5,4 +5,5 @@ quarkus.google.cloud.devservices.project-id=demo-test-project-id quarkus.google.cloud.access-token-enabled=false quarkus.google.cloud.devservices.firebase.auth.enabled=true quarkus.google.cloud.devservices.firebase.firestore.enabled=true +quarkus.google.cloud.devservices.firebase.database.enabled=true quarkus.google.cloud.devservices.pubsub.enabled=true diff --git a/pom.xml b/pom.xml index b5289034..ec8b14f1 100644 --- a/pom.xml +++ b/pom.xml @@ -32,6 +32,7 @@ storage firebase-devservices firebase-admin + firebase-realtime-database firestore bigtable secret-manager