Innovation, Clouds, Kubernetes, Standards and Java--airhacks.fm podcast

Subscribe to airhacks.fm podcast via: spotify| iTunes| RSS

The #192 airhacks.fm episode with Victor Orozco (@tuxtor) about:
Java's evolution from TDD, DevOps and automation, over cloud-native, to serverless Java in public clouds
is available for

From Java/JDK 7+ and Project Coin over Project Amber to Better Java Serialisation-airhacks.fm podcast

Subscribe to airhacks.fm podcast via: spotify| iTunes| RSS

The #191 airhacks.fm episode with Stuart Marks (@stuartmarks) about:
Western Pacific Railroad and the beginnings of business software development, Java 7 features, Project Coin, Project Amber, Java's serialization challenges and thoughts on future of Java serialization
is available for

Invoking AWS_IAM Auth Lambda Function URL with Java 11+ HttpClient

If your Lambda Function URL uses the AWS_IAM auth type:


import software.amazon.awscdk.services.lambda.FunctionUrlAuthType;
import software.amazon.awscdk.services.lambda.FunctionUrlOptions;
    
var functionUrl = function.addFunctionUrl(FunctionUrlOptions.builder()
.authType(FunctionUrlAuthType.AWS_IAM)
    .build());

you must sign each HTTP request using AWS Signature Version 4 (SigV4).

The class Aws4Signer ships with the dependency:


<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>auth</artifactId>
    <version>2.17.191</version>
</dependency>

...as well as the SDK:

<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>aws-sdk-java</artifactId>
    <version>2.17.191</version>
</dependency>

To sign a request:


import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.List;

import org.junit.jupiter.api.Test;

import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.auth.signer.Aws4Signer;
import software.amazon.awssdk.auth.signer.params.Aws4SignerParams;
import software.amazon.awssdk.http.SdkHttpFullRequest;
import software.amazon.awssdk.http.SdkHttpMethod;
import software.amazon.awssdk.regions.Region;

public class JavaHTTP11ClientTest {

    @Test
    public void signedHttpGET() throws IOException, InterruptedException {
        var uri = URI.create("https://mtpe2t7ucalsample62y0zkfwq.lambda-url.eu-central-1.on.aws/hello/");
        var host = uri.getHost();
        var path = uri.getPath();

...you have to create a SdkHttpFullRequest first:

        var fullRequest = SdkHttpFullRequest.builder()
                .encodedPath(path)
                .host(host)
                .protocol("https")
                .method(SdkHttpMethod.GET)
                .build();

The request is passed to AWS Signature Version 4 (SigV4) utility, which performs the signing:


        
        var signedRequest = Aws4Signer.create().sign(fullRequest,
            Aws4SignerParams.builder()
                    .signingName("lambda")
                    .awsCredentials(DefaultCredentialsProvider.create()
                                    .resolveCredentials())
                    .signingRegion(Region.EU_CENTRAL_1)
                    .build());

The signature is is passed as Authorization and X-Amz-Date headers to the Java 11 HttpClient:


        //Java 11+ HttpClient          
        var client = HttpClient.newHttpClient();
        var builder = HttpRequest.newBuilder(uri);

        signedRequest.headers().forEach((name, list) -> addHeader(builder, name, list));
        var request = builder.GET().build();
        var response = client.send(request, BodyHandlers.ofString());
        var status = response.statusCode();
        var body = response.body();
        //...
    }

    static void addHeader(HttpRequest.Builder requestBuilder,String name, List<String> values){
        if(name.equalsIgnoreCase("host")){
            return;
        }
        values.forEach(value -> requestBuilder.header(name, value));
    }    
}

The function URL Lambda from this example is based on the MicroProfile with Quarkus as AWS Lambda Function deployed with Cloud Development Kit (CDK) v2 for Java template.

Real World Enterprise Serverless Java on AWS Cloud--airhacks.fm podcast

Subscribe to airhacks.fm podcast via: spotify| iTunes| RSS

The #190 airhacks.fm episode with Goran Opacic (@goranopacic) about:
running a sales force automation company with serverless Java on AWS Lambdas, ECS Fargate, spot instances, Quarkus and managed services
is available for

Java 17 String to JSON with Glassfish' jakarta.json

