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

gtully pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git


The following commit(s) were added to refs/heads/main by this push:
     new 587ffb223c ARTEMIS-3042 simple properties based, extensible broker 
image
587ffb223c is described below

commit 587ffb223cd2461a9da5c53e5ac189b9aa24640c
Author: Gary Tully <gary.tu...@gmail.com>
AuthorDate: Thu Jun 30 16:09:00 2022 +0100

    ARTEMIS-3042 simple properties based, extensible broker image
---
 .../org/apache/activemq/artemis/cli/Artemis.java   |  15 ++-
 .../org/apache/activemq/cli/test/ArtemisTest.java  |   3 +-
 artemis-image/README.md                            |  57 ++++++++
 artemis-image/TODO.md                              |   7 +
 artemis-image/examples/README.md                   |  55 ++++++++
 .../amqp_sasl_scram.properties                     |  44 ++++++
 .../amqp_sasl_scram_test__etc/login.config         |  26 ++++
 .../examples/amqp_sasl_scram_test__etc/role        |  18 +++
 artemis-image/examples/byoc__etc/broker.xml        |  46 +++++++
 artemis-image/examples/pom.xml                     |  77 +++++++++++
 artemis-image/pom.xml                              | 105 +++++++++++++++
 .../src/main/jib/config/acceptor.properties        |  21 +++
 artemis-image/src/main/resources/log4j2.properties |  20 +++
 .../artemis/ActiveMQImageExamplesTest.java         |  87 ++++++++++++
 .../artemis/jms/server/embedded/EmbeddedJMS.java   |   2 +-
 .../core/server/embedded/EmbeddedActiveMQ.java     |   7 +-
 .../artemis/core/server/embedded/Main.java         | 148 +++++++++++++++++++++
 .../core/server/impl/ActiveMQServerImpl.java       |   1 +
 .../artemis/core/server/embedded/MainTest.java     |  30 +++++
 pom.xml                                            |   8 ++
 20 files changed, 766 insertions(+), 11 deletions(-)

