main 5135af00b4aa cached
219 files
527.1 KB
135.7k tokens
485 symbols
1 requests
Download .txt
Showing preview only (595K chars total). Download the full file or copy to clipboard to get everything.
Repository: GoogleCloudPlatform/getting-started-java
Branch: main
Commit: 5135af00b4aa
Files: 219
Total size: 527.1 KB

Directory structure:
gitextract_3yeindkx/

├── .github/
│   ├── CODEOWNERS
│   ├── blunderbuss.yml
│   └── sync-repo-settings.yaml
├── .gitignore
├── .gitmodules
├── .kokoro/
│   ├── java11/
│   │   ├── common.cfg
│   │   ├── continuous.cfg
│   │   ├── periodic.cfg
│   │   └── presubmit.cfg
│   ├── java8/
│   │   ├── common.cfg
│   │   ├── continuous.cfg
│   │   ├── periodic.cfg
│   │   └── presubmit.cfg
│   ├── lint/
│   │   ├── common.cfg
│   │   └── presubmit.cfg
│   ├── tests/
│   │   ├── run_diff_only.sh
│   │   ├── run_lint.sh
│   │   └── run_tests.sh
│   └── trampoline.sh
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── appengine-standard-java8/
│   ├── deployAll.sh
│   ├── helloworld-gae-javasdk-tools/
│   │   ├── README.md
│   │   ├── build.gradle
│   │   ├── gradle/
│   │   │   └── wrapper/
│   │   │       ├── gradle-wrapper.jar
│   │   │       └── gradle-wrapper.properties
│   │   ├── gradlew
│   │   ├── gradlew.bat
│   │   ├── pom.xml
│   │   ├── settings.gradle
│   │   └── src/
│   │       ├── main/
│   │       │   ├── java/
│   │       │   │   └── com/
│   │       │   │       └── example/
│   │       │   │           └── appengine/
│   │       │   │               └── java8/
│   │       │   │                   └── HelloAppEngine.java
│   │       │   └── webapp/
│   │       │       ├── WEB-INF/
│   │       │       │   └── appengine-web.xml
│   │       │       └── index.jsp
│   │       └── test/
│   │           └── java/
│   │               └── com/
│   │                   └── example/
│   │                       └── appengine/
│   │                           └── java8/
│   │                               └── HelloAppEngineTest.java
│   ├── kotlin-appengine-standard/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── nbactions.xml
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           ├── kotlin/
│   │           │   └── HomeController.kt
│   │           └── webapp/
│   │               └── WEB-INF/
│   │                   ├── appengine-web.xml
│   │                   └── logging.properties
│   ├── kotlin-sb-appengine-standard/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── nbactions.xml
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           ├── kotlin/
│   │           │   └── org/
│   │           │       └── jetbrains/
│   │           │           └── kotlin/
│   │           │               └── demo/
│   │           │                   ├── Application.kt
│   │           │                   ├── Greeting.kt
│   │           │                   └── GreetingController.kt
│   │           └── webapp/
│   │               └── WEB-INF/
│   │                   ├── appengine-web.xml
│   │                   └── logging.properties
│   └── kotlin-spark-appengine-standard/
│       ├── .gitignore
│       ├── README.md
│       ├── pom.xml
│       └── src/
│           └── main/
│               ├── kotlin/
│               │   ├── MainApp.kt
│               │   └── SparkInitFilter.kt
│               └── webapp/
│                   └── WEB-INF/
│                       ├── appengine-web.xml
│                       └── logging.properties
├── background/
│   ├── README.md
│   ├── pom.xml
│   ├── sample_message.json
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── getstarted/
│       │   │           └── background/
│       │   │               ├── functions/
│       │   │               │   ├── CreateServlet.java
│       │   │               │   └── TranslateServlet.java
│       │   │               ├── objects/
│       │   │               │   ├── PubSubMessage.java
│       │   │               │   ├── TranslateAttributes.java
│       │   │               │   └── TranslateMessage.java
│       │   │               └── util/
│       │   │                   └── BackgroundContextListener.java
│       │   └── webapp/
│       │       ├── base.jsp
│       │       ├── form.jsp
│       │       └── list.jsp
│       └── test/
│           └── java/
│               └── com/
│                   └── getstarted/
│                       └── background/
│                           └── UserJourneyTestIT.java
├── bookshelf/
│   └── 1-cloud-run/
│       ├── README.md
│       ├── pom.xml
│       └── src/
│           └── main/
│               ├── java/
│               │   └── com/
│               │       └── example/
│               │           └── getstarted/
│               │               ├── basicactions/
│               │               │   ├── CreateBookServlet.java
│               │               │   ├── DeleteBookServlet.java
│               │               │   ├── ErrorsBookServlet.java
│               │               │   ├── ListBookServlet.java
│               │               │   ├── ReadBookServlet.java
│               │               │   └── UpdateBookServlet.java
│               │               ├── daos/
│               │               │   ├── BookDao.java
│               │               │   └── FirestoreDao.java
│               │               ├── objects/
│               │               │   ├── Book.java
│               │               │   └── Result.java
│               │               └── util/
│               │                   ├── BookshelfContextListener.java
│               │                   └── CloudStorageHelper.java
│               └── webapp/
│                   ├── WEB-INF/
│                   │   └── web.xml
│                   ├── base.jsp
│                   ├── form.jsp
│                   ├── list.jsp
│                   └── view.jsp
├── bookshelf-standard/
│   ├── 2-structured-data/
│   │   ├── README.md
│   │   ├── jenkins.sh
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           ├── java/
│   │           │   └── com/
│   │           │       └── example/
│   │           │           └── getstarted/
│   │           │               ├── basicactions/
│   │           │               │   ├── CreateBookServlet.java
│   │           │               │   ├── DeleteBookServlet.java
│   │           │               │   ├── ListBookServlet.java
│   │           │               │   ├── ReadBookServlet.java
│   │           │               │   └── UpdateBookServlet.java
│   │           │               ├── daos/
│   │           │               │   ├── BookDao.java
│   │           │               │   ├── CloudSqlDao.java
│   │           │               │   └── DatastoreDao.java
│   │           │               ├── objects/
│   │           │               │   ├── Book.java
│   │           │               │   └── Result.java
│   │           │               └── util/
│   │           │                   └── DatastoreSessionFilter.java
│   │           └── webapp/
│   │               ├── WEB-INF/
│   │               │   ├── appengine-web.xml
│   │               │   ├── logging.properties
│   │               │   └── web.xml
│   │               ├── base.jsp
│   │               ├── form.jsp
│   │               ├── list.jsp
│   │               └── view.jsp
│   ├── 3-binary-data/
│   │   ├── README.md
│   │   ├── jenkins.sh
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           ├── java/
│   │           │   └── com/
│   │           │       └── example/
│   │           │           └── getstarted/
│   │           │               ├── basicactions/
│   │           │               │   ├── CreateBookServlet.java
│   │           │               │   ├── DeleteBookServlet.java
│   │           │               │   ├── ListBookServlet.java
│   │           │               │   ├── ReadBookServlet.java
│   │           │               │   └── UpdateBookServlet.java
│   │           │               ├── daos/
│   │           │               │   ├── BookDao.java
│   │           │               │   ├── CloudSqlDao.java
│   │           │               │   └── DatastoreDao.java
│   │           │               ├── objects/
│   │           │               │   ├── Book.java
│   │           │               │   └── Result.java
│   │           │               └── util/
│   │           │                   ├── CloudStorageHelper.java
│   │           │                   └── DatastoreSessionFilter.java
│   │           └── webapp/
│   │               ├── WEB-INF/
│   │               │   ├── appengine-web.xml
│   │               │   ├── logging.properties
│   │               │   └── web.xml
│   │               ├── base.jsp
│   │               ├── form.jsp
│   │               ├── list.jsp
│   │               └── view.jsp
│   ├── 4-auth/
│   │   ├── README.md
│   │   ├── jenkins.sh
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           ├── java/
│   │           │   └── com/
│   │           │       └── example/
│   │           │           └── getstarted/
│   │           │               ├── auth/
│   │           │               │   ├── ListByUserFilter.java
│   │           │               │   ├── LoginServlet.java
│   │           │               │   ├── LogoutFilter.java
│   │           │               │   └── LogoutServlet.java
│   │           │               ├── basicactions/
│   │           │               │   ├── CreateBookServlet.java
│   │           │               │   ├── DeleteBookServlet.java
│   │           │               │   ├── ListBookServlet.java
│   │           │               │   ├── ListByUserServlet.java
│   │           │               │   ├── ReadBookServlet.java
│   │           │               │   └── UpdateBookServlet.java
│   │           │               ├── daos/
│   │           │               │   ├── BookDao.java
│   │           │               │   ├── CloudSqlDao.java
│   │           │               │   └── DatastoreDao.java
│   │           │               ├── objects/
│   │           │               │   ├── Book.java
│   │           │               │   └── Result.java
│   │           │               └── util/
│   │           │                   ├── CloudStorageHelper.java
│   │           │                   └── DatastoreSessionFilter.java
│   │           └── webapp/
│   │               ├── WEB-INF/
│   │               │   ├── appengine-web.xml
│   │               │   ├── datastore-indexes.xml
│   │               │   ├── logging.properties
│   │               │   └── web.xml
│   │               ├── base.jsp
│   │               ├── form.jsp
│   │               ├── list.jsp
│   │               └── view.jsp
│   └── 5-logging/
│       ├── README.md
│       ├── jenkins.sh
│       ├── pom.xml
│       └── src/
│           └── main/
│               ├── java/
│               │   └── com/
│               │       └── example/
│               │           └── getstarted/
│               │               ├── auth/
│               │               │   ├── ListByUserFilter.java
│               │               │   ├── LoginServlet.java
│               │               │   ├── LogoutFilter.java
│               │               │   └── LogoutServlet.java
│               │               ├── basicactions/
│               │               │   ├── CreateBookServlet.java
│               │               │   ├── DeleteBookServlet.java
│               │               │   ├── ListBookServlet.java
│               │               │   ├── ListByUserServlet.java
│               │               │   ├── ReadBookServlet.java
│               │               │   └── UpdateBookServlet.java
│               │               ├── daos/
│               │               │   ├── BookDao.java
│               │               │   ├── CloudSqlDao.java
│               │               │   └── DatastoreDao.java
│               │               ├── objects/
│               │               │   ├── Book.java
│               │               │   └── Result.java
│               │               └── util/
│               │                   ├── CloudStorageHelper.java
│               │                   └── DatastoreSessionFilter.java
│               └── webapp/
│                   ├── WEB-INF/
│                   │   ├── appengine-web.xml
│                   │   ├── datastore-indexes.xml
│                   │   ├── logging.properties
│                   │   └── web.xml
│                   ├── base.jsp
│                   ├── form.jsp
│                   ├── list.jsp
│                   └── view.jsp
├── codecov.yml
├── gce/
│   ├── README.md
│   ├── config/
│   │   └── base/
│   │       ├── etc/
│   │       │   └── java-util-logging.properties
│   │       ├── modules/
│   │       │   └── gce.mod
│   │       └── resources/
│   │           └── jetty-logging.properties
│   ├── makeProject
│   ├── pom.xml
│   ├── scripts/
│   │   └── startup-script.sh
│   └── src/
│       ├── main/
│       │   ├── appengine/
│       │   │   └── app.yaml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── example/
│       │   │           └── getstarted/
│       │   │               └── basicactions/
│       │   │                   └── HelloworldController.java
│       │   └── webapp/
│       │       └── WEB-INF/
│       │           └── web.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── example/
│                       └── getstarted/
│                           └── basicactions/
│                               └── UserJourneyTestIT.java
├── helloworld-jsp/
│   ├── README.md
│   ├── build.gradle
│   ├── eclipse-launch-profiles/
│   │   ├── AppEngineDeploy.launch
│   │   └── AppEngineRun.launch
│   ├── gradle/
│   │   └── wrapper/
│   │       ├── gradle-wrapper.jar
│   │       └── gradle-wrapper.properties
│   ├── gradlew
│   ├── gradlew.bat
│   ├── nbactions.xml
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── appengine/
│           │   └── app.yaml
│           ├── java/
│           │   └── org/
│           │       └── example/
│           │           └── appengine/
│           │               └── hello/
│           │                   └── HelloInfo.java
│           └── webapp/
│               ├── WEB-INF/
│               │   ├── logging.properties
│               │   └── web.xml
│               └── hello.jsp
├── mvnw.cmd
└── renovate.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/CODEOWNERS
================================================
# Code owners file.
# This file controls who is tagged for review for any given pull request.

# The java-samples-reviewers team is the default owner for anything not
# explicitly taken by someone else.
*                         @GoogleCloudPlatform/java-samples-reviewers


================================================
FILE: .github/blunderbuss.yml
================================================
assign_issues:
  - GoogleCloudPlatform/java-samples-reviewers
assign_prs:
  - GoogleCloudPlatform/java-samples-reviewers


================================================
FILE: .github/sync-repo-settings.yaml
================================================
rebaseMergeAllowed: true
squashMergeAllowed: true
mergeCommitAllowed: false
branchProtectionRules:
- pattern: main
  isAdminEnforced: false
  requiredStatusCheckContexts:
    - 'Kokoro CI - Java 8'
    - 'Kokoro CI - Java 11'
    - 'Kokoro CI - Lint'
    - 'cla/google'
  requiredApprovingReviewCount: 1
  requiresCodeOwnerReviews: true
  requiresStrictStatusChecks: true
permissionRules:
  - team: java-samples-reviewers
    permission: push
  - team: yoshi-java
    permission: push
  - team: devrel-java-admin
    permission: admin
  - team: yoshi-admins
    permission: admin


================================================
FILE: .gitignore
================================================
# Eclipse files
.project
.classpath
.settings

# IntelliJ IDEA
.Idea
*.iml
.idea/

# Target folders
target/
build/
out/
.gradle/
bin/

## Vim ##
# swap
[._]*.s[a-w][a-z]
[._]s[a-w][a-z]
# session
Session.vim
# temporary
.netrwhist
*~
# auto-generated tag files
tags

## Secrets ##
client-secret.json

**/pom.xml.versionsBackup

================================================
FILE: .gitmodules
================================================


================================================
FILE: .kokoro/java11/common.cfg
================================================
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Format: //devtools/kokoro/config/proto/build.proto

# Build timeout of 5 hours
timeout_mins: 300

# Download trampoline resources.
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"

# Use the trampoline script to run in docker.
build_file: "getting-started-java/.kokoro/trampoline.sh"

action {
  define_artifacts {
    regex: "**/*sponge_log.xml"
  }
}

# Set the JAVA VERSION env var.
env_vars: {
    key: "JAVA_VERSION"
    value: "1.8,11"
}

# Configure the docker image for kokoro-trampoline.
env_vars: {
    key: "TRAMPOLINE_IMAGE"
    value: "gcr.io/cloud-devrel-kokoro-resources/java11"
}


================================================
FILE: .kokoro/java11/continuous.cfg
================================================
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Format: //devtools/kokoro/config/proto/build.proto

# Tell the trampoline which tests to run.
env_vars: {
    key: "TRAMPOLINE_BUILD_FILE"
    value: "github/getting-started-java/.kokoro/tests/run_tests.sh"
}


================================================
FILE: .kokoro/java11/periodic.cfg
================================================
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Format: //devtools/kokoro/config/proto/build.proto

# Tell the trampoline which build file to use.
env_vars: {
    key: "TRAMPOLINE_BUILD_FILE"
    value: "github/getting-started-java/.kokoro/tests/run_tests.sh"
}


================================================
FILE: .kokoro/java11/presubmit.cfg
================================================
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Format: //devtools/kokoro/config/proto/build.proto

# Tell the trampoline which build file to use.
env_vars: {
    key: "TRAMPOLINE_BUILD_FILE"
    value: "github/getting-started-java/.kokoro/tests/run_diff_only.sh"
}


================================================
FILE: .kokoro/java8/common.cfg
================================================
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Format: //devtools/kokoro/config/proto/build.proto

# Build timeout of 5 hours
timeout_mins: 300

# Download trampoline resources.
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"

# Use the trampoline script to run in docker.
build_file: "getting-started-java/.kokoro/trampoline.sh"

action {
  define_artifacts {
    regex: "**/*sponge_log.xml"
  }
}

# Set the JAVA VERSION env var.
env_vars: {
    key: "JAVA_VERSION"
    value: "1.8"
}

# Configure the docker image for kokoro-trampoline.
env_vars: {
    key: "TRAMPOLINE_IMAGE"
    value: "gcr.io/cloud-devrel-kokoro-resources/java8"
}


================================================
FILE: .kokoro/java8/continuous.cfg
================================================
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Format: //devtools/kokoro/config/proto/build.proto

# Tell trampoline which tests to run.
env_vars: {
    key: "TRAMPOLINE_BUILD_FILE"
    value: "github/getting-started-java/.kokoro/tests/run_tests.sh"
}



================================================
FILE: .kokoro/java8/periodic.cfg
================================================
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Format: //devtools/kokoro/config/proto/build.proto

# Tell the trampoline which build file to use.
env_vars: {
    key: "TRAMPOLINE_BUILD_FILE"
    value: "github/getting-started-java/.kokoro/tests/run_tests.sh"
}



================================================
FILE: .kokoro/java8/presubmit.cfg
================================================
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Format: //devtools/kokoro/config/proto/build.proto

# Tell the trampoline which build file to use.
env_vars: {
    key: "TRAMPOLINE_BUILD_FILE"
    value: "github/getting-started-java/.kokoro/tests/run_diff_only.sh"
}


================================================
FILE: .kokoro/lint/common.cfg
================================================
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Format: //devtools/kokoro/config/proto/build.proto

# Use the trampoline to bounce the script into docker.
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"
build_file: "getting-started-java/.kokoro/trampoline.sh"
env_vars: {
    key: "TRAMPOLINE_IMAGE"
    value: "gcr.io/cloud-devrel-kokoro-resources/java8"
}
env_vars: {
    key: "TRAMPOLINE_BUILD_FILE"
    value: "github/getting-started-java/.kokoro/tests/run_lint.sh"
}

# Access btlr binaries used in the tests
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/btlr"


# Upload logs to result-store
action {
  define_artifacts {
    regex: "**/*sponge_log.xml"
  }
}


================================================
FILE: .kokoro/lint/presubmit.cfg
================================================
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Format: //devtools/kokoro/config/proto/build.proto

# Tell the trampoline which build file to use.
env_vars: {
    key: "GIT_DIFF"
    value: "origin/main... ."
}


================================================
FILE: .kokoro/tests/run_diff_only.sh
================================================
#!/usr/bin/env bash
# Copyright 2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
mydir="${0%/*}"
"$mydir"/run_tests.sh --only-diff

================================================
FILE: .kokoro/tests/run_lint.sh
================================================
#!/usr/bin/env bash
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# `-e` enables the script to automatically fail when a command fails
# `-o pipefail` sets the exit code to the rightmost comment to exit with a non-zero
set -eo pipefail

# If on kokoro, add btlr to the path and cd into repo root
if [ -n "$KOKORO_GFILE_DIR" ]; then
  bltr_dir="$KOKORO_GFILE_DIR/v0.0.1/"
  chmod +x "${bltr_dir}"btlr
  export PATH="$PATH:$bltr_dir"
  cd github/getting-started-java || exit
fi

opts=()
if [ -n "$GIT_DIFF" ]; then
  opts+=(
    "--git-diff"
    "$GIT_DIFF"
  )
fi

btlr "${opts[@]}" run "**/pom.xml" -- mvn -P lint --quiet --batch-mode checkstyle:check


================================================
FILE: .kokoro/tests/run_tests.sh
================================================
#!/bin/bash
# Copyright 2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# `-e` enables the script to automatically fail when a command fails
# `-o pipefail` sets the exit code to the rightmost comment to exit with a non-zero
set -eo pipefail
# Enables `**` to include files nested inside sub-folders
shopt -s globstar

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

# `--script-debug` can be added make local testing of this script easier
if [[ $* == *--script-debug* ]]; then
    SCRIPT_DEBUG="true"
    JAVA_VERSION="1.8"
else
    SCRIPT_DEBUG="false"
fi

# `--only-diff` will only run tests on projects container changes from the main branch.
if [[ $* == *--only-diff* ]]; then
    ONLY_DIFF="true"
else
    ONLY_DIFF="false"
fi

# Verify Java versions have been specified
if [[ -z ${JAVA_VERSION+x} ]]; then
    echo -e "'JAVA_VERSION' env var should be a comma delimited list of valid java versions."
    exit 1
fi

if [[ "$SCRIPT_DEBUG" != "true" ]]; then
    # Update `gcloud` and log versioning for debugging
    apt update && apt -y upgrade google-cloud-sdk

    echo "********** GCLOUD INFO ***********"
    gcloud -v
    echo "********** MAVEN INFO  ***********"
    mvn -v
    echo "********** GRADLE INFO ***********"
    gradle -v

    # Setup required env variables
    export GOOGLE_CLOUD_PROJECT=java-docs-samples-testing
    export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/secrets/java-docs-samples-service-account.json

    # Grab latest version of secrets
    mkdir -p "${KOKORO_GFILE_DIR}/secrets"
    gcloud secrets versions access latest --secret="java-docs-samples-service-account" > "$GOOGLE_APPLICATION_CREDENTIALS"
    gcloud secrets versions access latest --secret="java-firestore-samples-secrets" > "${KOKORO_GFILE_DIR}/secrets/java-firestore-samples-secrets.txt"
    
    # Execute secret file contents
    source "${KOKORO_GFILE_DIR}/secrets/java-firestore-samples-secrets.txt"
    # Activate service account
    gcloud auth activate-service-account \
        --key-file="$GOOGLE_APPLICATION_CREDENTIALS" \
        --project="$GOOGLE_CLOUD_PROJECT"

    cd github/getting-started-java
fi

echo -e "\n******************** TESTING PROJECTS ********************"
# Switch to 'fail at end' to allow all tests to complete before exiting.
set +e
# Use RTN to return a non-zero value if the test fails.
RTN=0
ROOT=$(pwd)

git config --global --add safe.directory $PWD

# Find all POMs in the repository (may break on whitespace).
for file in **/pom.xml; do
    cd "$ROOT"
    # Navigate to the project folder.
    file=$(dirname "$file")
    cd "$file"

    # If $DIFF_ONLY is true, skip projects without changes.
    if [[ "$ONLY_DIFF" = "true" ]]; then
        git diff --quiet origin/main.. .
        CHANGED=$?
        if [[ "$CHANGED" -eq 0 ]]; then
          # echo -e "\n Skipping $file: no changes in folder.\n"
          continue
        fi
    fi

    echo "------------------------------------------------------------"
    echo "- testing $file"
    echo "------------------------------------------------------------"

    # Fail the tests if no Java version was found.
    POM_JAVA=$(grep -oP '(?<=<maven.compiler.target>).*?(?=</maven.compiler.target>)' pom.xml)
    ALLOWED_VERSIONS=("1.8" "11")
    # shellcheck disable=SC2199
    # shellcheck disable=SC2076
    if [[ "$POM_JAVA" = "" ]] || [[ !  "${ALLOWED_VERSIONS[@]}" =~ "${POM_JAVA}" ]]; then
        RTN=1
        echo -e "\n Testing failed: Unable to determine Java version. Please set in pom:"
        echo -e "\n<properties>"
        echo -e "  <maven.compiler.target>1.8</maven.compiler.target>"
        echo -e "  <maven.compiler.source>1.8</maven.compiler.source>"
        echo -e "</properties>\n"
        continue
    fi

    # Skip tests that don't have the correct Java version.
    # shellcheck disable=SC2076
    if ! [[ ",$JAVA_VERSION," =~ ",$POM_JAVA," ]]; then
        echo -e "\n Skipping tests: Java version ($POM_JAVA) not required ($JAVA_VERSION)\n"
        continue
    fi

    # Use maven to execute the tests for the project.
    mvn --quiet --batch-mode --fail-at-end clean verify \
       -Dfile.encoding="UTF-8" \
       -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn \
       -Dmaven.test.redirectTestOutputToFile=true \
       -Dbigtable.projectID="${GOOGLE_CLOUD_PROJECT}" \
       -Dbigtable.instanceID=instance
    EXIT=$?

    if [[ $EXIT -ne 0 ]]; then
      RTN=1
      echo -e "\n Testing failed: Maven returned a non-zero exit code. \n"
    else
      echo -e "\n Testing completed.\n"
    fi

done

exit "$RTN"


================================================
FILE: .kokoro/trampoline.sh
================================================
#!/bin/bash
# Copyright 2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

python3 "${KOKORO_GFILE_DIR}/trampoline_v1.py"


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Code of Conduct

As contributors and maintainers of this project,
and in the interest of fostering an open and welcoming community,
we pledge to respect all people who contribute through reporting issues,
posting feature requests, updating documentation,
submitting pull requests or patches, and other activities.

We are committed to making participation in this project
a harassment-free experience for everyone,
regardless of level of experience, gender, gender identity and expression,
sexual orientation, disability, personal appearance,
body size, race, ethnicity, age, religion, or nationality.

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information,
such as physical or electronic
addresses, without explicit permission
* Other unethical or unprofessional conduct.

Project maintainers have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct.
By adopting this Code of Conduct,
project maintainers commit themselves to fairly and consistently
applying these principles to every aspect of managing this project.
Project maintainers who do not follow or enforce the Code of Conduct
may be permanently removed from the project team.

This code of conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.

Instances of abusive, harassing, or otherwise unacceptable behavior
may be reported by opening an issue
or contacting one or more of the project maintainers.

