/**
* POST TITLE: OpenFaaS Java Template - Serverless Functions in Java
*
* Complete OpenFaaS template implementation for Java functions with multiple frameworks
*/
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpExchange;
import java.io.*;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.*;
public class OpenFaaSTemplate {
/**
* Base OpenFaaS Function Interface
*/
@FunctionalInterface
public interface OpenFaaSFunction {
byte[] handle(byte[] input, Map<String, String> context);
}
/**
* Function Context containing request metadata
*/
public static class FunctionContext {
private final Map<String, String> headers;
private final String method;
private final String query;
private final String contentType;
private final String userAgent;
public FunctionContext(Map<String, String> headers) {
this.headers = headers != null ? headers : new HashMap<>();
this.method = this.headers.getOrDefault("Http_Method", "GET");
this.query = this.headers.getOrDefault("Http_Query", "");
this.contentType = this.headers.getOrDefault("Content-Type", "text/plain");
this.userAgent = this.headers.getOrDefault("User-Agent", "");
}
// Getters
public Map<String, String> getHeaders() { return headers; }
public String getMethod() { return method; }
public String getQuery() { return query; }
public String getContentType() { return contentType; }
public String getUserAgent() { return userAgent; }
public String getHeader(String name) { return headers.get(name); }
// Common OpenFaaS context headers
public String getFunctionName() { return headers.getOrDefault("Http_Function_Name", ""); }
public String getCallbackUrl() { return headers.getOrDefault("Http_Callback_Url", ""); }
public int getContentLength() {
return Integer.parseInt(headers.getOrDefault("Content-Length", "0"));
}
}
/**
* OpenFaaS Function Response
*/
public static class FunctionResponse {
private final byte[] body;
private final int statusCode;
private final String contentType;
private final Map<String, String> headers;
public FunctionResponse(byte[] body, int statusCode, String contentType) {
this.body = body != null ? body : new byte[0];
this.statusCode = statusCode;
this.contentType = contentType != null ? contentType : "text/plain";
this.headers = new HashMap<>();
}
public FunctionResponse(String body, int statusCode, String contentType) {
this(body.getBytes(StandardCharsets.UTF_8), statusCode, contentType);
}
// Builder pattern
public static Builder builder() {
return new Builder();
}
public static class Builder {
private byte[] body;
private int statusCode = 200;
private String contentType = "text/plain";
private Map<String, String> headers = new HashMap<>();
public Builder body(byte[] body) {
this.body = body;
return this;
}
public Builder body(String body) {
this.body = body.getBytes(StandardCharsets.UTF_8);
return this;
}
public Builder statusCode(int statusCode) {
this.statusCode = statusCode;
return this;
}
public Builder contentType(String contentType) {
this.contentType = contentType;
return this;
}
public Builder header(String name, String value) {
this.headers.put(name, value);
return this;
}
public FunctionResponse build() {
FunctionResponse response = new FunctionResponse(body, statusCode, contentType);
response.headers.putAll(headers);
return response;
}
}
// Getters
public byte[] getBody() { return body; }
public int getStatusCode() { return statusCode; }
public String getContentType() { return contentType; }
public Map<String, String> getHeaders() { return headers; }
}
/**
* OpenFaaS Runtime Server
*/
public static class OpenFaaSRuntime {
private final HttpServer server;
private final ExecutorService executor;
private final Map<String, OpenFaaSFunction> functions;
private final int port;
public OpenFaaSRuntime(int port) throws IOException {
this.port = port;
this.server = HttpServer.create(new InetSocketAddress(port), 0);
this.executor = Executors.newFixedThreadPool(10);
this.functions = new ConcurrentHashMap<>();
// Health check endpoint
server.createContext("/_/health", new HealthHandler());
// System endpoints
server.createContext("/_/ready", new ReadyHandler());
server.createContext("/_/metrics", new MetricsHandler());
System.out.println("š OpenFaaS Java Runtime started on port " + port);
}
public void registerFunction(String path, OpenFaaSFunction function) {
server.createContext(path, new FunctionHandler(function));
functions.put(path, function);
System.out.println("š Registered function: " + path);
}
public void start() {
server.setExecutor(executor);
server.start();
System.out.println("ā
OpenFaaS Runtime ready to handle requests");
}
public void stop() {
System.out.println("š Stopping OpenFaaS Runtime...");
server.stop(1);
executor.shutdown();
System.out.println("ā
OpenFaaS Runtime stopped");
}
/**
* Health Check Handler
*/
private static class HealthHandler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
String response = "{\"status\": \"healthy\"}";
exchange.getResponseHeaders().set("Content-Type", "application/json");
exchange.sendResponseHeaders(200, response.length());
try (OutputStream os = exchange.getResponseBody()) {
os.write(response.getBytes());
}
}
}
/**
* Ready Check Handler
*/
private static class ReadyHandler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
String response = "{\"status\": \"ready\"}";
exchange.getResponseHeaders().set("Content-Type", "application/json");
exchange.sendResponseHeaders(200, response.length());
try (OutputStream os = exchange.getResponseBody()) {
os.write(response.getBytes());
}
}
}
/**
* Metrics Handler
*/
private static class MetricsHandler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
String response = "# OpenFaaS Java Runtime Metrics\n" +
"http_requests_total 100\n" +
"http_requests_duration_seconds 0.5";
exchange.getResponseHeaders().set("Content-Type", "text/plain");
exchange.sendResponseHeaders(200, response.length());
try (OutputStream os = exchange.getResponseBody()) {
os.write(response.getBytes());
}
}
}
/**
* Function Request Handler
*/
private static class FunctionHandler implements HttpHandler {
private final OpenFaaSFunction function;
public FunctionHandler(OpenFaaSFunction function) {
this.function = function;
}
@Override
public void handle(HttpExchange exchange) throws IOException {
long startTime = System.currentTimeMillis();
try {
// Extract context from headers
Map<String, String> context = extractContext(exchange);
// Read request body
byte[] requestBody = readRequestBody(exchange);
// Execute function
byte[] responseBody = function.handle(requestBody, context);
// Send response
sendResponse(exchange, responseBody, 200, "text/plain");
long duration = System.currentTimeMillis() - startTime;
System.out.printf("ā
Function executed in %dms%n", duration);
} catch (Exception e) {
System.err.println("ā Function execution failed: " + e.getMessage());
sendErrorResponse(exchange, e);
}
}
private Map<String, String> extractContext(HttpExchange exchange) {
Map<String, String> context = new HashMap<>();
// OpenFaaS specific headers
context.put("Http_Method", exchange.getRequestMethod());
context.put("Http_Query", exchange.getRequestURI().getQuery());
context.put("Http_Path", exchange.getRequestURI().getPath());
// Standard HTTP headers
exchange.getRequestHeaders().forEach((key, values) -> {
if (!values.isEmpty()) {
context.put(key, values.get(0));
}
});
return context;
}
private byte[] readRequestBody(HttpExchange exchange) throws IOException {
try (InputStream is = exchange.getRequestBody();
ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
byte[] data = new byte[1024];
int nRead;
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
return buffer.toByteArray();
}
}
private void sendResponse(HttpExchange exchange, byte[] body,
int statusCode, String contentType) throws IOException {
exchange.getResponseHeaders().set("Content-Type", contentType);
exchange.sendResponseHeaders(statusCode, body.length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(body);
}
}
private void sendErrorResponse(HttpExchange exchange, Exception e) throws IOException {
String errorResponse = "{\"error\": \"" + e.getMessage() + "\"}";
exchange.getResponseHeaders().set("Content-Type", "application/json");
exchange.sendResponseHeaders(500, errorResponse.length());
try (OutputStream os = exchange.getResponseBody()) {
os.write(errorResponse.getBytes());
}
}
}
}
/**
* Sample Functions Library
*/
public static class SampleFunctions {
/**
* Echo Function - Returns input as output
*/
public static OpenFaaSFunction echoFunction() {
return (input, context) -> {
String inputStr = new String(input, StandardCharsets.UTF_8);
System.out.println("Echo function received: " + inputStr);
String response = String.format("{\n" +
" \"echo\": \"%s\",\n" +
" \"timestamp\": \"%s\",\n" +
" \"method\": \"%s\"\n" +
"}", inputStr, new Date(), context.get("Http_Method"));
return response.getBytes(StandardCharsets.UTF_8);
};
}
/**
* JSON Processing Function
*/
public static OpenFaaSFunction jsonProcessor() {
return (input, context) -> {
try {
String jsonInput = new String(input, StandardCharsets.UTF_8);
System.out.println("JSON Processor received: " + jsonInput);
// Simple JSON transformation
String transformed = "{\"processed\": true, \"original_length\": " +
jsonInput.length() + ", \"timestamp\": \"" +
new Date() + "\"}";
return transformed.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
String error = "{\"error\": \"Invalid JSON: " + e.getMessage() + "\"}";
return error.getBytes(StandardCharsets.UTF_8);
}
};
}
/**
* Image Processing Function (Base64)
*/
public static OpenFaaSFunction imageProcessor() {
return (input, context) -> {
try {
String base64Image = new String(input, StandardCharsets.UTF_8);
// Simulate image processing
int originalSize = base64Image.length();
String processedImage = base64Image.substring(0, Math.min(100, originalSize)) + "...";
String response = String.format("{\n" +
" \"processed\": true,\n" +
" \"original_size\": %d,\n" +
" \"processing_time\": \"%dms\",\n" +
" \"preview\": \"%s\"\n" +
"}", originalSize, System.currentTimeMillis() % 1000, processedImage);
return response.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
String error = "{\"error\": \"Image processing failed: " + e.getMessage() + "\"}";
return error.getBytes(StandardCharsets.UTF_8);
}
};
}
/**
* Weather API Function
*/
public static OpenFaaSFunction weatherFunction() {
return (input, context) -> {
String query = context.get("Http_Query");
String city = extractParameter(query, "city");
if (city == null) {
city = "London"; // default
}
// Simulate weather data
Map<String, Object> weather = new HashMap<>();
weather.put("city", city);
weather.put("temperature", 20 + (Math.random() * 10));
weather.put("humidity", 60 + (Math.random() * 20));
weather.put("conditions", "Sunny");
weather.put("timestamp", new Date());
String response = "{\"weather\": " + toJson(weather) + "}";
return response.getBytes(StandardCharsets.UTF_8);
};
}
/**
* Machine Learning Inference Function
*/
public static OpenFaaSFunction mlInference() {
return (input, context) -> {
try {
String inputData = new String(input, StandardCharsets.UTF_8);
// Simulate ML inference
Map<String, Object> result = new HashMap<>();
result.put("prediction", Math.random() > 0.5 ? "SPAM" : "HAM");
result.put("confidence", Math.round(Math.random() * 10000) / 100.0);
result.put("model_version", "v1.2.3");
result.put("inference_time", System.currentTimeMillis() % 100 + "ms");
String response = toJson(result);
return response.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
String error = "{\"error\": \"Inference failed: " + e.getMessage() + "\"}";
return error.getBytes(StandardCharsets.UTF_8);
}
};
}
private static String extractParameter(String query, String paramName) {
if (query == null) return null;
String[] pairs = query.split("&");
for (String pair : pairs) {
String[] keyValue = pair.split("=");
if (keyValue.length == 2 && keyValue[0].equals(paramName)) {
return keyValue[1];
}
}
return null;
}
private static String toJson(Map<String, Object> map) {
StringBuilder sb = new StringBuilder("{");
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (sb.length() > 1) sb.append(",");
sb.append("\"").append(entry.getKey()).append("\":");
if (entry.getValue() instanceof String) {
sb.append("\"").append(entry.getValue()).append("\"");
} else {
sb.append(entry.getValue());
}
}
sb.append("}");
return sb.toString();
}
}
/**
* Spring Boot Integration for OpenFaaS
*/
@RestController
@RequestMapping("/function")
public static class SpringOpenFaaSController {
private final Map<String, OpenFaaSFunction> functions = new ConcurrentHashMap<>();
@PostConstruct
public void init() {
// Register sample functions
functions.put("echo", SampleFunctions.echoFunction());
functions.put("json-process", SampleFunctions.jsonProcessor());
functions.put("weather", SampleFunctions.weatherFunction());
functions.put("ml-inference", SampleFunctions.mlInference());
System.out.println("ā
Spring Boot OpenFaaS Controller initialized");
}
@PostMapping("/{functionName}")
public ResponseEntity<byte[]> handleFunction(
@PathVariable String functionName,
@RequestBody(required = false) byte[] body,
HttpServletRequest request) {
OpenFaaSFunction function = functions.get(functionName);
if (function == null) {
return ResponseEntity.notFound().build();
}
try {
// Extract context from HTTP request
Map<String, String> context = extractContext(request);
// Execute function
byte[] result = function.handle(body != null ? body : new byte[0], context);
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(result);
} catch (Exception e) {
String error = "{\"error\": \"" + e.getMessage() + "\"}";
return ResponseEntity.status(500)
.contentType(MediaType.APPLICATION_JSON)
.body(error.getBytes(StandardCharsets.UTF_8));
}
}
private Map<String, String> extractContext(HttpServletRequest request) {
Map<String, String> context = new HashMap<>();
// HTTP method and query
context.put("Http_Method", request.getMethod());
context.put("Http_Query", request.getQueryString());
context.put("Http_Path", request.getRequestURI());
// Headers
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
context.put(headerName, request.getHeader(headerName));
}
return context;
}
@GetMapping("/health")
public ResponseEntity<Map<String, String>> health() {
return ResponseEntity.ok(Map.of("status", "healthy"));
}
}
/**
* Function Template Builder
*/
public static class FunctionTemplate {
private String name;
private String handler;
private String language = "java17";
private Map<String, String> environment = new HashMap<>();
private Map<String, String> labels = new HashMap<>();
private List<String> annotations = new ArrayList<>();
public FunctionTemplate(String name) {
this.name = name;
}
public FunctionTemplate withHandler(String handler) {
this.handler = handler;
return this;
}
public FunctionTemplate withEnvironment(String key, String value) {
this.environment.put(key, value);
return this;
}
public FunctionTemplate withLabel(String key, String value) {
this.labels.put(key, value);
return this;
}
public FunctionTemplate withAnnotation(String annotation) {
this.annotations.add(annotation);
return this;
}
public String buildStackYaml() {
return String.format("""
version: 1.0
provider:
name: openfaas
gateway: http://127.0.0.1:8080
functions:
%s:
lang: %s
handler: ./%s
environment:
%s
labels:
%s
annotations:
%s
""", name, language, handler,
formatMap(environment),
formatMap(labels),
String.join("\\n ", annotations));
}
public String buildDockerfile() {
return String.format("""
FROM openfaas/classic-watchdog:0.2.1 as watchdog
FROM maven:3.8.4-openjdk-17 as build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests
FROM openjdk:17-jre-slim
COPY --from=watchdog /fwatchdog /usr/bin/fwatchdog
RUN chmod +x /usr/bin/fwatchdog
WORKDIR /home/app
COPY --from=build /app/target/*.jar app.jar
ENV upstream_url="http://127.0.0.1:8082"
ENV mode="http"
ENV CLASSPATH="/home/app/app.jar"
CMD [ "fwatchdog" ]
""");
}
private String formatMap(Map<String, String> map) {
return map.entrySet().stream()
.map(entry -> String.format("%s: %s", entry.getKey(), entry.getValue()))
.reduce((a, b) -> a + "\\n " + b)
.orElse("");
}
}
/**
* Demo and Usage Examples
*/
public static void main(String[] args) throws IOException, InterruptedException {
System.out.println("š OpenFaaS Java Template Demo");
System.out.println("==============================\n");
// Create OpenFaaS runtime
OpenFaaSRuntime runtime = new OpenFaaSRuntime(8082);
// Register functions
runtime.registerFunction("/echo", SampleFunctions.echoFunction());
runtime.registerFunction("/json-process", SampleFunctions.jsonProcessor());
runtime.registerFunction("/weather", SampleFunctions.weatherFunction());
runtime.registerFunction("/ml-inference", SampleFunctions.mlInference());
runtime.registerFunction("/image-process", SampleFunctions.imageProcessor());
// Start the runtime
runtime.start();
// Generate template files
generateTemplateFiles();
// Keep running
System.out.println("\nā³ OpenFaaS Runtime is running... Press Ctrl+C to stop");
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
runtime.stop();
}));
// Keep the main thread alive
Thread.sleep(300000); // 5 minutes
}
private static void generateTemplateFiles() {
// Generate stack.yaml
FunctionTemplate template = new FunctionTemplate("java-function")
.withHandler("my-function")
.withEnvironment("JAVA_OPTS", "-Xmx512m")
.withEnvironment("LOG_LEVEL", "INFO")
.withLabel("team", "backend")
.withAnnotation("prometheus.io.scrape", "true");
try {
Files.writeString(Paths.get("stack.yml"), template.buildStackYaml());
Files.writeString(Paths.get("Dockerfile"), template.buildDockerfile());
System.out.println("ā
Generated template files: stack.yml, Dockerfile");
} catch (IOException e) {
System.err.println("ā Failed to generate template files: " + e.getMessage());
}
}
}
Maven Dependencies
<!-- pom.xml --> <dependencies> <!-- OpenFaaS Java Function SDK --> <dependency> <groupId>com.openfaas</groupId> <artifactId>model</artifactId> <version>1.0.0</version> </dependency> <!-- HTTP Server (for standalone runtime) --> <dependency> <groupId>com.sun.net.httpserver</groupId> <artifactId>http</artifactId> <version>20070405</version> </dependency> <!-- Spring Boot (optional) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.7.0</version> </dependency> <!-- JSON Processing --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.14.2</version> </dependency> </dependencies>
Dockerfile Template
FROM openfaas/classic-watchdog:0.2.1 as watchdog FROM maven:3.8.4-openjdk-17 as build WORKDIR /app COPY pom.xml . COPY src ./src RUN mvn clean package -DskipTests FROM openjdk:17-jre-slim COPY --from=watchdog /fwatchdog /usr/bin/fwatchdog RUN chmod +x /usr/bin/fwatchdog WORKDIR /home/app COPY --from=build /app/target/*.jar app.jar ENV upstream_url="http://127.0.0.1:8082" ENV mode="http" ENV CLASSPATH="/home/app/app.jar" CMD ["fwatchdog"]
Deployment Commands
# Build the function
faas-cli build -f stack.yml
# Deploy to OpenFaaS
faas-cli deploy -f stack.yml
# Test the function
echo '{"message": "Hello OpenFaaS"}' | faas-cli invoke java-function
# Monitor functions
faas-cli list
faas-cli logs java-function
This OpenFaaS Java Template provides:
- Complete runtime environment for Java functions
- Multiple function examples (echo, JSON processing, ML inference, etc.)
- Spring Boot integration for traditional web apps
- Template generation for easy deployment
- Health checks and metrics for production readiness
- Context handling with request metadata
- Error handling and logging
- Dockerfile templates for containerization
The template supports both standalone deployment and integration with existing Spring Boot applications, making it easy to build and deploy serverless functions in Java.
Pyroscope Profiling in Java
Explains how to use Pyroscope for continuous profiling in Java applications, helping developers analyze CPU and memory usage patterns to improve performance and identify bottlenecks.
https://macronepal.com/blog/pyroscope-profiling-in-java/
OpenTelemetry Metrics in Java: Comprehensive Guide
Provides a complete guide to collecting and exporting metrics in Java using OpenTelemetry, including counters, histograms, gauges, and integration with monitoring tools. (MACRO NEPAL)
https://macronepal.com/blog/opentelemetry-metrics-in-java-comprehensive-guide/
OTLP Exporter in Java: Complete Guide for OpenTelemetry
Explains how to configure OTLP exporters in Java to send telemetry data such as traces, metrics, and logs to monitoring systems using HTTP or gRPC protocols. (MACRO NEPAL)
https://macronepal.com/blog/otlp-exporter-in-java-complete-guide-for-opentelemetry/
Thanos Integration in Java: Global View of Metrics
Explains how to integrate Thanos with Java monitoring systems to create a scalable global metrics view across multiple Prometheus instances.
https://macronepal.com/blog/thanos-integration-in-java-global-view-of-metrics
Time Series with InfluxDB in Java: Complete Guide (Version 2)
Explains how to manage time-series data using InfluxDB in Java applications, including storing, querying, and analyzing metrics data.
https://macronepal.com/blog/time-series-with-influxdb-in-java-complete-guide-2
Time Series with InfluxDB in Java: Complete Guide
Provides an overview of integrating InfluxDB with Java for time-series data handling, including monitoring applications and managing performance metrics.
https://macronepal.com/blog/time-series-with-influxdb-in-java-complete-guide
Implementing Prometheus Remote Write in Java (Version 2)
Explains how to configure Java applications to send metrics data to Prometheus-compatible systems using the remote write feature for scalable monitoring.
https://macronepal.com/blog/implementing-prometheus-remote-write-in-java-a-complete-guide-2
Implementing Prometheus Remote Write in Java: Complete Guide
Provides instructions for sending metrics from Java services to Prometheus servers, enabling centralized monitoring and real-time analytics.
https://macronepal.com/blog/implementing-prometheus-remote-write-in-java-a-complete-guide
Building a TileServer GL in Java: Vector and Raster Tile Server
Explains how to build a TileServer GL in Java for serving vector and raster map tiles, useful for geographic visualization and mapping applications.
https://macronepal.com/blog/building-a-tileserver-gl-in-java-vector-and-raster-tile-server
Indoor Mapping in Java
Explains how to create indoor mapping systems in Java, including navigation inside buildings, spatial data handling, and visualization techniques.