├── .github
    ├── CODEOWNERS
    ├── dependabot.template.yml
    ├── dependabot.yml
    ├── snippet-bot.yml
    ├── tests.sh
    └── workflows
    │   ├── generate_dependabot.yml
    │   ├── gradle-wrapper-validation.yml
    │   ├── lint.yml
    │   └── tests.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── appengine
    ├── README.md
    ├── ktor
    │   ├── .editorconfig
    │   ├── README.md
    │   ├── build.gradle.kts
    │   ├── gradle.properties
    │   ├── gradle
    │   │   └── wrapper
    │   │   │   ├── gradle-wrapper.jar
    │   │   │   └── gradle-wrapper.properties
    │   ├── gradlew
    │   ├── gradlew.bat
    │   ├── settings.gradle.kts
    │   └── src
    │   │   └── main
    │   │       ├── kotlin
    │   │           └── HelloApplication.kt
    │   │       ├── resources
    │   │           ├── application.conf
    │   │           └── logback.xml
    │   │       └── webapp
    │   │           └── WEB-INF
    │   │               ├── appengine-web.xml
    │   │               ├── logging.properties
    │   │               └── web.xml
    └── springboot
    │   ├── .gitignore
    │   ├── .mvn
    │       └── wrapper
    │       │   └── maven-wrapper.properties
    │   ├── README.md
    │   ├── mvnw
    │   ├── mvnw.cmd
    │   ├── pom.xml
    │   └── src
    │       ├── main
    │           ├── kotlin
    │           │   ├── DemoApplication.kt
    │           │   └── MessageController.kt
    │           ├── resources
    │           │   └── application.properties
    │           └── webapp
    │           │   └── WEB-INF
    │           │       └── appengine-web.xml
    │       └── test
    │           └── kotlin
    │               └── DemoApplicationTests.kt
├── firestore
    ├── README.md
    ├── build.gradle.kts
    ├── gradle
    │   └── wrapper
    │   │   ├── gradle-wrapper.jar
    │   │   └── gradle-wrapper.properties
    ├── gradlew
    ├── gradlew.bat
    ├── settings.gradle.kts
    └── src
    │   ├── main
    │       └── kotlin
    │       │   ├── Firestore.kt
    │       │   └── Quickstart.kt
    │   └── test
    │       └── kotlin
    │           └── FirestoreTest.kt
├── functions
    ├── README.md
    ├── build.gradle.kts
    ├── gradle
    │   └── wrapper
    │   │   ├── gradle-wrapper.jar
    │   │   └── gradle-wrapper.properties
    ├── gradlew
    ├── gradlew.bat
    ├── settings.gradle.kts
    └── src
    │   ├── main
    │       └── kotlin
    │       │   ├── EventExample.kt
    │       │   └── HttpExample.kt
    │   └── test
    │       └── kotlin
    │           ├── EventExampleTest.kt
    │           └── HttpExampleTest.kt
├── getting-started
    └── android-with-appengine
    │   ├── .gitignore
    │   ├── README.md
    │   ├── backend
    │       ├── .gitignore
    │       ├── .mvn
    │       │   └── wrapper
    │       │   │   └── maven-wrapper.properties
    │       ├── README.md
    │       ├── mvnw
    │       ├── mvnw.cmd
    │       ├── pom.xml
    │       └── src
    │       │   ├── main
    │       │       ├── kotlin
    │       │       │   └── com
    │       │       │   │   └── google
    │       │       │   │       └── cloud
    │       │       │   │           └── kotlin
    │       │       │   │               └── emojify
    │       │       │   │                   ├── EmojifyApplication.kt
    │       │       │   │                   └── EmojifyController.kt
    │       │       ├── resources
    │       │       │   ├── application.properties
    │       │       │   └── emojis
    │       │       │   │   ├── anger.png
    │       │       │   │   ├── joy.png
    │       │       │   │   ├── none.png
    │       │       │   │   ├── sorrow.png
    │       │       │   │   └── surprise.png
    │       │       └── webapp
    │       │       │   └── WEB-INF
    │       │       │       ├── appengine-web.xml
    │       │       │       └── logging.properties
    │       │   └── test
    │       │       └── kotlin
    │       │           └── com
    │       │               └── google
    │       │                   └── cloud
    │       │                       └── kotlin
    │       │                           └── emojify
    │       │                               └── EmojifyApplicationTests.kt
    │   ├── frontend
    │       ├── README.md
    │       ├── build.gradle.kts
    │       ├── emojify
    │       │   ├── .gitignore
    │       │   ├── build.gradle.kts
    │       │   └── src
    │       │   │   └── main
    │       │   │       ├── AndroidManifest.xml
    │       │   │       ├── assets
    │       │   │           └── application.properties
    │       │   │       ├── kotlin
    │       │   │           └── com
    │       │   │           │   └── google
    │       │   │           │       └── cloud
    │       │   │           │           └── kotlin
    │       │   │           │               └── emojify
    │       │   │           │                   ├── Adapter.kt
    │       │   │           │                   ├── Application.kt
    │       │   │           │                   ├── ImageActivity.kt
    │       │   │           │                   └── MediaLoader.kt
    │       │   │       └── res
    │       │   │           ├── drawable-hdpi
    │       │   │               ├── ic_back_white.png
    │       │   │               ├── ic_camera_white.png
    │       │   │               ├── ic_eye_white.png
    │       │   │               ├── ic_image_white.png
    │       │   │               ├── ic_logo_white.png
    │       │   │               ├── ic_video_white.png
    │       │   │               └── tag_video_white.png
    │       │   │           ├── drawable-xhdpi
    │       │   │               ├── ic_back_white.png
    │       │   │               ├── ic_camera_white.png
    │       │   │               ├── ic_eye_white.png
    │       │   │               ├── ic_image_white.png
    │       │   │               ├── ic_logo_white.png
    │       │   │               └── ic_video_white.png
    │       │   │           ├── drawable-xxhdpi
    │       │   │               ├── ic_back_white.png
    │       │   │               ├── ic_camera_white.png
    │       │   │               ├── ic_eye_white.png
    │       │   │               ├── ic_image_white.png
    │       │   │               ├── ic_logo_white.png
    │       │   │               ├── ic_video_white.png
    │       │   │               └── tag_video_white.png
    │       │   │           ├── drawable-xxxhdpi
    │       │   │               ├── ic_back_white.png
    │       │   │               ├── ic_camera_white.png
    │       │   │               ├── ic_eye_white.png
    │       │   │               ├── ic_image_white.png
    │       │   │               ├── ic_logo_white.png
    │       │   │               ├── ic_video_white.png
    │       │   │               ├── placeholder.jpg
    │       │   │               └── tag_video_white.png
    │       │   │           ├── drawable
    │       │   │               └── ic_geek.xml
    │       │   │           ├── layout
    │       │   │               ├── activity_album.xml
    │       │   │               ├── activity_list_content.xml
    │       │   │               ├── item_content_image.xml
    │       │   │               ├── toolbar.xml
    │       │   │               └── toolbar_scroll.xml
    │       │   │           ├── menu
    │       │   │               ├── menu_album.xml
    │       │   │               └── menu_album_image.xml
    │       │   │           ├── mipmap-hdpi
    │       │   │               ├── ic_launcher.png
    │       │   │               └── ic_launcher_round.png
    │       │   │           ├── mipmap-mdpi
    │       │   │               ├── ic_launcher.png
    │       │   │               └── ic_launcher_round.png
    │       │   │           ├── mipmap-xhdpi
    │       │   │               ├── ic_launcher.png
    │       │   │               └── ic_launcher_round.png
    │       │   │           ├── mipmap-xxhdpi
    │       │   │               ├── ic_launcher.png
    │       │   │               └── ic_launcher_round.png
    │       │   │           ├── mipmap-xxxhdpi
    │       │   │               ├── ic_launcher.png
    │       │   │               └── ic_launcher_round.png
    │       │   │           └── values
    │       │   │               ├── colors.xml
    │       │   │               ├── strings.xml
    │       │   │               └── styles.xml
    │       ├── gradle.properties
    │       ├── gradle
    │       │   └── wrapper
    │       │   │   ├── gradle-wrapper.jar
    │       │   │   └── gradle-wrapper.properties
    │       ├── gradlew
    │       ├── gradlew.bat
    │       └── settings.gradle.kts
    │   └── screenshots
    │       ├── emojified-meetup.jpg
    │       ├── meetup.jpg
    │       ├── placeholder-image-1.png
    │       ├── placeholder-image-2.png
    │       ├── result.png
    │       └── welcome.png
├── pubsub
    ├── README.md
    ├── build.gradle.kts
    ├── gradle
    │   └── wrapper
    │   │   ├── gradle-wrapper.jar
    │   │   └── gradle-wrapper.properties
    ├── gradlew
    ├── gradlew.bat
    ├── settings.gradle.kts
    └── src
    │   ├── main
    │       └── kotlin
    │       │   └── PubSub.kt
    │   └── test
    │       └── kotlin
    │           └── PubSubExampleTest.kt
├── run
    ├── README.md
    ├── grpc-hello-world-bidi-streaming
    │   ├── .editorconfig
    │   ├── .gitignore
    │   ├── Procfile
    │   ├── README.md
    │   ├── app.json
    │   ├── build.gradle.kts
    │   ├── gradle
    │   │   └── wrapper
    │   │   │   ├── gradle-wrapper.jar
    │   │   │   └── gradle-wrapper.properties
    │   ├── gradlew
    │   ├── gradlew.bat
    │   ├── settings.gradle.kts
    │   └── src
    │   │   └── main
    │   │       ├── kotlin
    │   │           └── io
    │   │           │   └── grpc
    │   │           │       └── examples
    │   │           │           └── helloworld
    │   │           │               ├── HelloWorldClient.kt
    │   │           │               └── HelloWorldServer.kt
    │   │       └── proto
    │   │           └── hello_world.proto
    ├── grpc-hello-world-gradle
    │   ├── .editorconfig
    │   ├── .gitignore
    │   ├── Procfile
    │   ├── README.md
    │   ├── build.gradle.kts
    │   ├── gradle
    │   │   └── wrapper
    │   │   │   ├── gradle-wrapper.jar
    │   │   │   └── gradle-wrapper.properties
    │   ├── gradlew
    │   ├── gradlew.bat
    │   ├── settings.gradle.kts
    │   └── src
    │   │   └── main
    │   │       ├── kotlin
    │   │           └── io
    │   │           │   └── grpc
    │   │           │       └── examples
    │   │           │           └── helloworld
    │   │           │               ├── HelloWorldClient.kt
    │   │           │               └── HelloWorldServer.kt
    │   │       └── proto
    │   │           └── hello_world.proto
    ├── grpc-hello-world-mvn
    │   ├── .gitignore
    │   ├── .mvn
    │   │   ├── jvm.config
    │   │   └── wrapper
    │   │   │   └── maven-wrapper.properties
    │   ├── Procfile
    │   ├── README.md
    │   ├── mvnw
    │   ├── mvnw.cmd
    │   ├── pom.xml
    │   └── src
    │   │   └── main
    │   │       ├── kotlin
    │   │           └── io
    │   │           │   └── grpc
    │   │           │       └── examples
    │   │           │           └── helloworld
    │   │           │               ├── HelloWorldClient.kt
    │   │           │               └── HelloWorldServer.kt
    │   │       └── proto
    │   │           └── hello_world.proto
    ├── grpc-hello-world-streaming
    │   ├── .editorconfig
    │   ├── .gitignore
    │   ├── Procfile
    │   ├── README.md
    │   ├── build.gradle.kts
    │   ├── gradle
    │   │   └── wrapper
    │   │   │   ├── gradle-wrapper.jar
    │   │   │   └── gradle-wrapper.properties
    │   ├── gradlew
    │   ├── gradlew.bat
    │   ├── settings.gradle.kts
    │   └── src
    │   │   └── main
    │   │       ├── kotlin
    │   │           └── io
    │   │           │   └── grpc
    │   │           │       └── examples
    │   │           │           └── helloworld
    │   │           │               ├── HelloWorldClient.kt
    │   │           │               └── HelloWorldServer.kt
    │   │       └── proto
    │   │           └── hello_world.proto
    ├── http4k-hello-world
    │   ├── Procfile
    │   ├── README.md
    │   ├── build.gradle.kts
    │   ├── gradle
    │   │   └── wrapper
    │   │   │   ├── gradle-wrapper.jar
    │   │   │   └── gradle-wrapper.properties
    │   ├── gradlew
    │   ├── gradlew.bat
    │   ├── settings.gradle.kts
    │   └── src
    │   │   └── main
    │   │       └── kotlin
    │   │           └── WebApp.kt
    ├── ktor-hello-world
    │   ├── .gitignore
    │   ├── Procfile
    │   ├── README.md
    │   ├── build.gradle.kts
    │   ├── gradle
    │   │   └── wrapper
    │   │   │   ├── gradle-wrapper.jar
    │   │   │   └── gradle-wrapper.properties
    │   ├── gradlew
    │   ├── gradlew.bat
    │   ├── settings.gradle.kts
    │   └── src
    │   │   └── main
    │   │       ├── kotlin
    │   │           └── WebApp.kt
    │   │       └── resources
    │   │           └── logback.xml
    ├── micronaut-hello-world
    │   ├── .gitignore
    │   ├── Procfile
    │   ├── README.md
    │   ├── build.gradle.kts
    │   ├── gradle
    │   │   ├── libs.versions.toml
    │   │   └── wrapper
    │   │   │   ├── gradle-wrapper.jar
    │   │   │   └── gradle-wrapper.properties
    │   ├── gradlew
    │   ├── gradlew.bat
    │   ├── settings.gradle.kts
    │   └── src
    │   │   └── main
    │   │       ├── kotlin
    │   │           └── hello
    │   │           │   └── WebApp.kt
    │   │       └── resources
    │   │           ├── application.properties
    │   │           └── logback.xml
    ├── plain-hello-world
    │   ├── .gitattributes
    │   ├── .gitignore
    │   ├── .mvn
    │   │   └── wrapper
    │   │   │   └── maven-wrapper.properties
    │   ├── README.md
    │   ├── mvnw
    │   ├── mvnw.cmd
    │   ├── pom.xml
    │   └── src
    │   │   └── main
    │   │       └── java
    │   │           └── com
    │   │               └── google
    │   │                   └── WebApp.kt
    ├── quarkus-hello-world
    │   ├── .gitignore
    │   ├── .mvn
    │   │   └── wrapper
    │   │   │   └── maven-wrapper.properties
    │   ├── README.md
    │   ├── mvnw
    │   ├── mvnw.cmd
    │   ├── pom.xml
    │   └── src
    │   │   └── main
    │   │       └── kotlin
    │   │           └── com
    │   │               └── google
    │   │                   └── App.kt
    ├── springboot-cloudsql
    │   ├── .gitignore
    │   ├── README.md
    │   ├── build.gradle.kts
    │   ├── gradle
    │   │   └── wrapper
    │   │   │   ├── gradle-wrapper.jar
    │   │   │   └── gradle-wrapper.properties
    │   ├── gradlew
    │   ├── gradlew.bat
    │   ├── project.toml
    │   ├── settings.gradle.kts
    │   └── src
    │   │   ├── main
    │   │       ├── kotlin
    │   │       │   └── kotlinbars
    │   │       │   │   └── Main.kt
    │   │       └── resources
    │   │       │   ├── application.properties
    │   │       │   └── schema.sql
    │   │   └── test
    │   │       ├── kotlin
    │   │           └── kotlinbars
    │   │           │   └── BarRepoTest.kt
    │   │       └── resources
    │   │           └── application.properties
    └── springboot-hello-world
    │   ├── .gitignore
    │   ├── Procfile
    │   ├── README.md
    │   ├── app.json
    │   ├── build.gradle.kts
    │   ├── gradle
    │       └── wrapper
    │       │   ├── gradle-wrapper.jar
    │       │   └── gradle-wrapper.properties
    │   ├── gradlew
    │   ├── gradlew.bat
    │   ├── project.toml
    │   ├── settings.gradle.kts
    │   └── src
    │       └── main
    │           ├── kotlin
    │               └── DemoApplication.kt
    │           └── resources
    │               └── application.properties
├── storage
    ├── README.md
    ├── build.gradle.kts
    ├── gradle
    │   └── wrapper
    │   │   ├── gradle-wrapper.jar
    │   │   └── gradle-wrapper.properties
    ├── gradlew
    ├── gradlew.bat
    ├── resources
    │   └── upload
    │   │   └── dog.jpg
    ├── settings.gradle.kts
    └── src
    │   ├── main
    │       └── kotlin
    │       │   ├── Quickstart.kt
    │       │   └── Storage.kt
    │   └── test
    │       └── kotlin
    │           ├── QuickstartTest.kt
    │           └── StorageTest.kt
└── vision
    ├── README.md
    ├── build.gradle.kts
    ├── gradle
        └── wrapper
        │   ├── gradle-wrapper.jar
        │   └── gradle-wrapper.properties
    ├── gradlew
    ├── gradlew.bat
    ├── resources
        └── doggo.jpg
    ├── settings.gradle.kts
    └── src
        ├── main
            └── kotlin
            │   └── Quickstart.kt
        └── test
            └── kotlin
                └── QuickstartTest.kt
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Code owners file.
2 | # This file controls who is tagged for review for any given pull request.
3 | #
4 | # For syntax help see:
5 | # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax
6 | 
7 | *     @GoogleCloudPlatform/kotlin-eng
8 | 
--------------------------------------------------------------------------------
/.github/dependabot.template.yml:
--------------------------------------------------------------------------------
 1 | version: 2
 2 | updates:
 3 |   - package-ecosystem: "github-actions"
 4 |     directory: "/"
 5 |     schedule:
 6 |       interval: "weekly"
 7 | 
 8 |   - package-ecosystem: "gradle"
 9 |     directory: "gradlew"
10 |     schedule:
11 |       interval: "weekly"
12 | 
13 |   - package-ecosystem: "maven"
14 |     directory: "pom.xml"
15 |     schedule:
16 |       interval: "weekly"
17 | 
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
 1 | # This file was generated by the "Generate Dependabot Glob" action. Do not edit it directly.
 2 | # Make changes to `.github/dependabot.template.yml` and a PR will be automatically created.
 3 | version: 2
 4 | updates:
 5 |   - package-ecosystem: github-actions
 6 |     directory: /
 7 |     schedule:
 8 |       interval: weekly
 9 |   - package-ecosystem: gradle
10 |     directory: appengine/ktor
11 |     schedule:
12 |       interval: weekly
13 |   - package-ecosystem: gradle
14 |     directory: firestore
15 |     schedule:
16 |       interval: weekly
17 |   - package-ecosystem: gradle
18 |     directory: functions
19 |     schedule:
20 |       interval: weekly
21 |   - package-ecosystem: gradle
22 |     directory: getting-started/android-with-appengine/frontend
23 |     schedule:
24 |       interval: weekly
25 |   - package-ecosystem: gradle
26 |     directory: pubsub
27 |     schedule:
28 |       interval: weekly
29 |   - package-ecosystem: gradle
30 |     directory: run/grpc-hello-world-bidi-streaming
31 |     schedule:
32 |       interval: weekly
33 |   - package-ecosystem: gradle
34 |     directory: run/grpc-hello-world-gradle
35 |     schedule:
36 |       interval: weekly
37 |   - package-ecosystem: gradle
38 |     directory: run/grpc-hello-world-streaming
39 |     schedule:
40 |       interval: weekly
41 |   - package-ecosystem: gradle
42 |     directory: run/http4k-hello-world
43 |     schedule:
44 |       interval: weekly
45 |   - package-ecosystem: gradle
46 |     directory: run/ktor-hello-world
47 |     schedule:
48 |       interval: weekly
49 |   - package-ecosystem: gradle
50 |     directory: run/micronaut-hello-world
51 |     schedule:
52 |       interval: weekly
53 |   - package-ecosystem: gradle
54 |     directory: run/springboot-cloudsql
55 |     schedule:
56 |       interval: weekly
57 |   - package-ecosystem: gradle
58 |     directory: run/springboot-hello-world
59 |     schedule:
60 |       interval: weekly
61 |   - package-ecosystem: gradle
62 |     directory: storage
63 |     schedule:
64 |       interval: weekly
65 |   - package-ecosystem: gradle
66 |     directory: vision
67 |     schedule:
68 |       interval: weekly
69 |   - package-ecosystem: maven
70 |     directory: appengine/springboot
71 |     schedule:
72 |       interval: weekly
73 |   - package-ecosystem: maven
74 |     directory: getting-started/android-with-appengine/backend
75 |     schedule:
76 |       interval: weekly
77 |   - package-ecosystem: maven
78 |     directory: run/grpc-hello-world-mvn
79 |     schedule:
80 |       interval: weekly
81 |   - package-ecosystem: maven
82 |     directory: run/plain-hello-world
83 |     schedule:
84 |       interval: weekly
85 |   - package-ecosystem: maven
86 |     directory: run/quarkus-hello-world
87 |     schedule:
88 |       interval: weekly
89 | 
--------------------------------------------------------------------------------
/.github/snippet-bot.yml:
--------------------------------------------------------------------------------
1 | 
2 | 
--------------------------------------------------------------------------------
/.github/workflows/generate_dependabot.yml:
--------------------------------------------------------------------------------
 1 | on:
 2 |   push:
 3 |   repository_dispatch:
 4 |   workflow_dispatch:
 5 | 
 6 | jobs:
 7 |   generate:
 8 |     runs-on: ubuntu-latest
 9 |     steps:
10 |       - uses: actions/checkout@v4
11 |         
12 |       - name: Generate dependabot.yml
13 |         uses: Makeshift/generate-dependabot-glob-action@master
14 | 
15 |       - name: Create Pull Request
16 |         uses: peter-evans/create-pull-request@v6
17 | 
--------------------------------------------------------------------------------
/.github/workflows/gradle-wrapper-validation.yml:
--------------------------------------------------------------------------------
 1 | name: "Validate Gradle Wrapper"
 2 | on:
 3 |   push:
 4 |     branches:
 5 |       - main
 6 |   pull_request:
 7 | jobs:
 8 |   validation:
 9 |     name: "Validation"
10 |     runs-on: ubuntu-latest
11 |     steps:
12 |       - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
13 |       - uses: gradle/wrapper-validation-action@v2
14 | 
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
 1 | name: Lint
 2 | on:
 3 |   push:
 4 |     branches:
 5 |       - main
 6 |   pull_request:
 7 | jobs:
 8 |   lint:
 9 |     runs-on: ubuntu-latest
