Skip to content

Commit

Permalink
feat: my-widget-service example for Java (#172)
Browse files Browse the repository at this point in the history
* my-widget-service java example

* cleaned up output.json

* Updated Readme for my-widget-service

* Updated pom.xml fix the build

* removed org.codehaus.mojo plugin from pom.xml

* updated the reference to app class in pom.xml

* updated cdk.json to point to App class, cleaned up the stack code with consistent formatting

* updated gitignore for bin directory

* format updates to  stack class

* updated cdk version to 1.18.0

* add .class to gitignore

* java syntax updates

updated to use "Builder" syntax for construct library
  • Loading branch information
srihariph authored and mergify[bot] committed Dec 4, 2019
1 parent f350ba2 commit b53f0d4
Show file tree
Hide file tree
Showing 10 changed files with 1,222 additions and 0 deletions.
16 changes: 16 additions & 0 deletions java/my-widget-service/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.classpath.txt
target
.classpath
.project
.idea
.settings
.vscode
*.iml

# CDK asset staging directory
.cdk.staging
cdk.out

#Java bin directory
*.class

32 changes: 32 additions & 0 deletions java/my-widget-service/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# My Widget Service

This example uses lambda to serve-up widgets.

## Building

To build this app, run `mvn compile`. This will download the required
dependencies to compile the Java code.

You can use your IDE to write code and unit tests, but you will need to use the
CDK toolkit if you wish to synthesize/deploy stacks.

## CDK Toolkit

The [`cdk.json`](./cdk.json) file in the root of this repository includes
instructions for the CDK toolkit on how to execute this program.

Specifically, it will tell the toolkit to use the `mvn exec:java` command as the
entry point of your application. After changing your Java code, you will be able
to run the CDK toolkit commands as usual (Maven will recompile as needed):

$ cdk ls
<list all stacks in this program>

$ cdk synth
<cloudformation template>

$ cdk deploy
<deploy stack to your account>

$ cdk diff
<diff against deployed stack>
3 changes: 3 additions & 0 deletions java/my-widget-service/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"app": "mvn exec:java -Dexec.mainClass=software.amazon.awscdk.examples.MyWidgetServiceApp"
}
98 changes: 98 additions & 0 deletions java/my-widget-service/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>

<groupId>com.amazonaws.cdk</groupId>
<artifactId>my-widget-service</artifactId>
<version>1.0.0</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.amazonaws.cdk.examples.MyWidgetServiceApp</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>

</plugins>
</build>

<dependencies>
<!-- AWS Cloud Development Kit -->
<dependency>
<groupId>software.amazon.awscdk</groupId>
<artifactId>core</artifactId>
<version>1.18.0</version>
</dependency>
<dependency>
<groupId>software.amazon.awscdk</groupId>
<artifactId>s3</artifactId>
<version>1.18.0</version>
</dependency>
<dependency>
<groupId>software.amazon.awscdk</groupId>
<artifactId>apigateway</artifactId>
<version>1.18.0</version>
</dependency>
<dependency>
<groupId>software.amazon.awscdk</groupId>
<artifactId>iam</artifactId>
<version>1.18.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
138 changes: 138 additions & 0 deletions java/my-widget-service/resources/widgets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
//snippet-comment:[These are tags for the AWS doc team's sample catalog. Do not remove.]
//snippet-comment:[This should be in the resources/ directory]
//snippet-comment:[and only works with my_widget_service.ts in the bin/ directory]
//snippet-comment:[and widget_service.ts in the lib/ directory.]
//snippet-sourceauthor:[Doug-AWS]
//snippet-sourcedescription:[Lambda function to handle GET, POST, and DELETE.]
//snippet-keyword:[CDK V0.24.1]
//snippet-keyword:[S3.deleteObject function]
//snippet-keyword:[S3.getObject function]
//snippet-keyword:[S3.listObjectsV2 function]
//snippet-keyword:[S3.putObject function]
//snippet-keyword:[JavaScript]
//snippet-service:[cdk]
//snippet-sourcetype:[full-example]
//snippet-sourcedate:[2019-2-8]
// Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// This file is licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// This file 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.
//snippet-start:[cdk.typescript.widgets]
//snippet-start:[cdk.typescript.widgets.imports]
const AWS = require('aws-sdk');
const S3 = new AWS.S3();
//snippet-end:[cdk.typescript.widgets.imports]

const bucketName = process.env.BUCKET;

