From e3a391c8c9969a7b2bd4d8f3877ca23892173970 Mon Sep 17 00:00:00 2001 From: Les Vogel Date: Tue, 16 May 2017 17:29:27 -0700 Subject: [PATCH] Add Bigtable (#670) --- appengine-java8/bigtable/.dockerignore | 5 + appengine-java8/bigtable/README.md | 56 +++++ appengine-java8/bigtable/build.gradle | 91 +++++++++ .../gradle/wrapper/gradle-wrapper.properties | 6 + appengine-java8/bigtable/gradlew | 172 ++++++++++++++++ appengine-java8/bigtable/gradlew.bat | 84 ++++++++ appengine-java8/bigtable/pom.xml | 191 ++++++++++++++++++ appengine-java8/bigtable/settings.gradle | 1 + .../example/bigtable/BigtableHelloWorld.java | 147 ++++++++++++++ .../com/example/bigtable/BigtableHelper.java | 141 +++++++++++++ .../src/main/webapp/WEB-INF/appengine-web.xml | 24 +++ .../bigtable/src/main/webapp/WEB-INF/web.xml | 34 ++++ .../bigtable/src/main/webapp/favicon.ico | Bin 0 -> 1150 bytes .../bigtable/src/main/webapp/index.jsp | 32 +++ .../bigtable/ITBigtableHelloWorld.java | 51 +++++ appengine-java8/pom.xml | 1 + 16 files changed, 1036 insertions(+) create mode 100644 appengine-java8/bigtable/.dockerignore create mode 100644 appengine-java8/bigtable/README.md create mode 100644 appengine-java8/bigtable/build.gradle create mode 100644 appengine-java8/bigtable/gradle/wrapper/gradle-wrapper.properties create mode 100755 appengine-java8/bigtable/gradlew create mode 100644 appengine-java8/bigtable/gradlew.bat create mode 100644 appengine-java8/bigtable/pom.xml create mode 100644 appengine-java8/bigtable/settings.gradle create mode 100644 appengine-java8/bigtable/src/main/java/com/example/bigtable/BigtableHelloWorld.java create mode 100644 appengine-java8/bigtable/src/main/java/com/example/bigtable/BigtableHelper.java create mode 100644 appengine-java8/bigtable/src/main/webapp/WEB-INF/appengine-web.xml create mode 100644 appengine-java8/bigtable/src/main/webapp/WEB-INF/web.xml create mode 100644 appengine-java8/bigtable/src/main/webapp/favicon.ico create mode 100644 appengine-java8/bigtable/src/main/webapp/index.jsp create mode 100644 appengine-java8/bigtable/src/test/java/com/example/bigtable/ITBigtableHelloWorld.java diff --git a/appengine-java8/bigtable/.dockerignore b/appengine-java8/bigtable/.dockerignore new file mode 100644 index 00000000000..1700486b441 --- /dev/null +++ b/appengine-java8/bigtable/.dockerignore @@ -0,0 +1,5 @@ +pom.xml +src/* +web/* +Dockerfile +app.yaml diff --git a/appengine-java8/bigtable/README.md b/appengine-java8/bigtable/README.md new file mode 100644 index 00000000000..5fd95ed030f --- /dev/null +++ b/appengine-java8/bigtable/README.md @@ -0,0 +1,56 @@ +Bigtable-hello-j8 +================= + +Moves the Bigtable Hello World application to Google App Engine Standard for Java 8. + + +* [Java 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) +* [Maven](https://maven.apache.org/download.cgi) (at least 3.3.9) +* [Gradle](https://gradle.org) +* [Google Cloud SDK](https://cloud.google.com/sdk/) (aka gcloud) + +Initialize the Google Cloud SDK using: + + gcloud init + + gcloud auth application-default login + +Then you need to [Create a Cloud Bigtable Instance](https://cloud.google.com/bigtable/docs/creating-instance) + + +## Using Maven + +### Run Locally + + mvn -Dbigtable.projectID=PROJECTID -Dbigtable.instanceID=INSTANCEID appengine:run + +### Deploy to App Engine Standard for Java 8 + + mvn -Dbigtable.projectID=PROJECTID -Dbigtable.instanceID=INSTANCEID appengine:deploy + +### Run Integration Tests + + mvn -Dbigtable.projectID=PROJECTID -Dbigtable.instanceID=INSTANCEID verify + +## Using Gradle + +### Run Locally + + gradle -Dbigtable.projectID=PROJECTID -Dbigtable.instanceID=INSTANCEID appengineRun + +### Integration Tests & Deploy to App Engine Standard for Java 8 + + gradle -Dbigtable.projectID=PROJECTID -Dbigtable.instanceID=INSTANCEID appengineDeploy + +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/) + +### When done + +Cloud Bigtable Instances should be [deleted](https://cloud.google.com/bigtable/docs/deleting-instance) +when they are no longer being used as they use significant resources. diff --git a/appengine-java8/bigtable/build.gradle b/appengine-java8/bigtable/build.gradle new file mode 100644 index 00000000000..dc8172c0f76 --- /dev/null +++ b/appengine-java8/bigtable/build.gradle @@ -0,0 +1,91 @@ +// 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.cloud.tools:appengine-gradle-plugin:1.3.1' + } +} + +apply plugin: 'java' +apply plugin: 'war' +apply plugin: 'com.google.cloud.tools.appengine' + +group = 'com.example.google.cloud.bigtable' +version = '0.1-SNAPSHOT' + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} + +repositories { + maven { url "https://oss.sonatype.org/content/repositories/snapshots" } + jcenter() + mavenCentral() +} + +dependencies { + compile group: 'com.google.cloud.bigtable', name: 'bigtable-hbase-1.2', version:'0.9.6.2' + compile group: 'org.apache.hbase', name: 'hbase-client', version:'1.2.4' + compile group: 'io.netty', name: 'netty-tcnative-boringssl-static', version:'1.1.33.Fork26' + compile group: 'jstl', name: 'jstl', version:'1.2' + + providedCompile group: 'javax.servlet', name: 'javax.servlet-api', version:'3.1.0' + + testCompile group: 'com.google.truth', name: 'truth', version:'0.30' + testCompile group: 'junit', name: 'junit', version:'4.12' + testCompile group: 'org.mockito', name: 'mockito-all', version:'1.10.19' +} + +// Always run unit tests +appengineDeploy.dependsOn test + +// [START model] +appengine { + run { + + } + deploy { // deploy configuration + stopPreviousVersion = true // default - stop the current version + promote = true // default - & make this the current version + } +} + +test { + useJUnit() + testLogging.showStandardStreams = true + + systemProperty 'BIGTABLE_PROJECT', System.getProperty("bigtable.projectID") + systemProperty 'BIGTABLE_INSTANCE',System.getProperty("bigtable.instanceID") + + 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] +// [END gradle] diff --git a/appengine-java8/bigtable/gradle/wrapper/gradle-wrapper.properties b/appengine-java8/bigtable/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..bb0239ffea0 --- /dev/null +++ b/appengine-java8/bigtable/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Apr 03 21:11:48 PDT 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-bin.zip diff --git a/appengine-java8/bigtable/gradlew b/appengine-java8/bigtable/gradlew new file mode 100755 index 00000000000..4453ccea33d --- /dev/null +++ b/appengine-java8/bigtable/gradlew @@ -0,0 +1,172 @@ +#!/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" "$@" diff --git a/appengine-java8/bigtable/gradlew.bat b/appengine-java8/bigtable/gradlew.bat new file mode 100644 index 00000000000..e95643d6a2c --- /dev/null +++ b/appengine-java8/bigtable/gradlew.bat @@ -0,0 +1,84 @@ +@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 diff --git a/appengine-java8/bigtable/pom.xml b/appengine-java8/bigtable/pom.xml new file mode 100644 index 00000000000..7414ba43489 --- /dev/null +++ b/appengine-java8/bigtable/pom.xml @@ -0,0 +1,191 @@ + + + + + 4.0.0 + war + 0.1-SNAPSHOT + + com.example.google.cloud.bigtable + bigtable-hello-j8 + + + appengine-java8-samples + com.google.cloud + 1.0.0 + .. + + + + 1.3.1 + UTF-8 + UTF-8 + 1.8 + 1.8 + + 0.9.6.2 + 1.2.4 + YOUR_PROJECT_ID + YOUR_INSTANCE_ID + + 2.4.1 + hbase-hadoop2-compat + + true + true + false + + + + + com.google.cloud.bigtable + bigtable-hbase-1.2 + ${bigtable.version} + + + + org.apache.hbase + hbase-client + ${hbase.version} + + + + io.netty + netty-tcnative-boringssl-static + 1.1.33.Fork26 + + + + + javax.servlet + javax.servlet-api + 3.1.0 + jar + provided + + + jstl + jstl + 1.2 + + + + + + com.google.truth + truth + 0.30 + test + + + + junit + junit + 4.12 + test + + + org.mockito + mockito-all + 1.10.19 + test + + + + + + ${project.build.directory}/${project.build.finalName}/WEB-INF/classes + + + org.codehaus.mojo + versions-maven-plugin + 2.3 + + + compile + + display-dependency-updates + display-plugin-updates + + + + + + + org.apache.maven.plugins + maven-resources-plugin + 3.0.2 + + UTF-8 + + @ + + false + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.0.0 + + true + + + + ${basedir}/src/main/webapp/WEB-INF + true + WEB-INF + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 2.19.1 + + + ${bigtable.projectID} + ${bigtable.instanceID} + + + + + + com.google.cloud.tools + appengine-maven-plugin + ${appengine.maven.plugin} + + + + + + + + + snapshots-repo + https://oss.sonatype.org/content/repositories/snapshots + false + true + + + + + diff --git a/appengine-java8/bigtable/settings.gradle b/appengine-java8/bigtable/settings.gradle new file mode 100644 index 00000000000..1302054a84f --- /dev/null +++ b/appengine-java8/bigtable/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'bigtable-hello-j8' diff --git a/appengine-java8/bigtable/src/main/java/com/example/bigtable/BigtableHelloWorld.java b/appengine-java8/bigtable/src/main/java/com/example/bigtable/BigtableHelloWorld.java new file mode 100644 index 00000000000..ad2057beb65 --- /dev/null +++ b/appengine-java8/bigtable/src/main/java/com/example/bigtable/BigtableHelloWorld.java @@ -0,0 +1,147 @@ +/* + * Copyright 2016 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.bigtable; + +import org.apache.hadoop.hbase.HColumnDescriptor; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.Admin; +import org.apache.hadoop.hbase.client.Connection; +import org.apache.hadoop.hbase.client.Get; +import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.client.ResultScanner; +import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.client.Table; +import org.apache.hadoop.hbase.util.Bytes; + +import java.io.IOException; +// [START example] +/** + * A minimal application that connects to Cloud Bigtable using the native HBase API + * and performs some basic operations. + */ +public class BigtableHelloWorld { + + // Refer to table metadata names by byte array in the HBase API + private static final byte[] TABLE_NAME = Bytes.toBytes("Hello-Bigtable"); + private static final byte[] COLUMN_FAMILY_NAME = Bytes.toBytes("cf1"); + private static final byte[] COLUMN_NAME = Bytes.toBytes("greeting"); + + // Write some friendly greetings to Cloud Bigtable + private static final String[] GREETINGS = + { "Hello World!", "Hello Cloud Bigtable!", "Hello HBase!" }; + + + public static String create(Connection connection) { + try { + // The admin API lets us create, manage and delete tables + Admin admin = connection.getAdmin(); + // [END connecting_to_bigtable] + + // [START creating_a_table] + // Create a table with a single column family + HTableDescriptor descriptor = new HTableDescriptor(TableName.valueOf(TABLE_NAME)); + descriptor.addFamily(new HColumnDescriptor(COLUMN_FAMILY_NAME)); + + admin.createTable(descriptor); + // [END creating_a_table] + } catch (IOException e) { + return "Table exists."; + } + return "Create table " + Bytes.toString(TABLE_NAME); + } + + /** + * Connects to Cloud Bigtable, runs some basic operations and prints the results. + */ + public static String doHelloWorld() { + + StringBuilder result = new StringBuilder(); + + // [START connecting_to_bigtable] + // Create the Bigtable connection, use try-with-resources to make sure it gets closed + Connection connection = BigtableHelper.getConnection(); + result.append(create(connection)); + result.append("

"); + try (Table table = connection.getTable(TableName.valueOf(TABLE_NAME))) { + + // Retrieve the table we just created so we can do some reads and writes + + // [START writing_rows] + // Write some rows to the table + result.append("Write some greetings to the table
"); + for (int i = 0; i < GREETINGS.length; i++) { + // Each row has a unique row key. + // + // Note: This example uses sequential numeric IDs for simplicity, but + // this can result in poor performance in a production application. + // Since rows are stored in sorted order by key, sequential keys can + // result in poor distribution of operations across nodes. + // + // For more information about how to design a Bigtable schema for the + // best performance, see the documentation: + // + // https://cloud.google.com/bigtable/docs/schema-design + String rowKey = "greeting" + i; + + // Put a single row into the table. We could also pass a list of Puts to write a batch. + Put put = new Put(Bytes.toBytes(rowKey)); + put.addColumn(COLUMN_FAMILY_NAME, COLUMN_NAME, Bytes.toBytes(GREETINGS[i])); + table.put(put); + } + // [END writing_rows] + + // [START getting_a_row] + // Get the first greeting by row key + String rowKey = "greeting0"; + Result getResult = table.get(new Get(Bytes.toBytes(rowKey))); + String greeting = Bytes.toString(getResult.getValue(COLUMN_FAMILY_NAME, COLUMN_NAME)); + result.append("Get a single greeting by row key
"); + // [END getting_a_row] + result.append(" "); + result.append(rowKey); + result.append("= "); + result.append(greeting); + result.append("
"); + + // [START scanning_all_rows] + // Now scan across all rows. + Scan scan = new Scan(); + + result.append("Scan for all greetings:"); + ResultScanner scanner = table.getScanner(scan); + for (Result row : scanner) { + byte[] valueBytes = row.getValue(COLUMN_FAMILY_NAME, COLUMN_NAME); + result.append(" "); + result.append(Bytes.toString(valueBytes)); + result.append("
"); + } + // [END scanning_all_rows] + + } catch (IOException e) { + result.append("Exception while running HelloWorld: " + e.getMessage() + "
"); + result.append(e.toString()); + return result.toString(); + } + + return result.toString(); + } + + +} +// [END example] diff --git a/appengine-java8/bigtable/src/main/java/com/example/bigtable/BigtableHelper.java b/appengine-java8/bigtable/src/main/java/com/example/bigtable/BigtableHelper.java new file mode 100644 index 00000000000..07b43359237 --- /dev/null +++ b/appengine-java8/bigtable/src/main/java/com/example/bigtable/BigtableHelper.java @@ -0,0 +1,141 @@ +/** + * Copyright 2015 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.bigtable; + +import com.google.cloud.bigtable.hbase.BigtableConfiguration; +import org.apache.hadoop.hbase.client.Connection; + +import java.io.IOException; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.annotation.WebListener; + +/** + * BigtableHelper, a ServletContextListener, is setup in web.xml to run before a JSP is run. + * Project / Instance settings can be passed as an Environment Variable, a System Property, or set + * in web.xml from a context-param + * + **/ +@WebListener +public class BigtableHelper implements ServletContextListener { + + private static String PROJECT_ID; + private static String INSTANCE_ID; + +// The initial connection to Cloud Bigtable is an expensive operation -- We cache this Connection +// to speed things up. For this sample, keeping them here is a good idea, for +// your application, you may wish to keep this somewhere else. + private static Connection connection = null; // The authenticated connection + + private static ServletContext sc; + +/** + * Connect will establish the connection to Cloud Bigtable. + **/ + public static void connect() throws IOException { + + if (PROJECT_ID == null || INSTANCE_ID == null ) { + if (sc != null) { + sc.log("environment variables BIGTABLE_PROJECT, and BIGTABLE_INSTANCE need to be defined."); + } + return; + } + + connection = BigtableConfiguration.connect(PROJECT_ID, INSTANCE_ID); + } + + public static Connection getConnection() { + if (connection == null) { + try { + connect(); + } catch (IOException e) { + if (sc != null) { + sc.log("connect ", e); + } + } + } + if (connection == null) { + if (sc != null) { + sc.log("BigtableHelper-No Connection"); + } + } + return connection; + } + + @Override + public void contextInitialized(ServletContextEvent event) { + // This will be invoked as part of a warmup request, or the first user + // request if no warmup request was invoked. + + if (event != null) { + sc = event.getServletContext(); + if (PROJECT_ID == null) { + PROJECT_ID = sc.getInitParameter("BIGTABLE_PROJECT"); + } + if (INSTANCE_ID == null) { + INSTANCE_ID = sc.getInitParameter("BIGTABLE_INSTANCE"); + } + } + + if (PROJECT_ID != null && PROJECT_ID.startsWith("@")) { + PROJECT_ID = null; + } + if (INSTANCE_ID != null && INSTANCE_ID.startsWith("@")) { + INSTANCE_ID = null; + } + + if (PROJECT_ID == null) { + PROJECT_ID = System.getProperty("BIGTABLE_PROJECT"); + } + if (INSTANCE_ID == null) { + INSTANCE_ID = System.getProperty("BIGTABLE_INSTANCE"); + } + + try { + connect(); + } catch (IOException e) { + if (sc != null) { + sc.log("BigtableHelper - connect ", e); + } + } + if (connection == null) { + if (sc != null) { + sc.log("BigtableHelper-No Connection"); + } + } + if (sc != null) { + sc.log("ctx Initialized: " + PROJECT_ID + " " + INSTANCE_ID); + } + } + + @Override + public void contextDestroyed(ServletContextEvent event) { + // App Engine does not currently invoke this method. + if (connection == null) { + return; + } + try { + connection.close(); + } catch (IOException io) { + if (sc != null) { + sc.log("contextDestroyed ", io); + } + } + connection = null; + } +} diff --git a/appengine-java8/bigtable/src/main/webapp/WEB-INF/appengine-web.xml b/appengine-java8/bigtable/src/main/webapp/WEB-INF/appengine-web.xml new file mode 100644 index 00000000000..aa2113af00a --- /dev/null +++ b/appengine-java8/bigtable/src/main/webapp/WEB-INF/appengine-web.xml @@ -0,0 +1,24 @@ + + + + + true + java8 + + + + + + + diff --git a/appengine-java8/bigtable/src/main/webapp/WEB-INF/web.xml b/appengine-java8/bigtable/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..66495223908 --- /dev/null +++ b/appengine-java8/bigtable/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,34 @@ + + + + + + index.jsp + + + BIGTABLE_PROJECT + @bigtable.projectID@ + + + BIGTABLE_INSTANCE + @bigtable.instanceID@ + + diff --git a/appengine-java8/bigtable/src/main/webapp/favicon.ico b/appengine-java8/bigtable/src/main/webapp/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..0062ab413e73fa137f91cc1b082ce6a9bc992730 GIT binary patch literal 1150 zcmchVT}YE*6vvO#ObKxkm}F29kx=MGBotCtksqk6T__r47lF2m6b%yb3oXOSIbYlS zT0@&?=KPkK%d$<~me%IfxfOnO(T!aM-B`iXL)@7O-l`DN1e2iD~XBziRG#kh#!R zlB8E8it@c6mm2KdQt4SrtcazQq9_WzNfg|g7q>oV8HRho0@vImRu-q>c1&T}ZNrEn z8w_M!@>p|P*lUL-1J(u!w6ahr(+Hi9ZooSBf?u?cW7TQJtD)!6ceg^Ls^;x8CJa_y zf%=*VO;Z1ys*4oKB@ovui@-u#Hq6{5exOLqtJr&1mYlE|hcK)zgn3L4omPc*wSr%= z8_+Kc`Kie`Q0Tpfu$IM8wNYDwH_b8_xGb!Fa=_S@3&Y(2n7fMcvbUY_wU~QvMAZdK z^0GqD1uKoB1e>V`i?b%)Jv)KVjGx!#!(1kYZAgyE(SB%Kt6uq5SN`+}7YLJM^E%zeeoan^L zM+er|To@bdfV#d4+`}^7JU$FVz3jW7t&A1oPE$#Oia#jM!CG;cH`F9xacU4>zbwNv z(v8_^Bi`xc$PJ;B0@aimxf5om`sBbn^J*!q@>tZRP~WWpI{ozearr={bfhEqd}}Jv zK>=z^KlB$XBx>VDdCR&2bjiYnIr*n?DSu{fx8Qypof#;IMom2B2sJKw|89xT^OJ2e zEr^toK%ZJ)g{BNoPa4xBd`WiX!TwTk{wUFga8*Axhs;;~iN0-fp|&9>`oXlnwito? E4Z4s|oB#j- literal 0 HcmV?d00001 diff --git a/appengine-java8/bigtable/src/main/webapp/index.jsp b/appengine-java8/bigtable/src/main/webapp/index.jsp new file mode 100644 index 00000000000..6ac15ddcdc8 --- /dev/null +++ b/appengine-java8/bigtable/src/main/webapp/index.jsp @@ -0,0 +1,32 @@ + +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ page import="com.example.bigtable.BigtableHelloWorld" %> + +<%-- + ~ 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. + --%> + + + + + Hello App Engine Standard using Java 8 + + +

Hello App Engine -- Standard for Java 8!

+ +

This is <%= BigtableHelloWorld.doHelloWorld() %>. + + + diff --git a/appengine-java8/bigtable/src/test/java/com/example/bigtable/ITBigtableHelloWorld.java b/appengine-java8/bigtable/src/test/java/com/example/bigtable/ITBigtableHelloWorld.java new file mode 100644 index 00000000000..abce9adcb26 --- /dev/null +++ b/appengine-java8/bigtable/src/test/java/com/example/bigtable/ITBigtableHelloWorld.java @@ -0,0 +1,51 @@ +/** + * Copyright 2016 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.bigtable; + +import static com.google.common.truth.Truth.assertThat; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Unit tests for {@link HelloAppEngine}. + */ + +@RunWith(JUnit4.class) +@SuppressWarnings("checkstyle:abbreviationaswordinname") +public class ITBigtableHelloWorld { + private BigtableHelper helper; + + @Before + public void setUp() throws Exception { + helper = new BigtableHelper(); + helper.contextInitialized(null); + } + + @Test + public void bigtable_test() { + String result = BigtableHelloWorld.doHelloWorld(); + assertThat(result).contains("Write some greetings to the table"); + assertThat(result).contains("Get a single greeting by row key"); + assertThat(result).contains("greeting0= Hello World!"); + assertThat(result).contains("Hello Cloud Bigtable!"); + assertThat(result).contains("Hello HBase!"); + } + +} diff --git a/appengine-java8/pom.xml b/appengine-java8/pom.xml index 96050a85620..07b9f6d7f24 100644 --- a/appengine-java8/pom.xml +++ b/appengine-java8/pom.xml @@ -37,6 +37,7 @@ analytics appidentity + cloudsql datastore