-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# CDK Java Example | ||
|
||
This an example of a CDK program written in Java. | ||
|
||
> NOTE: Since this example currently resides inside the CDK repository, it takes | ||
a dependency on the CDK for Java maven package that's built under | ||
`packages/aws-cdk-java`. To enable this, we generate the `pom.xml` file, so we | ||
can plug in the locations of the local maven repositories. This is not | ||
something you will need to do if you are simply using the published CDK maven | ||
package. | ||
|
||
## Building | ||
|
||
To build this app, run `npm run prepare`. This will: | ||
|
||
1. Generate `project/pom.xml` with correct references to jsii and CDK | ||
dependencies. | ||
2. Run `mvn package`, which will compile, test and assemble an executable jar. | ||
|
||
## IDE | ||
|
||
Once the `pom.xml` file is generated, the [`./project`](./project) directory is | ||
fully functional Maven project, and you should be able to open it from any Java | ||
IDE which supports Maven. | ||
|
||
You can use the 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 use `java -jar <executale-jar> app` for the `--app` switch. This means, | ||
you should be able to use the toolkit normally: | ||
|
||
``` | ||
$ 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> | ||
``` | ||
|
||
If you make modifications, make sure to rebuild the app, either by callign `mvn | ||
package` from `./project` or `npm run prepare` from the root. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
{ | ||
"app": "/bin/bash run-program.sh" | ||
} | ||
"app": "java -jar project/target/cdk-examples-java-0.7.2-beta-jar-with-dependencies.jar app" | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
eladb
Contributor
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,4 +3,7 @@ target | |
# generated by pom.xml.t.js | ||
pom.xml | ||
|
||
.idea | ||
.idea | ||
.classpath | ||
.project | ||
.settings |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package com.amazonaws.cdk.examples; | ||
|
||
import com.amazonaws.cdk.Construct; | ||
import com.amazonaws.cdk.sns.Topic; | ||
import com.amazonaws.cdk.sqs.Queue; | ||
import com.amazonaws.cdk.sqs.QueueProps; | ||
|
||
/** | ||
* A sink queue is a queue aggregates messages published to any number of SNS topics. | ||
*/ | ||
public class SinkQueue extends Construct { | ||
private final Queue queue; | ||
private int numberOfTopics = 0; | ||
This comment has been minimized.
Sorry, something went wrong.
RomainMuller
Contributor
|
||
private final int maxTopics; | ||
|
||
/** | ||
* Defines a SinkQueue. | ||
* | ||
* @param parent Parent construct | ||
* @param name Logical name | ||
* @param props Props | ||
*/ | ||
public SinkQueue(final Construct parent, final String name, SinkQueueProps props) { | ||
super(parent, name); | ||
|
||
// ensure props is non-null | ||
props = props != null ? props : SinkQueueProps.builder().build(); | ||
|
||
// defaults | ||
QueueProps queueProps = props.getQueueProps(); | ||
this.maxTopics = props.getMaxTopics() != null ? props.getMaxTopics().intValue() : 10; | ||
|
||
// WORKAROUND: https://github.com/awslabs/aws-cdk/issues/157 | ||
if (queueProps == null) { | ||
queueProps = QueueProps.builder().build(); | ||
This comment has been minimized.
Sorry, something went wrong.
RomainMuller
Contributor
|
||
} | ||
|
||
this.queue = new Queue(this, "Resource", queueProps); | ||
} | ||
|
||
/** | ||
* Defines a SinkQueue with default props. | ||
* @param parent Parent construct | ||
* @param name Logical name | ||
*/ | ||
public SinkQueue(final Construct parent, final String name) { | ||
this(parent, name, null); | ||
} | ||
|
||
/** | ||
* Subscribes this queue to receive messages published to the specified topics. | ||
* | ||
* @param topics The topics to subscribe to | ||
*/ | ||
public void subscribe(final Topic... topics) { | ||
for (Topic topic: topics) { | ||
if (numberOfTopics == maxTopics) { | ||
throw new RuntimeException("Cannot add more topics to the sink. Maximum topics is configured to " + this.maxTopics); | ||
} | ||
topic.subscribeQueue(this.queue); | ||
numberOfTopics++; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.amazonaws.cdk.examples; | ||
|
||
import com.amazonaws.cdk.sqs.QueueProps; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Builder; | ||
import lombok.Data; | ||
import lombok.NoArgsConstructor; | ||
|
||
/** | ||
* Props for {@link SinkQueue} | ||
*/ | ||
@Data @Builder @NoArgsConstructor @AllArgsConstructor | ||
This comment has been minimized.
Sorry, something went wrong.
RomainMuller
Contributor
|
||
public class SinkQueueProps { | ||
/** | ||
* Props for the queue itself | ||
* @default See {@link com.amazonaws.cdk.sqs.Queue} defaults | ||
*/ | ||
private QueueProps queueProps; | ||
|
||
/** | ||
* The maximum number of topics allowed to subscribe to this queue. | ||
* @default 10 | ||
*/ | ||
private Number maxTopics; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package com.amazonaws.cdk.examples; | ||
|
||
import com.amazonaws.cdk.Stack; | ||
import com.amazonaws.cdk.sns.Topic; | ||
import com.amazonaws.cdk.sqs.QueueProps; | ||
import com.fasterxml.jackson.databind.JsonNode; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import org.junit.Test; | ||
|
||
import java.io.IOException; | ||
import java.net.URL; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.assertTrue; | ||
|
||
public class SinkQueueTest { | ||
|
||
private static ObjectMapper JSON = new ObjectMapper(); | ||
|
||
/** Defines a queue sink with default props */ | ||
@Test public void testDefaults() throws IOException { | ||
Stack stack = new Stack(); | ||
new SinkQueue(stack, "MySinkQueue"); | ||
assertTemplate(stack, "{\"Resources\":{\"MySinkQueueEFCD79C2\":{\"Type\":\"AWS::SQS::Queue\"}}}"); | ||
} | ||
|
||
/** Defines a sink with custom queue props */ | ||
@Test public void testQueueProps() throws IOException { | ||
Stack stack = new Stack(); | ||
new SinkQueue(stack, "MySinkQueue", SinkQueueProps.builder() | ||
.queueProps(QueueProps.builder() | ||
.withVisibilityTimeoutSec(500) | ||
.build()) | ||
.build()); | ||
assertTemplate(stack, "{\n" + | ||
" \"Resources\" : {\n" + | ||
" \"MySinkQueueEFCD79C2\" : {\n" + | ||
" \"Type\" : \"AWS::SQS::Queue\",\n" + | ||
" \"Properties\" : {\n" + | ||
" \"VisibilityTimeout\" : 500\n" + | ||
" }\n" + | ||
" }\n" + | ||
" }\n" + | ||
"}"); | ||
} | ||
|
||
/** Calls "subscribe" to add topics to the sink */ | ||
@Test public void testSubscribeTopics() throws IOException { | ||
Stack stack = new Stack(); | ||
|
||
SinkQueue sink = new SinkQueue(stack, "MySinkQueue"); | ||
|
||
// add three topics in two calls to "subscribe" | ||
sink.subscribe(new Topic(stack, "Topic1"), new Topic(stack, "Topic2")); | ||
sink.subscribe(new Topic(stack, "Topic3")); | ||
|
||
assertTemplate(stack, getClass().getResource("testSubscribeTopics.expected.json")); | ||
} | ||
|
||
/** Verifies that if we exceed the number of allows topics, an exception is thrown */ | ||
@Test public void failsIfExceedMaxTopic() throws IOException { | ||
Stack stack = new Stack(); | ||
|
||
SinkQueue sink = new SinkQueue(stack, "MySinkQueue", SinkQueueProps.builder() | ||
.maxTopics(3) | ||
.build()); | ||
|
||
sink.subscribe(new Topic(stack, "Topic1")); | ||
sink.subscribe(new Topic(stack, "Topic2")); | ||
sink.subscribe(new Topic(stack, "Topic3")); | ||
|
||
boolean thrown = false; | ||
try { | ||
sink.subscribe(new Topic(stack, "Topic4")); | ||
} catch (RuntimeException e) { | ||
thrown = true; | ||
} | ||
assertTrue(thrown); | ||
} | ||
|
||
private static void assertTemplate(final Stack stack, final URL expectedResource) throws IOException { | ||
assertTemplate(stack, JSON.readTree(expectedResource)); | ||
} | ||
|
||
private static void assertTemplate(final Stack stack, final String expectedTemplate) throws IOException { | ||
assertTemplate(stack, JSON.readTree(expectedTemplate)); | ||
} | ||
|
||
private static void assertTemplate(final Stack stack, final JsonNode expected) throws IOException { | ||
JsonNode actual = JSON.valueToTree(stack.toCloudFormation()); | ||
|
||
// print to stderr if non-equal, so it will be easy to grab | ||
if (expected == null || !expected.equals(actual)) { | ||
String prettyActual = JSON.writerWithDefaultPrettyPrinter().writeValueAsString(actual); | ||
System.err.println(prettyActual); | ||
} | ||
|
||
assertEquals(expected, actual); | ||
} | ||
} |
What's the
app
that is being passed as an argument here?