/*
* JBoss, Home of Professional Open Source
* Copyright 2010 Red Hat Inc. and/or its affiliates and other contributors
* by the @authors tag. 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.test.impl.client.deployment;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.jboss.arquillian.container.spi.Container;
import org.jboss.arquillian.container.spi.ContainerRegistry;
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.deployment.TargetDescription;
import org.jboss.arquillian.container.spi.client.protocol.ProtocolDescription;
import org.jboss.arquillian.container.test.api.TargetsContainer;
import org.jboss.arquillian.container.test.impl.client.deployment.event.GenerateDeployment;
import org.jboss.arquillian.container.test.impl.domain.ProtocolDefinition;
import org.jboss.arquillian.container.test.impl.domain.ProtocolRegistry;
import org.jboss.arquillian.container.test.spi.TestDeployment;
import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor;
import org.jboss.arquillian.container.test.spi.client.deployment.AuxiliaryArchiveAppender;
import org.jboss.arquillian.container.test.spi.client.deployment.AuxiliaryArchiveProcessor;
import org.jboss.arquillian.container.test.spi.client.deployment.DeploymentPackager;
import org.jboss.arquillian.container.test.spi.client.deployment.DeploymentScenarioGenerator;
import org.jboss.arquillian.container.test.spi.client.deployment.ProtocolArchiveProcessor;
import org.jboss.arquillian.container.test.spi.client.protocol.Protocol;
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;
import org.jboss.arquillian.core.spi.ServiceLoader;
import org.jboss.arquillian.test.spi.TestClass;
import org.jboss.arquillian.test.spi.annotation.ClassScoped;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.container.ClassContainer;
/**
* DeploymentGenerator
*
* @author <a href="mailto:aslak@redhat.com">Aslak Knutsen</a>
* @version $Revision: $
*/
public class DeploymentGenerator {
@Inject
private Instance<ServiceLoader> serviceLoader;
@Inject
@ClassScoped
private InstanceProducer<DeploymentScenario> deployment;
@Inject
private Instance<ContainerRegistry> containerRegistry;
@Inject
private Instance<ProtocolRegistry> protocolRegistry;
public void generateDeployment(@Observes GenerateDeployment event) {
DeploymentScenarioGenerator generator = serviceLoader.get().onlyOne(
DeploymentScenarioGenerator.class, AnnotationDeploymentScenarioGenerator.class);
DeploymentScenario scenario = new DeploymentScenario();
for (DeploymentDescription deployment : generator.generate(event.getTestClass())) {
scenario.addDeployment(deployment);
}
validate(scenario);
createTestableDeployments(scenario, event.getTestClass());
deployment.set(scenario);
}
//-------------------------------------------------------------------------------------||
// Validate DeploymentScenario --------------------------------------------------------||
//-------------------------------------------------------------------------------------||
protected void validate(DeploymentScenario scenario) {
ContainerRegistry conReg = containerRegistry.get();
for (TargetDescription target : scenario.targets()) {
Container container = conReg.getContainer(target);
if (container == null) {
throwTargetNotFoundValidationException(conReg, target);
}
}
for (Deployment deployment : scenario.deployments()) {
Container container = conReg.getContainer(deployment.getDescription().getTarget());
if ("custom".equalsIgnoreCase(container.getContainerConfiguration().getMode())) {
if (deployment.getDescription().managed()) {
throw new ValidationException(
"Deployment "
+ deployment.getDescription().getName()
+ " is targeted against container "
+
container.getName()
+ ". This container is set to mode custom which can not handle managed deployments. "
+
"Please verify the @"
+ TargetsContainer.class.getName()
+ " annotation or container@mode in arquillian.xml");
}
}
}
ProtocolRegistry proReg = protocolRegistry.get();
for (ProtocolDescription proDesc : scenario.protocols()) {
if (ProtocolDescription.DEFAULT.equals(proDesc)) {
continue;
}
ProtocolDefinition protocol = proReg.getProtocol(proDesc);
if (protocol == null) {
throw new ValidationException(DeploymentScenario.class.getSimpleName()
+ " contains protocols not maching any defined Protocol in the registry. " + proDesc.getName());
}
}
}
//-------------------------------------------------------------------------------------||
// Enrich with Protocol Packaging -----------------------------------------------------||
//-------------------------------------------------------------------------------------||
/**
* @param scenario
*/
private void createTestableDeployments(DeploymentScenario scenario, TestClass testCase) {
ProtocolRegistry protoReg = protocolRegistry.get();
buildTestableDeployments(scenario, testCase, protoReg);
}
private void buildTestableDeployments(DeploymentScenario scenario, TestClass testCase, ProtocolRegistry protoReg) {
for (Deployment deployment : scenario.deployments()) {
DeploymentDescription description = deployment.getDescription();
if (!description.testable() || !description.isArchiveDeployment()) {
continue;
}
List<Archive<?>> auxiliaryArchives = loadAuxiliaryArchives(description);
ProtocolDefinition protocolDefinition = protoReg.getProtocol(description.getProtocol());
if (protocolDefinition == null) {
protocolDefinition = protoReg.getProtocol(
containerRegistry.get()
.getContainer(description.getTarget())
.getDeployableContainer()
.getDefaultProtocol());
}
Protocol<?> protocol = protocolDefinition.getProtocol();
DeploymentPackager packager = protocol.getPackager();
Archive<?> applicationArchive = description.getArchive();
applyApplicationProcessors(description.getArchive(), testCase);
applyAuxiliaryProcessors(auxiliaryArchives);
try {
// this should be made more reliable, does not work with e.g. a EnterpriseArchive
if (ClassContainer.class.isInstance(applicationArchive)) {
ClassContainer<?> classContainer = ClassContainer.class.cast(applicationArchive);
classContainer.addClass(testCase.getJavaClass());
}
} catch (UnsupportedOperationException e) {
/*
* Quick Fix: https://jira.jboss.org/jira/browse/ARQ-118
* Keep in mind when rewriting for https://jira.jboss.org/jira/browse/ARQ-94
* that a ShrinkWrap archive might not support a Container if even tho the
* ContianerBase implements it. Check the Archive Interface..
*/
}
description.setTestableArchive(
packager.generateDeployment(
new TestDeployment(deployment.getDescription(), applicationArchive, auxiliaryArchives),
serviceLoader.get().all(ProtocolArchiveProcessor.class)));
}
}
private List<Archive<?>> loadAuxiliaryArchives(DeploymentDescription deployment) {
List<Archive<?>> archives = new ArrayList<Archive<?>>();
// load based on the Containers ClassLoader
Collection<AuxiliaryArchiveAppender> archiveAppenders = serviceLoader.get().all(AuxiliaryArchiveAppender.class);
for (AuxiliaryArchiveAppender archiveAppender : archiveAppenders) {
Archive<?> auxiliaryArchive = archiveAppender.createAuxiliaryArchive();
if (auxiliaryArchive != null) {
archives.add(auxiliaryArchive);
}
}
return archives;
}
private void applyApplicationProcessors(Archive<?> applicationArchive, TestClass testClass) {
Collection<ApplicationArchiveProcessor> processors = serviceLoader.get().all(ApplicationArchiveProcessor.class);
for (ApplicationArchiveProcessor processor : processors) {
processor.process(applicationArchive, testClass);
}
}
private void applyAuxiliaryProcessors(List<Archive<?>> auxiliaryArchives) {
Collection<AuxiliaryArchiveProcessor> processors = serviceLoader.get().all(AuxiliaryArchiveProcessor.class);
for (AuxiliaryArchiveProcessor processor : processors) {
for (Archive<?> auxiliaryArchive : auxiliaryArchives) {
processor.process(auxiliaryArchive);
}
}
}
private void throwTargetNotFoundValidationException(ContainerRegistry conReg, TargetDescription target) {
if (conReg.getContainers().size() == 0) {
throwNoContainerFound(target);
}
throwNoMatchFound(conReg, target);
}
private void throwNoContainerFound(TargetDescription target) {
throw new ValidationException("DeploymentScenario contains a target (" + target.getName()
+ ") not matching any defined Container in the registry.\n"
+ "Please include at least 1 Deployable Container on your Classpath.");
}
private void throwNoMatchFound(ContainerRegistry conReg, TargetDescription target) {
throw new ValidationException("DeploymentScenario contains a target (" + target.getName()
+ ") not matching any defined Container in the registry.\n" + "Possible causes are: None of the "
+ conReg.getContainers().size() + " Containers are marked as default or you have defined a " + "@"
+ org.jboss.arquillian.container.test.api.Deployment.class.getSimpleName() + " with a @"
+ TargetsContainer.class.getSimpleName() + " of value (" + target.getName() + ") that "
+ "does not match any found/configured Containers (" + toString(conReg)
+ "), see arquillian.xml container@qualifier");
}
private String toString(ContainerRegistry reg) {
StringBuilder sb = new StringBuilder();
for (Container container : reg.getContainers()) {
sb.append(container.getName()).append(",");
}
if (sb.length() > 0) {
sb.deleteCharAt(sb.length() - 1);
}
return sb.toString();
}
}