Skip to content

Commit

Permalink
Initial import of MVM/SparkJava/gcloud-java example
Browse files Browse the repository at this point in the history
  • Loading branch information
Ajay Kannan committed Jan 6, 2016
1 parent 92907e5 commit 2c94683
Show file tree
Hide file tree
Showing 13 changed files with 881 additions and 0 deletions.
49 changes: 49 additions & 0 deletions managedvms/sparkjava/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
gcloud-java example using Managed VMs & SparkJava
=================================================

This app demonstrates how to use [`gcloud-java`'s Datastore client](https://github.com/GoogleCloudPlatform/gcloud-java/tree/master/gcloud-java-datastore#google-cloud-java-client-for-datastore) from within an [App Engine Managed VM](https://cloud.google.com/appengine/docs/java/managed-vms/) project using [SparkJava](http://sparkjava.com/). The app allows you to create and modify a database of "users", which contains their ID, name, and email information.

`gcloud-java` is an idiomatic Java client for [Google Cloud Platform](https://cloud.google.com/) services. Read more about the library [here](https://github.com/GoogleCloudPlatform/gcloud-java#google-cloud-java-client).

Setup
-----

1. Create a Google Developers Console project with the Datastore API enabled. [Follow these instructions](https://cloud.google.com/docs/authentication#preparation) to get your project set up. If you wish to deploy this application, you will also need to [enable billing](https://support.google.com/cloud/?rd=2#topic=6288636).

2. Set up the local development environment by [installing the Google Cloud SDK](https://cloud.google.com/sdk/) and running the following commands in command line: `gcloud auth login` and `gcloud config set project [YOUR PROJECT ID]`.

3. Ensure that you have Maven installed. See installation instructions [here](https://maven.apache.org/install.html).

Running locally
---------------

Run the application on your local machine by typing the following into your command line from the `sparkjava` directory: `mvn clean package exec:java`. Navigate to `localhost:8080` to view and interact with the application.

Deploying
---------

If you've enabled billing (step 1 in [Setup](#Setup)), you can deploy the application to the web by running `mvn gcloud:deploy` from your command line (from the `sparkjava` directory).

How does it work?
-----------------

You'll notice that the source code is split into three folders: `appengine`, `java/com/google/appengine/sparkdemo`, and `resource/public`. The `appengine` folder contains a `Dockerfile` and an `app.yaml`, necessary files to [configure the VM environment](https://cloud.google.com/appengine/docs/managed-vms/config). The `java/com/google/appengine/sparkdemo` folder contains the controller code, which uses the `gcloud-java` library to modify the records in the Google Cloud Datastore. Finally, the `resource/public` folder contains the home webpage, which uses jQuery to send HTTP requests to create, remove, and update records.

Spark runs the [`main` method](https://github.com/GoogleCloudPlatform/java-docs-samples/blob/master/managedvms/sparkjava-demo/src/main/java/com/google/appengine/sparkdemo/Main.java) upon server startup. The `main` method creates the controller, [`UserController`](https://github.com/GoogleCloudPlatform/java-docs-samples/blob/master/managedvms/sparkjava-demo/src/main/java/com/google/appengine/sparkdemo/UserController.java). The URIs used to send HTTP requests in the [home page](https://github.com/GoogleCloudPlatform/java-docs-samples/blob/master/managedvms/sparkjava-demo/src/main/resources/public/index.html) correspond to methods in the `UserController` class. For example, the `index.html` code for `create` makes a `POST` request to the path `/api/users` with a body containing the name and email of a user to add. `UserController` contains the following code to process that request:

```java
post("/api/users", (req, res) -> userService.createUser(
req.queryParams("name"),
req.queryParams("email),
), json());
```
This code snippet gets the name and email of the user from the POST request and passes it to `createUser` (in [`UserService.java`](https://github.com/GoogleCloudPlatform/java-docs-samples/blob/master/managedvms/sparkjava-demo/src/main/java/com/google/appengine/sparkdemo/UserService.java)) to create a database record using `gcloud-java`. If you want a more in-depth tutorial on using `gcloud-java` Datastore client, see the [Getting Started](https://github.com/GoogleCloudPlatform/gcloud-java/tree/master/gcloud-java-datastore#getting-started) section in the `gcloud-java-datastore` documentation.
Communication with the Google Cloud Datastore requires authentication and setting a project ID. When running locally, `gcloud-java` automatically detects your credentials and project ID because you logged into the Google Cloud SDK and set your project ID. There are also many other options for authenticating and setting a project ID. To read more, see the [Authentication](https://github.com/GoogleCloudPlatform/gcloud-java#authentication) and [Specifying a Project ID](https://github.com/GoogleCloudPlatform/gcloud-java#specifying-a-project-id) sections of the `gcloud-java` documentation.
You built and ran this application using Maven. To read more about using Maven with Managed VMs, see the [Using Apache Maven documentation](https://cloud.google.com/appengine/docs/java/managed-vms/maven). While this particular project uses Maven, `gcloud-java` can also be accessed using Gradle and SBT. See how to obtain the dependency in the [Quickstart section](https://github.com/GoogleCloudPlatform/gcloud-java#quickstart) of the `gcloud-java` documentation.
License
-------
Apache 2.0 - See [LICENSE](https://github.com/GoogleCloudPlatform/java-docs-samples/blob/master/LICENSE) for more information.
89 changes: 89 additions & 0 deletions managedvms/sparkjava/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<groupId>com.google.appengine.sparkdemo</groupId>
<artifactId>sparkdemo</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>com.google.gcloud</groupId>
<artifactId>gcloud-java</artifactId>
<version>0.1.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.google.appengine.sparkdemo.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.4.0</version>
<configuration>
<mainClass>com.google.appengine.sparkdemo.Main</mainClass>
<arguments>
<argument>-jar</argument>
<argument>target/sparkdemo-1.0-jar-with-dependencies.jar</argument>
</arguments>
</configuration>
</plugin>
<plugin>
<groupId>com.google.appengine</groupId>
<artifactId>gcloud-maven-plugin</artifactId>
<version>2.0.9.88.v20151125</version>
<configuration>
</configuration>
</plugin>
</plugins>
</build>
</project>
4 changes: 4 additions & 0 deletions managedvms/sparkjava/src/main/appengine/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM gcr.io/google_appengine/openjdk8
VOLUME /tmp
ADD sparkdemo-1.0-jar-with-dependencies.jar app.jar
ENTRYPOINT [ "java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
2 changes: 2 additions & 0 deletions managedvms/sparkjava/src/main/appengine/app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
runtime: custom
vm: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2015 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.google.appengine.sparkdemo;

import static spark.Spark.port;

import com.google.gcloud.datastore.DatastoreOptions;

public class Main {

public static void main(String[] args) {
port(8080);
UserController userController =
new UserController(new UserService(DatastoreOptions.defaultInstance().service()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2015 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.google.appengine.sparkdemo;

public class ResponseError {

private String message;

public ResponseError(String message, String... args) {
this.message = String.format(message, (Object) args);
}

public ResponseError(Exception e) {
this.message = e.getMessage();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2015 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.google.appengine.sparkdemo;

import java.util.UUID;

public class User {

private String id;
private String name;
private String email;

public User(String name, String email) {
this(UUID.randomUUID().toString(), name, email);
}

public User(String id, String name, String email) {
this.id = id;
this.email = email;
this.name = name;
}

public String getId() {
return id;
}

public String getName() {
return name;
}

public String getEmail() {
return email;
}

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

public void setName(String name) {
this.name = name;
}

public void setEmail(String email) {
this.email = email;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2015 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.google.appengine.sparkdemo;

import static spark.Spark.after;
import static spark.Spark.delete;
import static spark.Spark.exception;
import static spark.Spark.get;
import static spark.Spark.post;
import static spark.Spark.put;

import com.google.gson.Gson;

import spark.ResponseTransformer;
import spark.Spark;

public class UserController {

public UserController(final UserService userService) {
Spark.staticFileLocation("/public");

get("/api/users", (req, res) -> userService.getAllUsers(), UserController::toJson);

post("/api/users",
(req, res) -> userService.createUser(req.queryParams("name"), req.queryParams("email")),
json());

put("/api/users/:id", (req, res) -> userService.updateUser(
req.params(":id"),
req.queryParams("name"),
req.queryParams("email")
), json());

delete("/api/users/:id", (req, res) -> userService.deleteUser(req.params(":id")), json());

after((req, res) -> {
res.type("application/json");
});

exception(IllegalArgumentException.class, (e, req, res) -> {
res.status(400);
res.body(toJson(new ResponseError(e)));
});
}

private static String toJson(Object object) {
return new Gson().toJson(object);
}

private static ResponseTransformer json() {
return UserController::toJson;
}
}
Loading

0 comments on commit 2c94683

Please sign in to comment.