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

org.jboss.as.arquillian.container.domain.CommonDomainDeployableContainer Maven / Gradle / Ivy

There is a newer version: 5.1.0.Beta4
Show newest version
/*
 * Copyright 2015 Red Hat, Inc.
 *
 * Licensed 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.jboss.as.arquillian.container.domain;

import java.net.URI;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jboss.arquillian.config.descriptor.api.ContainerDef;
import org.jboss.arquillian.config.descriptor.impl.ContainerDefImpl;
import org.jboss.arquillian.container.spi.Container;
import org.jboss.arquillian.container.spi.Container.State;
import org.jboss.arquillian.container.spi.ContainerRegistry;
import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
import org.jboss.arquillian.container.spi.client.container.DeploymentException;
import org.jboss.arquillian.container.spi.client.container.LifecycleException;
import org.jboss.arquillian.container.spi.client.protocol.ProtocolDescription;
import org.jboss.arquillian.container.spi.client.protocol.metadata.ProtocolMetaData;
import org.jboss.arquillian.container.spi.context.annotation.ContainerScoped;
import org.jboss.arquillian.container.spi.event.SetupContainer;
import org.jboss.arquillian.core.api.Event;
import org.jboss.arquillian.core.api.Injector;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.InstanceProducer;
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.arquillian.core.spi.ServiceLoader;
import org.jboss.as.arquillian.container.domain.Domain.Server;
import org.jboss.as.arquillian.container.domain.Domain.ServerGroup;
import org.jboss.as.controller.client.ModelControllerClient;
import org.jboss.as.controller.client.ModelControllerClientConfiguration;
import org.jboss.as.controller.client.helpers.DelegatingModelControllerClient;
import org.jboss.as.controller.client.helpers.domain.DomainClient;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.descriptor.api.Descriptor;
import org.wildfly.arquillian.domain.ServerGroupArchive;
import org.wildfly.arquillian.domain.api.DomainManager;

/**
 * @author Aslak Knutsen
 * @version $Revision: $
 */