This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0,
available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)


================================================
FILE: CONTRIBUTING.md
================================================
# How to become a contributor and submit your own code

## Contributor License Agreements

We'd love to accept your sample apps and patches! Before we can take them, we
have to jump a couple of legal hurdles.

Please fill out either the individual or corporate Contributor License Agreement
(CLA):

  * If you are an individual writing original source code and you're sure you
    own the intellectual property, then you'll need to sign an [individual CLA](https://developers.google.com/open-source/cla/individual).
  * If you work for a company that wants to allow you to contribute your work,
    then you'll need to sign a [corporate CLA](https://developers.google.com/open-source/cla/corporate).

Follow either of the two links above to access the appropriate CLA and
instructions for how to sign and return it. Once we receive it, we'll be able to
accept your pull requests.

## Contributing A Patch

1. Submit an issue describing your proposed change to the repository in question.
2. The repository owner will respond to your issue promptly.
3. If your proposed change is accepted, and you haven't already done so, sign a
   CLA (see details above).
4. Fork the desired repo, then develop and test your code changes.
5. Ensure that your code adheres to the existing style in the sample to which
   you are contributing. Refer to the [Google Java Style Guide](http://google.github.io/styleguide/javaguide.html) and the
   [Google Cloud Platform Community Style Guide](https://cloud.google.com/community/tutorials/styleguide) for the
   recommended coding standards for this organization.
6. Ensure that your code has an appropriate set of unit tests which all pass.
7. Submit a pull request.


================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
# Getting started on Google Cloud Platform for Java®

[![CircleCI Build Status](https://circleci.com/gh/GoogleCloudPlatform/getting-started-java.svg?style=shield&circle-token=51b789e102291cbeae6817678d02da0f4cf25f1f)](https://circleci.com/gh/GoogleCloudPlatform/getting-started-java)
[![Coverage Status](https://codecov.io/gh/GoogleCloudPlatform/getting-started-java/branch/main/graph/badge.svg)](https://codecov.io/gh/GoogleCloudPlatform/getting-started-java)

The code for the samples is contained in individual folders on this repository.
Follow the instructions at [Getting Started on Google Cloud Platform for Java](https://cloud.google.com/java/) or the README files in each folder for instructions on how to run locally and deploy.

Managed VMs on Google Cloud Platform use the [Java Servlets](http://www.oracle.com/technetwork/java/overview-137084.html) & [Java Server Pages](http://www.oracle.com/technetwork/java/index-jsp-138231.html) on [Jetty](http://www.eclipse.org/jetty/).

1. [Helloworld-servlet](helloworld-servlet) Servlet based Hello World app
1. [HelloWorld-jsp](helloworld-jsp) Java Server Pages based Hello World app
1. [Bookshelf](bookshelf) A full featured app that demonstrates Authentication and CRUD operations for [Cloud Datastore](https://cloud.google.com/datastore/docs/concepts/overview?hl=en) and [Cloud SQL](https://cloud.google.com/sql/docs/introduction).

## Google Cloud Samples

To browse ready to use code samples check [Google Cloud samples](https://cloud.google.com/docs/samples).

## Contributing changes

* See [CONTRIBUTING.md](CONTRIBUTING.md)


## Licensing

* See [LICENSE](LICENSE)

Java is a registered trademark of Oracle Corporation and/or its affiliates.


================================================
FILE: appengine-standard-java8/deployAll.sh
================================================
#!/bin/bash
# Copyright 2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# set -x
# set -v

# gcloud config configurations activate qa

for app in "helloworld" "kotlin-appengine-standard" \
      "kotlin-sb-appengine-standard" \
      "springboot-appengine-standard" "kotlin-spark-appengine-standard" \
      "sparkjava-appengine-standard"
do
  (cd "${app}"
      sed --in-place='.xx' "s/<\/runtime>/<\/runtime><service>${app}<\/service>/" \
          src/main/webapp/WEB-INF/appengine-web.xml
      mvn -B --fail-at-end -q package appengine:deploy -Dapp.deploy.version="1" \
          -Dapp.stage.quickstart=true -Dapp.deploy.force=true -Dapp.deploy.promote=true \
          -Dapp.deploy.projectId="${GOOGLE_CLOUD_PROJECT}" -DskipTests=true
      mv src/main/webapp/WEB-INF/appengine-web.xml.xx src/main/webapp/WEB-INF/appengine-web.xml)
done

echo "STATUS: ${?}"


================================================
FILE: appengine-standard-java8/helloworld-gae-javasdk-tools/README.md
================================================
HelloWorld for App Engine Standard (Java 8) using the App Engine Java SDK tooling
============================

This sample demonstrates how to deploy an application on Google App Engine.

See the [Google App Engine standard environment documentation][ae-docs] for more
detailed instructions.

[ae-docs]: https://cloud.google.com/appengine/docs/java/


* [Java 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html)
* [Maven](https://maven.apache.org/download.cgi) (at least 3.5)
* [Gradle](https://gradle.org/gradle-download/) (optional)
* [Google Cloud SDK](https://cloud.google.com/sdk/) (aka gcloud)

## Setup

• Download and initialize the [Cloud SDK](https://cloud.google.com/sdk/)
```
gcloud init
```
* Create an App Engine app within the current Google Cloud Project

```
gcloud app create
```

* In the `pom.xml`, update the [App Engine Maven Plugin](https://cloud.google.com/appengine/docs/standard/java/tools/maven-reference)
with your Google Cloud Project Id:

```
<plugin>
  <groupId>com.google.cloud.tools</groupId>
  <artifactId>appengine-maven-plugin</artifactId>
  <version>2.3.0</version>
  <configuration>
    <projectId>GCLOUD_CONFIG</projectId>
    <version>GCLOUD_CONFIG</version>
  </configuration>
</plugin>
```
**Note:** `GCLOUD_CONFIG` is a special version for autogenerating an App Engine 
version. Change this field to specify a specific version name.

## Maven
### Running locally

    mvn clean package appengine:run

To use visit: http://localhost:8080/

### Deploying

Update `src/main/webapp/WEB-INF/appengine-web.xml` `<application>` tag with the Project ID.

    mvn clean package appengine:deploy

To use visit:  https://YOUR-PROJECT-ID.appspot.com

## Gradle

For more information see the [plugin project](https://github.com/GoogleCloudPlatform/gradle-appengine-plugin#gradle-app-engine-plugin-) on github.

### Running locally

    gradle appengineRun

If you do not have gradle installed, you can run using `./gradlew appengineRun`.

To use visit: http://localhost:8080/

### Deploying

Update `src/main/webapp/WEB-INF/appengine-web.xml` `<application>` tag with the Project ID.

    gradle appengineUpdate

If you do not have gradle installed, you can deploy using `./gradlew appengineDeploy`.

To use visit:  https://1-dot-YOUR-PROJECT-ID.appspot.com

This is using version-dot-project naming.

## Testing

    mvn verify

 or

    gradle test

As you add / modify the source code (`src/main/java/...`) it's very useful to add [unit testing](https://cloud.google.com/appengine/docs/java/tools/localunittesting)
to (`src/main/test/...`).  The following resources are quite useful:

* [Junit4](http://junit.org/junit4/)
* [Mockito](http://mockito.org/)
* [Truth](http://google.github.io/truth/)


================================================
FILE: appengine-standard-java8/helloworld-gae-javasdk-tools/build.gradle
================================================
// Copyright 2017 Google Inc.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// [START gradle]
buildscript {    // Configuration for building
  repositories {
    jcenter()    // Bintray's repository - a fast Maven Central mirror & more
    mavenCentral()
  }
  dependencies {
    classpath 'com.google.appengine:gradle-appengine-plugin:+'    // latest App Engine Gradle tasks
  }
}

repositories {   // repositories for Jar's you access in your code
  mavenCentral()
  jcenter()
}

apply plugin: 'java'                              // standard Java tasks
apply plugin: 'war'                               // standard Web Archive plugin
apply plugin: 'appengine'  // App Engine tasks

dependencies {
  appengineSdk 'com.google.appengine:appengine-java-sdk:1.9.93'

  compile 'com.google.appengine:appengine-api-1.0-sdk:+'  // Latest App Engine Api's
  providedCompile 'javax.servlet:javax.servlet-api:4.0.1'

  compile 'jstl:jstl:1.2'

// Add your dependencies here.
//  compile 'com.google.cloud:google-cloud:+'   // Latest Cloud API's http://googlecloudplatform.github.io/google-cloud-java

  testCompile 'junit:junit:4.13.2'
  testCompile 'com.google.truth:truth:1.2.0'
  testCompile 'org.mockito:mockito-all:1.10.19'

  testCompile 'com.google.appengine:appengine-testing:+'
  testCompile 'com.google.appengine:appengine-api-stubs:+'
  testCompile 'com.google.appengine:appengine-tools-sdk:+'
}

// Always run unit tests
appengineUpdate.dependsOn test
appengineStage.dependsOn test

// [START model]
appengine {  // App Engine tasks configuration
  downloadSdk = true
}

test {
  useJUnit()
  testLogging.showStandardStreams = true
  beforeTest { descriptor ->
     logger.lifecycle("test: " + descriptor + "  Running")
  }

  onOutput { descriptor, event ->
     logger.lifecycle("test: " + descriptor + ": " + event.message )
  }
  afterTest { descriptor, result ->
    logger.lifecycle("test: " + descriptor + ": " + result )
  }
}
// [END model]

group   = "com.example.appengine_standard_java8"        // Generated output GroupId
version = "1.0-SNAPSHOT"        // Version in generated output

sourceCompatibility = 1.8     // App Engine Flexible uses Java 8
targetCompatibility = 1.8     // App Engine Flexible uses Java 8
// [END gradle]


================================================
FILE: appengine-standard-java8/helloworld-gae-javasdk-tools/gradle/wrapper/gradle-wrapper.properties
================================================
#Tue Jun 13 16:53:48 PDT 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip


================================================
FILE: appengine-standard-java8/helloworld-gae-javasdk-tools/gradlew
================================================
#!/usr/bin/env sh

##############################################################################
##
##  Gradle start up script for UN*X
##
##############################################################################

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`"/$link"
    fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn ( ) {
    echo "$*"
}

die ( ) {
    echo
    echo "$*"
    echo
    exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
  CYGWIN* )
    cygwin=true
    ;;
  Darwin* )
    darwin=true
    ;;
  MINGW* )
    msys=true
    ;;
  NONSTOP* )
    nonstop=true
    ;;
esac

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD="$JAVA_HOME/jre/sh/java"
    else
        JAVACMD="$JAVA_HOME/bin/java"
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD="java"
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
    MAX_FD_LIMIT=`ulimit -H -n`
    if [ $? -eq 0 ] ; then
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
            MAX_FD="$MAX_FD_LIMIT"
        fi
        ulimit -n $MAX_FD
        if [ $? -ne 0 ] ; then
            warn "Could not set maximum file descriptor limit: $MAX_FD"
        fi
    else
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
    fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
    JAVACMD=`cygpath --unix "$JAVACMD"`

    # We build the pattern for arguments to be converted via cygpath
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
    SEP=""
    for dir in $ROOTDIRSRAW ; do
        ROOTDIRS="$ROOTDIRS$SEP$dir"
        SEP="|"
    done
    OURCYGPATTERN="(^($ROOTDIRS))"
    # Add a user-defined pattern to the cygpath arguments
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
    fi
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    i=0
    for arg in "$@" ; do
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option

        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
        else
            eval `echo args$i`="\"$arg\""
        fi
        i=$((i+1))
    done
    case $i in
        (0) set -- ;;
        (1) set -- "$args0" ;;
        (2) set -- "$args0" "$args1" ;;
        (3) set -- "$args0" "$args1" "$args2" ;;
        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
    esac
fi

# Escape application args
save ( ) {
    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
    echo " "
}
APP_ARGS=$(save "$@")

# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"

# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
  cd "$(dirname "$0")"
fi

exec "$JAVACMD" "$@"


================================================
FILE: appengine-standard-java8/helloworld-gae-javasdk-tools/gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto init

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:init
@rem Get command-line arguments, handling Windows variants

if not "%OS%" == "Windows_NT" goto win9xME_args

:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2

:win9xME_args_slurp
if "x%~1" == "x" goto execute

set CMD_LINE_ARGS=%*

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: appengine-standard-java8/helloworld-gae-javasdk-tools/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2017 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- [START pom] -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>

  <groupId>com.example.appengine_standard_java8</groupId>
  <artifactId>helloworld_gae_tooling</artifactId>

  <!-- [START_EXCLUDE silent] -->
  <!-- Parent POM defines common plugins and properties. -->
  <parent>
    <groupId>com.google.cloud.samples</groupId>
    <artifactId>shared-configuration</artifactId>
    <version>1.2.0</version>
  </parent>
  <!-- [END_EXCLUDE] -->

  <!-- [START properties] -->
  <properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <!-- [START_EXCLUDE silent] -->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <maven.compiler.showDeprecation>true</maven.compiler.showDeprecation>
    <archiveClasses>true</archiveClasses>
    <failOnMissingWebXml>false</failOnMissingWebXml>
    <!-- [END_EXCLUDE] -->
  </properties>
  <!-- [END properties] -->

  <dependencies>
    <!-- Compile/runtime dependencies -->
    <!-- [START api-dependencies] -->
    <dependency>
      <groupId>com.google.appengine</groupId>
      <artifactId>appengine-api-1.0-sdk</artifactId>
      <version>2.0.15</version>
    </dependency>
    <!-- [END api-dependencies] -->

    <!-- [START servlet] -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <type>jar</type>
      <scope>provided</scope>
    </dependency>
    <!-- [END servlet] -->

    <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
    <!-- [START_EXCLUDE silent] -->
    <!-- Test Dependencies -->
    <dependency>
      <groupId>com.google.appengine</groupId>
      <artifactId>appengine-testing</artifactId>
      <version>2.0.15</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.google.appengine</groupId>
      <artifactId>appengine-api-stubs</artifactId>
      <version>2.0.15</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>com.google.appengine</groupId>
      <artifactId>appengine-tools-sdk</artifactId>
      <version>2.0.15</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>com.google.truth</groupId>
      <artifactId>truth</artifactId>
      <version>1.2.0</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-core</artifactId>
      <version>4.5.0</version>
      <scope>test</scope>
    </dependency>
    <!-- [END_EXCLUDE] -->
  </dependencies>

  <build>
    <!-- for hot reload of the web application-->
    <outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
    <plugins>
      <!-- [START gaejavaplugin] -->
      <plugin>
        <groupId>com.google.cloud.tools</groupId>
        <artifactId>appengine-maven-plugin</artifactId>
        <version>2.4.4</version>
        <configuration>
          <!-- can be set w/ -DprojectId=myProjectId on command line -->
          <projectId>GCLOUD_CONFIG</projectId>
          <!-- set the GAE version or use "GCLOUD_CONFIG" for an autogenerated GAE version -->
          <version>GCLOUD_CONFIG</version>
          <fullScanSeconds>1</fullScanSeconds>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.11.0</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
      <!-- [END gaejavaplugin] -->

      <!-- [START_EXCLUDE silent] -->
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>versions-maven-plugin</artifactId>
        <version>2.11.0</version>
        <executions>
          <execution>
            <phase>compile</phase>
            <goals>
              <goal>display-dependency-updates</goal>
              <goal>display-plugin-updates</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.4.0</version>
      </plugin>

      <plugin>
        <artifactId>maven-clean-plugin</artifactId>
        <version>3.3.2</version>
      </plugin>

      <plugin>
        <artifactId>maven-install-plugin</artifactId>
        <version>3.1.1</version>
      </plugin>

      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>3.1.2</version>
      </plugin>

      <plugin>
        <artifactId>maven-site-plugin</artifactId>
        <version>3.12.1</version>
      </plugin>

      <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>3.3.0</version>
      </plugin>

      <plugin>
        <artifactId>maven-deploy-plugin</artifactId>
        <version>3.0.0</version>
      </plugin>

      <plugin>
        <artifactId>maven-enforcer-plugin</artifactId>
        <version>3.1.0</version>
        <executions>
          <execution>
            <id>enforce-maven</id>
            <goals>
              <goal>enforce</goal>
            </goals>
            <configuration>
              <rules>
                <requireMavenVersion>
                  <version>3.5</version>
                </requireMavenVersion>
                <requirePluginVersions>
                   <message>Best Practice is to always define plugin versions!</message>
                   <banLatest>true</banLatest>
                   <banRelease>true</banRelease>
                   <phases>clean,deploy,verify,appengine:run,appengine:deploy,appengine:update,appengine:devappaserver,site</phases>
                </requirePluginVersions>
              </rules>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <!-- [END_EXCLUDE] -->
    </plugins>
  </build>
</project>
<!-- [END pom] -->


================================================
FILE: appengine-standard-java8/helloworld-gae-javasdk-tools/settings.gradle
================================================
/*
 * This settings file was generated by the Gradle 'init' task.
 *
 * The settings file is used to specify which projects to include in your build.
 * In a single project build this file can be empty or even removed.
 *
 * Detailed information about configuring a multi-project build in Gradle can be found
 * in the user guide at https://docs.gradle.org/3.5/userguide/multi_project_builds.html
 */

/*
// To declare projects as part of a multi-project build use the 'include' method
include 'shared'
include 'api'
include 'services:webservice'
*/

rootProject.name = 'helloworld_gae_tooling'


================================================
FILE: appengine-standard-java8/helloworld-gae-javasdk-tools/src/main/java/com/example/appengine/java8/HelloAppEngine.java
================================================
/*
 * Copyright 2017 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.appengine.java8;

// [START example]
import com.google.appengine.api.utils.SystemProperty;
import java.io.IOException;
import java.util.Properties;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// With @WebServlet annotation the webapp/WEB-INF/web.xml is no longer required.
@WebServlet(name = "HelloAppEngine", value = "/hello")
public class HelloAppEngine extends HttpServlet {

  @Override
  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws IOException {

    Properties properties = System.getProperties();

    response.setContentType("text/plain");
    response.getWriter().println("Hello App Engine - Standard using "
        + SystemProperty.version.get() + " Java " + properties.get("java.specification.version"));

  }

  public static String getInfo() {
    return "Version: " + System.getProperty("java.version")
          + " OS: " + System.getProperty("os.name")
          + " User: " + System.getProperty("user.name");
  }

}
// [END example]


================================================
FILE: appengine-standard-java8/helloworld-gae-javasdk-tools/src/main/webapp/WEB-INF/appengine-web.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!--
  Copyright 2017 Google Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<!-- [START config] -->
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
  <application>helloworld-gae</application>
  <runtime>java8</runtime>
  <threadsafe>true</threadsafe>
</appengine-web-app>
  <!-- [END config] -->


================================================
FILE: appengine-standard-java8/helloworld-gae-javasdk-tools/src/main/webapp/index.jsp
================================================
<!DOCTYPE html>
<!-- [START_EXCLUDE] -->
<%--
  ~ Copyright 2017 Google Inc.
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License"); you
  ~ may not use this file except in compliance with the License. You may
  ~ obtain a copy of the License at
  ~
  ~     http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  ~ implied. See the License for the specific language governing
  ~ permissions and limitations under the License.
  --%>
<!-- [END_EXCLUDE] -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="com.example.appengine.java8.HelloAppEngine" %>
<html>
<head>
  <link href='//fonts.googleapis.com/css?family=Marmelad' rel='stylesheet' type='text/css'>
  <title>Hello App Engine Standard Java 8</title>
</head>
<body>
    <h1>Hello App Engine -- Java 8!</h1>

  <p>This is <%= HelloAppEngine.getInfo() %>.</p>
  <table>
    <tr>
      <td colspan="2" style="font-weight:bold;">Available Servlets:</td>
    </tr>
    <tr>
      <td><a href='/hello'>Hello App Engine</a></td>
    </tr>
  </table>

</body>
</html>


================================================
FILE: appengine-standard-java8/helloworld-gae-javasdk-tools/src/test/java/com/example/appengine/java8/HelloAppEngineTest.java
================================================
/*
 * Copyright 2017 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.appengine.java8;

import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;

import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

/**
 * Unit tests for {@link HelloAppEngine}.
 */
// [START example]
@RunWith(JUnit4.class)
public class HelloAppEngineTest {
  private static final String FAKE_URL = "fake.fk/hello";
  // Set up a helper so that the ApiProxy returns a valid environment for local testing.
  private final LocalServiceTestHelper helper = new LocalServiceTestHelper();

  @Mock private HttpServletRequest mockRequest;
  @Mock private HttpServletResponse mockResponse;
  private StringWriter responseWriter;
  private HelloAppEngine servletUnderTest;

  @Before
  public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
    helper.setUp();

    //  Set up some fake HTTP requests
    when(mockRequest.getRequestURI()).thenReturn(FAKE_URL);

    // Set up a fake HTTP response.
    responseWriter = new StringWriter();
    when(mockResponse.getWriter()).thenReturn(new PrintWriter(responseWriter));

    servletUnderTest = new HelloAppEngine();
  }

  @After public void tearDown() {
    helper.tearDown();
  }

  @Test
  public void doGetWritesResponse() throws Exception {
    servletUnderTest.doGet(mockRequest, mockResponse);

    // We expect our hello world response.
    assertThat(responseWriter.toString())
        .contains("Hello App Engine - Standard ");
  }

  @Test
  public void helloInfoTest() {
    String result = HelloAppEngine.getInfo();
    assertThat(result)
        .containsMatch("^Version:\\s+.+OS:\\s+.+User:\\s");
  }
}
// [END example]


================================================
FILE: appengine-standard-java8/kotlin-appengine-standard/.gitignore
================================================
hotspot.log
*.iml
*.ipr
*.iws
.gradle/
build/
target/
classes/
/var
pom.xml.versionsBackup
test-output/
/atlassian-ide-plugin.xml
.idea
.DS_Store
.classpath
.settings
.project
temp-testng-customsuite.xml
test-output
.externalToolBuilders
*~


================================================
FILE: appengine-standard-java8/kotlin-appengine-standard/README.md
================================================
App Engine Java Kotlin Servlet 3.1 with Java8
===

## Sample Servlet 3.1 written in Kotlin for use with App Engine Java8 Standard.

See the [Google App Engine standard environment documentation][ae-docs] for more
detailed instructions.

[ae-docs]: https://cloud.google.com/appengine/docs/java/

* [Java 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html)
* [Maven](https://maven.apache.org/download.cgi) (at least 3.5)
* [Google Cloud SDK](https://cloud.google.com/sdk/) (aka gcloud command line tool)

## Setup

* Download and initialize the [Cloud SDK](https://cloud.google.com/sdk/)

```
gcloud init
```

* Create an App Engine app within the current Google Cloud Project

```
gcloud app create
```

* In the `pom.xml`, update the [App Engine Maven Plugin](https://cloud.google.com/appengine/docs/standard/java/tools/maven-reference)
with your Google Cloud Project Id:

```
<plugin>
  <groupId>com.google.cloud.tools</groupId>
  <artifactId>appengine-maven-plugin</artifactId>
  <version>2.3.0</version>
  <configuration>
    <projectId>GCLOUD_CONFIG</projectId>
    <version>GCLOUD_CONFIG</version>
  </configuration>
</plugin>
```
**Note:** `GCLOUD_CONFIG` is a special version for autogenerating an App Engine
version. Change this field to specify a specific version name. 

## Maven
### Running locally

`mvn package appengine:run`

To use visit: http://localhost:8080/

### Deploying

`mvn package appengine:deploy`

To use visit:  https://YOUR-PROJECT-ID.appspot.com

## Testing

`mvn verify`

As you add / modify the source code (`src/main/java/...`) it's very useful to add [unit testing](https://cloud.google.com/appengine/docs/java/tools/localunittesting)
to (`src/main/test/...`).  The following resources are quite useful:

* [Junit4](http://junit.org/junit4/)
* [Mockito](http://mockito.org/)
* [Truth](http://google.github.io/truth/)


For further information, consult the
[Java App Engine](https://developers.google.com/appengine/docs/java/overview) documentation.


================================================
FILE: appengine-standard-java8/kotlin-appengine-standard/nbactions.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2017 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<actions>
    <action>
        <actionName>CUSTOM-appengine:devserver</actionName>
        <displayName>appengine:devserver</displayName>
        <goals>
            <goal>appengine:devserver</goal>
        </goals>
    </action>
    <action>
        <actionName>CUSTOM-appengine:update</actionName>
        <displayName>appengine:update</displayName>
        <goals>
            <goal>appengine:update</goal>
        </goals>
    </action>
    <action>
        <actionName>CUSTOM-appengine:rollback</actionName>
        <displayName>appengine:rollback</displayName>
        <goals>
            <goal>appengine:rollback</goal>
        </goals>
    </action>
    <action>
        <actionName>CUSTOM-appengine:update_cron</actionName>
        <displayName>appengine:update_cron</displayName>
        <goals>
            <goal>appengine:update_cron</goal>
        </goals>
    </action>
    <action>
        <actionName>CUSTOM-appengine:update_dos</actionName>
        <displayName>appengine:update_dos</displayName>
        <goals>
            <goal>appengine:update_dos</goal>
        </goals>
    </action>
    <action>
        <actionName>CUSTOM-appengine:update_indexes</actionName>
        <displayName>appengine:update_indexes</displayName>
        <goals>
            <goal>appengine:update_indexes</goal>
        </goals>
    </action>
    <action>
        <actionName>CUSTOM-appengine:update_queues</actionName>
        <displayName>appengine:update_queues</displayName>
        <goals>
            <goal>appengine:update_queues</goal>
        </goals>
    </action>
    <action>
            <actionName>run</actionName>
            <packagings>
                <packaging>war</packaging>
                <packaging>ear</packaging>
                <packaging>ejb</packaging>
            </packagings>
            <goals>
                <goal>appengine:devserver</goal>
            </goals>
            <properties>
                <netbeans.deploy>true</netbeans.deploy>
            </properties>
        </action>
</actions>


================================================
FILE: appengine-standard-java8/kotlin-appengine-standard/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2017 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>

  <groupId>com.google.appengine.demos</groupId>
  <artifactId>kotlin-appengine-standard</artifactId>

  <!-- Parent POM defines common plugins and properties. -->
  <parent>
    <groupId>com.google.cloud.samples</groupId>
    <artifactId>shared-configuration</artifactId>
    <version>1.2.0</version>
  </parent>

  <properties>
    <java.version>1.8</java.version>
    <kotlin.version>1.3.72</kotlin.version>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
  </properties>

  <dependencies>
    <dependency>
      <groupId>com.google.appengine</groupId>
      <artifactId>appengine-api-1.0-sdk</artifactId>
      <version>2.0.15</version>
    </dependency>
    <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <type>jar</type>
    </dependency>
    <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-stdlib</artifactId>
      <version>1.6.0</version>
    </dependency>
  </dependencies>

  <build>
    <outputDirectory>target/${project.artifactId}-${project.version}/WEB-INF/classes</outputDirectory>
    <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
    <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
    <plugins>
      <plugin>
        <artifactId>kotlin-maven-plugin</artifactId>
        <groupId>org.jetbrains.kotlin</groupId>
        <version>1.5.31</version>
        <configuration/>
        <executions>
          <execution>
            <id>compile</id>
            <phase>compile</phase>
            <goals>
              <goal>compile</goal>
            </goals>
          </execution>
          <execution>
            <id>test-compile</id>
            <phase>test-compile</phase>
            <goals>
              <goal>test-compile</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.3.2</version>
        <configuration>
          <archiveClasses>true</archiveClasses>
          <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
      </plugin>
      <!-- [START cloudplugin] -->
      <plugin>
        <groupId>com.google.cloud.tools</groupId>
        <artifactId>appengine-maven-plugin</artifactId>
        <version>2.4.4</version>
        <configuration>
          <!-- can be set w/ -DprojectId=myProjectId on command line -->
          <projectId>GCLOUD_CONFIG</projectId>
          <!-- set the GAE version or use "GCLOUD_CONFIG" for an autogenerated GAE version -->
          <version>GCLOUD_CONFIG</version>
        </configuration>
      </plugin>
      <!-- [END cloudplugin] -->
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.11.0</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>


================================================
FILE: appengine-standard-java8/kotlin-appengine-standard/src/main/kotlin/HomeController.kt
================================================
// See https://github.com/JetBrains/kotlin-examples/blob/master/LICENSE
package org.jetbrains.kotlin.demo

import javax.servlet.annotation.WebServlet
import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

@WebServlet(name = "Hello", value = ["/"])
class HomeController : HttpServlet() {
    override fun doGet(req: HttpServletRequest, res: HttpServletResponse) {
        res.writer.write("Hello, World! I am a Servlet 3.1 running on Java8 App Engine Standard, and written in Kotlin...")
 
    }
}


================================================
FILE: appengine-standard-java8/kotlin-appengine-standard/src/main/webapp/WEB-INF/appengine-web.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <threadsafe>true</threadsafe>
    <runtime>java8</runtime>
    <system-properties>
        <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
    </system-properties>
</appengine-web-app>


================================================
FILE: appengine-standard-java8/kotlin-appengine-standard/src/main/webapp/WEB-INF/logging.properties
================================================
# Copyright 2017 Google Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#     http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# A default java.util.logging configuration.
# (All App Engine logging is through java.util.logging by default).
#
# To use this configuration, copy it into your application's WEB-INF
# folder and add the following to your appengine-web.xml:
# 
# <system-properties>
#   <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
# </system-properties>
#

# Set the default logging level for all loggers to WARNING
.level = WARNING


================================================
FILE: appengine-standard-java8/kotlin-sb-appengine-standard/.gitignore
================================================
hotspot.log
*.iml
*.ipr
*.iws
.gradle/
build/
target/
classes/
/var
pom.xml.versionsBackup
test-output/
/atlassian-ide-plugin.xml
.idea
.DS_Store
.classpath
.settings
.project
temp-testng-customsuite.xml
test-output
.externalToolBuilders
*~


================================================
FILE: appengine-standard-java8/kotlin-sb-appengine-standard/README.md
================================================
App Engine Java SpringBoot Kotlin application
===

## Sample SpringBoot application written in Kotlin for use with App Engine Java8 Standard.

See the [Google App Engine standard environment documentation][ae-docs] for more
detailed instructions.

[ae-docs]: https://cloud.google.com/appengine/docs/java/

* [Java 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html)
* [Maven](https://maven.apache.org/download.cgi) (at least 3.5)
* [Google Cloud SDK](https://cloud.google.com/sdk/) (aka gcloud command line tool)

## Setup

* Download and initialize the [Cloud SDK](https://cloud.google.com/sdk/)

```
gcloud init
```

* Create an App Engine app within the current Google Cloud Project

```
gcloud app create
```

* In the `pom.xml`, update the [App Engine Maven Plugin](https://cloud.google.com/appengine/docs/standard/java/tools/maven-reference)
with your Google Cloud Project Id:

```
<plugin>
  <groupId>com.google.cloud.tools</groupId>
  <artifactId>appengine-maven-plugin</artifactId>
  <version>2.3.0</version>
  <configuration>
    <projectId>GCLOUD_CONFIG</projectId>
    <version>GCLOUD_CONFIG</version>
  </configuration>
</plugin>
```
**Note:** `GCLOUD_CONFIG` is a special version for autogenerating an App Engine
version. Change this field to specify a specific version name.

## Maven
### Running locally

`mvn package appengine:run`

To use visit: http://localhost:8080/

### Deploying

`mvn package appengine:deploy`

To use visit:  https://YOUR-PROJECT-ID.appspot.com

## Testing

`mvn verify`

As you add / modify the source code (`src/main/java/...`) it's very useful to add [unit testing](https://cloud.google.com/appengine/docs/java/tools/localunittesting)
to (`src/main/test/...`).  The following resources are quite useful:

* [Junit4](http://junit.org/junit4/)
* [Mockito](http://mockito.org/)
* [Truth](http://google.github.io/truth/)


For further information, consult the
[Java App Engine](https://developers.google.com/appengine/docs/java/overview) documentation.


================================================
FILE: appengine-standard-java8/kotlin-sb-appengine-standard/nbactions.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2017 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<actions>
    <action>
        <actionName>CUSTOM-appengine:devserver</actionName>
        <displayName>appengine:devserver</displayName>
        <goals>
            <goal>appengine:devserver</goal>
        </goals>
    </action>
    <action>
        <actionName>CUSTOM-appengine:update</actionName>
        <displayName>appengine:update</displayName>
        <goals>
            <goal>appengine:update</goal>
        </goals>
    </action>
    <action>
        <actionName>CUSTOM-appengine:rollback</actionName>
        <displayName>appengine:rollback</displayName>
        <goals>
            <goal>appengine:rollback</goal>
        </goals>
    </action>
    <action>
        <actionName>CUSTOM-appengine:update_cron</actionName>
        <displayName>appengine:update_cron</displayName>
        <goals>
            <goal>appengine:update_cron</goal>
        </goals>
    </action>
    <action>
        <actionName>CUSTOM-appengine:update_dos</actionName>
        <displayName>appengine:update_dos</displayName>
        <goals>
            <goal>appengine:update_dos</goal>
        </goals>
    </action>
    <action>
        <actionName>CUSTOM-appengine:update_indexes</actionName>
        <displayName>appengine:update_indexes</displayName>
        <goals>
            <goal>appengine:update_indexes</goal>
        </goals>
    </action>
    <action>
        <actionName>CUSTOM-appengine:update_queues</actionName>
        <displayName>appengine:update_queues</displayName>
        <goals>
            <goal>appengine:update_queues</goal>
        </goals>
    </action>
    <action>
            <actionName>run</actionName>
            <packagings>
                <packaging>war</packaging>
                <packaging>ear</packaging>
                <packaging>ejb</packaging>
            </packagings>
            <goals>
                <goal>appengine:devserver</goal>
            </goals>
            <properties>
                <netbeans.deploy>true</netbeans.deploy>
            </properties>
        </action>
</actions>


================================================
FILE: appengine-standard-java8/kotlin-sb-appengine-standard/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2017 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>

  <groupId>com.google.appengine.demos</groupId>
  <artifactId>kotlin-sb-appengine-standard</artifactId>

  <parent>
    <groupId>com.google.cloud.samples</groupId>
    <artifactId>shared-configuration</artifactId>
    <version>1.2.0</version>
  </parent>

  <properties>
    <java.version>1.8</java.version>
    <kotlin.version>1.6.0</kotlin.version>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
  </properties>

  <dependencies>
    <dependency>
      <groupId>com.google.appengine</groupId>
      <artifactId>appengine-api-1.0-sdk</artifactId>
      <version>2.0.15</version>
    </dependency>
    <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version>3.1.1</version>
      <exclusions>
        <exclusion>
          <groupId>org.slf4j</groupId>
          <artifactId>jul-to-slf4j</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <type>jar</type>
    </dependency>
    <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-stdlib-jdk8</artifactId>
      <version>${kotlin.version}</version>
    </dependency>
    <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-reflect</artifactId>
      <version>${kotlin.version}</version>
    </dependency>
    <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-maven-allopen</artifactId>
      <version>${kotlin.version}</version>
    </dependency>
  </dependencies>

  <build>
    <outputDirectory>target/${project.artifactId}-${project.version}/WEB-INF/classes</outputDirectory>
    <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
    <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
    <plugins>
      <plugin>
        <artifactId>kotlin-maven-plugin</artifactId>
        <groupId>org.jetbrains.kotlin</groupId>
        <version>${kotlin.version}</version>
        <configuration>
          <compilerPlugins>
            <plugin>spring</plugin>
          </compilerPlugins>
          <jvmTarget>${java.version}</jvmTarget>
        </configuration>
        <executions>
          <execution>
            <id>compile</id>
            <phase>compile</phase>
            <goals>
              <goal>compile</goal>
            </goals>
          </execution>
          <execution>
            <id>test-compile</id>
            <phase>test-compile</phase>
            <goals>
              <goal>test-compile</goal>
            </goals>
          </execution>
        </executions>
          <dependencies>
            <dependency>
              <groupId>org.jetbrains.kotlin</groupId>
              <artifactId>kotlin-maven-allopen</artifactId>
              <version>${kotlin.version}</version>
            </dependency>
          </dependencies>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.3.2</version>
        <configuration>
          <archiveClasses>true</archiveClasses>
          <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
      </plugin>

      <!-- [START cloudplugin] -->
      <plugin>
        <groupId>com.google.cloud.tools</groupId>
        <artifactId>appengine-maven-plugin</artifactId>
        <version>2.4.4</version>
        <configuration>
          <!-- can be set w/ -DprojectId=myProjectId on command line -->
          <projectId>GCLOUD_CONFIG</projectId>
          <!-- set the GAE version or use "GCLOUD_CONFIG" for an autogenerated GAE version -->
          <version>GCLOUD_CONFIG</version>
        </configuration>
      </plugin>
      <!-- [END cloudplugin] -->
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.11.0</version>
        <configuration>
          <source>${java.version}</source>
          <target>${java.version}</target>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>


================================================
FILE: appengine-standard-java8/kotlin-sb-appengine-standard/src/main/kotlin/org/jetbrains/kotlin/demo/Application.kt
================================================
// See https://github.com/JetBrains/kotlin-examples/blob/master/LICENSE
package org.jetbrains.kotlin.demo

import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer

@SpringBootApplication
class Application : SpringBootServletInitializer() {

}

fun main(args: Array<String>) {
	SpringApplication.run(Application::class.java, *args)
}


================================================
FILE: appengine-standard-java8/kotlin-sb-appengine-standard/src/main/kotlin/org/jetbrains/kotlin/demo/Greeting.kt
================================================
// See https://github.com/JetBrains/kotlin-examples/blob/master/LICENSE
package org.jetbrains.kotlin.demo

data class Greeting(val id: Long, val content: String)


================================================
FILE: appengine-standard-java8/kotlin-sb-appengine-standard/src/main/kotlin/org/jetbrains/kotlin/demo/GreetingController.kt
================================================
// See https://github.com/JetBrains/kotlin-examples/blob/master/LICENSE
package org.jetbrains.kotlin.demo

import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import java.util.concurrent.atomic.AtomicLong

@RestController
class GreetingController {

    val counter = AtomicLong()

    @GetMapping("/greeting")
    fun greeting(@RequestParam(value = "name", defaultValue = "World") name: String) =
                Greeting(counter.incrementAndGet(), "Hello, $name, from a SpringBoot Application written in Kotlin, running on Google App Engine Java8 Standard...")
}


================================================
FILE: appengine-standard-java8/kotlin-sb-appengine-standard/src/main/webapp/WEB-INF/appengine-web.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <threadsafe>true</threadsafe>
    <runtime>java8</runtime>
    <system-properties>
        <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
    </system-properties>
</appengine-web-app>


================================================
FILE: appengine-standard-java8/kotlin-sb-appengine-standard/src/main/webapp/WEB-INF/logging.properties
================================================
# Copyright 2017 Google Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#     http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# A default java.util.logging configuration.
# (All App Engine logging is through java.util.logging by default).
#
# To use this configuration, copy it into your application's WEB-INF
# folder and add the following to your appengine-web.xml:
# 
# <system-properties>
#   <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
# </system-properties>
#

# Set the default logging level for all loggers to WARNING
.level = WARNING


================================================
FILE: appengine-standard-java8/kotlin-spark-appengine-standard/.gitignore
================================================
hotspot.log
*.iml
*.ipr
*.iws
.gradle/
build/
target/
classes/
/var
pom.xml.versionsBackup
test-output/
/atlassian-ide-plugin.xml
.idea
.DS_Store
.classpath
.settings
.project
temp-testng-customsuite.xml
test-output
.externalToolBuilders
*~


================================================
FILE: appengine-standard-java8/kotlin-spark-appengine-standard/README.md
================================================
App Engine SparkJava Kotlin with Java8
===

## Sample SparkJava application written in Kotlin for use with App Engine Java8 Standard.

For Spark Kotlin documentation, see [Spark Kotlin](https://github.com/perwendel/spark-kotlin/).

See the [Google App Engine standard environment documentation][ae-docs] for more
detailed instructions.

[ae-docs]: https://cloud.google.com/appengine/docs/java/

* [Java 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html)
* [Maven](https://maven.apache.org/download.cgi) (at least 3.5)
* [Google Cloud SDK](https://cloud.google.com/sdk/) (aka gcloud command line tool)

## Setup

* Download and initialize the [Cloud SDK](https://cloud.google.com/sdk/)

```
gcloud init
```

* Create an App Engine app within the current Google Cloud Project

```
gcloud app create
```

* In the `pom.xml`, update the [App Engine Maven Plugin](https://cloud.google.com/appengine/docs/standard/java/tools/maven-reference)
with your Google Cloud Project Id:

```
<plugin>
  <groupId>com.google.cloud.tools</groupId>
  <artifactId>appengine-maven-plugin</artifactId>
  <version>2.3.0</version>
  <configuration>
    <projectId>GCLOUD_CONFIG</projectId>
    <version>GCLOUD_CONFIG</version>
  </configuration>
</plugin>
```
**Note:** `GCLOUD_CONFIG` is a special version for autogenerating an App Engine
version. Change this field to specify a specific version name.

## Maven
### Running locally

`mvn package appengine:run`

To use visit: http://localhost:8080/

### Deploying

`mvn package appengine:deploy`

To use visit:  https://YOUR-PROJECT-ID.appspot.com

## Testing

`mvn verify`

As you add / modify the source code (`src/main/java/...`) it's very useful to add [unit testing](https://cloud.google.com/appengine/docs/java/tools/localunittesting)
to (`src/main/test/...`).  The following resources are quite useful:

* [Junit4](http://junit.org/junit4/)
* [Mockito](http://mockito.org/)
* [Truth](http://google.github.io/truth/)


For further information, consult the
[Java App Engine](https://developers.google.com/appengine/docs/java/overview) documentation.


================================================
FILE: appengine-standard-java8/kotlin-spark-appengine-standard/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2017 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>

  <groupId>com.google.appengine.demos</groupId>
  <artifactId>kotlin-spark-appengine-standard</artifactId>

  <!-- Parent POM defines common plugins and properties. -->
  <parent>
    <groupId>com.google.cloud.samples</groupId>
    <artifactId>shared-configuration</artifactId>
    <version>1.2.0</version>
  </parent>

  <properties>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
  </properties>

  <dependencies>
    <dependency>
      <groupId>com.google.appengine</groupId>
      <artifactId>appengine-api-1.0-sdk</artifactId>
      <version>2.0.15</version>
    </dependency>
    <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <type>jar</type>
    </dependency>
    <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-stdlib-jre8</artifactId>
      <version>1.2.71</version>
    </dependency>
    <dependency>
      <groupId>com.sparkjava</groupId>
      <artifactId>spark-kotlin</artifactId>
      <version>1.0.0-alpha</version>
      <exclusions>
        <exclusion>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-server</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-io</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-security</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-webapp</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-util</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-client</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.eclipse.jetty.websocket</groupId>
          <artifactId>websocket-api</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.eclipse.jetty.websocket</groupId>
          <artifactId>websocket-client</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.eclipse.jetty.websocket</groupId>
          <artifactId>websocket-common</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.eclipse.jetty.websocket</groupId>
          <artifactId>websocket-server</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-api</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.eclipse.jetty.websocket</groupId>
          <artifactId>websocket-servlet</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>2.0.11</version> <!-- TEST if not 1.7.25 -->
    </dependency>
  </dependencies>

  <build>
    <outputDirectory>target/${project.artifactId}-${project.version}/WEB-INF/classes</outputDirectory>
    <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
    <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
    <plugins>
      <plugin>
        <artifactId>kotlin-maven-plugin</artifactId>
        <groupId>org.jetbrains.kotlin</groupId>
        <version>1.5.31</version>
        <configuration/>
        <executions>
          <execution>
            <id>compile</id>
            <phase>compile</phase>
            <goals>
              <goal>compile</goal>
            </goals>
          </execution>
          <execution>
            <id>test-compile</id>
            <phase>test-compile</phase>
            <goals>
              <goal>test-compile</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.3.2</version>
        <configuration>
          <archiveClasses>true</archiveClasses>
        </configuration>
      </plugin>
      <!-- [START cloudplugin] -->
      <plugin>
        <groupId>com.google.cloud.tools</groupId>
        <artifactId>appengine-maven-plugin</artifactId>
        <version>2.4.4</version>
        <configuration>
          <!-- can be set w/ -DprojectId=myProjectId on command line -->
          <projectId>GCLOUD_CONFIG</projectId>
          <!-- set the GAE version or use "GCLOUD_CONFIG" for an autogenerated GAE version -->
          <version>GCLOUD_CONFIG</version>
        </configuration>
      </plugin>
      <!-- [END cloudplugin] -->
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.11.0</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>


================================================
FILE: appengine-standard-java8/kotlin-spark-appengine-standard/src/main/kotlin/MainApp.kt
================================================
/**
 * Copyright 2017 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import spark.kotlin.Http
import spark.kotlin.ignite
import spark.servlet.SparkApplication

/**
 * Example usage of spark-kotlin.
 * See https://github.com/perwendel/spark-kotlin
 */
class MainApp : SparkApplication {
    override fun init() {
        
        val http: Http = ignite()

        http.get("/") {
            """Hello Spark Kotlin running on Java8 App Engine Standard.
            <p>You can try /hello<p> or /saymy/:name<p> or redirect
            <p>or /nothing"""
        }
        http.get("/hello") {
            "Hello Spark Kotlin running on Java8 App Engine Standard."
        }

        http.get("/nothing") {
            status(404)
            "Oops, we couldn't find what you're looking for."
        }

        http.get("/saymy/:name") {
            params(":name")
        }

        http.get("/redirect") {
            redirect("/hello");
        }
    }
}

================================================
FILE: appengine-standard-java8/kotlin-spark-appengine-standard/src/main/kotlin/SparkInitFilter.kt
================================================
/**
 * Copyright 2017 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import javax.servlet.annotation.WebFilter
import javax.servlet.annotation.WebInitParam

import spark.servlet.SparkFilter


// Use Servlet annotation to define the Spark filter without web.xml:
@WebFilter(
        filterName = "SparkInitFilter",
        urlPatterns = arrayOf("/*"),
        initParams = arrayOf(
                WebInitParam(
                        name = "applicationClass",
                        value = "MainApp")

        ))
class SparkInitFilter : SparkFilter() {
}


================================================
FILE: appengine-standard-java8/kotlin-spark-appengine-standard/src/main/webapp/WEB-INF/appengine-web.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <threadsafe>true</threadsafe>
    <runtime>java8</runtime>
    <system-properties>
        <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
    </system-properties>
</appengine-web-app>


================================================
FILE: appengine-standard-java8/kotlin-spark-appengine-standard/src/main/webapp/WEB-INF/logging.properties
================================================
# Copyright 2017 Google Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#     http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# A default java.util.logging configuration.
# (All App Engine logging is through java.util.logging by default).
#
# To use this configuration, copy it into your application's WEB-INF
# folder and add the following to your appengine-web.xml:
# 
# <system-properties>
#   <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
# </system-properties>
#

# Set the default logging level for all loggers to WARNING
.level = WARNING


================================================
FILE: background/README.md
================================================
# Background Processing App on Cloud Run Tutorial

Contains the code for using Cloud Firestore, Cloud Translate, and Cloud Pub/Sub.

This is part of the [getting started experience](https://cloud.google.com/java/getting-started).

### Running Locally

To run your project locally:

* Choose a Pub/Sub Topic Name and generate a Pub/Sub Verification Token using `uuidgen` or an
  online UUID generator such as [uuidgenerator.net](https://www.uuidgenerator.net/).

      export PUBSUB_TOPIC=<your-topic-name>
      export PUBSUB_VERIFICATION_TOKEN=<your-verification-token>
      export FIRESTORE_CLOUD_PROJECT=<your-project-id>
* Create a Pub/Sub topic:

      gcloud pubsub topics create $PUBSUB_TOPIC

* Run with the Jetty Maven plugin:

      mvn jetty:run-war

**Note**: If you run into an error about `Invalid Credentials`, you may have to run:

    gcloud auth application-default login
    
* Navigate to http://localhost:8080/
* Click `+ Request Translation`, and fill out the form using a phrase, a source language code ("en"
  for English) and a target language code (e.g. "es" for Spanish).
* Click `Submit`. This will submit the request to your Pub/Sub topic and redirect you back to the
  list page.

You will see that nothing has changed. This because there is no subscription on that Pub/Sub topic
yet. Since you can't set up a Pub/Sub push subscription to post requests to `localhost`, you can
instead send a manual request with `curl` (from a second terminal, in the 
`getting-started-java/background` directory):

    curl -H "Content-Type: application/json" -i --data @sample_message.json \
       "localhost:8080/pubsub/push?token=$PUBSUB_VERIFICATION_TOKEN"
       
Refresh `http://localhost:8080` now and you will see a translated entry in the list.

### Deploying to Cloud Run

To build your image:

* Update the parameters in `pom.xml`:
  * Replace `MY_PROJECT` with your project ID.
* Build and deploy to your GCR with the [Jib][jib] Maven plugin.

      mvn clean package jib:build
* Deploy the app to Cloud Run:

      gcloud beta run deploy background --image gcr.io/<MY_PROJECT>/background \
            --platform managed --region us-central1 --memory 512M \
            --update-env-vars PUBSUB_TOPIC=$PUBSUB_TOPIC,PUBSUB_VERIFICATION_TOKEN=$PUBSUB_VERIFICATION_TOKEN

  Where <MY_PROJECT> is the name of the project you created.
* Create a Pub/Sub Subscription that will send requests to the Cloud Run endpoint created
  with the previous command:
      
      gcloud pubsub subscriptions create <your-subscription-name> \
            --topic $PUBSUB_TOPIC --push-endpoint \
            <CLOUD_RUN_ENDPOINT>/translate?token=$PUBSUB_VERIFICATION_TOKEN \
            --ack-deadline 30
            
  This command will output a link to visit the page, hereafter called <CLOUD_RUN_ENDPOINT>.
* Now fill out the `+ Request Translation` form again, this time at <CLOUD_RUN_ENDPOINT>. When you
  click `Submit` it will redirect you back to /translate.
  * The new request will take a moment to show, so refresh after a minute or two.
  
[jib]: https://github.com/GoogleContainerTools/jib
  
### Architecture

The flow of translation requests fits together as such:

* When the `+ Request Translation` form is submitted, it posts a message to the Pub/Sub topic you
  created with the Text as (encoded) data, and the source/target language codes as attributes.
* The Subscription you created receives this data and pushes it to the Cloud Run endpoint (with a
  POST request to /translate).
* The /translate endpoint processes POST requests (that include the correct
  PUBSUB_VERIFICATION_TOKEN) by performing the Translate request and saving the result in Firestore.
* When you visit the Cloud Run endpoint, it reads the past 10 requests from Firestore and shows them
  in a table at the `/` or `/translate` endpoints.


================================================
FILE: background/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2019 Google LLC

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->
<project>
  <modelVersion>4.0.0</modelVersion>
  <packaging>war</packaging>

  <groupId>com.example.getstarted</groupId>
  <artifactId>background-processing</artifactId>
  <version>1.0-SNAPSHOT</version>

  <parent>
    <groupId>com.google.cloud.samples</groupId>
    <artifactId>shared-configuration</artifactId>
    <version>1.2.0</version>
  </parent>

  <properties>
    <gcloud.appId>MY_PROJECT</gcloud.appId>

    <failOnMissingWebXml>false</failOnMissingWebXml>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.showDeprecation>true</maven.compiler.showDeprecation>
    <maven.compiler.showWarnings>true</maven.compiler.showWarnings>
    <maven.compiler.failOnWarning>false</maven.compiler.failOnWarning>
    <maven.war.filteringDeploymentDescriptors>false</maven.war.filteringDeploymentDescriptors>
    <jetty.version>9.4.51.v20230217</jetty.version>
  </properties>

  <dependencies>
    <!-- [START getting_started_background_processing_dependencies] -->
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-firestore</artifactId>
      <version>3.13.2</version>
    </dependency>
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-translate</artifactId>
      <version>2.20.0</version>
    </dependency>

    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-pubsub</artifactId>
      <version>1.123.17</version>
    </dependency>
    <!-- [END getting_started_background_processing_dependencies] -->

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
    </dependency>

    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>33.1.0-jre</version>
      <scope>compile</scope>
    </dependency>

    <dependency>
      <groupId>io.opencensus</groupId>
      <artifactId>opencensus-contrib-http-util</artifactId>
      <version>0.31.1</version>
    </dependency>

    <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

    <!-- Test dependencies -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-server</artifactId>
      <version>4.0.0-alpha-2</version>
    </dependency>
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-chrome-driver</artifactId>
      <version>4.10.0</version>
    </dependency>
  </dependencies>

  <build>
    <finalName>background-processing</finalName>
    <!-- Optional - for hot reload of the web application when using an IDE Eclipse / IDEA -->
    <outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes
    </outputDirectory>
    <plugins>
      <plugin>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>${jetty.version}</version>
      </plugin>

      <plugin>
        <groupId>com.google.cloud.tools</groupId>
        <artifactId>jib-maven-plugin</artifactId>
        <version>3.4.0</version>
        <configuration>
          <to>
            <image>gcr.io/${gcloud.appId}/background</image>
          </to>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>


================================================
FILE: background/sample_message.json
================================================
{
  "message":{
    "data":"Hello world!",
    "attributes":{
      "sourceLang":"en",
      "targetLang":"es"
    },
    "messageId":"181789827785065",
    "publishTime":"2018-01-06T00:41:01.839Z"
  }
}


================================================
FILE: background/src/main/java/com/getstarted/background/functions/CreateServlet.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.getstarted.background.functions;

import com.google.cloud.pubsub.v1.Publisher;
import com.google.protobuf.ByteString;
import com.google.pubsub.v1.PubsubMessage;
import java.io.IOException;
import java.util.Enumeration;
import java.util.concurrent.ExecutionException;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/** Servlet for the Translation Request form. */
@WebServlet(
    name = "create",
    urlPatterns = {"/create"})
public class CreateServlet extends HttpServlet {
  private static Logger logger = Logger.getLogger(CreateServlet.class.getName());

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    req.setAttribute("action", "Add");
    req.setAttribute("destination", "create");
    req.setAttribute("page", "form");
    req.getRequestDispatcher("/base.jsp").forward(req, resp);
  }

  // [START getting_started_background_app_request]
  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    String text = req.getParameter("data");
    String sourceLang = req.getParameter("sourceLang");
    String targetLang = req.getParameter("targetLang");

    Enumeration<String> paramNames = req.getParameterNames();
    while (paramNames.hasMoreElements()) {
      String paramName = paramNames.nextElement();
      logger.warning("Param name: " + paramName + " = " + req.getParameter(paramName));
    }

    Publisher publisher = (Publisher) getServletContext().getAttribute("publisher");

    PubsubMessage pubsubMessage =
        PubsubMessage.newBuilder()
            .setData(ByteString.copyFromUtf8(text))
            .putAttributes("sourceLang", sourceLang)
            .putAttributes("targetLang", targetLang)
            .build();

    try {
      publisher.publish(pubsubMessage).get();
    } catch (InterruptedException | ExecutionException e) {
      throw new ServletException("Exception publishing message to topic.", e);
    }

    resp.sendRedirect("/");
  }
  // [END getting_started_background_app_request]
}


================================================
FILE: background/src/main/java/com/getstarted/background/functions/TranslateServlet.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.getstarted.background.functions;

import com.getstarted.background.objects.PubSubMessage;
import com.getstarted.background.objects.TranslateMessage;
import com.google.api.core.ApiFuture;
import com.google.cloud.firestore.CollectionReference;
import com.google.cloud.firestore.DocumentSnapshot;
import com.google.cloud.firestore.Firestore;
import com.google.cloud.firestore.QueryDocumentSnapshot;
import com.google.cloud.firestore.QuerySnapshot;
import com.google.cloud.firestore.SetOptions;
import com.google.cloud.firestore.WriteResult;
import com.google.cloud.translate.Translate;
import com.google.cloud.translate.Translation;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(
    name = "translate",
    urlPatterns = {"/", "/translate"})
public class TranslateServlet extends HttpServlet {
  private static final Gson gson = new Gson();
  private static final String PUBSUB_VERIFICATION_TOKEN =
      System.getenv("PUBSUB_VERIFICATION_TOKEN");

  // [START getting_started_background_app_list]
  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    Firestore firestore = (Firestore) this.getServletContext().getAttribute("firestore");
    CollectionReference translations = firestore.collection("translations");
    QuerySnapshot snapshot;
    try {
      snapshot = translations.limit(10).get().get();
    } catch (InterruptedException | ExecutionException e) {
      throw new ServletException("Exception retrieving documents from Firestore.", e);
    }
    List<TranslateMessage> translateMessages = Lists.newArrayList();
    List<QueryDocumentSnapshot> documents = Lists.newArrayList(snapshot.getDocuments());
    documents.sort(Comparator.comparing(DocumentSnapshot::getCreateTime));

    for (DocumentSnapshot document : Lists.reverse(documents)) {
      String encoded = gson.toJson(document.getData());
      TranslateMessage message = gson.fromJson(encoded, TranslateMessage.class);
      message.setData(decode(message.getData()));
      translateMessages.add(message);
    }
    req.setAttribute("messages", translateMessages);
    req.setAttribute("page", "list");
    req.getRequestDispatcher("/base.jsp").forward(req, resp);
  }
  // [END getting_started_background_app_list]

  /**
   * Handle a posted message from Pubsub.
   *
   * @param req The message Pubsub posts to this process.
   * @param resp Not used.
   */
  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse resp)
      throws IOException, ServletException {

    // Block requests that don't contain the proper verification token.
    String pubsubVerificationToken = PUBSUB_VERIFICATION_TOKEN;
    if (req.getParameter("token").compareTo(pubsubVerificationToken) != 0) {
      resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
      return;
    }

    // [START getting_started_background_translate_string]
    String body = req.getReader().lines().collect(Collectors.joining(System.lineSeparator()));

    PubSubMessage pubsubMessage = gson.fromJson(body, PubSubMessage.class);
    TranslateMessage message = pubsubMessage.getMessage();

    // Use Translate service client to translate the message.
    Translate translate = (Translate) this.getServletContext().getAttribute("translate");
    message.setData(decode(message.getData()));
    Translation translation =
        translate.translate(
            message.getData(),
            Translate.TranslateOption.sourceLanguage(message.getAttributes().getSourceLang()),
            Translate.TranslateOption.targetLanguage(message.getAttributes().getTargetLang()));
    // [END getting_started_background_translate_string]

    message.setTranslatedText(translation.getTranslatedText());

    try {
      // [START getting_started_background_translate]
      // Use Firestore service client to store the translation in Firestore.
      Firestore firestore = (Firestore) this.getServletContext().getAttribute("firestore");

      CollectionReference translations = firestore.collection("translations");

      ApiFuture<WriteResult> setFuture = translations.document().set(message, SetOptions.merge());

      setFuture.get();
      resp.getWriter().write(translation.getTranslatedText());
      // [END getting_started_background_translate]
    } catch (InterruptedException | ExecutionException e) {
      throw new ServletException("Exception storing data in Firestore.", e);
    }
  }

  private String decode(String data) throws UnsupportedEncodingException {
    return new String(Base64.getDecoder().decode(data), "UTF-8");
  }
}


================================================
FILE: background/src/main/java/com/getstarted/background/objects/PubSubMessage.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.getstarted.background.objects;

// [START getting_started_background_pub_sub_message]
public class PubSubMessage {
  private TranslateMessage message;
  private String subscription;

  public TranslateMessage getMessage() {
    return message;
  }

  public void setMessage(TranslateMessage message) {
    this.message = message;
  }

  public String getSubscription() {
    return subscription;
  }

  public void setSubscription(String subscription) {
    this.subscription = subscription;
  }
}
// [END getting_started_background_pub_sub_message]


================================================
FILE: background/src/main/java/com/getstarted/background/objects/TranslateAttributes.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.getstarted.background.objects;

// [START getting_started_background_translate_attributes]
public class TranslateAttributes {
  private String sourceLang;
  private String targetLang;

  public String getSourceLang() {
    return sourceLang;
  }

  public void setSourceLang(String sourceLang) {
    this.sourceLang = sourceLang;
  }

  public String getTargetLang() {
    return targetLang;
  }

  public void setTargetLang(String targetLang) {
    this.targetLang = targetLang;
  }
}
// [END getting_started_background_translate_attributes]


================================================
FILE: background/src/main/java/com/getstarted/background/objects/TranslateMessage.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.getstarted.background.objects;

// [START getting_started_background_translate_message]
public class TranslateMessage {
  public String data;
  public TranslateAttributes attributes;
  public String messageId;
  public String publishTime;
  public String translatedText;
  public String sourceLang = "en";
  public String targetLang = "en";

  public String getData() {
    return data;
  }

  public void setData(String data) {
    this.data = data;
  }

  public TranslateAttributes getAttributes() {
    return attributes;
  }

  public void setAttributes(TranslateAttributes attributes) {
    this.attributes = attributes;
  }

  public String getMessageId() {
    return messageId;
  }

  public void setMessageId(String messageId) {
    this.messageId = messageId;
  }

  public String getPublishTime() {
    return publishTime;
  }

  public void setPublishTime(String publishTime) {
    this.publishTime = publishTime;
  }

  public String getTranslatedText() {
    return translatedText;
  }

  public void setTranslatedText(String translatedText) {
    this.translatedText = translatedText;
  }

  public String getSourceLang() {
    return sourceLang;
  }

  public void setSourceLang(String sourceLang) {
    this.sourceLang = sourceLang;
  }

  public String getTargetLang() {
    return targetLang;
  }

  public void setTargetLang(String targetLang) {
    this.targetLang = targetLang;
  }
}
// [END getting_started_background_translate_message]


================================================
FILE: background/src/main/java/com/getstarted/background/util/BackgroundContextListener.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.getstarted.background.util;

import com.google.cloud.ServiceOptions;
import com.google.cloud.firestore.Firestore;
import com.google.cloud.firestore.FirestoreOptions;
import com.google.cloud.pubsub.v1.Publisher;
import com.google.cloud.translate.Translate;
import com.google.cloud.translate.TranslateOptions;
import com.google.pubsub.v1.TopicName;
import java.io.IOException;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

// [START background_context_listener]
@WebListener("Creates Firestore and TranslateServlet service clients for reuse between requests.")
public class BackgroundContextListener implements ServletContextListener {
  @Override
  public void contextDestroyed(javax.servlet.ServletContextEvent event) {}

  @Override
  public void contextInitialized(ServletContextEvent event) {
    String firestoreProjectId = System.getenv("FIRESTORE_CLOUD_PROJECT");
    Firestore firestore = (Firestore) event.getServletContext().getAttribute("firestore");
    if (firestore == null) {
      firestore =
          FirestoreOptions.getDefaultInstance().toBuilder()
              .setProjectId(firestoreProjectId)
              .build()
              .getService();
      event.getServletContext().setAttribute("firestore", firestore);
    }

    Translate translate = (Translate) event.getServletContext().getAttribute("translate");
    if (translate == null) {
      translate = TranslateOptions.getDefaultInstance().getService();
      event.getServletContext().setAttribute("translate", translate);
    }

    String topicId = System.getenv("PUBSUB_TOPIC");
    TopicName topicName = TopicName.of(firestoreProjectId, topicId);
    Publisher publisher = (Publisher) event.getServletContext().getAttribute("publisher");
    if (publisher == null) {
      try {
        publisher = Publisher.newBuilder(topicName).build();
        event.getServletContext().setAttribute("publisher", publisher);
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
}
// [END background_context_listener]


================================================
FILE: background/src/main/webapp/base.jsp
================================================
<!--
Copyright 2019 Google LLC

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->
<!-- [START getting_started_background_jsp_base] -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<html lang="en">
  <head>
    <title>Background Processing - Java on Google Cloud Platform</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
  </head>
  <body>
    <div class="navbar navbar-default">
      <div class="container">
        <div class="navbar-header">
          <div class="navbar-brand">Background Processing</div>
        </div>
      </div>
    </div>
    <c:import url="/${page}.jsp" />
  </body>
</html>
<!-- [END getting_started_background_jsp_base]-->


================================================
FILE: background/src/main/webapp/form.jsp
================================================
<!--
Copyright 2019 Google LLC

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->
<!-- [START getting_started_background_jsp_form] -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<div class="container">
  <h3>
    <c:out value="${action}" /> book
  </h3>

  <form method="POST" action="${destination}">

    <div class="form-group">
      <label for="data">Text</label>
      <input type="text" name="data" id="data" class="form-control" />
    </div>

    <div class="form-group">
      <h4><a href="https://cloud.google.com/translate/docs/languages">See language codes</a></h4>
      <label for="sourceLang">Source Language Code</label>
      <input type="text" name="sourceLang" id="sourceLang" class="form-control" />
    </div>
    <div class="form-group">
      <label for="targetLang">Target Language Code</label>
      <input type="text" name="targetLang" id="targetLang" class="form-control" />
    </div>

    <button type="submit" class="btn btn-success">Submit</button>
  </form>
</div>
<!-- [END getting_started_background_jsp_form] -->


================================================
FILE: background/src/main/webapp/list.jsp
================================================
<!--
Copyright 2019 Google LLC

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->
<!-- [START getting_started_background_jsp_list] -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<style>
table, th, td {
  border: 1px solid black;
  padding: 5px;
}
</style>
<div class="container">
  <h3>Translations</h3>
  <a href="/create" class="btn btn-success btn-sm">
    <i class="glyphicon glyphicon-plus"></i>
    Request translation
  </a>
  <c:choose>
  <c:when test="${empty messages}">
  <p>No translations found.</p>
  </c:when>
  <c:otherwise>
  <table>
    <tr>
      <th>Timestamp</th>
      <th>Message</th>
      <th>Source Language</th>
      <th>Target Language</th>
      <th>Translation</th>
    </tr>
    <c:forEach items="${messages}" var="message">
    <tr>
      <td>${message.publishTime}</td>
      <td>${fn:escapeXml(message.data)}</td>
      <td>${message.attributes.sourceLang}</td>
      <td>${message.attributes.targetLang}</td>
      <td>${fn:escapeXml(message.translatedText)}</td>
    </tr>
    </c:forEach>
  </table>
  <c:if test="${not empty cursor}">
  <nav>
    <ul class="pager">
      <li><a href="?cursor=${fn:escapeXml(cursor)}">More</a></li>
    </ul>
  </nav>
  </c:if>
  </c:otherwise>
  </c:choose>
</div>
<!-- [END getting_started_background_jsp_list] -->


================================================
FILE: background/src/test/java/com/getstarted/background/UserJourneyTestIT.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.getstarted.background;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import com.google.cloud.firestore.Firestore;
import com.google.cloud.firestore.FirestoreOptions;
import com.google.cloud.firestore.QueryDocumentSnapshot;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.remote.service.DriverService;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

/*
 * I can't figure out how to test server-side logging in a selenium test, so just confidence-check
 * that it hasn't broken anything.
 */
@RunWith(JUnit4.class)
@SuppressWarnings("checkstyle:AbbreviationAsWordInName")
@Ignore("Issue #498")
public class UserJourneyTestIT {

  private static final String TEXT = "Hello World!";
  private static final String SOURCE_LANG_CODE = "en";
  private static final String TARGET_LANG_CODE = "es";

  private static DriverService service;
  private WebDriver driver;

  @BeforeClass
  public static void setupClass() throws Exception {
    service = ChromeDriverService.createDefaultService();
    service.start();
  }

  @AfterClass
  public static void tearDownClass() throws ExecutionException, InterruptedException {
    // Clear the firestore list if we're not using the local emulator
    Firestore firestore = FirestoreOptions.getDefaultInstance().getService();
    for (QueryDocumentSnapshot docSnapshot :
        firestore.collection("translations").get().get().getDocuments()) {
      try {
        docSnapshot.getReference().delete().get();
      } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
      }
    }

    service.stop();
  }

  @Before
  public void setup() {
    driver = new ChromeDriver();
  }

  @After
  public void tearDown() {
    driver.quit();
  }

  private WebElement checkLandingPage() {
    WebElement button = driver.findElement(By.cssSelector("a.btn"));
    assertEquals("Request Translation", button.getText());

    WebElement heading = driver.findElement(By.cssSelector("body>.container h3"));
    assertEquals("Translations", heading.getText());

    List<WebElement> list = driver.findElements(By.cssSelector("body>.container tr"));
    assertEquals("Should be no entries in translation list.", 1, list.size());

    return button;
  }

  private void checkRequestTranslationPage() {
    List<WebElement> inputContainers = driver.findElements(By.cssSelector("form .form-group"));
    assertTrue("Should have more than 2 inputs", inputContainers.size() > 2);
    assertEquals(
        "First input should be Text",
        "Text",
        inputContainers.get(0).findElement(By.tagName("label")).getText());
    assertEquals(
        "Second input should be Source Language Code",
        "Source Language Code",
        inputContainers.get(1).findElement(By.tagName("label")).getText());
    assertEquals(
        "Third input should be Target Language Code",
        "Target Language Code",
        inputContainers.get(2).findElement(By.tagName("label")).getText());
  }

  private void submitForm() {
    driver.findElement(By.cssSelector("[name=data]")).sendKeys(UserJourneyTestIT.TEXT);
    driver
        .findElement(By.cssSelector("[name=sourceLang]"))
        .sendKeys(UserJourneyTestIT.SOURCE_LANG_CODE);
    driver
        .findElement(By.cssSelector("[name=targetLang]"))
        .sendKeys(UserJourneyTestIT.TARGET_LANG_CODE);

    driver.findElement(By.cssSelector("button[type=submit]")).submit();
  }

  @Test
  public void userJourney() {
    // Do selenium tests on the deployed version, if applicable
    String endpoint = "http://localhost:8080";
    System.out.println("Testing endpoint: " + endpoint);
    driver.get(endpoint);

    try {
      WebElement button = checkLandingPage();

      button.click();
      new WebDriverWait(driver, 10L) // 10 seconds
          .until(ExpectedConditions.urlMatches(".*/create$")::apply);

      checkRequestTranslationPage();

      submitForm();
      new WebDriverWait(driver, 10L)  // 10 seconds
          .until(ExpectedConditions.urlMatches(".*/")::apply);
    } catch (Exception e) {
      System.err.println(driver.getPageSource());
      throw e;
    }
  }
}


================================================
FILE: bookshelf/1-cloud-run/README.md
================================================
# Bookshelf App for Java on Cloud Run Tutorial

Contains the code for using Cloud Firestore.

This is part of a [Bookshelf tutorial](https://cloud.google.com/java/getting-started).

Most users can get this running by updating the parameters in `pom.xml`. You'll
also need to [create a bucket][create-bucket] in Google Cloud Storage, referred
to below as `MY_BUCKET`.

[create-bucket]: https://cloud.google.com/storage/docs/creating-buckets

### Running Locally

To run your project locally:

* Set the `BOOKSHELF_BUCKET` environment variable:

      export BOOKSHELF_BUCKET=<YOUR_BUCKET_NAME>

  Where <YOUR_BUCKET_NAME> is the bucket you created above.
* Run with the Jetty Maven plugin:

      mvn jetty:run

**Note**: If you run into an error about `Invalid Credentials`, you may have to run:

    gcloud auth application-default login

### Deploying to Cloud Run

To build your image:

* Update the parameters in `pom.xml`:
  * Replace `MY_PROJECT` with your project ID.
* Build and deploy to your GCR with [Jib][jib] Maven plugin.

      mvn clean package jib:build
      
* Deploy the app to Cloud Run:

      gcloud run deploy bookshelf --image gcr.io/<MY_PROJECT>/bookshelf \
            --region us-central1 --memory 512M \
            --update-env-vars BOOKSHELF_BUCKET="<YOUR_BUCKET_NAME>"

Where <MY_PROJECT> is the name of the project you created.

This command will output a link to visit the page.

[jib]: https://github.com/GoogleContainerTools/jib
[configure-memory]: https://cloud.google.com/run/docs/configuring/memory-limits


================================================
FILE: bookshelf/1-cloud-run/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2019 Google LLC

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->
<project>
  <modelVersion>4.0.0</modelVersion>
  <packaging>war</packaging>

  <groupId>com.example.getstarted</groupId>
  <artifactId>bookshelf-cloud-run</artifactId>
  <version>1.0-SNAPSHOT</version>

  <!-- Parent POM defines common plugins and properties. -->
  <parent>
    <groupId>com.google.cloud.samples</groupId>
    <artifactId>shared-configuration</artifactId>
    <version>1.2.0</version>
  </parent>

  <properties>
    <!-- [START bookshelf_config] -->
    <gcloud.appId>MY_PROJECT</gcloud.appId>
    <!-- [END bookshelf_config] -->

    <failOnMissingWebXml>false</failOnMissingWebXml>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.showDeprecation>true</maven.compiler.showDeprecation>
    <maven.compiler.showWarnings>true</maven.compiler.showWarnings>
    <maven.compiler.failOnWarning>false</maven.compiler.failOnWarning>
    <jetty.version>9.4.51.v20230217</jetty.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.google.cloud/google-cloud-firestore -->
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-firestore</artifactId>
      <version>3.13.2</version>
    </dependency>

    <dependency>
      <groupId>joda-time</groupId>
      <artifactId>joda-time</artifactId>
      <version>2.12.6</version>
    </dependency>

    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>33.1.0-jre</version>
      <scope>compile</scope>
    </dependency>

    <dependency>
      <groupId>io.opencensus</groupId>
      <artifactId>opencensus-contrib-http-util</artifactId>
      <version>0.31.1</version>
    </dependency>

    <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-storage</artifactId>
      <version>2.23.0</version>
    </dependency>

    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.5</version>
    </dependency>

    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.13.0</version>
    </dependency>
  </dependencies>

  <build>
    <finalName>bookshelf-cloud-run</finalName>
    <!-- Optional - for hot reload of the web application when using an IDE Eclipse / IDEA -->
    <outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes
    </outputDirectory>
    <plugins>
      <plugin>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>${jetty.version}</version>
      </plugin>
      <plugin>
        <groupId>com.google.cloud.tools</groupId>
        <artifactId>jib-maven-plugin</artifactId>
        <version>3.4.0</version>
        <configuration>
          <from>
            <image>jetty:10.0.9-jre11</image>
          </from>
          <container>
            <entrypoint>java,-jar,/usr/local/jetty/start.jar</entrypoint>
          </container>
          <to>
            <image>gcr.io/${gcloud.appId}/bookshelf</image>
          </to>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.3.2</version>
        <configuration>
          <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

================================================
FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/CreateBookServlet.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.getstarted.basicactions;

// [START bookshelf_create_servlet]

import com.example.getstarted.daos.BookDao;
import com.example.getstarted.objects.Book;
import com.example.getstarted.util.CloudStorageHelper;
import com.google.common.base.Strings;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;

@SuppressWarnings("serial")
@WebServlet(
    name = "create",
    urlPatterns = {"/create"})
public class CreateBookServlet extends HttpServlet {

  private static final Logger logger = Logger.getLogger(CreateBookServlet.class.getName());

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    req.setAttribute("action", "Add");
    req.setAttribute("destination", "create");
    req.setAttribute("page", "form");
    req.getRequestDispatcher("/base.jsp").forward(req, resp);
  }

  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    assert ServletFileUpload.isMultipartContent(req);
    CloudStorageHelper storageHelper =
        (CloudStorageHelper) getServletContext().getAttribute("storageHelper");

    String newImageUrl = null;
    Map<String, String> params = new HashMap<String, String>();
    try {
      FileItemIterator iter = new ServletFileUpload().getItemIterator(req);
      while (iter.hasNext()) {
        FileItemStream item = iter.next();
        if (item.isFormField()) {
          params.put(item.getFieldName(), Streams.asString(item.openStream()));
        } else if (!Strings.isNullOrEmpty(item.getName())) {
          newImageUrl =
              storageHelper.uploadFile(
                  item, System.getenv("BOOKSHELF_BUCKET"));
        }
      }
    } catch (FileUploadException e) {
      throw new IOException(e);
    }

    String createdByString = "";
    String createdByIdString = "";
    HttpSession session = req.getSession();
    if (session.getAttribute("userEmail") != null) { // Does the user have a logged in session?
      createdByString = (String) session.getAttribute("userEmail");
      createdByIdString = (String) session.getAttribute("userId");
    }

    Book book =
        new Book.Builder()
            .author(params.get("author"))
            .description(params.get("description"))
            .publishedDate(params.get("publishedDate"))
            .title(params.get("title"))
            .imageUrl(null == newImageUrl ? params.get("imageUrl") : newImageUrl)
            .createdBy(createdByString)
            .createdById(createdByIdString)
            .build();

    BookDao dao = (BookDao) this.getServletContext().getAttribute("dao");
    String id = dao.createBook(book);
    logger.log(Level.INFO, "Created book {0}", book);
    resp.sendRedirect("/read?id=" + id);
  }
}
// [END bookshelf_create_servlet]


================================================
FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/DeleteBookServlet.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.getstarted.basicactions;

// [START bookshelf_delete_servlet]

import com.example.getstarted.daos.BookDao;
import java.io.IOException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
@WebServlet(
    name = "delete",
    urlPatterns = {"/delete"})
public class DeleteBookServlet extends HttpServlet {

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    String id = req.getParameter("id");
    BookDao dao = (BookDao) this.getServletContext().getAttribute("dao");
    dao.deleteBook(id);
    resp.sendRedirect("/books");
  }
}
// [END bookshelf_delete_servlet]


================================================
FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/ErrorsBookServlet.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.getstarted.basicactions;

// [START bookshelf_errors_servlet]

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
@WebServlet(
    name = "errors",
    urlPatterns = {"/errors"})
public class ErrorsBookServlet extends HttpServlet {
  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
    throw new ServletException("Expected exception.");
  }
}
// [END bookshelf_errors_servlet]


================================================
FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/ListBookServlet.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.getstarted.basicactions;

// [START bookshelf_list_books_servlet]
import com.example.getstarted.daos.BookDao;
import com.example.getstarted.objects.Book;
import com.example.getstarted.objects.Result;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// a url pattern of "" makes this servlet the root servlet
@SuppressWarnings("serial")
@WebServlet(
    name = "list",
    urlPatterns = {"", "/books"},
    loadOnStartup = 1)
public class ListBookServlet extends HttpServlet {

  private static final Logger logger = Logger.getLogger(ListBookServlet.class.getName());

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws IOException, ServletException {
    BookDao dao = (BookDao) this.getServletContext().getAttribute("dao");
    String startCursor = req.getParameter("cursor");
    List<Book> books = null;
    String endCursor = null;
    try {
      Result<Book> result = dao.listBooks(startCursor);
      logger.log(Level.INFO, "Retrieved list of all books");
      books = result.getResult();
      endCursor = result.getCursor();
    } catch (Exception e) {
      throw new ServletException("Error listing books", e);
    }
    req.getSession().getServletContext().setAttribute("books", books);
    StringBuilder bookNames = new StringBuilder();
    for (Book book : books) {
      bookNames.append(book.getTitle()).append(" ");
    }
    logger.log(Level.INFO, "Loaded books: " + bookNames.toString());
    req.setAttribute("cursor", endCursor);
    req.setAttribute("page", "list");
    req.getRequestDispatcher("/base.jsp").forward(req, resp);
  }
}
// [END bookshelf_list_books_servlet]


================================================
FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/ReadBookServlet.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.getstarted.basicactions;

// [START bookshelf_read_servlet]

import com.example.getstarted.daos.BookDao;
import com.example.getstarted.objects.Book;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
@WebServlet(
    name = "read",
    urlPatterns = {"/read"})
public class ReadBookServlet extends HttpServlet {

  private final Logger logger = Logger.getLogger(ReadBookServlet.class.getName());

  @Override
  public void doGet(HttpServletRequest req,
                    HttpServletResponse resp) throws ServletException, IOException {
    String id = req.getParameter("id");
    BookDao dao = (BookDao) this.getServletContext().getAttribute("dao");
    Book book = dao.readBook(id);
    logger.log(Level.INFO, "Read book with id {0}", id);
    req.setAttribute("book", book);
    req.setAttribute("page", "view");
    req.getRequestDispatcher("/base.jsp").forward(req, resp);
  }
}
// [END bookshelf_read_servlet]


================================================
FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/UpdateBookServlet.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.getstarted.basicactions;

// [START bookshelf_update_servlet]

import com.example.getstarted.daos.BookDao;
import com.example.getstarted.objects.Book;
import com.example.getstarted.util.CloudStorageHelper;
import com.google.common.base.Strings;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;

@SuppressWarnings("serial")
@WebServlet(
    name = "update",
    urlPatterns = {"/update"})
public class UpdateBookServlet extends HttpServlet {
  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
    BookDao dao = (BookDao) this.getServletContext().getAttribute("dao");
    try {
      Book book = dao.readBook(req.getParameter("id"));
      req.setAttribute("book", book);
      req.setAttribute("action", "Edit");
      req.setAttribute("destination", "update");
      req.setAttribute("page", "form");
      req.getRequestDispatcher("/base.jsp").forward(req, resp);
    } catch (Exception e) {
      throw new ServletException("Error loading book for editing", e);
    }
  }

  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    BookDao dao = (BookDao) this.getServletContext().getAttribute("dao");

    assert ServletFileUpload.isMultipartContent(req);
    CloudStorageHelper storageHelper =
        (CloudStorageHelper) getServletContext().getAttribute("storageHelper");

    String newImageUrl = null;
    Map<String, String> params = new HashMap<String, String>();
    try {
      FileItemIterator iter = new ServletFileUpload().getItemIterator(req);
      while (iter.hasNext()) {
        FileItemStream item = iter.next();
        if (item.isFormField()) {
          params.put(item.getFieldName(), Streams.asString(item.openStream()));
        } else if (!Strings.isNullOrEmpty(item.getName())) {
          newImageUrl =
              storageHelper.uploadFile(
                  item, System.getenv("BOOKSHELF_BUCKET"));
        }
      }
    } catch (FileUploadException e) {
      throw new IOException(e);
    }

    Book oldBook = dao.readBook(params.get("id"));

    Book book =
        new Book.Builder()
            .author(params.get("author"))
            .description(params.get("description"))
            .publishedDate(params.get("publishedDate"))
            .title(params.get("title"))
            .imageUrl(null == newImageUrl ? params.get("imageUrl") : newImageUrl)
            .id(params.get("id"))
            .createdBy(oldBook.getCreatedBy())
            .createdById(oldBook.getCreatedById())
            .build();

    dao.updateBook(book);
    resp.sendRedirect("/read?id=" + params.get("id"));
  }
}
// [END bookshelf_update_servlet]


================================================
FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/daos/BookDao.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.getstarted.daos;

import com.example.getstarted.objects.Book;
import com.example.getstarted.objects.Result;

// [START bookshelf_base_dao]
public interface BookDao {
  String createBook(Book book);

  Book readBook(String bookId);

  void updateBook(Book book);

  void deleteBook(String bookId);

  Result<Book> listBooks(String startCursor);

  Result<Book> listBooksByUser(String userId, String startCursor);
}
// [END bookshelf_base_dao]


================================================
FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/daos/FirestoreDao.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.getstarted.daos;

import com.example.getstarted.objects.Book;
import com.example.getstarted.objects.Result;
import com.google.cloud.firestore.CollectionReference;
import com.google.cloud.firestore.DocumentReference;
import com.google.cloud.firestore.DocumentSnapshot;
import com.google.cloud.firestore.Firestore;
import com.google.cloud.firestore.FirestoreOptions;
import com.google.cloud.firestore.Query;
import com.google.cloud.firestore.QueryDocumentSnapshot;
import com.google.cloud.firestore.QuerySnapshot;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutionException;

// [START bookshelf_firestore_client]
public class FirestoreDao implements BookDao {
  private CollectionReference booksCollection;

  public FirestoreDao() {
    Firestore firestore = FirestoreOptions.getDefaultInstance().getService();
    booksCollection = firestore.collection("books");
  }

  // [START bookshelf_firestore_document_to_book]
  private Book documentToBook(DocumentSnapshot document) {
    Map<String, Object> data = document.getData();
    if (data == null) {
      System.out.println("No data in document " + document.getId());
      return null;
    }

    return new Book.Builder()
        .author((String) data.get(Book.AUTHOR))
        .description((String) data.get(Book.DESCRIPTION))
        .publishedDate((String) data.get(Book.PUBLISHED_DATE))
        .imageUrl((String) data.get(Book.IMAGE_URL))
        .createdBy((String) data.get(Book.CREATED_BY))
        .createdById((String) data.get(Book.CREATED_BY_ID))
        .title((String) data.get(Book.TITLE))
        .id(document.getId())
        .build();
  }
  // [END bookshelf_firestore_document_to_book]

  // [START bookshelf_firestore_create_book]
  @Override
  public String createBook(Book book) {
    String id = UUID.randomUUID().toString();
    DocumentReference document = booksCollection.document(id);
    Map<String, Object> data = Maps.newHashMap();

    data.put(Book.AUTHOR, book.getAuthor());
    data.put(Book.DESCRIPTION, book.getDescription());
    data.put(Book.PUBLISHED_DATE, book.getPublishedDate());
    data.put(Book.TITLE, book.getTitle());
    data.put(Book.IMAGE_URL, book.getImageUrl());
    data.put(Book.CREATED_BY, book.getCreatedBy());
    data.put(Book.CREATED_BY_ID, book.getCreatedById());
    try {
      document.set(data).get();
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }

    return id;
  }
  // [END bookshelf_firestore_create_book]

  // [START bookshelf_firestore_read]
  @Override
  public Book readBook(String bookId) {
    try {
      DocumentSnapshot document = booksCollection.document(bookId).get().get();

      return documentToBook(document);
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }
    return null;
  }
  // [END bookshelf_firestore_read]

  // [START bookshelf_firestore_update]
  @Override
  public void updateBook(Book book) {
    DocumentReference document = booksCollection.document(book.getId());
    Map<String, Object> data = Maps.newHashMap();

    data.put(Book.AUTHOR, book.getAuthor());
    data.put(Book.DESCRIPTION, book.getDescription());
    data.put(Book.PUBLISHED_DATE, book.getPublishedDate());
    data.put(Book.TITLE, book.getTitle());
    data.put(Book.IMAGE_URL, book.getImageUrl());
    data.put(Book.CREATED_BY, book.getCreatedBy());
    data.put(Book.CREATED_BY_ID, book.getCreatedById());
    try {
      document.set(data).get();
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }
  }
  // [END bookshelf_firestore_update]

  // [START bookshelf_firestore_delete]
  @Override
  public void deleteBook(String bookId) {
    try {
      booksCollection.document(bookId).delete().get();
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }
  }
  // [END bookshelf_firestore_delete]

  // [START bookshelf_firestore_documents_to_books]
  private List<Book> documentsToBooks(List<QueryDocumentSnapshot> documents) {
    List<Book> resultBooks = new ArrayList<>();
    for (QueryDocumentSnapshot snapshot : documents) {
      resultBooks.add(documentToBook(snapshot));
    }
    return resultBooks;
  }
  // [END bookshelf_firestore_documents_to_books]

  // [START bookshelf_firestore_list_books]
  @Override
  public Result<Book> listBooks(String startTitle) {
    Query booksQuery = booksCollection.orderBy("title").limit(10);
    if (startTitle != null) {
      booksQuery = booksQuery.startAfter(startTitle);
    }
    try {
      QuerySnapshot snapshot = booksQuery.get().get();
      List<Book> results = documentsToBooks(snapshot.getDocuments());
      String newCursor = null;
      if (results.size() > 0) {
        newCursor = results.get(results.size() - 1).getTitle();
      }
      return new Result<>(results, newCursor);
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }
    return new Result<>(Lists.newArrayList(), null);
  }
  // [END bookshelf_firestore_list_books]

  // [START bookshelf_firestore_list_by_user]
  @Override
  public Result<Book> listBooksByUser(String userId, String startTitle) {
    Query booksQuery =
        booksCollection.orderBy("title").whereEqualTo(Book.CREATED_BY_ID, userId).limit(10);
    if (startTitle != null) {
      booksQuery = booksQuery.startAfter(startTitle);
    }
    try {
      QuerySnapshot snapshot = booksQuery.get().get();
      List<Book> results = documentsToBooks(snapshot.getDocuments());
      String newCursor = null;
      if (results.size() > 0) {
        newCursor = results.get(results.size() - 1).getTitle();
      }
      return new Result<>(results, newCursor);
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }
    return new Result<>(Lists.newArrayList(), null);
  }
  // [END bookshelf_firestore_list_by_user]
}
// [END bookshelf_firestore_client]


================================================
FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/objects/Book.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.getstarted.objects;

// [START bookshelf_book]
public class Book {
  private String title;
  private String author;
  private String createdBy;
  private String createdById;
  private String publishedDate;
  private String description;
  private String id;
  private String imageUrl;
  public static final String AUTHOR = "author";
  public static final String CREATED_BY = "createdBy";
  public static final String CREATED_BY_ID = "createdById";
  public static final String DESCRIPTION = "description";
  public static final String ID = "id";
  public static final String PUBLISHED_DATE = "publishedDate";
  public static final String TITLE = "title";
  public static final String IMAGE_URL = "imageUrl";

  // We use a Builder pattern here to simplify and standardize construction of
  // Book objects.
  private Book(Builder builder) {
    this.title = builder.title;
    this.author = builder.author;
    this.createdBy = builder.createdBy;
    this.createdById = builder.createdById;
    this.publishedDate = builder.publishedDate;
    this.description = builder.description;
    this.id = builder.id;
    this.imageUrl = builder.imageUrl;
  }

  public static class Builder {
    private String title;
    private String author;
    private String createdBy;
    private String createdById;
    private String publishedDate;
    private String description;
    private String id;
    private String imageUrl;

    public Builder title(String title) {
      this.title = title;
      return this;
    }

    public Builder author(String author) {
      this.author = author;
      return this;
    }

    public Builder createdBy(String createdBy) {
      this.createdBy = createdBy;
      return this;
    }

    public Builder createdById(String createdById) {
      this.createdById = createdById;
      return this;
    }

    public Builder publishedDate(String publishedDate) {
      this.publishedDate = publishedDate;
      return this;
    }

    public Builder description(String description) {
      this.description = description;
      return this;
    }

    public Builder id(String id) {
      this.id = id;
      return this;
    }

    public Builder imageUrl(String imageUrl) {
      this.imageUrl = imageUrl;
      return this;
    }

    public Book build() {
      return new Book(this);
    }
  }

  public String getTitle() {
    return title;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  public String getAuthor() {
    return author;
  }

  public void setAuthor(String author) {
    this.author = author;
  }

  public String getCreatedBy() {
    return createdBy;
  }

  public void setCreatedBy(String createdBy) {
    this.createdBy = createdBy;
  }

  public String getCreatedById() {
    return createdById;
  }

  public void setCreatedById(String createdById) {
    this.createdById = createdById;
  }

  public String getPublishedDate() {
    return publishedDate;
  }

  public void setPublishedDate(String publishedDate) {
    this.publishedDate = publishedDate;
  }

  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  public String getImageUrl() {
    return imageUrl;
  }

  public void setImageUrl(String imageUrl) {
    this.imageUrl = imageUrl;
  }

  @Override
  public String toString() {
    return "Title: "
        + title
        + ", Author: "
        + author
        + ", Published date: "
        + publishedDate
        + ", Added by: "
        + createdBy;
  }
}
// [END bookshelf_book]


================================================
FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/objects/Result.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.getstarted.objects;

import java.util.List;

// [START bookshelf_result]
public class Result<K> {
  private String cursor;
  private List<K> result;

  public String getCursor() {
    return cursor;
  }

  public void setCursor(String cursor) {
    this.cursor = cursor;
  }

  public List<K> getResult() {
    return result;
  }

  public void setResult(List<K> result) {
    this.result = result;
  }

  public Result(List<K> result, String cursor) {
    this.result = result;
    this.cursor = cursor;
  }

  public Result(List<K> result) {
    this.result = result;
    this.cursor = null;
  }
}
// [END bookshelf_result]


================================================
FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/util/BookshelfContextListener.java
================================================
/* Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.getstarted.util;

import com.example.getstarted.daos.BookDao;
import com.example.getstarted.daos.FirestoreDao;
import com.google.common.base.Strings;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener("Creates BookDao and other servlet context objects for reuse.")
public class BookshelfContextListener implements ServletContextListener {
  @Override
  public void contextDestroyed(javax.servlet.ServletContextEvent event) {
  }

  @Override
  public void contextInitialized(ServletContextEvent event) {
    // This function is called when the application starts and will safely set a few required
    // context attributes such as the BookDao.

    BookDao dao = (BookDao) event.getServletContext().getAttribute("dao");
    if (dao == null) {
      dao = new FirestoreDao();
      event.getServletContext().setAttribute("dao", dao);
    }

    Boolean isCloudStorageConfigured = (Boolean) event.getServletContext()
        .getAttribute("isCloudStorageConfigured");
    if (isCloudStorageConfigured == null) {
      event.getServletContext()
          .setAttribute(
              "isCloudStorageConfigured",
              !Strings.isNullOrEmpty(System.getenv("BOOKSHELF_BUCKET")));
    }

    CloudStorageHelper storageHelper = (CloudStorageHelper) event.getServletContext().getAttribute(
        "storageHelper");
    if (storageHelper == null) {
      storageHelper = new CloudStorageHelper();
      event.getServletContext().setAttribute("storageHelper", storageHelper);
    }
  }
}


================================================
FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/util/CloudStorageHelper.java
================================================
/*
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.getstarted.util;

import com.google.cloud.storage.Acl;
import com.google.cloud.storage.Acl.Role;
import com.google.cloud.storage.Acl.User;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import org.apache.commons.fileupload.FileItemStream;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

// [START bookshelf_cloud_storage_client]
public class CloudStorageHelper {

  private final Logger logger = Logger.getLogger(CloudStorageHelper.class.getName());
  private static Storage storage = null;

  // [START bookshelf_cloud_storage_client_init]
  static {
    storage = StorageOptions.getDefaultInstance().getService();
  }
  // [END bookshelf_cloud_storage_client_init]

  // [START bookshelf_cloud_storage_client_upload_file]

  /**
   * Uploads a file to Google Cloud Storage to the bucket specified in the BUCKET_NAME environment
   * variable, appending a timestamp to end of the uploaded filename.
   */
  public String uploadFile(FileItemStream fileStream, final String bucketName)
      throws IOException, ServletException {
    checkFileExtension(fileStream.getName());

    System.out.println("FileStream name: " + fileStream.getName() + "\nBucket name: " + bucketName);

    DateTimeFormatter dtf = DateTimeFormat.forPattern("-YYYY-MM-dd-HHmmssSSS");
    DateTime dt = DateTime.now(DateTimeZone.UTC);
    String dtString = dt.toString(dtf);
    final String fileName = fileStream.getName() + dtString;

    // the inputstream is closed by default, so we don't need to close it here
    @SuppressWarnings("deprecation")
    BlobInfo blobInfo =
        storage.create(
            BlobInfo.newBuilder(bucketName, fileName)
                // Modify access list to allow all users with link to read file
                .setAcl(new ArrayList<>(Arrays.asList(Acl.of(User.ofAllUsers(), Role.READER))))
                .build(),
            fileStream.openStream());
    logger.log(
        Level.INFO, "Uploaded file {0} as {1}", new Object[] {fileStream.getName(), fileName});
    // return the public download link
    return blobInfo.getMediaLink();
  }
  // [END bookshelf_cloud_storage_client_upload_file]

  // [START bookshelf_cloud_storage_client_check_file_extension]

  /** Checks that the file extension is supported. */
  private void checkFileExtension(String fileName) throws ServletException {
    if (fileName != null && !fileName.isEmpty() && fileName.contains(".")) {
      String[] allowedExt = {".jpg", ".jpeg", ".png", ".gif"};
      for (String ext : allowedExt) {
        if (fileName.endsWith(ext)) {
          return;
        }
      }
      throw new ServletException("file must be an image");
    }
  }
  // [END bookshelf_cloud_storage_client_check_file_extension]
}
// [END bookshelf_cloud_storage_client]


================================================
FILE: bookshelf/1-cloud-run/src/main/webapp/WEB-INF/web.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!--
 Copyright 2023 Google LLC
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
       http://www.apache.org/licenses/LICENSE-2.0
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">

    <servlet>
        <servlet-name>list</servlet-name>
        <servlet-class>com.example.getstarted.basicactions.ListBookServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>list</servlet-name>
        <url-pattern>/</url-pattern>
        <url-pattern>/books</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>create</servlet-name>
        <servlet-class>com.example.getstarted.basicactions.CreateBookServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>create</servlet-name>
        <url-pattern>/create</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>update</servlet-name>
        <servlet-class>com.example.getstarted.basicactions.UpdateBookServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>update</servlet-name>
        <url-pattern>/update</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>read</servlet-name>
        <servlet-class>com.example.getstarted.basicactions.ReadBookServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>read</servlet-name>
        <url-pattern>/read</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>delete</servlet-name>
        <servlet-class>com.example.getstarted.basicactions.DeleteBookServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>delete</servlet-name>
        <url-pattern>/delete</url-pattern>
    </servlet-mapping>

</web-app>

================================================
FILE: bookshelf/1-cloud-run/src/main/webapp/base.jsp
================================================
<!--
Copyright 2019 Google LLC

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->
<!-- [START bookshelf_jsp_base] -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<html lang="en">
  <head>
    <title>Bookshelf - Java on Google Cloud Platform</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
  </head>
  <body>
    <div class="navbar navbar-default">
      <div class="container">
        <div class="navbar-header">
          <div class="navbar-brand">Bookshelf</div>
        </div>
      </div>
    </div>
    <c:import url="/${page}.jsp" />
  </body>
</html>
<!-- [END bookshelf_jsp_base]-->


================================================
FILE: bookshelf/1-cloud-run/src/main/webapp/form.jsp
================================================
<!--
Copyright 2019 Google LLC

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->
<!-- [START bookshelf_jsp_form] -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<div class="container">
  <h3>
    <c:out value="${action}" /> book
  </h3>

  <form method="POST" action="${destination}" enctype="multipart/form-data">

    <div class="form-group">
      <label for="title">Title</label>
      <input type="text" name="title" id="title" value="${fn:escapeXml(book.title)}" class="form-control" />
    </div>

    <div class="form-group">
      <label for="author">Author</label>
      <input type="text" name="author" id="author" value="${fn:escapeXml(book.author)}" class="form-control" />
    </div>

    <div class="form-group">
      <label for="publishedDate">Date Published</label>
      <input type="text" name="publishedDate" id="publishedDate" value="${fn:escapeXml(book.publishedDate)}" class="form-control" />
    </div>

    <div class="form-group">
      <label for="description">Description</label>
      <textarea name="description" id="description" class="form-control">${fn:escapeXml(book.description)}</textarea>
    </div>

    <div class="form-group ${isCloudStorageConfigured ? '' : 'hidden'}">
      <label for="image">Cover Image</label>
      <input type="file" name="file" id="file" class="form-control" />
    </div>

    <div class="form-group hidden">
      <label for="imageUrl">Cover Image URL</label>
      <input type="hidden" name="id" value="${book.id}" />
      <input type="text" name="imageUrl" id="imageUrl" value="${fn:escapeXml(book.imageUrl)}" class="form-control" />
    </div>

    <button type="submit" class="btn btn-success">Save</button>
  </form>
</div>
<!-- [END bookshelf_jsp_form] -->


================================================
FILE: bookshelf/1-cloud-run/src/main/webapp/list.jsp
================================================
<!--
Copyright 2019 Google LLC

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->
<!-- [START bookshelf_jsp_list] -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<div class="container">
  <h3>Books</h3>
  <a href="/create" class="btn btn-success btn-sm">
    <i class="glyphicon glyphicon-plus"></i>
    Add book
  </a>
  <c:choose>
  <c:when test="${empty books}">
  <p>No books found</p>
  </c:when>
  <c:otherwise>
  <c:forEach items="${books}" var="book">
  <div class="media">
    <a href="/read?id=${book.id}">
      <div class="media-left">
        <img alt="ahhh" src="${fn:escapeXml(not empty book.imageUrl?book.imageUrl:'http://placekitten.com/g/128/192')}">
      </div>
      <div class="media-body">
        <h4>${fn:escapeXml(book.title)}</h4>
        <p>${fn:escapeXml(book.author)}</p>
      </div>
    </a>
  </div>
  </c:forEach>
  <c:if test="${not empty cursor}">
  <nav>
    <ul class="pager">
      <li><a href="?cursor=${fn:escapeXml(cursor)}">More</a></li>
    </ul>
  </nav>
  </c:if>
  </c:otherwise>
  </c:choose>
</div>
<!-- [END bookshelf_jsp_list] -->


================================================
FILE: bookshelf/1-cloud-run/src/main/webapp/view.jsp
================================================
<!--
Copyright 2019 Google LLC

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->
<!-- [START bookshelf_jsp_view] -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<div class="container">
  <h3>Book</h3>
  <div class="btn-group">
    <a href="/update?id=${book.id}" class="btn btn-primary btn-sm">
      <i class="glyphicon glyphicon-edit"></i>
      Edit book
    </a>
    <a href="/delete?id=${book.id}" class="btn btn-danger btn-sm">
      <i class="glyphicon glyphicon-trash"></i>
      Delete book
    </a>
  </div>

  <div class="media">
    <div class="media-left">
      <img class="book-image" src="${fn:escapeXml(not empty book.imageUrl?book.imageUrl:'http://placekitten.com/g/128/192')}">
    </
Download .txt
gitextract_3yeindkx/

├── .github/
│   ├── CODEOWNERS
│   ├── blunderbuss.yml
│   └── sync-repo-settings.yaml
├── .gitignore
├── .gitmodules
├── .kokoro/
│   ├── java11/
│   │   ├── common.cfg
│   │   ├── continuous.cfg
│   │   ├── periodic.cfg
│   │   └── presubmit.cfg
│   ├── java8/
│   │   ├── common.cfg
│   │   ├── continuous.cfg
│   │   ├── periodic.cfg
│   │   └── presubmit.cfg
│   ├── lint/
│   │   ├── common.cfg
│   │   └── presubmit.cfg
│   ├── tests/
│   │   ├── run_diff_only.sh
│   │   ├── run_lint.sh
│   │   └── run_tests.sh
│   └── trampoline.sh
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── appengine-standard-java8/
│   ├── deployAll.sh
│   ├── helloworld-gae-javasdk-tools/
│   │   ├── README.md
│   │   ├── build.gradle
│   │   ├── gradle/
│   │   │   └── wrapper/
│   │   │       ├── gradle-wrapper.jar
│   │   │       └── gradle-wrapper.properties
│   │   ├── gradlew
│   │   ├── gradlew.bat
│   │   ├── pom.xml
│   │   ├── settings.gradle
│   │   └── src/
│   │       ├── main/
│   │       │   ├── java/
│   │       │   │   └── com/
│   │       │   │       └── example/
│   │       │   │           └── appengine/
│   │       │   │               └── java8/
│   │       │   │                   └── HelloAppEngine.java
│   │       │   └── webapp/
│   │       │       ├── WEB-INF/
│   │       │       │   └── appengine-web.xml
│   │       │       └── index.jsp
│   │       └── test/
│   │           └── java/
│   │               └── com/
│   │                   └── example/
│   │                       └── appengine/
│   │                           └── java8/
│   │                               └── HelloAppEngineTest.java
│   ├── kotlin-appengine-standard/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── nbactions.xml
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           ├── kotlin/
│   │           │   └── HomeController.kt
│   │           └── webapp/
│   │               └── WEB-INF/
│   │                   ├── appengine-web.xml
│   │                   └── logging.properties
│   ├── kotlin-sb-appengine-standard/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── nbactions.xml
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           ├── kotlin/
│   │           │   └── org/
│   │           │       └── jetbrains/
│   │           │           └── kotlin/
│   │           │               └── demo/
│   │           │                   ├── Application.kt
│   │           │                   ├── Greeting.kt
│   │           │                   └── GreetingController.kt
│   │           └── webapp/
│   │               └── WEB-INF/
│   │                   ├── appengine-web.xml
│   │                   └── logging.properties
│   └── kotlin-spark-appengine-standard/
│       ├── .gitignore
│       ├── README.md
│       ├── pom.xml
│       └── src/
│           └── main/
│               ├── kotlin/
│               │   ├── MainApp.kt
│               │   └── SparkInitFilter.kt
│               └── webapp/
│                   └── WEB-INF/
│                       ├── appengine-web.xml
│                       └── logging.properties
├── background/
│   ├── README.md
│   ├── pom.xml
│   ├── sample_message.json
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── getstarted/
│       │   │           └── background/
│       │   │               ├── functions/
│       │   │               │   ├── CreateServlet.java
│       │   │               │   └── TranslateServlet.java
│       │   │               ├── objects/
│       │   │               │   ├── PubSubMessage.java
│       │   │               │   ├── TranslateAttributes.java
│       │   │               │   └── TranslateMessage.java
│       │   │               └── util/
│       │   │                   └── BackgroundContextListener.java
│       │   └── webapp/
│       │       ├── base.jsp
│       │       ├── form.jsp
│       │       └── list.jsp
│       └── test/
│           └── java/
│               └── com/
│                   └── getstarted/
│                       └── background/
│                           └── UserJourneyTestIT.java
├── bookshelf/
│   └── 1-cloud-run/
│       ├── README.md
│       ├── pom.xml
│       └── src/
│           └── main/
│               ├── java/
│               │   └── com/
│               │       └── example/
│               │           └── getstarted/
│               │               ├── basicactions/
│               │               │   ├── CreateBookServlet.java
│               │               │   ├── DeleteBookServlet.java
│               │               │   ├── ErrorsBookServlet.java
│               │               │   ├── ListBookServlet.java
│               │               │   ├── ReadBookServlet.java
│               │               │   └── UpdateBookServlet.java
│               │               ├── daos/
│               │               │   ├── BookDao.java
│               │               │   └── FirestoreDao.java
│               │               ├── objects/
│               │               │   ├── Book.java
│               │               │   └── Result.java
│               │               └── util/
│               │                   ├── BookshelfContextListener.java
│               │                   └── CloudStorageHelper.java
│               └── webapp/
│                   ├── WEB-INF/
│                   │   └── web.xml
│                   ├── base.jsp
│                   ├── form.jsp
│                   ├── list.jsp
│                   └── view.jsp
├── bookshelf-standard/
│   ├── 2-structured-data/
│   │   ├── README.md
│   │   ├── jenkins.sh
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           ├── java/
│   │           │   └── com/
│   │           │       └── example/
│   │           │           └── getstarted/
│   │           │               ├── basicactions/
│   │           │               │   ├── CreateBookServlet.java
│   │           │               │   ├── DeleteBookServlet.java
│   │           │               │   ├── ListBookServlet.java
│   │           │               │   ├── ReadBookServlet.java
│   │           │               │   └── UpdateBookServlet.java
│   │           │               ├── daos/
│   │           │               │   ├── BookDao.java
│   │           │               │   ├── CloudSqlDao.java
│   │           │               │   └── DatastoreDao.java
│   │           │               ├── objects/
│   │           │               │   ├── Book.java
│   │           │               │   └── Result.java
│   │           │               └── util/
│   │           │                   └── DatastoreSessionFilter.java
│   │           └── webapp/
│   │               ├── WEB-INF/
│   │               │   ├── appengine-web.xml
│   │               │   ├── logging.properties
│   │               │   └── web.xml
│   │               ├── base.jsp
│   │               ├── form.jsp
│   │               ├── list.jsp
│   │               └── view.jsp
│   ├── 3-binary-data/
│   │   ├── README.md
│   │   ├── jenkins.sh
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           ├── java/
│   │           │   └── com/
│   │           │       └── example/
│   │           │           └── getstarted/
│   │           │               ├── basicactions/
│   │           │               │   ├── CreateBookServlet.java
│   │           │               │   ├── DeleteBookServlet.java
│   │           │               │   ├── ListBookServlet.java
│   │           │               │   ├── ReadBookServlet.java
│   │           │               │   └── UpdateBookServlet.java
│   │           │               ├── daos/
│   │           │               │   ├── BookDao.java
│   │           │               │   ├── CloudSqlDao.java
│   │           │               │   └── DatastoreDao.java
│   │           │               ├── objects/
│   │           │               │   ├── Book.java
│   │           │               │   └── Result.java
│   │           │               └── util/
│   │           │                   ├── CloudStorageHelper.java
│   │           │                   └── DatastoreSessionFilter.java
│   │           └── webapp/
│   │               ├── WEB-INF/
│   │               │   ├── appengine-web.xml
│   │               │   ├── logging.properties
│   │               │   └── web.xml
│   │               ├── base.jsp
│   │               ├── form.jsp
│   │               ├── list.jsp
│   │               └── view.jsp
│   ├── 4-auth/
│   │   ├── README.md
│   │   ├── jenkins.sh
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           ├── java/
│   │           │   └── com/
│   │           │       └── example/
│   │           │           └── getstarted/
│   │           │               ├── auth/
│   │           │               │   ├── ListByUserFilter.java
│   │           │               │   ├── LoginServlet.java
│   │           │               │   ├── LogoutFilter.java
│   │           │               │   └── LogoutServlet.java
│   │           │               ├── basicactions/
│   │           │               │   ├── CreateBookServlet.java
│   │           │               │   ├── DeleteBookServlet.java
│   │           │               │   ├── ListBookServlet.java
│   │           │               │   ├── ListByUserServlet.java
│   │           │               │   ├── ReadBookServlet.java
│   │           │               │   └── UpdateBookServlet.java
│   │           │               ├── daos/
│   │           │               │   ├── BookDao.java
│   │           │               │   ├── CloudSqlDao.java
│   │           │               │   └── DatastoreDao.java
│   │           │               ├── objects/
│   │           │               │   ├── Book.java
│   │           │               │   └── Result.java
│   │           │               └── util/
│   │           │                   ├── CloudStorageHelper.java
│   │           │                   └── DatastoreSessionFilter.java
│   │           └── webapp/
│   │               ├── WEB-INF/
│   │               │   ├── appengine-web.xml
│   │               │   ├── datastore-indexes.xml
│   │               │   ├── logging.properties
│   │               │   └── web.xml
│   │               ├── base.jsp
│   │               ├── form.jsp
│   │               ├── list.jsp
│   │               └── view.jsp
│   └── 5-logging/
│       ├── README.md
│       ├── jenkins.sh
│       ├── pom.xml
│       └── src/
│           └── main/
│               ├── java/
│               │   └── com/
│               │       └── example/
│               │           └── getstarted/
│               │               ├── auth/
│               │               │   ├── ListByUserFilter.java
│               │               │   ├── LoginServlet.java
│               │               │   ├── LogoutFilter.java
│               │               │   └── LogoutServlet.java
│               │               ├── basicactions/
│               │               │   ├── CreateBookServlet.java
│               │               │   ├── DeleteBookServlet.java
│               │               │   ├── ListBookServlet.java
│               │               │   ├── ListByUserServlet.java
│               │               │   ├── ReadBookServlet.java
│               │               │   └── UpdateBookServlet.java
│               │               ├── daos/
│               │               │   ├── BookDao.java
│               │               │   ├── CloudSqlDao.java
│               │               │   └── DatastoreDao.java
│               │               ├── objects/
│               │               │   ├── Book.java
│               │               │   └── Result.java
│               │               └── util/
│               │                   ├── CloudStorageHelper.java
│               │                   └── DatastoreSessionFilter.java
│               └── webapp/
│                   ├── WEB-INF/
│                   │   ├── appengine-web.xml
│                   │   ├── datastore-indexes.xml
│                   │   ├── logging.properties
│                   │   └── web.xml
│                   ├── base.jsp
│                   ├── form.jsp
│                   ├── list.jsp
│                   └── view.jsp
├── codecov.yml
├── gce/
│   ├── README.md
│   ├── config/
│   │   └── base/
│   │       ├── etc/
│   │       │   └── java-util-logging.properties
│   │       ├── modules/
│   │       │   └── gce.mod
│   │       └── resources/
│   │           └── jetty-logging.properties
│   ├── makeProject
│   ├── pom.xml
│   ├── scripts/
│   │   └── startup-script.sh
│   └── src/
│       ├── main/
│       │   ├── appengine/
│       │   │   └── app.yaml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── example/
│       │   │           └── getstarted/
│       │   │               └── basicactions/
│       │   │                   └── HelloworldController.java
│       │   └── webapp/
│       │       └── WEB-INF/
│       │           └── web.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── example/
│                       └── getstarted/
│                           └── basicactions/
│                               └── UserJourneyTestIT.java
├── helloworld-jsp/
│   ├── README.md
│   ├── build.gradle
│   ├── eclipse-launch-profiles/
│   │   ├── AppEngineDeploy.launch
│   │   └── AppEngineRun.launch
│   ├── gradle/
│   │   └── wrapper/
│   │       ├── gradle-wrapper.jar
│   │       └── gradle-wrapper.properties
│   ├── gradlew
│   ├── gradlew.bat
│   ├── nbactions.xml
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── appengine/
│           │   └── app.yaml
│           ├── java/
│           │   └── org/
│           │       └── example/
│           │           └── appengine/
│           │               └── hello/
│           │                   └── HelloInfo.java
│           └── webapp/
│               ├── WEB-INF/
│               │   ├── logging.properties
│               │   └── web.xml
│               └── hello.jsp
├── mvnw.cmd
└── renovate.json
Download .txt
SYMBOL INDEX (485 symbols across 81 files)

FILE: appengine-standard-java8/helloworld-gae-javasdk-tools/src/main/java/com/example/appengine/java8/HelloAppEngine.java
  class HelloAppEngine (line 29) | @WebServlet(name = "HelloAppEngine", value = "/hello")
    method doGet (line 32) | @Override
    method getInfo (line 44) | public static String getInfo() {

FILE: appengine-standard-java8/helloworld-gae-javasdk-tools/src/test/java/com/example/appengine/java8/HelloAppEngineTest.java
  class HelloAppEngineTest (line 39) | @RunWith(JUnit4.class)
    method setUp (line 50) | @Before
    method tearDown (line 65) | @After public void tearDown() {
    method doGetWritesResponse (line 69) | @Test
    method helloInfoTest (line 78) | @Test

FILE: background/src/main/java/com/getstarted/background/functions/CreateServlet.java
  class CreateServlet (line 32) | @WebServlet(
    method doGet (line 38) | @Override
    method doPost (line 48) | @Override

FILE: background/src/main/java/com/getstarted/background/functions/TranslateServlet.java
  class TranslateServlet (line 45) | @WebServlet(
    method doGet (line 54) | @Override
    method doPost (line 87) | @Override
    method decode (line 133) | private String decode(String data) throws UnsupportedEncodingException {

FILE: background/src/main/java/com/getstarted/background/objects/PubSubMessage.java
  class PubSubMessage (line 19) | public class PubSubMessage {
    method getMessage (line 23) | public TranslateMessage getMessage() {
    method setMessage (line 27) | public void setMessage(TranslateMessage message) {
    method getSubscription (line 31) | public String getSubscription() {
    method setSubscription (line 35) | public void setSubscription(String subscription) {

FILE: background/src/main/java/com/getstarted/background/objects/TranslateAttributes.java
  class TranslateAttributes (line 19) | public class TranslateAttributes {
    method getSourceLang (line 23) | public String getSourceLang() {
    method setSourceLang (line 27) | public void setSourceLang(String sourceLang) {
    method getTargetLang (line 31) | public String getTargetLang() {
    method setTargetLang (line 35) | public void setTargetLang(String targetLang) {

FILE: background/src/main/java/com/getstarted/background/objects/TranslateMessage.java
  class TranslateMessage (line 19) | public class TranslateMessage {
    method getData (line 28) | public String getData() {
    method setData (line 32) | public void setData(String data) {
    method getAttributes (line 36) | public TranslateAttributes getAttributes() {
    method setAttributes (line 40) | public void setAttributes(TranslateAttributes attributes) {
    method getMessageId (line 44) | public String getMessageId() {
    method setMessageId (line 48) | public void setMessageId(String messageId) {
    method getPublishTime (line 52) | public String getPublishTime() {
    method setPublishTime (line 56) | public void setPublishTime(String publishTime) {
    method getTranslatedText (line 60) | public String getTranslatedText() {
    method setTranslatedText (line 64) | public void setTranslatedText(String translatedText) {
    method getSourceLang (line 68) | public String getSourceLang() {
    method setSourceLang (line 72) | public void setSourceLang(String sourceLang) {
    method getTargetLang (line 76) | public String getTargetLang() {
    method setTargetLang (line 80) | public void setTargetLang(String targetLang) {

FILE: background/src/main/java/com/getstarted/background/util/BackgroundContextListener.java
  class BackgroundContextListener (line 31) | @WebListener("Creates Firestore and TranslateServlet service clients for...
    method contextDestroyed (line 33) | @Override
    method contextInitialized (line 36) | @Override

FILE: background/src/test/java/com/getstarted/background/UserJourneyTestIT.java
  class UserJourneyTestIT (line 48) | @RunWith(JUnit4.class)
    method setupClass (line 60) | @BeforeClass
    method tearDownClass (line 66) | @AfterClass
    method setup (line 82) | @Before
    method tearDown (line 87) | @After
    method checkLandingPage (line 92) | private WebElement checkLandingPage() {
    method checkRequestTranslationPage (line 105) | private void checkRequestTranslationPage() {
    method submitForm (line 122) | private void submitForm() {
    method userJourney (line 134) | @Test

FILE: bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/basicactions/CreateBookServlet.java
  class CreateBookServlet (line 27) | @SuppressWarnings("serial")
    method doGet (line 31) | @Override
    method doPost (line 42) | @Override

FILE: bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/basicactions/DeleteBookServlet.java
  class DeleteBookServlet (line 26) | @SuppressWarnings("serial")
    method doGet (line 29) | @Override

FILE: bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/basicactions/ListBookServlet.java
  class ListBookServlet (line 32) | @SuppressWarnings("serial")
    method init (line 35) | @Override
    method doGet (line 70) | @Override

FILE: bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/basicactions/ReadBookServlet.java
  class ReadBookServlet (line 27) | @SuppressWarnings("serial")
    method doGet (line 30) | @Override

FILE: bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/basicactions/UpdateBookServlet.java
  class UpdateBookServlet (line 27) | @SuppressWarnings("serial")
    method doGet (line 30) | @Override
    method doPost (line 46) | @Override

FILE: bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/daos/BookDao.java
  type BookDao (line 23) | public interface BookDao {
    method createBook (line 24) | Long createBook(Book book) throws SQLException;
    method readBook (line 26) | Book readBook(Long bookId) throws SQLException;
    method updateBook (line 28) | void updateBook(Book book) throws SQLException;
    method deleteBook (line 30) | void deleteBook(Long bookId) throws SQLException;
    method listBooks (line 32) | Result<Book> listBooks(String startCursor) throws SQLException;

FILE: bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/daos/CloudSqlDao.java
  class CloudSqlDao (line 30) | public class CloudSqlDao implements BookDao {
    method CloudSqlDao (line 37) | public CloudSqlDao(final String url) throws SQLException {
    method createBook (line 51) | @Override
    method readBook (line 76) | @Override
    method updateBook (line 100) | @Override
    method deleteBook (line 120) | @Override
    method listBooks (line 132) | @Override

FILE: bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/daos/DatastoreDao.java
  class DatastoreDao (line 37) | public class DatastoreDao implements BookDao {
    method DatastoreDao (line 43) | public DatastoreDao() {
    method entityToBook (line 49) | public Book entityToBook(Entity entity) {
    method createBook (line 61) | @Override
    method readBook (line 75) | @Override
    method updateBook (line 87) | @Override
    method deleteBook (line 101) | @Override
    method entitiesToBooks (line 109) | public List<Book> entitiesToBooks(Iterator<Entity> results) {
    method listBooks (line 119) | @Override

FILE: bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/objects/Book.java
  class Book (line 19) | public class Book {
    method Book (line 43) | private Book(Builder builder) {
    class Builder (line 56) | public static class Builder {
      method title (line 66) | public Builder title(String title) {
      method author (line 71) | public Builder author(String author) {
      method createdBy (line 76) | public Builder createdBy(String createdBy) {
      method createdById (line 81) | public Builder createdById(String createdById) {
      method publishedDate (line 86) | public Builder publishedDate(String publishedDate) {
      method description (line 91) | public Builder description(String description) {
      method id (line 96) | public Builder id(Long id) {
      method imageUrl (line 101) | public Builder imageUrl(String imageUrl) {
      method build (line 106) | public Book build() {
    method getTitle (line 111) | public String getTitle() {
    method setTitle (line 115) | public void setTitle(String title) {
    method getAuthor (line 119) | public String getAuthor() {
    method setAuthor (line 123) | public void setAuthor(String author) {
    method getCreatedBy (line 127) | public String getCreatedBy() {
    method setCreatedBy (line 131) | public void setCreatedBy(String createdBy) {
    method getCreatedById (line 135) | public String getCreatedById() {
    method setCreatedById (line 139) | public void setCreatedById(String createdById) {
    method getPublishedDate (line 143) | public String getPublishedDate() {
    method setPublishedDate (line 147) | public void setPublishedDate(String publishedDate) {
    method getDescription (line 151) | public String getDescription() {
    method setDescription (line 155) | public void setDescription(String description) {
    method getId (line 159) | public Long getId() {
    method setId (line 163) | public void setId(Long id) {
    method getImageUrl (line 167) | public String getImageUrl() {
    method setImageUrl (line 171) | public void setImageUrl(String imageUrl) {
    method toString (line 176) | @Override

FILE: bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/objects/Result.java
  class Result (line 21) | public class Result<K> {
    method Result (line 26) | public Result(List<K> result, String cursor) {
    method Result (line 31) | public Result(List<K> result) {

FILE: bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/util/DatastoreSessionFilter.java
  class DatastoreSessionFilter (line 54) | public class DatastoreSessionFilter implements Filter {
    method init (line 60) | @Override
    method doFilter (line 77) | @Override
    method mapToString (line 118) | @SuppressWarnings({"unused", "JdkObsolete"})
    method destroy (line 127) | @Override
    method getCookieValue (line 131) | protected String getCookieValue(HttpServletRequest req, String cookieN...
    method deleteSessionVariables (line 149) | protected void deleteSessionVariables(String sessionId, String... varN...
    method deleteSessionWithValue (line 172) | protected void deleteSessionWithValue(String varName, String varValue) {
    method setSessionVariables (line 198) | protected void setSessionVariables(String sessionId, Map<String, Strin...
    method loadSessionVariables (line 234) | protected Map<String, String> loadSessionVariables(HttpServletRequest ...

FILE: bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/basicactions/CreateBookServlet.java
  class CreateBookServlet (line 36) | @SuppressWarnings("serial")
    method doGet (line 40) | @Override
    method doPost (line 51) | @Override

FILE: bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/basicactions/DeleteBookServlet.java
  class DeleteBookServlet (line 26) | @SuppressWarnings("serial")
    method doGet (line 29) | @Override

FILE: bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/basicactions/ListBookServlet.java
  class ListBookServlet (line 34) | @SuppressWarnings("serial")
    method init (line 37) | @Override
    method doGet (line 82) | @Override

FILE: bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/basicactions/ReadBookServlet.java
  class ReadBookServlet (line 27) | @SuppressWarnings("serial")
    method doGet (line 30) | @Override

FILE: bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/basicactions/UpdateBookServlet.java
  class UpdateBookServlet (line 36) | @SuppressWarnings("serial")
    method doGet (line 38) | @Override
    method doPost (line 54) | @Override

FILE: bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/daos/BookDao.java
  type BookDao (line 23) | public interface BookDao {
    method createBook (line 24) | Long createBook(Book book) throws SQLException;
    method readBook (line 26) | Book readBook(Long bookId) throws SQLException;
    method updateBook (line 28) | void updateBook(Book book) throws SQLException;
    method deleteBook (line 30) | void deleteBook(Long bookId) throws SQLException;
    method listBooks (line 32) | Result<Book> listBooks(String startCursor) throws SQLException;

FILE: bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/daos/CloudSqlDao.java
  class CloudSqlDao (line 30) | public class CloudSqlDao implements BookDao {
    method CloudSqlDao (line 37) | public CloudSqlDao(final String url) throws SQLException {
    method createBook (line 51) | @Override
    method readBook (line 76) | @Override
    method updateBook (line 100) | @Override
    method deleteBook (line 120) | @Override
    method listBooks (line 132) | @Override

FILE: bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/daos/DatastoreDao.java
  class DatastoreDao (line 37) | public class DatastoreDao implements BookDao {
    method DatastoreDao (line 43) | public DatastoreDao() {
    method entityToBook (line 49) | public Book entityToBook(Entity entity) {
    method createBook (line 62) | @Override
    method readBook (line 77) | @Override
    method updateBook (line 89) | @Override
    method deleteBook (line 104) | @Override
    method entitiesToBooks (line 112) | public List<Book> entitiesToBooks(Iterator<Entity> results) {
    method listBooks (line 122) | @Override

FILE: bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/objects/Book.java
  class Book (line 19) | public class Book {
    method Book (line 43) | private Book(Builder builder) {
    class Builder (line 56) | public static class Builder {
      method title (line 66) | public Builder title(String title) {
      method author (line 71) | public Builder author(String author) {
      method createdBy (line 76) | public Builder createdBy(String createdBy) {
      method createdById (line 81) | public Builder createdById(String createdById) {
      method publishedDate (line 86) | public Builder publishedDate(String publishedDate) {
      method description (line 91) | public Builder description(String description) {
      method id (line 96) | public Builder id(Long id) {
      method imageUrl (line 101) | public Builder imageUrl(String imageUrl) {
      method build (line 106) | public Book build() {
    method getTitle (line 111) | public String getTitle() {
    method setTitle (line 115) | public void setTitle(String title) {
    method getAuthor (line 119) | public String getAuthor() {
    method setAuthor (line 123) | public void setAuthor(String author) {
    method getCreatedBy (line 127) | public String getCreatedBy() {
    method setCreatedBy (line 131) | public void setCreatedBy(String createdBy) {
    method getCreatedById (line 135) | public String getCreatedById() {
    method setCreatedById (line 139) | public void setCreatedById(String createdById) {
    method getPublishedDate (line 143) | public String getPublishedDate() {
    method setPublishedDate (line 147) | public void setPublishedDate(String publishedDate) {
    method getDescription (line 151) | public String getDescription() {
    method setDescription (line 155) | public void setDescription(String description) {
    method getId (line 159) | public Long getId() {
    method setId (line 163) | public void setId(Long id) {
    method getImageUrl (line 167) | public String getImageUrl() {
    method setImageUrl (line 171) | public void setImageUrl(String imageUrl) {
    method toString (line 176) | @Override

FILE: bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/objects/Result.java
  class Result (line 21) | public class Result<K> {
    method Result (line 26) | public Result(List<K> result, String cursor) {
    method Result (line 31) | public Result(List<K> result) {

FILE: bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/util/CloudStorageHelper.java
  class CloudStorageHelper (line 36) | public class CloudStorageHelper {
    method uploadFile (line 51) | @SuppressWarnings("deprecation")
    method checkFileExtension (line 80) | private void checkFileExtension(String fileName) throws ServletExcepti...

FILE: bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/util/DatastoreSessionFilter.java
  class DatastoreSessionFilter (line 54) | public class DatastoreSessionFilter implements Filter {
    method init (line 60) | @Override
    method doFilter (line 77) | @Override
    method mapToString (line 118) | @SuppressWarnings({"unused", "JdkObsolete"})
    method destroy (line 127) | @Override
    method getCookieValue (line 131) | protected String getCookieValue(HttpServletRequest req, String cookieN...
    method deleteSessionVariables (line 149) | protected void deleteSessionVariables(String sessionId, String... varN...
    method deleteSessionWithValue (line 172) | protected void deleteSessionWithValue(String varName, String varValue) {
    method setSessionVariables (line 198) | protected void setSessionVariables(String sessionId, Map<String, Strin...
    method loadSessionVariables (line 234) | protected Map<String, String> loadSessionVariables(HttpServletRequest ...

FILE: bookshelf-standard/4-auth/src/main/java/com/example/getstarted/auth/ListByUserFilter.java
  class ListByUserFilter (line 31) | public class ListByUserFilter implements Filter {
    method init (line 33) | @Override
    method doFilter (line 37) | @Override
    method destroy (line 52) | @Override

FILE: bookshelf-standard/4-auth/src/main/java/com/example/getstarted/auth/LoginServlet.java
  class LoginServlet (line 29) | @SuppressWarnings("serial")
    method doGet (line 31) | @Override

FILE: bookshelf-standard/4-auth/src/main/java/com/example/getstarted/auth/LogoutFilter.java
  class LogoutFilter (line 32) | public class LogoutFilter implements Filter {
    method init (line 35) | @Override
    method doFilter (line 39) | @Override
    method destroy (line 56) | @Override

FILE: bookshelf-standard/4-auth/src/main/java/com/example/getstarted/auth/LogoutServlet.java
  class LogoutServlet (line 27) | @SuppressWarnings("serial")
    method doGet (line 30) | @Override

FILE: bookshelf-standard/4-auth/src/main/java/com/example/getstarted/basicactions/CreateBookServlet.java
  class CreateBookServlet (line 37) | @SuppressWarnings("serial")
    method doGet (line 41) | @Override
    method doPost (line 52) | @Override

FILE: bookshelf-standard/4-auth/src/main/java/com/example/getstarted/basicactions/DeleteBookServlet.java
  class DeleteBookServlet (line 26) | @SuppressWarnings("serial")
    method doGet (line 29) | @Override

FILE: bookshelf-standard/4-auth/src/main/java/com/example/getstarted/basicactions/ListBookServlet.java
  class ListBookServlet (line 34) | @SuppressWarnings("serial")
    method init (line 37) | @Override
    method doGet (line 78) | @Override

FILE: bookshelf-standard/4-auth/src/main/java/com/example/getstarted/basicactions/ListByUserServlet.java
  class ListByUserServlet (line 30) | @SuppressWarnings("serial")
    method doGet (line 33) | @Override

FILE: bookshelf-standard/4-auth/src/main/java/com/example/getstarted/basicactions/ReadBookServlet.java
  class ReadBookServlet (line 27) | @SuppressWarnings("serial")
    method doGet (line 30) | @Override

FILE: bookshelf-standard/4-auth/src/main/java/com/example/getstarted/basicactions/UpdateBookServlet.java
  class UpdateBookServlet (line 36) | @SuppressWarnings("serial")
    method doGet (line 38) | @Override
    method doPost (line 54) | @Override

FILE: bookshelf-standard/4-auth/src/main/java/com/example/getstarted/daos/BookDao.java
  type BookDao (line 23) | public interface BookDao {
    method createBook (line 24) | Long createBook(Book book) throws SQLException;
    method readBook (line 26) | Book readBook(Long bookId) throws SQLException;
    method updateBook (line 28) | void updateBook(Book book) throws SQLException;
    method deleteBook (line 30) | void deleteBook(Long bookId) throws SQLException;
    method listBooks (line 32) | Result<Book> listBooks(String startCursor) throws SQLException;
    method listBooksByUser (line 34) | Result<Book> listBooksByUser(String userId, String startCursor) throws...

FILE: bookshelf-standard/4-auth/src/main/java/com/example/getstarted/daos/CloudSqlDao.java
  class CloudSqlDao (line 30) | public class CloudSqlDao implements BookDao {
    method CloudSqlDao (line 37) | public CloudSqlDao(final String url) throws SQLException {
    method createBook (line 51) | @Override
    method readBook (line 76) | @Override
    method updateBook (line 100) | @Override
    method deleteBook (line 120) | @Override
    method listBooks (line 132) | @Override
    method listBooksByUser (line 176) | @Override

FILE: bookshelf-standard/4-auth/src/main/java/com/example/getstarted/daos/DatastoreDao.java
  class DatastoreDao (line 37) | public class DatastoreDao implements BookDao {
    method DatastoreDao (line 43) | public DatastoreDao() {
    method entityToBook (line 49) | public Book entityToBook(Entity entity) {
    method createBook (line 64) | @Override
    method readBook (line 81) | @Override
    method updateBook (line 93) | @Override
    method deleteBook (line 110) | @Override
    method entitiesToBooks (line 118) | public List<Book> entitiesToBooks(Iterator<Entity> results) {
    method listBooks (line 128) | @Override
    method listBooksByUser (line 151) | @Override

FILE: bookshelf-standard/4-auth/src/main/java/com/example/getstarted/objects/Book.java
  class Book (line 19) | public class Book {
    method Book (line 43) | private Book(Builder builder) {
    class Builder (line 56) | public static class Builder {
      method title (line 66) | public Builder title(String title) {
      method author (line 71) | public Builder author(String author) {
      method createdBy (line 76) | public Builder createdBy(String createdBy) {
      method createdById (line 81) | public Builder createdById(String createdById) {
      method publishedDate (line 86) | public Builder publishedDate(String publishedDate) {
      method description (line 91) | public Builder description(String description) {
      method id (line 96) | public Builder id(Long id) {
      method imageUrl (line 101) | public Builder imageUrl(String imageUrl) {
      method build (line 106) | public Book build() {
    method getTitle (line 111) | public String getTitle() {
    method setTitle (line 115) | public void setTitle(String title) {
    method getAuthor (line 119) | public String getAuthor() {
    method setAuthor (line 123) | public void setAuthor(String author) {
    method getCreatedBy (line 127) | public String getCreatedBy() {
    method setCreatedBy (line 131) | public void setCreatedBy(String createdBy) {
    method getCreatedById (line 135) | public String getCreatedById() {
    method setCreatedById (line 139) | public void setCreatedById(String createdById) {
    method getPublishedDate (line 143) | public String getPublishedDate() {
    method setPublishedDate (line 147) | public void setPublishedDate(String publishedDate) {
    method getDescription (line 151) | public String getDescription() {
    method setDescription (line 155) | public void setDescription(String description) {
    method getId (line 159) | public Long getId() {
    method setId (line 163) | public void setId(Long id) {
    method getImageUrl (line 167) | public String getImageUrl() {
    method setImageUrl (line 171) | public void setImageUrl(String imageUrl) {
    method toString (line 176) | @Override

FILE: bookshelf-standard/4-auth/src/main/java/com/example/getstarted/objects/Result.java
  class Result (line 21) | public class Result<K> {
    method Result (line 26) | public Result(List<K> result, String cursor) {
    method Result (line 31) | public Result(List<K> result) {

FILE: bookshelf-standard/4-auth/src/main/java/com/example/getstarted/util/CloudStorageHelper.java
  class CloudStorageHelper (line 36) | public class CloudStorageHelper {
    method uploadFile (line 51) | public String uploadFile(FileItemStream fileStream, final String bucke...
    method checkFileExtension (line 79) | private void checkFileExtension(String fileName) throws ServletExcepti...

FILE: bookshelf-standard/4-auth/src/main/java/com/example/getstarted/util/DatastoreSessionFilter.java
  class DatastoreSessionFilter (line 54) | public class DatastoreSessionFilter implements Filter {
    method init (line 60) | @Override
    method doFilter (line 77) | @Override
    method mapToString (line 118) | @SuppressWarnings({"unused", "JdkObsolete"})
    method destroy (line 127) | @Override
    method getCookieValue (line 131) | protected String getCookieValue(HttpServletRequest req, String cookieN...
    method deleteSessionVariables (line 149) | protected void deleteSessionVariables(String sessionId, String... varN...
    method deleteSessionWithValue (line 172) | protected void deleteSessionWithValue(String varName, String varValue) {
    method setSessionVariables (line 198) | protected void setSessionVariables(String sessionId, Map<String, Strin...
    method loadSessionVariables (line 234) | protected Map<String, String> loadSessionVariables(HttpServletRequest ...

FILE: bookshelf-standard/5-logging/src/main/java/com/example/getstarted/auth/ListByUserFilter.java
  class ListByUserFilter (line 33) | public class ListByUserFilter implements Filter {
    method init (line 39) | @Override
    method doFilter (line 43) | @Override
    method destroy (line 68) | @Override

FILE: bookshelf-standard/5-logging/src/main/java/com/example/getstarted/auth/LoginServlet.java
  class LoginServlet (line 31) | @SuppressWarnings("serial")
    method doGet (line 36) | @Override

FILE: bookshelf-standard/5-logging/src/main/java/com/example/getstarted/auth/LogoutFilter.java
  class LogoutFilter (line 34) | public class LogoutFilter implements Filter {
    method init (line 39) | @Override
    method doFilter (line 43) | @Override
    method destroy (line 60) | @Override

FILE: bookshelf-standard/5-logging/src/main/java/com/example/getstarted/auth/LogoutServlet.java
  class LogoutServlet (line 27) | @SuppressWarnings("serial")
    method doGet (line 30) | @Override

FILE: bookshelf-standard/5-logging/src/main/java/com/example/getstarted/basicactions/CreateBookServlet.java
  class CreateBookServlet (line 39) | @SuppressWarnings("serial")
    method doGet (line 45) | @Override
    method doPost (line 56) | @Override

FILE: bookshelf-standard/5-logging/src/main/java/com/example/getstarted/basicactions/DeleteBookServlet.java
  class DeleteBookServlet (line 26) | @SuppressWarnings("serial")
    method doGet (line 29) | @Override

FILE: bookshelf-standard/5-logging/src/main/java/com/example/getstarted/basicactions/ListBookServlet.java
  class ListBookServlet (line 37) | @SuppressWarnings("serial")
    method init (line 42) | @Override
    method doGet (line 83) | @Override

FILE: bookshelf-standard/5-logging/src/main/java/com/example/getstarted/basicactions/ListByUserServlet.java
  class ListByUserServlet (line 32) | @SuppressWarnings("serial")
    method doGet (line 37) | @Override

FILE: bookshelf-standard/5-logging/src/main/java/com/example/getstarted/basicactions/ReadBookServlet.java
  class ReadBookServlet (line 29) | @SuppressWarnings("serial")
    method doGet (line 36) | @Override

FILE: bookshelf-standard/5-logging/src/main/java/com/example/getstarted/basicactions/UpdateBookServlet.java
  class UpdateBookServlet (line 36) | @SuppressWarnings("serial")
    method doGet (line 38) | @Override
    method doPost (line 54) | @Override

FILE: bookshelf-standard/5-logging/src/main/java/com/example/getstarted/daos/BookDao.java
  type BookDao (line 23) | public interface BookDao {
    method createBook (line 24) | Long createBook(Book book) throws SQLException;
    method readBook (line 26) | Book readBook(Long bookId) throws SQLException;
    method updateBook (line 28) | void updateBook(Book book) throws SQLException;
    method deleteBook (line 30) | void deleteBook(Long bookId) throws SQLException;
    method listBooks (line 32) | Result<Book> listBooks(String startCursor) throws SQLException;
    method listBooksByUser (line 34) | Result<Book> listBooksByUser(String userId, String startCursor) throws...

FILE: bookshelf-standard/5-logging/src/main/java/com/example/getstarted/daos/CloudSqlDao.java
  class CloudSqlDao (line 30) | public class CloudSqlDao implements BookDao {
    method CloudSqlDao (line 37) | public CloudSqlDao(final String url) throws SQLException {
    method createBook (line 51) | @Override
    method readBook (line 76) | @Override
    method updateBook (line 100) | @Override
    method deleteBook (line 120) | @Override
    method listBooks (line 132) | @Override
    method listBooksByUser (line 176) | @Override

FILE: bookshelf-standard/5-logging/src/main/java/com/example/getstarted/daos/DatastoreDao.java
  class DatastoreDao (line 37) | public class DatastoreDao implements BookDao {
    method DatastoreDao (line 43) | public DatastoreDao() {
    method entityToBook (line 49) | public Book entityToBook(Entity entity) {
    method createBook (line 64) | @Override
    method readBook (line 81) | @Override
    method updateBook (line 93) | @Override
    method deleteBook (line 110) | @Override
    method entitiesToBooks (line 118) | public List<Book> entitiesToBooks(Iterator<Entity> results) {
    method listBooks (line 128) | @Override
    method listBooksByUser (line 151) | @Override

FILE: bookshelf-standard/5-logging/src/main/java/com/example/getstarted/objects/Book.java
  class Book (line 19) | public class Book {
    method Book (line 43) | private Book(Builder builder) {
    class Builder (line 56) | public static class Builder {
      method title (line 66) | public Builder title(String title) {
      method author (line 71) | public Builder author(String author) {
      method createdBy (line 76) | public Builder createdBy(String createdBy) {
      method createdById (line 81) | public Builder createdById(String createdById) {
      method publishedDate (line 86) | public Builder publishedDate(String publishedDate) {
      method description (line 91) | public Builder description(String description) {
      method id (line 96) | public Builder id(Long id) {
      method imageUrl (line 101) | public Builder imageUrl(String imageUrl) {
      method build (line 106) | public Book build() {
    method getTitle (line 111) | public String getTitle() {
    method setTitle (line 115) | public void setTitle(String title) {
    method getAuthor (line 119) | public String getAuthor() {
    method setAuthor (line 123) | public void setAuthor(String author) {
    method getCreatedBy (line 127) | public String getCreatedBy() {
    method setCreatedBy (line 131) | public void setCreatedBy(String createdBy) {
    method getCreatedById (line 135) | public String getCreatedById() {
    method setCreatedById (line 139) | public void setCreatedById(String createdById) {
    method getPublishedDate (line 143) | public String getPublishedDate() {
    method setPublishedDate (line 147) | public void setPublishedDate(String publishedDate) {
    method getDescription (line 151) | public String getDescription() {
    method setDescription (line 155) | public void setDescription(String description) {
    method getId (line 159) | public Long getId() {
    method setId (line 163) | public void setId(Long id) {
    method getImageUrl (line 167) | public String getImageUrl() {
    method setImageUrl (line 171) | public void setImageUrl(String imageUrl) {
    method toString (line 176) | @Override

FILE: bookshelf-standard/5-logging/src/main/java/com/example/getstarted/objects/Result.java
  class Result (line 21) | public class Result<K> {
    method Result (line 26) | public Result(List<K> result, String cursor) {
    method Result (line 31) | public Result(List<K> result) {

FILE: bookshelf-standard/5-logging/src/main/java/com/example/getstarted/util/CloudStorageHelper.java
  class CloudStorageHelper (line 38) | public class CloudStorageHelper {
    method uploadFile (line 54) | public String uploadFile(FileItemStream fileStream, final String bucke...
    method checkFileExtension (line 84) | private void checkFileExtension(String fileName) throws ServletExcepti...

FILE: bookshelf-standard/5-logging/src/main/java/com/example/getstarted/util/DatastoreSessionFilter.java
  class DatastoreSessionFilter (line 54) | public class DatastoreSessionFilter implements Filter {
    method init (line 60) | @Override
    method doFilter (line 77) | @Override
    method mapToString (line 118) | @SuppressWarnings({"unused", "JdkObsolete"})
    method destroy (line 127) | @Override
    method getCookieValue (line 131) | protected String getCookieValue(HttpServletRequest req, String cookieN...
    method deleteSessionVariables (line 149) | protected void deleteSessionVariables(String sessionId, String... varN...
    method deleteSessionWithValue (line 172) | protected void deleteSessionWithValue(String varName, String varValue) {
    method setSessionVariables (line 198) | protected void setSessionVariables(String sessionId, Map<String, Strin...
    method loadSessionVariables (line 234) | protected Map<String, String> loadSessionVariables(HttpServletRequest ...

FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/CreateBookServlet.java
  class CreateBookServlet (line 41) | @SuppressWarnings("serial")
    method doGet (line 49) | @Override
    method doPost (line 58) | @Override

FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/DeleteBookServlet.java
  class DeleteBookServlet (line 27) | @SuppressWarnings("serial")
    method doGet (line 33) | @Override

FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/ErrorsBookServlet.java
  class ErrorsBookServlet (line 26) | @SuppressWarnings("serial")
    method doGet (line 31) | @Override

FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/ListBookServlet.java
  class ListBookServlet (line 33) | @SuppressWarnings("serial")
    method doGet (line 42) | @Override

FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/ReadBookServlet.java
  class ReadBookServlet (line 31) | @SuppressWarnings("serial")
    method doGet (line 39) | @Override

FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/UpdateBookServlet.java
  class UpdateBookServlet (line 38) | @SuppressWarnings("serial")
    method doGet (line 43) | @Override
    method doPost (line 58) | @Override

FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/daos/BookDao.java
  type BookDao (line 22) | public interface BookDao {
    method createBook (line 23) | String createBook(Book book);
    method readBook (line 25) | Book readBook(String bookId);
    method updateBook (line 27) | void updateBook(Book book);
    method deleteBook (line 29) | void deleteBook(String bookId);
    method listBooks (line 31) | Result<Book> listBooks(String startCursor);
    method listBooksByUser (line 33) | Result<Book> listBooksByUser(String userId, String startCursor);

FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/daos/FirestoreDao.java
  class FirestoreDao (line 37) | public class FirestoreDao implements BookDao {
    method FirestoreDao (line 40) | public FirestoreDao() {
    method documentToBook (line 46) | private Book documentToBook(DocumentSnapshot document) {
    method createBook (line 67) | @Override
    method readBook (line 91) | @Override
    method updateBook (line 105) | @Override
    method deleteBook (line 126) | @Override
    method documentsToBooks (line 137) | private List<Book> documentsToBooks(List<QueryDocumentSnapshot> docume...
    method listBooks (line 147) | @Override
    method listBooksByUser (line 169) | @Override

FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/objects/Book.java
  class Book (line 19) | public class Book {
    method Book (line 39) | private Book(Builder builder) {
    class Builder (line 50) | public static class Builder {
      method title (line 60) | public Builder title(String title) {
      method author (line 65) | public Builder author(String author) {
      method createdBy (line 70) | public Builder createdBy(String createdBy) {
      method createdById (line 75) | public Builder createdById(String createdById) {
      method publishedDate (line 80) | public Builder publishedDate(String publishedDate) {
      method description (line 85) | public Builder description(String description) {
      method id (line 90) | public Builder id(String id) {
      method imageUrl (line 95) | public Builder imageUrl(String imageUrl) {
      method build (line 100) | public Book build() {
    method getTitle (line 105) | public String getTitle() {
    method setTitle (line 109) | public void setTitle(String title) {
    method getAuthor (line 113) | public String getAuthor() {
    method setAuthor (line 117) | public void setAuthor(String author) {
    method getCreatedBy (line 121) | public String getCreatedBy() {
    method setCreatedBy (line 125) | public void setCreatedBy(String createdBy) {
    method getCreatedById (line 129) | public String getCreatedById() {
    method setCreatedById (line 133) | public void setCreatedById(String createdById) {
    method getPublishedDate (line 137) | public String getPublishedDate() {
    method setPublishedDate (line 141) | public void setPublishedDate(String publishedDate) {
    method getDescription (line 145) | public String getDescription() {
    method setDescription (line 149) | public void setDescription(String description) {
    method getId (line 153) | public String getId() {
    method setId (line 157) | public void setId(String id) {
    method getImageUrl (line 161) | public String getImageUrl() {
    method setImageUrl (line 165) | public void setImageUrl(String imageUrl) {
    method toString (line 169) | @Override

FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/objects/Result.java
  class Result (line 21) | public class Result<K> {
    method getCursor (line 25) | public String getCursor() {
    method setCursor (line 29) | public void setCursor(String cursor) {
    method getResult (line 33) | public List<K> getResult() {
    method setResult (line 37) | public void setResult(List<K> result) {
    method Result (line 41) | public Result(List<K> result, String cursor) {
    method Result (line 46) | public Result(List<K> result) {

FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/util/BookshelfContextListener.java
  class BookshelfContextListener (line 25) | @WebListener("Creates BookDao and other servlet context objects for reus...
    method contextDestroyed (line 27) | @Override
    method contextInitialized (line 31) | @Override

FILE: bookshelf/1-cloud-run/src/main/java/com/example/getstarted/util/CloudStorageHelper.java
  class CloudStorageHelper (line 38) | public class CloudStorageHelper {
    method uploadFile (line 55) | public String uploadFile(FileItemStream fileStream, final String bucke...
    method checkFileExtension (line 85) | private void checkFileExtension(String fileName) throws ServletExcepti...

FILE: gce/src/main/java/com/example/getstarted/basicactions/HelloworldController.java
  class HelloworldController (line 25) | @WebServlet(value = "/")
    method doGet (line 28) | @Override

FILE: gce/src/test/java/com/example/getstarted/basicactions/UserJourneyTestIT.java
  class UserJourneyTestIT (line 34) | @RunWith(JUnit4.class)
    method setupClass (line 40) | @BeforeClass
    method setup (line 46) | @Before
    method tearDown (line 51) | @After
    method userJourney (line 56) | @Test

FILE: helloworld-jsp/src/main/java/org/example/appengine/hello/HelloInfo.java
  class HelloInfo (line 22) | public class HelloInfo {
    method getInfo (line 24) | public static String getInfo() {
Condensed preview — 219 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (582K chars).
[
  {
    "path": ".github/CODEOWNERS",
    "chars": 273,
    "preview": "# Code owners file.\n# This file controls who is tagged for review for any given pull request.\n\n# The java-samples-review"
  },
  {
    "path": ".github/blunderbuss.yml",
    "chars": 121,
    "preview": "assign_issues:\n  - GoogleCloudPlatform/java-samples-reviewers\nassign_prs:\n  - GoogleCloudPlatform/java-samples-reviewers"
  },
  {
    "path": ".github/sync-repo-settings.yaml",
    "chars": 580,
    "preview": "rebaseMergeAllowed: true\nsquashMergeAllowed: true\nmergeCommitAllowed: false\nbranchProtectionRules:\n- pattern: main\n  isA"
  },
  {
    "path": ".gitignore",
    "chars": 326,
    "preview": "# Eclipse files\n.project\n.classpath\n.settings\n\n# IntelliJ IDEA\n.Idea\n*.iml\n.idea/\n\n# Target folders\ntarget/\nbuild/\nout/\n"
  },
  {
    "path": ".gitmodules",
    "chars": 0,
    "preview": ""
  },
  {
    "path": ".kokoro/java11/common.cfg",
    "chars": 1195,
    "preview": "# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": ".kokoro/java11/continuous.cfg",
    "chars": 787,
    "preview": "# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": ".kokoro/java11/periodic.cfg",
    "chars": 792,
    "preview": "# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": ".kokoro/java11/presubmit.cfg",
    "chars": 796,
    "preview": "# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": ".kokoro/java8/common.cfg",
    "chars": 1191,
    "preview": "# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": ".kokoro/java8/continuous.cfg",
    "chars": 784,
    "preview": "# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": ".kokoro/java8/periodic.cfg",
    "chars": 793,
    "preview": "# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": ".kokoro/java8/presubmit.cfg",
    "chars": 796,
    "preview": "# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": ".kokoro/lint/common.cfg",
    "chars": 1230,
    "preview": "# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": ".kokoro/lint/presubmit.cfg",
    "chars": 741,
    "preview": "# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": ".kokoro/tests/run_diff_only.sh",
    "chars": 645,
    "preview": "#!/usr/bin/env bash\n# Copyright 2017 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": ".kokoro/tests/run_lint.sh",
    "chars": 1182,
    "preview": "#!/usr/bin/env bash\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# yo"
  },
  {
    "path": ".kokoro/tests/run_tests.sh",
    "chars": 5148,
    "preview": "#!/bin/bash\n# Copyright 2017 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may n"
  },
  {
    "path": ".kokoro/trampoline.sh",
    "chars": 636,
    "preview": "#!/bin/bash\n# Copyright 2017 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 1981,
    "preview": "# Contributor Code of Conduct\n\nAs contributors and maintainers of this project,\nand in the interest of fostering an open"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1698,
    "preview": "# How to become a contributor and submit your own code\n\n## Contributor License Agreements\n\nWe'd love to accept your samp"
  },
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 1707,
    "preview": "# Getting started on Google Cloud Platform for Java®\n\n[![CircleCI Build Status](https://circleci.com/gh/GoogleCloudPlatf"
  },
  {
    "path": "appengine-standard-java8/deployAll.sh",
    "chars": 1381,
    "preview": "#!/bin/bash\n# Copyright 2017 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may n"
  },
  {
    "path": "appengine-standard-java8/helloworld-gae-javasdk-tools/README.md",
    "chars": 2750,
    "preview": "HelloWorld for App Engine Standard (Java 8) using the App Engine Java SDK tooling\n============================\n\nThis sam"
  },
  {
    "path": "appengine-standard-java8/helloworld-gae-javasdk-tools/build.gradle",
    "chars": 2771,
    "preview": "// Copyright 2017 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\");\n//  you may not use"
  },
  {
    "path": "appengine-standard-java8/helloworld-gae-javasdk-tools/gradle/wrapper/gradle-wrapper.properties",
    "chars": 230,
    "preview": "#Tue Jun 13 16:53:48 PDT 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
  },
  {
    "path": "appengine-standard-java8/helloworld-gae-javasdk-tools/gradlew",
    "chars": 5299,
    "preview": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up"
  },
  {
    "path": "appengine-standard-java8/helloworld-gae-javasdk-tools/gradlew.bat",
    "chars": 2260,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@r"
  },
  {
    "path": "appengine-standard-java8/helloworld-gae-javasdk-tools/pom.xml",
    "chars": 7105,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\nCopyright 2017 Google Inc.\n\nLicensed under the Apache License, Version 2.0 ("
  },
  {
    "path": "appengine-standard-java8/helloworld-gae-javasdk-tools/settings.gradle",
    "chars": 595,
    "preview": "/*\n * This settings file was generated by the Gradle 'init' task.\n *\n * The settings file is used to specify which proje"
  },
  {
    "path": "appengine-standard-java8/helloworld-gae-javasdk-tools/src/main/java/com/example/appengine/java8/HelloAppEngine.java",
    "chars": 1741,
    "preview": "/*\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not us"
  },
  {
    "path": "appengine-standard-java8/helloworld-gae-javasdk-tools/src/main/webapp/WEB-INF/appengine-web.xml",
    "chars": 857,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  Copyright 2017 Google Inc.\n\n  Licensed under the Apache License, Version 2"
  },
  {
    "path": "appengine-standard-java8/helloworld-gae-javasdk-tools/src/main/webapp/index.jsp",
    "chars": 1272,
    "preview": "<!DOCTYPE html>\n<!-- [START_EXCLUDE] -->\n<%--\n  ~ Copyright 2017 Google Inc.\n  ~\n  ~ Licensed under the Apache License, "
  },
  {
    "path": "appengine-standard-java8/helloworld-gae-javasdk-tools/src/test/java/com/example/appengine/java8/HelloAppEngineTest.java",
    "chars": 2625,
    "preview": "/*\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not us"
  },
  {
    "path": "appengine-standard-java8/kotlin-appengine-standard/.gitignore",
    "chars": 241,
    "preview": "hotspot.log\n*.iml\n*.ipr\n*.iws\n.gradle/\nbuild/\ntarget/\nclasses/\n/var\npom.xml.versionsBackup\ntest-output/\n/atlassian-ide-p"
  },
  {
    "path": "appengine-standard-java8/kotlin-appengine-standard/README.md",
    "chars": 2002,
    "preview": "App Engine Java Kotlin Servlet 3.1 with Java8\n===\n\n## Sample Servlet 3.1 written in Kotlin for use with App Engine Java8"
  },
  {
    "path": "appengine-standard-java8/kotlin-appengine-standard/nbactions.xml",
    "chars": 2631,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\nCopyright 2017 Google Inc.\nLicensed under the Apache License, Version 2.0 (t"
  },
  {
    "path": "appengine-standard-java8/kotlin-appengine-standard/pom.xml",
    "chars": 4163,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\nCopyright 2017 Google Inc.\nLicensed under the Apache License, Version 2.0 (t"
  },
  {
    "path": "appengine-standard-java8/kotlin-appengine-standard/src/main/kotlin/HomeController.kt",
    "chars": 572,
    "preview": "// See https://github.com/JetBrains/kotlin-examples/blob/master/LICENSE\npackage org.jetbrains.kotlin.demo\n\nimport javax."
  },
  {
    "path": "appengine-standard-java8/kotlin-appengine-standard/src/main/webapp/WEB-INF/appengine-web.xml",
    "chars": 885,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright 2017 Google Inc.\nLicensed under the Apache License, Version 2.0 (t"
  },
  {
    "path": "appengine-standard-java8/kotlin-appengine-standard/src/main/webapp/WEB-INF/logging.properties",
    "chars": 1027,
    "preview": "# Copyright 2017 Google Inc.\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this fi"
  },
  {
    "path": "appengine-standard-java8/kotlin-sb-appengine-standard/.gitignore",
    "chars": 241,
    "preview": "hotspot.log\n*.iml\n*.ipr\n*.iws\n.gradle/\nbuild/\ntarget/\nclasses/\n/var\npom.xml.versionsBackup\ntest-output/\n/atlassian-ide-p"
  },
  {
    "path": "appengine-standard-java8/kotlin-sb-appengine-standard/README.md",
    "chars": 2012,
    "preview": "App Engine Java SpringBoot Kotlin application\n===\n\n## Sample SpringBoot application written in Kotlin for use with App E"
  },
  {
    "path": "appengine-standard-java8/kotlin-sb-appengine-standard/nbactions.xml",
    "chars": 2631,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\nCopyright 2017 Google Inc.\nLicensed under the Apache License, Version 2.0 (t"
  },
  {
    "path": "appengine-standard-java8/kotlin-sb-appengine-standard/pom.xml",
    "chars": 5431,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\nCopyright 2017 Google Inc.\nLicensed under the Apache License, Version 2.0 (t"
  },
  {
    "path": "appengine-standard-java8/kotlin-sb-appengine-standard/src/main/kotlin/org/jetbrains/kotlin/demo/Application.kt",
    "chars": 476,
    "preview": "// See https://github.com/JetBrains/kotlin-examples/blob/master/LICENSE\npackage org.jetbrains.kotlin.demo\n\nimport org.sp"
  },
  {
    "path": "appengine-standard-java8/kotlin-sb-appengine-standard/src/main/kotlin/org/jetbrains/kotlin/demo/Greeting.kt",
    "chars": 162,
    "preview": "// See https://github.com/JetBrains/kotlin-examples/blob/master/LICENSE\npackage org.jetbrains.kotlin.demo\n\ndata class Gr"
  },
  {
    "path": "appengine-standard-java8/kotlin-sb-appengine-standard/src/main/kotlin/org/jetbrains/kotlin/demo/GreetingController.kt",
    "chars": 693,
    "preview": "// See https://github.com/JetBrains/kotlin-examples/blob/master/LICENSE\npackage org.jetbrains.kotlin.demo\n\nimport org.sp"
  },
  {
    "path": "appengine-standard-java8/kotlin-sb-appengine-standard/src/main/webapp/WEB-INF/appengine-web.xml",
    "chars": 885,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright 2017 Google Inc.\nLicensed under the Apache License, Version 2.0 (t"
  },
  {
    "path": "appengine-standard-java8/kotlin-sb-appengine-standard/src/main/webapp/WEB-INF/logging.properties",
    "chars": 1027,
    "preview": "# Copyright 2017 Google Inc.\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this fi"
  },
  {
    "path": "appengine-standard-java8/kotlin-spark-appengine-standard/.gitignore",
    "chars": 241,
    "preview": "hotspot.log\n*.iml\n*.ipr\n*.iws\n.gradle/\nbuild/\ntarget/\nclasses/\n/var\npom.xml.versionsBackup\ntest-output/\n/atlassian-ide-p"
  },
  {
    "path": "appengine-standard-java8/kotlin-spark-appengine-standard/README.md",
    "chars": 2101,
    "preview": "App Engine SparkJava Kotlin with Java8\n===\n\n## Sample SparkJava application written in Kotlin for use with App Engine Ja"
  },
  {
    "path": "appengine-standard-java8/kotlin-spark-appengine-standard/pom.xml",
    "chars": 6085,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\nCopyright 2017 Google Inc.\nLicensed under the Apache License, Version 2.0 (t"
  },
  {
    "path": "appengine-standard-java8/kotlin-spark-appengine-standard/src/main/kotlin/MainApp.kt",
    "chars": 1477,
    "preview": "/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not u"
  },
  {
    "path": "appengine-standard-java8/kotlin-spark-appengine-standard/src/main/kotlin/SparkInitFilter.kt",
    "chars": 1082,
    "preview": "/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not u"
  },
  {
    "path": "appengine-standard-java8/kotlin-spark-appengine-standard/src/main/webapp/WEB-INF/appengine-web.xml",
    "chars": 885,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nCopyright 2017 Google Inc.\nLicensed under the Apache License, Version 2.0 (t"
  },
  {
    "path": "appengine-standard-java8/kotlin-spark-appengine-standard/src/main/webapp/WEB-INF/logging.properties",
    "chars": 1027,
    "preview": "# Copyright 2017 Google Inc.\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this fi"
  },
  {
    "path": "background/README.md",
    "chars": 3840,
    "preview": "# Background Processing App on Cloud Run Tutorial\n\nContains the code for using Cloud Firestore, Cloud Translate, and Clo"
  },
  {
    "path": "background/pom.xml",
    "chars": 4267,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\nCopyright 2019 Google LLC\n\n Licensed under the Apache License, Version 2.0 ("
  },
  {
    "path": "background/sample_message.json",
    "chars": 204,
    "preview": "{\n  \"message\":{\n    \"data\":\"Hello world!\",\n    \"attributes\":{\n      \"sourceLang\":\"en\",\n      \"targetLang\":\"es\"\n    },\n  "
  },
  {
    "path": "background/src/main/java/com/getstarted/background/functions/CreateServlet.java",
    "chars": 2896,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "background/src/main/java/com/getstarted/background/functions/TranslateServlet.java",
    "chars": 5668,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "background/src/main/java/com/getstarted/background/objects/PubSubMessage.java",
    "chars": 1156,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "background/src/main/java/com/getstarted/background/objects/TranslateAttributes.java",
    "chars": 1149,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "background/src/main/java/com/getstarted/background/objects/TranslateMessage.java",
    "chars": 2067,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "background/src/main/java/com/getstarted/background/util/BackgroundContextListener.java",
    "chars": 2709,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "background/src/main/webapp/base.jsp",
    "chars": 1390,
    "preview": "<!--\nCopyright 2019 Google LLC\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this f"
  },
  {
    "path": "background/src/main/webapp/form.jsp",
    "chars": 1629,
    "preview": "<!--\nCopyright 2019 Google LLC\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this f"
  },
  {
    "path": "background/src/main/webapp/list.jsp",
    "chars": 1871,
    "preview": "<!--\nCopyright 2019 Google LLC\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this f"
  },
  {
    "path": "background/src/test/java/com/getstarted/background/UserJourneyTestIT.java",
    "chars": 5320,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "bookshelf/1-cloud-run/README.md",
    "chars": 1545,
    "preview": "# Bookshelf App for Java on Cloud Run Tutorial\n\nContains the code for using Cloud Firestore.\n\nThis is part of a [Bookshe"
  },
  {
    "path": "bookshelf/1-cloud-run/pom.xml",
    "chars": 4472,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\nCopyright 2019 Google LLC\n\n Licensed under the Apache License, Version 2.0 ("
  },
  {
    "path": "bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/CreateBookServlet.java",
    "chars": 4064,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/DeleteBookServlet.java",
    "chars": 1387,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/ErrorsBookServlet.java",
    "chars": 1242,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/ListBookServlet.java",
    "chars": 2537,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/ReadBookServlet.java",
    "chars": 1817,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "bookshelf/1-cloud-run/src/main/java/com/example/getstarted/basicactions/UpdateBookServlet.java",
    "chars": 3838,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "bookshelf/1-cloud-run/src/main/java/com/example/getstarted/daos/BookDao.java",
    "chars": 1056,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "bookshelf/1-cloud-run/src/main/java/com/example/getstarted/daos/FirestoreDao.java",
    "chars": 6707,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "bookshelf/1-cloud-run/src/main/java/com/example/getstarted/objects/Book.java",
    "chars": 4300,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "bookshelf/1-cloud-run/src/main/java/com/example/getstarted/objects/Result.java",
    "chars": 1240,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "bookshelf/1-cloud-run/src/main/java/com/example/getstarted/util/BookshelfContextListener.java",
    "chars": 2197,
    "preview": "/* Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use th"
  },
  {
    "path": "bookshelf/1-cloud-run/src/main/java/com/example/getstarted/util/CloudStorageHelper.java",
    "chars": 3734,
    "preview": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use"
  },
  {
    "path": "bookshelf/1-cloud-run/src/main/webapp/WEB-INF/web.xml",
    "chars": 2484,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n Copyright 2023 Google LLC\n Licensed under the Apache License, Version 2.0 ("
  },
  {
    "path": "bookshelf/1-cloud-run/src/main/webapp/base.jsp",
    "chars": 1332,
    "preview": "<!--\nCopyright 2019 Google LLC\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this f"
  },
  {
    "path": "bookshelf/1-cloud-run/src/main/webapp/form.jsp",
    "chars": 2312,
    "preview": "<!--\nCopyright 2019 Google LLC\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this f"
  },
  {
    "path": "bookshelf/1-cloud-run/src/main/webapp/list.jsp",
    "chars": 1663,
    "preview": "<!--\nCopyright 2019 Google LLC\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this f"
  },
  {
    "path": "bookshelf/1-cloud-run/src/main/webapp/view.jsp",
    "chars": 1817,
    "preview": "<!--\nCopyright 2019 Google LLC\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this f"
  },
  {
    "path": "bookshelf-standard/2-structured-data/README.md",
    "chars": 1065,
    "preview": "mvn package appengine:deploymvn package appengine:deploymvn package appengine:deploy# Bookshelf App for Java on App Engi"
  },
  {
    "path": "bookshelf-standard/2-structured-data/jenkins.sh",
    "chars": 1558,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2017 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# "
  },
  {
    "path": "bookshelf-standard/2-structured-data/pom.xml",
    "chars": 5623,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 "
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/basicactions/CreateBookServlet.java",
    "chars": 2359,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/basicactions/DeleteBookServlet.java",
    "chars": 1426,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/basicactions/ListBookServlet.java",
    "chars": 3591,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/basicactions/ReadBookServlet.java",
    "chars": 1584,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/basicactions/UpdateBookServlet.java",
    "chars": 2443,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/daos/BookDao.java",
    "chars": 1091,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/daos/CloudSqlDao.java",
    "chars": 6852,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/daos/DatastoreDao.java",
    "chars": 5529,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/objects/Book.java",
    "chars": 4392,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/objects/Result.java",
    "chars": 968,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/java/com/example/getstarted/util/DatastoreSessionFilter.java",
    "chars": 9621,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/webapp/WEB-INF/appengine-web.xml",
    "chars": 1196,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n Copyright 2015 Google Inc.\n\n Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/webapp/WEB-INF/logging.properties",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/webapp/WEB-INF/web.xml",
    "chars": 4356,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n Copyright 2016 Google Inc.\n Licensed under the Apache License, Version 2.0 "
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/webapp/base.jsp",
    "chars": 2074,
    "preview": "<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this "
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/webapp/form.jsp",
    "chars": 2255,
    "preview": "<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this "
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/webapp/list.jsp",
    "chars": 1636,
    "preview": "<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this "
  },
  {
    "path": "bookshelf-standard/2-structured-data/src/main/webapp/view.jsp",
    "chars": 1790,
    "preview": "<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this "
  },
  {
    "path": "bookshelf-standard/3-binary-data/README.md",
    "chars": 1359,
    "preview": "# Bookshelf App for Java on App Engine Standard Tutorial\n## Binary Data\n\nContains the code for using Cloud Datastore and"
  },
  {
    "path": "bookshelf-standard/3-binary-data/jenkins.sh",
    "chars": 1627,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2017 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# "
  },
  {
    "path": "bookshelf-standard/3-binary-data/pom.xml",
    "chars": 6192,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 "
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/basicactions/CreateBookServlet.java",
    "chars": 3676,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/basicactions/DeleteBookServlet.java",
    "chars": 1426,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/basicactions/ListBookServlet.java",
    "chars": 4160,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/basicactions/ReadBookServlet.java",
    "chars": 1584,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/basicactions/UpdateBookServlet.java",
    "chars": 3775,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/daos/BookDao.java",
    "chars": 1091,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/daos/CloudSqlDao.java",
    "chars": 6846,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/daos/DatastoreDao.java",
    "chars": 5719,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/objects/Book.java",
    "chars": 4388,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/objects/Result.java",
    "chars": 968,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/util/CloudStorageHelper.java",
    "chars": 3154,
    "preview": "/*\n * Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not us"
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/java/com/example/getstarted/util/DatastoreSessionFilter.java",
    "chars": 9621,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/webapp/WEB-INF/appengine-web.xml",
    "chars": 1196,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n Copyright 2015 Google Inc.\n\n Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/webapp/WEB-INF/logging.properties",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/webapp/WEB-INF/web.xml",
    "chars": 4549,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n Copyright 2016 Google Inc.\n Licensed under the Apache License, Version 2.0 "
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/webapp/base.jsp",
    "chars": 2074,
    "preview": "<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this "
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/webapp/form.jsp",
    "chars": 2285,
    "preview": "<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this "
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/webapp/list.jsp",
    "chars": 1636,
    "preview": "<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this "
  },
  {
    "path": "bookshelf-standard/3-binary-data/src/main/webapp/view.jsp",
    "chars": 1790,
    "preview": "<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this "
  },
  {
    "path": "bookshelf-standard/4-auth/README.md",
    "chars": 1360,
    "preview": "# Bookshelf App for Java on App Engine Standard Tutorial\n## Auth\n\nContains the code for using Cloud Datastore and Cloud "
  },
  {
    "path": "bookshelf-standard/4-auth/jenkins.sh",
    "chars": 1627,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2017 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# "
  },
  {
    "path": "bookshelf-standard/4-auth/pom.xml",
    "chars": 6229,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 "
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/java/com/example/getstarted/auth/ListByUserFilter.java",
    "chars": 1848,
    "preview": "/*\n * Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not us"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/java/com/example/getstarted/auth/LoginServlet.java",
    "chars": 1870,
    "preview": "/*\n * Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not us"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/java/com/example/getstarted/auth/LogoutFilter.java",
    "chars": 1911,
    "preview": "/*\n * Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not us"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/java/com/example/getstarted/auth/LogoutServlet.java",
    "chars": 1422,
    "preview": "/*\n * Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not us"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/java/com/example/getstarted/basicactions/CreateBookServlet.java",
    "chars": 4179,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/java/com/example/getstarted/basicactions/DeleteBookServlet.java",
    "chars": 1426,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/java/com/example/getstarted/basicactions/ListBookServlet.java",
    "chars": 4050,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/java/com/example/getstarted/basicactions/ListByUserServlet.java",
    "chars": 2101,
    "preview": "/*\n * Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not us"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/java/com/example/getstarted/basicactions/ReadBookServlet.java",
    "chars": 1584,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/java/com/example/getstarted/basicactions/UpdateBookServlet.java",
    "chars": 3900,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/java/com/example/getstarted/daos/BookDao.java",
    "chars": 1179,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/java/com/example/getstarted/daos/CloudSqlDao.java",
    "chars": 8686,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/java/com/example/getstarted/daos/DatastoreDao.java",
    "chars": 7552,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/java/com/example/getstarted/objects/Book.java",
    "chars": 4388,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/java/com/example/getstarted/objects/Result.java",
    "chars": 968,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/java/com/example/getstarted/util/CloudStorageHelper.java",
    "chars": 3157,
    "preview": "/*\n * Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not us"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/java/com/example/getstarted/util/DatastoreSessionFilter.java",
    "chars": 9621,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/webapp/WEB-INF/appengine-web.xml",
    "chars": 1196,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n Copyright 2015 Google Inc.\n\n Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/webapp/WEB-INF/datastore-indexes.xml",
    "chars": 293,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<datastore-indexes autoGenerate=\"true\">\n    <datastore-index kind=\"Book4\" ancesto"
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/webapp/WEB-INF/logging.properties",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/webapp/WEB-INF/web.xml",
    "chars": 5887,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n Copyright 2016 Google Inc.\n Licensed under the Apache License, Version 2.0 "
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/webapp/base.jsp",
    "chars": 2021,
    "preview": "<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this "
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/webapp/form.jsp",
    "chars": 2285,
    "preview": "<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this "
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/webapp/list.jsp",
    "chars": 1636,
    "preview": "<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this "
  },
  {
    "path": "bookshelf-standard/4-auth/src/main/webapp/view.jsp",
    "chars": 1790,
    "preview": "<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this "
  },
  {
    "path": "bookshelf-standard/5-logging/README.md",
    "chars": 1355,
    "preview": "# Bookshelf App for Java on App Engine Standard Tutorial\n## Logging\n\nContains the code for using Cloud Datastore and Clo"
  },
  {
    "path": "bookshelf-standard/5-logging/jenkins.sh",
    "chars": 1627,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2017 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# "
  },
  {
    "path": "bookshelf-standard/5-logging/pom.xml",
    "chars": 6229,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 "
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/java/com/example/getstarted/auth/ListByUserFilter.java",
    "chars": 2549,
    "preview": "/*\n * Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not us"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/java/com/example/getstarted/auth/LoginServlet.java",
    "chars": 2136,
    "preview": "/*\n * Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not us"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/java/com/example/getstarted/auth/LogoutFilter.java",
    "chars": 2130,
    "preview": "/*\n * Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not us"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/java/com/example/getstarted/auth/LogoutServlet.java",
    "chars": 1422,
    "preview": "/*\n * Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not us"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/java/com/example/getstarted/basicactions/CreateBookServlet.java",
    "chars": 4247,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/java/com/example/getstarted/basicactions/DeleteBookServlet.java",
    "chars": 1426,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/java/com/example/getstarted/basicactions/ListBookServlet.java",
    "chars": 4395,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/java/com/example/getstarted/basicactions/ListByUserServlet.java",
    "chars": 2402,
    "preview": "/*\n * Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not us"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/java/com/example/getstarted/basicactions/ReadBookServlet.java",
    "chars": 1866,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/java/com/example/getstarted/basicactions/UpdateBookServlet.java",
    "chars": 3844,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/java/com/example/getstarted/daos/BookDao.java",
    "chars": 1179,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/java/com/example/getstarted/daos/CloudSqlDao.java",
    "chars": 8686,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/java/com/example/getstarted/daos/DatastoreDao.java",
    "chars": 7552,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/java/com/example/getstarted/objects/Book.java",
    "chars": 4388,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/java/com/example/getstarted/objects/Result.java",
    "chars": 968,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/java/com/example/getstarted/util/CloudStorageHelper.java",
    "chars": 3419,
    "preview": "/*\n * Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not us"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/java/com/example/getstarted/util/DatastoreSessionFilter.java",
    "chars": 9621,
    "preview": "/* Copyright 2016 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use t"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/webapp/WEB-INF/appengine-web.xml",
    "chars": 1196,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n Copyright 2015 Google Inc.\n\n Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/webapp/WEB-INF/datastore-indexes.xml",
    "chars": 293,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<datastore-indexes autoGenerate=\"true\">\n    <datastore-index kind=\"Book5\" ancesto"
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/webapp/WEB-INF/logging.properties",
    "chars": 425,
    "preview": "# A default java.util.logging configuration.\n# (All App Engine logging is through java.util.logging by default).\n\n# Set "
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/webapp/WEB-INF/web.xml",
    "chars": 5887,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n Copyright 2016 Google Inc.\n Licensed under the Apache License, Version 2.0 "
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/webapp/base.jsp",
    "chars": 2021,
    "preview": "<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this "
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/webapp/form.jsp",
    "chars": 2285,
    "preview": "<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this "
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/webapp/list.jsp",
    "chars": 1636,
    "preview": "<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this "
  },
  {
    "path": "bookshelf-standard/5-logging/src/main/webapp/view.jsp",
    "chars": 1790,
    "preview": "<!--\nCopyright 2016 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this "
  },
  {
    "path": "codecov.yml",
    "chars": 630,
    "preview": "# Copyright 2016 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "gce/README.md",
    "chars": 1220,
    "preview": "# Getting Started with Java - Google Compute Engine\n\nSee the [Bookshelf tutorial][tutorial] for help getting started wit"
  },
  {
    "path": "gce/config/base/etc/java-util-logging.properties",
    "chars": 1097,
    "preview": "# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": "gce/config/base/modules/gce.mod",
    "chars": 864,
    "preview": "# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": "gce/config/base/resources/jetty-logging.properties",
    "chars": 724,
    "preview": "# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": "gce/makeProject",
    "chars": 7513,
    "preview": "#!/bin/bash\n#\n#    Copyright 2016 Google, Inc.\n#\n#    Licensed under the Apache License, Version 2.0 (the \"License\");\n# "
  },
  {
    "path": "gce/pom.xml",
    "chars": 4439,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\nCopyright 2019 Google LLC\n\n Licensed under the Apache License, Version 2.0 ("
  },
  {
    "path": "gce/scripts/startup-script.sh",
    "chars": 2514,
    "preview": "#! /bin/bash\n# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may n"
  },
  {
    "path": "gce/src/main/appengine/app.yaml",
    "chars": 883,
    "preview": "# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": "gce/src/main/java/com/example/getstarted/basicactions/HelloworldController.java",
    "chars": 1130,
    "preview": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use"
  },
  {
    "path": "gce/src/main/webapp/WEB-INF/web.xml",
    "chars": 1078,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n Copyright 2019 Google LLC\n Licensed under the Apache License, Version 2.0 ("
  }
]

// ... and 19 more files (download for full content)

About this extraction

This page contains the full source code of the GoogleCloudPlatform/getting-started-java GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 219 files (527.1 KB), approximately 135.7k tokens, and a symbol index with 485 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!