10 |     steps:
11 |     - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
12 |     - name: Install ktlint
13 |       run: |
14 |         curl -sSLO https://github.com/shyiko/ktlint/releases/download/0.48.2/ktlint
15 |         mkdir -p "${GITHUB_WORKSPACE}/bin/"
16 |         mv ktlint "${GITHUB_WORKSPACE}/bin/ktlint"
17 |         chmod +x "${GITHUB_WORKSPACE}/bin/ktlint"
18 |     - name: Run ktlint
19 |       run: |
20 |         "${GITHUB_WORKSPACE}/bin/ktlint" "**/*".kt '!**/build/generated/**' --version
21 |         "${GITHUB_WORKSPACE}/bin/ktlint" "**/*".kt '!**/build/generated/**' -l=info
22 | 
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
 1 | name: Unit Tests
 2 | on:
 3 |   push:
 4 |     branches:
 5 |       - main
 6 |   pull_request:
 7 | env:
 8 |   GOOGLE_CLOUD_PROJECT: ${{ secrets.GOOGLE_CLOUD_PROJECT }}
 9 |   GOOGLE_STORAGE_BUCKET: ${{ secrets.GOOGLE_CLOUD_PROJECT }}
10 | jobs:
11 |   sample_directories:
12 |     name: Get sample directories
13 |     runs-on: ubuntu-latest
14 |     steps:
15 |     - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
16 |     - id: set-testdirs
17 |       run: echo "testdirs=[$(for i in $(ls -d */); do echo -n \"${i%%/}\",; done | sed 's/.$//')]" >> "$GITHUB_OUTPUT"
18 |     outputs:
19 |       testdirs: ${{ steps.set-testdirs.outputs.testdirs }}
20 |   unit_tests:
21 |     needs: sample_directories
22 |     strategy:
23 |       matrix:
24 |         sample: ${{ fromJson(needs.sample_directories.outputs.testdirs) }}
25 |     runs-on: ubuntu-latest
26 |     name: ${{ matrix.sample }}
27 |     steps:
28 |     - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
29 |     - uses: actions/setup-java@v4
30 |       with:
31 |         distribution: 'temurin'
32 |         java-version: '17'
33 |     - name: Set Application Default Credentials Environment Variable
34 |       run: echo "GOOGLE_APPLICATION_CREDENTIALS=${HOME}/credentials.json" >> $GITHUB_ENV
35 |     - name: Set Application Default Credentials File
36 |       run: echo ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS_B64 }} | base64 --decode >> $GOOGLE_APPLICATION_CREDENTIALS
37 |     - name: Set config files for android-with-appengine sample
38 |       if: matrix.sample == 'getting-started' && (github.ref == 'refs/heads/main' || github.event.pull_request.head.repo.full_name == github.repository)
39 |       run : |
40 |         echo ${{ secrets.GOOGLE_SERVICES_B64 }} | base64 --decode >> ${GITHUB_WORKSPACE}/getting-started/android-with-appengine/frontend/emojify/google-services.json
41 |         echo "storage.bucket.name = $GOOGLE_CLOUD_PROJECT.appspot.com" >> ${GITHUB_WORKSPACE}/getting-started/android-with-appengine/backend/src/main/resources/application.properties
42 |     - name: Build ${{ matrix.sample }} samples
43 |       run: ./.github/tests.sh ${{ matrix.sample }}
44 | 
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
 1 | build
 2 | out
 3 | test-output
 4 | target/
 5 | classes/
 6 | /var
 7 | test-output/
 8 | temp-testng-customsuite.xml
 9 | /atlassian-ide-plugin.xml
10 | hotspot.log
11 | pom.xml.versionsBackup
12 | .gradle
13 | .idea
14 | *.iml
15 | .DS_Store
16 | *.ipr
17 | *.iws
18 | .gradle/
19 | .classpath
20 | .settings
21 | .project
22 | .externalToolBuilders
23 | *~
24 | 
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
 1 | # Contributor Code of Conduct
 2 | 
 3 | As contributors and maintainers of this project,
 4 | and in the interest of fostering an open and welcoming community,
 5 | we pledge to respect all people who contribute through reporting issues,
 6 | posting feature requests, updating documentation,
 7 | submitting pull requests or patches, and other activities.
 8 | 
 9 | We are committed to making participation in this project
10 | a harassment-free experience for everyone,
11 | regardless of level of experience, gender, gender identity and expression,
12 | sexual orientation, disability, personal appearance,
13 | body size, race, ethnicity, age, religion, or nationality.
14 | 
15 | Examples of unacceptable behavior by participants include:
16 | 
17 | * The use of sexualized language or imagery
18 | * Personal attacks
19 | * Trolling or insulting/derogatory comments
20 | * Public or private harassment
21 | * Publishing other's private information,
22 | such as physical or electronic
23 | addresses, without explicit permission
24 | * Other unethical or unprofessional conduct.
25 | 
26 | Project maintainers have the right and responsibility to remove, edit, or reject
27 | comments, commits, code, wiki edits, issues, and other contributions
28 | that are not aligned to this Code of Conduct.
29 | By adopting this Code of Conduct,
30 | project maintainers commit themselves to fairly and consistently
31 | applying these principles to every aspect of managing this project.
32 | Project maintainers who do not follow or enforce the Code of Conduct
33 | may be permanently removed from the project team.
34 | 
35 | This code of conduct applies both within project spaces and in public spaces
36 | when an individual is representing the project or its community.
37 | 
38 | Instances of abusive, harassing, or otherwise unacceptable behavior
39 | may be reported by opening an issue
40 | or contacting one or more of the project maintainers.
41 | 
42 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0,
43 | available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
44 | 
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
 1 | # How to become a contributor and submit your own code
 2 | 
 3 | ## Contributor License Agreements
 4 | 
 5 | We'd love to accept your patches! Before we can take them, we
 6 | have to jump a couple of legal hurdles.
 7 | 
 8 | Please fill out either the individual or corporate Contributor License Agreement
 9 | (CLA).