diff --git 
a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java 
b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java
index 31bd72ffd6..4242e75526 100644
--- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java
+++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java
@@ -115,14 +115,15 @@ public class Artemis {
    public static void verifyManagementDTO(File etc) {
       if (etc != null) {
          File management = new File(etc, "management.xml");
-
-         try {
-            ManagementContextDTO managementContextDTO = 
XmlUtil.decode(ManagementContextDTO.class, management);
-            if (managementContextDTO != null && 
managementContextDTO.getAuthorisation() != null) {
-               System.setProperty("javax.management.builder.initial", 
"org.apache.activemq.artemis.core.server.management.ArtemisMBeanServerBuilder");
+         if (management.exists()) {
+            try {
+               ManagementContextDTO managementContextDTO = 
XmlUtil.decode(ManagementContextDTO.class, management);
+               if (managementContextDTO != null && 
managementContextDTO.getAuthorisation() != null) {
+                  System.setProperty("javax.management.builder.initial", 
"org.apache.activemq.artemis.core.server.management.ArtemisMBeanServerBuilder");
+               }
+            } catch (Exception e) {
+               e.printStackTrace();
             }
-         } catch (Exception e) {
-            e.printStackTrace();
          }
       }
    }
diff --git 
a/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java 
b/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java
index d534224b9c..6d1f994b12 100644
--- a/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java
+++ b/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java
@@ -37,6 +37,7 @@ import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -2145,7 +2146,7 @@ public class ArtemisTest extends CliTestBase {
 
       // verify error
       Object ret = Artemis.internalExecute("run", "--properties", 
"https://www.apache.org";);
-      assertTrue(ret instanceof IllegalStateException);
+      assertTrue(ret instanceof FileNotFoundException);
    }
 
    @Test
diff --git a/artemis-image/README.md b/artemis-image/README.md
new file mode 100644
index 0000000000..cb959c6213
--- /dev/null
+++ b/artemis-image/README.md
@@ -0,0 +1,57 @@
+###What is in the image
+
+An _empty_, _open_, _default_ broker with an acceptor on port 61616
+
+ - by empty: has no addresses or queues but will auto create on demand
+ - by open: has no security; authentication or authorization, users or roles
+ - by default: has no configuration, it is dependent on the hard coded 
defaults of the embedded broker service
+
+###How will the image behave
+
+ 1) the image will use or create `/app/data` for persistence of data
+
+ 2) the image will use any [.properties 
files](https://activemq.apache.org/components/artemis/documentation/latest/configuration-index.html#broker_properties)
 from `/app/etc` to augment broker configuration
+
+ 3) the image will use `/app/etc/broker.xml` if present, to bootstrap 
configuration, the 'bring your own config' use case
+
+###Build and Use
+
+First build an OCI image tar file from this artemis project using mvn. 
+The image wraps a plain java application based on a jre image. You should note 
the default `fromImage` property in the pom.xml and potentially override using 
`-DfromImage=<image url>` with your choice, as it may be out of date.
+
+To build the image, use:
+
+ `$> mvn compile jib:buildTar@now`
+
+An OCI image is created as a tar file.
+
+> *Note that any OCI compatible container runtime and registry can be used for 
the next steps, eg: docker, podman... I have used podman.*
+
+To load the image tar into the local container registry, use:
+
+ `$> podman image load --input target/jib-image.tar`
+
+To run the image detached* and rootless with port 61616 exposed to localhost 
by podman, use:
+
+ `$> podman run --name=artemis -dp 61616:61616 
localhost/target/activemq-artemis-image:<version>`
+
+The `:<version>` part of the image name is the maven ${project.version} from 
the pom.xml. You can use tab completion to have podman help you pick that exact 
container.
+
+> **Note that you can later stop the detached container with: `$> podman stop 
artemis`*
+
+Execute the artemis producer/consumer command line tools to interact with the 
broker.
+
+ `$> ./bin/artemis producer --url tcp://localhost:61616`
+
+ `$> ./bin/artemis consumer --url tcp://localhost:61616`
+
+###Intent
+
+The intent is that this image is useful as is. If one can trust users and is 
happy with configuration defaults, having no access control or limits can work 
fine.
+
+If more control is necessary then this image can be configured by mounting an 
`/app/etc` directory with property files that augment default broker 
configuration.
+
+This image could also be the base for a derived jib image, by simply adding 
more property files to the `src/main/jib/config` directory.
+
+see examples/README.md for some more detail.
+
diff --git a/artemis-image/TODO.md b/artemis-image/TODO.md
new file mode 100644
index 0000000000..4a07a03643
--- /dev/null
+++ b/artemis-image/TODO.md
@@ -0,0 +1,7 @@
+TODO:
+ - replace @classpath_file with cp from libs/*.jar directory - more extensible 
for folks that want extra jars/plugins in derived images
+   - or figure out a mount point for extra jars
+ - currently running as root!
+   - maybe we need a base image with an 'app' or 'java' user preconfigured 
with rw permissions on /app
+   - or do that in a launch.sh
+     - this is a known and reasonable limitation of jib 
https://github.com/GoogleContainerTools/jib/issues/1029
\ No newline at end of file
diff --git a/artemis-image/examples/README.md b/artemis-image/examples/README.md
new file mode 100644
index 0000000000..36e7078c45
--- /dev/null
+++ b/artemis-image/examples/README.md
@@ -0,0 +1,55 @@
+###Examples
+
+This directory contains examples of customising the image for particular use 
cases
+
+####amqp_sasl_scram_test__etc
+In this example, you can run the image with configuration that locks the 
broker down to a single user on a single predefined
+queue called `TEST`. The necessary configuration overrides:
+ - restricting the acceptor to AMQP/SASL-SCRAM
+ - providing RBAC for queue TEST
+
+are in:`./amqp_sasl_scram_test__etc/amqp_sasl_scram.properties`
+
+To exercise this example, you need to choose a password for the pre-configured 
user 'A'.
+With SASL_SCRAM the broker retains a salted representation of that value, but 
not the plain text value.
+
+Register your chosen password by creating `./amqp_sasl_scram_test__etc/user` 
using mvn as follows:
+ 
+ `$> mvn exec:exec -Dexample.pwd=<some value>`
+
+To see the result, cat the generated user file to see the stored 
representation:
+
+ `$> cat ./amqp_sasl_scram_test__etc/user`
+
+You can then mount the `./amqp_sasl_scram_test__etc directory` as `/app/etc` 
for the container and initialize JAAS 
+via the `java.security.auth.login.config` system property, which is passed to 
the JVM via the ENV `JDK_JAVA_OPTIONS` as follows:
+
+ `$> podman run --name=artemis-amqp -dp 61616:61616 --env  
JDK_JAVA_OPTIONS=-Djava.security.auth.login.config=/app/etc/login.config 
--privileged -v ./amqp_sasl_scram_test__etc:/app/etc 
localhost/target/activemq-artemis-image:<version>`
+
+Execute the artemis producer/consumer command line tools to validate secure 
access to the TEST queue using AMQP
+SASL-SCRAM with your chosen password via:
+
+ `$> ./bin/artemis producer --protocol amqp --url amqp://localhost:61616 
--user A --password <some value>`
+
+ `$> ./bin/artemis consumer --protocol amqp --url amqp://localhost:61616 
--user A --password <some value>`
+
+####byoc__etc
+This is an example of "Bring Your Own Config" or BYOC. The image will look for 
`/app/etc/broker.xml`. If that file exists
+it will be treated as the broker xml configuration for the embedded broker. If 
your existing configuration is nicely
+locked down or if you want to provide some custom defaults for your image, 
referencing an existing broker.xml makes sense.
+Property files can still be used to augment the defaults or be used solely for 
more dynamic parts of configuration.
+
+To exercise the example, `./byoc__etc directory` as `/app/etc` for the 
container as follows:
+
+ `$> podman run --name=artemis-byoc -dp 61616:61616 --privileged -v 
./byoc__etc:/app/etc localhost/target/activemq-artemis-image:<version>`
+
+Peek at the broker logs to note the broker name 'byoc' configured from the 
broker.xml file
+
+`$> podman logs artemis-byoc
+
+Execute the artemis producer/consumer command line tools to validate, it 
behaves like the bare image:
+
+ `$> ./bin/artemis producer --url tcp://localhost:61616`
+
+ `$> ./bin/artemis consumer --url tcp://localhost:61616`
+
diff --git 
a/artemis-image/examples/amqp_sasl_scram_test__etc/amqp_sasl_scram.properties 
b/artemis-image/examples/amqp_sasl_scram_test__etc/amqp_sasl_scram.properties
new file mode 100644
index 0000000000..59fc7b5691
--- /dev/null
+++ 
b/artemis-image/examples/amqp_sasl_scram_test__etc/amqp_sasl_scram.properties
@@ -0,0 +1,44 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+## reset to default
+securityEnabled=true
+
+## reference user role files with login.config, 
-Djava.security.auth.login.config=jaas/login.config
+## the broker JAAS domain in login.config
+acceptorConfigurations.tcp.params.securityDomain=broker
+
+## lock down broker acceptor
+## to SCRAM AMQP
+acceptorConfigurations.tcp.params.saslMechanisms=SCRAM-SHA-512
+acceptorConfigurations.tcp.params.protocols=AMQP
+acceptorConfigurations.tcp.params.saslLoginConfigScope=amqp-sasl-scram
+
+## if over TLS, configure acceptor key and trust store
+# acceptorConfigurations.tcp.params.sslEnabled=true
+# acceptorConfigurations.tcp.params.keyStorePath=/app/etc/<keystore>.keystore
+# acceptorConfigurations.tcp.params.keyStorePassword=<password>
+
+
+## create TEST address and ANYCAST queue b/c we won't have createX permissions
+## TEST is the default queue for ./bin/artemis producer
+addressConfigurations.TEST.queueConfigs.TEST.routingType=ANYCAST
+
+## grant users role read/write
+securityRoles.TEST.users.send=true
+securityRoles.TEST.users.consume=true
+
diff --git a/artemis-image/examples/amqp_sasl_scram_test__etc/login.config 
b/artemis-image/examples/amqp_sasl_scram_test__etc/login.config
new file mode 100644
index 0000000000..536414f9f1
--- /dev/null
+++ b/artemis-image/examples/amqp_sasl_scram_test__etc/login.config
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+ 
+amqp-sasl-scram {
+   
org.apache.activemq.artemis.spi.core.security.jaas.SCRAMPropertiesLoginModule 
required
+   ;
+};
+
+broker {
+    org.apache.activemq.artemis.spi.core.security.jaas.SCRAMLoginModule 
required
+    ;
+};
diff --git a/artemis-image/examples/amqp_sasl_scram_test__etc/role 
b/artemis-image/examples/amqp_sasl_scram_test__etc/role
new file mode 100644
index 0000000000..bff70b03f7
--- /dev/null
+++ b/artemis-image/examples/amqp_sasl_scram_test__etc/role
@@ -0,0 +1,18 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+users=A
diff --git a/artemis-image/examples/byoc__etc/broker.xml 
b/artemis-image/examples/byoc__etc/broker.xml
new file mode 100644
index 0000000000..425624ed99
--- /dev/null
+++ b/artemis-image/examples/byoc__etc/broker.xml
@@ -0,0 +1,46 @@
+<?xml version='1.0'?>
+<!--
+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.
+-->
+<configuration
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+        xmlns="urn:activemq"
+        xsi:schemaLocation="urn:activemq:core 
schema/artemis-configuration.xsd">
+   <core xmlns="urn:activemq:core">
+
+      <!--
+       Configure an image in the traditional way.
+       Providing boilerplate xml can form the well known configuration for an 
organisational base image that can be further extended with properties
+      -->
+
+      <!-- set an example specific name, it appears in the started/stopped 
logging messages -->
+      <name>byoc</name>
+      <security-enabled>false</security-enabled>
+
+      <!-- broker properties in the image are still in play so there will be 
an acceptor
+         configured from src/main/resources/acceptors.properties -->
+
+      <addresses>
+         <address name="TEST">
+            <anycast>
+               <queue name="TEST"/>
+            </anycast>
+         </address>
+      </addresses>
+   </core>
+</configuration>
\ No newline at end of file
diff --git a/artemis-image/examples/pom.xml b/artemis-image/examples/pom.xml
new file mode 100644
index 0000000000..dee58330f8
--- /dev/null
+++ b/artemis-image/examples/pom.xml
@@ -0,0 +1,77 @@
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+   <modelVersion>4.0.0</modelVersion>
+
+   <parent>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>artemis-pom</artifactId>
+      <version>2.29.0-SNAPSHOT</version>
+      <relativePath>../../pom.xml</relativePath>
+   </parent>
+
+   <artifactId>artemis-image-examples</artifactId>
+   <name>Apache ActiveMQ Artemis Image Examples</name>
+   <packaging>pom</packaging>
+
+   <properties>
+      <!-- for checkstyle plugin -->
+      <activemq.basedir>${project.basedir}/../..</activemq.basedir>
+
+      <!-- for the locked down example user A is referenced in the 
amqp_sasl_scram_test__etc/role file,
+         so don't just change it here! -->
+      <example.user>A</example.user>
+      <!-- a password must be provided to generate the user credential data.
+         use: mvn exec:exec -Dexample.pwd=xyz on the command line to register 
your value in the example.user.file -->
+      <example.pwd></example.pwd>
+      <example.user.file>amqp_sasl_scram_test__etc/user</example.user.file>
+   </properties>
+
+   <dependencies>
+      <dependency>
+         <groupId>org.apache.activemq</groupId>
+         <artifactId>artemis-server</artifactId>
+         <version>${project.parent.version}</version>
+      </dependency>
+   </dependencies>
+
+
+   <build>
+      <plugins>
+         <!-- to easily create a single salted credential for our 
${example.user.file}-->
+         <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>exec-maven-plugin</artifactId>
+            <version>${exec-maven-plugin.version}</version>
+            <configuration>
+               <executable>java</executable>
+               <arguments>
+                  <argument>-classpath</argument>
+                  <classpath/>
+                  
<argument>org.apache.activemq.artemis.spi.core.security.jaas.SCRAMPropertiesLoginModule</argument>
+                  <argument>${example.user}</argument>
+                  <argument>${example.pwd}</argument>
+               </arguments>
+               <outputFile>${example.user.file}</outputFile>
+            </configuration>
+         </plugin>
+      </plugins>
+   </build>
+
+</project>
diff --git a/artemis-image/pom.xml b/artemis-image/pom.xml
new file mode 100644
index 0000000000..f580745127
--- /dev/null
+++ b/artemis-image/pom.xml
@@ -0,0 +1,105 @@
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+   <modelVersion>4.0.0</modelVersion>
+
+   <parent>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>artemis-pom</artifactId>
+      <version>2.29.0-SNAPSHOT</version>
+   </parent>
+
+   <artifactId>artemis-image</artifactId>
+   <name>Apache ActiveMQ Artemis Image</name>
+
+   <properties>
+
+      <!-- base jre image, reproducible build and single pull with @sha 
reference -->
+      
<fromImage>eclipse-temurin:20-jre@sha256:5340605ada8bee017109147c838a96a24ecec037bedac5f157b26817ab633e02</fromImage>
+
+      <!-- for checkstyle plugin -->
+      <activemq.basedir>${project.basedir}/..</activemq.basedir>
+      <!-- none of the surefire project defaults are relevant to the tests 
here -->
+      <activemq-surefire-argline></activemq-surefire-argline>
+
+   </properties>
+
+
+   <dependencies>
+      <dependency>
+         <groupId>org.apache.activemq</groupId>
+         <artifactId>apache-artemis</artifactId>
+         <version>${project.version}</version>
+         <type>pom</type>
+      </dependency>
+      <dependency>
+         <groupId>junit</groupId>
+         <artifactId>junit</artifactId>
+         <version>${junit.version}</version>
+         <scope>test</scope>
+      </dependency>
+      <!-- The johnzon-core and json-api contents are repackaged in -commons,
+           However maven can still need them during tests that don't see the 
shaded bits during build -->
+      <dependency>
+         <groupId>org.apache.johnzon</groupId>
+         <artifactId>johnzon-core</artifactId>
+         <scope>test</scope>
+      </dependency>
+      <dependency>
+         <groupId>jakarta.json</groupId>
+         <artifactId>jakarta.json-api</artifactId>
+         <scope>test</scope>
+      </dependency>
+   </dependencies>
+
+   <build>
+      <plugins>
+         <plugin>
+            <groupId>com.google.cloud.tools</groupId>
+            <artifactId>jib-maven-plugin</artifactId>
+            <configuration>
+               <from>
+                  <image>${fromImage}</image>
+               </from>
+               <to>
+                  
<image>target/activemq-artemis-image:${project.version}</image>
+               </to>
+               <container>
+                  
<mainClass>org.apache.activemq.artemis.core.server.embedded.Main</mainClass>
+                  <ports>
+                     <port>61616</port>
+                  </ports>
+                  <format>OCI</format>
+               </container>
+            </configuration>
+            <executions>
+               <execution>
+                  <id>now</id>
+                  <!-- build from command line with: mvn jib:buildTar@now -->
+                  <phase>none</phase>
+                  <goals>
+                     <goal>buildTar</goal>
+                  </goals>
+               </execution>
+            </executions>
+         </plugin>
+      </plugins>
+   </build>
+
+</project>
diff --git a/artemis-image/src/main/jib/config/acceptor.properties 
b/artemis-image/src/main/jib/config/acceptor.properties
new file mode 100644
index 0000000000..526af5e590
--- /dev/null
+++ b/artemis-image/src/main/jib/config/acceptor.properties
@@ -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.
+
+acceptorConfigurations.tcp.factoryClassName=org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory
+acceptorConfigurations.tcp.params.host=0.0.0.0
+acceptorConfigurations.tcp.params.port=61616
+
+# free for all with all protocols - good for demos
+securityEnabled=false
diff --git a/artemis-image/src/main/resources/log4j2.properties 
b/artemis-image/src/main/resources/log4j2.properties
new file mode 100644
index 0000000000..a0296fb6b0
--- /dev/null
+++ b/artemis-image/src/main/resources/log4j2.properties
@@ -0,0 +1,20 @@
+# 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.
+
+appender.stdout.name = STDOUT
+appender.stdout.type = Console
+
+# default config in log4j is error, we want info by default
+rootLogger = info, STDOUT
\ No newline at end of file
diff --git 
a/artemis-image/src/test/java/org/apache/activemq/artemis/ActiveMQImageExamplesTest.java
 
b/artemis-image/src/test/java/org/apache/activemq/artemis/ActiveMQImageExamplesTest.java
new file mode 100644
index 0000000000..4a205845c1
--- /dev/null
+++ 
b/artemis-image/src/test/java/org/apache/activemq/artemis/ActiveMQImageExamplesTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+package org.apache.activemq.artemis;
+
+import java.lang.invoke.MethodHandles;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
+import org.apache.activemq.artemis.core.server.ActiveMQServer;
+import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ;
+import org.apache.activemq.artemis.core.server.embedded.Main;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static 
org.apache.activemq.artemis.core.server.embedded.Main.configureDataDirectory;
+
+public class ActiveMQImageExamplesTest {
+
+   private static final Logger logger = 
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+   @Test
+   public void testSamlScram_etc() throws Exception {
+
+      ConfigurationImpl configuration = new ConfigurationImpl();
+
+      String dataDir = "./target/data";
+
+      configureDataDirectory(configuration, dataDir);
+
+      EmbeddedActiveMQ server = new EmbeddedActiveMQ();
+      // look for properties files to augment configuration
+      
server.setPropertiesResourcePath("./src/main/resources/,./examples/amqp_sasl_scram_test__etc/");
+      server.setConfiguration(configuration);
+
+      server.start();
+
+      server.stop();
+
+   }
+
+   @Test
+   public void testBYOC_etc() throws Exception {
+
+      final CountDownLatch done = new CountDownLatch(1);
+      Thread thread = new Thread(() -> {
+         try {
+            // contents byoc__etc copied to ./target/ to satisfy etc/broker.xml
+            Main.main(new String[] {"./target"});
+            done.countDown();
+         } catch (Exception e) {
+            logger.info("unexpected", e);
+         }
+      });
+
+      thread.start();
+
+      // shut it down after it starts!
+      do  {
+         if (Main.getEmbeddedServer() != null) {
+            if (Main.getEmbeddedServer().getActiveMQServer() != null) {
+               if (Main.getEmbeddedServer().getActiveMQServer().getState() == 
ActiveMQServer.SERVER_STATE.STARTED) {
+                  logger.trace("stopping server, state={}", 
Main.getEmbeddedServer().getActiveMQServer().getState());
+                  Main.getEmbeddedServer().stop();
+               }
+            }
+         }
+      }
+      while (!done.await(200, TimeUnit.MILLISECONDS));
+   }
+}
\ No newline at end of file
diff --git 
a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/embedded/EmbeddedJMS.java
 
b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/embedded/EmbeddedJMS.java
index 4904242c7b..150988317e 100644
--- 
a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/embedded/EmbeddedJMS.java
+++ 
b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/embedded/EmbeddedJMS.java
@@ -105,7 +105,7 @@ public class EmbeddedJMS extends EmbeddedActiveMQ {
 
    @Override
    public EmbeddedJMS start() throws Exception {
-      super.initStart();
+      super.createActiveMQServer();
       if (jmsConfiguration != null) {
          serverManager = new JMSServerManagerImpl(activeMQServer, 
jmsConfiguration);
       } else {
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/EmbeddedActiveMQ.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/EmbeddedActiveMQ.java
index 197134dd04..26190d68d0 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/EmbeddedActiveMQ.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/EmbeddedActiveMQ.java
@@ -130,12 +130,15 @@ public class EmbeddedActiveMQ {
    }
 
    public EmbeddedActiveMQ start() throws Exception {
-      initStart();
+      createActiveMQServer();
       activeMQServer.start();
       return this;
    }
 
-   protected void initStart() throws Exception {
+   public void createActiveMQServer() throws Exception {
+      if (activeMQServer != null) {
+         return;
+      }
       if (configuration == null) {
          if (configResourcePath == null)
             configResourcePath = "broker.xml";
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/Main.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/Main.java
new file mode 100644
index 0000000000..cf3517d308
--- /dev/null
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/Main.java
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+package org.apache.activemq.artemis.core.server.embedded;
+
+import java.io.File;
+import java.lang.invoke.MethodHandles;
+import java.util.concurrent.CountDownLatch;
+
+import org.apache.activemq.artemis.core.config.FileDeploymentManager;
+import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
+import org.apache.activemq.artemis.core.config.impl.FileConfiguration;
+import org.apache.activemq.artemis.core.config.impl.LegacyJMSConfiguration;
+import org.apache.activemq.artemis.core.server.ActivateCallback;
+import org.apache.activemq.artemis.core.server.ActiveMQServer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Main {
+
+   private static final Logger logger = 
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+   private static String workDir = "/app";
+   private static volatile EmbeddedActiveMQ embeddedServer;
+
+   public static void main(String[] args) throws Exception {
+
+      if (args.length == 1) {
+         workDir = args[0];
+         logger.debug("User supplied work dir {}", workDir);
+      }
+
+      String propertiesConfigPath = "/config/," + workDir + "/etc/";
+      if (args.length == 2) {
+         propertiesConfigPath = args[1];
+         logger.debug("User supplied properties config path {}", 
propertiesConfigPath);
+      }
+
+      FileConfiguration configuration = new FileConfiguration();
+
+      String dataDir = workDir + "/data";
+      configureDataDirectory(configuration, dataDir);
+
+      File bringYourOwnXml = new File(workDir + "/etc/broker.xml");
+      if (bringYourOwnXml.exists()) {
+         logger.debug("byo config found {}", bringYourOwnXml);
+         configuration = loadFromXmlFile(bringYourOwnXml, configuration);
+      }
+
+      embeddedServer = new EmbeddedActiveMQ();
+      // look for properties files to augment configuration
+      embeddedServer.setPropertiesResourcePath(propertiesConfigPath);
+      embeddedServer.setConfiguration(configuration);
+      embeddedServer.createActiveMQServer();
+
+      final ActiveMQServer activeMQServer = embeddedServer.getActiveMQServer();
+      final CountDownLatch serverStopped = new CountDownLatch(1);
+      registerCallbackToTriggerLatchOnStopped(activeMQServer, serverStopped);
+      exitWithErrorOnStartFailure(activeMQServer);
+      addShutdownHookForServerStop(embeddedServer);
+
+      logger.debug("starting server");
+      embeddedServer.start();
+
+      logger.debug("await server stop");
+      serverStopped.await();
+      embeddedServer = null;
+   }
+
+   private static void exitWithErrorOnStartFailure(ActiveMQServer 
activeMQServer) {
+      activeMQServer.registerActivationFailureListener(exception -> {
+         logger.error("server failed to start {}, exit(1) in thread", 
exception);
+         new Thread("exit(1)-on-start-failure") {
+            @Override
+            public void run() {
+               logger.error("exit(1)");
+               Runtime.getRuntime().exit(1);
+            }
+         }.start();
+      });
+   }
+
+   private static void registerCallbackToTriggerLatchOnStopped(ActiveMQServer 
activeMQServer, CountDownLatch serverStopped) {
+      activeMQServer.registerActivateCallback(new ActivateCallback() {
+
+         @Override
+         public void stop(ActiveMQServer server) {
+            logger.trace("server stop, state {}", server.getState());
+            serverStopped.countDown();
+         }
+
+         @Override
+         public void shutdown(ActiveMQServer server) {
+            logger.trace("server shutdown, state {}", server.getState());
+            serverStopped.countDown();
+         }
+      });
+   }
+
+   private static void addShutdownHookForServerStop(final EmbeddedActiveMQ 
server) {
+      Runtime.getRuntime().addShutdownHook(new Thread("shutdown-hook") {
+         @Override
+         public void run() {
+            try {
+               logger.trace("stop via shutdown hook");
+               server.stop();
+            } catch (Exception ignored) {
+               // we want to exit fast and silently
+               logger.trace("Error on stop {}", ignored);
+            }
+         }
+      });
+   }
+
+   public static FileConfiguration loadFromXmlFile(File bringYourOwnXml, 
FileConfiguration base) throws Exception {
+      FileDeploymentManager deploymentManager = new 
FileDeploymentManager(bringYourOwnXml.toURI().toASCIIString());
+      LegacyJMSConfiguration legacyJMSConfiguration = new 
LegacyJMSConfiguration(base);
+      
deploymentManager.addDeployable(base).addDeployable(legacyJMSConfiguration);
+      deploymentManager.readConfiguration();
+      return base;
+   }
+
+   public static void configureDataDirectory(ConfigurationImpl configuration, 
String dataDir) {
+      // any provided value via xml config or properties will override
+      configuration.setJournalDirectory(dataDir);
+      // setting these gives a better log message, not necessary otherwise
+      configuration.setBindingsDirectory(dataDir + "/bindings");
+      configuration.setLargeMessagesDirectory(dataDir + "/largemessages");
+      configuration.setPagingDirectory(dataDir + "/paging");
+   }
+
+   public static EmbeddedActiveMQ getEmbeddedServer() {
+      return embeddedServer;
+   }
+}
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
index b01a3ca759..425069f49c 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
@@ -608,6 +608,7 @@ public class ActiveMQServerImpl implements ActiveMQServer {
          internalStart();
       } catch (Throwable t) {
          ActiveMQServerLogger.LOGGER.failedToStartServer(t);
+         throw t;
       } finally {
          if (originalState == SERVER_STATE.STOPPED) {
             reloadNetworkHealthCheck();
diff --git 
a/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/embedded/MainTest.java
 
b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/embedded/MainTest.java
new file mode 100644
index 0000000000..92e1d532ac
--- /dev/null
+++ 
b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/embedded/MainTest.java
@@ -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.
+ */
+package org.apache.activemq.artemis.core.server.embedded;
+
+import java.io.IOException;
+
+import org.junit.Test;
+
+
+public class MainTest {
+
+   @Test(expected = IOException.class)
+   public void testNull() throws Exception {
+      Main.main(new String[]{});
+   }
+}
diff --git a/pom.xml b/pom.xml
index dbaf2b603e..1d45a24f9a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -68,6 +68,8 @@
       <module>artemis-features</module>
       <module>artemis-quorum-api</module>
       <module>artemis-quorum-ri</module>
+      <module>artemis-image</module>
+      <module>artemis-image/examples</module>
    </modules>
 
    <name>ActiveMQ Artemis Parent</name>
@@ -105,6 +107,7 @@
       <errorprone.version>2.10.0</errorprone.version>
       <maven.bundle.plugin.version>5.1.9</maven.bundle.plugin.version>
       <maven.checkstyle.plugin.version>3.1.2</maven.checkstyle.plugin.version>
+      <jib.maven.plugin.version>3.3.2</jib.maven.plugin.version>
       <sevntu.checks.version>1.39.0</sevntu.checks.version>
       <checkstyle.version>9.2.1</checkstyle.version>
       <mockito.version>5.2.0</mockito.version>
@@ -1892,6 +1895,11 @@
                </artifactItems>
             </configuration>
          </plugin>
+         <plugin>
+            <groupId>com.google.cloud.tools</groupId>
+            <artifactId>jib-maven-plugin</artifactId>
+            <version>${jib.maven.plugin.version}</version>
+         </plugin>
       </plugins>
    </build>
 


Reply via email to