public abstract class CommonDomainDeployableContainer implements
        DeployableContainer {

    @Inject
    private Instance containerRegistryInstance;

    @Inject
    private Instance serviceLoaderInstance;

    @Inject
    private Instance injectorInst;

    @Inject
    private Instance containerInst;

    @Inject // we need to fire setup events to trigger the container context creation
    private Event setupEvent;

    private final Logger log = Logger.getLogger(CommonDomainDeployableContainer.class.getName());
    private T containerConfig;
    private ManagementClient managementClient;
    private volatile ContainerDomainManager domainManager;

    @Inject
    @ContainerScoped
    private InstanceProducer archiveDeployerInst;

    @Inject
    @ContainerScoped
    private InstanceProducer managementClientInst;

    @Inject
    @ContainerScoped
    private InstanceProducer domainInst;

    @Override
    public ProtocolDescription getDefaultProtocol() {
        return new ProtocolDescription("Servlet 5.0");
    }

    @Override
    public void setup(T config) {
        containerConfig = config;

        // Register on setup so these can be injected into manual mode client tests
        final DomainClient domainClient = DomainClient.Factory.create(new DelegatingModelControllerClient(DomainDelegateProvider.INSTANCE));
        domainManager = new ContainerDomainManager(getContainerName(), isControllable(), domainClient);
        managementClient = new ManagementClient(domainClient, domainManager);
        managementClientInst.set(managementClient);

        ArchiveDeployer archiveDeployer = new ArchiveDeployer(managementClient);
        archiveDeployerInst.set(archiveDeployer);
    }

    @Override
    public void start() throws LifecycleException {
        // Create a client configuration builder from the container configuration
        final ModelControllerClientConfiguration.Builder clientConfigBuilder = new ModelControllerClientConfiguration.Builder()
                .setHostName(containerConfig.getManagementHostName())
                .setPort(containerConfig.getManagementPort());

        if (containerConfig.getUsername() != null) {
            Authentication.username = containerConfig.getUsername();
            Authentication.password = containerConfig.getPassword();
            clientConfigBuilder.setHandler(Authentication.getCallbackHandler());
        }

        final String authenticationConfig = containerConfig.getAuthenticationConfig();

        // Check for an Elytron configuration
        if (authenticationConfig != null) {
            clientConfigBuilder.setAuthenticationConfigUri(URI.create(authenticationConfig));
        }

        // Configure the current client and set the delegate for the provider so the same management client can be used
        // during starts and stops
        DomainDelegateProvider.INSTANCE.setDelegate(ModelControllerClient.Factory.create(clientConfigBuilder.build()));

        try {
            startInternal();
        } catch (LifecycleException e) {
            safeCloseClient();
            throw e;
        }

        ContainerRegistry registry = containerRegistryInstance.get();

        Map containerNameMap = containerConfig.getContainerNameMap();
        Map modeMap = containerConfig.getContainerModeMap();

        Domain domain = managementClient.createDomain(containerNameMap);
        domainInst.set(domain);

        // Register all ServerGroups
        for (ServerGroup serverGroup: domain.getServerGroups()) {
            Container serverContainer = createServerGroupContainer(registry, archiveDeployerInst.get(), domain, serverGroup);
            String mode = mapMode(modeMap, serverContainer.getName());
            if(mode != null) {
                serverContainer.getContainerConfiguration().setMode(mode);
            }
            setupEvent.fire(new SetupContainer(serverContainer));
            serverContainer.setState(Container.State.STARTED);
        }

        // Register all Servers
        for (Server server : domain.getServers()) {
            Container serverContainer = createServerContainer(registry, server);
            String mode = mapMode(modeMap, serverContainer.getName());
            if(mode != null) {
                serverContainer.getContainerConfiguration().setMode(mode);
            }
            String serverStatus = managementClient.getServerState(server);

            setupEvent.fire(new SetupContainer(serverContainer));
            if (serverStatus.equals("STARTED")) {
                serverContainer.setState(Container.State.STARTED);
            } else {
                serverContainer.setState(Container.State.STOPPED);
            }
        }
        domainManager.setContainerStarted(true);
    }

    @Override
    public final void stop() throws LifecycleException {
        domainManager.setContainerStarted(false);
        try {
            updateDomainMembersState(State.STOPPED);
            stopInternal();
        } finally {
            safeCloseClient();
        }
    }

    protected abstract void startInternal() throws LifecycleException;

    protected abstract void stopInternal() throws LifecycleException;

    @Override
    public ProtocolMetaData deploy(Archive archive) throws DeploymentException {
        // Get all the server groups we're deploying to
        final Set serverGroups = getServerGroups(archive);
        if (!serverGroups.isEmpty()) {
            final ProtocolMetaData metaData = new ProtocolMetaData();
            final ArchiveDeployer deployer = archiveDeployerInst.get();
            final String uniqueName = deployer.deploy(archive, serverGroups);
            final Domain domain = domainInst.get();
            for (String serverGroupName : serverGroups) {
                for (Server server : domain.getServersInGroup(serverGroupName)) {
                    metaData.addContext(new LazyHttpContext(server, uniqueName, managementClient));
                }
            }
            return metaData;
        }
        throw new DeploymentException("Could not determine the server-group to deploy the archive to.");
    }

    @Override
    public void undeploy(Archive archive) throws DeploymentException {
        // Get all the server groups we're deploying to
        final Set serverGroups = getServerGroups(archive);
        if (!serverGroups.isEmpty()) {
            final ArchiveDeployer deployer = archiveDeployerInst.get();
            deployer.undeploy(archive.getName(), serverGroups);
        } else {
            throw new DeploymentException("Could not determine the server-group for the undeploy.");
        }
    }

    @Override
    public void deploy(Descriptor descriptor) throws DeploymentException {
        throw new UnsupportedOperationException("Can not deploy directly from a Domain Controller");
    }

    @Override
    public void undeploy(Descriptor descriptor) throws DeploymentException {
        throw new UnsupportedOperationException("Can not undeploy directly from a Domain Controller");
    }

    /**
     * Returns the domain manager used for this container.
     *
     * 

* Do note this may return {@code null} if {@link #setup(CommonDomainContainerConfiguration)} has not been invoked. *

* * @return the domain manager used */ public DomainManager getDomainManager() { return domainManager; } protected T getContainerConfiguration() { return containerConfig; } protected ManagementClient getManagementClient() { return managementClient; } protected ModelControllerClient getModelControllerClient() { return managementClient.getControllerClient(); } private void safeCloseClient() { try { managementClient.close(); } catch (Exception e) { log.log(Level.WARNING, "Caught exception closing ModelControllerClient", e); } finally { DomainDelegateProvider.INSTANCE.setDelegate(null); } } private Container createServerContainer(ContainerRegistry registry, final Server server) { ContainerDef def = new ContainerDefImpl("arquillian") .container(server.getContainerName()) .setMode(getContainerMode()); return registry.create(def, new ServiceLoader() { @Override public X onlyOne(Class serviceClass, Class defaultServiceClass) { return serviceLoaderInstance.get().onlyOne(serviceClass, defaultServiceClass); } @Override public X onlyOne(Class serviceClass) { if (serviceClass == DeployableContainer.class) { return serviceClass.cast(injectorInst.get().inject(new ServerContainer(domainManager, server))); } return serviceLoaderInstance.get().onlyOne(serviceClass); } @Override public Collection all(Class serviceClass) { return serviceLoaderInstance.get().all(serviceClass); } }); } private Container createServerGroupContainer(ContainerRegistry registry, final ArchiveDeployer archiveDeployer, final Domain domain, final ServerGroup serverGroup) { ContainerDef def = new ContainerDefImpl("arquillian") .container(serverGroup.getContainerName()) .setMode(getContainerMode()); return registry.create(def, new ServiceLoader() { @Override public X onlyOne(Class serviceClass, Class defaultServiceClass) { return serviceLoaderInstance.get().onlyOne(serviceClass, defaultServiceClass); } @Override public X onlyOne(Class serviceClass) { if (serviceClass == DeployableContainer.class) { return serviceClass.cast(injectorInst.get().inject( new ServerGroupContainer(managementClient, archiveDeployer, domain, serverGroup, domainManager))); } return serviceLoaderInstance.get().onlyOne(serviceClass); } @Override public Collection all(Class serviceClass) { return serviceLoaderInstance.get().all(serviceClass); } }); } /** * Update all Arquillian Containers in the Domain (group and server) with the new State. * * The Domain Controller can start/stop nodes outside of Arquillian's control. */ private void updateDomainMembersState(State newState) { ContainerRegistry registry = containerRegistryInstance.get(); Domain domain = domainInst.get(); for (Server server : domain.getServers()) { registry.getContainer(server.getContainerName()).setState(newState); } for (ServerGroup group : domain.getServerGroups()) { registry.getContainer(group.getContainerName()).setState(newState); } } private String mapMode(Map modeMap, String name) { for(Map.Entry entry : modeMap.entrySet()) { if(name.matches(entry.getKey())) { log.info("Mapping " + name + " to container mode " + entry.getValue() + " based on expression " + entry.getKey()); return entry.getValue(); } } return null; } private String getContainerMode() { final Container container = containerInst.get(); return container.getContainerConfiguration().getMode(); } private String getContainerName() { final Container container = containerInst.get(); return container.getName(); } private boolean isControllable() { final String mode = getContainerMode(); return "manual".equalsIgnoreCase(mode) || "custom".equalsIgnoreCase(mode); } private static Set getServerGroups(final Archive archive) throws DeploymentException { if (archive instanceof ServerGroupArchive) { return ((ServerGroupArchive) archive).getServerGroups(); } throw new DeploymentException("Could not determine the server-group to deploy the archive to."); } private static class DomainDelegateProvider implements DelegatingModelControllerClient.DelegateProvider { static final DomainDelegateProvider INSTANCE = new DomainDelegateProvider(); private final AtomicReference delegate; private DomainDelegateProvider() { this.delegate = new AtomicReference<>(); } void setDelegate(final ModelControllerClient client) { delegate.set(client); } @Override public ModelControllerClient getDelegate() { final ModelControllerClient result = delegate.get(); if (result == null) { throw new IllegalStateException("The client has been closed. Ensure the container has been started."); } return result; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy