This is an automated email from the ASF dual-hosted git repository.

danwatford pushed a commit to branch release22.01
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git


The following commit(s) were added to refs/heads/release22.01 by this push:
     new 55987e5627 Implemented: Add docker build functionality to release22.01 
branch (OFBIZ-12797)
55987e5627 is described below

commit 55987e56278d468c2d69cf97936539e02858ae61
Author: Daniel Watford <dan...@watfordconsulting.com>
AuthorDate: Tue Apr 11 19:52:12 2023 +0100

    Implemented: Add docker build functionality to release22.01 branch 
(OFBIZ-12797)
    
    Added docker build sources, documentation and example usage to the
    release22.01 branch. Also added GitHub Actions workflow to build and
    push container images to the GitHub Container Registry (ghcr.io).
---
 .dockerignore                                      |  30 ++
 .github/workflows/docker-image.yaml                | 151 ++++++++
 DOCKER.md                                          | 189 ++++++++++
 Dockerfile                                         | 128 +++++++
 build.gradle                                       |   8 +
 docker/disable-component.xslt                      |  33 ++
 docker/docker-entrypoint.sh                        | 392 +++++++++++++++++++++
 .../after-config-applied.d/applySolrConfig.sh      |  26 ++
 docker/examples/postgres-demo/docker-compose.yml   |  49 +++
 docker/examples/postgres-demo/ofbiz-postgres.env   |  32 ++
 .../postgres-initdb.d/10-init-user-db.sh           |  35 ++
 docker/examples/postgres-demo/postgres.env         |  21 ++
 docker/send_ofbiz_stop_signal.sh                   |  39 ++
 docker/templates/postgres-entityengine.xml         | 176 +++++++++
 14 files changed, 1309 insertions(+)

diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000000..24f2d41429
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,30 @@
+#####################################################################
+# 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.
+#####################################################################
+
+Dockerfile
+.gradle/
+/bin/
+/build/
+/runtime/
+/themes/common-theme/webapp/common/js/node_modules/
+/themes/common-theme/webapp/common-theme/js/node_modules/
+/plugins/.svn
+/plugins/.github
+/plugins/.git
+
diff --git a/.github/workflows/docker-image.yaml 
b/.github/workflows/docker-image.yaml
new file mode 100644
index 0000000000..da5cef1103
--- /dev/null
+++ b/.github/workflows/docker-image.yaml
@@ -0,0 +1,151 @@
+# 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.
+
+#############################################################################
+# Local testing of this workflow can be carried out using
+# act (https://github.com/nektos/act).
+#
+# Act will set an environment variable, ACT, to indicate that it is running 
the workflow.
+# This environment variable is used to skip some build steps, such as logging 
in to
+# a container registry or pushing container images.
+#
+# On first run, act will prompt you to select a micro, medium or large runner 
image. This
+# workflow can be run using the medium image.
+#
+# Some actions, such as docker/metadata-action, require a GITHUB_TOKEN. To 
meet this
+# requirement when using act you will need to create a Personal Access Token 
on GitHub.
+# You can then run act using a command similar to:
+#   act --job docker_build --secret GITHUB_TOKEN
+# Act will then prompt you to enter your token.
+
+
+name: Build and push docker images
+
+on:
+  push:
+    branches: [ release22.01 ]
+    tags:
+      - '**'
+
+jobs:
+  docker_build:
+    name: Build and push OFBiz docker container images
+    runs-on: ubuntu-latest
+    steps:
+      - name: Check out OFBiz sources
+        uses: actions/checkout@v3
+
+      - name: Log in to the Container registry
+        if: ${{ !env.ACT }}
+        uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
+        with:
+          registry: ghcr.io
+          username: ${{ github.actor }}
+          password: ${{ secrets.GITHUB_TOKEN }}
+
+      
############################################################################
+      # Build and push a container image of the OFBiz Framework without any 
data loaded.
+      - name: Determine metadata (tags, labels) for Docker runtime build
+        id: runtimemeta
+        uses: docker/metadata-action@507c2f2dc502c992ad446e3d7a5dfbe311567a96
+        with:
+          images: ghcr.io/apache/ofbiz
+          tags: |
+            # Extract container tag from git tag.
+            type=match,pattern=release(.*),group=1
+            # Build container tag based on branch name and string '-snapshot'
+            type=ref,event=branch,suffix=-snapshot,priority=650
+
+      - name: Update VERSION file
+        run: |
+          # Populate the VERSION file based on the outputs of the 
metadata-action above.
+          # The same VERSION file will be used for all container images built 
in this workflow.
+
+          # Set the version label for this build.
+          echo 
"${{fromJSON(steps.runtimemeta.outputs.json).labels['org.opencontainers.image.version']}}.
 " > VERSION
+
+          # Append the git commit SHA.
+          echo '${uiLabelMap.CommonRevision}:' 
"${{fromJSON(steps.runtimemeta.outputs.json).labels['org.opencontainers.image.revision']}}.
 " >> VERSION
+
+          # Append the timestamp.
+          echo '${uiLabelMap.CommonBuiltOn}:' 
"${{fromJSON(steps.runtimemeta.outputs.json).labels['org.opencontainers.image.created']}}.
 " >> VERSION
+
+          echo "Version file contents:"
+          cat VERSION
+
+
+      - name: Build and push runtime docker image
+        uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
+        with:
+          context: .
+          target: runtime
+          push: ${{ !env.ACT }}
+          tags: ${{ steps.runtimemeta.outputs.tags }}
+          labels: ${{ steps.runtimemeta.outputs.labels }}
+
+      
############################################################################
+      # Build and push a container image of the OFBiz Framework preloaded with 
demo data
+      - name: Determine metadata (tags, labels) for Docker demo-preload build
+        id: demometa
+        uses: docker/metadata-action@507c2f2dc502c992ad446e3d7a5dfbe311567a96
+        with:
+          images: ghcr.io/apache/ofbiz
+          tags: |
+            type=match,pattern=release(.*),group=1,suffix=-preloaddemo
+            type=ref,event=branch,suffix=-preloaddemo-snapshot,priority=650
+
+      - name: Build and push demo docker image
+        uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
+        with:
+          context: .
+          target: demo
+          push: ${{ !env.ACT }}
+          tags: ${{ steps.demometa.outputs.tags }}
+          labels: ${{ steps.demometa.outputs.labels }}
+
+        
############################################################################
+        # Build and push a container image of the OFBiz Framework plus Plugins,
+        # without any data loaded.
+        # We need to use gradle to download sources as plugins might include 
an install
+        # task in their own build.gradle files. If the project drops support 
for plugins'
+        # install tasks then we can replace the JDK and gradle related steps 
below with
+        # a git checkout from the https://github.com/apache/ofbiz-plugins 
repository.
+      - name: Set up JDK 17
+        uses: actions/setup-java@v3.6.0
+        with:
+          java-version: 17
+          distribution: temurin
+          cache: 'gradle'
+      - name: Grant execute permission for gradlew
+        run: chmod +x gradlew
+      - name: Build with Gradle
+        run: ./gradlew pullAllPluginsSource
+      - name: Determine metadata (tags, labels) for Docker framework with 
plugins build
+        id: pluginsmeta
+        uses: docker/metadata-action@507c2f2dc502c992ad446e3d7a5dfbe311567a96
+        with:
+          images: ghcr.io/apache/ofbiz
+          tags: |
+            type=match,pattern=release(.*),group=1,suffix=-plugins
+            type=ref,event=branch,suffix=-plugins-snapshot,priority=650
+
+      - name: Build and push framework with plugins docker image
+        uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
+        with:
+          context: .
+          target: runtime
+          push: ${{ !env.ACT }}
+          tags: ${{ steps.pluginsmeta.outputs.tags }}
+          labels: ${{ steps.pluginsmeta.outputs.labels }}
diff --git a/DOCKER.md b/DOCKER.md
new file mode 100644
index 0000000000..50ecdf093e
--- /dev/null
+++ b/DOCKER.md
@@ -0,0 +1,189 @@
+# 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 demo --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 the 
docker-entrypoint.sh 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 | <empty> | Specify the hostname used to access OFBiz. If empty 
then the default value of host-headers-allowed from 
framework/security/config/security.properties is used. |
+|OFBIZ_CONTENT_URL_PREFIX | <empty> | 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. |
+|OFBIZ_SKIP_DB_DRIVER_DOWNLOAD | *empty* | Any non-empty value will cause the 
docker-entrypoint.sh script to skip downloading of any database drivers. |
+|OFBIZ_DISABLE_COMPONENTS | plugins/birt/ofbiz-component.xml | Commas 
seperated list of paths to ofbiz-component.xml files of the components that 
should not be loaded. | 
+
+### 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-hooks/before-config-applied.d` | Scripts processed 
before configuration, such as modifications to property files, are applied. |
+| `/docker-entrypoint-hooks/after-config-applied.d` | Scripts processed after 
configuration modifications have been applied. |
+| `/docker-entrypoint-hooks/before-data-load.d` | Scripts processed before 
data loading is executed. Could be used to apply modifications to data files.|
+| `/docker-entrypoint-hooks/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-hooks/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.
+
+### Database
+By default the OFBiz container will use an internal Derby database, storing 
database related files
+in the /ofbiz/runtime volume.
+
+Use of an external database can be configured through environment variables.
+
+#### Derby
+To use the embedded Derby database, ensure all database related environment 
variables are unset.
+
+#### PostgreSQL
+To use a Postgres database set the `OFBIZ_POSTGRES_HOST` environment variable. 
+
+Environment variable | Default | Description 
+---|---|---
+OFBIZ_POSTGRES_HOST | *unset* | Hostname of the PostgreSQL database server. 
+OFBIZ_POSTGRES_OFBIZ_DB | ofbiz | Name of the *ofbiz* database.
+OFBIZ_POSTGRES_OFBIZ_USER | ofbiz | Username when connecting to the ofbiz 
database.
+OFBIZ_POSTGRES_OFBIZ_PASSWORD | ofbiz | Password when connecting to the ofbiz 
database.
+OFBIZ_POSTGRES_OLAP_DB | ofbizolap | Name of the *olap* database.
+OFBIZ_POSTGRES_OLAP_USER | ofbizolap | Username when connecting to the olap 
database.
+OFBIZ_POSTGRES_OLAP_PASSWORD | ofbizolap | Password when connecting to the 
olap database.
+OFBIZ_POSTGRES_TENANT_DB | ofbiztenant | Name of the *tenant* database.
+OFBIZ_POSTGRES_TENANT_USER | ofbiztenant | Username when connecting to the 
tenant database.
+OFBIZ_POSTGRES_TENANT_PASSWORD | ofbiztenant | Password when connecting to the 
tenant database.
+
+The docker-entrypoint.sh script will download a JDBC driver to access the 
PostgreSQL server and
+place the script in the `/ofbiz/lib-extra` volume. If you wish to skip this 
step then set the
+OFBIZ_SKIP_DB_DRIVER_DOWNLOAD environment variable to a non-empty value. This 
would be
+useful if you have already placed a suitable database driver in the 
`/ofbiz/lib-extra` volume.
+
+## 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..23d7470c7e
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,128 @@
+# syntax=docker/dockerfile:1
+#####################################################################
+# 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.
+#####################################################################
+
+FROM eclipse-temurin:17 AS builder
+
+# Git is used for various OFBiz build tasks.
+RUN apt-get update \
+    && apt-get install -y --no-install-recommends git \
+    && rm -rf /var/lib/apt/lists/*
+
+WORKDIR /builder
+
+# Add and run the gradle wrapper to trigger a download if needed.
+COPY --chmod=755 gradle/init-gradle-wrapper.sh gradle/
+COPY --chmod=755 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 applications/ applications/
+COPY config/ config/
+COPY framework/ framework/
+COPY gradle/ gradle/
+COPY lib/ lib/
+# We use a regex to match the plugins directory to avoid a build error when 
the directory doesn't exist.
+COPY plugin[s]/ plugins/
+COPY themes/ themes/
+COPY APACHE2_HEADER build.gradle common.gradle gradle.properties NOTICE 
settings.gradle .
+
+# 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
+
+# xsltproc is used to disable OFBiz components during first run.
+RUN apt-get update \
+    && apt-get install -y --no-install-recommends xsltproc \
+    && rm -rf /var/lib/apt/lists/*
+
+RUN ["useradd", "ofbiz"]
+
+# Create directories used to mount volumes where hooks into the startup 
process can be placed.
+RUN ["mkdir", "--parents", \
+    "/docker-entrypoint-hooks/before-config-applied.d", \
+    "/docker-entrypoint-hooks/after-config-applied.d", \
+    "/docker-entrypoint-hooks/before-data-load.d", \
+    "/docker-entrypoint-hooks/after-data-load.d", \
+    "/docker-entrypoint-hooks/additional-data.d"]
+RUN ["/usr/bin/chown", "-R", "ofbiz:ofbiz", "/docker-entrypoint-hooks" ]
+
+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"]
+
+# Create directories for OFBiz volume mountpoints.
+RUN ["mkdir", "/ofbiz/runtime", "/ofbiz/config", "/ofbiz/lib-extra"]
+
+# Append the java runtime version to the OFBiz VERSION file.
+COPY --chmod=644 --chown=ofbiz:ofbiz VERSION .
+RUN echo '${uiLabelMap.CommonJavaVersion}:' "$(java --version | grep Runtime | 
sed 's/.*Runtime Environment //; s/ (build.*//;')" >> /ofbiz/VERSION
+
+# Leave executable scripts owned by root and non-writable, addressing 
sonarcloud rule,
+# 
https://sonarcloud.io/organizations/apache/rules?open=docker%3AS6504&rule_key=docker%3AS6504
+COPY --chmod=555 docker/docker-entrypoint.sh docker/send_ofbiz_stop_signal.sh .
+
+COPY --chmod=444 docker/disable-component.xslt .
+COPY --chmod=444 docker/templates templates
+
+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
+
+USER ofbiz
+
+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
+RUN touch /ofbiz/runtime/container_state/db_config_applied
+
+VOLUME ["/docker-entrypoint-hooks"]
+VOLUME ["/ofbiz/config", "/ofbiz/runtime", "/ofbiz/lib-extra"]
+
+
+###################################################################################
+# Runtime image with no data loaded.
+FROM runtimebase AS runtime
+
+USER ofbiz
+
+VOLUME ["/docker-entrypoint-hooks"]
+VOLUME ["/ofbiz/config", "/ofbiz/runtime", "/ofbiz/lib-extra"]
diff --git a/build.gradle b/build.gradle
index 4b1f6b4d87..e4a52406a4 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/disable-component.xslt b/docker/disable-component.xslt
new file mode 100644
index 0000000000..04e926ba09
--- /dev/null
+++ b/docker/disable-component.xslt
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+
+<!--
+    Copy all attributes and elements of the root ofbiz-component element in an 
XML document, changing the enabled
+    attribute to false.
+-->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
+    <xsl:template match="/">
+        <xsl:element name="ofbiz-component">
+            <xsl:copy-of select="ofbiz-component/@*"/>
+            <xsl:attribute name="enabled">false</xsl:attribute>
+            <xsl:copy-of select="ofbiz-component/node()"/>
+        </xsl:element>
+    </xsl:template>
+</xsl:stylesheet>
diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh
new file mode 100755
index 0000000000..baa1536c94
--- /dev/null
+++ b/docker/docker-entrypoint.sh
@@ -0,0 +1,392 @@
+#!/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: default value of host-headers-allowed from 
framework/security/config/security.properties.
+#
+# 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: <empty>
+#
+# 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>
+#
+# OFBIZ_SKIP_DB_DRIVER_DOWNLOAD
+# When connecting to databases other than the OFBiz embedded Derby database a 
suitable driver will be needed.
+# This script will attempt to download a suitable driver unless the 
OFBIZ_SKIP_DB_DRIVER_DOWNLOAD contains a non-empty
+# value.
+#
+# OFBIZ_POSTGRES_HOST
+# Sets the name of the PostgreSQL database host.
+# If OFBIZ_POSTGRES_HOST is non-empty, then the following OFBIZ_POSTGRES_* 
environment variables are used to configure
+# access to PostgreSQL databases.
+# OFBIZ_POSTGRES_OFBIZ_DB           Default: ofbiz
+# OFBIZ_POSTGRES_OFBIZ_USER         Default: ofbiz
+# OFBIZ_POSTGRES_OFBIZ_PASSWORD     Default: ofbiz
+# OFBIZ_POSTGRES_OLAP_DB            Default: ofbizolap
+# OFBIZ_POSTGRES_OLAP_USER          Default: ofbizolap
+# OFBIZ_POSTGRES_OLAP_PASSWORD      Default: ofbizolap
+# OFBIZ_POSTGRES_TENANT_DB          Default: ofbiztenant
+# OFBIZ_POSTGRES_TENANT_USER        Default: ofbiztenant
+# OFBIZ_POSTGRES_TENANT_PASSWORD    Default: ofbiztenant
+#
+# OFBIZ_DISABLE_COMPONENTS
+# Prevents loading of ofbiz-components.
+# Contains a comma separated list of relative paths from the ofbiz sources 
directory to the ofbiz-component.xml files
+# that should be prevented from loading.
+# Default: plugins/birt/ofbiz-component.xml
+#
+# 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-hooks/before-config-applied.d
+# Executed before any changes are applied to the OFBiz configuration files.
+#
+# /docker-entrypoint-hooks/after-config-applied.d
+# Executed after any changes are applied to the OFBiz configuration files.
+#
+# /docker-entrypoint-hooks/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-hooks/additional-data.d
+# Any data files (.xml files) in this directory are loaded after seed/demo 
data.
+#
+# /docker-entrypoint-hooks/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"
+CONTAINER_DB_CONFIG_APPLIED="$CONTAINER_STATE_DIR/db_config_applied"
+
+POSTGRES_DRIVER_URL="https://jdbc.postgresql.org/download/postgresql-42.5.4.jar";
+
+###############################################################################
+# 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="seed"
+    ;;
+  esac
+
+  OFBIZ_ADMIN_USER=${OFBIZ_ADMIN_USER:-admin}
+
+  OFBIZ_ADMIN_PASSWORD=${OFBIZ_ADMIN_PASSWORD:-ofbiz}
+
+  OFBIZ_POSTGRES_OFBIZ_DB=${OFBIZ_POSTGRES_OFBIZ_DB:-ofbiz}
+  OFBIZ_POSTGRES_OFBIZ_USER=${OFBIZ_POSTGRES_OFBIZ_USER:-ofbiz}
+  OFBIZ_POSTGRES_OFBIZ_PASSWORD=${OFBIZ_POSTGRES_OFBIZ_PASSWORD:-ofbiz}
+
+  OFBIZ_POSTGRES_OLAP_DB=${OFBIZ_POSTGRES_OLAP_DB:-ofbizolap}
+  OFBIZ_POSTGRES_OLAP_USER=${OFBIZ_POSTGRES_OLAP_USER:-ofbizolap}
+  OFBIZ_POSTGRES_OLAP_PASSWORD=${OFBIZ_POSTGRES_OLAP_PASSWORD:-ofbizolap}
+
+  OFBIZ_POSTGRES_TENANT_DB=${OFBIZ_POSTGRES_TENANT_DB:-ofbiztenant}
+  OFBIZ_POSTGRES_TENANT_USER=${OFBIZ_POSTGRES_TENANT_USER:-ofbiztenant}
+  OFBIZ_POSTGRES_TENANT_PASSWORD=${OFBIZ_POSTGRES_TENANT_PASSWORD:-ofbiztenant}
+
+  
OFBIZ_DISABLE_COMPONENTS=${OFBIZ_DISABLE_COMPONENTS-plugins/birt/ofbiz-component.xml}
+}
+
+###############################################################################
+# 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 before-data-load 
/docker-entrypoint-hooks/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-hooks/additional-data.d/ -prune -empty) 
]; then
+      /ofbiz/bin/ofbiz --load-data 
dir=/docker-entrypoint-hooks/additional-data.d
+    fi
+
+    touch "$CONTAINER_DATA_LOADED"
+
+    run_init_hooks after-data-load /docker-entrypoint-hooks/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
+}
+
+###############################################################################
+# Modify the given ofbiz-component configuration XML file to set the root
+# component's 'enabled' attribute to false.
+# $1 - Path to the XML file to be modified.
+disable_component() {
+  XML_FILE="/ofbiz/$1"
+  if [ -f "$XML_FILE" ]; then
+    TMPFILE=$(mktemp)
+
+    xsltproc /ofbiz/disable-component.xslt "$XML_FILE" > "$TMPFILE"
+    mv "$TMPFILE" "$XML_FILE"
+  else
+    echo "Cannot find ofbiz-component configuration file. Not disabling 
component: $XML_FILE"
+  fi
+}
+
+###############################################################################
+# Modify the given ofbiz-component configuration XML files to set their root
+# components' 'enabled' attribute to false.
+# $1 - Comma separated list of paths to configuration XML files to be modified.
+disable_components() {
+  COMMA_SEPARATED_PATHS="$1"
+
+  if [ -n "$COMMA_SEPARATED_PATHS" ]; then
+
+    # Split the comma separated paths into separate arguments.
+    IFS=,
+    set "$COMMA_SEPARATED_PATHS"
+
+    while [ -n "$1" ]; do
+      disable_component "$1"
+      shift
+    done
+  fi
+}
+
+###############################################################################
+# Apply any configuration changes required.
+# Changed property files need to be placed in /ofbiz/config so they appear 
earlier
+# in the classpath and override the build-time copies of the properties in 
ofbiz.jar.
+apply_configuration() {
+  if [ ! -f "$CONTAINER_CONFIG_APPLIED" ]; then
+    run_init_hooks before-config-applied 
/docker-entrypoint-hooks/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
+
+    if [ -n "$OFBIZ_HOST" ]; then
+      sed "s/host-headers-allowed=.*/host-headers-allowed=${OFBIZ_HOST}/" \
+        framework/security/config/security.properties 
>config/security.properties
+    fi
+
+    if [ -n "$OFBIZ_CONTENT_URL_PREFIX" ]; then
+      sed \
+        
--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 >config/url.properties
+    fi
+
+    if [ -n "$OFBIZ_DISABLE_COMPONENTS" ]; then
+      disable_component "$OFBIZ_DISABLE_COMPONENTS"
+    fi
+
+    touch "$CONTAINER_CONFIG_APPLIED"
+    run_init_hooks after-config-applied 
/docker-entrypoint-hooks/after-config-applied.d/*
+  fi
+}
+
+###############################################################################
+# Set up the connection to the OFBiz database.
+configure_database() {
+  if [ ! -f "$CONTAINER_DB_CONFIG_APPLIED" ]; then
+    if [ -n "$OFBIZ_POSTGRES_HOST" ]; then
+      sed \
+        --expression="s/@HOST@/$OFBIZ_POSTGRES_HOST/;" \
+        --expression="s/@OFBIZ_DB@/$OFBIZ_POSTGRES_OFBIZ_DB/;" \
+        --expression="s/@OFBIZ_USERNAME@/$OFBIZ_POSTGRES_OFBIZ_USER/;" \
+        --expression="s/@OFBIZ_PASSWORD@/$OFBIZ_POSTGRES_OFBIZ_PASSWORD/;" \
+        --expression="s/@OLAP_DB@/$OFBIZ_POSTGRES_OLAP_DB/;" \
+        --expression="s/@OLAP_USERNAME@/$OFBIZ_POSTGRES_OLAP_USER/;" \
+        --expression="s/@OLAP_PASSWORD@/$OFBIZ_POSTGRES_OLAP_PASSWORD/;" \
+        --expression="s/@TENANT_DB@/$OFBIZ_POSTGRES_TENANT_DB/;" \
+        --expression="s/@TENANT_USERNAME@/$OFBIZ_POSTGRES_TENANT_USER/;" \
+        --expression="s/@TENANT_PASSWORD@/$OFBIZ_POSTGRES_TENANT_PASSWORD/;" \
+        templates/postgres-entityengine.xml > config/entityengine.xml
+
+      if [ -z "$OFBIZ_SKIP_DB_DRIVER_DOWNLOAD" ]; then
+        echo "Retrieving PostgreSQL driver from $POSTGRES_DRIVER_URL"
+        wget --verbose --directory-prefix=lib-extra "$POSTGRES_DRIVER_URL"
+      fi
+    fi
+
+    touch "$CONTAINER_DB_CONFIG_APPLIED"
+  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
+    configure_database
+    apply_configuration
+    load_data
+    load_admin_user
+  fi
+
+  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
+  unset OFBIZ_POSTGRES_OFBIZ_DB
+  unset OFBIZ_POSTGRES_OFBIZ_USER
+  unset OFBIZ_POSTGRES_OFBIZ_PASSWORD
+  unset OFBIZ_POSTGRES_OLAP_DB
+  unset OFBIZ_POSTGRES_OLAP_USER
+  unset OFBIZ_POSTGRES_OLAP_PASSWORD
+  unset OFBIZ_POSTGRES_TENANT_DB
+  unset OFBIZ_POSTGRES_TENANT_USER
+  unset OFBIZ_POSTGRES_TENANT_PASSWORD
+
+  # Continue loading OFBiz.
+  exec "$@"
+}
+
+_main "$@"
diff --git 
a/docker/examples/postgres-demo/after-config-applied.d/applySolrConfig.sh 
b/docker/examples/postgres-demo/after-config-applied.d/applySolrConfig.sh
new file mode 100644
index 0000000000..71c891dfdb
--- /dev/null
+++ b/docker/examples/postgres-demo/after-config-applied.d/applySolrConfig.sh
@@ -0,0 +1,26 @@
+#!/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 -x
+
+if [ -d /ofbiz/plugins/solr ]; then
+  sed "s/^solr.webapp.domainName=.*/solr.webapp.domainName=${OFBIZ_HOST}/" \
+    /ofbiz/plugins/solr/config/solrconfig.properties > 
/ofbiz/config/solrconfig.properties
+fi
diff --git a/docker/examples/postgres-demo/docker-compose.yml 
b/docker/examples/postgres-demo/docker-compose.yml
new file mode 100644
index 0000000000..fcafaaf788
--- /dev/null
+++ b/docker/examples/postgres-demo/docker-compose.yml
@@ -0,0 +1,49 @@
+#####################################################################
+# 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.
+#####################################################################
+
+version: "2.4"
+
+services:
+  db:
+    image: postgres:13
+    mem_limit: 300M
+    memswap_limit: 300M
+    cpu_shares: 200
+    restart: "no"
+    volumes:
+      - ./postgres-initdb.d:/docker-entrypoint-initdb.d
+    env_file:
+      - postgres.env
+      - ofbiz-postgres.env
+
+  ofbiz:
+    image: ofbiz-docker:release22.01-snapshot
+    mem_limit: 2400M
+    memswap_limit: 2400M
+    cpu_shares: 200
+    ports:
+      - 8443:8443
+    volumes:
+      - 
./after-config-applied.d:/docker-entrypoint-hooks/after-config-applied.d
+    env_file:
+      - ofbiz-postgres.env
+    environment:
+      OFBIZ_DATA_LOAD: demo
+      OFBIZ_HOST: example.internal
+      OFBIZ_CONTENT_URL_PREFIX: https://example.internal:8443
diff --git a/docker/examples/postgres-demo/ofbiz-postgres.env 
b/docker/examples/postgres-demo/ofbiz-postgres.env
new file mode 100644
index 0000000000..ebe1e567cb
--- /dev/null
+++ b/docker/examples/postgres-demo/ofbiz-postgres.env
@@ -0,0 +1,32 @@
+#####################################################################
+# 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_POSTGRES_HOST=db
+
+OFBIZ_POSTGRES_OFBIZ_DB=ofbizmaindb
+OFBIZ_POSTGRES_OFBIZ_USER=ofbiz
+OFBIZ_POSTGRES_OFBIZ_PASSWORD="Ab6SqDD2YM2lmEsvao-"
+
+OFBIZ_POSTGRES_OLAP_DB=ofbizolapdb
+OFBIZ_POSTGRES_OLAP_USER=ofbizolap
+OFBIZ_POSTGRES_OLAP_PASSWORD="P7TFUtQHSuvha8gSxMME"
+
+OFBIZ_POSTGRES_TENANT_DB=ofbiztenantdb
+OFBIZ_POSTGRES_TENANT_USER=ofbiztenant
+OFBIZ_POSTGRES_TENANT_PASSWORD="4oXET73QGriblUejjbvR"
diff --git a/docker/examples/postgres-demo/postgres-initdb.d/10-init-user-db.sh 
b/docker/examples/postgres-demo/postgres-initdb.d/10-init-user-db.sh
new file mode 100644
index 0000000000..d3130c15ed
--- /dev/null
+++ b/docker/examples/postgres-demo/postgres-initdb.d/10-init-user-db.sh
@@ -0,0 +1,35 @@
+#!/bin/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
+
+psql -v ON_ERROR_STOP=1 --username "postgres" --dbname "postgres" <<-EOSQL
+    CREATE USER $OFBIZ_POSTGRES_OFBIZ_USER WITH PASSWORD 
'$OFBIZ_POSTGRES_OFBIZ_PASSWORD';
+    CREATE DATABASE $OFBIZ_POSTGRES_OFBIZ_DB;
+    GRANT ALL PRIVILEGES ON DATABASE $OFBIZ_POSTGRES_OFBIZ_DB TO 
$OFBIZ_POSTGRES_OFBIZ_USER;
+
+    CREATE USER $OFBIZ_POSTGRES_OLAP_USER WITH PASSWORD 
'$OFBIZ_POSTGRES_OLAP_PASSWORD';
+    CREATE DATABASE $OFBIZ_POSTGRES_OLAP_DB;
+    GRANT ALL PRIVILEGES ON DATABASE $OFBIZ_POSTGRES_OLAP_DB TO 
$OFBIZ_POSTGRES_OLAP_USER;
+
+    CREATE USER $OFBIZ_POSTGRES_TENANT_USER WITH PASSWORD 
'$OFBIZ_POSTGRES_TENANT_PASSWORD';
+    CREATE DATABASE $OFBIZ_POSTGRES_TENANT_DB;
+    GRANT ALL PRIVILEGES ON DATABASE $OFBIZ_POSTGRES_TENANT_DB TO 
$OFBIZ_POSTGRES_TENANT_USER;
+EOSQL
diff --git a/docker/examples/postgres-demo/postgres.env 
b/docker/examples/postgres-demo/postgres.env
new file mode 100644
index 0000000000..86924ae3b2
--- /dev/null
+++ b/docker/examples/postgres-demo/postgres.env
@@ -0,0 +1,21 @@
+#####################################################################
+# 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.
+#####################################################################
+
+# Mandatory environment variable to set the password of the postgres superuser.
+POSTGRES_PASSWORD="20wganpfDASBtBXY7GQ6"
\ No newline at end of file
diff --git a/docker/send_ofbiz_stop_signal.sh b/docker/send_ofbiz_stop_signal.sh
new file mode 100755
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"
diff --git a/docker/templates/postgres-entityengine.xml 
b/docker/templates/postgres-entityengine.xml
new file mode 100644
index 0000000000..b9485c3407
--- /dev/null
+++ b/docker/templates/postgres-entityengine.xml
@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+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.
+-->
+<!--
+ - This file configures the Entity Engine JDBC (or other DataSource) and JTA
+access. For a detailed description see the core/docs/entityconfig.html file.
+-->
+<entity-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+        
xsi:noNamespaceSchemaLocation="https://ofbiz.apache.org/dtds/entity-config.xsd";>
+    <resource-loader name="fieldfile" 
class="org.apache.ofbiz.base.config.FileLoader"
+            prepend-env="ofbiz.home" prefix="/framework/entity/fieldtype/"/>
+
+    <!-- the transaction factory class to use, one is needed for each way of 
getting JTA interfaces -->
+    <!-- Use this one for Geronimo -->
+    <transaction-factory 
class="org.apache.ofbiz.entity.transaction.GeronimoTransactionFactory"/>
+
+    <!-- the connection factory class to use, one is needed for obtaining 
connections/pools for defined resources -->
+    <connection-factory 
class="org.apache.ofbiz.entity.connection.DBCPConnectionFactory"/>
+
+    <debug-xa-resources value="false" />  <!-- see 
https://issues.apache.org/jira/browse/OFBIZ-4282 for more -->
+
+    <delegator name="default" entity-model-reader="main" 
entity-group-reader="main" entity-eca-reader="main" 
distributed-cache-clear-enabled="false">
+        <group-map group-name="org.apache.ofbiz" 
datasource-name="localpostgres"/>
+        <group-map group-name="org.apache.ofbiz.olap" 
datasource-name="localpostgresolap"/>
+        <group-map group-name="org.apache.ofbiz.tenant" 
datasource-name="localpostgrestenant"/>
+    </delegator>
+
+    <!-- May be used when you create a service that manages many data for 
massive imports, this for performance reason or to escape functional cases -->
+    <delegator name="default-no-eca" entity-model-reader="main" 
entity-group-reader="main" entity-eca-reader="main" entity-eca-enabled="false" 
distributed-cache-clear-enabled="false">
+        <group-map group-name="org.apache.ofbiz" 
datasource-name="localpostgres"/>
+        <group-map group-name="org.apache.ofbiz.olap" 
datasource-name="localpostgresolap"/>
+        <group-map group-name="org.apache.ofbiz.tenant" 
datasource-name="localpostgrestenant"/>
+    </delegator>
+
+    <!-- Be sure that your default delegator (or the one you use) uses the 
same datasource for test. You must run "gradlew loadAll" before running 
"gradlew testIntegration" -->
+    <delegator name="test" entity-model-reader="main" 
entity-group-reader="main" entity-eca-reader="main">
+        <group-map group-name="org.apache.ofbiz" datasource-name="localderby"/>
+        <group-map group-name="org.apache.ofbiz.olap" 
datasource-name="localpostgresolap"/>
+        <group-map group-name="org.apache.ofbiz.tenant" 
datasource-name="localpostgrestenant"/>
+    </delegator>
+
+
+    <!-- need to at least define a name for each component to use -->
+    <entity-model-reader name="main"/>
+
+    <!-- need to at least define a name for each component to use -->
+    <entity-group-reader name="main"/>
+
+    <!-- need to at least define a name for each component to use -->
+    <entity-eca-reader name="main"/>
+
+    <!-- need to at least define a name for each component to use -->
+    <entity-data-reader name="tenant"/>
+    <entity-data-reader name="seed"/>
+    <entity-data-reader name="seed-initial"/>
+    <entity-data-reader name="demo"/>
+    <entity-data-reader name="ext"/>
+    <entity-data-reader name="ext-test"/>
+    <entity-data-reader name="ext-demo"/>
+
+    <field-type name="postgres" loader="fieldfile" 
location="fieldtypepostgres.xml"/>
+
+    <datasource name="localpostgres"
+            helper-class="org.apache.ofbiz.entity.datasource.GenericHelperDAO"
+            schema-name="public"
+            field-type-name="postgres"
+            check-on-start="true"
+            add-missing-on-start="true"
+            use-fk-initially-deferred="false"
+            alias-view-columns="false"
+            join-style="ansi"
+            use-binary-type-for-blob="true"
+            use-order-by-nulls="true"
+            offset-style="limit"
+            result-fetch-size="50"> <!-- Comment out the result-fetch-size 
attribute for jdbc driver versions older than 8.0.
+            Not recommended to use those though. They are archived unsupported 
versions: http://jdbc.postgresql.org/download.html -->
+        
+        <read-data reader-name="tenant"/>
+        <read-data reader-name="seed"/>
+        <read-data reader-name="seed-initial"/>
+        <read-data reader-name="demo"/>
+        <read-data reader-name="ext"/>
+        <read-data reader-name="ext-test"/>
+        <read-data reader-name="ext-demo"/>
+        <inline-jdbc
+                jdbc-driver="org.postgresql.Driver"
+                jdbc-uri="jdbc:postgresql://@HOST@/@OFBIZ_DB@"
+                jdbc-username="@OFBIZ_USERNAME@"
+                jdbc-password="@OFBIZ_PASSWORD@"
+                isolation-level="ReadCommitted"
+                pool-minsize="2"
+                pool-maxsize="250"
+                time-between-eviction-runs-millis="600000"/><!-- Be warned 
that at this date (2009-09-20) the max_connections parameters in postgresql.conf
+                is set by default to 100 by the initdb process see 
http://www.postgresql.org/docs/8.4/static/runtime-config-connection.html#GUC-MAX-CONNECTIONS-->
+    </datasource>
+
+    <datasource name="localpostgresolap"
+                
helper-class="org.apache.ofbiz.entity.datasource.GenericHelperDAO"
+                schema-name="public"
+                field-type-name="postgres"
+                check-on-start="true"
+                add-missing-on-start="true"
+                use-fk-initially-deferred="false"
+                alias-view-columns="false"
+                join-style="ansi"
+                result-fetch-size="50"
+                use-binary-type-for-blob="true"
+                use-order-by-nulls="true"
+                offset-style="limit">
+        <read-data reader-name="tenant"/>
+        <read-data reader-name="seed"/>
+        <read-data reader-name="seed-initial"/>
+        <read-data reader-name="demo"/>
+        <read-data reader-name="ext"/>
+        <read-data reader-name="ext-test"/>
+        <read-data reader-name="ext-demo"/>
+        <inline-jdbc
+                jdbc-driver="org.postgresql.Driver"
+                jdbc-uri="jdbc:postgresql://@HOST@/@OLAP_DB@"
+                jdbc-username="@OLAP_USERNAME@"
+                jdbc-password="@OLAP_PASSWORD@"
+                isolation-level="ReadCommitted"
+                pool-minsize="2"
+                pool-maxsize="250"
+                time-between-eviction-runs-millis="600000"/><!-- Be warned 
that at this date (2009-09-20) the max_connections parameters in postgresql.conf
+                    is set by default to 100 by the initdb process see 
http://www.postgresql.org/docs/8.4/static/runtime-config-connection.html#GUC-MAX-CONNECTIONS-->
+    </datasource>
+
+    <datasource name="localpostgrestenant"
+                
helper-class="org.apache.ofbiz.entity.datasource.GenericHelperDAO"
+                schema-name="public"
+                field-type-name="postgres"
+                check-on-start="true"
+                add-missing-on-start="true"
+                use-fk-initially-deferred="false"
+                alias-view-columns="false"
+                join-style="ansi"
+                result-fetch-size="50"
+                use-binary-type-for-blob="true"
+                use-order-by-nulls="true"
+                offset-style="limit">
+        <read-data reader-name="tenant"/>
+        <read-data reader-name="seed"/>
+        <read-data reader-name="seed-initial"/>
+        <read-data reader-name="demo"/>
+        <read-data reader-name="ext"/>
+        <read-data reader-name="ext-test"/>
+        <read-data reader-name="ext-demo"/>
+        <inline-jdbc
+                jdbc-driver="org.postgresql.Driver"
+                jdbc-uri="jdbc:postgresql://@HOST@/@TENANT_DB@"
+                jdbc-username="@TENANT_USERNAME@"
+                jdbc-password="@TENANT_PASSWORD@"
+                isolation-level="ReadCommitted"
+                pool-minsize="2"
+                pool-maxsize="250"
+                time-between-eviction-runs-millis="600000"/><!-- Be warned 
that at this date (2009-09-20) the max_connections parameters in postgresql.conf
+                    is set by default to 100 by the initdb process see 
http://www.postgresql.org/docs/8.4/static/runtime-config-connection.html#GUC-MAX-CONNECTIONS-->
+    </datasource>
+</entity-config>

Reply via email to