To read a Java String with Jakarta JSON Processing (JSON-P) into a jakarta.json.JsonObject with Glassfish' implementation add the following dependency to your pom.xml:


<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>jakarta.json</artifactId>
    <version>2.0.1</version>
</dependency>

Now a JsonObject can be created from a String:

import java.io.StringReader;
import org.junit.jupiter.api.Test;
import jakarta.json.Json;

public class JsonpWithGlassfishTest {

    @Test
    public void parseJSON() {
        var expected = "glassfish";
        var json = """
                {"hello":"%s"}
                """.formatted(expected);
                
        try (var stringReader = new StringReader(json)){
            var jsonObject = Json.createReader(stringReader).readObject();
            var actual = jsonObject.getString("hello");
            assertEquals(expected, actual);
        }
    }
}

AWS Lambda with Provisioned Concurrency: How to use the latest deployment with HTTP API Gateway

To use the latest AWS Lambda deployment with HTTP API Gateway (or REST API Gateway):


import software.amazon.awscdk.services.apigatewayv2.alpha.HttpApi;
import software.amazon.awscdk.services.apigatewayv2.integrations.alpha.HttpLambdaIntegration;
//...
void integrateWithHTTPApiGateway(IFunction function) {
    var lambdaIntegration = HttpLambdaIntegration.Builder.create("HttpApiGatewayIntegration", function).build();
    var httpApiGateway = HttpApi.Builder.create(this, "HttpApiGatewayIntegration")
        .defaultIntegration(lambdaIntegration).build();
    var url = httpApiGateway.getUrl();
    CfnOutput.Builder.create(this, "HttpApiGatewayUrlOutput").value(url).build();
}

...configured with provisioned concurrency, you need to create an alias function.addAlias("XYZ"); (this convenience method was introduced with CDK v2.23.0) in addition to the version and use the function instance for the integration:

        
import software.amazon.awscdk.Duration;
import software.amazon.awscdk.services.lambda.Architecture;
import software.amazon.awscdk.services.lambda.Code;
import software.amazon.awscdk.services.lambda.Function;
import software.amazon.awscdk.services.lambda.Runtime;
import software.amazon.awscdk.services.lambda.Version;
import software.constructs.Construct;

public class QuarkusLambda extends Construct {

    static String lambdaHandler = "io.quarkus.amazon.lambda.runtime.QuarkusStreamHandler::handleRequest";
    static int memory = 1024; // ~0.5 vCPU
    static int provisionedConcurrency = 1;
    static int timeout = 10;
    Function function;

    public QuarkusLambda(Construct scope, String functionName) {
        super(scope, "QuarkusLambda");
        this.function = createFunction(functionName, lambdaHandler, memory, timeout);
        
        Version.Builder.create(this, "ProvisionedConcurrencyVersion")
                .lambda(function)
                .provisionedConcurrentExecutions(provisionedConcurrency)
                .build();
        function.addAlias("recent");
        integrateWithHTTPApiGateway(function);
        
    }

    Function createFunction(String functionName, String functionHandler, int memory, int timeout) {
        return Function.Builder.create(this, functionName)
                .runtime(Runtime.JAVA_11)
                .architecture(Architecture.ARM_64)
                .code(Code.fromAsset("../lambda/target/function.zip"))
                .handler(functionHandler)
                .memorySize(memory)
                .functionName(functionName)
                .timeout(Duration.seconds(timeout))
                .build();
    }

}

The code is based on quarkus AWS Lambda template.

How Pulumi for Java Happened--airhacks.fm podcast

Subscribe to airhacks.fm podcast via: spotify| iTunes| RSS

The #189 airhacks.fm episode with Joe Duffy (@funcofjoe) about:
Java, Infrastructure as Code, Pulumi's architecture, Java support and thoughts on public clouds and serverless computing
is available for

AWS Lambda: "UnreservedConcurrentExecution below its minimum value" and the solution

To fix the following AWS Lambda deployment error error:

Resource handler returned message: "Specified ReservedConcurrentExecutions for function decreases account's UnreservedConcurrentExecution below its minimum value of [50]. (Service: Lambda, Status Code: 400, Request ID: (...)
remove the reservedConcurrentExecutions from the lambda configuration:

