Skip to content

Commit

Permalink
feat(dynamodb): implement dynamoDB connector (#381)
Browse files Browse the repository at this point in the history
  • Loading branch information
Oleksiivanov authored Apr 18, 2023
1 parent 4a8a335 commit 71d43a3
Show file tree
Hide file tree
Showing 41 changed files with 2,005 additions and 3 deletions.
4 changes: 4 additions & 0 deletions bundle/mvn/default-bundle/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
<groupId>io.camunda.connector</groupId>
<artifactId>connector-sqs</artifactId>
</dependency>
<dependency>
<groupId>io.camunda.connector</groupId>
<artifactId>connector-aws</artifactId>
</dependency>
<dependency>
<groupId>io.camunda.connector</groupId>
<artifactId>connector-aws-lambda</artifactId>
Expand Down
5 changes: 5 additions & 0 deletions bundle/mvn/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@
<artifactId>connector-sqs</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.camunda.connector</groupId>
<artifactId>connector-aws</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.camunda.connector</groupId>
<artifactId>connector-aws-lambda</artifactId>
Expand Down
5 changes: 5 additions & 0 deletions connectors/aws/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under one or more contributor license agreements and licensed to you under a proprietary license.
You may not use this file except in compliance with the proprietary license.
The proprietary license can be either the Camunda Platform Self-Managed Free Edition license (available on Camunda’s website) or the Camunda Platform Self-Managed Enterprise Edition license (a copy you obtain when you contact Camunda).
The Camunda Platform Self-Managed Free Edition comes for free but only allows for usage of the software (file) in non-production environments.
If you want to use the software (file) in production, you need to purchase the Camunda Platform Self-Managed Enterprise Edition.
108 changes: 108 additions & 0 deletions connectors/aws/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Camunda Amazon Web Services (AWS) Connector
This is a base connector that provides common functionality for working with AWS services. It provides an abstract implementation of `io.camunda.connector.aws.model.AwsService` that can be extended to implement AWS-specific services.

## Service implementation
The AWS Base Connector provides an abstract implementation of `io.camunda.connector.aws.model.AwsService` that can be extended to implement AWS-specific services.

To create a new service implementation, you can follow the steps below:

- Create a new class that extends `io.camunda.connector.aws.model.AwsService`.
- Implement the `invoke` method with your own logic. This method should take in an `AWSStaticCredentialsProvider`, an `AwsBaseConfiguration`, and an `OutboundConnectorContext`, and should return an `Object` that represents the result of the operation.
- Add a private `String` field called `type` to your class.
- Implement the `getType` and `setType` methods to get and set the value of the `type` field.
- Register your new service implementation in the `io.camunda.connector.aws.GsonComponentSupplier` class by adding a new case statement to the `create` method that handles the `type` value of your new service implementation.
- Here's an example implementation of a new service:

```java
public class MyAwsService implements AwsService {

private String type = "myServiceType";

@Override
public Object invoke(
final AWSStaticCredentialsProvider credentialsProvider,
final AwsBaseConfiguration configuration,
final OutboundConnectorContext context) {
// your AWS-specific service logic goes here
return null;
}

@Override
public String getType() {
return type;
}

@Override
public void setType(final String type) {
this.type = type;
}
}

```
- Here's an example of registering a new service in GsonComponentSupplier:
```java
public final class GsonComponentSupplier {

private static final Gson GSON =
new GsonBuilder()
.serializeNulls()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.registerTypeAdapterFactory(
RuntimeTypeAdapterFactory.of(AwsService.class, "type")
.registerSubtype(AwsDynamoDbService.class, "myServiceType"))
.create();

private GsonComponentSupplier() {}

public static Gson gsonInstance() {
return GSON;
}
}
```

- For implementing AWS service connector template, you need to use the following task definition type: io.camunda:aws:1. Here's an example of an AWS service connector template that uses AWS Base Connector as the entry point:
```json
{
"$schema": "https://unpkg.com/@camunda/zeebe-element-templates-json-schema/resources/schema.json",
"name": "AWS myServiceType",
"id": "io.camunda.connectors.myService.v1",
"documentationRef": "https://docs.camunda.io/docs/components/connectors/out-of-the-box-connectors/aws-myService/",
"category": {
"id": "connectors",
"name": "Connectors"
},
"appliesTo": [
"bpmn:Task"
],
"elementType": {
"value": "bpmn:ServiceTask"
},
"groups": [
],
"properties": [
{
"type": "Hidden",
"value": "io.camunda:aws:1",
"binding": {
"type": "zeebe:taskDefinition:type"
}
},
{
"type": "Hidden",
"value": "myServiceType",
"binding": {
"type": "zeebe:input",
"name": "service.type"
},
"constraints": {
"notEmpty": true
}
}
]
}
```


## Implemented services :
### AWS DynamoDB Connector
The [AWS DynamoDB Connector](https://docs.camunda.io/docs/components/connectors/out-of-the-box-connectors/aws-dynamodb/) allows you to connect your BPMN service with [Amazon Web Service's DynamoDB Service](https://aws.amazon.com/dynamodb/). This can be useful for performing CRUD operations on AWS DynamoDB tables from within a BPMN process.
3 changes: 3 additions & 0 deletions connectors/aws/connector.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: AWS
type: io.camunda:aws:1
variables: [ authentication, configuration, input, type ]
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
"value": "dynamoDb",
"binding": {
"type": "zeebe:input",
"name": "type"
"name": "service.type"
},
"constraints": {
"notEmpty": true
Expand Down Expand Up @@ -635,8 +635,6 @@
"condition": {
"property": "itemOperationType",
"oneOf": [
"deleteItem",
"getItem",
"updateItem"
]
}
Expand Down
63 changes: 63 additions & 0 deletions connectors/aws/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<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>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>

<parent>
<groupId>io.camunda.connector</groupId>
<artifactId>connector-function-parent</artifactId>
<version>0.19.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<name>connector-aws</name>
<description>Camunda Connector AWS function</description>
<artifactId>connector-aws</artifactId>
<packaging>jar</packaging>

<licenses>
<license>
<name>Camunda Platform Self-Managed Free Edition license</name>
<url>https://camunda.com/legal/terms/cloud-terms-and-conditions/camunda-cloud-self-managed-free-edition-terms/</url>
</license>
<license>
<name>Camunda Platform Self-Managed Enterprise Edition license</name>
</license>
</licenses>

<dependencies>


<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>

<dependency>
<groupId>org.danilopianini</groupId>
<artifactId>gson-extras</artifactId>
</dependency>

<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-dynamodb</artifactId>
<version>${version.aws-java-sdk}</version>
</dependency>

</dependencies>

</project>


Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. Licensed under a proprietary license.
* See the License.txt file for more information. You may not use this file
* except in compliance with the proprietary license.
*/
package io.camunda.connector.aws;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.google.gson.Gson;
import io.camunda.connector.api.annotation.OutboundConnector;
import io.camunda.connector.api.outbound.OutboundConnectorContext;
import io.camunda.connector.api.outbound.OutboundConnectorFunction;
import io.camunda.connector.aws.model.impl.AwsBaseAuthentication;
import io.camunda.connector.aws.model.impl.AwsBaseRequest;

@OutboundConnector(
name = "AWS",
inputVariables = {"authentication", "configuration", "input", "service"},
type = "io.camunda:aws:1")
public class AwsConnectorFunction implements OutboundConnectorFunction {
private final Gson gson;

public AwsConnectorFunction() {
this.gson = GsonComponentSupplier.gsonInstance();
}

@Override
public Object execute(final OutboundConnectorContext context) throws Exception {
String variables = context.getVariables();

AwsBaseRequest awsRequest = gson.fromJson(variables, AwsBaseRequest.class);
context.validate(awsRequest);
context.replaceSecrets(awsRequest);

return awsRequest
.getService()
.invoke(extractCredentialsProvider(awsRequest), awsRequest.getConfiguration(), context);
}

private AWSStaticCredentialsProvider extractCredentialsProvider(final AwsBaseRequest authConfig) {
AwsBaseAuthentication authentication = authConfig.getAuthentication();
return new AWSStaticCredentialsProvider(
new BasicAWSCredentials(authentication.getAccessKey(), authentication.getSecretKey()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. Licensed under a proprietary license.
* See the License.txt file for more information. You may not use this file
* except in compliance with the proprietary license.
*/
package io.camunda.connector.aws;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.ToNumberPolicy;
import com.google.gson.typeadapters.RuntimeTypeAdapterFactory;
import io.camunda.connector.aws.dynamodb.AwsDynamoDbService;
import io.camunda.connector.aws.model.AwsService;

public final class GsonComponentSupplier {

private static final Gson GSON =
new GsonBuilder()
.serializeNulls()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.registerTypeAdapterFactory(
RuntimeTypeAdapterFactory.of(AwsService.class, "type")
.registerSubtype(AwsDynamoDbService.class, "dynamoDb"))
.create();

private GsonComponentSupplier() {}

public static Gson gsonInstance() {
return GSON;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. Licensed under a proprietary license.
* See the License.txt file for more information. You may not use this file
* except in compliance with the proprietary license.
*/
package io.camunda.connector.aws.dynamodb;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import io.camunda.connector.aws.model.impl.AwsBaseConfiguration;

public final class AwsDynamoDbClientSupplier {

private AwsDynamoDbClientSupplier() {}

public static DynamoDB getDynamoDdClient(
final AWSStaticCredentialsProvider credentialsProvider,
final AwsBaseConfiguration configuration) {
AmazonDynamoDB client =
AmazonDynamoDBClientBuilder.standard()
.withCredentials(credentialsProvider)
.withRegion(configuration.getRegion())
.build();
return new DynamoDB(client);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. Licensed under a proprietary license.
* See the License.txt file for more information. You may not use this file
* except in compliance with the proprietary license.
*/
package io.camunda.connector.aws.dynamodb;

import io.camunda.connector.aws.dynamodb.model.item.AddItem;
import io.camunda.connector.aws.dynamodb.model.item.DeleteItem;
import io.camunda.connector.aws.dynamodb.model.item.GetItem;
import io.camunda.connector.aws.dynamodb.model.item.UpdateItem;
import io.camunda.connector.aws.dynamodb.model.table.CreateTable;
import io.camunda.connector.aws.dynamodb.model.table.DeleteTable;
import io.camunda.connector.aws.dynamodb.model.table.DescribeTable;
import io.camunda.connector.aws.dynamodb.model.table.ScanTable;
import io.camunda.connector.aws.dynamodb.operation.AwsDynamoDbOperation;
import io.camunda.connector.aws.dynamodb.operation.item.AddItemOperation;
import io.camunda.connector.aws.dynamodb.operation.item.DeleteItemOperation;
import io.camunda.connector.aws.dynamodb.operation.item.GetItemOperation;
import io.camunda.connector.aws.dynamodb.operation.item.UpdateItemOperation;
import io.camunda.connector.aws.dynamodb.operation.table.CreateTableOperation;
import io.camunda.connector.aws.dynamodb.operation.table.DeleteTableOperation;
import io.camunda.connector.aws.dynamodb.operation.table.DescribeTableOperation;
import io.camunda.connector.aws.dynamodb.operation.table.ScanTableOperation;
import io.camunda.connector.aws.model.AwsInput;

public class AwsDynamoDbOperationFactory {
private static final AwsDynamoDbOperationFactory instance = new AwsDynamoDbOperationFactory();

private AwsDynamoDbOperationFactory() {}

public static AwsDynamoDbOperationFactory getInstance() {
return instance;
}

public AwsDynamoDbOperation createOperation(AwsInput input) {
if (input instanceof AddItem) {
return new AddItemOperation((AddItem) input);
} else if (input instanceof CreateTable) {
return new CreateTableOperation((CreateTable) input);
} else if (input instanceof DeleteItem) {
return new DeleteItemOperation((DeleteItem) input);
} else if (input instanceof DeleteTable) {
return new DeleteTableOperation((DeleteTable) input);
} else if (input instanceof DescribeTable) {
return new DescribeTableOperation((DescribeTable) input);
} else if (input instanceof GetItem) {
return new GetItemOperation((GetItem) input);
} else if (input instanceof ScanTable) {
return new ScanTableOperation((ScanTable) input);
} else if (input instanceof UpdateItem) {
return new UpdateItemOperation((UpdateItem) input);
} else {
throw new UnsupportedOperationException("Unsupported operation : [" + input.getClass() + "]");
}
}
}
Loading

0 comments on commit 71d43a3

Please sign in to comment.