Skip to content

Commit db10bd9

Browse files
committed
Merge pull request #157 from GoogleCloudPlatform/cloudsql
Add cloudsql gen1 sample for app engine
2 parents f4d5d66 + cc0c034 commit db10bd9

File tree

6 files changed

+250
-0
lines changed

6 files changed

+250
-0
lines changed

appengine/cloudsql/README.md

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Cloud SQL sample for Google App Enginge
2+
This sample demonstrates how to use [Cloud SQL](https://cloud.google.com/sql/) on Google App Engine
3+
## Setup
4+
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)
5+
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.
6+
## Running locally
7+
1. You will need to be running a local instance of MySQL.
8+
1. Update the connection string in ``appengine-web.xml`` with your local MySQL instance values.
9+
$ mvn clean appengine:devserver
10+
## Deploying
11+
1. Update the connection string in ``appengine-web.xml`` with your Cloud SQL instance values.
12+
$ mvn clean appengine:update

appengine/cloudsql/pom.xml

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<!--
2+
Copyright 2016 Google Inc. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
-->
16+
<project>
17+
<modelVersion>4.0.0</modelVersion>
18+
<packaging>war</packaging>
19+
<version>1.0-SNAPSHOT</version>
20+
<groupId>com.example.appengine</groupId>
21+
<artifactId>appengine-cloudsql</artifactId>
22+
23+
<parent>
24+
<artifactId>doc-samples</artifactId>
25+
<groupId>com.google.cloud</groupId>
26+
<version>1.0.0</version>
27+
<relativePath>../..</relativePath>
28+
</parent>
29+
30+
<dependencies>
31+
<dependency>
32+
<groupId>com.google.cloud.sql</groupId>
33+
<artifactId>mysql-socket-factory</artifactId>
34+
<version>1.0.0-beta1</version>
35+
</dependency>
36+
<dependency>
37+
<groupId>javax.servlet</groupId>
38+
<artifactId>javax.servlet-api</artifactId>
39+
<version>3.1.0</version>
40+
<type>jar</type>
41+
<scope>provided</scope>
42+
</dependency>
43+
<!-- [START dependencies] -->
44+
<dependency>
45+
<groupId>mysql</groupId>
46+
<artifactId>mysql-connector-java</artifactId>
47+
<version>5.1.38</version>
48+
</dependency>
49+
<!-- Parent POM defines ${appengine.sdk.version} (updates frequently). -->
50+
<dependency>
51+
<groupId>com.google.appengine</groupId>
52+
<artifactId>appengine-api-1.0-sdk</artifactId>
53+
</dependency>
54+
<!-- [END dependencies] -->
55+
</dependencies>
56+
<build>
57+
<!-- for hot reload of the web application -->
58+
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
59+
<plugins>
60+
<plugin>
61+
<groupId>com.google.appengine</groupId>
62+
<artifactId>appengine-maven-plugin</artifactId>
63+
<version>${appengine.sdk.version}</version>
64+
</plugin>
65+
</plugins>
66+
</build>
67+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/**
2+
* Copyright 2016 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.appengine.cloudsql;
18+
19+
import java.io.IOException;
20+
import java.io.PrintWriter;
21+
import java.net.Inet4Address;
22+
import java.net.Inet6Address;
23+
import java.net.InetAddress;
24+
import java.sql.Connection;
25+
import java.sql.DriverManager;
26+
import java.sql.PreparedStatement;
27+
import java.sql.ResultSet;
28+
import java.sql.SQLException;
29+
import java.sql.Timestamp;
30+
import java.util.Date;
31+
32+
import javax.servlet.ServletException;
33+
import javax.servlet.http.HttpServlet;
34+
import javax.servlet.http.HttpServletRequest;
35+
import javax.servlet.http.HttpServletResponse;
36+
37+
// [START example]
38+
@SuppressWarnings("serial")
39+
public class CloudSqlServlet extends HttpServlet {
40+
41+
@Override
42+
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException,
43+
ServletException {
44+
String path = req.getRequestURI();
45+
if (path.startsWith("/favicon.ico")) {
46+
return; // ignore the request for favicon.ico
47+
}
48+
// store only the first two octets of a users ip address
49+
String userIp = req.getRemoteAddr();
50+
InetAddress address = InetAddress.getByName(userIp);
51+
if (address instanceof Inet6Address) {
52+
// nest indexOf calls to find the second occurrence of a character in a string
53+
// an alternative is to use Apache Commons Lang: StringUtils.ordinalIndexOf()
54+
userIp = userIp.substring(0, userIp.indexOf(":", userIp.indexOf(":") + 1)) + ":*:*:*:*:*:*";
55+
} else if (address instanceof Inet4Address) {
56+
userIp = userIp.substring(0, userIp.indexOf(".", userIp.indexOf(".") + 1)) + ".*.*";
57+
}
58+
59+
final String createTableSql = "CREATE TABLE IF NOT EXISTS visits ( visit_id INT NOT NULL "
60+
+ "AUTO_INCREMENT, user_ip VARCHAR(46) NOT NULL, timestamp DATETIME NOT NULL, "
61+
+ "PRIMARY KEY (visit_id) )";
62+
final String createVisitSql = "INSERT INTO visits (user_ip, timestamp) VALUES (?, ?)";
63+
final String selectSql = "SELECT user_ip, timestamp FROM visits ORDER BY timestamp DESC "
64+
+ "LIMIT 10";
65+
PrintWriter out = resp.getWriter();
66+
resp.setContentType("text/plain");
67+
String url;
68+
if (System
69+
.getProperty("com.google.appengine.runtime.version").startsWith("Google App Engine/")) {
70+
// Check the System properties to determine if we are running on appengine or not
71+
// Google App Engine sets a few system properties that will reliably be present on a remote
72+
// instance.
73+
url = System.getProperty("ae-cloudsql.cloudsql-database-url");
74+
try {
75+
// Load the class that provides the new "jdbc:google:mysql://" prefix.
76+
Class.forName("com.mysql.jdbc.GoogleDriver");
77+
} catch (ClassNotFoundException e) {
78+
throw new ServletException("Error loading Google JDBC Driver", e);
79+
}
80+
} else {
81+
// Set the url with the local MySQL database connection url when running locally
82+
url = System.getProperty("ae-cloudsql.local-database-url");
83+
}
84+
try (Connection conn = DriverManager.getConnection(url);
85+
PreparedStatement statementCreateVisit = conn.prepareStatement(createVisitSql)) {
86+
conn.createStatement().executeUpdate(createTableSql);
87+
statementCreateVisit.setString(1, userIp);
88+
statementCreateVisit.setTimestamp(2, new Timestamp(new Date().getTime()));
89+
statementCreateVisit.executeUpdate();
90+
91+
try (ResultSet rs = conn.prepareStatement(selectSql).executeQuery()) {
92+
out.print("Last 10 visits:\n");
93+
while (rs.next()) {
94+
String savedIp = rs.getString("user_ip");
95+
String timeStamp = rs.getString("timestamp");
96+
out.print("Time: " + timeStamp + " Addr: " + savedIp + "\n");
97+
}
98+
}
99+
} catch (SQLException e) {
100+
throw new ServletException("SQL error", e);
101+
}
102+
}
103+
}
104+
// [END example]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!-- [START_EXCLUDE] -->
3+
<!--
4+
Copyright 2016 Google Inc. All Rights Reserved.
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
-->
15+
<!-- [END_EXCLUDE] -->
16+
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
17+
<application>YOUR-PROJECT-ID</application>
18+
<version>YOUR-VERSION-ID</version>
19+
<threadsafe>true</threadsafe>
20+
<use-google-connector-j>true</use-google-connector-j>
21+
<system-properties>
22+
<property name="ae-cloudsql.cloudsql-database-url" value="jdbc:google:mysql://YOUR-PROJECT-NAME:YOUR-CLOUDSQL-INSTANCE-NAME/DATABASE-NAME?user=USERNAME&amp;password=PASSWORD" />
23+
<property name="ae-cloudsql.local-database-url" value="jdbc:mysql://localhost/DATABASE-NAME?user=USERNAME&amp;PASSWORD=password&amp;useSSL=false" />
24+
</system-properties>
25+
</appengine-web-app>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!-- [START_EXCLUDE] -->
3+
<!--
4+
Copyright 2016 Google Inc. All Rights Reserved.
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
-->
15+
<!-- [END_EXCLUDE] -->
16+
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
17+
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
18+
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
19+
version="2.5">
20+
<servlet>
21+
<servlet-name>cloudsql</servlet-name>
22+
<servlet-class>com.example.appengine.cloudsql.CloudSqlServlet</servlet-class>
23+
</servlet>
24+
<servlet-mapping>
25+
<servlet-name>cloudsql</servlet-name>
26+
<url-pattern>/</url-pattern>
27+
</servlet-mapping>
28+
</web-app>

appengine/helloworld/src/main/webapp/WEB-INF/appengine-web.xml

+14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
11
<?xml version="1.0" encoding="utf-8"?>
2+
<!-- [START_EXCLUDE] -->
3+
<!--
4+
Copyright 2016 Google Inc. All Rights Reserved.
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
-->
15+
<!-- [END_EXCLUDE] -->
216
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
317
<application>YOUR-PROJECT-ID</application>
418
<version>YOUR-VERSION-ID</version>

0 commit comments

Comments
 (0)