Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .github/workflows/containerize_fleet_analysis_backend.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# /********************************************************************************
# * Copyright (c) 2026 Contributors to the Eclipse Foundation
# *
# * See the NOTICE file(s) distributed with this work for additional
# * information regarding copyright ownership.
# *
# * This program and the accompanying materials are made available under the
# * terms of the Apache License 2.0 which is available at
# * https://www.apache.org/licenses/LICENSE-2.0
# *
# * SPDX-License-Identifier: Apache-2.0
# ********************************************************************************/
name: Containerize Fleet Analysis Backend and Push to Container Registry

on:
push:
branches:
- main
paths:
- "components/backend-fleet-analysis-java/**"
- ".github/workflows/containerize_fleet_analysis_backend.yaml"
workflow_dispatch:

permissions:
contents: read
packages: write

jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract image metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}/fleet-analysis-backend

- name: Build and push
uses: docker/build-push-action@v5
with:
context: components/backend-fleet-analysis-java
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ docker compose -f ./fms-blueprint-compose.yaml -f ./fms-blueprint-compose-zenoh.

This will pull (or build if necessary) the container images and create and start all components.

The stack includes the Jakarta EE fleet analysis backend and exposes it on `http://127.0.0.1:8082/fleet-analysis/api`.

Once all services have been started, the current vehicle status can be viewed on a [Grafana dashboard](http://127.0.0.1:3000),
using *admin*/*admin* as username and password for logging in.

Expand Down Expand Up @@ -114,6 +116,8 @@ setup manually.

Additional information can be found in the components' corresponding subfolders.

The fleet analysis backend component lives in `components/backend-fleet-analysis-java`.

# Contributing

We are looking forward to your ideas and PRs. Each PRs triggers a GitHub action which checks the formating, performs
Expand Down
3 changes: 3 additions & 0 deletions components/backend-fleet-analysis-java/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
target
.idea
*.iml
34 changes: 34 additions & 0 deletions components/backend-fleet-analysis-java/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# /********************************************************************************
# * Copyright (c) 2026 Contributors to the Eclipse Foundation
# *
# * See the NOTICE file(s) distributed with this work for additional
# * information regarding copyright ownership.
# *
# * This program and the accompanying materials are made available under the
# * terms of the Apache License 2.0 which is available at
# * https://www.apache.org/licenses/LICENSE-2.0
# *
# * SPDX-License-Identifier: Apache-2.0
# ********************************************************************************/

FROM maven:3.9.6-eclipse-temurin-21 AS build

WORKDIR /workspace
COPY pom.xml .
COPY src ./src
RUN mvn -q -DskipTests package

FROM eclipse-temurin:21-jre

ARG PAYARA_MICRO_VERSION=6.2024.2
WORKDIR /opt/payara
ADD https://repo1.maven.org/maven2/fish/payara/extras/payara-micro/${PAYARA_MICRO_VERSION}/payara-micro-${PAYARA_MICRO_VERSION}.jar /opt/payara/payara-micro.jar

COPY --from=build /workspace/target/*.war /opt/payara/fleet-analysis-backend.war

ENV TMPDIR=/tmp

RUN mkdir -p /tmp && chmod 1777 /tmp

EXPOSE 8080
ENTRYPOINT ["java","-Djava.io.tmpdir=/tmp","-jar","/opt/payara/payara-micro.jar","--deploy","/opt/payara/fleet-analysis-backend.war","--contextRoot","/fleet-analysis"]
157 changes: 157 additions & 0 deletions components/backend-fleet-analysis-java/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# Fleet Analysis Backend (Jakarta EE 11)

This service provides a small Jakarta EE 11 backend to analyze Fleet Management telemetry and
return summary statistics for dashboards or alerts.

## Responsibilities

- Accepts fleet telemetry snapshots as JSON.
- Returns computed summary metrics (fleet size, average speed, battery SOC range, braking count).
- Writes header/snapshot telemetry to InfluxDB when requested.
- Reads InfluxDB telemetry and writes fleet statistics periodically.

## Build

```bash
mvn package
```

## Run (example with Payara Micro)

1. Download [Payara Micro 6](https://www.payara.fish/downloads/payara-platform-community-edition/).
2. Deploy the WAR:

```bash
java -jar payara-micro.jar --deploy target/fleet-analysis-backend.war --contextRoot /fleet-analysis
```

The API will be available at `http://localhost:8080/fleet-analysis/api`.

## Build Docker image (without Docker Compose)

From the repository root:

```bash
docker build -t fleet-analysis-backend:local components/backend-fleet-analysis-java
```

Run it manually (example):

```bash
docker run --rm -p 8082:8080 --name fleet-analysis-backend \
-e INFLUXDB_TOKEN_FILE=/tmp/fms-demo.token \
-e INFLUXDB_STATS_INTERVAL_SECONDS=30 \
-v /path/to/fms-demo.token:/tmp/fms-demo.token:ro \
fleet-analysis-backend:local
```

## Accessing output

Variant 1: Docker container logs

```bash
docker logs -f fleet-analysis-backend
```

Variant 2: API

```bash
curl -s http://localhost:8082/fleet-analysis/api/analysis/stats | jq
```

## API

### `POST /api/analysis/summary`

Request body (example):

```json
[
{
"vehicleId": "bike-001",
"speedKph": 42.3,
"batterySoc": 0.78,
"brakeActive": false,
"updatedAt": "2024-06-10T10:15:30Z"
},
{
"vehicleId": "bike-002",
"speedKph": 12.4,
"batterySoc": 0.52,
"brakeActive": true,
"updatedAt": "2024-06-10T10:15:32Z"
}
]
```

Response:

```json
{
"vehicleCount": 2,
"averageSpeedKph": 27.35,
"minBatterySoc": 0.52,
"maxBatterySoc": 0.78,
"brakingVehicles": 1
}
```

### `POST /api/telemetry/ingest`

Writes header and/or snapshot measurements into InfluxDB. Configure the client using:

- `INFLUXDB_URI` (default: `http://influxdb:8086`)
- `INFLUXDB_ORG` (default: `sdv`)
- `INFLUXDB_BUCKET` (default: `demo`)
- `INFLUXDB_TOKEN` or `INFLUXDB_TOKEN_FILE`

Request body (example):

```json
{
"vin": "truck-001",
"trigger": "periodic",
"createdDateTime": 1737940602000,
"header": {
"hrTotalVehicleDistance": 12345.6,
"grossCombinationVehicleWeight": 18100.2,
"totalEngineHours": 82.5,
"engineTotalFuelUsed": 221.9,
"driver1Id": "driver-01",
"driver1IdCardIssuer": "fleet"
},
"snapshot": {
"latitude": 37.7749,
"longitude": -122.4194,
"speed": 54.2,
"positionDateTime": 1737940602,
"wheelBasedSpeed": 53.7,
"fuelLevel1": 0.42,
"parkingBrakeSwitch": false
}
}
```

### Fleet stats (InfluxDB)

The service periodically computes fleet statistics from the `header`/`snapshot` measurements and
writes them into a `fleet_stats` measurement.

Default schedule: every 30 seconds (configure with `INFLUXDB_STATS_INTERVAL_SECONDS` as an env var
or Java system property).
Initial delay before the first stats run defaults to 10 seconds (configure with
`INFLUXDB_STATS_INITIAL_DELAY_SECONDS`).

**Measurement: `fleet_stats`**

Fields:

- `vehicleCount` (unique `vin` across all time)
- `headerCount` (total number of header points)
- `snapshotCount` (total number of snapshot points)
- `totalCount` (header + snapshot points)
- `generatedAt` (ms since Unix epoch)

### `GET /api/analysis/stats`

Returns the latest stats snapshot (and triggers a refresh if none exist yet).
29 changes: 29 additions & 0 deletions components/backend-fleet-analysis-java/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<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>

<groupId>org.eclipse.sdv</groupId>
<artifactId>fleet-analysis-backend</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>war</packaging>

<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId>
<version>10.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.influxdb</groupId>
<artifactId>influxdb-client-java</artifactId>
<version>7.0.0</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// ********************************************************************************
// * Copyright (c) 2026 Contributors to the Eclipse Foundation
// *
// * See the NOTICE file(s) distributed with this work for additional
// * information regarding copyright ownership.
// *
// * This program and the accompanying materials are made available under the
// * terms of the Apache License 2.0 which is available at
// * https://www.apache.org/licenses/LICENSE-2.0
// *
// * SPDX-License-Identifier: Apache-2.0
// ********************************************************************************

package org.eclipse.sdv.fleet.analysis;

import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;

@ApplicationPath("/api")
public class AnalysisApplication extends Application {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// ********************************************************************************
// * Copyright (c) 2026 Contributors to the Eclipse Foundation
// *
// * See the NOTICE file(s) distributed with this work for additional
// * information regarding copyright ownership.
// *
// * This program and the accompanying materials are made available under the
// * terms of the Apache License 2.0 which is available at
// * https://www.apache.org/licenses/LICENSE-2.0
// *
// * SPDX-License-Identifier: Apache-2.0
// ********************************************************************************

package org.eclipse.sdv.fleet.analysis;

import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

import java.util.List;

@Path("/analysis")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class FleetAnalysisResource {

@POST
@Path("/summary")
public FleetAnalysisSummary summarize(List<FleetTelemetry> telemetry) {
FleetAnalysisSummary summary = new FleetAnalysisSummary();
if (telemetry == null || telemetry.isEmpty()) {
summary.setVehicleCount(0);
summary.setAverageSpeedKph(0.0);
summary.setMinBatterySoc(0.0);
summary.setMaxBatterySoc(0.0);
summary.setBrakingVehicles(0);
return summary;
}

summary.setVehicleCount(telemetry.size());
summary.setAverageSpeedKph(
telemetry.stream().mapToDouble(FleetTelemetry::getSpeedKph).average().orElse(0.0));
summary.setMinBatterySoc(
telemetry.stream().mapToDouble(FleetTelemetry::getBatterySoc).min().orElse(0.0));
summary.setMaxBatterySoc(
telemetry.stream().mapToDouble(FleetTelemetry::getBatterySoc).max().orElse(0.0));
summary.setBrakingVehicles(telemetry.stream().filter(FleetTelemetry::isBrakeActive).count());

return summary;
}
}
Loading
Loading