//snippet-start:[cdk.typescript.widgets.exports_main]
exports.main = async function(event, context) {
try {
var method = event.httpMethod;
// Get name, if present
var widgetName = event.path.startsWith('/') ? event.path.substring(1) : event.path;

if (method === "GET") {
// GET / to get the names of all widgets
if (event.path === "/") {
const data = await S3.listObjectsV2({ Bucket: bucketName }).promise();
var body = {
widgets: data.Contents.map(function(e) { return e.Key })
};
return {
statusCode: 200,
headers: {},
body: JSON.stringify(body)
};
}

if (widgetName) {
// GET /name to get info on widget name
const data = await S3.getObject({ Bucket: bucketName, Key: widgetName}).promise();
var body = data.Body.toString('utf-8');

return {
statusCode: 200,
headers: {},
body: JSON.stringify(body)
};
}
}

if (method === "POST") {
// POST /name
// Return error if we do not have a name
if (!widgetName) {
return {
statusCode: 400,
headers: {},
body: "Widget name missing"
};
}

// Create some dummy data to populate object
const now = new Date();
var data = widgetName + " created: " + now;

var base64data = new Buffer(data, 'binary');

await S3.putObject({
Bucket: bucketName,
Key: widgetName,
Body: base64data,
ContentType: 'application/json'
}).promise();

return {
statusCode: 200,
headers: {},
body: JSON.stringify(event.widgets)
};
}

if (method === "DELETE") {
// DELETE /name
// Return an error if we do not have a name
if (!widgetName) {
return {
statusCode: 400,
headers: {},
body: "Widget name missing"
};
}

await S3.deleteObject({
Bucket: bucketName, Key: widgetName
}).promise();

return {
statusCode: 200,
headers: {},
body: "Successfully deleted widget " + widgetName
};
}

// We got something besides a GET, POST, or DELETE
return {
statusCode: 400,
headers: {},
body: "We only accept GET, POST, and DELETE, not " + method
};
} catch(error) {
var body = error.stack || JSON.stringify(error, null, 2);
return {
statusCode: 400,
headers: {},
body: body
}
}
}
//snippet-end:[cdk.typescript.widgets.exports_main]
//snippet-end:[cdk.typescript.widgets]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package software.amazon.awscdk.examples;

import software.amazon.awscdk.core.App;



import java.util.Arrays;

public class MyWidgetServiceApp {
public static void main(final String argv[]) {
App app = new App();

new MyWidgetServiceStack(app, "MyWidgetServiceStack");

app.synth();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package software.amazon.awscdk.examples;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import software.amazon.awscdk.core.Construct;
import software.amazon.awscdk.core.Duration;
import software.amazon.awscdk.core.Stack;
import software.amazon.awscdk.services.apigateway.LambdaIntegration;
import software.amazon.awscdk.services.apigateway.LambdaIntegrationOptions;
import software.amazon.awscdk.services.apigateway.Resource;
import software.amazon.awscdk.services.apigateway.RestApi;
import software.amazon.awscdk.services.apigateway.RestApiProps;
import software.amazon.awscdk.services.iam.IManagedPolicy;
import software.amazon.awscdk.services.iam.ManagedPolicy;
import software.amazon.awscdk.services.iam.Role;
import software.amazon.awscdk.services.iam.RoleProps;
import software.amazon.awscdk.services.iam.ServicePrincipal;
import software.amazon.awscdk.services.lambda.Code;
import software.amazon.awscdk.services.lambda.Function;
import software.amazon.awscdk.services.lambda.FunctionProps;
import software.amazon.awscdk.services.lambda.Runtime;
import software.amazon.awscdk.services.s3.Bucket;

public class MyWidgetServiceStack extends Stack {
public MyWidgetServiceStack(final Construct scope, final String id) {
super(scope, id, null);

Bucket bucket = Bucket.Builder.create(this, "WidgetStore").build();

RestApi api = RestApi.Builder.create(this, "widgets-api")
.restApiName("Widget Service")
.description("This service serves widgets.")
.build();

List<IManagedPolicy> managedPolicyArray = new ArrayList<IManagedPolicy>();
managedPolicyArray.add((IManagedPolicy) ManagedPolicy.fromAwsManagedPolicyName("AmazonS3FullAccess"));

Role restApiRole = Role.Builder.create(this, "RestAPIRole")
.assumedBy(new ServicePrincipal("apigateway.amazonaws.com"))
.managedPolicies(managedPolicyArray)
.build();

Map<String, String> environmentVariables = new HashMap<String, String>();
environmentVariables.put("BUCKET", bucket.getBucketName());

Function lambdaFunction = Function.Builder.create(this, "WidgetHandler")
.code(Code.fromAsset("resources"))
.handler("widgets.main")
.timeout(Duration.seconds(300))
.runtime(Runtime.NODEJS_10_X)
.environment(environmentVariables)
.build();

bucket.grantReadWrite(lambdaFunction);

Map<String, String> lambdaIntegrationMap = new HashMap<String, String>();
lambdaIntegrationMap.put("application/json", "{ \"statusCode\": \"200\" }");

LambdaIntegration getWidgetIntegration = LambdaIntegration.Builder.create(lambdaFunction)
.requestTemplates(lambdaIntegrationMap)
.build();

api.getRoot().addMethod("GET", getWidgetIntegration);

LambdaIntegration postWidgetIntegration = new LambdaIntegration(lambdaFunction);
LambdaIntegration deleteWidgetIntegration = new LambdaIntegration(lambdaFunction);

Resource widget = api.getRoot().addResource("{id}");

widget.addMethod("POST", postWidgetIntegration);
widget.addMethod("GET", getWidgetIntegration);
widget.addMethod("DELETE", deleteWidgetIntegration);

}
}
Loading

0 comments on commit b53f0d4

Please sign in to comment.