import software.amazon.awscdk.Duration;
import software.amazon.awscdk.services.lambda.Architecture;
import software.amazon.awscdk.services.lambda.Code;
import software.amazon.awscdk.services.lambda.IFunction;
import software.amazon.awscdk.services.lambda.Function;
import software.amazon.awscdk.services.lambda.Runtime;

IFunction createFunction(String functionName,String functionHandler, int memory, int maximumConcurrentExecution, int timeout) {
    return Function.Builder.create(this, functionName)
            .runtime(Runtime.JAVA_11)
            .architecture(Architecture.ARM_64)
            .code(Code.fromAsset("../lambda/target/function.zip"))
            .handler(functionHandler)
            .memorySize(memory)
            .functionName(functionName)
            .timeout(Duration.seconds(timeout))
            //.reservedConcurrentExecutions(maximumConcurrentExecution)
            .build();
}    

...or request a concurrency limit increase for your AWS account.

Serverless Caches, JPA, Quarkus, JWT, SOAP deprecation, JSF performance, PostgreSQL clusters and JPA--98th airhacks.tv

The 98th airhacks.tv, live streamed from youtube.com/c/bienadam with the following topics:

"Serverless, Caches, JPA, Quarkus, Multipart, JWT authentication and Jakarta EE security, Java 11 SOAP deprecation, JSF performance, PostgreSQL clusters and JPA"

is ready:

See you every first Monday of the month at https://airhacks.tv 8pm CET (UTC+1:00). Show is also announced at: meetup.com/airhacks.

Any questions left? Ask now: gist.github.com/AdamBien/cb27cbe9bf704633549ae96b1c3bbc20 and get the answers at the next airhacks.tv.

AWS Lambda: Exposing Java (Corretto) / MicroProfile HTTP / REST Service via Function URL without Gateways or Application Load Balancers with CDK

With Lambda function URLs you can directly expose an AWS Lambda, without REST / HTTP API Gateway or Application Load Balancer.

An AWS Lambda function:


import software.amazon.awscdk.services.lambda.IFunction;
import software.amazon.awscdk.services.lambda.Function;
import software.amazon.awscdk.services.lambda.Runtime;
import software.constructs.Construct;

public class QuarkusLambda extends Construct{

    static Map<String, String> configuration = Map.of("message", "hello, quarkus as AWS Lambda");
    static String lambdaHandler = "io.quarkus.amazon.lambda.runtime.QuarkusStreamHandler::handleRequest";
    static int memory = 1024; //~0.5 vCPU
    static int maxConcurrency = 2;
    static int timeout = 10;
    IFunction function;

    public QuarkusLambda(Construct scope,String functionName) {
        super(scope, "QuarkusLambda");
        this.function = createFunction(functionName, lambdaHandler, configuration, memory, maxConcurrency, timeout);
    }

    IFunction createFunction(String functionName,String functionHandler, Map<String,String> configuration, int memory, int maximumConcurrentExecution, int timeout) {
        return Function.Builder.create(this, functionName)
                .runtime(Runtime.JAVA_11)
                .architecture(Architecture.ARM_64)
                .code(Code.fromAsset("../lambda/target/function.zip"))
                .handler(functionHandler)
                .memorySize(memory)
                .functionName(functionName)
                .environment(configuration)
                .timeout(Duration.seconds(timeout))
                .reservedConcurrentExecutions(maximumConcurrentExecution)
                .build();
    }    

    public IFunction getFunction(){
        return this.function;
    }
}

Can be directly exposed via a generated URL with:


var quarkuLambda = new QuarkusLambda(this, "airhacks_lambda_gretings_boundary_FUrl");
var function = quarkuLambda.getFunction();
var functionUrl = function
        .addFunctionUrl(FunctionUrlOptions.builder()
        .authType(FunctionUrlAuthType.NONE)
        .build());
CfnOutput.Builder.create(this, "FunctionURLOutput").value(functionUrl.getUrl()).build();

In this 6 minute screencast I refactored a Lambda from HTTP API Gateway to use Function URL directly:

The example in the screencast is based on the Quarkus / Lambda template: github.com/AdamBien/aws-quarkus-lambda-cdk-plain

Online Workshops
...the last 150 posts
...the last 10 comments
License