diff --git a/appengine/cloudsql/README.md b/appengine/cloudsql/README.md new file mode 100644 index 00000000000..4a8261599ea --- /dev/null +++ b/appengine/cloudsql/README.md @@ -0,0 +1,12 @@ +# Cloud SQL sample for Google App Enginge +This sample demonstrates how to use [Cloud SQL](https://cloud.google.com/sql/) on Google App Engine +## Setup +Before you can run or deploy the sample, you will need to create a [Cloud SQL instance](https://cloud.google.com/sql/docs/create-instance) +1. Create a new user and database for the application. The easiest way to do this is via the [Google Developers Console](https://console.developers.google.com/project/_/sql/instances/example-instance2/access-control/users). Alternatively, you can use MySQL tools such as the command line client or workbench. +## Running locally +1. You will need to be running a local instance of MySQL. +1. Update the connection string in ``appengine-web.xml`` with your local MySQL instance values. + $ mvn clean appengine:devserver +## Deploying +1. Update the connection string in ``appengine-web.xml`` with your Cloud SQL instance values. + $ mvn clean appengine:update diff --git a/appengine/cloudsql/pom.xml b/appengine/cloudsql/pom.xml new file mode 100644 index 00000000000..e47a6eac97d --- /dev/null +++ b/appengine/cloudsql/pom.xml @@ -0,0 +1,67 @@ + + + 4.0.0 + war + 1.0-SNAPSHOT + com.example.appengine + appengine-cloudsql + + + doc-samples + com.google.cloud + 1.0.0 + ../.. + + + + + com.google.cloud.sql + mysql-socket-factory + 1.0.0-beta1 + + + javax.servlet + javax.servlet-api + 3.1.0 + jar + provided + + + + mysql + mysql-connector-java + 5.1.38 + + + + com.google.appengine + appengine-api-1.0-sdk + + + + + + ${project.build.directory}/${project.build.finalName}/WEB-INF/classes + + + com.google.appengine + appengine-maven-plugin + ${appengine.sdk.version} + + + + diff --git a/appengine/cloudsql/src/main/java/com/example/appengine/cloudsql/CloudSqlServlet.java b/appengine/cloudsql/src/main/java/com/example/appengine/cloudsql/CloudSqlServlet.java new file mode 100644 index 00000000000..ecd2c69f59e --- /dev/null +++ b/appengine/cloudsql/src/main/java/com/example/appengine/cloudsql/CloudSqlServlet.java @@ -0,0 +1,104 @@ +/** + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.appengine.cloudsql; + +import java.io.IOException; +import java.io.PrintWriter; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.Date; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +// [START example] +@SuppressWarnings("serial") +public class CloudSqlServlet extends HttpServlet { + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, + ServletException { + String path = req.getRequestURI(); + if (path.startsWith("/favicon.ico")) { + return; // ignore the request for favicon.ico + } + // store only the first two octets of a users ip address + String userIp = req.getRemoteAddr(); + InetAddress address = InetAddress.getByName(userIp); + if (address instanceof Inet6Address) { + // nest indexOf calls to find the second occurrence of a character in a string + // an alternative is to use Apache Commons Lang: StringUtils.ordinalIndexOf() + userIp = userIp.substring(0, userIp.indexOf(":", userIp.indexOf(":") + 1)) + ":*:*:*:*:*:*"; + } else if (address instanceof Inet4Address) { + userIp = userIp.substring(0, userIp.indexOf(".", userIp.indexOf(".") + 1)) + ".*.*"; + } + + final String createTableSql = "CREATE TABLE IF NOT EXISTS visits ( visit_id INT NOT NULL " + + "AUTO_INCREMENT, user_ip VARCHAR(46) NOT NULL, timestamp DATETIME NOT NULL, " + + "PRIMARY KEY (visit_id) )"; + final String createVisitSql = "INSERT INTO visits (user_ip, timestamp) VALUES (?, ?)"; + final String selectSql = "SELECT user_ip, timestamp FROM visits ORDER BY timestamp DESC " + + "LIMIT 10"; + PrintWriter out = resp.getWriter(); + resp.setContentType("text/plain"); + String url; + if (System + .getProperty("com.google.appengine.runtime.version").startsWith("Google App Engine/")) { + // Check the System properties to determine if we are running on appengine or not + // Google App Engine sets a few system properties that will reliably be present on a remote + // instance. + url = System.getProperty("ae-cloudsql.cloudsql-database-url"); + try { + // Load the class that provides the new "jdbc:google:mysql://" prefix. + Class.forName("com.mysql.jdbc.GoogleDriver"); + } catch (ClassNotFoundException e) { + throw new ServletException("Error loading Google JDBC Driver", e); + } + } else { + // Set the url with the local MySQL database connection url when running locally + url = System.getProperty("ae-cloudsql.local-database-url"); + } + try (Connection conn = DriverManager.getConnection(url); + PreparedStatement statementCreateVisit = conn.prepareStatement(createVisitSql)) { + conn.createStatement().executeUpdate(createTableSql); + statementCreateVisit.setString(1, userIp); + statementCreateVisit.setTimestamp(2, new Timestamp(new Date().getTime())); + statementCreateVisit.executeUpdate(); + + try (ResultSet rs = conn.prepareStatement(selectSql).executeQuery()) { + out.print("Last 10 visits:\n"); + while (rs.next()) { + String savedIp = rs.getString("user_ip"); + String timeStamp = rs.getString("timestamp"); + out.print("Time: " + timeStamp + " Addr: " + savedIp + "\n"); + } + } + } catch (SQLException e) { + throw new ServletException("SQL error", e); + } + } +} +// [END example] diff --git a/appengine/cloudsql/src/main/webapp/WEB-INF/appengine-web.xml b/appengine/cloudsql/src/main/webapp/WEB-INF/appengine-web.xml new file mode 100644 index 00000000000..3026fd2b7ca --- /dev/null +++ b/appengine/cloudsql/src/main/webapp/WEB-INF/appengine-web.xml @@ -0,0 +1,25 @@ + + + + + + YOUR-PROJECT-ID + YOUR-VERSION-ID + true + true + + + + + diff --git a/appengine/cloudsql/src/main/webapp/WEB-INF/web.xml b/appengine/cloudsql/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..05375810dc6 --- /dev/null +++ b/appengine/cloudsql/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,28 @@ + + + + + + + cloudsql + com.example.appengine.cloudsql.CloudSqlServlet + + + cloudsql + / + + diff --git a/appengine/helloworld/src/main/webapp/WEB-INF/appengine-web.xml b/appengine/helloworld/src/main/webapp/WEB-INF/appengine-web.xml index c9e245399bf..c322e7d016e 100644 --- a/appengine/helloworld/src/main/webapp/WEB-INF/appengine-web.xml +++ b/appengine/helloworld/src/main/webapp/WEB-INF/appengine-web.xml @@ -1,4 +1,18 @@ + + + YOUR-PROJECT-ID YOUR-VERSION-ID