All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.alfresco.testcontainers.AlfrescoContainer Maven / Gradle / Ivy

package org.alfresco.testcontainers;

import org.testcontainers.activemq.ActiveMQContainer;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.containers.wait.strategy.HttpWaitStrategy;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.utility.DockerImageName;

import java.time.Duration;

/**
 * The Alfresco Community Docker container which exposes by default port 8080.
 */
public class AlfrescoContainer> extends GenericContainer {

    // Alfresco Community Docker base image
    private static final DockerImageName DEFAULT_ALFRESCO_IMAGE_NAME = DockerImageName.parse("alfresco/alfresco-content-repository-community");

    // PostgreSQL Docker base image
    private static final DockerImageName DEFAULT_POSTGRESQL_IMAGE_NAME = DockerImageName.parse("postgres:15.6");

    // ActiveMQ Docker base image
    private static final DockerImageName DEFAULT_ACTIVEMQ_IMAGE_NAME = DockerImageName.parse("apache/activemq-classic:5.18.3");

    // Default Java tool options for Alfresco
    protected static final String DEFAULT_JAVA_TOOL_OPTIONS =
            """
            -Dencryption.keystore.type=JCEKS
            -Dencryption.cipherAlgorithm=DESede/CBC/PKCS5Padding
            -Dencryption.keyAlgorithm=DESede
            -Dencryption.keystore.location=/usr/local/tomcat/shared/classes/alfresco/extension/keystore/keystore
            -Dmetadata-keystore.password=mp6yc0UD9e
            -Dmetadata-keystore.aliases=metadata
            -Dmetadata-keystore.metadata.password=oKIWzVdEdA
            -Dmetadata-keystore.metadata.algorithm=DESede
            """.replace("\n", " ").trim();

    // Default Java options for Alfresco
    protected static final String DEFAULT_JAVA_OPTS =
            """
            -Ddb.driver=org.postgresql.Driver
            -Ddb.username=alfresco
            -Ddb.password=alfresco
            -Ddb.url=jdbc:postgresql://postgres:5432/alfresco
            -Dindex.subsystem.name=noindex
            -Dlocal.transform.service.enabled=false
            -Drepo.event2.enabled=false
            -Dmessaging.subsystem.autoStart=false
            -Dcsrf.filter.enabled=false
            """.replace("\n", " ").trim();

    // Alfresco Community requires at least one PostgreSQL container, so a shared network is necessary.
    private final Network network;

    // PostgreSQL Container to be used as DB by Alfresco Community
    private PostgreSQLContainer postgresContainer;

    // ActiveMQ Container to be used as Messaging Engine by Alfresco Community
    private ActiveMQContainer activeMQContainer;

    /**
     * Create an Alfresco Community Container by passing the full docker image name.
     *
     * @param version Alfresco docker image version as a {@link String}, like:
     *     7.4.1
     *     23.2.1
     */
    public AlfrescoContainer(String version) {
        this(DockerImageName.parse(DEFAULT_ALFRESCO_IMAGE_NAME.getUnversionedPart() + ":" + version));
    }

    /**
     * Create an Alfresco Community Container by passing the full docker image name.
     *
     * @param dockerImageName Full docker image name as a {@link DockerImageName}, like:
     *      DockerImageName.parse("alfresco/alfresco-content-repository-community:7.4.1")
     *      DockerImageName.parse("alfresco/alfresco-content-repository-community:23.2.1")
     */
    public AlfrescoContainer(final DockerImageName dockerImageName) {
        super(dockerImageName);
        dockerImageName.assertCompatibleWith(DEFAULT_ALFRESCO_IMAGE_NAME);
        this.network = Network.newNetwork();
    }

    /**
     * Generates custom Java options for ActiveMQ, updating the messaging broker URL.
     *
     * @return A string containing the updated Java options.
     */
    private String getActivemqJavaOpts() {
        String brokerAlias = activeMQContainer.getNetworkAliases().get(0);
        String activemqBrokerUrl = String.format(
                "-Dmessaging.broker.url=\"failover:(nio://%s:61616)?timeout=3000&jms.useCompression=true\"", brokerAlias
        );
        return DEFAULT_JAVA_OPTS.replace(
                "-Drepo.event2.enabled=false -Dmessaging.subsystem.autoStart=false ", ""
        ) + " " + activemqBrokerUrl;
    }


