Deploying a MAMS Service
The delivery service can run as a Java process or in a container. Download the complete project; it includes a small HTTP client, a Dockerfile and a Compose configuration. Use Java 17 and Maven for a local build, or Docker with Compose for the container example.
Run the compiled application
From the extracted delivery-service directory, compile the agents and collect their runtime dependencies:
mvn clean package org.apache.maven.plugins:maven-dependency-plugin:3.7.0:copy-dependencies -DincludeScope=runtime
java -cp 'target/classes:target/dependency/*' Main
On Windows, separate the classpath entries with ; instead of :. Keep the wildcard inside the quoted classpath so Java expands it.
Main starts the HTTP server on port 9000 and creates the courier agents in the same JVM. Its public collection is /main/deliveries. The courier names are used in messages in this example; changing those names requires changing the corresponding message destinations.
In a second terminal, in the same project directory, run:
java -cp 'target/classes:target/dependency/*' Client http://localhost:9000
The client starts its own MAMS environment on port 9001, requests the delivery collection and prints HTTP 200: delivery service reached followed by the response. Ports 9000 and 9001 must be free. Stop the service with Ctrl+C when finished.
Build a container
The supplied Dockerfile builds the audited MAMS source commit before building the application. The source pin makes the container build reproducible against the implementation described here; the application dependencies use MAMS 2.4.1.
FROM maven:3.9.14-eclipse-temurin-17 AS build
ARG MAMS_REF=280367ee634fdcf6a37a0f1c594eb97a2c4476c2
RUN apt-get update -qq && apt-get install -y --no-install-recommends git \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /build
RUN git clone https://gitlab.com/mams-ucd/mams-cartago.git mams \
&& git -C mams checkout --detach "$MAMS_REF" \
&& mvn -B -f mams/pom.xml -pl mams-astra-javatypes -am -DskipTests install
WORKDIR /build/app
COPY pom.xml ./
COPY src/ src/
RUN mvn -B -DskipTests clean package \
org.apache.maven.plugins:maven-dependency-plugin:3.7.0:copy-dependencies \
-DincludeScope=runtime
FROM eclipse-temurin:17-jre
WORKDIR /app
COPY --from=build /build/app/target/classes/ /app/classes/
COPY --from=build /build/app/target/dependency/ /app/lib/
USER 10001:10001
EXPOSE 9000
ENTRYPOINT ["java", "-cp", "/app/classes:/app/lib/*"]
CMD ["Main"]
The build stage contains Maven and the compiler. The final image contains Java 17, the compiled application and its runtime libraries, and runs as a non-root user. See Docker’s multi-stage build documentation.
Run the service and client with Compose
The Compose configuration puts the service and client on the same network:
services:
delivery:
build: .
image: mams-delivery-guide:local
ports:
- "127.0.0.1:9000:9000"
client:
image: mams-delivery-guide:local
command: ["Client", "http://delivery:9000"]
profiles: ["tools"]
Start the service:
docker compose up --build -d delivery
curl -i http://localhost:9000/main/deliveries
Wait for the request to return 200 OK before running the client. Building an image or starting a container does not mean the HTTP server is ready.
docker compose run --rm client
The client uses http://delivery:9000. Compose resolves delivery to the service container, and communication between containers uses the container port. A browser or command on the host uses http://localhost:9000, through the published port. Inside a container, localhost refers to that container. See Compose networking.
The mapping 127.0.0.1:9000:9000 makes this demonstration available on the host’s loopback interface. If you change it to 127.0.0.1:9002:9000, host requests use port 9002; the Compose client still uses delivery:9000.
Inspect service output and remove the containers when finished:
docker compose logs -f delivery
docker compose down
Resource addresses and lifecycle
The current server constructs absolute resource URIs using the JVM host address. A URI in a Location header or a resource link can therefore contain a container address that is reachable within its network but inaccessible from the host. Port mapping does not rewrite these response values. For a client using a known service endpoint, preserve the resource path and resolve it against that endpoint when necessary. The collection client demonstrates this for local development; its localhost substitution must be adapted for a container or another host.
Set up MAMS once per JVM and let agents share that environment. A separately launched client has its own environment and needs its own available port. This example keeps delivery state in memory: restarting the process loses its resources and history. An active request waits up to 30 seconds for an agent decision by default and returns a JSON 504 response if no decision arrives; see resource management.
The verification checks exercise the direct Java launch and HTTP client. The container configuration additionally requires a working Docker engine; building and running the image is a separate deployment check.