Skip to content

Postgres & CloudSQL update for flex #738

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 29, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 34 additions & 15 deletions flexible/cloudsql/README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,38 @@
# Cloud SQL sample for Google App Engine Flexible
This sample demonstrates how to use [Cloud SQL](https://cloud.google.com/sql/) on Google App Engine
Flexible.

This sample demonstrates how to use [Cloud SQL](https://cloud.google.com/cloudsql/) on Google App
Engine Flexible

## 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.cloud.google.com/sql/instances). Alternatively, you can use
MySQL tools such as the command line client or workbench.
2. Change the root password (under Access Control) and / or create a new user / password.
3. Create a Database (under Databases) (or use MySQL with `gcloud sql connect <instance> --user=root`)
4. Note the **Instance connection name** under Overview > Properties
(It will look like project:region:zone for 2nd Generation)
* If you haven't already, Download and initialize the [Cloud SDK](https://cloud.google.com/sdk/)

`gcloud init`

* If you haven't already, Create an App Engine app within the current Google Cloud Project

`gcloud app create`

* If you haven't already, Setup
[Application Default Credentials](https://developers.google.com/identity/protocols/application-default-credentials)

`gcloud auth application-default login`

* [Create an instance](https://cloud.google.com/sql/docs/mysql/create-instance)

* [Create a Database](https://cloud.google.com/sql/docs/mysql/create-manage-databases)

* [Create a user](https://cloud.google.com/sql/docs/mysql/create-manage-users)

* Note the **Instance connection name** under Overview > properties

Looks like: `projectID:region:instance`

## Running locally

```bash
$ mvn clean jetty:run -DINSTANCE_CONNECTION_NAME=instanceConnectionName -Duser=root -Dpassword=myPassowrd -Ddatabase=myDatabase
```

## Deploying

Expand All @@ -20,10 +41,8 @@ $ mvn clean appengine:deploy -DINSTANCE_CONNECTION_NAME=instanceConnectionName -
-Dpassword=myPassword -Ddatabase=myDatabase
```

Or you can update the properties in `pom.xml`

## Running locally
## Cleaning up

* [Delete your Instance](https://cloud.google.com/sql/docs/mysql/delete-instance)

```bash
$ mvn clean jetty:run -DINSTANCE_CONNECTION_NAME=instanceConnectionName -Duser=root -Dpassword=myPassowrd -Ddatabase=myDatabase
```
33 changes: 7 additions & 26 deletions flexible/cloudsql/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,20 @@

<!-- [START properties] -->
<properties>
<!-- INSTANCE_CONNECTION_NAME from Cloud Console > SQL > Instance Details > Properties
or `gcloud sql instances describe <instance> | grep connectionName`
project:region:instance for Cloud SQL 2nd Generation
<!--
INSTANCE_CONNECTION_NAME from Cloud Console > SQL > Instance Details > Properties
or `gcloud sql instances describe <instance> | grep connectionName`
-->
<INSTANCE_CONNECTION_NAME></INSTANCE_CONNECTION_NAME>
<INSTANCE_CONNECTION_NAME>Project:Region:Instance</INSTANCE_CONNECTION_NAME>
<user>root</user>
<password></password>
<password>myPassword</password>
<database>sqldemo</database>
<!-- [START_EXCLUDE] -->
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>

<failOnMissingWebXml>false</failOnMissingWebXml> <!-- REQUIRED -->

<appengine.maven.plugin>1.3.1</appengine.maven.plugin>
<jetty>9.4.4.v20170414</jetty>
<!-- [END_EXCLUDE] -->
<sqlURL>jdbc:mysql://google/${database}?cloudSqlInstance=${INSTANCE_CONNECTION_NAME}&amp;socketFactory=com.google.cloud.sql.mysql.SocketFactory&amp;user=${user}&amp;password=${password}&amp;useSSL=false</sqlURL>
Expand Down Expand Up @@ -82,7 +81,7 @@
<dependency>
<groupId>com.google.cloud.sql</groupId>
<artifactId>mysql-socket-factory-connector-j-6</artifactId>
<version>1.0.2</version>
<version>1.0.3</version>
</dependency>
<!-- [END dependencies] -->
</dependencies>
Expand All @@ -97,28 +96,10 @@
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
<plugins>

<!--
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<webResources>
<resource>
<directory>${basedir}/src/main/appengine</directory>
<filtering>true</filtering>
<targetPath></targetPath>
</resource>
</webResources>
</configuration>
</plugin>
-->


<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>appengine-maven-plugin</artifactId>
<version>${appengine.maven.plugin}</version>
<version>1.3.1</version>
</plugin>

<plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package com.example.cloudsql;

import com.google.common.base.Stopwatch;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Inet4Address;
Expand All @@ -29,6 +31,7 @@
import java.sql.Timestamp;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
Expand All @@ -40,62 +43,86 @@
@SuppressWarnings("serial")
@WebServlet(name = "cloudsql", value = "")
public class CloudSqlServlet extends HttpServlet {
String url;
Connection conn;

@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException,
ServletException {
// 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";

String path = req.getRequestURI();
if (path.startsWith("/favicon.ico")) {
return; // ignore the request for favicon.ico
}

PrintWriter out = resp.getWriter();
resp.setContentType("text/plain");

try (Connection conn = DriverManager.getConnection(url);
PreparedStatement statementCreateVisit = conn.prepareStatement(createVisitSql)) {
// 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)) + ".*.*";
}

Stopwatch stopwatch = Stopwatch.createStarted();
try (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()) {
stopwatch.stop();
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");
}
out.println("Elapsed: " + stopwatch.elapsed(TimeUnit.MILLISECONDS));
}
} catch (SQLException e) {
throw new ServletException("SQL error", e);
}
}

@Override
public void init() {
public void init() throws ServletException {
try {
String url;

Properties properties = new Properties();
properties.load(
getServletContext().getResourceAsStream("/WEB-INF/classes/config.properties"));
url = properties.getProperty("sqlUrl");
} catch (IOException e) {
log("no property", e); // Servlet Init should never fail.
try {
properties.load(
getServletContext().getResourceAsStream("/WEB-INF/classes/config.properties"));
url = properties.getProperty("sqlUrl");
} catch (IOException e) {
log("no property", e); // Servlet Init should never fail.
return;
}

log("connecting to: " + url);
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(optional/future) instead of DriverManager.getConnection,
connection pooling with commons-bcp : https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2

} catch (ClassNotFoundException e) {
throw new ServletException("Error loading JDBC Driver", e);
} catch (SQLException e) {
throw new ServletException("Unable to connect to PostGre", e);
}

} finally {
// Nothing really to do here.
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions flexible/postgres/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/bin/
target
48 changes: 48 additions & 0 deletions flexible/postgres/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# PostgreSQL sample for Google App Engine Flexible

This sample demonstrates how to use [Cloud SQL](https://cloud.google.com/sql/) on Google App
Engine Flexible

## Setup

* If you haven't already, Download and initialize the [Cloud SDK](https://cloud.google.com/sdk/)

`gcloud init`

* If you haven't already, Create an App Engine app within the current Google Cloud Project

`gcloud app create`

* If you haven't already, Setup
[Application Default Credentials](https://developers.google.com/identity/protocols/application-default-credentials)

`gcloud auth application-default login`

* [Create an instance](https://cloud.google.com/sql/docs/postgresql/create-instance)

* [Create a Database](https://cloud.google.com/sql/docs/postgresql/create-manage-databases)

* [Create a user](https://cloud.google.com/sql/docs/postgresql/create-manage-users)

* Note the **Instance connection name** under Overview > properties

Looks like: `projectID:region:instance`

## Running locally

```bash
$ mvn clean jetty:run -DINSTANCE_CONNECTION_NAME=instanceConnectionName -Duser=root -Dpassword=myPassowrd -Ddatabase=myDatabase
```

## Deploying

```bash
$ mvn clean appengine:deploy -DINSTANCE_CONNECTION_NAME=instanceConnectionName -Duser=root
-Dpassword=myPassword -Ddatabase=myDatabase
```


## Cleaning up

* [Delete your Instance](https://cloud.google.com/sql/docs/postgresql/delete-instance)

Loading