    /**
     * Configures the Alfresco container with the necessary environment variables, network, and wait strategy.
     * This method is automatically called during the container initialization.
     */
    @Override
    protected void configure() {
        super.configure();

        if (postgresContainer == null) {
            createDefaultPostgreSQLContainer();
        }

        String javaOpts = activeMQContainer != null ? getActivemqJavaOpts() : DEFAULT_JAVA_OPTS;

        withEnv("JAVA_TOOL_OPTIONS", DEFAULT_JAVA_TOOL_OPTIONS);
        withEnv("JAVA_OPTS", javaOpts);
        withNetwork(network);
        withNetworkAliases("alfresco");
        withExposedPorts(8080);

        waitingFor(new HttpWaitStrategy()
                .forPort(8080)
                .forPath("/alfresco/api/-default-/public/alfresco/versions/1/probes/-ready-")
                .forStatusCodeMatching(response -> response == 200)
                .withStartupTimeout(Duration.ofMinutes(3)));
    }

    /**
     * Starts the Alfresco container and its dependencies, such as PostgreSQL and ActiveMQ.
     * 

* The PostgreSQL container is started first, followed by the ActiveMQ container if present. * Finally, the Alfresco container is started. This ensures that all required services are up * and running before Alfresco attempts to start. *

*/ @Override public void start() { // Apply AlfrescoContainer configuration this.configure(); // Start the PostgreSQL container first as it's essential for Alfresco to function postgresContainer.start(); // Start the ActiveMQ container if it is present, enabling messaging services if (activeMQContainer != null) { activeMQContainer.start(); } // Start the Alfresco container after the dependencies are up and running super.start(); } /** * Stops the Alfresco container and its dependencies, such as PostgreSQL and ActiveMQ. *

* The Alfresco container is stopped first to ensure all processes are gracefully terminated. * The ActiveMQ container is stopped next if it was started, followed by the PostgreSQL container * to ensure data integrity and avoid potential data loss. *

*/ @Override public void stop() { // Stop the PostgreSQL container last as it is crucial for maintaining data integrity try { super.stop(); // Stop the Alfresco container first to ensure all processes are gracefully terminated } finally { // Ensure that the ActiveMQ container is stopped if it was started if (activeMQContainer != null) { activeMQContainer.stop(); } // Stop the PostgreSQL container after other services to avoid data loss postgresContainer.stop(); } } /** * Enable ActiveMQ Messaging service * @return this container instance */ public SELF withMessagingEnabled() { createDefaultActivemqContainer(); return self(); } /** * Gets the network shared by the containers. * * @return The shared network. */ public Network getNetwork() { return network; } /** * Sets the PostgreSQL container to be used by the Alfresco container. * * @param postgreSQLContainer The PostgreSQL container. */ public void setPostgreSQLContainer(PostgreSQLContainer postgreSQLContainer) { this.postgresContainer = postgreSQLContainer; } /** * Gets the PostgreSQL container being used. * * @return The PostgreSQL container. */ public PostgreSQLContainer getPostgreSQLContainer() { return this.postgresContainer; } /** * Creates and configures a default PostgreSQL container for Alfresco. */ public void createDefaultPostgreSQLContainer() { this.postgresContainer = new PostgreSQLContainer<>(DEFAULT_POSTGRESQL_IMAGE_NAME) .withNetwork(network) .withNetworkAliases("postgres") .withPassword("alfresco") .withUsername("alfresco") .withDatabaseName("alfresco") .waitingFor(Wait.forListeningPort().withStartupTimeout(Duration.ofMinutes(2))); } /** * Sets the ActiveMQ container to be used by the Alfresco container. * * @param activemqContainer The ActiveMQ container. */ public void setActivemqContainer(ActiveMQContainer activemqContainer) { this.activeMQContainer = activemqContainer; } /** * Gets the ActiveMQ container being used. * * @return The ActiveMQ container. */ public ActiveMQContainer getActivemqContainer() { return activeMQContainer; } /** * Creates and configures a default ActiveMQ container for Alfresco. */ public void createDefaultActivemqContainer() { activeMQContainer = new ActiveMQContainer(DEFAULT_ACTIVEMQ_IMAGE_NAME) .withNetwork(network) .withNetworkAliases("activemq") .waitingFor(Wait.forListeningPort().withStartupTimeout(Duration.ofMinutes(2))) .withExposedPorts(61616, 8161); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy