Flange Cloud™ Quick Start
Flange Cloud initially supports the Amazon Web Services cloud platform.
Requisites
- Java 17+ (e.g. Adoptium)
- Apache Maven 3.9.x
- AWS Command Line Interface (CLI)
- AWS Serverless Application Model (SAM) CLI (🚧 In a future version, Flange may no longer depend on SAM.)
- Bash (or Git Bash on Windows)
Development
Service interfaces (e.g. CalendarService
) and service implementations (e.g. CalendarServiceImpl
) must be in separate Maven projects. This allows cloud components to access services without being tightly coupled to service implementations, which may be deployed independently. Otherwise individual Maven projects may be built together as aggregatess of a composite project, or may be developed independently as separate projects. Flange doesn't care if you store your entire application in a single source code repository or in multiple repositories.
Service Interface
- Annotate a service interface such as
CalendarService
with@CloudFunctionApi
. This tells Flange that the service will be invoked as a cloud function (e.g. Lambda in AWS). - Pass parameters using aggregate data types, preferably a Java record class. Common Java value types such as
Instant
,Locale
, and evenOptional<>
are supported. - A service method must return a value using
CompletableFuture<T>
.
@CloudFunctionApi
public interface CalendarService {
CompletableFuture<Optional<String>> findHolidayName(LocalDate date);
…
Service Implementation
- Annotate a service implementation such as
CalendarServiceImpl
with@CloudFunctionService
. This tells Flange that the service will be implemented as a cloud function (e.g. Lambda in AWS). - (optional) If the service implementation in turn depends on another service such as
OtherService
, add an annotation@ServiceConsumer(OtherService.class)
indicating the interface of the other service. You will probably also want to inject the other service interface in the constructor; see below.
@CloudFunctionService
@ServiceConsumer(OtherService.class)
public class CalendarServiceImpl implements CalendarService {
private final OtherService otherService;
public CalendarServiceImpl(OtherService otherService) {
this.otherService = requireNonNull(otherService);
}
@Override
public CompletableFuture<Optional<String>> findHolidayName(LocalDate date) {
if(date.getDayOfYear() == 1) {
return CompletableFuture.completedFuture(Optional.of("New Year"));
}
//TODO check for other holidays
return CompletableFuture.completedFuture(Optional.empty());
…
Flange Cloud Application (optional)
You can create an application “driver” program to invoke your functions for testing locally or invoking functions in the cloud. Flange Cloud provides an extremely lightweight FlangeCloudApplication
interface to facility creating an application that recognizes command-line arguments for invoking deployed cloud functions, just as deployed Flange services invoke other Flange services in the cloud. The interface provides a convenient FlangeCloudApplication.start(…)
method to execute your application from the main(…)
entrypoint. The following example shows a simple application that implements FlangeCloudApplication
and uses a CalendarService
that may be local or in the cloud.
@ServiceConsumer(CalendarService.class)
public class HolidayApp implements FlangeCloudApplication {
private final CalendarService calendarService;
public HolidayApp(CalendarService calendarService) {
this.calendarService = requireNonNull(calendarService);
}
@Override
public void run() {
//TODO access `calendarService`
}
public static void main(String[] args) {
FlangeCloudApplication.start(HolidayApp.class, args);
}
}
Executing the application locally or in the cloud is explained in a section below.
Declare Local Dependency Implementations (optional)
If you intend to run your application locally, for example from a local application “driver” program as explained in the previous section, you must prepare a flange-dependencies.lst
file in the application project (typically in src/main/resources/
), indicating the full path and class name of each service implementation as in the example below. Flange currently does no classpath scanning, which allows for faster cold start times. Classpath scanning may be provided as a configurable option in a future version of Flange.
com.example.calendar.service.impl.CalendarServiceImpl
com.example.other.service.impl.OtherServiceImpl
Build
Dependency Management
Before including specific Flange dependencies in individual projects as needed, it is easiest to place the entire Flange bill of materials (BOM) under dependency management. Add the following to a parent POM, setting flange.version
appropriately:
<dependencyManagement>
<dependencies>
…
<dependency>
<groupId>dev.flange</groupId>
<artifactId>flange-bom</artifactId>
<version>${flange.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Annotation Processing
Turn on Flange Cloud annotation processing in your Maven project(s) for the Maven Compiler Plugin. It is recommended to simply add the following to a parent POM, setting flange.version
appropriately:
<build>
<pluginManagement>
<plugins>
…
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>dev.flange</groupId>
<artifactId>flange-build</artifactId>
<version>${flange.version}</version>
</annotationProcessorPath>
</annotationProcessorPaths>
<annotationProcessors>
<annotationProcessor>dev.flange.build.cloud.FlangeCloudAnnotationProcessor</annotationProcessor>
</annotationProcessors>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
Flange Cloud Dependency
Each component using Flange Cloud interface (primarily annotations and exceptions) must include the Flange Cloud API dependency, dev.flange:flange-cloud
:
<dependencies>
…
<dependency>
<groupId>dev.flange</groupId>
<artifactId>flange-cloud</artifactId>
</dependency>
</dependencies>
Service Implementation Runtime Dependency
Each project containing one or more service implementations must declare the dev.flange:flange-cloud-aws-runtime
dependency to provide the necessary runtime support when deployed to the cloud. Declare the dependency with provided
scope so that this cloud-related code will not be included when executing locally; the Flange Cloud assembly (see below) will know how to include the runtime appropriately when deploying to the cloud, as long as it is declared in the POM as so:
<dependencies>
…
<dependency>
<groupId>dev.flange</groupId>
<artifactId>flange-cloud-aws-runtime</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
Service Implementation Assembly Configuration
For each service implementation to deployed as a cloud flunction, configure the Maven Assembly Plugin in the project POM for the service using the following form. Replace ServiceImpl
with the name of your service implementation class, such as CalenderServiceImpl
from the example above.
<build>
<plugins>
…
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>ServiceImpl</finalName>
<appendAssemblyId>true</appendAssemblyId>
<descriptors>
<descriptor>${project.build.directory}/generated-sources/annotations/assembly-ServiceImpl-aws-lambda.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Performing a Build
Performing a build and preparing for deploying is done in typical Maven fashion:
mvn clean package
A full clean build is required before deploying to the cloud.
Deployment
CloudFormation Environment Stack
Flange Cloud requires that you have a CloudFormation stack to serve as your deployment environment such as dev
, test-jdoe
, or prod
. Multiple deployment environments can be set up on the same AWS account.
The CloudFormation stack name must be in the form flange-environment
, where environment
is the identifier of the development environment the stack defines. (🚧 Future versions of Flange will allow more flexibility in the stack name.) The stack must export the following outputs:
flange-environment:FlangeStage
- The deployment stage, such as
def
,qa
, orprod
flange-environment:FlangeProfilesActive
- The comma-separated list of active profiles, such as
dev,test
. flange-environment:StagingBucketName
- The name of the S3 bucket for staging artifacts.
Deploy to the Cloud
Use the cloud deploy
command of the Flange command-line interface (CLI) script flange.sh
, found in the bin/
directory in the source code distribution, to deploy your services to the cloud. You may invoke the Flange CLI in a service implementation Maven project to deploy an individual service to the cloud, or invoke the Flange CLI in the root directory of an aggregate Maven project to deploy all services to the cloud. The following example assumes you have a CloudFormation stack (see above) for a deployment environment named dev
.
flange.sh cloud deploy dev
Execution
Once you deploy your services to the cloud, they automatically know how to invoke other cloud services they depend on. In order to manually invoke a deployed Flange cloud function service, you can create a local application serving as a “driver”, as explained above. (The other option for manually invoking a deployed Flange cloud function service is to use a low-level cloud invocation, which requires knowledge of the underlying Flange Cloud marshalling technique and which is outside the scope of this quick start.)
Local Application Execution, Local Service Invocation
To execute your application locally, invoking your services locally, simply run your application as you would normally, either from the command line or within your IDE.
Local Application Execution, Cloud Service Invocation
You can also execute your application locally, but have it invoke your deployed services in the cloud (assuming you have already deployed the services as explained above). This requires that your application use the FlangeCloudApplication
facility explained above. Execute it using the Flange CLI bin/flange.sh
exec
. Indicate the aws
platform using the --flange-platform
option, specify the deployment environment using the --flange-env
option. The following example shows how to execute one of the applications from the published examples, invoking services deployed on the AWS platform in the dev
deployment environment. Don't forget to include --
after flange.sh exec
to indicate that the --flange-*
arguments are intended for the application, not the the Flange CLI itself.
flange.sh exec -- \
dev.flange.example.cloud.hellouser_faas.app.HelloUserFaasApp \
--flange-platform aws --flange-env dev