/* * JBoss, Home of Professional Open Source * Copyright 2011 Red Hat Inc. and/or its affiliates and other contributors * as indicated by the @authors tag. All rights reserved. * See the copyright.txt in the distribution for a * full listing of individual contributors. * * 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.arquillian.container.impl.client.container; import java.util.List; import java.util.concurrent.Callable; 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.deployment.Deployment; import org.jboss.arquillian.container.spi.client.deployment.DeploymentDescription; import org.jboss.arquillian.container.spi.client.deployment.DeploymentScenario; import org.jboss.arquillian.container.spi.client.protocol.metadata.ProtocolMetaData; import org.jboss.arquillian.container.spi.context.annotation.DeploymentScoped; import org.jboss.arquillian.container.spi.event.DeployDeployment; import org.jboss.arquillian.container.spi.event.DeployManagedDeployments; import org.jboss.arquillian.container.spi.event.DeploymentEvent; import org.jboss.arquillian.container.spi.event.UnDeployDeployment; import org.jboss.arquillian.container.spi.event.UnDeployManagedDeployments; import org.jboss.arquillian.container.spi.event.container.AfterDeploy; import org.jboss.arquillian.container.spi.event.container.AfterUnDeploy; import org.jboss.arquillian.container.spi.event.container.BeforeDeploy; import org.jboss.arquillian.container.spi.event.container.BeforeUnDeploy; import org.jboss.arquillian.container.spi.event.container.DeployerEvent; 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.api.annotation.Observes; /** * Controller for handling all Deployment related operations. <br/> * <br/> * <p> * Fires DeployDeployment events for each deployment that should be deployed during startup. This so the Cores exception * handling * will be triggered if Deployment fails inside the context of the deployment and container. This lets extensions listen * for Exceptions types * and handle them inside the same context. * * @author <a href="mailto:aslak@redhat.com">Aslak Knutsen</a> * @version $Revision: $ */ public class ContainerDeployController { @Inject private Instance<ContainerRegistry> containerRegistry; @Inject private Instance<DeploymentScenario> deploymentScenario; @Inject private Instance<Injector> injector; /** * Deploy all deployments marked as managed = true. * * @throws Exception */ public void deployManaged(@Observes DeployManagedDeployments event) throws Exception { forEachManagedDeployment(new Operation<Container, Deployment>() { @Inject private Event<DeploymentEvent> event; @Override public void perform(Container container, Deployment deployment) throws Exception { //when a container is manually controlled, the deployment is deployed automatically //once the container is manually started, not now if (!"manual".equals(container.getContainerConfiguration().getMode())) { if (container.getState() != State.STARTED) { throw new IllegalStateException("Trying to deploy a managed deployment " + deployment.getDescription().getName() + " to a non started managed container " + container.getName()); } event.fire(new DeployDeployment(container, deployment)); } } }); } /** * Undeploy all deployments marked as managed, and all manually deployed. * * @throws Exception */ public void undeployManaged(@Observes UnDeployManagedDeployments event) throws Exception { forEachDeployedDeployment(new Operation<Container, Deployment>() { @Inject private Event<DeploymentEvent> event; @Override public void perform(Container container, Deployment deployment) throws Exception { if (container.getState().equals(Container.State.STARTED) && deployment.isDeployed()) { event.fire(new UnDeployDeployment(container, deployment)); } } }); } public void deploy(@Observes final DeployDeployment event) throws Exception { executeOperation(new Callable<Void>() { @Inject private Event<DeployerEvent> deployEvent; @Inject @DeploymentScoped private InstanceProducer<DeploymentDescription> deploymentDescriptionProducer; @Inject @DeploymentScoped private InstanceProducer<Deployment> deploymentProducer; @Inject @DeploymentScoped private InstanceProducer<ProtocolMetaData> protocolMetadata; @Override public Void call() throws Exception { DeployableContainer<?> deployableContainer = event.getDeployableContainer(); Deployment deployment = event.getDeployment(); DeploymentDescription deploymentDescription = deployment.getDescription(); /* * TODO: should the DeploymentDescription producer some how be automatically registered ? * Or should we just 'know' who is the first one to create the context */ deploymentDescriptionProducer.set(deploymentDescription); deploymentProducer.set(deployment); deployEvent.fire(new BeforeDeploy(deployableContainer, deploymentDescription)); try { if (deploymentDescription.isArchiveDeployment()) { protocolMetadata.set(deployableContainer.deploy( deploymentDescription.getTestableArchive() != null ? deploymentDescription.getTestableArchive() : deploymentDescription.getArchive())); } else { deployableContainer.deploy(deploymentDescription.getDescriptor()); } deployment.deployed(); } catch (Exception e) { deployment.deployedWithError(e); throw e; } deployEvent.fire(new AfterDeploy(deployableContainer, deploymentDescription)); return null; } }); } public void undeploy(@Observes final UnDeployDeployment event) throws Exception { executeOperation(new Callable<Void>() { @Inject private Event<DeployerEvent> deployEvent; @Override public Void call() throws Exception { DeployableContainer<?> deployableContainer = event.getDeployableContainer(); Deployment deployment = event.getDeployment(); DeploymentDescription description = deployment.getDescription(); deployEvent.fire(new BeforeUnDeploy(deployableContainer, description)); try { if (deployment.getDescription().isArchiveDeployment()) { try { deployableContainer.undeploy( description.getTestableArchive() != null ? description.getTestableArchive() : description.getArchive()); } catch (Exception e) { if (!deployment.hasDeploymentError()) { throw e; } } } else { deployableContainer.undeploy(description.getDescriptor()); } } finally { deployment.undeployed(); } deployEvent.fire(new AfterUnDeploy(deployableContainer, description)); return null; } }); } private void forEachManagedDeployment(Operation<Container, Deployment> operation) throws Exception { DeploymentScenario scenario = this.deploymentScenario.get(); if (scenario == null) { return; } forEachDeployment(scenario.managedDeploymentsInDeployOrder(), operation); } private void forEachDeployedDeployment(Operation<Container, Deployment> operation) throws Exception { DeploymentScenario scenario = this.deploymentScenario.get(); if (scenario == null) { return; } forEachDeployment(scenario.deployedDeploymentsInUnDeployOrder(), operation); } private void forEachDeployment(List<Deployment> deployments, Operation<Container, Deployment> operation) throws Exception { injector.get().inject(operation); ContainerRegistry containerRegistry = this.containerRegistry.get(); if (containerRegistry == null) { return; } for (Deployment deployment : deployments) { Container container = containerRegistry.getContainer(deployment.getDescription().getTarget()); operation.perform(container, deployment); } } private void executeOperation(Callable<Void> operation) throws Exception { injector.get().inject(operation); operation.call(); } public interface Operation<T, X> { void perform(T container, X deployment) throws Exception; } }