10 | 
11 |   * If you are an individual writing original source code and you're sure you
12 |     own the intellectual property, then you'll need to sign an [individual CLA]
13 |     (https://developers.google.com/open-source/cla/individual).
14 |   * If you work for a company that wants to allow you to contribute your work,
15 |     then you'll need to sign a [corporate CLA]
16 |     (https://developers.google.com/open-source/cla/corporate).
17 | 
18 | Follow either of the two links above to access the appropriate CLA and
19 | instructions for how to sign and return it. Once we receive it, we'll be able to
20 | accept your pull requests.
21 | 
22 | ## Contributing A Patch
23 | 
24 | 1. Submit an issue describing your proposed change to the repo in question.
25 | 1. The repo owner will respond to your issue promptly.
26 | 1. If your proposed change is accepted, and you haven't already done so, sign a
27 |    Contributor License Agreement (see details above).
28 | 1. Fork the desired repo, develop and test your code changes.
29 | 1. Ensure that your code adheres to the existing style in the sample to which
30 |    you are contributing.
31 | 1. Ensure that your code has an appropriate set of unit tests which all pass.
32 | 1. Submit a pull request.
33 | 
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
 1 | # Google Cloud Platform Kotlin Samples
 2 | 
 3 | This repository holds samples written in Kotlin that demonstrate the Google
 4 | Cloud Platform.
 5 | 
 6 | ## Index
 7 | 
 8 | |Path|Description|
 9 | |---|---|
10 | |[appengine](appengine)|Basic examples for deploying Kotlin applications to [App Engine for Java 8][appengine].|
11 | |[firestore](firestore)|This sample demonstrates the [Google Cloud Firestore API][firestore-api].|
12 | |[functions](functions)|This sample demonstrates deploying to [Google Cloud Functions][functions].|
13 | |[pubsub](pubsub)|This sample demonstrates the [Google Cloud Pub/Sub API][pubsub-api].|
14 | |[run](run)|Basic examples for deploying Kotlin applications to [Cloud Run][run].|
15 | |[storage](storage)|This sample demonstrates the [Google Cloud Storage API][storage-api].|
16 | |[vision](vision)|This sample demonstrates the [Google Cloud Vision API][vision-api].|
17 | |[emojify](getting-started/android-with-appengine)|Getting started with Server side Kotlin? This app demonstrates an Android frontend written in Kotlin that communicates with a Kotlin backend running on [App Engine for Java 8][appengine].|
18 | 
19 | The samples use the [Google Cloud Client Library for Java][google-cloud-java].
20 | 
21 | ## Contributing changes.
22 | 
23 | Entirely new samples and bug fixes are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute.
24 | 
25 | ## Licensing
26 | 
27 | Code in this repository is licensed under the Apache 2.0. See [LICENSE](LICENSE).
28 | 
29 | [appengine]: https://cloud.google.com/appengine/docs/standard/java/runtime-java8
30 | [storage-api]: https://cloud.google.com/storage/
31 | [vision-api]: https://cloud.google.com/vision/
32 | [pubsub-api]: https://cloud.google.com/pubsub/
33 | [run]: https://cloud.google.com/run/
34 | [firestore-api]: https://cloud.google.com/firestore/
35 | [functions]: https://cloud.google.com/functions/
36 | [google-cloud-java]: https://googlecloudplatform.github.io/google-cloud-java
37 | 
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 | 
3 | To report a security issue, please use [g.co/vulnz](https://g.co/vulnz).
4 | 
5 | The Google Security Team will respond within 5 working days of your report on g.co/vulnz.
6 | 
7 | We use g.co/vulnz for our intake, and do coordination and disclosure here using GitHub Security Advisory to privately discuss and fix the issue.
8 | 
--------------------------------------------------------------------------------
/appengine/README.md:
--------------------------------------------------------------------------------
 1 | Kotlin Samples for App Engine
 2 | =============================
 3 | 
 4 | These sample Kotlin applications demonstrate how to deploy Kotlin backends to [App Engine for Java 8](https://cloud.google.com/appengine/docs/standard/java/runtime-java8).
 5 | 
 6 | |Link|Description|
 7 | |---|---|
 8 | |[Simple Kotlin app - no framework](https://github.com/GoogleCloudPlatform/getting-started-java/tree/master/appengine-standard-java8/kotlin-appengine-standard)|Deploy a basic Kotlin application to App Engine for Java 8. This sample does not use any framework|
 9 | |[Kotlin on Ktor](ktor)|Deploy a Kotlin application built with [Ktor](ktor) to App Engine for Java 8|
10 | |[Kotlin on Spring Boot](springboot)|Deploy a Kotlin application built with [Spring Boot](springboot) to App Engine for Java 8|
11 | |[Kotlin Spark Sample](https://github.com/GoogleCloudPlatform/getting-started-java/tree/master/appengine-standard-java8/kotlin-spark-appengine-standard)|Deploy a Kotlin application built with Spark to App Engine for Java 8|
12 | |[Android app with Kotlin Backend](https://github.com/GoogleCloudPlatform/kotlin-samples/tree/main/getting-started/android-with-appengine)|Sample of a Kotlin Spring Boot backend that runs on App Engine Standard for Java8 and communicates with an Android app written in Kotlin.|
13 | 
--------------------------------------------------------------------------------
/appengine/ktor/.editorconfig:
--------------------------------------------------------------------------------
 1 | root = true
 2 | 
 3 | [*]
 4 | trim_trailing_whitespace = true
 5 | insert_final_newline = true
 6 | charset = utf-8
 7 | indent_style = space
 8 | 
 9 | [{*.sh,gradlew}]
10 | end_of_line = lf
11 | 
12 | [{*.bat,*.cmd}]
13 | end_of_line = crlf
14 | 
15 | [{*.kts,*.kt}]
16 | max_line_length = 100
17 | 
--------------------------------------------------------------------------------
/appengine/ktor/README.md:
--------------------------------------------------------------------------------
 1 | # Ktor on Google App Engine Standard
 2 | 
 3 | To download and run this sample, download the code with the commands below, and
 4 | then follow the steps in the [Community Tutorial][tutorial].
 5 | 
 6 | ```sh
 7 | git clone git@github.com:GoogleCloudPlatform/kotlin-samples
 8 | cd kotlin-samples/appengine/ktor
 9 | ```
10 | 
11 | [tutorial]: https://cloud.google.com/community/tutorials/kotlin-ktor-app-engine-java8
12 | 
--------------------------------------------------------------------------------
/appengine/ktor/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |     kotlin("jvm") version "1.9.23"
 3 |     war
 4 |     id("com.google.cloud.tools.appengine") version "2.4.5"
 5 | }
 6 | 
 7 | repositories {
 8 |     mavenCentral()
 9 | }
10 | 
11 | kotlin {
12 |     jvmToolchain(17)
13 | }
14 | 
15 | dependencies {
16 |     implementation(platform("io.ktor:ktor-bom:2.3.9"))
17 |     implementation("io.ktor:ktor-server-servlet")
18 |     implementation("io.ktor:ktor-server-html-builder")
19 |     implementation("io.ktor:ktor-server-call-logging:2.3.9")
20 |     implementation("io.ktor:ktor-server-default-headers:2.3.9")
21 |     implementation("com.google.cloud:google-cloud-logging-logback:0.131.3-alpha")
22 | 
23 |     runtimeOnly("com.google.appengine:appengine:1.9.98")
24 | }
25 | 
26 | appengine {
27 |     deploy {
28 |         projectId = "GCLOUD_CONFIG"
29 |         version = "GCLOUD_CONFIG"
30 |     }
31 | }
32 | 
--------------------------------------------------------------------------------
/appengine/ktor/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.parallel=true
2 | 
3 | kotlin.code.style=official
4 | 
--------------------------------------------------------------------------------
/appengine/ktor/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/appengine/ktor/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/appengine/ktor/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 | 
--------------------------------------------------------------------------------
/appengine/ktor/settings.gradle.kts:
--------------------------------------------------------------------------------
 1 | rootProject.name = "appengine-ktor"
 2 | 
 3 | pluginManagement {
 4 |     repositories {
 5 |         mavenCentral()
 6 |         gradlePluginPortal()
 7 |     }
 8 |     resolutionStrategy {
 9 |         eachPlugin {
10 |             if (requested.id.id == "com.google.cloud.tools.appengine") {
11 |                 useModule("com.google.cloud.tools:appengine-gradle-plugin:${requested.version}")
12 |             }
13 |         }
14 |     }
15 | }
16 | 
--------------------------------------------------------------------------------
/appengine/ktor/src/main/kotlin/HelloApplication.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2018 Google LLC.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package com.example.demo
18 | 
19 | import io.ktor.server.application.Application
20 | import io.ktor.server.application.call
21 | import io.ktor.server.application.install
22 | import io.ktor.server.html.respondHtml
23 | import io.ktor.server.plugins.callloging.CallLogging
24 | import io.ktor.server.plugins.defaultheaders.DefaultHeaders
25 | import io.ktor.server.routing.get
26 | import io.ktor.server.routing.routing
27 | import kotlinx.html.body
28 | import kotlinx.html.head
29 | import kotlinx.html.p
30 | import kotlinx.html.title
31 | 
32 | // Entry Point of the application as defined in resources/application.conf.
33 | // @see https://ktor.io/servers/configuration.html#hocon-file
34 | fun Application.main() {
35 |     // This adds Date and Server headers to each response, and allows custom additional headers
36 |     install(DefaultHeaders)
37 |     // This uses use the logger to log every call (request/response)
38 |     install(CallLogging)
39 | 
40 |     routing {
41 |         // Here we use a DSL for building HTML on the route "/"
42 |         // @see https://github.com/Kotlin/kotlinx.html
43 |         get("/") {
44 |             call.respondHtml {
45 |                 head {
46 |                     title { +"Ktor on Google App Engine Standard" }
47 |                 }
48 |                 body {
49 |                     p {
50 |                         +"Hello there! This is Ktor running on Google Appengine Standard"
51 |                     }
52 |                 }
53 |             }
54 |         }
55 |         get("/demo") {
56 |             call.respondHtml {
57 |                 head {
58 |                     title { +"Ktor on Google App Engine Standard" }
59 |                 }
60 |                 body {
61 |                     p {
62 |                         +"It's another route!"
63 |                     }
64 |                 }
65 |             }
66 |         }
67 |     }
68 | }
69 | 
--------------------------------------------------------------------------------
/appengine/ktor/src/main/resources/application.conf:
--------------------------------------------------------------------------------
1 | ktor {
2 |     application {
3 |         modules = [ com.example.demo.HelloApplicationKt.main ]
4 |     }
5 | }
6 | 
--------------------------------------------------------------------------------
/appengine/ktor/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
 1 | 
 2 |     
 3 |     
 4 |     
 5 |         
 6 |         
 7 |             INFO
 8 |         
 9 |         application.log 
10 |         WARN 
11 |     
12 |     
13 |         
14 |             %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
15 |         
16 |     
17 | 
18 |     
19 |         
20 |         
21 |         
22 |         
23 |     
24 | 
25 | 
26 | 
--------------------------------------------------------------------------------
/appengine/ktor/src/main/webapp/WEB-INF/appengine-web.xml:
--------------------------------------------------------------------------------
1 | 
2 | 
3 |     true
4 |     java8
5 |     
6 |         
7 |     
8 | 
9 | 
--------------------------------------------------------------------------------
/appengine/ktor/src/main/webapp/WEB-INF/logging.properties:
--------------------------------------------------------------------------------
1 | .level = INFO
2 | 
--------------------------------------------------------------------------------
/appengine/ktor/src/main/webapp/WEB-INF/web.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         KtorServlet
 5 |         KtorServlet
 6 |         io.ktor.server.servlet.ServletApplicationEngine
 7 |         
 8 |         
 9 |             io.ktor.config
10 |             application.conf
11 |         
12 |     
13 |     
14 |         KtorServlet
15 |         /
16 |     
17 | 
18 | 
--------------------------------------------------------------------------------
/appengine/springboot/.gitignore:
--------------------------------------------------------------------------------
1 | /.mvn/wrapper/maven-wrapper.jar
2 | 
--------------------------------------------------------------------------------
/appengine/springboot/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
 1 | # Licensed to the Apache Software Foundation (ASF) under one
 2 | # or more contributor license agreements.  See the NOTICE file
 3 | # distributed with this work for additional information
 4 | # regarding copyright ownership.  The ASF licenses this file
 5 | # to you under the Apache License, Version 2.0 (the
 6 | # "License"); you may not use this file except in compliance
 7 | # with the License.  You may obtain a copy of the License at
 8 | #
 9 | #   http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied.  See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip
18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
19 | 
--------------------------------------------------------------------------------
/appengine/springboot/README.md:
--------------------------------------------------------------------------------
 1 | # Kotlin Spring Boot on App Engine Standard
 2 | 
 3 | To download and run this sample, download the code with the commands below, and
 4 | then follow the steps in the [Community Tutorial][tutorial].
 5 | 
 6 | ```sh
 7 | git clone git@github.com:GoogleCloudPlatform/kotlin-samples
 8 | cd kotlin-samples/appengine/springboot
 9 | ```
10 | 
11 | [tutorial]: https://cloud.google.com/community/tutorials/kotlin-springboot-app-engine-java8
12 | 
--------------------------------------------------------------------------------
/appengine/springboot/src/main/kotlin/DemoApplication.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2018 Google LLC.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package com.example.demo
18 | 
19 | import org.springframework.boot.autoconfigure.SpringBootApplication
20 | import org.springframework.boot.runApplication
21 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer
22 | 
23 | @SpringBootApplication
24 | class DemoApplication : SpringBootServletInitializer()
25 | 
26 | fun main(args: Array) {
27 |     runApplication(*args)
28 | }
29 | 
--------------------------------------------------------------------------------
/appengine/springboot/src/main/kotlin/MessageController.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2018 Google LLC.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package com.example.demo
18 | 
19 | import org.springframework.web.bind.annotation.RequestMapping
20 | import org.springframework.web.bind.annotation.RestController
21 | 
22 | data class Message(val text: String, val priority: String)
23 | 
24 | @RestController
25 | class MessageController {
26 |     @RequestMapping("/message")
27 |     fun message(): Message {
28 |         return Message("Hello from Google Cloud", "High")
29 |     }
30 | }
31 | 
--------------------------------------------------------------------------------
/appengine/springboot/src/main/resources/application.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/appengine/springboot/src/main/resources/application.properties
--------------------------------------------------------------------------------
/appengine/springboot/src/main/webapp/WEB-INF/appengine-web.xml:
--------------------------------------------------------------------------------
1 | 
2 | 
3 |     true
4 |     java8
5 | 
6 | 
--------------------------------------------------------------------------------
/appengine/springboot/src/test/kotlin/DemoApplicationTests.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2018 Google LLC.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package com.example.demo
18 | 
19 | import org.junit.Test
20 | import org.junit.runner.RunWith
21 | import org.springframework.boot.test.context.SpringBootTest
22 | import org.springframework.test.context.junit4.SpringRunner
23 | 
24 | @RunWith(SpringRunner::class)
25 | @SpringBootTest
26 | class DemoApplicationTests {
27 | 
28 |     @Test
29 |     fun contextLoads() {
30 |     }
31 | }
32 | 
--------------------------------------------------------------------------------
/firestore/README.md:
--------------------------------------------------------------------------------
 1 | # Firestore Kotlin Sample
 2 | 
 3 | [![Open in Cloud Shell][shell_img]][shell_link]
 4 | 
 5 | [shell_img]: http://gstatic.com/cloudssh/images/open-btn.svg
 6 | [shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googlecloudplatform/kotlin-samples&page=editor&working_dir=firestore
 7 | 
 8 | ## Description
 9 | 
10 | This simple command-line application demonstrates how invoke the Google [Cloud Firestore API][firestore-api] from a Kotlin application.
11 | 
12 | **Check out the sample code in** [quickstart.kt](src/main/kotlin/quickstart.kt) **and**
13 | [firestore.kt](src/main/kotlin/firestore.kt).
14 | 
15 | ## Quickstart
16 | 
17 | #### Setup
18 | - Configure your project to use [Cloud Firestore](https://console.cloud.google.com/firestore) in Native mode.
19 | - [Enable Cloud Firestore API][enable-firestore-api] inside your Google Cloud project.
20 | - Set up [authentication](https://cloud.google.com/docs/authentication/getting-started).
21 | 
22 | #### Build
23 | - Clone the repository
24 |   ```sh
25 |   git clone https://github.com/GoogleCloudPlatform/kotlin-samples
26 |   cd kotlin-samples/firestore
27 |   ```
28 | - Build the project with Gradle Wrapper:
29 |   ```sh
30 |   # run with "-info" flag to print potential errors
31 |   ./gradlew installDist -info
32 |   ```
33 | You should now have a **'firestore.jar'** file under **build/libs/**
34 | 
35 | #### Running the sample
36 | 
37 | Usage: ```build/install/firestore/bin/firestore YOUR_COLLECTION_NAME [KEY] [VALUE]```
38 | 
39 | * Running with a collection name will print all keys and values in the collection.
40 | * Running with a collection name and key will print the key/value pair.
41 | * Running with a collection name, key, and value will set the key to that value.
42 | 
43 | ## Contributing changes
44 | 
45 | * See [CONTRIBUTING.md](../CONTRIBUTING.md)
46 | 
47 | ## Licensing
48 | 
49 | * See [LICENSE](../LICENSE)
50 | 
51 | [firestore-api]: https://cloud.google.com/firestore
52 | [enable-firestore-api]: https://console.cloud.google.com/flows/enableapi?apiid=firestore.googleapis.com
53 | 
--------------------------------------------------------------------------------
/firestore/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |     application
 3 |     kotlin("jvm") version "1.9.23"
 4 | }
 5 | 
 6 | repositories {
 7 |     mavenCentral()
 8 | }
 9 | 
10 | dependencies {
11 |     implementation(kotlin("reflect"))
12 |     implementation("com.google.cloud:google-cloud-firestore:3.18.0")
13 |     testImplementation("junit:junit:4.13.2")
14 |     testImplementation(kotlin("test"))
15 |     // see: https://github.com/googleapis/sdk-platform-java/pull/1832
16 |     modules {
17 |         module("com.google.guava:listenablefuture") {
18 |             replacedBy("com.google.guava:guava", "listenablefuture is part of guava")
19 |         }
20 |     }
21 | }
22 | 
23 | kotlin {
24 |     jvmToolchain(17)
25 | }
26 | 
27 | application {
28 |     mainClass.set("com.google.firestore.FirestoreKt")
29 | }
30 | 
--------------------------------------------------------------------------------
/firestore/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/firestore/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/firestore/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 | 
--------------------------------------------------------------------------------
/firestore/settings.gradle.kts:
--------------------------------------------------------------------------------
 1 | pluginManagement {
 2 |     repositories {
 3 |         mavenCentral()
 4 |         gradlePluginPortal()
 5 |     }
 6 | }
 7 | 
 8 | rootProject.name = "firestore"
 9 | 
10 | plugins {
11 |     id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
12 | }
13 | 
--------------------------------------------------------------------------------
/firestore/src/main/kotlin/Firestore.kt:
--------------------------------------------------------------------------------
 1 | // Copyright 2018 Google LLC.
 2 | //
 3 | //  Licensed under the Apache License, Version 2.0 (the "License");
 4 | //  you may not use this file except in compliance with the License.
 5 | //  You may obtain a copy of the License at
 6 | //
 7 | //        http://www.apache.org/licenses/LICENSE-2.0
 8 | //
 9 | //  Unless required by applicable law or agreed to in writing, software
10 | //  distributed under the License is distributed on an "AS IS" BASIS,
11 | //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | //  See the License for the specific language governing permissions and
13 | //  limitations under the License.
14 | 
15 | package com.google.firestore
16 | 
17 | import com.google.cloud.firestore.FirestoreOptions
18 | 
19 | fun main(vararg args: String) {
20 |     // validate the arguments
21 |     if (args.isEmpty() || args.size > 3) {
22 |         throw Exception("Usage: java -jar firestore.jar YOUR_COLLECTION_ID [KEY] [VALUE]")
23 |     }
24 | 
25 |     // create the client
26 |     val db = FirestoreOptions.newBuilder()
27 |         .build()
28 |         .service
29 | 
30 |     // create the docRef and data object
31 |     val docRef = db.collection(args[0]).document("samples")
32 |     val data = docRef
33 |         .get() // future
34 |         .get() // snapshot
35 |         .data // MutableMap
36 | 
37 |     // If no arguments are supplied, call the quickstart. Fetch the key value if only one argument is supplied.
38 |     // Set the key to the supplied value if two arguments are supplied.
39 |     when (args.size) {
40 |         1 -> quickstart(args[0], "samples")
41 |         2 -> println("${args[1]}: ${data?.get(args[1]) ?: "not found"}")
42 |         else -> {
43 |             val future = docRef.update(args[1], args[2])
44 |             println("Updated collection: ${future.get()}")
45 |         }
46 |     }
47 | }
48 | 
--------------------------------------------------------------------------------
/firestore/src/main/kotlin/Quickstart.kt:
--------------------------------------------------------------------------------
 1 | // Copyright 2018 Google LLC.
 2 | //
 3 | //  Licensed under the Apache License, Version 2.0 (the "License");
 4 | //  you may not use this file except in compliance with the License.
 5 | //  You may obtain a copy of the License at
 6 | //
 7 | //        http://www.apache.org/licenses/LICENSE-2.0
 8 | //
 9 | //  Unless required by applicable law or agreed to in writing, software
10 | //  distributed under the License is distributed on an "AS IS" BASIS,
11 | //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | //  See the License for the specific language governing permissions and
13 | //  limitations under the License.
14 | 
15 | package com.google.firestore
16 | 
17 | import com.google.cloud.firestore.FirestoreOptions
18 | 
19 | fun quickstart(collectionName: String, documentName: String) {
20 |     // [START firestore_quickstart]
21 |     // Create the client.
22 |     val db = FirestoreOptions.newBuilder()
23 |         .build()
24 |         .service
25 | 
26 |     // Fetch the document reference and data object.
27 |     val docRef = db.collection(collectionName).document(documentName)
28 |     val data = docRef
29 |         .get() // future
30 |         .get() // snapshot
31 |         .data ?: error("Document $collectionName:$documentName not found") // MutableMap
32 | 
33 |     // Print the retrieved data.
34 |     data.forEach { (key, value) -> println("$key: $value") }
35 |     // [END firestore_quickstart]
36 | }
37 | 
--------------------------------------------------------------------------------
/firestore/src/test/kotlin/FirestoreTest.kt:
--------------------------------------------------------------------------------
 1 | // Copyright 2018 Google LLC.
 2 | //
 3 | //  Licensed under the Apache License, Version 2.0 (the "License");
 4 | //  you may not use this file except in compliance with the License.
 5 | //  You may obtain a copy of the License at
 6 | //
 7 | //        http://www.apache.org/licenses/LICENSE-2.0
 8 | //
 9 | //  Unless required by applicable law or agreed to in writing, software
10 | //  distributed under the License is distributed on an "AS IS" BASIS,
11 | //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | //  See the License for the specific language governing permissions and
13 | //  limitations under the License.
14 | 
15 | package com.google.firestore
16 | 
17 | import org.hamcrest.CoreMatchers.containsString
18 | import org.hamcrest.MatcherAssert.assertThat
19 | import org.junit.After
20 | import org.junit.Assert
21 | import org.junit.Before
22 | import org.junit.Test
23 | import java.io.ByteArrayOutputStream
24 | import java.io.PrintStream
25 | 
26 | internal class FirestoreTest {
27 | 
28 |     private val outContent = ByteArrayOutputStream()
29 |     private val originalOut = System.out!!
30 |     private val collection = "test-collection"
31 | 
32 |     @Before
33 |     fun `setup streams`() {
34 |         System.setOut(PrintStream(outContent))
35 |     }
36 | 
37 |     @After
38 |     fun `restore streams`() {
39 |         System.setOut(originalOut)
40 |     }
41 | 
42 |     @Test
43 |     fun `fetch non-existing`() {
44 |         main(collection, "non-existing")
45 |         Assert.assertEquals("non-existing: not found\n", outContent.toString())
46 |     }
47 | 
48 |     @Test
49 |     fun `set and fetch value`() {
50 |         // Generate a key based on the current time (so it shouldn't exist)
51 |         val key = System.currentTimeMillis().toString()
52 | 
53 |         // ensure key doesn't currently exist
54 |         main(collection, key)
55 |         Assert.assertEquals("$key: not found\n", outContent.toString())
56 | 
57 |         // set the key to "some value"
58 |         main(collection, key, "some value")
59 |         assertThat(outContent.toString(), containsString("Updated collection: "))
60 | 
61 |         // ensure key exists now (and reset the output stream)
62 |         outContent.reset()
63 |         main(collection, key)
64 |         Assert.assertEquals("$key: some value\n", outContent.toString())
65 |     }
66 | 
67 |     @Test(expected = Exception::class)
68 |     fun `too few arguments`() {
69 |         main()
70 |     }
71 | 
72 |     @Test(expected = Exception::class)
73 |     fun `too many arguments`() {
74 |         main("arg1", "arg2", "arg3", "arg4")
75 |     }
76 | }
77 | 
--------------------------------------------------------------------------------
/functions/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | import org.gradle.api.tasks.testing.logging.TestLogEvent.*
 2 | 
 3 | plugins {
 4 |     kotlin("jvm") version "1.9.23"
 5 |     id("com.github.johnrengelman.shadow") version "8.1.1"
 6 | }
 7 | 
 8 | repositories {
 9 |     mavenCentral()
10 | }
11 | 
12 | dependencies {
13 |     implementation("javax.servlet:javax.servlet-api:4.0.1")
14 |     testImplementation("org.mockito:mockito-core:5.+")
15 |     testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.2")
16 |     testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.2")
17 | }
18 | 
19 | kotlin {
20 |     jvmToolchain(17)
21 | }
22 | 
23 | tasks.withType {
24 |     useJUnitPlatform()
25 | 
26 |     testLogging {
27 |         showStandardStreams = true
28 |         exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
29 |         events(STARTED, PASSED, SKIPPED, FAILED)
30 |     }
31 | }
32 | 
33 | 
34 | //application {
35 | //    mainClass.set("WebAppKt")
36 | //}
37 | 
38 | //tasks.replace("assemble").dependsOn("installDist")
39 | 
40 | //tasks.create("stage").dependsOn("installDist")
41 | /*
42 | buildscript {
43 |     ext.kotlin_version = '1.3.20'
44 | 
45 |     repositories {
46 |         jcenter()
47 |     }
48 |     dependencies {
49 |         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
50 |         classpath "com.github.jengelman.gradle.plugins:shadow:5.0.0"
51 |     }
52 | }
53 | 
54 | plugins {
55 |     id 'java'
56 |     id "org.jetbrains.kotlin.jvm" version "1.2.61"
57 | }
58 | 
59 | apply plugin: 'com.github.johnrengelman.shadow'
60 | tasks.build.dependsOn tasks.shadowJar
61 | 
62 | shadowJar {
63 |     mergeServiceFiles()
64 | }
65 | 
66 | dependencies {
67 |     compile "org.jetbrains.kotlin:kotlin-stdlib"
68 |     compile "javax.servlet:javax.servlet-api:3.1.0"
69 |     testCompile 'junit:junit:4.12'
70 |     testImplementation 'org.mockito:mockito-core:5.+'
71 | }
72 | 
73 | sourceSets {
74 |     main.java.srcDirs += 'src/main/kotlin'
75 |     test.java.srcDirs += 'src/test/kotlin'
76 | }
77 | 
78 | repositories {
79 |     mavenCentral()
80 | }
81 | */
82 | 
--------------------------------------------------------------------------------
/functions/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/functions/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/functions/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 | 
--------------------------------------------------------------------------------
/functions/settings.gradle.kts:
--------------------------------------------------------------------------------
 1 | pluginManagement {
 2 |     repositories {
 3 |         mavenCentral()
 4 |         gradlePluginPortal()
 5 |     }
 6 | }
 7 | 
 8 | rootProject.name = "gcloud-functions"
 9 | 
10 | plugins {
11 |     id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
12 | }
13 | 
--------------------------------------------------------------------------------
/functions/src/main/kotlin/EventExample.kt:
--------------------------------------------------------------------------------
 1 | // [START functions_helloworld_pubsub]
 2 | import java.util.Base64
 3 | import java.util.logging.Logger
 4 | 
 5 | class EventExample {
 6 |     companion object {
 7 |         var log: Logger = Logger.getLogger(EventExample::class.java.name)
 8 |     }
 9 | 
10 |     fun helloPubSub(message: PubSubMessage) {
11 |         val data = String(Base64.getDecoder().decode(message.data))
12 |         log.info(data)
13 |     }
14 | }
15 | 
16 | data class PubSubMessage(
17 |     val data: String,
18 |     val messageId: String,
19 |     val publishTime: String,
20 |     val attributes: Map,
21 | )
22 | // [END functions_helloworld_pubsub]
23 | 
--------------------------------------------------------------------------------
/functions/src/main/kotlin/HttpExample.kt:
--------------------------------------------------------------------------------
 1 | import javax.servlet.http.HttpServletRequest
 2 | import javax.servlet.http.HttpServletResponse
 3 | 
 4 | class HttpExample {
 5 |     fun helloWorld(req: HttpServletRequest, resp: HttpServletResponse) {
 6 |         with(resp.writer) {
 7 |             println("Hello World!")
 8 |         }
 9 |     }
10 | }
11 | 
--------------------------------------------------------------------------------
/functions/src/test/kotlin/EventExampleTest.kt:
--------------------------------------------------------------------------------
 1 | // Copyright 2018 Google LLC.
 2 | //
 3 | //  Licensed under the Apache License, Version 2.0 (the "License");
 4 | //  you may not use this file except in compliance with the License.
 5 | //  You may obtain a copy of the License at
 6 | //
 7 | //        http://www.apache.org/licenses/LICENSE-2.0
 8 | //
 9 | //  Unless required by applicable law or agreed to in writing, software
10 | //  distributed under the License is distributed on an "AS IS" BASIS,
11 | //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | //  See the License for the specific language governing permissions and
13 | //  limitations under the License.
14 | 
15 | import org.junit.jupiter.api.Test
16 | import org.mockito.Mockito.mock
17 | import org.mockito.Mockito.times
18 | import org.mockito.Mockito.verify
19 | import java.util.logging.Logger
20 | 
21 | internal class EventExampleTest {
22 | 
23 |     @Test
24 |     fun `pubsub trigger`() {
25 |         val message = PubSubMessage(
26 |             data = "SGVsbG8sIFB1Yi9TdWIh",
27 |             messageId = "",
28 |             publishTime = "",
29 |             attributes = mapOf(),
30 |         )
31 | 
32 |         val log = mock(Logger::class.java)
33 |         EventExample.log = log
34 |         EventExample().helloPubSub(message)
35 | 
36 |         verify(log, times(1)).info("Hello, Pub/Sub!")
37 |     }
38 | }
39 | 
--------------------------------------------------------------------------------
/functions/src/test/kotlin/HttpExampleTest.kt:
--------------------------------------------------------------------------------
 1 | // Copyright 2018 Google LLC.
 2 | //
 3 | //  Licensed under the Apache License, Version 2.0 (the "License");
 4 | //  you may not use this file except in compliance with the License.
 5 | //  You may obtain a copy of the License at
 6 | //
 7 | //        http://www.apache.org/licenses/LICENSE-2.0
 8 | //
 9 | //  Unless required by applicable law or agreed to in writing, software
10 | //  distributed under the License is distributed on an "AS IS" BASIS,
11 | //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | //  See the License for the specific language governing permissions and
13 | //  limitations under the License.
14 | 
15 | import org.junit.jupiter.api.Test
16 | import org.mockito.Mockito.mock
17 | import org.mockito.Mockito.times
18 | import org.mockito.Mockito.verify
19 | import org.mockito.Mockito.`when`
20 | import java.io.PrintWriter
21 | import javax.servlet.http.HttpServletRequest
22 | import javax.servlet.http.HttpServletResponse
23 | 
24 | internal class HttpExampleTest {
25 | 
26 |     @Test
27 |     fun `http trigger`() {
28 |         val req = mock(HttpServletRequest::class.java)
29 |         val res = mock(HttpServletResponse::class.java)
30 |         val writer = mock(PrintWriter::class.java)
31 |         `when`(res.writer).thenReturn(writer)
32 | 
33 |         HttpExample().helloWorld(req, res)
34 | 
35 |         verify(writer, times(1)).println("Hello World!")
36 |     }
37 | }
38 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/.gitignore:
--------------------------------------------------------------------------------
 1 | /target/
 2 | /**/local.properties
 3 | google-services.json
 4 | 
 5 | 
 6 | ### STS ###
 7 | .apt_generated
 8 | .classpath
 9 | .factorypath
10 | .project
11 | .settings
12 | .springBeans
13 | .sts4-cache
14 | 
15 | ### IntelliJ IDEA ###
16 | .idea
17 | *.iws
18 | *.iml
19 | *.ipr
20 | 
21 | ### NetBeans ###
22 | /nbproject/private/
23 | /build/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/README.md:
--------------------------------------------------------------------------------
 1 | Serverless Kotlin: Getting Started App
 2 | ===
 3 | 
 4 | This sample application, called **Emojify**, demonstrates a Kotlin backend which communicates with a mobile frontend. The backend receives an input image from the frontend and overlays an emoji on each of the detected faces in the image based on facial expressions.
 5 | 
 6 | Follow the [Extend an Android frontend with a Kotlin backend running on App Engine](https://g.co/codelabs/emojify) codelab to build and run it yourself!
 7 | 
 8 | Example of source and emojified images:
 9 | 
10 |  
11 | 
12 | Picture taken at [DroidCon NYC Extended](https://dcnyc-extended-2018.splashthat.com/).
13 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/backend/.gitignore:
--------------------------------------------------------------------------------
1 | /.mvn/wrapper/maven-wrapper.jar
2 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/backend/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
 1 | # Licensed to the Apache Software Foundation (ASF) under one
 2 | # or more contributor license agreements.  See the NOTICE file
 3 | # distributed with this work for additional information
 4 | # regarding copyright ownership.  The ASF licenses this file
 5 | # to you under the Apache License, Version 2.0 (the
 6 | # "License"); you may not use this file except in compliance
 7 | # with the License.  You may obtain a copy of the License at
 8 | #
 9 | #   http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied.  See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip
18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
19 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/backend/README.md:
--------------------------------------------------------------------------------
 1 | Emojify Backend
 2 | ===
 3 | 
 4 | ## Sample SpringBoot application written in Kotlin for use with App Engine Java8 Standard.
 5 | This folder contains the source code of Emojify backend. When deployed on App Engine, the backend acts as a cloud endpoint:
 6 | * Input: name of source image in configured bucket (see setup)
 7 | * Output: object of class [EmojifyResponse](src/main/kotlin/com/google/cloud/kotlin/emojify/EmojifyController.kt)
 8 | 
 9 | ## Setup
10 | 
11 | * Download and initialize the [Cloud SDK](https://cloud.google.com/sdk/)
12 | 
13 |     `gcloud init`
14 | 
15 | * Edit value of *storage.bucket.name* in **application.properties** (src/main/resources): `storage.bucket.name = REPLACE_THIS_WITH_YOUR_BUCKET`.
16 | 
17 | ## Maven
18 | ### Running locally
19 | 
20 | `./mvnw package appengine:run`
21 | 
22 | To use visit: http://localhost:8080/
23 | 
24 | ### Deploying to App Engine
25 | 
26 | `./mvnw appengine:deploy`
27 | 
28 | See the [Google App Engine standard environment documentation][ae-docs] for more
29 | detailed instructions.
30 | 
31 | [ae-docs]: https://cloud.google.com/appengine/docs/java/
32 | 
33 | * [Java 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html)
34 | * [Maven](https://maven.apache.org/download.cgi) (at least 3.5)
35 | * [Google Cloud SDK](https://cloud.google.com/sdk/) (aka gcloud command line tool)
36 | 
37 | ## Testing
38 | 
39 | `./mvnw verify`
40 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/backend/src/main/kotlin/com/google/cloud/kotlin/emojify/EmojifyApplication.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2018 Google LLC
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package com.google.cloud.kotlin.emojify
18 | 
19 | import com.google.cloud.storage.Storage
20 | import com.google.cloud.storage.StorageOptions
21 | import com.google.cloud.vision.v1.ImageAnnotatorClient
22 | import org.springframework.boot.autoconfigure.SpringBootApplication
23 | import org.springframework.boot.runApplication
24 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer
25 | import org.springframework.context.annotation.Bean
26 | 
27 | @SpringBootApplication
28 | class EmojifyApplication : SpringBootServletInitializer() {
29 |     @Bean
30 |     fun storage(): Storage = StorageOptions.getDefaultInstance().service
31 | 
32 |     @Bean
33 |     fun vision(): ImageAnnotatorClient = ImageAnnotatorClient.create()
34 | }
35 | 
36 | fun main(args: Array) {
37 |     runApplication(*args)
38 | }
39 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/backend/src/main/resources/application.properties:
--------------------------------------------------------------------------------
 1 | # Copyright 2018 Google LLC
 2 | # Licensed under the Apache License, Version 2.0 (the "License");
 3 | # you may not use this file except in compliance with the License.
 4 | # You may obtain a copy of the License at
 5 | #     http://www.apache.org/licenses/LICENSE-2.0
 6 | # Unless required by applicable law or agreed to in writing, software
 7 | # distributed under the License is distributed on an "AS IS" BASIS,
 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 9 | # See the License for the specific language governing permissions and
10 | # limitations under the License.
11 | 
12 | # Your bucket name must be of the format YOUR_PROJECT_ID.appspot.com for the 
13 | # Emojify frontend to work as expected
14 | storage.bucket.name = YOUR_PROJECT_ID.appspot.com
15 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/backend/src/main/resources/emojis/anger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/backend/src/main/resources/emojis/anger.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/backend/src/main/resources/emojis/joy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/backend/src/main/resources/emojis/joy.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/backend/src/main/resources/emojis/none.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/backend/src/main/resources/emojis/none.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/backend/src/main/resources/emojis/sorrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/backend/src/main/resources/emojis/sorrow.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/backend/src/main/resources/emojis/surprise.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/backend/src/main/resources/emojis/surprise.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/backend/src/main/webapp/WEB-INF/appengine-web.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
14 | 
15 |     true
16 |     java8
17 |     
18 |         
19 |     
20 |     
21 |         1
22 |     
23 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/backend/src/main/webapp/WEB-INF/logging.properties:
--------------------------------------------------------------------------------
 1 | # Copyright 2018 Google LLC
 2 | # Licensed under the Apache License, Version 2.0 (the "License");
 3 | # you may not use this file except in compliance with the License.
 4 | # You may obtain a copy of the License at
 5 | #     http://www.apache.org/licenses/LICENSE-2.0
 6 | # Unless required by applicable law or agreed to in writing, software
 7 | # distributed under the License is distributed on an "AS IS" BASIS,
 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 9 | # See the License for the specific language governing permissions and
10 | # limitations under the License.
11 | 
12 | # A default java.util.logging configuration.
13 | # (All App Engine logging is through java.util.logging by default).
14 | #
15 | # To use this configuration, copy it into your application's WEB-INF
16 | # folder and add the following to your appengine-web.xml:
17 | # 
18 | # 
19 | #   
20 | # 
21 | #
22 | 
23 | # Set the default logging level for all loggers to WARNING
24 | .level = WARNING
25 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/README.md:
--------------------------------------------------------------------------------
 1 | Emojify Frontend
 2 | ===
 3 | 
 4 | ## Description
 5 | 
 6 | Android app written in Kotlin
 7 | 
 8 | * Allows User to select an existing picture or take a new picture
 9 | * Uploads selected image to bucket in Cloud Storage (see Setup for how to configure bucket)
10 | * Makes a url call to Emojify backend (https://YOUR-PROJECT-ID.appspot.com/emojify?objectName=IMAGE_NAME)
11 | * Processes backend response (parses emojified image public url)
12 | * Downloads and draws emojified image
13 | 
14 | A few screenshots:
15 | 
16 |  <
17 |  <
18 | ## Setup
19 | 
20 | This app uses Firebase. You will need to:
21 | * Configure Firebase for your Google Cloud Project. Note that it is **REQUIRED** that your android app and the backend are connected to the same Google Cloud Project and that you deploy the backend first! 
22 | * Connect the app to Firebase ([Android Studio](https://developer.android.com/studio/write/firebase); [Manually](https://firebase.google.com/docs/android/setup#manually_add_firebase)). After this step, you should have your Firebase configuration file (google-services.json) present at `frontend/emojify/`
23 | * Edit value of `cloud.project.id` in `application.properties` (src/main/assets): `cloud.project.id = REPLACE_THIS_WITH_YOUR_PROJECT_ID`
24 | * You're all set!
25 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |     id("com.android.application") version "8.3.0" apply false
 3 |     kotlin("android") version "1.9.23" apply false
 4 | }
 5 | 
 6 | allprojects {
 7 |     repositories {
 8 |         mavenCentral()
 9 |         google()
10 |     }
11 | }
12 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/.gitignore:
--------------------------------------------------------------------------------
1 | /build/
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |     id("com.android.application")
 3 |     kotlin("android")
 4 | }
 5 | 
 6 | kotlin {
 7 |     jvmToolchain(11)
 8 | }
 9 | 
10 | dependencies {
11 |     implementation("androidx.constraintlayout:constraintlayout:2.1.4")
12 |     implementation("com.yanzhenjie:album:2.1.3")
13 |     implementation("com.yanzhenjie:mediascanner:1.0.3")
14 |     implementation("com.google.android.material:material:1.11.0")
15 |     implementation("androidx.appcompat:appcompat:1.6.1")
16 |     implementation("androidx.recyclerview:recyclerview:1.3.2")
17 |     implementation("androidx.cardview:cardview:1.0.0")
18 |     implementation("com.github.bumptech.glide:glide:4.16.0")
19 |     implementation("com.android.volley:volley:1.2.1")
20 |     implementation("com.google.firebase:firebase-core:21.1.1")
21 |     implementation("com.google.firebase:firebase-storage:20.3.0")
22 |     implementation("com.google.firebase:firebase-auth:22.3.1")
23 |     implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
24 | }
25 | 
26 | android {
27 |     compileSdk = 34
28 |     namespace = "com.google.cloud.kotlin.emojify"
29 | 
30 |     defaultConfig {
31 |         minSdk = 28
32 |     }
33 | 
34 |     compileOptions {
35 |         sourceCompatibility = JavaVersion.VERSION_11
36 |         targetCompatibility = JavaVersion.VERSION_11
37 |     }
38 | 
39 |     buildFeatures {
40 |         viewBinding = true
41 |     }
42 | }
43 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
14 | 
15 | 
16 |     
17 |     
18 |     
19 |     
20 |     
21 |     
22 | 
23 |     
31 | 
32 |         
37 |             
38 |                 
39 |                 
40 |             
41 |         
42 |     
43 | 
44 | 
45 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/assets/application.properties:
--------------------------------------------------------------------------------
 1 | # Copyright 2018 Google LLC
 2 | # Licensed under the Apache License, Version 2.0 (the "License");
 3 | # you may not use this file except in compliance with the License.
 4 | # You may obtain a copy of the License at
 5 | #     http://www.apache.org/licenses/LICENSE-2.0
 6 | # Unless required by applicable law or agreed to in writing, software
 7 | # distributed under the License is distributed on an "AS IS" BASIS,
 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 9 | # See the License for the specific language governing permissions and
10 | # limitations under the License.
11 | 
12 | cloud.project.id = REPLACE_THIS_WITH_YOUR_PROJECT_ID
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/kotlin/com/google/cloud/kotlin/emojify/Adapter.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2018 Google LLC
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package com.google.cloud.kotlin.emojify
18 | 
19 | import android.view.LayoutInflater
20 | import android.view.View
21 | import android.view.ViewGroup
22 | import androidx.recyclerview.widget.DiffUtil
23 | import androidx.recyclerview.widget.ListAdapter
24 | import androidx.recyclerview.widget.RecyclerView
25 | import com.google.cloud.kotlin.emojify.databinding.ItemContentImageBinding
26 | import com.yanzhenjie.album.Album
27 | import com.yanzhenjie.album.AlbumFile
28 | 
29 | class AlbumFileDiffCallback : DiffUtil.ItemCallback() {
30 | 
31 |     override fun areItemsTheSame(oldItem: AlbumFile, newItem: AlbumFile): Boolean {
32 |         return oldItem.path == newItem.path
33 |     }
34 | 
35 |     override fun areContentsTheSame(oldItem: AlbumFile, newItem: AlbumFile): Boolean {
36 |         return oldItem == newItem
37 |     }
38 | }
39 | 
40 | class Adapter(private val clickListener: (AlbumFile) -> Unit) : ListAdapter(AlbumFileDiffCallback()) {
41 | 
42 |     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
43 |         val inflater = LayoutInflater.from(parent.context)
44 |         return ViewHolder(inflater.inflate(R.layout.item_content_image, parent, false))
45 |     }
46 | 
47 |     override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(getItem(position), clickListener)
48 | 
49 |     class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
50 |         private lateinit var itemContentImageBinding: ItemContentImageBinding
51 | 
52 |         fun bind(albumFile: AlbumFile, clickListener: (AlbumFile) -> Unit) {
53 |             Album.getAlbumConfig().albumLoader.load(itemContentImageBinding.ivAlbumContentImage, albumFile)
54 |             itemView.setOnClickListener { clickListener(albumFile) }
55 |         }
56 |     }
57 | }
58 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/kotlin/com/google/cloud/kotlin/emojify/Application.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2018 Google LLC
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package com.google.cloud.kotlin.emojify
18 | 
19 | import com.yanzhenjie.album.Album
20 | import com.yanzhenjie.album.AlbumConfig
21 | import java.util.Locale
22 | 
23 | class Application : android.app.Application() {
24 | 
25 |     override fun onCreate() {
26 |         super.onCreate()
27 |         Album.initialize(
28 |             AlbumConfig.newBuilder(this)
29 |                 .setAlbumLoader(MediaLoader())
30 |                 .setLocale(Locale.getDefault())
31 |                 .build(),
32 |         )
33 |     }
34 | }
35 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/kotlin/com/google/cloud/kotlin/emojify/MediaLoader.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2018 Google LLC
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package com.google.cloud.kotlin.emojify
18 | 
19 | import android.widget.ImageView
20 | import com.bumptech.glide.Glide
21 | import com.bumptech.glide.load.engine.DiskCacheStrategy
22 | import com.bumptech.glide.request.RequestOptions
23 | import com.yanzhenjie.album.AlbumFile
24 | import com.yanzhenjie.album.AlbumLoader
25 | 
26 | class MediaLoader : AlbumLoader {
27 | 
28 |     override fun load(imageView: ImageView, albumFile: AlbumFile) {
29 |         load(imageView, albumFile.path)
30 |     }
31 | 
32 |     override fun load(imageView: ImageView, url: String) {
33 |         Glide.with(imageView.context)
34 |             .load(url)
35 |             .apply(
36 |                 RequestOptions()
37 |                     .diskCacheStrategy(DiskCacheStrategy.NONE)
38 |                     .skipMemoryCache(true)
39 |                     .error(R.drawable.placeholder)
40 |                     .placeholder(R.drawable.placeholder),
41 |             )
42 |             .into(imageView)
43 |     }
44 | }
45 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-hdpi/ic_back_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-hdpi/ic_back_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-hdpi/ic_camera_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-hdpi/ic_camera_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-hdpi/ic_eye_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-hdpi/ic_eye_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-hdpi/ic_image_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-hdpi/ic_image_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-hdpi/ic_logo_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-hdpi/ic_logo_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-hdpi/ic_video_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-hdpi/ic_video_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-hdpi/tag_video_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-hdpi/tag_video_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xhdpi/ic_back_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xhdpi/ic_back_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xhdpi/ic_camera_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xhdpi/ic_camera_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xhdpi/ic_eye_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xhdpi/ic_eye_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xhdpi/ic_image_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xhdpi/ic_image_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xhdpi/ic_logo_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xhdpi/ic_logo_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xhdpi/ic_video_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xhdpi/ic_video_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxhdpi/ic_back_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxhdpi/ic_back_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxhdpi/ic_camera_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxhdpi/ic_camera_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxhdpi/ic_eye_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxhdpi/ic_eye_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxhdpi/ic_image_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxhdpi/ic_image_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxhdpi/ic_logo_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxhdpi/ic_logo_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxhdpi/ic_video_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxhdpi/ic_video_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxhdpi/tag_video_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxhdpi/tag_video_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxxhdpi/ic_back_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxxhdpi/ic_back_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxxhdpi/ic_camera_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxxhdpi/ic_camera_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxxhdpi/ic_eye_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxxhdpi/ic_eye_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxxhdpi/ic_image_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxxhdpi/ic_image_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxxhdpi/ic_logo_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxxhdpi/ic_logo_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxxhdpi/ic_video_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxxhdpi/ic_video_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxxhdpi/placeholder.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxxhdpi/placeholder.jpg
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxxhdpi/tag_video_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/drawable-xxxhdpi/tag_video_white.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/layout/activity_album.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
14 | 
16 | 
17 |     
18 | 
19 |     
20 | 
21 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/layout/activity_list_content.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
14 | 
19 | 
20 |     
26 | 
27 |     
33 | 
34 |     
38 | 
39 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/layout/item_content_image.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
14 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/layout/toolbar.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
14 | 
17 | 
18 |     
21 | 
22 | 
23 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/layout/toolbar_scroll.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
14 | 
18 | 
19 |     
23 | 
24 | 
25 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/menu/menu_album.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
14 | 
35 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/menu/menu_album_image.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
14 | 
26 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/emojify/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
14 | 
15 |     #2196F3
16 |     #1E88E5
17 |     #dc572e
18 |     #FF2B2B2B
19 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/emojify/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
14 | 
15 |     Emojify
16 |     +
17 |     Media Album
18 |     Album
19 |     Original image
20 |     Checkable Options
21 |     Canceled
22 |     There is no picture selected!
23 |     Your shiny emojified picture is ready!
24 |     Crossing fingers…
25 |     Something is coming…
26 |     Your shiny emojified picture is ready!
27 |     There was an error calling the backend!
28 |     There was an error with Cloud Storage!
29 |     Image View
30 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/gradle.properties:
--------------------------------------------------------------------------------
 1 | # Project-wide Gradle settings.
 2 | 
 3 | # IDE (e.g. Android Studio) users:
 4 | # Gradle settings configured through the IDE *will override*
 5 | # any settings specified in this file.
 6 | 
 7 | # For more details on how to configure your build environment visit
 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
 9 | 
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | android.enableJetifier=true
13 | android.useAndroidX=true
14 | org.gradle.jvmargs=-Xmx1536m
15 | 
16 | # When configured, Gradle will run in incubating parallel mode.
17 | # This option should only be used with decoupled projects. More details, visit
18 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
19 | # org.gradle.parallel=true
20 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/frontend/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/frontend/settings.gradle.kts:
--------------------------------------------------------------------------------
 1 | pluginManagement {
 2 |     repositories {
 3 |         gradlePluginPortal()
 4 |         google()
 5 |         mavenCentral()
 6 |     }
 7 | }
 8 | 
 9 | plugins {
10 |     id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
11 | }
12 | 
13 | rootProject.name = "android-with-appengine-frontend"
14 | 
15 | include(":emojify")
16 | 
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/screenshots/emojified-meetup.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/screenshots/emojified-meetup.jpg
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/screenshots/meetup.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/screenshots/meetup.jpg
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/screenshots/placeholder-image-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/screenshots/placeholder-image-1.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/screenshots/placeholder-image-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/screenshots/placeholder-image-2.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/screenshots/result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/screenshots/result.png
--------------------------------------------------------------------------------
/getting-started/android-with-appengine/screenshots/welcome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/getting-started/android-with-appengine/screenshots/welcome.png
--------------------------------------------------------------------------------
/pubsub/README.md:
--------------------------------------------------------------------------------
 1 | # Google Cloud Pub/Sub Kotlin Sample
 2 | 
 3 | [![Open in Cloud Shell][shell_img]][shell_link]
 4 | 
 5 | [shell_img]: http://gstatic.com/cloudssh/images/open-btn.svg
 6 | [shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googlecloudplatform/kotlin-samples&page=editor&working_dir=pubsub
 7 | 
 8 | ## Description
 9 | 
10 | [Google Cloud Pub/Sub][pubsub] is a fully-managed real-time messaging service that allows you to send and receive messages between independent applications. This simple Kotlin command-line application demonstrates how to access the Pub/Sub API using
11 | the [Google Cloud Client Library for Java][google-cloud-java].
12 | 
13 | [pubsub]: https://cloud.google.com/pubsub/
14 | [google-cloud-java]: https://github.com/GoogleCloudPlatform/google-cloud-java
15 | 
16 | 
17 | ## Quickstart
18 | 
19 | #### Setup
20 | - [Enable](https://console.cloud.google.com/apis/api/pubsub.googleapis.com/overview) Pub/Sub API.
21 | - Set up [authentication](https://cloud.google.com/docs/authentication/getting-started).
22 | 
23 | #### Build
24 | - Clone the repository
25 |   ```sh
26 |   git clone https://github.com/GoogleCloudPlatform/kotlin-samples
27 |   cd kotlin-samples/pubsub
28 |   ```
29 | - Build the project with Gradle Wrapper:
30 |   ```sh
31 |   # run with "--info" flag to print potential errors
32 |   ./gradlew build --info
33 |   ```
34 | You should now have a **'pubsub-kotlin-sample-all.jar'** file under **build/libs/**
35 | 
36 | #### Create a new topic
37 | 
38 | `java -jar build/libs/pubsub-kotlin-sample-all.jar create `
39 | 
40 | #### Create a subscription
41 | 
42 | `java -jar build/libs/pubsub-kotlin-sample-all.jar sub  `
43 | 
44 | #### Publish messages
45 | 
46 | `java -jar build/libs/pubsub-kotlin-sample-all.jar pub  `
47 | 
48 | #### Receive messages
49 | 
50 | `java -jar build/libs/pubsub-kotlin-sample-all.jar listen `
51 | 
52 | Subscriber will continue to listen on the topic for 5 minutes and print out message id and data as messages are received.
53 | 
54 | #### Delete a topic
55 | 
56 | `java -jar build/libs/pubsub-kotlin-sample-all.jar del-topic `
57 | 
58 | #### Delete a subscription
59 | 
60 | `java -jar build/libs/pubsub-kotlin-sample-all.jar del-sub `
61 | 
62 | #### Testing
63 | Run the test with Gradle Wrapper
64 | 
65 | `./gradlew test`
66 | 
67 | ## Contributing changes
68 | 
69 | * See [CONTRIBUTING.md](../CONTRIBUTING.md)
70 | 
71 | ## Licensing
72 | 
73 | * See [LICENSE](../LICENSE)
74 | 
--------------------------------------------------------------------------------
/pubsub/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | import org.gradle.api.tasks.testing.logging.TestLogEvent.*
 2 | 
 3 | plugins {
 4 |     application
 5 |     kotlin("jvm") version "1.9.23"
 6 |     id("com.github.johnrengelman.shadow") version "8.1.1"
 7 | }
 8 | 
 9 | repositories {
10 |     mavenCentral()
11 | }
12 | 
13 | dependencies {
14 |     implementation(platform("com.google.cloud:libraries-bom:26.34.0"))
15 |     implementation("com.google.cloud:google-cloud-core")
16 |     implementation("com.google.cloud:google-cloud-pubsub")
17 |     implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
18 |     testImplementation("com.google.truth:truth:1.4.2")
19 |     testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
20 |     // see: https://github.com/googleapis/sdk-platform-java/pull/1832
21 |     modules {
22 |         module("com.google.guava:listenablefuture") {
23 |             replacedBy("com.google.guava:guava", "listenablefuture is part of guava")
24 |         }
25 |     }
26 | }
27 | 
28 | kotlin {
29 |     jvmToolchain(17)
30 | }
31 | 
32 | tasks.withType {
33 |     testLogging {
34 |         showStandardStreams = true
35 |         exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
36 |         events(STARTED, PASSED, SKIPPED, FAILED)
37 |     }
38 | }
39 | 
40 | application {
41 |     mainClass.set("pubsubKt")
42 | }
43 | 
--------------------------------------------------------------------------------
/pubsub/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/pubsub/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/pubsub/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 | 
--------------------------------------------------------------------------------
/pubsub/settings.gradle.kts:
--------------------------------------------------------------------------------
 1 | pluginManagement {
 2 |     repositories {
 3 |         mavenCentral()
 4 |         gradlePluginPortal()
 5 |     }
 6 | }
 7 | 
 8 | rootProject.name = "pubsub-kotlin-sample"
 9 | 
10 | plugins {
11 |     id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
12 | }
13 | 
--------------------------------------------------------------------------------
/run/README.md:
--------------------------------------------------------------------------------
 1 | Kotlin Samples for Cloud Run
 2 | ============================
 3 | 
 4 | These sample Kotlin applications demonstrate how to deploy Kotlin to [Google Cloud Run](https://cloud.google.com/run/docs).
 5 | 
 6 | |Link|Description|Deploy|
 7 | |---|---|---|
 8 | |[Plain Kotlin](plain-hello-world)|Deploy a basic HTTP server Cloud Run (uses Maven)|[](https://deploy.cloud.run/?dir=run/plain-hello-world)|
 9 | |[Spring Boot Kotlin](springboot-hello-world)|Deploy a basic Spring Boot service on Cloud Run (uses Gradle)|[](https://deploy.cloud.run/?dir=run/springboot-hello-world)|
10 | |[Ktor Kotlin](ktor-hello-world)|Deploy a basic Ktor service on Cloud Run (uses Gradle)|[](https://deploy.cloud.run/?dir=run/ktor-hello-world)|
11 | |[http4k Kotlin](http4k-hello-world)|Deploy a basic http4k service on Cloud Run (uses Gradle)|[](https://deploy.cloud.run/?dir=run/http4k-hello-world)|
12 | |[Micronaut Kotlin](micronaut-hello-world)|Deploy a basic Micronaut service on Cloud Run (uses Gradle)|[](https://deploy.cloud.run/?dir=run/micronaut-hello-world)|
13 | |[Quarkus Kotlin](quarkus-hello-world)|Deploy a basic Quarkus service on Cloud Run (uses Maven)|[](https://deploy.cloud.run/?dir=run/quarkus-hello-world)|
14 | |[gRPC Kotlin Maven](grpc-hello-world-mvn)|Deploy a unary gRPC service on Cloud Run (uses Maven)|[](https://deploy.cloud.run/?dir=run/grpc-hello-world-mvn)|
15 | |[gRPC Kotlin Gradle](grpc-hello-world-gradle)|Deploy a unary gRPC service on Cloud Run (uses Gradle)|[](https://deploy.cloud.run/?dir=run/grpc-hello-world-gradle)|
16 | |[gRPC Kotlin Streaming](grpc-hello-world-streaming)|Deploy a unary streaming gRPC service on Cloud Run|[](https://deploy.cloud.run/?dir=run/grpc-hello-world-streaming)|
17 | |[gRPC Kotlin Bidi Streaming](grpc-hello-world-bidi-streaming)|Deploy a bidirectional streaming gRPC service on Cloud Run|[](https://deploy.cloud.run/?dir=run/grpc-hello-world-bidi-streaming)|
18 | |[Spring Boot CloudSQL](springboot-cloudsql)|A Spring Boot REST server connected to CloudSQL Postgres using R2DBC|TODO: Button Support|
19 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-bidi-streaming/.editorconfig:
--------------------------------------------------------------------------------
1 | [build/generated/source/proto/main/**]
2 | ktlint = disabled
3 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-bidi-streaming/.gitignore:
--------------------------------------------------------------------------------
1 | /build/
2 | /.idea/
3 | /.gradle/
4 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-bidi-streaming/Procfile:
--------------------------------------------------------------------------------
1 | web: build/install/grpc-hello-world-bidi-streaming/bin/grpc-hello-world-bidi-streaming
2 | client: build/install/grpc-hello-world-streaming/bin/HelloWorldClientKt $HOST
3 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-bidi-streaming/README.md:
--------------------------------------------------------------------------------
 1 | gRPC Kotlin BiDi Streaming Cloud Run Example
 2 | --------------------------------------------
 3 | 
 4 | Run Locally:
 5 | 1. In one shell / terminal window, start the server:
 6 |     ```
 7 |     ./gradlew run
 8 |     ```
 9 | 1. In another shell / terminal window, run the client:
10 |     ```
11 |     ./gradlew HelloWorldClient
12 |     ```
13 | 
14 |    You should continually see: `hello, world`
15 | 
16 | Deploy on Cloud Run:
17 | 
18 | 1. [](https://deploy.cloud.run)
19 | 
20 |     *This will take a few minutes to build and deploy.*
21 | 
22 | 1. From within Cloud Shell, run the client against the service you just deployed on Cloud Run, replacing `YOUR_CLOUD_RUN_DOMAIN_NAME` with your service's domain name and replacing `YOUR_PROJECT_ID` with your GCP project:
23 |    ```
24 |    export PROJECT_ID=YOUR_PROJECT_ID
25 |    docker run -it --entrypoint=/cnb/lifecycle/launcher gcr.io/$PROJECT_ID/grpc-hello-world-bidi-streaming \
26 |    "build/install/grpc-hello-world-bidi-streaming/bin/HelloWorldClientKt YOUR_CLOUD_RUN_DOMAIN_NAME"
27 |    ```
28 | 
29 |    You should continually see output like: `hello, YOUR_CLOUD_RUN_DOMAIN_NAME`
30 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-bidi-streaming/app.json:
--------------------------------------------------------------------------------
1 | {
2 |     "options": {
3 |         "http2": true
4 |     }
5 | }
6 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-bidi-streaming/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |     application
 3 |     kotlin("jvm") version "1.9.23"
 4 |     id("com.google.protobuf") version "0.9.4"
 5 |     id("org.jlleitschuh.gradle.ktlint") version "12.1.0"
 6 | }
 7 | 
 8 | repositories {
 9 |     mavenLocal()
10 |     google()
11 |     mavenCentral()
12 | }
13 | 
14 | java {
15 |     toolchain {
16 |         languageVersion.set(JavaLanguageVersion.of(8))
17 |     }
18 | }
19 | 
20 | kotlin.sourceSets.all {
21 |     languageSettings.optIn("kotlin.RequiresOptIn")
22 | }
23 | 
24 | val grpcVersion = "1.62.2"
25 | val grpcKotlinVersion = "1.4.1"
26 | val protobufVersion = "3.25.3"
27 | val coroutinesVersion = "1.8.0"
28 | 
29 | dependencies {
30 |     implementation(kotlin("stdlib"))
31 |     implementation("javax.annotation:javax.annotation-api:1.3.2")
32 |     implementation("io.grpc:grpc-kotlin-stub:$grpcKotlinVersion")
33 |     implementation("io.grpc:grpc-protobuf:$grpcVersion")
34 |     implementation("com.google.protobuf:protobuf-kotlin:$protobufVersion")
35 |     implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
36 |     runtimeOnly("io.grpc:grpc-netty-shaded:$grpcVersion")
37 | }
38 | 
39 | protobuf {
40 |     protoc {
41 |         artifact = "com.google.protobuf:protoc:$protobufVersion"
42 |     }
43 | 
44 |     plugins {
45 |         create("grpc") {
46 |             artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion"
47 |         }
48 |         create("grpckt") {
49 |             artifact = "io.grpc:protoc-gen-grpc-kotlin:$grpcKotlinVersion:jdk8@jar"
50 |         }
51 |     }
52 | 
53 |     generateProtoTasks {
54 |         all().forEach {
55 |             it.plugins {
56 |                 create("grpc")
57 |                 create("grpckt")
58 |             }
59 |             it.builtins {
60 |                 create("kotlin")
61 |             }
62 |         }
63 |     }
64 | }
65 | 
66 | application {
67 |     mainClass.set("io.grpc.examples.helloworld.HelloWorldServerKt")
68 | }
69 | 
70 | ktlint {
71 |     filter {
72 |         // this doesn't work: https://github.com/JLLeitschuh/ktlint-gradle/issues/746
73 |         exclude("**/generated/**")
74 |     }
75 | }
76 | 
77 | tasks.register("HelloWorldClient") {
78 |     dependsOn("classes")
79 |     classpath = sourceSets["main"].runtimeClasspath
80 |     mainClass.set("io.grpc.examples.helloworld.HelloWorldClientKt")
81 | }
82 | 
83 | val otherStartScripts =
84 |     tasks.register("otherStartScripts") {
85 |         mainClass.set("io.grpc.examples.helloworld.HelloWorldClientKt")
86 |         applicationName = "HelloWorldClientKt"
87 |         outputDir = tasks.named("startScripts").get().outputDir
88 |         classpath = tasks.named("startScripts").get().classpath
89 |     }
90 | 
91 | tasks.named("startScripts") {
92 |     dependsOn(otherStartScripts)
93 | }
94 | 
95 | task("stage").dependsOn("installDist")
96 | 
97 | tasks.replace("assemble").dependsOn(":installDist")
98 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-bidi-streaming/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/run/grpc-hello-world-bidi-streaming/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/run/grpc-hello-world-bidi-streaming/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-bidi-streaming/settings.gradle.kts:
--------------------------------------------------------------------------------
 1 | pluginManagement {
 2 |     repositories {
 3 |         mavenCentral()
 4 |         gradlePluginPortal()
 5 |     }
 6 | }
 7 | 
 8 | rootProject.name = "grpc-hello-world-bidi-streaming"
 9 | 
10 | plugins {
11 |     id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
12 | }
13 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-bidi-streaming/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldClient.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2020 gRPC authors.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package io.grpc.examples.helloworld
18 | 
19 | import io.grpc.ManagedChannel
20 | import io.grpc.ManagedChannelBuilder
21 | import io.grpc.examples.helloworld.GreeterGrpcKt.GreeterCoroutineStub
22 | import kotlinx.coroutines.Dispatchers
23 | import kotlinx.coroutines.asExecutor
24 | import kotlinx.coroutines.coroutineScope
25 | import kotlinx.coroutines.delay
26 | import kotlinx.coroutines.flow.Flow
27 | import kotlinx.coroutines.flow.collect
28 | import kotlinx.coroutines.flow.flow
29 | import kotlinx.coroutines.runBlocking
30 | import java.io.Closeable
31 | import java.util.concurrent.TimeUnit
32 | 
33 | class HelloWorldClient(private val channel: ManagedChannel) : Closeable {
34 |     private val stub: GreeterCoroutineStub = GreeterCoroutineStub(channel)
35 | 
36 |     suspend fun sayHello(producer: Flow): Unit =
37 |         coroutineScope {
38 |             stub.sayHelloStream(producer).collect { helloResponse ->
39 |                 println(helloResponse.message)
40 |             }
41 |         }
42 | 
43 |     override fun close() {
44 |         channel.shutdown().awaitTermination(5, TimeUnit.SECONDS)
45 |     }
46 | }
47 | 
48 | fun main(args: Array) =
49 |     runBlocking {
50 |         val isRemote = args.size == 1
51 | 
52 |         val builder =
53 |             if (isRemote) {
54 |                 ManagedChannelBuilder.forTarget(args[0].removePrefix("https://") + ":443").useTransportSecurity()
55 |             } else {
56 |                 ManagedChannelBuilder.forTarget("localhost:50051").usePlaintext()
57 |             }
58 | 
59 |         val client = HelloWorldClient(builder.executor(Dispatchers.Default.asExecutor()).build())
60 | 
61 |         val user = args.singleOrNull() ?: "world"
62 | 
63 |         val helloFlow =
64 |             flow {
65 |                 while (true) {
66 |                     delay(1000)
67 |                     emit(helloRequest { name = user })
68 |                 }
69 |             }
70 | 
71 |         client.sayHello(helloFlow)
72 |     }
73 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-bidi-streaming/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldServer.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2020 gRPC authors.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package io.grpc.examples.helloworld
18 | 
19 | import io.grpc.Server
20 | import io.grpc.ServerBuilder
21 | import kotlinx.coroutines.flow.Flow
22 | import kotlinx.coroutines.flow.map
23 | 
24 | class HelloWorldServer(private val port: Int) {
25 |     val server: Server =
26 |         ServerBuilder
27 |             .forPort(port)
28 |             .addService(HelloWorldService())
29 |             .build()
30 | 
31 |     fun start() {
32 |         server.start()
33 |         println("Server started, listening on $port")
34 |         val thread =
35 |             Thread {
36 |                 println("*** shutting down gRPC server since JVM is shutting down")
37 |                 stop()
38 |                 println("*** server shut down")
39 |             }
40 |         Runtime.getRuntime().addShutdownHook(thread)
41 |     }
42 | 
43 |     private fun stop() {
44 |         server.shutdown()
45 |     }
46 | 
47 |     fun blockUntilShutdown() {
48 |         server.awaitTermination()
49 |     }
50 | 
51 |     private class HelloWorldService : GreeterGrpcKt.GreeterCoroutineImplBase() {
52 |         override fun sayHelloStream(requests: Flow): Flow {
53 |             return requests.map { request ->
54 |                 println(request)
55 |                 helloReply { message = "hello, ${request.name}" }
56 |             }
57 |         }
58 |     }
59 | }
60 | 
61 | fun main() {
62 |     val port = System.getenv("PORT")?.toInt() ?: 50051
63 |     val server = HelloWorldServer(port)
64 |     server.start()
65 |     server.blockUntilShutdown()
66 | }
67 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-bidi-streaming/src/main/proto/hello_world.proto:
--------------------------------------------------------------------------------
 1 | // Copyright 2015 gRPC authors.
 2 | //
 3 | // Licensed under the Apache License, Version 2.0 (the "License");
 4 | // you may not use this file except in compliance with the License.
 5 | // You may obtain a copy of the License at
 6 | //
 7 | //     http://www.apache.org/licenses/LICENSE-2.0
 8 | //
 9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | 
15 | syntax = "proto3";
16 | 
17 | package io.grpc.examples.helloworld;
18 | 
19 | option java_multiple_files = true;
20 | 
21 | // The greeting service definition.
22 | service Greeter {
23 |   // Continually sends a greeting
24 |   rpc SayHelloStream (stream HelloRequest) returns (stream HelloReply) {}
25 | }
26 | 
27 | // The request message containing the user's name.
28 | message HelloRequest {
29 |   string name = 1;
30 | }
31 | 
32 | // The response message containing the greetings
33 | message HelloReply {
34 |   string message = 1;
35 | }
36 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-gradle/.editorconfig:
--------------------------------------------------------------------------------
1 | [build/generated/source/proto/main/**]
2 | ktlint = disabled
3 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-gradle/.gitignore:
--------------------------------------------------------------------------------
1 | /build/
2 | /.idea/
3 | /.gradle/
4 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-gradle/Procfile:
--------------------------------------------------------------------------------
1 | web: build/install/grpc-hello-world-gradle/bin/grpc-hello-world-gradle
2 | client: build/install/grpc-hello-world-gradle/bin/HelloWorldClientKt $HOST
3 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-gradle/README.md:
--------------------------------------------------------------------------------
 1 | gRPC Kotlin Cloud Run Example
 2 | -----------------------------
 3 | 
 4 | Run Locally:
 5 | 1. In one shell / terminal window, start the server:
 6 |     ```
 7 |     ./gradlew run
 8 |     ```
 9 | 1. In another shell / terminal window, run the client:
10 |     ```
11 |     ./gradlew HelloWorldClient
12 |     ```
13 | 
14 |    You should see output like: `Greeter client received: Hello world`
15 | 
16 | Deploy on Cloud Run:
17 | 
18 | 1. [](https://deploy.cloud.run)
19 | 
20 |     *This will take a few minutes to build and deploy.*
21 | 
22 | 1. From within Cloud Shell, run the client against the service you just deployed on Cloud Run, replacing `YOUR_CLOUD_RUN_DOMAIN_NAME` with your service's domain name and replacing `YOUR_PROJECT_ID` with your GCP project:
23 |     ```
24 |     export PROJECT_ID=YOUR_PROJECT_ID
25 |     docker run -it --entrypoint=/cnb/lifecycle/launcher gcr.io/$PROJECT_ID/grpc-hello-world-gradle \
26 |     "build/install/grpc-hello-world-gradle/bin/HelloWorldClientKt YOUR_CLOUD_RUN_DOMAIN_NAME"
27 |     ```
28 | 
29 |    You should see output like: `Greeter client received: Hello YOUR_CLOUD_RUN_DOMAIN_NAME`
30 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-gradle/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |     application
 3 |     kotlin("jvm") version "1.9.23"
 4 |     id("com.google.protobuf") version "0.9.4"
 5 |     id("org.jlleitschuh.gradle.ktlint") version "12.1.0"
 6 | }
 7 | 
 8 | repositories {
 9 |     google()
10 |     mavenCentral()
11 | }
12 | 
13 | kotlin {
14 |     jvmToolchain(17)
15 | }
16 | 
17 | kotlin.sourceSets.all {
18 |     languageSettings.optIn("kotlin.RequiresOptIn")
19 | }
20 | 
21 | val grpcVersion = "1.62.2"
22 | val grpcKotlinVersion = "1.4.1"
23 | val protobufVersion = "3.25.3"
24 | val coroutinesVersion = "1.8.0"
25 | 
26 | dependencies {
27 |     implementation("javax.annotation:javax.annotation-api:1.3.2")
28 |     implementation("io.grpc:grpc-kotlin-stub:$grpcKotlinVersion")
29 |     implementation("io.grpc:grpc-protobuf:$grpcVersion")
30 |     implementation("com.google.protobuf:protobuf-kotlin:$protobufVersion")
31 |     implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
32 |     runtimeOnly("io.grpc:grpc-netty-shaded:$grpcVersion")
33 | }
34 | 
35 | protobuf {
36 |     protoc {
37 |         artifact = "com.google.protobuf:protoc:$protobufVersion"
38 |     }
39 | 
40 |     plugins {
41 |         create("grpc") {
42 |             artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion"
43 |         }
44 |         create("grpckt") {
45 |             artifact = "io.grpc:protoc-gen-grpc-kotlin:$grpcKotlinVersion:jdk8@jar"
46 |         }
47 |     }
48 | 
49 |     generateProtoTasks {
50 |         all().forEach {
51 |             it.plugins {
52 |                 create("grpc")
53 |                 create("grpckt")
54 |             }
55 |             it.builtins {
56 |                 create("kotlin")
57 |             }
58 |         }
59 |     }
60 | }
61 | 
62 | application {
63 |     mainClass.set("io.grpc.examples.helloworld.HelloWorldServerKt")
64 | }
65 | 
66 | ktlint {
67 |     filter {
68 |         // this doesn't work: https://github.com/JLLeitschuh/ktlint-gradle/issues/746
69 |         exclude("**/generated/**")
70 |     }
71 | }
72 | 
73 | tasks.register("HelloWorldClient") {
74 |     dependsOn("classes")
75 |     javaLauncher.set(javaToolchains.launcherFor(java.toolchain))
76 |     classpath = sourceSets["main"].runtimeClasspath
77 |     mainClass.set("io.grpc.examples.helloworld.HelloWorldClientKt")
78 | }
79 | 
80 | val otherStartScripts =
81 |     tasks.register("otherStartScripts") {
82 |         mainClass.set("io.grpc.examples.helloworld.HelloWorldClientKt")
83 |         applicationName = "HelloWorldClientKt"
84 |         outputDir = tasks.named("startScripts").get().outputDir
85 |         classpath = tasks.named("startScripts").get().classpath
86 |     }
87 | 
88 | tasks.named("startScripts") {
89 |     dependsOn(otherStartScripts)
90 | }
91 | 
92 | task("stage").dependsOn("installDist")
93 | 
94 | tasks.replace("assemble").dependsOn(":installDist")
95 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-gradle/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/run/grpc-hello-world-gradle/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/run/grpc-hello-world-gradle/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-gradle/settings.gradle.kts:
--------------------------------------------------------------------------------
 1 | pluginManagement {
 2 |     repositories {
 3 |         mavenCentral()
 4 |         gradlePluginPortal()
 5 |     }
 6 | }
 7 | 
 8 | rootProject.name = "grpc-hello-world-gradle"
 9 | 
10 | plugins {
11 |     id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
12 | }
13 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-gradle/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldClient.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2020 gRPC authors.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package io.grpc.examples.helloworld
18 | 
19 | import io.grpc.ManagedChannel
20 | import io.grpc.ManagedChannelBuilder
21 | import io.grpc.StatusException
22 | import io.grpc.examples.helloworld.GreeterGrpcKt.GreeterCoroutineStub
23 | import kotlinx.coroutines.asCoroutineDispatcher
24 | import kotlinx.coroutines.asExecutor
25 | import kotlinx.coroutines.runBlocking
26 | import java.io.Closeable
27 | import java.util.concurrent.Executors
28 | import java.util.concurrent.TimeUnit
29 | 
30 | class HelloWorldClient(val channel: ManagedChannel) : Closeable {
31 |     private val stub: GreeterCoroutineStub = GreeterCoroutineStub(channel)
32 | 
33 |     fun greet(s: String) =
34 |         runBlocking {
35 |             val request = helloRequest { name = s }
36 |             try {
37 |                 val response = stub.sayHello(request)
38 |                 println("Greeter client received: ${response.message}")
39 |             } catch (e: StatusException) {
40 |                 println("RPC failed: ${e.status}")
41 |             }
42 |         }
43 | 
44 |     override fun close() {
45 |         channel.shutdown().awaitTermination(5, TimeUnit.SECONDS)
46 |     }
47 | }
48 | 
49 | /**
50 |  * Greeter, uses first argument as name to greet if present;
51 |  * greets "world" otherwise.
52 |  */
53 | fun main(args: Array) {
54 |     val isRemote = args.size == 1
55 | 
56 |     Executors.newFixedThreadPool(10).asCoroutineDispatcher().use { dispatcher ->
57 |         val builder =
58 |             if (isRemote) {
59 |                 ManagedChannelBuilder.forTarget(args[0].removePrefix("https://") + ":443").useTransportSecurity()
60 |             } else {
61 |                 ManagedChannelBuilder.forTarget("localhost:50051").usePlaintext()
62 |             }
63 | 
64 |         val channel = builder.executor(dispatcher.asExecutor()).build()
65 |         HelloWorldClient(channel).use {
66 |             val user = args.singleOrNull() ?: "world"
67 |             it.greet(user)
68 |         }
69 |     }
70 | }
71 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-gradle/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldServer.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2020 gRPC authors.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package io.grpc.examples.helloworld
18 | 
19 | import io.grpc.Server
20 | import io.grpc.ServerBuilder
21 | 
22 | class HelloWorldServer(val port: Int) {
23 |     val server: Server =
24 |         ServerBuilder
25 |             .forPort(port)
26 |             .addService(HelloWorldService())
27 |             .build()
28 | 
29 |     fun start() {
30 |         server.start()
31 |         println("Server started, listening on $port")
32 |         val thread =
33 |             Thread {
34 |                 println("*** shutting down gRPC server since JVM is shutting down")
35 |                 stop()
36 |                 println("*** server shut down")
37 |             }
38 |         Runtime.getRuntime().addShutdownHook(thread)
39 |     }
40 | 
41 |     private fun stop() {
42 |         server.shutdown()
43 |     }
44 | 
45 |     fun blockUntilShutdown() {
46 |         server.awaitTermination()
47 |     }
48 | 
49 |     private class HelloWorldService : GreeterGrpcKt.GreeterCoroutineImplBase() {
50 |         override suspend fun sayHello(request: HelloRequest) =
51 |             helloReply {
52 |                 message = "Hello ${request.name}"
53 |             }
54 |     }
55 | }
56 | 
57 | fun main() {
58 |     val port = System.getenv("PORT")?.toInt() ?: 50051
59 |     val server = HelloWorldServer(port)
60 |     server.start()
61 |     server.blockUntilShutdown()
62 | }
63 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-gradle/src/main/proto/hello_world.proto:
--------------------------------------------------------------------------------
 1 | // Copyright 2015 gRPC authors.
 2 | //
 3 | // Licensed under the Apache License, Version 2.0 (the "License");
 4 | // you may not use this file except in compliance with the License.
 5 | // You may obtain a copy of the License at
 6 | //
 7 | //     http://www.apache.org/licenses/LICENSE-2.0
 8 | //
 9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | 
15 | syntax = "proto3";
16 | 
17 | package io.grpc.examples.helloworld;
18 | 
19 | option java_multiple_files = true;
20 | 
21 | // The greeting service definition.
22 | service Greeter {
23 |   // Sends a greeting
24 |   rpc SayHello (HelloRequest) returns (HelloReply) {}
25 | }
26 | 
27 | // The request message containing the user's name.
28 | message HelloRequest {
29 |   string name = 1;
30 | }
31 | 
32 | // The response message containing the greetings
33 | message HelloReply {
34 |   string message = 1;
35 | }
36 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-mvn/.gitignore:
--------------------------------------------------------------------------------
1 | /build/
2 | /.idea/
3 | /.gradle/
4 | /.mvn/wrapper/maven-wrapper.jar
5 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-mvn/.mvn/jvm.config:
--------------------------------------------------------------------------------
1 | --add-opens java.base/java.lang=ALL-UNNAMED
2 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-mvn/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
 1 | # Licensed to the Apache Software Foundation (ASF) under one
 2 | # or more contributor license agreements.  See the NOTICE file
 3 | # distributed with this work for additional information
 4 | # regarding copyright ownership.  The ASF licenses this file
 5 | # to you under the Apache License, Version 2.0 (the
 6 | # "License"); you may not use this file except in compliance
 7 | # with the License.  You may obtain a copy of the License at
 8 | #
 9 | #   http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied.  See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip
18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
19 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-mvn/Procfile:
--------------------------------------------------------------------------------
1 | web: java $JAVA_OPTS -cp target/classes:target/dependency/* io.grpc.examples.helloworld.HelloWorldServerKt
2 | client: java $JAVA_OPTS -cp target/classes:target/dependency/* io.grpc.examples.helloworld.HelloWorldClientKt $HOST
3 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-mvn/README.md:
--------------------------------------------------------------------------------
 1 | gRPC Kotlin Cloud Run Example
 2 | -----------------------------
 3 | 
 4 | Run Locally:
 5 | 1. In one shell / terminal window, start the server:
 6 |     ```
 7 |     ./mvnw compile exec:java -Dexec.mainClass="io.grpc.examples.helloworld.HelloWorldServerKt"
 8 |     ```
 9 | 1. In another shell / terminal window, run the client:
10 |     ```
11 |     ./mvnw compile exec:java -Dexec.mainClass="io.grpc.examples.helloworld.HelloWorldClientKt"
12 |     ```
13 | 
14 |    You should see output like: `Greeter client received: Hello world`
15 | 
16 | Deploy on Cloud Run:
17 | 
18 | 1. [](https://deploy.cloud.run)
19 | 
20 |     *This will take a few minutes to build and deploy.*
21 | 
22 | 1. From within Cloud Shell, run the client against the service you just deployed on Cloud Run, replacing `YOUR_CLOUD_RUN_DOMAIN_NAME` with your service's domain name and replacing `YOUR_PROJECT_ID` with your GCP project:
23 |    ```
24 |    export PROJECT_ID=YOUR_PROJECT_ID
25 |    docker run -it --entrypoint=/cnb/lifecycle/launcher gcr.io/$PROJECT_ID/grpc-hello-world-mvn \
26 |    "java -cp target/classes:target/dependency/* io.grpc.examples.helloworld.HelloWorldClientKt YOUR_CLOUD_RUN_DOMAIN_NAME"
27 |    ```
28 | 
29 |    You should see output like: `Greeter client received: Hello YOUR_CLOUD_RUN_DOMAIN_NAME`
30 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-mvn/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldClient.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2020 gRPC authors.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package io.grpc.examples.helloworld
18 | 
19 | import io.grpc.ManagedChannel
20 | import io.grpc.ManagedChannelBuilder
21 | import io.grpc.StatusException
22 | import io.grpc.examples.helloworld.GreeterGrpcKt.GreeterCoroutineStub
23 | import kotlinx.coroutines.asCoroutineDispatcher
24 | import kotlinx.coroutines.asExecutor
25 | import kotlinx.coroutines.runBlocking
26 | import java.io.Closeable
27 | import java.util.concurrent.Executors
28 | import java.util.concurrent.TimeUnit
29 | 
30 | class HelloWorldClient(val channel: ManagedChannel) : Closeable {
31 |     private val stub: GreeterCoroutineStub = GreeterCoroutineStub(channel)
32 | 
33 |     fun greet(s: String) = runBlocking {
34 |         val request = helloRequest { name = s }
35 |         try {
36 |             val response = stub.sayHello(request)
37 |             println("Greeter client received: ${response.message}")
38 |         } catch (e: StatusException) {
39 |             println("RPC failed: ${e.status}")
40 |         }
41 |     }
42 | 
43 |     override fun close() {
44 |         channel.shutdown().awaitTermination(5, TimeUnit.SECONDS)
45 |     }
46 | }
47 | 
48 | /**
49 |  * Greeter, uses first argument as name to greet if present;
50 |  * greets "world" otherwise.
51 |  */
52 | fun main(args: Array) {
53 |     val isRemote = args.size == 1
54 | 
55 |     Executors.newFixedThreadPool(10).asCoroutineDispatcher().use { dispatcher ->
56 |         val builder = if (isRemote) {
57 |             ManagedChannelBuilder.forTarget(args[0].removePrefix("https://") + ":443").useTransportSecurity()
58 |         } else {
59 |             ManagedChannelBuilder.forTarget("localhost:50051").usePlaintext()
60 |         }
61 | 
62 |         HelloWorldClient(builder.executor(dispatcher.asExecutor()).build()).use {
63 |             val user = args.singleOrNull() ?: "world"
64 |             it.greet(user)
65 |         }
66 |     }
67 | }
68 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-mvn/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldServer.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2020 gRPC authors.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package io.grpc.examples.helloworld
18 | 
19 | import io.grpc.Server
20 | import io.grpc.ServerBuilder
21 | 
22 | class HelloWorldServer(val port: Int) {
23 |     val server: Server = ServerBuilder
24 |         .forPort(port)
25 |         .addService(HelloWorldService())
26 |         .build()
27 | 
28 |     fun start() {
29 |         server.start()
30 |         println("Server started, listening on $port")
31 |         Runtime.getRuntime().addShutdownHook(
32 |             Thread {
33 |                 println("*** shutting down gRPC server since JVM is shutting down")
34 |                 stop()
35 |                 println("*** server shut down")
36 |             },
37 |         )
38 |     }
39 | 
40 |     private fun stop() {
41 |         server.shutdown()
42 |     }
43 | 
44 |     fun blockUntilShutdown() {
45 |         server.awaitTermination()
46 |     }
47 | 
48 |     private class HelloWorldService : GreeterGrpcKt.GreeterCoroutineImplBase() {
49 |         override suspend fun sayHello(request: HelloRequest) = helloReply {
50 |             message = "Hello ${request.name}"
51 |         }
52 |     }
53 | }
54 | 
55 | fun main() {
56 |     val port = System.getenv("PORT")?.toInt() ?: 50051
57 |     val server = HelloWorldServer(port)
58 |     server.start()
59 |     server.blockUntilShutdown()
60 | }
61 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-mvn/src/main/proto/hello_world.proto:
--------------------------------------------------------------------------------
 1 | // Copyright 2015 gRPC authors.
 2 | //
 3 | // Licensed under the Apache License, Version 2.0 (the "License");
 4 | // you may not use this file except in compliance with the License.
 5 | // You may obtain a copy of the License at
 6 | //
 7 | //     http://www.apache.org/licenses/LICENSE-2.0
 8 | //
 9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | 
15 | syntax = "proto3";
16 | 
17 | package io.grpc.examples.helloworld;
18 | 
19 | option java_multiple_files = true;
20 | 
21 | // The greeting service definition.
22 | service Greeter {
23 |   // Sends a greeting
24 |   rpc SayHello (HelloRequest) returns (HelloReply) {}
25 | }
26 | 
27 | // The request message containing the user's name.
28 | message HelloRequest {
29 |   string name = 1;
30 | }
31 | 
32 | // The response message containing the greetings
33 | message HelloReply {
34 |   string message = 1;
35 | }
36 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-streaming/.editorconfig:
--------------------------------------------------------------------------------
1 | [build/generated/source/proto/main/**]
2 | ktlint = disabled
3 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-streaming/.gitignore:
--------------------------------------------------------------------------------
1 | /build/
2 | /.idea/
3 | /.gradle/
4 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-streaming/Procfile:
--------------------------------------------------------------------------------
1 | web: build/install/grpc-hello-world-streaming/bin/grpc-hello-world-streaming
2 | client: build/install/grpc-hello-world-streaming/bin/HelloWorldClientKt $HOST
3 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-streaming/README.md:
--------------------------------------------------------------------------------
 1 | gRPC Kotlin Server Streaming Cloud Run Example
 2 | ---------------------------------------
 3 | 
 4 | Run Locally:
 5 | 1. In one shell / terminal window, start the server:
 6 |     ```
 7 |     ./gradlew run
 8 |     ```
 9 | 1. In another shell / terminal window, run the client:
10 |     ```
11 |     ./gradlew HelloWorldClient
12 |     ```
13 | 
14 |    You should continually see: `hello, world`
15 | 
16 | Deploy on Cloud Run:
17 | 
18 | 1. [](https://deploy.cloud.run)
19 | 
20 |     *This will take a few minutes to build and deploy.*
21 | 
22 | 1. From within Cloud Shell, run the client against the service you just deployed on Cloud Run, replacing `YOUR_CLOUD_RUN_DOMAIN_NAME` with your service's domain name and replacing `YOUR_PROJECT_ID` with your GCP project:
23 |    ```
24 |    export PROJECT_ID=YOUR_PROJECT_ID
25 |    docker run -it --entrypoint=/cnb/lifecycle/launcher gcr.io/$PROJECT_ID/grpc-hello-world-streaming \
26 |    "build/install/grpc-hello-world-streaming/bin/HelloWorldClientKt YOUR_CLOUD_RUN_DOMAIN_NAME"
27 |    ```
28 | 
29 |    You should continually see output like: `Greeter client received: Hello YOUR_CLOUD_RUN_DOMAIN_NAME`
30 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-streaming/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |     application
 3 |     kotlin("jvm") version "1.9.23"
 4 |     id("com.google.protobuf") version "0.9.4"
 5 |     id("org.jlleitschuh.gradle.ktlint") version "12.1.0"
 6 | }
 7 | 
 8 | repositories {
 9 |     mavenLocal()
10 |     google()
11 |     mavenCentral()
12 | }
13 | 
14 | java {
15 |     toolchain {
16 |         languageVersion.set(JavaLanguageVersion.of(8))
17 |     }
18 | }
19 | 
20 | kotlin.sourceSets.all {
21 |     languageSettings.optIn("kotlin.RequiresOptIn")
22 | }
23 | 
24 | val grpcVersion = "1.62.2"
25 | val grpcKotlinVersion = "1.4.1"
26 | val protobufVersion = "3.25.3"
27 | val coroutinesVersion = "1.8.0"
28 | 
29 | dependencies {
30 |     implementation(kotlin("stdlib"))
31 |     implementation("javax.annotation:javax.annotation-api:1.3.2")
32 |     implementation("io.grpc:grpc-kotlin-stub:$grpcKotlinVersion")
33 |     implementation("io.grpc:grpc-protobuf:$grpcVersion")
34 |     implementation("com.google.protobuf:protobuf-kotlin:$protobufVersion")
35 |     implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
36 |     runtimeOnly("io.grpc:grpc-netty-shaded:$grpcVersion")
37 | }
38 | 
39 | protobuf {
40 |     protoc {
41 |         artifact = "com.google.protobuf:protoc:$protobufVersion"
42 |     }
43 | 
44 |     plugins {
45 |         create("grpc") {
46 |             artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion"
47 |         }
48 |         create("grpckt") {
49 |             artifact = "io.grpc:protoc-gen-grpc-kotlin:$grpcKotlinVersion:jdk8@jar"
50 |         }
51 |     }
52 | 
53 |     generateProtoTasks {
54 |         all().forEach {
55 |             it.plugins {
56 |                 create("grpc")
57 |                 create("grpckt")
58 |             }
59 |             it.builtins {
60 |                 create("kotlin")
61 |             }
62 |         }
63 |     }
64 | }
65 | 
66 | application {
67 |     mainClass.set("io.grpc.examples.helloworld.HelloWorldServerKt")
68 | }
69 | 
70 | ktlint {
71 |     filter {
72 |         // this doesn't work: https://github.com/JLLeitschuh/ktlint-gradle/issues/746
73 |         exclude("**/generated/**")
74 |     }
75 | }
76 | 
77 | tasks.register("HelloWorldClient") {
78 |     dependsOn("classes")
79 |     classpath = sourceSets["main"].runtimeClasspath
80 |     mainClass.set("io.grpc.examples.helloworld.HelloWorldClientKt")
81 | }
82 | 
83 | val otherStartScripts =
84 |     tasks.register("otherStartScripts") {
85 |         mainClass.set("io.grpc.examples.helloworld.HelloWorldClientKt")
86 |         applicationName = "HelloWorldClientKt"
87 |         outputDir = tasks.named("startScripts").get().outputDir
88 |         classpath = tasks.named("startScripts").get().classpath
89 |     }
90 | 
91 | tasks.named("startScripts") {
92 |     dependsOn(otherStartScripts)
93 | }
94 | 
95 | task("stage").dependsOn("installDist")
96 | 
97 | tasks.replace("assemble").dependsOn(":installDist")
98 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-streaming/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/run/grpc-hello-world-streaming/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/run/grpc-hello-world-streaming/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-streaming/settings.gradle.kts:
--------------------------------------------------------------------------------
 1 | pluginManagement {
 2 |     repositories {
 3 |         mavenCentral()
 4 |         gradlePluginPortal()
 5 |     }
 6 | }
 7 | 
 8 | rootProject.name = "grpc-hello-world-streaming"
 9 | 
10 | plugins {
11 |     id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
12 | }
13 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-streaming/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldClient.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2020 gRPC authors.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package io.grpc.examples.helloworld
18 | 
19 | import io.grpc.ManagedChannel
20 | import io.grpc.ManagedChannelBuilder
21 | import io.grpc.examples.helloworld.GreeterGrpcKt.GreeterCoroutineStub
22 | import kotlinx.coroutines.asCoroutineDispatcher
23 | import kotlinx.coroutines.asExecutor
24 | import kotlinx.coroutines.flow.collect
25 | import kotlinx.coroutines.runBlocking
26 | import java.io.Closeable
27 | import java.util.concurrent.Executors
28 | import java.util.concurrent.TimeUnit
29 | 
30 | class HelloWorldClient(val channel: ManagedChannel) : Closeable {
31 |     private val stub: GreeterCoroutineStub = GreeterCoroutineStub(channel)
32 | 
33 |     fun greet(s: String) =
34 |         runBlocking {
35 |             val request = helloRequest { name = s }
36 |             val flow = stub.sayHelloStream(request)
37 |             flow.collect { response ->
38 |                 println(response.message)
39 |             }
40 |         }
41 | 
42 |     override fun close() {
43 |         channel.shutdown().awaitTermination(5, TimeUnit.SECONDS)
44 |     }
45 | }
46 | 
47 | /**
48 |  * Greeter, uses first argument as name to greet if present;
49 |  * greets "world" otherwise.
50 |  */
51 | fun main(args: Array) {
52 |     val isRemote = args.size == 1
53 | 
54 |     Executors.newFixedThreadPool(10).asCoroutineDispatcher().use { dispatcher ->
55 |         val builder =
56 |             if (isRemote) {
57 |                 ManagedChannelBuilder.forTarget(args[0].removePrefix("https://") + ":443").useTransportSecurity()
58 |             } else {
59 |                 ManagedChannelBuilder.forTarget("localhost:50051").usePlaintext()
60 |             }
61 | 
62 |         val channel = builder.executor(dispatcher.asExecutor()).build()
63 |         HelloWorldClient(channel).use {
64 |             val user = args.singleOrNull() ?: "world"
65 |             it.greet(user)
66 |         }
67 |     }
68 | }
69 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-streaming/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldServer.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2020 gRPC authors.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package io.grpc.examples.helloworld
18 | 
19 | import io.grpc.Server
20 | import io.grpc.ServerBuilder
21 | import kotlinx.coroutines.delay
22 | import kotlinx.coroutines.flow.Flow
23 | import kotlinx.coroutines.flow.flow
24 | 
25 | class HelloWorldServer(val port: Int) {
26 |     val server: Server =
27 |         ServerBuilder
28 |             .forPort(port)
29 |             .addService(HelloWorldService())
30 |             .build()
31 | 
32 |     fun start() {
33 |         server.start()
34 |         println("Server started, listening on $port")
35 |         val thread =
36 |             Thread {
37 |                 println("*** shutting down gRPC server since JVM is shutting down")
38 |                 stop()
39 |                 println("*** server shut down")
40 |             }
41 |         Runtime.getRuntime().addShutdownHook(thread)
42 |     }
43 | 
44 |     private fun stop() {
45 |         server.shutdown()
46 |     }
47 | 
48 |     fun blockUntilShutdown() {
49 |         server.awaitTermination()
50 |     }
51 | 
52 |     private class HelloWorldService : GreeterGrpcKt.GreeterCoroutineImplBase() {
53 |         override fun sayHelloStream(request: HelloRequest): Flow =
54 |             flow {
55 |                 while (true) {
56 |                     delay(1000)
57 |                     emit(helloReply { message = "hello, ${request.name}" })
58 |                 }
59 |             }
60 |     }
61 | }
62 | 
63 | fun main() {
64 |     val port = System.getenv("PORT")?.toInt() ?: 50051
65 |     val server = HelloWorldServer(port)
66 |     server.start()
67 |     server.blockUntilShutdown()
68 | }
69 | 
--------------------------------------------------------------------------------
/run/grpc-hello-world-streaming/src/main/proto/hello_world.proto:
--------------------------------------------------------------------------------
 1 | // Copyright 2015 gRPC authors.
 2 | //
 3 | // Licensed under the Apache License, Version 2.0 (the "License");
 4 | // you may not use this file except in compliance with the License.
 5 | // You may obtain a copy of the License at
 6 | //
 7 | //     http://www.apache.org/licenses/LICENSE-2.0
 8 | //
 9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | 
15 | syntax = "proto3";
16 | 
17 | package io.grpc.examples.helloworld;
18 | 
19 | option java_multiple_files = true;
20 | 
21 | // The greeting service definition.
22 | service Greeter {
23 |   // Continually sends a greeting
24 |   rpc SayHelloStream (HelloRequest) returns (stream HelloReply) {}
25 | }
26 | 
27 | // The request message containing the user's name.
28 | message HelloRequest {
29 |   string name = 1;
30 | }
31 | 
32 | // The response message containing the greetings
33 | message HelloReply {
34 |   string message = 1;
35 | }
36 | 
--------------------------------------------------------------------------------
/run/http4k-hello-world/Procfile:
--------------------------------------------------------------------------------
1 | web: build/install/hello-kotlin-http4k/bin/hello-kotlin-http4k
2 | 
--------------------------------------------------------------------------------
/run/http4k-hello-world/README.md:
--------------------------------------------------------------------------------
 1 | Hello Kotlin http4k
 2 | -----------------
 3 | 
 4 | ## Run Locally:
 5 | 1. Start the local server:
 6 |     ```
 7 |     ./gradlew run
 8 |     ```
 9 | 1. Open: [localhost:8080](http://localhost:8080)
10 | 
11 | ## Click-to-Deploy on Google Cloud Run
12 | [](https://deploy.cloud.run)
13 | 
14 | ## CLI Deploy on Google Cloud Run
15 | 1. [Install & setup gcloud](https://cloud.google.com/sdk/install)
16 | 
17 | 1. Enable the Container, Container Registry, Cloud Build, and Cloud Run APIs:
18 |     ```
19 |     gcloud services enable container.googleapis.com containerregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com
20 |     ```
21 | 
22 | 1. Build the container image on Cloud Build using Buildpacks, storing the image on Google Container Registry:
23 |     ```
24 |     export PROJECT_ID=YOUR_GCP_PROJECT
25 |     gcloud builds submit --pack=image=gcr.io/$PROJECT_ID/http4k-hello-world
26 |     ```
27 | 
28 | 1. Deploy the container on Cloud Run:
29 |     ```
30 |     gcloud run deploy \
31 |       --project=$PROJECT_ID \
32 |       --region=us-central1 \
33 |       --platform=managed \
34 |       --allow-unauthenticated \
35 |       --image=gcr.io/$PROJECT_ID/http4k-hello-world \
36 |       http4k-hello-world
37 |     ```
38 | 
39 | ## Local Docker Build & Run
40 | 
41 | 1. [Install Docker](https://docs.docker.com/get-docker/)
42 | 
43 | 1. [Install pack](https://buildpacks.io/docs/install-pack/)
44 | 
45 | 1. Build the image using Buildpacks:
46 |     ```
47 |     pack build --builder=gcr.io/buildpacks/builder:v1 http4k-hello-world
48 |     ```
49 | 
50 | 1. Run image:
51 |     ```
52 |     docker run -p8080:8080 http4k-hello-world
53 |     ```
54 | 
55 | 1. Open: [localhost:8080](http://localhost:8080)
56 | 
--------------------------------------------------------------------------------
/run/http4k-hello-world/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |     application
 3 |     kotlin("jvm") version "1.9.23"
 4 | }
 5 | 
 6 | repositories {
 7 |     mavenCentral()
 8 | }
 9 | 
10 | dependencies {
11 |     implementation("org.http4k:http4k-core:5.14.0.0")
12 |     implementation("org.http4k:http4k-server-undertow:5.14.0.0")
13 | }
14 | 
15 | kotlin {
16 |     jvmToolchain(17)
17 | }
18 | 
19 | application {
20 |     mainClass.set("WebAppKt")
21 | }
22 | 
23 | tasks.replace("assemble").dependsOn("installDist")
24 | 
25 | tasks.create("stage").dependsOn("installDist")
26 | 
--------------------------------------------------------------------------------
/run/http4k-hello-world/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/run/http4k-hello-world/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/run/http4k-hello-world/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 | 
--------------------------------------------------------------------------------
/run/http4k-hello-world/settings.gradle.kts:
--------------------------------------------------------------------------------
 1 | pluginManagement {
 2 |     repositories {
 3 |         mavenCentral()
 4 |         gradlePluginPortal()
 5 |     }
 6 | }
 7 | 
 8 | rootProject.name = "hello-kotlin-http4k"
 9 | 
10 | plugins {
11 |     id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
12 | }
13 | 
--------------------------------------------------------------------------------
/run/http4k-hello-world/src/main/kotlin/WebApp.kt:
--------------------------------------------------------------------------------
 1 | import org.http4k.core.Method.GET
 2 | import org.http4k.core.Response
 3 | import org.http4k.core.Status.Companion.OK
 4 | import org.http4k.core.then
 5 | import org.http4k.filter.DebuggingFilters.PrintRequest
 6 | import org.http4k.routing.bind
 7 | import org.http4k.routing.routes
 8 | import org.http4k.server.Undertow
 9 | import org.http4k.server.asServer
10 | 
11 | val app = routes(
12 |     "/" bind GET to {
13 |         Response(OK).body("hello, world")
14 |     },
15 | )
16 | 
17 | fun main() {
18 |     val port = System.getenv("PORT")?.toInt() ?: 8080
19 | 
20 |     val server = PrintRequest()
21 |         .then(app)
22 |         .asServer(Undertow(port)).start()
23 | 
24 |     println("Server started on " + server.port())
25 | }
26 | 
--------------------------------------------------------------------------------
/run/ktor-hello-world/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle/
2 | /.idea/
3 | /build/
4 | *.iml
5 | 
--------------------------------------------------------------------------------
/run/ktor-hello-world/Procfile:
--------------------------------------------------------------------------------
1 | web: build/install/hello-kotlin-ktor/bin/hello-kotlin-ktor
2 | 
--------------------------------------------------------------------------------
/run/ktor-hello-world/README.md:
--------------------------------------------------------------------------------
 1 | Hello Kotlin Ktor
 2 | -----------------
 3 | 
 4 | ## Run Locally:
 5 | 1. Start the local server:
 6 |     ```
 7 |     ./gradlew run
 8 |     ```
 9 | 1. Open: [localhost:8080](http://localhost:8080)
10 | 
11 | ## Click-to-Deploy on Google Cloud Run
12 | [](https://deploy.cloud.run)
13 | 
14 | ## CLI Deploy on Google Cloud Run
15 | 1. [Install & setup gcloud](https://cloud.google.com/sdk/install)
16 | 
17 | 1. Enable the Container, Container Registry, Cloud Build, and Cloud Run APIs:
18 |     ```
19 |     gcloud services enable container.googleapis.com containerregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com
20 |     ```
21 | 
22 | 1. Build the container image on Cloud Build using Buildpacks, storing the image on Google Container Registry:
23 |     ```
24 |     export PROJECT_ID=YOUR_GCP_PROJECT
25 |     gcloud builds submit --pack=image=gcr.io/$PROJECT_ID/ktor-hello-world
26 |     ```
27 | 
28 | 1. Deploy the container on Cloud Run:
29 |     ```
30 |     gcloud run deploy \
31 |       --project=$PROJECT_ID \
32 |       --region=us-central1 \
33 |       --platform=managed \
34 |       --allow-unauthenticated \
35 |       --image=gcr.io/$PROJECT_ID/ktor-hello-world \
36 |       ktor-hello-world
37 |     ```
38 | 
39 | ## Local Docker Build & Run
40 | 
41 | 1. [Install Docker](https://docs.docker.com/get-docker/)
42 | 
43 | 1. [Install pack](https://buildpacks.io/docs/install-pack/)
44 | 
45 | 1. Build the image using Buildpacks:
46 |     ```
47 |     pack build --builder=gcr.io/buildpacks/builder:v1 ktor-hello-world
48 |     ```
49 | 
50 | 1. Run image:
51 |     ```
52 |     docker run -p8080:8080 ktor-hello-world
53 |     ```
54 | 
55 | 1. Open: [localhost:8080](http://localhost:8080)
56 | 
--------------------------------------------------------------------------------
/run/ktor-hello-world/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |     application
 3 |     kotlin("jvm") version "1.9.23"
 4 | }
 5 | 
 6 | repositories {
 7 |     mavenCentral()
 8 | }
 9 | 
10 | dependencies {
11 |     implementation(kotlin("reflect"))
12 |     implementation("io.ktor:ktor-server-core:2.3.9")
13 |     implementation("io.ktor:ktor-server-call-logging:2.3.9")
14 |     implementation("io.ktor:ktor-server-default-headers:2.3.8")
15 |     implementation("io.ktor:ktor-server-cio:2.3.9")
16 |     runtimeOnly("ch.qos.logback:logback-classic:1.5.3")
17 | }
18 | 
19 | kotlin {
20 |     jvmToolchain(17)
21 | }
22 | 
23 | application {
24 |     mainClass.set("WebAppKt")
25 | }
26 | 
27 | tasks.replace("assemble").dependsOn("installDist")
28 | 
29 | tasks.create("stage").dependsOn("installDist")
30 | 
--------------------------------------------------------------------------------
/run/ktor-hello-world/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/run/ktor-hello-world/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/run/ktor-hello-world/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 | 
--------------------------------------------------------------------------------
/run/ktor-hello-world/settings.gradle.kts:
--------------------------------------------------------------------------------
 1 | pluginManagement {
 2 |     repositories {
 3 |         mavenCentral()
 4 |         gradlePluginPortal()
 5 |     }
 6 | }
 7 | 
 8 | rootProject.name = "hello-kotlin-ktor"
 9 | 
10 | plugins {
11 |     id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
12 | }
13 | 
--------------------------------------------------------------------------------
/run/ktor-hello-world/src/main/kotlin/WebApp.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2018 Google LLC.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | import io.ktor.server.application.Application
18 | import io.ktor.server.application.call
19 | import io.ktor.server.application.install
20 | import io.ktor.server.cio.CIO
21 | import io.ktor.server.engine.embeddedServer
22 | import io.ktor.server.plugins.callloging.CallLogging
23 | import io.ktor.server.plugins.defaultheaders.DefaultHeaders
24 | import io.ktor.server.response.respondText
25 | import io.ktor.server.routing.Routing
26 | import io.ktor.server.routing.get
27 | 
28 | fun Application.module() {
29 |     install(DefaultHeaders)
30 |     install(CallLogging)
31 |     install(Routing) {
32 |         get("/") {
33 |             call.respondText("hello, world")
34 |         }
35 |     }
36 | }
37 | 
38 | fun main() {
39 |     val port = System.getenv("PORT")?.toInt() ?: 8080
40 |     embeddedServer(CIO, port, watchPaths = listOf("build"), module = Application::module).start(true)
41 | }
42 | 
--------------------------------------------------------------------------------
/run/ktor-hello-world/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
 1 | 
 2 |     
 3 |         
 4 |             %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
 5 |         
 6 |     
 7 | 
 8 |     
 9 |         
10 |     
11 | 
12 |     
13 |     
14 | 
15 | 
--------------------------------------------------------------------------------
/run/micronaut-hello-world/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle/
2 | /.idea/
3 | /build/
4 | *.iml
5 | 
--------------------------------------------------------------------------------
/run/micronaut-hello-world/Procfile:
--------------------------------------------------------------------------------
1 | web: build/install/micronaut-hello-world/bin/micronaut-hello-world
2 | 
--------------------------------------------------------------------------------
/run/micronaut-hello-world/README.md:
--------------------------------------------------------------------------------
 1 | Micronaut + Kotlin Hello, World
 2 | ---------------------------------
 3 | 
 4 | ## Run Locally:
 5 | 1. Start the local server: `./gradlew -t run`
 6 | 1. Open: [localhost:8080](http://localhost:8080)
 7 | 
 8 | ## Deploy on Cloud Run (with a couple clicks):
 9 | [](https://deploy.cloud.run)
10 | 
11 | ## Run on Google Cloud Run (with the command line):
12 | 
13 | 1. [Install & setup gcloud](https://cloud.google.com/sdk/install)
14 | 
15 | 1. Enable the Container, Container Registry, Cloud Build, and Cloud Run APIs:
16 |     ```
17 |     gcloud services enable container.googleapis.com containerregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com
18 |     ```
19 | 
20 | 1. Build the container image on Cloud Build using Buildpacks, storing the image on Google Container Registry:
21 |     ```
22 |     export PROJECT_ID=YOUR_GCP_PROJECT_ID
23 |     gcloud builds submit --pack=image=gcr.io/$PROJECT_ID/micronaut-hello-world
24 |     ```
25 | 
26 | 1. Deploy on Google Cloud Run:
27 |     ```
28 |     gcloud run deploy \
29 |       --image=gcr.io/$PROJECT_ID/micronaut-hello-world \
30 |       --platform=managed \
31 |       --allow-unauthenticated \
32 |       --project=$PROJECT_ID \
33 |       --region=us-central1 \
34 |       micronaut-hello-world
35 |     ```
36 | 
37 | ## Local Docker Build & Run
38 | 
39 | 1. [Install Docker](https://docs.docker.com/get-docker/)
40 | 
41 | 1. [Install pack](https://buildpacks.io/docs/install-pack/)
42 | 
43 | 1. Build the image using Buildpacks:
44 |     ```
45 |     pack build --builder=gcr.io/buildpacks/builder:v1 micronaut-hello-world
46 |     ```
47 | 
48 | 1. Run image:
49 |     ```
50 |     docker run -p8080:8080 micronaut-hello-world
51 |     ```
52 | 
53 | 1. Open: [localhost:8080](http://localhost:8080)
54 | 
--------------------------------------------------------------------------------
/run/micronaut-hello-world/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |     kotlin("jvm") version "1.9.23"
 3 |     kotlin("plugin.allopen") version "1.9.23"
 4 |     id("com.google.devtools.ksp") version "1.9.23-1.0.19"
 5 |     id("io.micronaut.application") version "4.3.4"
 6 | }
 7 | 
 8 | repositories {
 9 |     mavenCentral()
10 | }
11 | 
12 | micronaut {
13 |     processing {
14 |         incremental(true)
15 |         annotations("hello.*")
16 |     }
17 | }
18 | 
19 | dependencies {
20 |     ksp("io.micronaut.serde:micronaut-serde-processor")
21 |     implementation(kotlin("reflect"))
22 |     implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
23 |     implementation("io.micronaut:micronaut-http-server-netty")
24 |     implementation("io.micronaut.kotlin:micronaut-kotlin-runtime")
25 |     implementation("io.micronaut.serde:micronaut-serde-jackson")
26 |     runtimeOnly("ch.qos.logback:logback-classic")
27 |     runtimeOnly("com.fasterxml.jackson.module:jackson-module-kotlin")
28 | }
29 | 
30 | kotlin {
31 |     jvmToolchain(17)
32 | }
33 | 
34 | application {
35 |     mainClass = "hello.WebAppKt"
36 | }
37 | 
38 | tasks.replace("assemble").dependsOn("installDist")
39 | 
40 | tasks.create("stage").dependsOn("installDist")
41 | 
--------------------------------------------------------------------------------
/run/micronaut-hello-world/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | micronaut="4.0.0"
3 | 
--------------------------------------------------------------------------------
/run/micronaut-hello-world/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/run/micronaut-hello-world/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/run/micronaut-hello-world/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 | 
--------------------------------------------------------------------------------
/run/micronaut-hello-world/settings.gradle.kts:
--------------------------------------------------------------------------------
 1 | pluginManagement {
 2 |     repositories {
 3 |         mavenCentral()
 4 |         gradlePluginPortal()
 5 |     }
 6 | }
 7 | 
 8 | rootProject.name = "micronaut-hello-world"
 9 | 
10 | plugins {
11 |   id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
12 |   id("io.micronaut.platform.catalog") version "4.3.4"
13 | }
14 | 
--------------------------------------------------------------------------------
/run/micronaut-hello-world/src/main/kotlin/hello/WebApp.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2018 Google LLC.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package hello
18 | 
19 | import io.micronaut.http.HttpResponse
20 | import io.micronaut.http.annotation.Controller
21 | import io.micronaut.http.annotation.Get
22 | import io.micronaut.runtime.Micronaut.build
23 | import kotlinx.coroutines.async
24 | import kotlinx.coroutines.coroutineScope
25 | 
26 | fun main(args: Array) {
27 |     build()
28 |         .args(*args)
29 |         .packages("hello")
30 |         .start()
31 | }
32 | 
33 | @Controller
34 | class WebApp {
35 |     @Get("/")
36 |     // it is silly to use coroutines here, but we do it as an example
37 |     suspend fun index(): HttpResponse = coroutineScope {
38 |         val futureResponse = async {
39 |             HttpResponse.ok("hello, world")
40 |         }
41 |         futureResponse.await()
42 |     }
43 | }
44 | 
--------------------------------------------------------------------------------
/run/micronaut-hello-world/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | micronaut.router.static-resources.assets.enabled=true
2 | micronaut.router.static-resources.assets.paths=classpath:assets
3 | micronaut.router.static-resources.assets.mapping=/assets/**
4 | 
--------------------------------------------------------------------------------
/run/micronaut-hello-world/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
 1 | 
 2 |     
 3 |         
 4 |             %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
 5 |         
 6 |     
 7 | 
 8 |     
 9 |     
10 | 
11 |     
12 |         
13 |     
14 | 
15 | 
16 | 
--------------------------------------------------------------------------------
/run/plain-hello-world/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | mvnw text eol=lf
3 | 
--------------------------------------------------------------------------------
/run/plain-hello-world/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | /.idea/
3 | /*.iml
4 | /.mvn/wrapper/maven-wrapper.jar
5 | 
--------------------------------------------------------------------------------
/run/plain-hello-world/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
 1 | # Licensed to the Apache Software Foundation (ASF) under one
 2 | # or more contributor license agreements.  See the NOTICE file
 3 | # distributed with this work for additional information
 4 | # regarding copyright ownership.  The ASF licenses this file
 5 | # to you under the Apache License, Version 2.0 (the
 6 | # "License"); you may not use this file except in compliance
 7 | # with the License.  You may obtain a copy of the License at
 8 | #
 9 | #   http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied.  See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip
18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
19 | 
--------------------------------------------------------------------------------
/run/plain-hello-world/README.md:
--------------------------------------------------------------------------------
 1 | Hello World
 2 | -----------
 3 | 
 4 | ## Run Locally:
 5 | 1. Start the local server:
 6 |     ```
 7 |     ./mvnw compile exec:java
 8 |     ```
 9 | 1. Open: [localhost:8080](http://localhost:8080)
10 | 
11 | ## Click-to-Deploy on Google Cloud Run
12 | [](https://deploy.cloud.run)
13 | 
14 | ## CLI Deploy on Google Cloud Run
15 | 1. [Install & setup gcloud](https://cloud.google.com/sdk/install)
16 | 
17 | 1. Enable the Container, Container Registry, Cloud Build, and Cloud Run APIs:
18 |     ```
19 |     gcloud services enable container.googleapis.com containerregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com
20 |     ```
21 | 
22 | 1. Build the container image and store it on Google Container Registry:
23 |     ```
24 |     export PROJECT_ID=YOUR_GCP_PROJECT
25 |     ./mvnw compile jib:build -Dimage=gcr.io/$PROJECT_ID/plain-hello-world
26 |     ```
27 | 
28 | 1. Deploy the container on Cloud Run:
29 |     ```
30 |     gcloud run deploy \
31 |       --project=$PROJECT_ID \
32 |       --region=us-central1 \
33 |       --platform=managed \
34 |       --allow-unauthenticated \
35 |       --image=gcr.io/$PROJECT_ID/plain-hello-world \
36 |       plain-hello-world
37 |     ```
38 | 
39 | ## Local Docker Build & Run
40 | 
41 | 1. [Install Docker](https://docs.docker.com/get-docker/)
42 | 
43 | 1. Build the image using Jib:
44 |     ```
45 |     ./mvnw compile jib:dockerBuild -Dimage=plain-hello-world
46 |     ```
47 | 
48 | 1. Run image:
49 |     ```
50 |     docker run -p8080:8080 plain-hello-world
51 |     ```
52 | 
53 | 1. Open: [localhost:8080](http://localhost:8080)
54 | 
--------------------------------------------------------------------------------
/run/plain-hello-world/pom.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 4 |     4.0.0
 5 | 
 6 |     com.google
 7 |     plain-hello-world
 8 |     jar
 9 |     0.1.0-SNAPSHOT
10 | 
11 |     
12 |         8
13 |         8
14 |     
15 | 
16 |     
17 |         
18 |             org.jetbrains.kotlin
19 |             kotlin-stdlib-jdk8
20 |             1.9.23
21 |         
22 |     
23 | 
24 |     
25 |         
26 |             
27 |                 org.jetbrains.kotlin
28 |                 kotlin-maven-plugin
29 |                 1.9.23
30 |                 
31 |                     
32 |                         compile
33 |                         process-sources
34 |                         
35 |                             compile
36 |                         
37 |                     
38 |                 
39 |             
40 | 
41 |             
42 |                 org.codehaus.mojo
43 |                 exec-maven-plugin
44 |                 3.2.0
45 |                 
46 |                     
47 |                         
48 |                             java
49 |                         
50 |                     
51 |                 
52 |                 
53 |                     com.google.WebAppKt
54 |                 
55 |             
56 | 
57 |             
58 |                 com.google.cloud.tools
59 |                 jib-maven-plugin
60 |                 3.4.1
61 |             
62 |         
63 |     
64 | 
65 | 
66 | 
--------------------------------------------------------------------------------
/run/plain-hello-world/src/main/java/com/google/WebApp.kt:
--------------------------------------------------------------------------------
 1 | package com.google
 2 | 
 3 | import com.sun.net.httpserver.HttpServer
 4 | import java.net.InetSocketAddress
 5 | 
 6 | fun main() {
 7 |     val port = Integer.parseInt(System.getenv().getOrDefault("PORT", "8080"))
 8 |     val server = HttpServer.create(InetSocketAddress(port), 0)
 9 | 
10 |     server.createContext("/") { handler ->
11 |         val response = "hello, world".toByteArray()
12 |         handler.sendResponseHeaders(200, response.size.toLong())
13 |         handler.responseBody.write(response)
14 |     }
15 | 
16 |     println("Listening at http://localhost:$port")
17 | 
18 |     server.start()
19 | }
20 | 
--------------------------------------------------------------------------------
/run/quarkus-hello-world/.gitignore:
--------------------------------------------------------------------------------
 1 | # Eclipse
 2 | .project
 3 | .classpath
 4 | .settings/
 5 | bin/
 6 | 
 7 | # IntelliJ
 8 | .idea
 9 | *.ipr
10 | *.iml
11 | *.iws
12 | 
13 | # NetBeans
14 | nb-configuration.xml
15 | 
16 | # Visual Studio Code
17 | .vscode
18 | 
19 | # OSX
20 | .DS_Store
21 | 
22 | # Vim
23 | *.swp
24 | *.swo
25 | 
26 | # patch
27 | *.orig
28 | *.rej
29 | 
30 | # Maven
31 | target/
32 | pom.xml.tag
33 | pom.xml.releaseBackup
34 | pom.xml.versionsBackup
35 | release.properties
36 | 
37 | /.mvn/wrapper/maven-wrapper.jar
38 | 
--------------------------------------------------------------------------------
/run/quarkus-hello-world/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
 1 | # Licensed to the Apache Software Foundation (ASF) under one
 2 | # or more contributor license agreements.  See the NOTICE file
 3 | # distributed with this work for additional information
 4 | # regarding copyright ownership.  The ASF licenses this file
 5 | # to you under the Apache License, Version 2.0 (the
 6 | # "License"); you may not use this file except in compliance
 7 | # with the License.  You may obtain a copy of the License at
 8 | #
 9 | #   http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied.  See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip
18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
19 | 
--------------------------------------------------------------------------------
/run/quarkus-hello-world/README.md:
--------------------------------------------------------------------------------
 1 | Quarkus + Kotlin Hello, World
 2 | ---------------------------------
 3 | 
 4 | ## Run Locally:
 5 | 1. Start the local server: `./mvnw quarkus:dev`
 6 | 1. Open: [localhost:8080](http://localhost:8080)
 7 | 
 8 | ## Deploy on Cloud Run (with a couple clicks):
 9 | [](https://deploy.cloud.run)
10 | 
11 | ## Run on Google Cloud Run (with the command line):
12 | 
13 | 1. [Install & setup gcloud](https://cloud.google.com/sdk/install)
14 | 
15 | 1. Enable the Container, Container Registry, Cloud Build, and Cloud Run APIs:
16 |     ```
17 |     gcloud services enable container.googleapis.com containerregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com
18 |     ```
19 | 
20 | 1. Build the container image on Cloud Build using Buildpacks, storing the image on Google Container Registry:
21 |     ```
22 |     export PROJECT_ID=YOUR_GCP_PROJECT_ID
23 |     gcloud builds submit --pack=image=gcr.io/$PROJECT_ID/quarkus-hello-world
24 |     ```
25 | 
26 | 1. Deploy on Google Cloud Run:
27 |     ```
28 |     gcloud run deploy \
29 |       --image=gcr.io/$PROJECT_ID/quarkus-hello-world \
30 |       --platform=managed \
31 |       --allow-unauthenticated \
32 |       --project=$PROJECT_ID \
33 |       --region=us-central1 \
34 |       quarkus-hello-world
35 |     ```
36 | 
37 | ## Local Docker Build & Run
38 | 
39 | 1. [Install Docker](https://docs.docker.com/get-docker/)
40 | 
41 | 1. [Install pack](https://buildpacks.io/docs/install-pack/)
42 | 
43 | 1. Build the image using Buildpacks:
44 |     ```
45 |     pack build --builder=gcr.io/buildpacks/builder:v1 quarkus-hello-world
46 |     ```
47 | 
48 | 1. Run image:
49 |     ```
50 |     docker run -p8080:8080 quarkus-hello-world
51 |     ```
52 | 
53 | 1. Open: [localhost:8080](http://localhost:8080)
54 | 
--------------------------------------------------------------------------------
/run/quarkus-hello-world/src/main/kotlin/com/google/App.kt:
--------------------------------------------------------------------------------
 1 | package com.google
 2 | 
 3 | import jakarta.ws.rs.GET
 4 | import jakarta.ws.rs.Path
 5 | import jakarta.ws.rs.Produces
 6 | import jakarta.ws.rs.core.MediaType
 7 | 
 8 | @Path("/")
 9 | class App {
10 |     @GET
11 |     @Produces(MediaType.TEXT_PLAIN)
12 |     fun index(): String {
13 |         return "hello, world"
14 |     }
15 | }
16 | 
--------------------------------------------------------------------------------
/run/springboot-cloudsql/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle/
2 | .idea/
3 | build/
4 | *.iml
5 | /local.properties
6 | 
--------------------------------------------------------------------------------
/run/springboot-cloudsql/README.md:
--------------------------------------------------------------------------------
 1 | # Spring Boot CloudSQL
 2 | 
 3 | 
 4 | 
 5 | ## Local Dev (Requires JDK 17 or higher)
 6 | 
 7 | Run the server:
 8 | ```
 9 | ./gradlew bootRun
10 | ```
11 | 
12 | Use the server:
13 | ```
14 | # Create a "bar"
15 | curl -v -X POST localhost:8080/bars    -H 'Content-Type: application/json'    -d '{"name": "Test"}'
16 | 
17 | # Get the "bars"
18 | curl localhost:8080/bars
19 | ```
20 | 
21 | 
22 | Run the tests:
23 | ```
24 | ./gradlew test
25 | ```
26 | 
27 | 
28 | Create container & run with docker:
29 | ```
30 | ./gradlew bootBuildImage
31 | 
32 | docker run --rm -ePOSTGRES_PASSWORD=password -p5432:5432 --name my-postgres postgres:13.3
33 | 
34 | # psql
35 | docker exec -it my-postgres psql -U postgres
36 | 
37 | docker run -it --network host \
38 |   -eSPRING_R2DBC_URL=r2dbc:postgresql://localhost/postgres \
39 |   -eSPRING_R2DBC_USERNAME=postgres \
40 |   -eSPRING_R2DBC_PASSWORD=password \
41 |   springboot-cloudsql
42 | ```
43 | 
44 | [http://localhost:8080/bars](http://localhost:8080/bars)
45 | 
46 | 
47 | ## Google Cloud
48 | 
49 | 1. Set project:
50 |     ```
51 |     export PROJECT_ID=YOUR_PROJECT_ID
52 |     ```
53 | 2. Create the Cloud SQL instance, VPC, and VPC Connector
54 | 3. Create & push the container:
55 |     ```
56 |     ./gradlew bootBuildImage --imageName=gcr.io/$PROJECT_ID/springboot-cloudsql
57 |     docker push gcr.io/$PROJECT_ID/springboot-cloudsql
58 |     ```
59 | 4. Init the schema:
60 |     TODO: Need to run the container with an arg `init` and the env vars: `SPRING_R2DBC_URL`, `SPRING_R2DBC_USERNAME`, `SPRING_R2DBC_PASSWORD` in a place that can access the db
61 | 5. Deploy the Cloud Run service:
62 |     ```
63 |     gcloud run deploy \
64 |       --image=gcr.io/$PROJECT_ID/springboot-cloudsql \
65 |       --platform=managed \
66 |       --allow-unauthenticated \
67 |       --project=$PROJECT_ID \
68 |       --region=us-central1 \
69 |       --set-env-vars=SPRING_R2DBC_URL=r2dbc:postgresql://YOUR_DB_IP/postgres \
70 |       --set-env-vars=SPRING_R2DBC_USERNAME=YOUR_DB_USERNAME \
71 |       --set-env-vars=SPRING_R2DBC_PASSWORD=YOUR_DB_PASSWORD \
72 |       springboot-cloudsql
73 |     ```
74 | 
--------------------------------------------------------------------------------
/run/springboot-cloudsql/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | import org.gradle.api.tasks.testing.logging.TestLogEvent.*
 2 | 
 3 | plugins {
 4 |     application
 5 |     kotlin("jvm")                         version "1.9.23"
 6 |     kotlin("plugin.spring")               version "1.9.23"
 7 |     id("org.springframework.boot")        version "3.2.3"
 8 |     id("io.spring.dependency-management") version "1.1.4"
 9 | }
10 | 
11 | repositories {
12 |     mavenCentral()
13 | }
14 | 
15 | dependencies {
16 |     implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core")
17 | 
18 |     implementation("org.springframework.boot:spring-boot-starter-webflux")
19 | 
20 |     implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
21 |     implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
22 |     implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
23 | 
24 |     implementation("org.springframework.boot:spring-boot-starter-data-r2dbc")
25 |     runtimeOnly("org.postgresql:r2dbc-postgresql")
26 | 
27 |     testImplementation("org.springframework.boot:spring-boot-starter-test")
28 | 
29 |     testImplementation("org.testcontainers:postgresql:1.19.7")
30 |     testImplementation("org.testcontainers:r2dbc:1.19.7")
31 | 
32 |     developmentOnly("org.springframework.boot:spring-boot-devtools")
33 | }
34 | 
35 | kotlin {
36 |     jvmToolchain(17)
37 | }
38 | 
39 | application {
40 |     mainClass.set("kotlinbars.MainKt")
41 | }
42 | 
43 | tasks.withType {
44 |     classpath = sourceSets["test"].runtimeClasspath + classpath
45 | }
46 | 
47 | tasks.withType {
48 |     useJUnitPlatform()
49 | 
50 |     testLogging {
51 |         showStandardStreams = true
52 |         exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
53 |         events(STARTED, PASSED, SKIPPED, FAILED)
54 |     }
55 | }
56 | 
--------------------------------------------------------------------------------
/run/springboot-cloudsql/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/run/springboot-cloudsql/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/run/springboot-cloudsql/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 | 
--------------------------------------------------------------------------------
/run/springboot-cloudsql/project.toml:
--------------------------------------------------------------------------------
1 | [[build.env]]
2 | name = "GOOGLE_RUNTIME_VERSION"
3 | value = "17"
4 | 
--------------------------------------------------------------------------------
/run/springboot-cloudsql/settings.gradle.kts:
--------------------------------------------------------------------------------
 1 | pluginManagement {
 2 |     repositories {
 3 |         mavenCentral()
 4 |         gradlePluginPortal()
 5 |     }
 6 | }
 7 | 
 8 | rootProject.name = "springboot-cloudsql"
 9 | 
10 | plugins {
11 |   id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
12 | }
13 | 
--------------------------------------------------------------------------------
/run/springboot-cloudsql/src/main/kotlin/kotlinbars/Main.kt:
--------------------------------------------------------------------------------
 1 | package kotlinbars
 2 | 
 3 | import kotlinx.coroutines.reactive.awaitFirst
 4 | import kotlinx.coroutines.reactive.awaitFirstOrNull
 5 | import org.slf4j.LoggerFactory
 6 | import org.springframework.boot.autoconfigure.SpringBootApplication
 7 | import org.springframework.boot.runApplication
 8 | import org.springframework.data.annotation.Id
 9 | import org.springframework.data.repository.reactive.ReactiveCrudRepository
10 | import org.springframework.http.HttpStatus
11 | import org.springframework.http.ResponseEntity
12 | import org.springframework.web.bind.annotation.GetMapping
13 | import org.springframework.web.bind.annotation.PostMapping
14 | import org.springframework.web.bind.annotation.RequestBody
15 | import org.springframework.web.bind.annotation.RestController
16 | import java.net.URI
17 | import java.util.Properties
18 | 
19 | data class Bar(@Id val id: Long?, val name: String)
20 | 
21 | interface BarRepo : ReactiveCrudRepository
22 | 
23 | @SpringBootApplication
24 | @RestController
25 | class WebApp(val barRepo: BarRepo) {
26 | 
27 |     val logger = LoggerFactory.getLogger(WebApp::class.java)
28 | 
29 |     @GetMapping("/bars")
30 |     suspend fun getBars(): List {
31 |         return barRepo.findAll().collectList().awaitFirst()
32 |     }
33 | 
34 |     @PostMapping("/bars")
35 |     suspend fun addBar(@RequestBody bar: Bar) = run {
36 |         barRepo.save(bar).awaitFirstOrNull()?.let {
37 |             ResponseEntity(HttpStatus.NO_CONTENT)
38 |         } ?: ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR)
39 |     }
40 | 
41 |     @GetMapping("/error")
42 |     fun error() = run {
43 |         logger.error("An Error")
44 |     }
45 | }
46 | 
47 | fun main(args: Array) {
48 |     val props = Properties()
49 | 
50 |     System.getenv()["DATABASE_URL"]?.let {
51 |         val dbUri = URI(it)
52 |         props["spring.r2dbc.url"] = "r2dbc:postgresql://" + dbUri.host + dbUri.path
53 |         props["spring.r2dbc.username"] = dbUri.userInfo.split(":")[0]
54 |         props["spring.r2dbc.password"] = dbUri.userInfo.split(":")[1]
55 |     }
56 | 
57 |     runApplication(*args)
58 | }
59 | 
--------------------------------------------------------------------------------
/run/springboot-cloudsql/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | spring.sql.init.mode=always
2 | 
--------------------------------------------------------------------------------
/run/springboot-cloudsql/src/main/resources/schema.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE bar (
2 |                      id   SERIAL PRIMARY KEY,
3 |                      name VARCHAR(255) NOT NULL
4 | );
--------------------------------------------------------------------------------
/run/springboot-cloudsql/src/test/kotlin/kotlinbars/BarRepoTest.kt:
--------------------------------------------------------------------------------
 1 | package kotlinbars
 2 | 
 3 | import kotlinx.coroutines.reactive.awaitFirst
 4 | import kotlinx.coroutines.runBlocking
 5 | import org.assertj.core.api.Assertions.assertThat
 6 | import org.junit.jupiter.api.Test
 7 | import org.springframework.beans.factory.annotation.Autowired
 8 | import org.springframework.boot.test.context.SpringBootTest
 9 | 
10 | @SpringBootTest
11 | class BarRepoTest(@Autowired val barRepo: BarRepo) {
12 | 
13 |     @Test
14 |     fun `barRepo works`(): Unit = runBlocking {
15 |         barRepo.save(Bar(null, "foo")).awaitFirst()
16 | 
17 |         val bars = barRepo.findAll().collectList().awaitFirst()
18 |         assertThat(bars.size).isEqualTo(1)
19 |         assertThat(bars.first().id).isNotNull
20 |     }
21 | }
22 | 
--------------------------------------------------------------------------------
/run/springboot-cloudsql/src/test/resources/application.properties:
--------------------------------------------------------------------------------
1 | spring.sql.init.mode=always
2 | spring.r2dbc.url=r2dbc:tc:postgresql:///bars?TC_IMAGE_TAG=13.3
3 | 
--------------------------------------------------------------------------------
/run/springboot-hello-world/.gitignore:
--------------------------------------------------------------------------------
 1 | HELP.md
 2 | .gradle
 3 | build/
 4 | !gradle/wrapper/gradle-wrapper.jar
 5 | !**/src/main/**
 6 | !**/src/test/**
 7 | 
 8 | ### STS ###
 9 | .apt_generated
10 | .classpath
11 | .factorypath
12 | .project
13 | .settings
14 | .springBeans
15 | .sts4-cache
16 | 
17 | ### IntelliJ IDEA ###
18 | .idea
19 | *.iws
20 | *.iml
21 | *.ipr
22 | out/
23 | 
24 | ### NetBeans ###
25 | /nbproject/private/
26 | /nbbuild/
27 | /dist/
28 | /nbdist/
29 | /.nb-gradle/
30 | 
31 | ### VS Code ###
32 | .vscode/
33 | 
--------------------------------------------------------------------------------
/run/springboot-hello-world/Procfile:
--------------------------------------------------------------------------------
1 | web: java -jar build/libs/springboot-hello-world.jar
2 | 
--------------------------------------------------------------------------------
/run/springboot-hello-world/README.md:
--------------------------------------------------------------------------------
 1 | Spring Boot + Kotlin Hello, World
 2 | ---------------------------------
 3 | 
 4 | ## Run Locally (Requires JDK 17 or higher):
 5 | 1. Start the local server: `./gradlew bootRun`
 6 | 1. (Optional) To enable auto-reload, in another terminal / shell: `./gradlew -t classes`
 7 | 1. Open: [localhost:8080](http://localhost:8080)
 8 | 
 9 | ## Deploy on Cloud Run (with a couple clicks):
10 | [](https://deploy.cloud.run)
11 | 
12 | ## Run on Google Cloud Run (with the command line):
13 | 
14 | 1. [Install & setup gcloud](https://cloud.google.com/sdk/install)
15 | 
16 | 1. Enable the Container, Container Registry, Cloud Build, and Cloud Run APIs:
17 |     ```
18 |     gcloud services enable container.googleapis.com containerregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com
19 |     ```
20 | 
21 | 1. Build the container image on Cloud Build using Buildpacks, storing the image on Google Container Registry:
22 |     ```
23 |     export PROJECT_ID=YOUR_GCP_PROJECT_ID
24 |     gcloud builds submit --pack=image=gcr.io/$PROJECT_ID/springboot-hello-world
25 |     ```
26 | 
27 | 1. Deploy on Google Cloud Run:
28 |     ```
29 |     gcloud run deploy \
30 |       --image=gcr.io/$PROJECT_ID/springboot-hello-world \
31 |       --platform=managed \
32 |       --allow-unauthenticated \
33 |       --project=$PROJECT_ID \
34 |       --region=us-central1 \
35 |       --memory=1Gi \
36 |       springboot-hello-world
37 |     ```
38 | 
39 | ## Local Docker Build & Run
40 | 
41 | 1. [Install Docker](https://docs.docker.com/get-docker/)
42 | 
43 | 1. Build the image
44 |     ```
45 |     ./gradlew bootBuildImage --imageName=springboot-hello-world
46 |     ```
47 | 
48 | 1. Run image:
49 |     ```
50 |     docker run -p8080:8080 springboot-hello-world
51 |     ```
52 | 
53 | 1. Open: [localhost:8080](http://localhost:8080)
54 | 
--------------------------------------------------------------------------------
/run/springboot-hello-world/app.json:
--------------------------------------------------------------------------------
1 | {
2 |     "options": {
3 |         "memory": "1Gi"
4 |     }
5 | }
6 | 
--------------------------------------------------------------------------------
/run/springboot-hello-world/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 | 	id("org.springframework.boot") version "3.2.3"
 3 | 	id("io.spring.dependency-management") version "1.1.4"
 4 | 	kotlin("jvm") version "1.9.23"
 5 | 	kotlin("plugin.spring") version "1.9.23"
 6 | }
 7 | 
 8 | repositories {
 9 | 	mavenCentral()
10 | }
11 | 
12 | kotlin {
13 | 	jvmToolchain(17)
14 | }
15 | 
16 | dependencies {
17 | 	implementation(kotlin("reflect"))
18 | 	implementation("org.springframework.boot:spring-boot-starter-webflux")
19 | 	implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
20 | 	implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm")
21 | 	implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
22 | 	developmentOnly("org.springframework.boot:spring-boot-devtools")
23 | }
24 | 
--------------------------------------------------------------------------------
/run/springboot-hello-world/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/run/springboot-hello-world/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/run/springboot-hello-world/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 | 
--------------------------------------------------------------------------------
/run/springboot-hello-world/project.toml:
--------------------------------------------------------------------------------
1 | [[build.env]]
2 | name = "GOOGLE_RUNTIME_VERSION"
3 | value = "17"
4 | 
--------------------------------------------------------------------------------
/run/springboot-hello-world/settings.gradle.kts:
--------------------------------------------------------------------------------
 1 | pluginManagement {
 2 |     repositories {
 3 |         mavenCentral()
 4 |         gradlePluginPortal()
 5 |     }
 6 | }
 7 | 
 8 | rootProject.name = "springboot-hello-world"
 9 | 
10 | plugins {
11 |     id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
12 | }
13 | 
--------------------------------------------------------------------------------
/run/springboot-hello-world/src/main/kotlin/DemoApplication.kt:
--------------------------------------------------------------------------------
 1 | package demo
 2 | 
 3 | import kotlinx.coroutines.delay
 4 | import org.springframework.boot.autoconfigure.SpringBootApplication
 5 | import org.springframework.boot.runApplication
 6 | import org.springframework.web.bind.annotation.GetMapping
 7 | import org.springframework.web.bind.annotation.RestController
 8 | 
 9 | @SpringBootApplication
10 | @RestController
11 | class DemoApplication {
12 | 
13 |     @GetMapping("/")
14 |     suspend fun index() = run {
15 |         delay(10)
16 |         "hello, world"
17 |     }
18 | }
19 | 
20 | fun main(args: Array) {
21 |     runApplication(*args)
22 | }
23 | 
--------------------------------------------------------------------------------
/run/springboot-hello-world/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.port=${PORT:8080}
2 | 
--------------------------------------------------------------------------------
/storage/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |     application
 3 |     kotlin("jvm") version "1.9.23"
 4 | }
 5 | 
 6 | repositories {
 7 |     mavenCentral()
 8 | }
 9 | 
10 | dependencies {
11 |     implementation(kotlin("reflect"))
12 |     implementation("com.google.cloud:google-cloud-storage:2.35.0")
13 |     testImplementation("junit:junit:4.13.2")
14 |     // see: https://github.com/googleapis/sdk-platform-java/pull/1832
15 |     modules {
16 |         module("com.google.guava:listenablefuture") {
17 |             replacedBy("com.google.guava:guava", "listenablefuture is part of guava")
18 |         }
19 |     }
20 | }
21 | 
22 | kotlin {
23 |     jvmToolchain(17)
24 | }
25 | 
26 | application {
27 |     mainClass.set("com.google.storage.StorageKt")
28 | }
29 | 
--------------------------------------------------------------------------------
/storage/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/storage/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/storage/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 | 
--------------------------------------------------------------------------------
/storage/resources/upload/dog.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/storage/resources/upload/dog.jpg
--------------------------------------------------------------------------------
/storage/settings.gradle.kts:
--------------------------------------------------------------------------------
 1 | pluginManagement {
 2 |     repositories {
 3 |         mavenCentral()
 4 |         gradlePluginPortal()
 5 |     }
 6 | }
 7 | 
 8 | rootProject.name = "storage"
 9 | 
10 | plugins {
11 |     id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
12 | }
13 | 
--------------------------------------------------------------------------------
/storage/src/main/kotlin/Quickstart.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2018 Google Inc.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package com.google.storage
18 | 
19 | /**
20 |  * A class which instantiates a Cloud Storage client and lists all objects in a
21 |  * bucket.
22 |  */
23 | 
24 | import com.google.cloud.storage.StorageOptions
25 | 
26 | fun quickstart(bucketName: String) {
27 |     // [START storage_quickstart]
28 |     // import com.google.cloud.storage.StorageOptions
29 |     val storage = StorageOptions.getDefaultInstance().service
30 |     val bucket = storage.get(bucketName) ?: error("Bucket $bucketName does not exist.")
31 | 
32 |     println("Listing all blobs in bucket $bucketName:")
33 |     bucket.list().iterateAll().forEach { blob ->
34 |         println("${blob.name} (content-type: ${blob.contentType}, size: ${blob.size})")
35 |     }
36 |     // [END storage_quickstart]
37 | }
38 | 
--------------------------------------------------------------------------------
/storage/src/test/kotlin/QuickstartTest.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2018 Google Inc.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package com.google.storage
18 | 
19 | import org.junit.Test
20 | 
21 | internal class QuickstartTest {
22 |     @Test
23 |     fun quickstartTest() {
24 |         quickstart(System.getenv("GOOGLE_STORAGE_BUCKET"))
25 |     }
26 | }
27 | 
--------------------------------------------------------------------------------
/storage/src/test/kotlin/StorageTest.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright 2018 Google Inc.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  * http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | 
17 | package com.google.storage
18 | 
19 | import com.google.cloud.Timestamp
20 | import org.junit.FixMethodOrder
21 | import org.junit.Test
22 | import org.junit.runners.MethodSorters
23 | import java.util.Random
24 | 
25 | @FixMethodOrder(MethodSorters.NAME_ASCENDING)
26 | internal class StorageTest {
27 | 
28 |     companion object {
29 |         val timestamp = Timestamp.now().seconds
30 |         val rand = Random().nextInt(10000)
31 |         val bucketName = "my_kotlin_sample_bucket_${timestamp}_$rand"
32 |     }
33 | 
34 |     @Test(expected = IllegalStateException::class)
35 |     fun t01_mainNoArgTest() {
36 |         main()
37 |     }
38 | 
39 |     @Test(expected = IllegalStateException::class)
40 |     fun t02_badActionName() {
41 |         main("feedMyDog")
42 |     }
43 | 
44 |     @Test
45 |     fun t03_usage() {
46 |         main("usage")
47 |     }
48 | 
49 |     @Test(expected = IllegalStateException::class)
50 |     fun t04_createWithoutBucketName() {
51 |         main("create")
52 |     }
53 | 
54 |     @Test
55 |     fun t05_createBucket() {
56 |         main("create", bucketName)
57 |     }
58 | 
59 |     @Test
60 |     fun t06_infoStorage() {
61 |         main("info")
62 |     }
63 | 
64 |     @Test(expected = IllegalStateException::class)
65 |     fun t07_infoBucketNameNotExist() {
66 |         main("info", "i_bet_you_do_not_have_a_bucket_with_this_name")
67 |     }
68 | 
69 |     fun t08_infoBucket() {
70 |         main("info", bucketName)
71 |     }
72 | 
73 |     @Test
74 |     fun t09_upload() {
75 |         main("upload", "resources/upload/dog.jpg", bucketName, "dog.jpg")
76 |     }
77 | 
78 |     @Test
79 |     fun t10_uploadNoBlobName() {
80 |         main("upload", "resources/upload/dog.jpg", bucketName)
81 |     }
82 | 
83 |     @Test
84 |     fun t11_download() {
85 |         main("download", bucketName, "dog.jpg", "resources/dog-downloaded.jpg")
86 |     }
87 | 
88 |     @Test
89 |     fun t12_deleteBlob() {
90 |         main("delete", bucketName, "dog.jpg")
91 |     }
92 | 
93 |     @Test
94 |     fun t13_deleteBucket() {
95 |         main("delete", bucketName)
96 |     }
97 | }
98 | 
--------------------------------------------------------------------------------
/vision/README.md:
--------------------------------------------------------------------------------
 1 | # Google Cloud Vision Kotlin Sample
 2 | 
 3 | [![Open in Cloud Shell][shell_img]][shell_link]
 4 | 
 5 | [shell_img]: http://gstatic.com/cloudssh/images/open-btn.svg
 6 | [shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googlecloudplatform/kotlin-samples&page=editor&working_dir=vision
 7 | 
 8 | ## Description
 9 | 
10 | This simple command-line application demonstrates how to invoke the [Google
11 | Cloud Vision API][vision-api-docs] from Kotlin. The sample calls the Vision API on an input image.
12 | 
13 | Example:
14 | ```sh 
15 | build/install/vision/bin/vision ./resources/doggo.jpg
16 | ```
17 | 
18 | ## Quickstart
19 | 
20 | #### Setup
21 | - [Enable][enable-vision-api] Cloud Vision API.
22 | - Set up [authentication](https://cloud.google.com/docs/authentication/getting-started).
23 | 
24 | #### Build
25 | - Clone the repository
26 | ```sh
27 | git clone https://github.com/GoogleCloudPlatform/kotlin-samples
28 | cd kotlin-samples/vision
29 | ```
30 | - Build the project with Gradle Wrapper:
31 | ```sh
32 | # run with "-info" flag to print potential errors
33 | ./gradlew installDist -info
34 | ```
35 | #### Running the sample!
36 | 
37 | ```sh
38 | # Call the Vision API with the default image file in "resources/doggo.jpg"
39 | build/install/vision/bin/vision
40 | # Call the Vision API with your own image file
41 | build/install/vision/bin/vision path/to/your-image.jpg
42 | ```
43 | ## Contributing changes
44 | 
45 | * See [CONTRIBUTING.md](../CONTRIBUTING.md)
46 | 
47 | ## Licensing
48 | 
49 | * See [LICENSE](../LICENSE)
50 | 
51 | [vision-api-docs]: https://cloud.google.com/vision/
52 | [enable-vision-api]: https://console.cloud.google.com/flows/enableapi?apiid=vision.googleapis.com
53 | [google-cloud-java]: https://googlecloudplatform.github.io/google-cloud-java
54 | 
--------------------------------------------------------------------------------
/vision/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |     application
 3 |     kotlin("jvm") version "1.9.23"
 4 | }
 5 | 
 6 | repositories {
 7 |     mavenCentral()
 8 | }
 9 | 
10 | dependencies {
11 |     implementation(kotlin("reflect"))
12 |     implementation("com.google.cloud:google-cloud-vision:3.35.0")
13 |     testImplementation("junit:junit:4.13.2")
14 |     testImplementation(kotlin("test"))
15 |     // see: https://github.com/googleapis/sdk-platform-java/pull/1832
16 |     modules {
17 |         module("com.google.guava:listenablefuture") {
18 |             replacedBy("com.google.guava:guava", "listenablefuture is part of guava")
19 |         }
20 |     }
21 | }
22 | 
23 | kotlin {
24 |     jvmToolchain(17)
25 | }
26 | 
27 | application {
28 |     mainClass.set("com.google.vision.QuickstartKt")
29 | }
30 | 
--------------------------------------------------------------------------------
/vision/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/vision/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/vision/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 | 
--------------------------------------------------------------------------------
/vision/resources/doggo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/kotlin-samples/fabbf5b5dcee3f239d9e1c60e049dca7713d2694/vision/resources/doggo.jpg
--------------------------------------------------------------------------------
/vision/settings.gradle.kts:
--------------------------------------------------------------------------------
 1 | pluginManagement {
 2 |     repositories {
 3 |         mavenCentral()
 4 |         gradlePluginPortal()
 5 |     }
 6 | }
 7 | 
 8 | rootProject.name = "vision"
 9 | 
10 | plugins {
11 |     id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
12 | }
13 | 
--------------------------------------------------------------------------------
/vision/src/main/kotlin/Quickstart.kt:
--------------------------------------------------------------------------------
 1 | // Copyright 2018 Google Inc.
 2 | //
 3 | //  Licensed under the Apache License, Version 2.0 (the "License");
 4 | //  you may not use this file except in compliance with the License.
 5 | //  You may obtain a copy of the License at
 6 | //
 7 | //        http://www.apache.org/licenses/LICENSE-2.0
 8 | //
 9 | //  Unless required by applicable law or agreed to in writing, software
10 | //  distributed under the License is distributed on an "AS IS" BASIS,
11 | //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | //  See the License for the specific language governing permissions and
13 | //  limitations under the License.
14 | package com.google.vision
15 | 
16 | import com.google.cloud.vision.v1.AnnotateImageRequest
17 | import com.google.cloud.vision.v1.Feature
18 | import com.google.cloud.vision.v1.Feature.Type
19 | import com.google.cloud.vision.v1.Image
20 | import com.google.cloud.vision.v1.ImageAnnotatorClient
21 | import com.google.protobuf.ByteString
22 | import java.io.File
23 | import java.io.IOException
24 | 
25 | fun main(args: Array) {
26 |     val imageFileName = if (args.isEmpty()) {
27 |         "./resources/doggo.jpg" // Image file path
28 |     } else {
29 |         args[0] // grab args[0] for file
30 |     }
31 | 
32 |     val imageFile = File(imageFileName)
33 |     if (!imageFile.exists()) {
34 |         throw NoSuchFileException(file = imageFile, reason = "The file you specified does not exist")
35 |     }
36 | 
37 |     try {
38 |         quickstart(imageFileName)
39 |     } catch (e: IOException) {
40 |         println("Image annotation failed:")
41 |         println(e.message)
42 |     }
43 | }
44 | 
45 | fun quickstart(imageFileName: String) {
46 |     // [START vision_quickstart]
47 |     // import com.google.cloud.vision.v1.ImageAnnotatorClient
48 |     // import java.io.File
49 |     val imgProto = ByteString.copyFrom(File(imageFileName).readBytes())
50 |     val vision = ImageAnnotatorClient.create()
51 | 
52 |     // Set up the Cloud Vision API request.
53 |     val img = Image.newBuilder().setContent(imgProto).build()
54 |     val feat = Feature.newBuilder().setType(Type.LABEL_DETECTION).build()
55 |     val request = AnnotateImageRequest.newBuilder()
56 |         .addFeatures(feat)
57 |         .setImage(img)
58 |         .build()
59 | 
60 |     // Call the Cloud Vision API and perform label detection on the image.
61 |     val result = vision.batchAnnotateImages(arrayListOf(request))
62 | 
63 |     // Print the label annotations for the first response.
64 |     result.responsesList[0].labelAnnotationsList.forEach { label ->
65 |         println("${label.description} (${(label.score * 100).toInt()}%)")
66 |     }
67 |     // [END vision_quickstart]
68 | }
69 | 
--------------------------------------------------------------------------------
/vision/src/test/kotlin/QuickstartTest.kt:
--------------------------------------------------------------------------------
 1 | // Copyright 2018 Google Inc.
 2 | //
 3 | //  Licensed under the Apache License, Version 2.0 (the "License");
 4 | //  you may not use this file except in compliance with the License.
 5 | //  You may obtain a copy of the License at
 6 | //
 7 | //        http://www.apache.org/licenses/LICENSE-2.0
 8 | //
 9 | //  Unless required by applicable law or agreed to in writing, software
10 | //  distributed under the License is distributed on an "AS IS" BASIS,
11 | //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | //  See the License for the specific language governing permissions and
13 | //  limitations under the License.
14 | 
15 | package com.google.vision
16 | 
17 | import org.junit.Test
18 | 
19 | internal class QuickstartTest {
20 | 
21 |     @Test
22 |     fun mainTest() {
23 |         /*
24 |          * Pass the image to the Vision API, expect a non-error response.
25 |          */
26 |         val args = arrayOf("./resources/doggo.jpg")
27 |         main(args)
28 |     }
29 | 
30 |     @Test(expected = NoSuchFileException::class)
31 |     fun mainNoImageTest() {
32 |         /*
33 |          * Pass invalid image path to the Vision API, expect an exception.
34 |          */
35 |         val args = arrayOf("does/not/exist.jpg")
36 |         main(args)
37 |     }
38 | }
39 | 
--------------------------------------------------------------------------------