You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by da...@apache.org on 2023/02/22 16:57:21 UTC
[ofbiz-framework] branch experimental-docker created (now 0ef7f9c52a)
This is an automated email from the ASF dual-hosted git repository.
danwatford pushed a change to branch experimental-docker
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
at 0ef7f9c52a Implemented: Build OFBiz as a docker container image (OFBIZ-12757)
This branch includes the following new commits:
new 0ef7f9c52a Implemented: Build OFBiz as a docker container image (OFBIZ-12757)
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[ofbiz-framework] 01/01: Implemented: Build OFBiz as a docker container image (OFBIZ-12757)
Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
danwatford pushed a commit to branch experimental-docker
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
commit 0ef7f9c52a473ab561f7ccad57fa0a340351d60b
Author: Daniel Watford <da...@watfordconsulting.com>
AuthorDate: Wed Feb 22 16:54:16 2023 +0000
Implemented: Build OFBiz as a docker container image (OFBIZ-12757)
Added a Dockerfile to define a build based on currently checked-out
sources. Changes include an initialisation script for launching an OFBiz
container which configures OFBiz settings for the current environment.
---
.dockerignore | 7 ++
DOCKER.md | 157 +++++++++++++++++++++++
Dockerfile | 79 ++++++++++++
build.gradle | 8 ++
docker/docker-entrypoint.sh | 260 +++++++++++++++++++++++++++++++++++++++
docker/send_ofbiz_stop_signal.sh | 39 ++++++
6 files changed, 550 insertions(+)
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000000..86fb0090f5
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,7 @@
+Dockerfile
+.gradle/
+/bin/
+/build/
+/runtime/
+/themes/common-theme/webapp/common/js/node_modules/
+/themes/common-theme/webapp/common-theme/js/node_modules/
diff --git a/DOCKER.md b/DOCKER.md
new file mode 100644
index 0000000000..2af492dac8
--- /dev/null
+++ b/DOCKER.md
@@ -0,0 +1,157 @@
+# Building and running OFBiz using Docker
+
+OFBiz includes a Dockerfile which can be used to build a container image for running OFBiz.
+The container image is built based on the sources already available in the build
+content, i.e. it only uses sources that you have already downloaded.
+
+If you want to include any plugins in your container image, you must download those
+plugins before running the build. (See the plugin documentation in README.adoc).
+
+## Quickstart
+Follow these instructions to qet started building and running OFBiz using Docker.
+
+### Build the OFBiz container image
+
+From the sources directory (i.e. the directory containing Docker.md), run
+```shell script
+DOCKER_BUILDKIT=1 docker build --tag ofbiz-docker .
+```
+
+### Run the OFBiz container
+
+Run the following command:
+```shell script
+docker run -it -e OFBIZ_DATA_LOAD=demo --name ofbiz-docker -p 8443:8443 ofbiz-docker
+```
+
+This will start an instance of the ofbiz-docker container, publish port 8443 to localhost,
+load the OFBiz demo data, and then run the OFBiz server.
+
+Once start up completes, you can access OFBIZ at http://localhost:8443/partymgr
+
+## Other container building options
+
+The OFBiz `Dockerfile` defines a mult-stage build. The default container image produced by the build is named `runtime`
+and consists of an unintialized OFBiz installation.
+
+During the first run of a container based on this image, seed or demo data can be loaded, and an admin user created.
+
+The runtime container is the default target of a docker build and can be created with commands similar to:
+```shell script
+DOCKER_BUILDKIT=1 docker build --tag ofbiz-docker .
+```
+OR
+```shell script
+DOCKER_BUILDKIT=1 docker build --target runtime --tag ofbiz-docker .
+```
+
+The Dockerfile also defines another stage, `demo`, which produces a container image with demonstration data already
+loaded. This container image may be useful in cases where containers are frequency run and destroyed and the time
+taken to load demo data is becoming noticeable.
+
+To build a container image pre-loaded with demo data, run:
+```shell script
+DOCKER_BUILDKIT=1 docker build --target runtime --tag ofbiz-docker .
+```
+
+## Container runtime options
+
+The container's behaviour at runtime is controlled via environment variables, 'hook' scripts and XML entity import
+files. These items will only be applied to a container during its first run. Flags stored in
+`/ofbiz/runtime/container_state` will prevent the repeated application of these items during subsequent starts of the
+container.
+
+Use of environment variables, hook scripts and XML entity import files are manged by the docker-entrypoint.sh script.
+
+### Environment variables
+Environment variables are used in `docker-entrypoint.sh` to control configuration options for the OFBiz container.
+
+|Environment variable | Default value | Description |
+|---|---|---|
+|OFBIZ_SKIP_INIT | *empty* | Any non-empty value will cause this script to skip any initialisation steps. |
+|OFBIZ_ADMIN_USER | admin | Sets the username of the OFBIZ admin user. |
+|OFBIZ_ADMIN_PASSWORD | ofbiz | Sets the password of the OFBIZ admin user. |
+|OFBIZ_DATA_LOAD | seed | Determine what type of data loading is required. *none*: No data loading is perfomed. *seed*: Seed data is loaded. *demo*: Demo data is loaded. |
+|OFBIZ_HOST | localhost | Specify the hostname used to access OFBiz. |
+|OFBIZ_CONTENT_URL_PREFIX | https://${OFBIZ_HOST} | Used to set the content.url.prefix.secure and content.url.prefix.standard properties in `framework/webapp/config/url.properties`. |
+|OFBIZ_ENABLE_AJP_PORT | *empty* | Enable the AJP (Apache JServe Protocol) port to allow communication with OFBiz via a reverse proxy. Enabled when this environment variable contains a non-empty value. |
+
+### Hooks
+At various steps of initialisation, the `docker-entrypoint.sh` script will check for
+'hook' scripts in various directories.
+
+Users of the container can mount files into these directories and influence the OFBiz startup process.
+
+Only script files with filename extension `.sh` will be processed. If the file is executable, it will
+be executed, otherwise it will be sourced.
+
+|Directory | Step |
+|---|---|
+| `/docker-entrypoint-before-config-applied.d` | Scripts processed before configuration, such as modifications to property files, are applied. |
+| `/docker-entrypoint-after-config-applied.d` | Scripts processed after configuration modifications have been applied. |
+| `/docker-entrypoint-before-data-load.d` | Scripts processed before data loading is executed. Could be used to apply modifications to data files.|
+| `/docker-entrypoint-after-data-load.d` | Scripts processed after data loading is executed. |
+
+### Data files
+During the data loading step - but after either seed or demo data has been loaded - directory
+`/docker-entrypoint-additional-data.d` will be checked to see if any files are present.
+
+If files are present then the load-data functionality in OFBiz will be executed, specifying the
+`/docker-entrypoint-additional-data.d` directory as a data source. Any `.xml` files in this
+directory will be treated as a data source and will be imported by the entity engine.
+
+This functionality can be used to pre-load OFBiz with user-specific data, such as
+a chart of accounts.
+
+## Examples of running the OFBiz container
+
+```
+docker run -it -p 8443:8443 ofbiz-docker
+```
+Launch the OFBiz container, load the seed data, create the administrator user with
+name `admin` and password `ofbiz`, listen on port 8443 for connections to `localhost`.
+
+Users can access OFBiz at https://localhost:8443/partymgr
+
+The docker container will remain attached the terminal. Interrupting the container,
+i.e. pressing Ctrl-C, will trigger a graceful shutdown of the container.
+
+```
+docker run -it -e OFBIZ_DATA_LOAD=demo -p 8443:8443 ofbiz-docker
+```
+Launch the OFBiz container, load the demo data, listen on port 8443 for connections to `localhost`.
+
+The demo data includes the administrator user with name `admin` and password `ofbiz`.
+
+```
+docker run -it -e OFBIZ_DATA_LOAD=seed -e OFBIZ_ADMIN_USER=localadmin -e OFBIZ_ADMIN_PASSWORD=TTTTT -p 8443:8443 ofbiz-docker
+```
+Launch the OFBiz container, load the seed data, create the administrator user with
+name `localadmin` and password `TTTTT`, listen on port 8443 for connections to `localhost`.
+
+```
+docker run -it -v 'C:\ofbiz-framework\add-data':/docker-entrypoint-additional-data.d -p 8443:8443 ofbiz-docker
+```
+Example of running on Windows.
+
+Launches the container with default seed data and administrator user.
+
+After data is loaded, any `.xml` files in directory `C:\ofbiz-framework\add-data` are imported by
+the OFBiz entity engine.
+
+```
+docker run -it -p 8443:8443 ofbiz-docker
+```
+Launch the OFBiz container, load the seed data, create the administrator user with
+name `admin` and password `ofbiz`, listen on port 8443 for connections to `localhost`.
+
+Users can access OFBiz at https://localhost:8443/partymgr
+
+The docker container will remain attached the terminal. Interrupting the container,
+i.e. pressing Ctrl-C, will trigger a graceful shutdown of the container.
+
+
+```
+docker run -it -e OFBIZ_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" -p 8443:8443 -p 5005:5005 ofbiz-docker
+```
+Creates a debuggable instance of OFBiz, listening on port 5005.
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000..9dcd87e0d8
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,79 @@
+# syntax=docker/dockerfile:1
+FROM eclipse-temurin:17 as builder
+
+# Git is used for various OFBiz build tasks.
+RUN apt-get update \
+ && apt-get install -y git \
+ && rm -rf /var/lib/apt/lists/*
+
+WORKDIR /builder
+
+# Add and run the gradle wrapper to trigger a download if needed.
+COPY gradle/init-gradle-wrapper.sh gradle/
+COPY gradlew .
+RUN ["sed", "-i", "s/shasum/sha1sum/g", "gradle/init-gradle-wrapper.sh"]
+RUN ["gradle/init-gradle-wrapper.sh"]
+
+# Run gradlew to trigger downloading of the gradle distribution (if needed)
+RUN --mount=type=cache,id=gradle-cache,sharing=locked,target=/root/.gradle \
+ ["./gradlew", "--console", "plain"]
+
+# Copy all OFBiz sources.
+COPY . .
+
+# Build OFBiz while mounting a gradle cache
+RUN --mount=type=cache,id=gradle-cache,sharing=locked,target=/root/.gradle \
+ --mount=type=tmpfs,target=runtime/tmp \
+ ["./gradlew", "--console", "plain", "distTar"]
+
+###################################################################################
+
+FROM eclipse-temurin:17 as runtimebase
+
+RUN ["useradd", "ofbiz"]
+
+# Configure volumes where hooks into the startup process can be placed.
+RUN ["mkdir", "/docker-entrypoint-before-config-applied.d", "/docker-entrypoint-after-config-applied.d", \
+ "/docker-entrypoint-before-data-load.d", "/docker-entrypoint-after-data-load.d", \
+ "/docker-entrypoint-additional-data.d"]
+RUN ["sh", "-c", "/usr/bin/chown -R ofbiz:ofbiz /docker-entrypoint-*.d" ]
+
+USER ofbiz
+WORKDIR /ofbiz
+
+# Extract the OFBiz tar distribution created by the builder stage.
+RUN --mount=type=bind,from=builder,source=/builder/build/distributions/ofbiz.tar,target=/mnt/ofbiz.tar \
+ ["tar", "--extract", "--strip-components=1", "--file=/mnt/ofbiz.tar"]
+
+COPY docker/docker-entrypoint.sh .
+COPY docker/send_ofbiz_stop_signal.sh .
+
+EXPOSE 8443
+EXPOSE 8009
+EXPOSE 5005
+
+ENTRYPOINT ["/ofbiz/docker-entrypoint.sh"]
+CMD ["bin/ofbiz"]
+
+###################################################################################
+# Load demo data before defining volumes. This results in a container image
+# that is ready to go for demo purposes.
+FROM runtimebase as demo
+
+RUN /ofbiz/bin/ofbiz --load-data
+RUN mkdir --parents /ofbiz/runtime/container_state
+RUN touch /ofbiz/runtime/container_state/data_loaded
+RUN touch /ofbiz/runtime/container_state/admin_loaded
+
+VOLUME ["/docker-entrypoint-before-config-applied.d", "/docker-entrypoint-after-config-applied.d", \
+ "/docker-entrypoint-before-data-load.d", "/docker-entrypoint-after-data-load.d", \
+ "/docker-entrypoint-additional-data.d"]
+
+
+###################################################################################
+# Runtime image with no data loaded.
+FROM runtimebase as runtime
+
+VOLUME ["/docker-entrypoint-before-config-applied.d", "/docker-entrypoint-after-config-applied.d", \
+ "/docker-entrypoint-before-data-load.d", "/docker-entrypoint-after-data-load.d", \
+ "/docker-entrypoint-additional-data.d"]
diff --git a/build.gradle b/build.gradle
index 1a66fb4277..82b50374fb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -125,6 +125,14 @@ node {
npmInstallCommand = System.getenv("CI") ? 'ci' : 'install'
}
+tasks.getByName("distTar") {
+ dependsOn "npmInstall"
+}
+
+tasks.getByName("distZip") {
+ dependsOn "npmInstall"
+}
+
java {
sourceCompatibility(JavaVersion.VERSION_17)
targetCompatibility(JavaVersion.VERSION_17)
diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh
new file mode 100644
index 0000000000..d6ac5e8368
--- /dev/null
+++ b/docker/docker-entrypoint.sh
@@ -0,0 +1,260 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+###############################################################################
+
+###############################################################################
+# OFBiz initialisation script for use as the entry point in a docker container.
+#
+# Triggers the loading of data and configuration of various OFBiz properties before
+# executing the command given as arguments to the script.
+#
+# Behaviour controlled by environment variables:
+#
+# OFBIZ_SKIP_INIT
+# Any non-empty value will cause this script to skip any initialisation steps.
+# Default: <empty>
+#
+# OFBIZ_ADMIN_USER
+# The username of the OFBIZ admin user.
+# Default: admin
+#
+# OFBIZ_ADMIN_PASSWORD
+# The password of the OFBIZ admin user.
+# Default: ofbiz
+#
+# OFBIZ_DATA_LOAD
+# Determine what type of data loading is required.
+# Default: seed
+# Values:
+# - none: No data loading is performed.
+# - seed: Seed data is loaded.
+# - demo: Demo data is loaded.
+#
+# OFBIZ_HOST
+# Specify the hostname used to access OFBiz.
+# Used to populate the host-headers-allowed property in framework/security/config/security.properties.
+# Default: localhost
+#
+# OFBIZ_CONTENT_URL_PREFIX
+# Used to set the content.url.prefix.secure and content.url.prefix.standard properties in
+# framework/webapp/config/url.properties.
+# Default: https://${OFBIZ_HOST}
+#
+# OFBIZ_ENABLE_AJP_PORT
+# Enable the AJP (Apache JServe Protocol) port to allow communication with OFBiz via a reverse proxy.
+# Enabled when this environment variable contains a non-empty value.
+# Default value: <empty>
+#
+# Hooks are executed at the various stages of the initialisation process by executing scripts in the following
+# directories. Scripts must be executable and have the .sh extension:
+#
+# /docker-entrypoint-before-data-load.d
+# Executed before any data loading is about to be performed. Only executed if data loading is required.
+# Example usage would be to alter the data to be loaded.
+#
+# /docker-entrypoint-after-data-load.d
+# Executed after any data loading has been performed. Only executed if data loading was required.
+#
+###############################################################################
+set -x
+set -e
+
+trap shutdown_ofbiz SIGTERM SIGINT
+
+CONTAINER_STATE_DIR="/ofbiz/runtime/container_state"
+CONTAINER_DATA_LOADED="$CONTAINER_STATE_DIR/data_loaded"
+CONTAINER_ADMIN_LOADED="$CONTAINER_STATE_DIR/admin_loaded"
+CONTAINER_CONFIG_APPLIED="$CONTAINER_STATE_DIR/config_applied"
+
+###############################################################################
+# Validate and apply defaults to any environment variables used by this script.
+# See script header for environment variable descriptions.
+ofbiz_setup_env() {
+ case "$OFBIZ_DATA_LOAD" in
+ none | seed | demo) ;;
+ *)
+ OFBIZ_DATA_LOAD="none"
+ ;;
+ esac
+
+ OFBIZ_ADMIN_USER=${OFBIZ_ADMIN_USER:-admin}
+
+ OFBIZ_ADMIN_PASSWORD=${OFBIZ_ADMIN_PASSWORD:-ofbiz}
+
+ OFBIZ_HOST=${OFBIZ_HOST:-localhost}
+
+ OFBIZ_CONTENT_URL_PREFIX=${OFBIZ_CONTENT_URL_PREFIX:-https://${OFBIZ_HOST}}
+}
+
+###############################################################################
+# Create the runtime container state directory used to track which initialisation
+# steps have been run for the container.
+# This directory should be hosted on a volume that persists for the life of the container.
+create_ofbiz_runtime_directories() {
+ if [ ! -d "$CONTAINER_STATE_DIR" ]; then
+ mkdir --parents "$CONTAINER_STATE_DIR"
+ fi
+}
+
+###############################################################################
+# Execute the shell scripts at the paths passed to this function.
+# Args:
+# 1: Name of the hook stage being executed. Used for logging.
+# 2+: Variable number of paths to the shell scripts to be executed.
+# Only scripts with the .sh extension are executed.
+# Scripts will be sourced if they are not executable.
+run_init_hooks() {
+ local hookStage="$1"
+ shift
+ local filePath
+ for filePath; do
+ case "$filePath" in
+ *.sh)
+ if [ -x "$filePath" ]; then
+ printf '%s: running %s\n' "$hookStage" "$filePath"
+ "$filePath"
+ else
+ printf '%s: sourcing %s\n' "$hookStage" "$filePath"
+ . "$filePath"
+ fi
+ ;;
+ *)
+ printf '%s: Not a script. Ignoring %s\n' "$hookStage" "$filePath"
+ ;;
+ esac
+ done
+}
+
+###############################################################################
+# If required, load data into OFBiz.
+load_data() {
+ if [ ! -f "$CONTAINER_DATA_LOADED" ]; then
+ run_init_hooks /docker-entrypoint-before-data-load.d/*
+
+ case "$OFBIZ_DATA_LOAD" in
+ none) ;;
+
+ seed)
+ /ofbiz/bin/ofbiz --load-data readers=seed,seed-initial
+ ;;
+
+ demo)
+ /ofbiz/bin/ofbiz --load-data
+ # Demo data includes the admin user so indicate that the user is already loaded.
+ touch "$CONTAINER_ADMIN_LOADED"
+ ;;
+ esac
+
+ # Load any additional data files provided.
+ if [ -z $(find /docker-entrypoint-additional-data.d/ -prune -empty) ]; then
+ /ofbiz/bin/ofbiz --load-data dir=/docker-entrypoint-additional-data.d
+ fi
+
+ touch "$CONTAINER_DATA_LOADED"
+
+ run_init_hooks /docker-entrypoint-after-data-load.d/*
+ fi
+}
+
+###############################################################################
+# Create and load the password hash for the admin user.
+load_admin_user() {
+ if [ ! -f "$CONTAINER_ADMIN_LOADED" ]; then
+ TMPFILE=$(mktemp)
+
+ # Concatenate a random salt and the admin password.
+ SALT=$(tr --delete --complement A-Za-z0-9 </dev/urandom | head --bytes=16)
+ SALT_AND_PASSWORD="${SALT}${OFBIZ_ADMIN_PASSWORD}"
+
+ # Take a SHA-1 hash of the combined salt and password and strip off any additional output form the sha1sum utility.
+ SHA1SUM_ASCII_HEX=$(printf "$SALT_AND_PASSWORD" | sha1sum | cut --delimiter=' ' --fields=1 --zero-terminated | tr --delete '\000')
+
+ # Convert the ASCII Hex representation of the hash to raw bytes by inserting escape sequences and running
+ # through the printf command. Encode the result as URL base 64 and remove padding.
+ SHA1SUM_ESCAPED_STRING=$(printf "$SHA1SUM_ASCII_HEX" | sed -e 's/\(..\)\.\?/\\x\1/g')
+ SHA1SUM_BASE64=$(printf "$SHA1SUM_ESCAPED_STRING" | basenc --base64url --wrap=0 | tr --delete '=')
+
+ # Concatenate the hash type, salt and hash as the encoded password value.
+ ENCODED_PASSWORD_HASH="\$SHA\$${SALT}\$${SHA1SUM_BASE64}"
+
+ # Populate the login data template
+ sed "s/@userLoginId@/$OFBIZ_ADMIN_USER/g; s/currentPassword=\".*\"/currentPassword=\"$ENCODED_PASSWORD_HASH\"/g;" framework/resources/templates/AdminUserLoginData.xml >"$TMPFILE"
+
+ # Load data from the populated template.
+ /ofbiz/bin/ofbiz --load-data "file=$TMPFILE"
+
+ rm "$TMPFILE"
+
+ touch "$CONTAINER_ADMIN_LOADED"
+ fi
+}
+
+###############################################################################
+# Apply any configuration changes required.
+apply_configuration() {
+ if [ ! -f "$CONTAINER_CONFIG_APPLIED" ]; then
+ run_init_hooks /docker-entrypoint-before-config-applied.d/*
+
+ if [ -n "$OFBIZ_ENABLE_AJP_PORT" ]; then
+ # Configure tomcat to listen for AJP connections on all interfaces within the container.
+ sed --in-place \
+ '/<property name="ajp-connector" value="connector">/ a <property name="address" value="0.0.0.0"/>' \
+ /ofbiz/framework/catalina/ofbiz-component.xml
+ fi
+
+ sed --in-place \
+ "s/host-headers-allowed=.*/host-headers-allowed=${OFBIZ_HOST}/" framework/security/config/security.properties
+
+ sed --in-place \
+ --expression="s#content.url.prefix.secure=.*#content.url.prefix.secure=${OFBIZ_CONTENT_URL_PREFIX}#;" \
+ --expression="s#content.url.prefix.standard=.*#content.url.prefix.standard=${OFBIZ_CONTENT_URL_PREFIX}#;" \
+ framework/webapp/config/url.properties
+
+ touch "$CONTAINER_CONFIG_APPLIED"
+ run_init_hooks /docker-entrypoint-after-config-applied.d/*
+ fi
+}
+
+###############################################################################
+# Send a shutdown signal to OFBiz
+shutdown_ofbiz() {
+ /ofbiz/send_ofbiz_stop_signal.sh
+}
+
+_main() {
+ if [ -z "$OFBIZ_SKIP_INIT" ]; then
+ ofbiz_setup_env
+ create_ofbiz_runtime_directories
+ apply_configuration
+ load_data
+ load_admin_user
+ fi
+
+ # Continue loading OFBiz.
+ unset OFBIZ_SKIP_INIT
+ unset OFBIZ_ADMIN_USER
+ unset OFBIZ_ADMIN_PASSWORD
+ unset OFBIZ_DATA_LOAD
+ unset OFBIZ_ENABLE_AJP_PORT
+ unset OFBIZ_HOST
+ unset OFBIZ_CONTENT_URL_PREFIX
+ exec "$@"
+}
+
+_main "$@"
+
diff --git a/docker/send_ofbiz_stop_signal.sh b/docker/send_ofbiz_stop_signal.sh
new file mode 100644
index 0000000000..6a15c120c2
--- /dev/null
+++ b/docker/send_ofbiz_stop_signal.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+###############################################################################
+
+set -e
+
+# Read a property value. Assumes all properties are single line and do not have spaces around the '=' sign or comments following the valuel.
+function getPropertyValue
+{
+ echo "$1" | sed "/^$2=/!d; s///"
+}
+
+echo "Getting admin port and key..."
+START_PROPERTIES_CONTENT=$(cat /ofbiz/framework/start/src/main/resources/org/apache/ofbiz/base/start/start.properties)
+
+OFBIZ_ADMIN_PORT=$(getPropertyValue "$START_PROPERTIES_CONTENT" "ofbiz.admin.port")
+echo Admin port: $OFBIZ_ADMIN_PORT;
+
+OFBIZ_ADMIN_KEY=$(getPropertyValue "$START_PROPERTIES_CONTENT" "ofbiz.admin.key")
+echo Admin key: $OFBIZ_ADMIN_KEY;
+
+echo "Sending shutdown signal..."
+echo "$OFBIZ_ADMIN_KEY:SHUTDOWN" | curl telnet://localhost:$OFBIZ_ADMIN_PORT
+echo "Done"