diff --git a/.gitignore b/.gitignore index a6b51d0..43a2ba3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ build/ +service-account.json + *.class *.war *.ear diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9b1ae84..29d3f33 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ -# Contributing to the Firebase Node.JS Quickstarts +# Contributing to the Firebase Java Quickstarts -We'd love for you to contribute to our source code and to make the Firebase Node.JS Quickstarts even better than it is today! Here are the guidelines we'd like you to follow: +We'd love for you to contribute to our source code and to make the Firebase Java Quickstarts even better than it is today! Here are the guidelines we'd like you to follow: - [Code of Conduct](#coc) - [Question or Problem?](#question) @@ -12,19 +12,19 @@ We'd love for you to contribute to our source code and to make the Firebase Node ## Code of Conduct -As contributors and maintainers of the Firebase Node.JS Quickstarts project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities. +As contributors and maintainers of the Firebase Java Quickstarts project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities. Communication through any of Firebase's channels (GitHub, StackOverflow, Google+, Twitter, etc.) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, disability, age, race, ethnicity, religion, or level of experience. We expect anyone contributing to the project to do the same. -If any member of the community violates this code of conduct, the maintainers of the Firebase Node.JS Quickstarts project may take action, removing issues, comments, and PRs or blocking accounts as deemed appropriate. +If any member of the community violates this code of conduct, the maintainers of the Firebase Java Quickstarts project may take action, removing issues, comments, and PRs or blocking accounts as deemed appropriate. If you are subject to or witness unacceptable behavior, or have any other concerns, please drop us a line at nivco@google.com. ## Got a Question or Problem? -If you have questions about how to use the Firebase Node.JS Quickstarts, please direct these to [StackOverflow][stackoverflow] and use the `firebase` tag. We are also available on GitHub issues. +If you have questions about how to use the Firebase Javqa Quickstarts, please direct these to [StackOverflow][stackoverflow] and use the `firebase` tag. We are also available on GitHub issues. If you feel that we're missing an important bit of documentation, feel free to file an issue so we can help. Here's an example to get you started: diff --git a/README.md b/README.md index a7fa4a9..c4de05e 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,12 @@ # Firebase Quickstarts for Java -A collection of quickstart samples demonstrating the Firebase APIs using the Java Server SDK. For more information, see https://firebase.google.com. +A collection of quickstart samples demonstrating the Firebase APIs using the Admin Java SDK. For more information, see https://firebase.google.com. ## How to make contributions? Please read and follow the steps in the [CONTRIBUTING.md](CONTRIBUTING.md) ## License See [LICENSE](LICENSE) + +## Build Status +[![Build Status](https://travis-ci.org/firebase/quickstart-java.svg?branch=master)](https://travis-ci.org/firebase/quickstart-java) \ No newline at end of file diff --git a/auth/README.md b/auth/README.md deleted file mode 100644 index 0fa2700..0000000 --- a/auth/README.md +++ /dev/null @@ -1,33 +0,0 @@ -Firebase Java Auth Quickstart -========================================== - -This directory contains example snippets for the Firebase Admin Authentication SDK, mostly for use -in documentation. - - -Introduction ------------- - -- [Read more about Firebase Auth](https://firebase.google.com/docs/auth/) - -Getting Started ---------------- - -- Create your project on the [Firebase Console](https://console.firebase.google.com). -- Create a service account as described in [Adding Firebase to your Server](https://firebase.google.com/docs/admin/setup) and download the JSON file. - - Copy the json file to this folder and rename it to `service-account.json`. - - -Run --------------- -- From the `auth` directory run `./gradlew build run` to start run the quickstart. - -Support -------- - -https://firebase.google.com/support/ - -License -------- - -© Google, 2017. Licensed under an [Apache-2](../LICENSE) license. diff --git a/auth/build.gradle b/auth/build.gradle deleted file mode 100644 index 244863d..0000000 --- a/auth/build.gradle +++ /dev/null @@ -1,20 +0,0 @@ -group 'com.google.firebase.quickstart' -version '1.0' - -apply plugin: 'groovy' -apply plugin: 'java' - -apply plugin: 'application' -mainClassName = 'com.google.firebase.quickstart.AuthSnippets' - -sourceCompatibility = 1.8 - -repositories { - mavenCentral() - mavenLocal() -} - -dependencies { - // Firebase Java SDK - compile 'com.google.firebase:firebase-admin:5.0.2-SNAPSHOT' -} diff --git a/auth/src/main/java/com/google/firebase/quickstart/AuthSnippets.java b/auth/src/main/java/com/google/firebase/quickstart/AuthSnippets.java deleted file mode 100644 index 287534a..0000000 --- a/auth/src/main/java/com/google/firebase/quickstart/AuthSnippets.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.google.firebase.quickstart; - -import com.google.firebase.FirebaseApp; -import com.google.firebase.FirebaseOptions; -import com.google.firebase.auth.FirebaseAuth; -import com.google.firebase.auth.FirebaseCredentials; -import com.google.firebase.auth.UserRecord; -import com.google.firebase.auth.UserRecord.CreateRequest; -import com.google.firebase.auth.UserRecord.UpdateRequest; -import com.google.firebase.tasks.Task; -import java.io.FileInputStream; -import java.io.IOException; - -/** - * Auth snippets for documentation. - * - * See: - * https://firebase.google.com/docs/auth/admin - */ -public class AuthSnippets { - - public static Task getUserById(String uid) { - // [START get_user_by_id] - Task task = FirebaseAuth.getInstance().getUser(uid) - .addOnSuccessListener(userRecord -> { - // See the UserRecord reference doc for the contents of userRecord. - System.out.println("Successfully fetched user data: " + userRecord.getUid()); - }) - .addOnFailureListener(e -> { - System.err.println("Error fetching user data: " + e.getMessage()); - }); - // [END get_user_by_id] - - return task; - } - - public static Task getUserByEmail(String email) { - // [START get_user_by_email] - Task task = FirebaseAuth.getInstance().getUserByEmail(email) - .addOnSuccessListener(userRecord -> { - // See the UserRecord reference doc for the contents of userRecord. - System.out.println("Successfully fetched user data: " + userRecord.getEmail()); - }) - .addOnFailureListener(e -> { - System.err.println("Error fetching user data: " + e.getMessage()); - }); - // [END get_user_by_email] - - return task; - } - - public static Task createUser() { - // [START create_user] - CreateRequest request = new CreateRequest() - .setEmail("user@example.com") - .setEmailVerified(false) - .setPassword("secretPassword") - .setDisplayName("John Doe") - .setPhotoUrl("http://www.example.com/12345678/photo.png") - .setDisabled(false); - - Task task = FirebaseAuth.getInstance().createUser(request) - .addOnSuccessListener(userRecord -> { - // See the UserRecord reference doc for the contents of userRecord. - System.out.println("Successfully created new user: " + userRecord.getUid()); - }) - .addOnFailureListener(e -> { - System.err.println("Error creating new user: " + e.getMessage()); - }); - // [END create_user] - - return task; - } - - public static Task createUserWithUid() { - // [START create_user_with_uid] - CreateRequest request = new CreateRequest() - .setUid("some-uid") - .setEmail("user@example.com"); - - Task task = FirebaseAuth.getInstance().createUser(request) - .addOnSuccessListener(userRecord -> { - // See the UserRecord reference doc for the contents of userRecord. - System.out.println("Successfully created new user: " + userRecord.getUid()); - }) - .addOnFailureListener(e -> { - System.err.println("Error creating new user: " + e.getMessage()); - }); - // [END create_user_with_uid] - - return task; - } - - public static Task updateUser(String uid) { - // [START update_user] - UpdateRequest request = new UpdateRequest(uid) - .setEmail("user@example.com") - .setEmailVerified(true) - .setPassword("newPassword") - .setDisplayName("Jane Doe") - .setPhotoUrl("http://www.example.com/12345678/photo.png") - .setDisabled(true); - - Task task = FirebaseAuth.getInstance().updateUser(request) - .addOnSuccessListener(userRecord -> { - // See the UserRecord reference doc for the contents of userRecord. - System.out.println("Successfully updated user: " + userRecord.getUid()); - }) - .addOnFailureListener(e -> { - System.err.println("Error updating user: " + e.getMessage()); - }); - // [END update_user] - - return task; - } - - public static Task deleteUser(String uid) { - // [START delete_user] - Task task = FirebaseAuth.getInstance().deleteUser(uid) - .addOnSuccessListener(aVoid -> System.out.println("Successfully deleted user.")) - .addOnFailureListener(e -> System.err.println("Error updating user: " + e.getMessage())); - // [END delete_user] - - return task; - } - - public static void main(String[] args) { - System.out.println("Hello, AuthSnippets!"); - - // Initialize Firebase - try { - // [START initialize] - FileInputStream serviceAccount = new FileInputStream("service-account.json"); - FirebaseOptions options = new FirebaseOptions.Builder() - .setCredential(FirebaseCredentials.fromCertificate(serviceAccount)) - .build(); - FirebaseApp.initializeApp(options); - // [END initialize] - } catch (IOException e) { - System.out.println("ERROR: invalid service account credentials. See README."); - System.out.println(e.getMessage()); - - System.exit(1); - } - - // Smoke test - createUserWithUid() - .continueWithTask(task -> getUserById("some-uid")) - .continueWithTask(task -> getUserByEmail("user@example.com")) - .continueWithTask(task -> updateUser("some-uid")) - .continueWithTask(task -> deleteUser("some-uid")) - .addOnCompleteListener(task -> System.out.println("Done! Success: " + task.isSuccessful())); - } - -} diff --git a/build.gradle b/build.gradle index 0e0abac..5b9d0fb 100644 --- a/build.gradle +++ b/build.gradle @@ -3,6 +3,10 @@ allprojects { mavenCentral() mavenLocal() } + dependencies { + // Add the dependency for the Google services Gradle plugin + classpath 'com.google.gms:google-services:4.3.15' + } } task clean(type: Delete) { diff --git a/auth/.gitignore b/config/.gitignore similarity index 65% rename from auth/.gitignore rename to config/.gitignore index 595bf6a..a90cb68 100644 --- a/auth/.gitignore +++ b/config/.gitignore @@ -1 +1,2 @@ service-account.json +config.json \ No newline at end of file diff --git a/config/LICENSE b/config/LICENSE new file mode 100644 index 0000000..5e741d0 --- /dev/null +++ b/config/LICENSE @@ -0,0 +1,211 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + 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. + + All code in any directories or sub-directories that end with *.html or + *.css is licensed under the Creative Commons Attribution International + 4.0 License, which full text can be found here: + https://creativecommons.org/licenses/by/4.0/legalcode. + + As an exception to this license, all html or css that is generated by + the software at the direction of the user is copyright the user. The + user has full ownership and control over such content, including + whether and how they wish to license it. diff --git a/config/README.md b/config/README.md new file mode 100644 index 0000000..54d15e4 --- /dev/null +++ b/config/README.md @@ -0,0 +1,108 @@ +Firebase Remote Config REST API Java Quickstart +=============================================== + +The [Firebase Remote Config](https://firebase.google.com/docs/remote-config/) Java quickstart app demonstrates retrieving and +updating the Firebase Remote Config template. + +Introduction +------------ + +This is a simple example of using the Firebase Remote Config REST API to update +the Remote Config template being used by clients apps. + +Getting started +--------------- + +1. [Add Firebase to your Android Project](https://firebase.google.com/docs/android/setup). +2. Create a service account as described in [Adding Firebase to your Server](https://firebase.google.com/docs/admin/setup) and download the JSON file. + - Copy the private key JSON file to this folder and rename it to `service-account.json`. +3. Change the build.gradle file under config/, to replace '[YOUR_SERVICE_ACCOUNT_JSON_DIR]' to the directory of `service-account.json`. + +Run +--- + +- Get active template + - From the `config` directory run `./gradlew run -Paction=get` to retrieve the template. + - The returned template is stored in a file named `config.json`. + - Note the ETag printed to the console you will need to use it when publishing template updates. +- Update the template + - If your template already has parameters, adjust one or more of the values. + - If your template is empty, update it to look like this: + + { + "conditions": [ + { + "name": "AndroidUsers", + "expression": "device.os == 'android'", + "tagColor": "PURPLE" + }, + { + "name": "iOSUsers", + "expression": "device.os == 'ios'", + "tagColor": "GREEN" + } + ], + "parameters": { + "welcome_message": { + "defaultValue": { + "value": "Welcome" + }, + "conditionalValues": { + "AndroidUsers": { + "value": "Welcome Android User" + }, + "iOSUsers": { + "value": "Welcome iOS User" + } + } + } + } + } + + - From the `config` directory run `./gradlew run -Paction=publish -Petag=''` to update the template. + - Be sure to set the etag to the one that was last printed in the console. + - Confirm in the console that the template has been updated. + - At this point mobile clients can fetch the updated values. +- View existing versions + - From the `config` directory run `./gradlew run -Paction=versions` to print the + last 5 template versions. +- Roll back to an existing template + - From the `config` directory run `./gradlew run -Paction=rollback -Pversion=` to + activate the template with the matching version number. + +Best practices +-------------- + +This section provides some additional information about how the Remote Config +REST API should be used when retrieving and updating templates. + +### [Versions](https://firebase.google.com/docs/remote-config/templates) ### + +Each time you update parameters, {{remote_config}} creates a +new versioned {{remote_config}} template and stores the previous template as +a version that you can retrieve or roll back to as needed. + +All non-active versions expire and are removed if they are older than 90 days or if +there are more than 300 newer template versions. Since template versions expire, any +versions that need to be retrieved later on should be persisted externally. + +Use the `listVersions` [query parameters](https://firebase.google.com/docs/reference/remote-config/rest/v1/projects.remoteConfig/listVersions#query-parameters) +to filter the versions that are returned. + +### ETags ### + +Each time the Remote Config template it retrieved an ETag is included. This ETag is a +unique identifier of the current template on the server. When submitting updates +to the template you must include the latest ETag to ensure that your updates are consistent. + +In the event that you want to completely overwrite the server's template use +an ETag of "\*". Use this with caution since this operation cannot be undone. + +**NOTE:** To get the ETag your request must accept the gzip encoding. Add the header +`Accept-Encoding: gzip` to receive the ETag in the response header `ETag`. + +Support +------- + +- [Stack Overflow](https://stackoverflow.com/questions/tagged/firebase-remote-config) +- [Firebase Support](https://firebase.google.com/support/) diff --git a/config/build.gradle b/config/build.gradle new file mode 100644 index 0000000..2dc03aa --- /dev/null +++ b/config/build.gradle @@ -0,0 +1,31 @@ +apply plugin: 'java' +apply plugin: 'application' +mainClassName = 'com.google.firebase.samples.config.Configure' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +# run.doFirst { environment 'GOOGLE_APPLICATION_CREDENTIALS', '[YOUR_SERVICE_ACCOUNT_JSON_DIR]' } + +run { + if (project.hasProperty("action")) { + args = args << "${action}" + } + if (project.hasProperty("etag")) { + args = args << "${etag}" + } + if (project.hasProperty("version") && !project.version.equals("unspecified")) { + args = args << "${version}" + } + standardInput = System.in +} + +dependencies { + testCompile group: 'junit', name: 'junit', version: '4.12' + compile 'com.google.auth:google-auth-library-oauth2-http:0.26.0' + compile 'com.google.code.gson:gson:2.8.7' + implementation 'com.google.firebase:firebase-admin:9.1.1' +} diff --git a/auth/gradle/wrapper/gradle-wrapper.jar b/config/gradle/wrapper/gradle-wrapper.jar similarity index 99% rename from auth/gradle/wrapper/gradle-wrapper.jar rename to config/gradle/wrapper/gradle-wrapper.jar index 20c81d8..fc02a97 100644 Binary files a/auth/gradle/wrapper/gradle-wrapper.jar and b/config/gradle/wrapper/gradle-wrapper.jar differ diff --git a/auth/gradle/wrapper/gradle-wrapper.properties b/config/gradle/wrapper/gradle-wrapper.properties similarity index 80% rename from auth/gradle/wrapper/gradle-wrapper.properties rename to config/gradle/wrapper/gradle-wrapper.properties index 62ae997..70e10dd 100644 --- a/auth/gradle/wrapper/gradle-wrapper.properties +++ b/config/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Jun 05 12:47:30 PDT 2017 +#Tue Jul 18 12:41:35 PDT 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip diff --git a/auth/gradlew b/config/gradlew similarity index 100% rename from auth/gradlew rename to config/gradlew diff --git a/auth/gradlew.bat b/config/gradlew.bat similarity index 100% rename from auth/gradlew.bat rename to config/gradlew.bat diff --git a/config/settings.gradle b/config/settings.gradle new file mode 100644 index 0000000..82435c2 --- /dev/null +++ b/config/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'config' + diff --git a/config/src/main/java/com/google/firebase/samples/config/Configure.java b/config/src/main/java/com/google/firebase/samples/config/Configure.java new file mode 100644 index 0000000..9ed5088 --- /dev/null +++ b/config/src/main/java/com/google/firebase/samples/config/Configure.java @@ -0,0 +1,205 @@ +package com.google.firebase.samples.config; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; +import com.google.firebase.remoteconfig.FirebaseRemoteConfig; +import com.google.firebase.remoteconfig.FirebaseRemoteConfigException; +import com.google.firebase.remoteconfig.ListVersionsOptions; +import com.google.firebase.remoteconfig.ListVersionsPage; +import com.google.firebase.remoteconfig.Template; +import com.google.firebase.remoteconfig.Version; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonArray; +import com.google.gson.JsonParser; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + + +/** + * Retrieve and publish templates for Firebase Remote Config using the REST API. + */ +public class Configure { + + /** + * Gets current Firebase Remote Config template from server and store it locally. + * + * @throws IOException + */ + private static void getTemplate() throws IOException { + try { + Template template = FirebaseRemoteConfig.getInstance().getTemplate(); + JsonParser jsonParser = new JsonParser(); + JsonElement jsonElement = jsonParser.parse(template.toJSON()); + Gson gson = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); + String jsonStr = gson.toJson(jsonElement); + + File file = new File("config.json"); + PrintWriter printWriter = new PrintWriter(new FileWriter(file)); + printWriter.print(jsonStr); + printWriter.flush(); + printWriter.close(); + System.out.println("Template retrieved and has been written to config.json"); + + // Print ETag + String etag = template.getETag(); + System.out.println("ETag from server: " + etag); + } catch (FirebaseRemoteConfigException e) { + System.out.println(e.getHttpResponse().getContent()); + } + } + + /** + * Prints the last 5 available Firebase Remote Config template metadata from the server. + */ + private static void getVersions() { + ListVersionsOptions listVersionsOptions = ListVersionsOptions.builder().setPageSize(5).build(); + try { + ListVersionsPage page = FirebaseRemoteConfig.getInstance().listVersions(listVersionsOptions); + System.out.println("Versions: "); + System.out.println(versionsToJSONString(page)); + } catch (FirebaseRemoteConfigException e) { + System.out.println(e.getHttpResponse().getContent()); + } + } + + /** + * Rolls back to an available version of Firebase Remote Config template. + * + * @param version The version to roll back to. + */ + private static void rollback(int version) { + try { + Template template = FirebaseRemoteConfig.getInstance().rollback(version); + System.out.println("Rolled back to: " + version); + System.out.println(template.toJSON()); + System.out.println("ETag from server: " + template.getETag()); + } catch (FirebaseRemoteConfigException e) { + System.out.println("Error:"); + System.out.println(e.getHttpResponse().getContent()); + } + } + + /** + * Publishes local template to Firebase server. + * + * @throws IOException + */ + private static void publishTemplate(String etag) throws IOException { + if (etag.equals("*")) { + Scanner scanner = new Scanner(System.in); + System.out.println("Are you sure you would like to force replace the template? Yes (y), No (n)"); + String answer = scanner.nextLine(); + if (!answer.equalsIgnoreCase("y")) { + System.out.println("Publish canceled."); + return; + } + } + + System.out.println("Publishing template..."); + + String templateStr = readConfig(); + try { + Template template = Template.fromJSON(templateStr); + if (etag.equals("*")) { + Template publishedTemplate = FirebaseRemoteConfig.getInstance() + .forcePublishTemplate(template); + } else { + Template publishedTemplate = FirebaseRemoteConfig.getInstance() + .publishTemplate(template); + } + System.out.println("Template has been published."); + } + catch (FirebaseRemoteConfigException e) { + System.out.println("Error:"); + System.out.println(e.getHttpResponse().getContent()); + } + } + + /** + * Reads the Firebase Remote Config template from config.json file. + * + * @return String with contents of config.json file. + * @throws FileNotFoundException + */ + private static String readConfig() throws FileNotFoundException { + File file = new File("config.json"); + Scanner scanner = new Scanner(file); + + StringBuilder stringBuilder = new StringBuilder(); + while (scanner.hasNext()) { + stringBuilder.append(scanner.nextLine()); + } + return stringBuilder.toString(); + } + + /** + * Converts the list of versions into a formatted JSON string. + * + * @return String representing the list of versions. + */ + private static String versionsToJSONString(ListVersionsPage page) { + Gson gson = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); + JsonParser jsonParser = new JsonParser(); + + JsonArray versionsJsonArray = new JsonArray(); + for (Version version : page.iterateAll()) { + versionsJsonArray.add(jsonParser.parse(gson.toJson(version))); + } + + JsonObject jsonObject = new JsonObject(); + jsonObject.add("versions", versionsJsonArray); + return gson.toJson(jsonParser.parse(jsonObject.toString())); + } + + public static void initializeWithDefaultCredentials() throws IOException { + // [START initialize_sdk_with_application_default] + FirebaseOptions options = new FirebaseOptions.Builder() + .setCredentials(GoogleCredentials.getApplicationDefault()) + .build(); + + FirebaseApp.initializeApp(options); + // [END initialize_sdk_with_application_default] + } + + public static void main(String[] args) throws IOException { + initializeWithDefaultCredentials(); + if (args.length > 1 && args[0].equals("publish")) { + publishTemplate(args[1]); + } else if (args.length == 1 && args[0].equals("get")) { + getTemplate(); + } else if (args.length == 1 && args[0].equals("versions")) { + getVersions(); + } else if (args.length > 1 && args[0].equals("rollback")) { + rollback(Integer.parseInt(args[1])); + } else { + System.err.println("Invalid request. Please use one of the following commands:"); + // To get the current template from the server. + System.err.println("./gradlew run -Paction=get"); + // To publish the template in config.json to the server. + System.err.println("./gradlew run -Paction=publish -Petag=''"); + // To get the available template versions from the server. + System.err.println("./gradlew run -Paction=versions"); + // To roll back to a particular version. + System.err.println("./gradlew run -Paction=rollback -Pversion="); + } + } + +} diff --git a/database/.gitignore b/database/.gitignore deleted file mode 100644 index 595bf6a..0000000 --- a/database/.gitignore +++ /dev/null @@ -1 +0,0 @@ -service-account.json diff --git a/database/README.md b/database/README.md deleted file mode 100644 index 18ae923..0000000 --- a/database/README.md +++ /dev/null @@ -1,42 +0,0 @@ -Firebase Java Realtime Database Quickstart -========================================== - -The Java Firebase Database quickstart demonstrates how to connect to and use the Firebase Realtime Database using Java through a simple social blogging app. It will interoperate with the Web, iOS and Android database quickstarts. - -This server will: - - Update the star counts for all posts. - - Send notifications when a post has been stared. - - Run weekly job listing the top 5 posts. - -Introduction ------------- - -- [Read more about Firebase Database](https://firebase.google.com/docs/database/) - -Getting Started ---------------- - -- Create your project on the [Firebase Console](https://console.firebase.google.com). -- Create a service account as described in [Adding Firebase to your Server](https://firebase.google.com/docs/admin/setup) and download the JSON file. - - Copy the json file to this folder and rename it to `service-account.json`. -- Change the `DATATBASE_URL` variable in `Database.java` to be the URL of your Firebase Database. - - -Run --------------- -- From the `database` directory run `./gradlew build run` to start run the quickstart. -- Configure and run one of the Database quickstarts for [Web](https://github.com/firebase/quickstart-js/tree/master/database), - [iOS](https://github.com/firebase/quickstart-ios/tree/master/database) or - [Android](https://github.com/firebase/quickstart-android/tree/master/database). - Then use one of these apps to publish new posts: you should see console output when one of your posts have - received a new star and the starred counter should be kept up to date by the app. - -Support -------- - -https://firebase.google.com/support/ - -License -------- - -© Google, 2016. Licensed under an [Apache-2](../LICENSE) license. diff --git a/database/build.gradle b/database/build.gradle deleted file mode 100644 index 5b04dd8..0000000 --- a/database/build.gradle +++ /dev/null @@ -1,22 +0,0 @@ -group 'com.google.firebase.quickstart' -version '1.0' - -apply plugin: 'java' - -apply plugin: 'application' -mainClassName = 'com.google.firebase.quickstart.Database' - -sourceCompatibility = 1.8 - -repositories { - mavenCentral() - mavenLocal() -} - -dependencies { - // Firebase Java SDK - compile 'com.google.firebase:firebase-admin:4.1.1' - - // Sundial Job Scheduler - compile 'org.knowm:sundial:2.1.1' -} diff --git a/database/gradle/wrapper/gradle-wrapper.jar b/database/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 9411448..0000000 Binary files a/database/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/database/settings.gradle b/database/settings.gradle deleted file mode 100644 index 527b65e..0000000 --- a/database/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -rootProject.name = 'database' - diff --git a/database/src/main/java/com/google/firebase/quickstart/Database.java b/database/src/main/java/com/google/firebase/quickstart/Database.java deleted file mode 100644 index 4dab0dd..0000000 --- a/database/src/main/java/com/google/firebase/quickstart/Database.java +++ /dev/null @@ -1,209 +0,0 @@ -/** - * Copyright Google Inc. All Rights Reserved. - * - * 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.quickstart; - -import com.google.firebase.FirebaseApp; -import com.google.firebase.FirebaseOptions; -import com.google.firebase.auth.FirebaseCredentials; -import com.google.firebase.database.*; -import com.google.firebase.quickstart.email.MyEmailer; -import com.google.firebase.quickstart.model.Post; -import com.google.firebase.quickstart.model.User; -import org.knowm.sundial.SundialJobScheduler; - -import java.io.FileInputStream; -import java.io.FileNotFoundException; - -/** - * Firebase Database quickstart sample for the Java Admin SDK. - * See: https://firebase.google.com/docs/admin/setup#add_firebase_to_your_app - */ -public class Database { - - private static final String DATABASE_URL = "https://.firebaseio.com/"; - - private static DatabaseReference database; - - /** - * Notify a user of a new start and then update the last notification time. - */ - private static void sendNotificationToUser(final String uid, final String postId) { - // [START single_value_read] - final DatabaseReference userRef = database.child("users").child(uid); - userRef.addListenerForSingleValueEvent(new ValueEventListener() { - public void onDataChange(DataSnapshot dataSnapshot) { - User user = dataSnapshot.getValue(User.class); - if (user.email != null) { - // Send email notification - MyEmailer.sendNotificationEmail(user.email, uid, postId); - } - } - - public void onCancelled(DatabaseError databaseError) { - System.out.println("Unable to get user data from " + userRef.getKey()); - System.out.println("Error: " + databaseError.getMessage()); - } - }); - // [END single_value_read] - } - - /** - * Update the startCount value to equal the number of stars in the map. - */ - private static void updateStarCount(DatabaseReference postRef) { - // [START post_stars_transaction] - postRef.runTransaction(new Transaction.Handler() { - public Transaction.Result doTransaction(MutableData mutableData) { - Post post = mutableData.getValue(Post.class); - if (post != null) { - // Update the starCount to be the same as the number of members in the stars map. - if (post.stars != null) { - post.starCount = post.stars.size(); - } else { - post.starCount = 0; - } - - mutableData.setValue(post); - return Transaction.success(mutableData); - } else { - return Transaction.success(mutableData); - } - } - - public void onComplete(DatabaseError databaseError, boolean complete, DataSnapshot dataSnapshot) { - System.out.println("updateStarCount:onComplete:" + complete); - } - }); - // [END post_stars_transaction] - } - - /** - * Start global listener for all Posts. - */ - public static void startListeners() { - database.child("posts").addChildEventListener(new ChildEventListener() { - - public void onChildAdded(DataSnapshot dataSnapshot, String prevChildName) { - final String postId = dataSnapshot.getKey(); - final Post post = dataSnapshot.getValue(Post.class); - - // Listen for changes in the number of stars and update starCount - addStarsChangedListener(post, postId); - - // Listen for new stars on the post, notify users on changes - addNewStarsListener(dataSnapshot.getRef(), post); - } - - public void onChildChanged(DataSnapshot dataSnapshot, String prevChildName) {} - - public void onChildRemoved(DataSnapshot dataSnapshot) {} - - public void onChildMoved(DataSnapshot dataSnapshot, String prevChildName) {} - - public void onCancelled(DatabaseError databaseError) { - System.out.println("startListeners: unable to attach listener to posts"); - System.out.println("startListeners: " + databaseError.getMessage()); - } - }); - } - - /** - * Listen for stars added or removed and update the starCount. - */ - private static void addStarsChangedListener(Post post, String postId) { - // Get references to the post in both locations - final DatabaseReference postRef = database.child("posts").child(postId); - final DatabaseReference userPostRef = database.child("user-posts").child(post.uid).child(postId); - - // When the post changes, update the star counts - // [START post_value_event_listener] - postRef.child("stars").addValueEventListener(new ValueEventListener() { - public void onDataChange(DataSnapshot dataSnapshot) { - updateStarCount(postRef); - // [START_EXCLUDE] - updateStarCount(userPostRef); - // [END_EXCLUDE] - } - - public void onCancelled(DatabaseError databaseError) { - System.out.println("Unable to attach listener to stars for post: " + postRef.getKey()); - System.out.println("Error: " + databaseError.getMessage()); - } - }); - // [END post_value_event_listener] - } - - /** - * Send email to author when new star is received. - */ - private static void addNewStarsListener(final DatabaseReference postRef, final Post post) { - // [START child_event_listener_recycler] - postRef.child("stars").addChildEventListener(new ChildEventListener() { - public void onChildAdded(DataSnapshot dataSnapshot, String prevChildName) { - // New star added, notify the author of the post - sendNotificationToUser(post.uid, postRef.getKey()); - } - - public void onChildChanged(DataSnapshot dataSnapshot, String prevChildName) {} - - public void onChildRemoved(DataSnapshot dataSnapshot) {} - - public void onChildMoved(DataSnapshot dataSnapshot, String prevChildName) {} - - public void onCancelled(DatabaseError databaseError) { - System.out.println("Unable to attach new star listener to: " + postRef.getKey()); - System.out.println("Error: " + databaseError.getMessage()); - } - }); - // [END child_event_listener_recycler] - } - - /** - * Send an email listing the top posts every Sunday. - */ - private static void startWeeklyTopPostEmailer() { - SundialJobScheduler.startScheduler("com.google.firebase.quickstart.email"); - } - - public static void main(String[] args) { - // Initialize Firebase - try { - // [START initialize] - FileInputStream serviceAccount = new FileInputStream("service-account.json"); - FirebaseOptions options = new FirebaseOptions.Builder() - .setCredential(FirebaseCredentials.fromCertificate(serviceAccount)) - .setDatabaseUrl(DATABASE_URL) - .build(); - FirebaseApp.initializeApp(options); - // [END initialize] - } catch (FileNotFoundException e) { - System.out.println("ERROR: invalid service account credentials. See README."); - System.out.println(e.getMessage()); - - System.exit(1); - } - - // Shared Database reference - database = FirebaseDatabase.getInstance().getReference(); - - // Start listening to the Database - startListeners(); - - // Kick off weekly email task - startWeeklyTopPostEmailer(); - } - -} diff --git a/database/src/main/java/com/google/firebase/quickstart/email/MyEmailer.java b/database/src/main/java/com/google/firebase/quickstart/email/MyEmailer.java deleted file mode 100644 index a3686c3..0000000 --- a/database/src/main/java/com/google/firebase/quickstart/email/MyEmailer.java +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright Google Inc. All Rights Reserved. - * - * 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.quickstart.email; - -import com.google.firebase.database.DatabaseReference; -import com.google.firebase.database.FirebaseDatabase; -import com.google.firebase.database.ServerValue; -import com.google.firebase.quickstart.model.Post; -import com.google.firebase.quickstart.model.User; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Class to send email notifications from the server. - */ -public class MyEmailer { - - public static void sendNotificationEmail(String email, String uid, String postId) { - // TODO(developer): send email to user notifying them that one of their posts got a new star - System.out.println("sendNotificationEmail: MOCK IMPLEMENTATION"); - System.out.println("sendNotificationEmail: " + email); - - // Save the date of the last notification sent - // [START write_fan_out] - Map update = new HashMap(); - update.put("/posts/" + postId + "/lastNotificationTimestamp", ServerValue.TIMESTAMP); - update.put("/user-posts/" + uid + "/" + postId + "/lastNotificationTimestamp", ServerValue.TIMESTAMP); - - FirebaseDatabase.getInstance().getReference().updateChildren(update); - // [END write_fan_out] - } - - public static void sendWeeklyEmail(Map users, List topPosts) { - // TODO(developer): send email to each user notifying them about the current top posts - System.out.println("sendWeeklyEmail: MOCK IMPLEMENTATION"); - System.out.println("sendWeeklyEmail: there are " + users.size() + " total users."); - System.out.println("sendWeeklyEmail: the top post is " + topPosts.get(0).title + " by " + topPosts.get(0).author); - - for (String userId : users.keySet()) { - // Mark the last time the weekly email was sent out - // [START basic_write] - DatabaseReference userRef = FirebaseDatabase.getInstance().getReference() - .child("users").child(userId).child("lastSentWeeklyTimestamp"); - userRef.setValue(ServerValue.TIMESTAMP); - // [END basic_write] - } - } - -} diff --git a/database/src/main/java/com/google/firebase/quickstart/email/WeeklyEmailJob.java b/database/src/main/java/com/google/firebase/quickstart/email/WeeklyEmailJob.java deleted file mode 100644 index 40e063c..0000000 --- a/database/src/main/java/com/google/firebase/quickstart/email/WeeklyEmailJob.java +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright Google Inc. All Rights Reserved. - * - * 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.quickstart.email; - -import com.google.firebase.database.*; -import com.google.firebase.quickstart.model.Post; -import com.google.firebase.quickstart.model.User; -import org.knowm.sundial.Job; -import org.knowm.sundial.annotations.CronTrigger; -import org.knowm.sundial.exceptions.JobInterruptException; - -import java.util.List; -import java.util.Map; - -/** - * Cron job to send weekly emails (Sundays at 2:30pm) - */ -@CronTrigger(cron = "0 30 14 ? * SUN *") -public class WeeklyEmailJob extends Job { - - public void doRun() throws JobInterruptException { - DatabaseReference ref = FirebaseDatabase.getInstance().getReference(); - - // Top 5 Posts in the database, ordered by stars - // [START top_posts_query] - Query topPostsQuery = ref.child("posts").orderByChild("starCount").limitToLast(5); - // [END top_posts_query] - - // All Users - final DatabaseReference allUsersRef = ref.child("users"); - - topPostsQuery.addListenerForSingleValueEvent(new ValueEventListener() { - public void onDataChange(final DataSnapshot topPostsSnapshot) { - allUsersRef.addListenerForSingleValueEvent(new ValueEventListener() { - public void onDataChange(DataSnapshot allUsersSnapshot) { - // Get users and posts as lists - Map users = allUsersSnapshot.getValue(new GenericTypeIndicator>() {}); - List posts = topPostsSnapshot.getValue(new GenericTypeIndicator>() {}); - - // Send email to all users about the top 5 posts - MyEmailer.sendWeeklyEmail(users, posts); - } - - public void onCancelled(DatabaseError databaseError) { - System.out.println("WeeklyEmailJob: could not get all users"); - System.out.println("WeeklyEmailJob: " + databaseError.getMessage()); - } - }); - } - - public void onCancelled(DatabaseError databaseError) { - System.out.println("WeeklyEmailJob: could not get top posts"); - System.out.println("WeeklyEmailJob: " + databaseError.getMessage()); - } - }); - } - -} diff --git a/database/src/main/java/com/google/firebase/quickstart/model/Post.java b/database/src/main/java/com/google/firebase/quickstart/model/Post.java deleted file mode 100644 index f0362b1..0000000 --- a/database/src/main/java/com/google/firebase/quickstart/model/Post.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright Google Inc. All Rights Reserved. - * - * 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.quickstart.model; - -import com.google.firebase.database.IgnoreExtraProperties; - -import java.util.HashMap; -import java.util.Map; - -/** - * POJO class representing a Post stored in the Firebase Database. - */ -// [START post_class] -@IgnoreExtraProperties -public class Post { - - public String uid; - public String author; - public String title; - public String body; - public int starCount = 0; - public Map stars = new HashMap(); - - public Post() { - // Default constructor required for calls to DataSnapshot.getValue(Post.class) - } - - public Post(String uid, String author, String title, String body) { - this.uid = uid; - this.author = author; - this.title = title; - this.body = body; - } -} -// [END post_class] diff --git a/database/src/main/java/com/google/firebase/quickstart/model/User.java b/database/src/main/java/com/google/firebase/quickstart/model/User.java deleted file mode 100644 index 4c037b3..0000000 --- a/database/src/main/java/com/google/firebase/quickstart/model/User.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright Google Inc. All Rights Reserved. - * - * 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.quickstart.model; - -import com.google.firebase.database.IgnoreExtraProperties; - -/** - * POJO representing a User stored in the Firebase Database. - */ -// [START user_class] -@IgnoreExtraProperties -public class User { - - public String username; - public String email; - - public User() { - // Default constructor required for calls to DataSnapshot.getValue(User.class) - } - - public User(String username, String email) { - this.username = username; - this.email = email; - } - -} -// [END user_class] \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index b4f86c8..5c2d1cf 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5e34c6e..394ea66 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Jun 05 12:42:45 PDT 2017 +#Fri Nov 08 13:53:56 PST 2019 +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 4453cce..83f2acf 100755 --- a/gradlew +++ b/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# 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 +# +# https://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. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,16 +44,16 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -109,8 +125,8 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` @@ -155,7 +171,7 @@ if $cygwin ; then fi # Escape application args -save ( ) { +save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } diff --git a/gradlew.bat b/gradlew.bat index e95643d..24467a1 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/messaging/.gitignore b/messaging/.gitignore new file mode 100644 index 0000000..fe6109d --- /dev/null +++ b/messaging/.gitignore @@ -0,0 +1 @@ +service-account.json \ No newline at end of file diff --git a/messaging/README.md b/messaging/README.md new file mode 100644 index 0000000..747c160 --- /dev/null +++ b/messaging/README.md @@ -0,0 +1,99 @@ +Firebase Cloud Messaging Java Quickstart +======================================== + +The Firebase Cloud Messaging Java quickstart app demonstrates sending +notification messages to a topic. All clients subscribed to the topic +will receive the message. + +Introduction +------------ + +This is a simple example of using Firebase Cloud Messaging REST API to send +the same message to different platforms. To learn more about how you can use +Firebase Cloud Messaging REST API in your app, see [About Cloud Messaging Server](https://firebase.google.com/docs/cloud-messaging/server/). + +Getting started +--------------- + +1. Create a service account as described in [Adding Firebase to your Server](https://firebase.google.com/docs/admin/setup) and download the JSON file. + - Copy the json file to this folder and rename it to `service-account.json`. +2. Change the build.gradle file under messaging/, to replace '[YOUR_SERVICE_ACCOUNT_JSON_DIR]' to the directory of `service-account.json`. + +Run +--- +- This sample allows you to send two types of messages: + + 1. A message that uses the common `notification` object of the API. It is used to define + the `title` and `body` of a notification message (display message). To send this message, from the + `messaging` directory run: + + ./gradlew run -Pmessage=common-message + + 2. A message that uses the common `notification` object of the API as well as tha `android` and + `apns` objects to customize the messages received on the corresponding platforms. To send this + message, from the `messaging` directory run: + + ./gradlew run -Pmessage=override-message + +- Any client devices that you have subscribed to the news topic should receive + a notification message. + + 1. When you use the `common-message` option, clients receive a simple notification message + with only title and body defined. + + 2. When you use the `override-message` option, clients receive a simple notification message + with title and body defined. In addition: + - iOS devices would receive high priority messages and if the app is in the background then a + badge will be applied to the app's icon. + + - Android devices would receive a message with a `click_action`. In this case it is set + to the default intent, but this could be customized to any intent available in your app. + +Best practices +-------------- +This section provides some additional information about how the FCM payloads can +be used to target different platforms. + +### Common payloads ### + +In many cases you may want to send the same message to multiple platforms. If +this is a notification message (display notification) then you can use the +common payloads. These are payloads that are automatically translated to their +platform equivalent payloads. + +### Platform customizations ### + +In cases where you would like to customize the message for the different platforms +that will receive the message, use the platform specific objects to add or override +anything set by the common fields. + +For example, if you want to send a notification message (display notification) to all platforms +but you would like to include accompanying data to Android clients receiving the +message, then you can use the `android` object to define a `data` payload that will +be appended to the notification message when sent to Android clients. + +Support +------- + +- [Stack Overflow](https://stackoverflow.com/questions/tagged/firebase-cloud-messaging) +- [Firebase Support](https://firebase.google.com/support/) + +License +------- + +Copyright 2016 Google, Inc. + +Licensed to the Apache Software Foundation (ASF) under one or more contributor +license agreements. See the NOTICE file distributed with this work for +additional information regarding copyright ownership. The ASF licenses this +file to you 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. diff --git a/messaging/build.gradle b/messaging/build.gradle new file mode 100644 index 0000000..6819f40 --- /dev/null +++ b/messaging/build.gradle @@ -0,0 +1,34 @@ +group 'com.google.firebase.quickstart' +version '1.0' + +apply plugin: 'java' + +apply plugin: 'application' +mainClassName = 'com.google.firebase.quickstart.Messaging' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +run.doFirst { environment 'GOOGLE_APPLICATION_CREDENTIALS', '[YOUR_SERVICE_ACCOUNT_JSON_DIR]' } + +run { + if (project.hasProperty("message")) { + args = args << "${message}" + } + standardInput = System.in +} + +dependencies { + testCompile group: 'junit', name: 'junit', version: '4.12' + + compile 'com.google.auth:google-auth-library-oauth2-http:0.26.0' + compile 'com.google.code.gson:gson:2.8.7' +} + +dependencies { + implementation 'com.google.firebase:firebase-admin:9.1.1' +} + diff --git a/messaging/gradle/wrapper/gradle-wrapper.jar b/messaging/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..cc4fdc2 Binary files /dev/null and b/messaging/gradle/wrapper/gradle-wrapper.jar differ diff --git a/database/gradle/wrapper/gradle-wrapper.properties b/messaging/gradle/wrapper/gradle-wrapper.properties similarity index 69% rename from database/gradle/wrapper/gradle-wrapper.properties rename to messaging/gradle/wrapper/gradle-wrapper.properties index dd26f2e..1f303be 100644 --- a/database/gradle/wrapper/gradle-wrapper.properties +++ b/messaging/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Tue Jun 07 10:22:44 PDT 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-all.zip +zipStorePath=wrapper/dists \ No newline at end of file diff --git a/database/gradlew b/messaging/gradlew similarity index 64% rename from database/gradlew rename to messaging/gradlew index 9d82f78..2fe81a7 100755 --- a/database/gradlew +++ b/messaging/gradlew @@ -1,4 +1,20 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# 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 +# +# https://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. +# ############################################################################## ## @@ -6,20 +22,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +64,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,26 +75,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -85,7 +105,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -105,8 +125,8 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` @@ -134,27 +154,30 @@ if $cygwin ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/database/gradlew.bat b/messaging/gradlew.bat similarity index 71% rename from database/gradlew.bat rename to messaging/gradlew.bat index aec9973..24467a1 100644 --- a/database/gradlew.bat +++ b/messaging/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -8,14 +24,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +62,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +75,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/messaging/settings.gradle b/messaging/settings.gradle new file mode 100644 index 0000000..0ed74f1 --- /dev/null +++ b/messaging/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'quickstart' + diff --git a/messaging/src/main/java/com/google/firebase/quickstart/Messaging.java b/messaging/src/main/java/com/google/firebase/quickstart/Messaging.java new file mode 100644 index 0000000..38258a2 --- /dev/null +++ b/messaging/src/main/java/com/google/firebase/quickstart/Messaging.java @@ -0,0 +1,216 @@ +package com.google.firebase.quickstart; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Arrays; +import java.util.Scanner; +import com.google.firebase.messaging.Message; +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.messaging.Aps; +import com.google.firebase.messaging.AndroidConfig; +import com.google.firebase.messaging.ApnsConfig; +import com.google.firebase.messaging.Notification; +import com.google.firebase.messaging.AndroidNotification; +import com.google.firebase.messaging.FirebaseMessagingException; +import com.google.auth.oauth2.GoogleCredentials; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; + +/** + * Firebase Cloud Messaging (FCM) can be used to send messages to clients on iOS, Android and Web. + * + * This sample uses FCM to send two types of messages to clients that are subscribed to the `news` + * topic. One type of message is a simple notification message (display message). The other is + * a notification message (display notification) with platform specific customizations, for example, + * a badge is added to messages that are sent to iOS devices. + */ +public class Messaging { + + private static final String MESSAGING_SCOPE = "https://www.googleapis.com/auth/firebase.messaging"; + private static final String[] SCOPES = { MESSAGING_SCOPE }; + + private static final String TITLE = "FCM Notification"; + private static final String BODY = "Notification from FCM"; + + /** + * Retrieves a valid access token that can be used to authorize requests to the FCM REST + * API. + * This method is not used in the rest of the class: the main method in this class uses + * the default credential in sending a FCM message. However, this method is used to + * demonstrate how to generate an OAuth2 access token using the service account + * credential downloaded from Firebase Console. The access token can be attached to your + * HTTP request to FCM. + * + * @return Access token. + * @throws IOException + */ + // [START retrieve_access_token] + private static String getAccessToken() throws IOException { + GoogleCredentials googleCredentials = GoogleCredentials + .fromStream(new FileInputStream("service-account.json")) + .createScoped(Arrays.asList(SCOPES)); + googleCredentials.refresh(); + return googleCredentials.getAccessToken().getTokenValue(); + } + // [END retrieve_access_token] + + /** + * Sends request message to FCM using HTTP. + * + * @param message The message of the send request. + * @throws FirebaseMessagingException + */ + private static void sendMessage(Message message) throws FirebaseMessagingException { + try { + String response = FirebaseMessaging.getInstance().send(message); + System.out.println("Message sent to Firebase for delivery, response:"); + System.out.println(response); + } catch (FirebaseMessagingException e) { + System.out.println("Unable to send message to Firebase, error code:"); + System.out.println(e.getMessagingErrorCode()); + } + } + + /** + * Sends a message that uses the common FCM fields to send a notification message to all + * platforms. Also platform specific overrides are used to customize how the message is + * received on Android and iOS. + * + * @throws FirebaseMessagingException + */ + private static void sendOverrideMessage() throws FirebaseMessagingException { + Message overrideMessage = buildOverrideMessage(); + System.out.println("FCM request body for override message:"); + prettyPrint(overrideMessage); + sendMessage(overrideMessage); + } + + /** + * Builds the body of an FCM request. This body defines the common notification object + * as well as platform specific customizations using the android and apns objects. + * + * @return Message representation of the FCM request body. + */ + private static Message buildOverrideMessage() { + Message message = buildNotificationMessage() + .setAndroidConfig(buildAndroidOverridePayload()) + .setApnsConfig(buildApnsOverridePayload()) + .build(); + + return message; + } + + /** + * Builds the android config that will customize how a message is received on Android. + * + * @return android config of an FCM request. + */ + private static AndroidConfig buildAndroidOverridePayload() { + AndroidNotification androidNotification = AndroidNotification.builder() + .setClickAction("android.intent.action.MAIN") + .build(); + + AndroidConfig androidConfig = AndroidConfig.builder() + .setNotification(androidNotification) + .build(); + + return androidConfig; + } + + /** + * Builds the apns config that will customize how a message is received on iOS. + * + * @return apns config of an FCM request. + */ + private static ApnsConfig buildApnsOverridePayload() { + Aps aps = Aps.builder() + .setBadge(1) + .build(); + + ApnsConfig apnsConfig = ApnsConfig.builder() + .putHeader("apns-priority", "10") + .setAps(aps) + .build(); + + return apnsConfig; + } + + /** + * Sends notification message to FCM for delivery to registered devices. + * + * @throws FirebaseMessagingException + */ + public static void sendCommonMessage() throws FirebaseMessagingException { + Message notificationMessage = buildNotificationMessage().build(); + System.out.println("FCM request body for message using common notification object:"); + prettyPrint(notificationMessage); + sendMessage(notificationMessage); + } + + /** + * Constructs the body of a notification message request. + * + * @return the builder object of the notification message. + */ + private static Message.Builder buildNotificationMessage() { + Notification notification = Notification.builder() + .setTitle(TITLE) + .setBody(BODY) + .build(); + + Message.Builder message = Message.builder() + .setNotification(notification) + .setTopic("news"); + + return message; + } + + /** + * Pretty-prints an object. + * + * @param object object to pretty print. + */ + private static void prettyPrint(Object object) { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + System.out.println(gson.toJson(object) + "\n"); + } + + /** + * Initializes the enviroment with Firebase default credentials. + */ + public static void initializeWithDefaultCredentials() throws IOException { + // [START initialize_sdk_with_application_default] + FirebaseOptions options = new FirebaseOptions.Builder() + .setCredentials(GoogleCredentials.getApplicationDefault()) + .build(); + + FirebaseApp.initializeApp(options); + // [END initialize_sdk_with_application_default] + } + + public static void main(String[] args) throws IOException, FirebaseMessagingException { + initializeWithDefaultCredentials(); + if (args.length == 1 && args[0].equals("common-message")) { + sendCommonMessage(); + } else if (args.length == 1 && args[0].equals("override-message")) { + sendOverrideMessage(); + } else { + System.err.println("Invalid command. Please use one of the following commands:"); + // To send a simple notification message that is sent to all platforms using the common + // fields. + System.err.println("./gradlew run -Pmessage=common-message"); + // To send a simple notification message to all platforms using the common fields as well as + // applying platform specific overrides. + System.err.println("./gradlew run -Pmessage=override-message"); + } + } + +} diff --git a/settings.gradle b/settings.gradle index 6381c47..cb1b484 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':auth', ':database' +include ':auth', ':database', ':messaging', ':config'