diff --git a/container/impl-base/src/main/java/org/jboss/arquillian/container/impl/ContainerImpl.java b/container/impl-base/src/main/java/org/jboss/arquillian/container/impl/ContainerImpl.java index dbe3fe3e4..f1cf57978 100644 --- a/container/impl-base/src/main/java/org/jboss/arquillian/container/impl/ContainerImpl.java +++ b/container/impl-base/src/main/java/org/jboss/arquillian/container/impl/ContainerImpl.java @@ -20,6 +20,7 @@ import org.jboss.arquillian.config.descriptor.api.ProtocolDef; import org.jboss.arquillian.container.spi.Container; import org.jboss.arquillian.container.spi.ServerKillProcessor; +import org.jboss.arquillian.container.spi.client.container.ConfigurationMapper; import org.jboss.arquillian.container.spi.client.container.ContainerConfiguration; import org.jboss.arquillian.container.spi.client.container.DeployableContainer; import org.jboss.arquillian.container.spi.client.container.LifecycleException; @@ -47,25 +48,25 @@ * @author Aslak Knutsen * @version $Revision: $ */ -public class ContainerImpl implements Container { +public class ContainerImpl implements Container { @Inject private Event event; @Inject @ContainerScoped - private InstanceProducer containerProducer; + private InstanceProducer> containerProducer; @Inject private Instance serviceLoader; - private DeployableContainer deployableContainer; + private DeployableContainer deployableContainer; private String name; private State state = State.STOPPED; private Throwable failureCause; private ContainerDef containerConfiguration; - public ContainerImpl(String name, DeployableContainer deployableContainer, ContainerDef containerConfiguration) { + public ContainerImpl(String name, DeployableContainer deployableContainer, ContainerDef containerConfiguration) { Validate.notNull(name, "Name must be specified"); Validate.notNull(deployableContainer, "DeployableContainer must be specified"); Validate.notNull(containerConfiguration, "ConfigurationConfiguration must be specified"); @@ -87,7 +88,7 @@ public String getName() { * @see org.jboss.arquillian.container.impl.ContainerT#getDeployableContainer() */ @Override - public DeployableContainer getDeployableContainer() { + public DeployableContainer getDeployableContainer() { return deployableContainer; } @@ -103,10 +104,15 @@ public ContainerDef getContainerConfiguration() { * @see org.jboss.arquillian.container.impl.ContainerT#createDeployableConfiguration() */ @Override - public ContainerConfiguration createDeployableConfiguration() throws Exception { - ContainerConfiguration config = SecurityActions.newInstance( - deployableContainer.getConfigurationClass(), new Class[0], new Object[0]); - MapObject.populate(config, containerConfiguration.getContainerProperties()); + public T createDeployableConfiguration() throws Exception { + Class configClass = (Class) deployableContainer.getConfigurationClass(); + T config = SecurityActions.newInstance(configClass, new Class[0], new Object[0]); + ConfigurationMapper mapper = deployableContainer.getConfigurationMapper(); + if(mapper != null) { + mapper.populateConfiguration(config, containerConfiguration); + } else { + MapObject.populate(config, containerConfiguration.getContainerProperties()); + } config.validate(); return config; } diff --git a/container/impl-base/src/test/java/org/jboss/arquillian/container/impl/ContainerRegistryTestCase.java b/container/impl-base/src/test/java/org/jboss/arquillian/container/impl/ContainerRegistryTestCase.java index 8ab81eac2..6e5f85cf0 100644 --- a/container/impl-base/src/test/java/org/jboss/arquillian/container/impl/ContainerRegistryTestCase.java +++ b/container/impl-base/src/test/java/org/jboss/arquillian/container/impl/ContainerRegistryTestCase.java @@ -16,10 +16,12 @@ */ package org.jboss.arquillian.container.impl; +import org.jboss.arquillian.config.descriptor.api.ContainerDef; import org.jboss.arquillian.config.descriptor.impl.ContainerDefImpl; import org.jboss.arquillian.container.spi.ConfigurationException; import org.jboss.arquillian.container.spi.Container; import org.jboss.arquillian.container.spi.ContainerRegistry; +import org.jboss.arquillian.container.spi.client.container.ConfigurationMapper; import org.jboss.arquillian.container.spi.client.container.ContainerConfiguration; import org.jboss.arquillian.container.spi.client.container.DeployableContainer; import org.jboss.arquillian.container.spi.client.deployment.TargetDescription; @@ -140,6 +142,46 @@ public void shouldBeAbleToCreatePrivateContainerConfiguration() throws Exception ((PrivateDummyContainerConfiguration) container.createDeployableConfiguration()).getProperty()); } + @Test + public void shouldBeAbleToCreateContainerConfigurationCustomMapper() throws Exception { + ServiceLoader serviceLoader = Mockito.mock(ServiceLoader.class); + DeployableContainer deployableContainer = + Mockito.mock(DeployableContainer.class); + + Mockito.when(serviceLoader.onlyOne(Mockito.same(DeployableContainer.class))).thenReturn(deployableContainer); + Mockito.when(deployableContainer.getConfigurationClass()).thenReturn(CustomContainerConfiguration.class); + Mockito.when(deployableContainer.getConfigurationMapper()).thenReturn(new CustomMapper()); + + String name = "custom-container"; + String prop = "prop-value"; + String[] hosts = {"host1", "host2", "host3"}; + + ContainerRegistry registry = new LocalContainerRegistry(injector.get()); + ContainerDefImpl containerDef = new ContainerDefImpl(ARQUILLIAN_XML); + containerDef.setContainerName(name); + containerDef.property("property", prop); + containerDef.property("hosts", "host1,host2,host3"); + + registry.create(containerDef, serviceLoader); + + Container container = registry.getContainer(new TargetDescription(name)); + + Assert.assertEquals( + "Verify that the only registered container is returned as default", + name, container.getName()); + + CustomContainerConfiguration config = container.createDeployableConfiguration(); + Assert.assertEquals( + "Verify that the custom configuration 'property' was populated", + prop, + config.getProperty()); + + Assert.assertArrayEquals( + "Verify that the custom configuration 'hosts' was populated", + hosts, + config.getHosts()); + } + @Test public void shouldBeAbleToSpecifyTarget() throws Exception { String name = "some-name"; @@ -197,4 +239,23 @@ private static class PrivateDummyContainerConfiguration extends DummyContainerCo private PrivateDummyContainerConfiguration() { } } + private static class CustomContainerConfiguration extends DummyContainerConfiguration { + private String[] hosts; + public String[] getHosts() { + return hosts; + } + public void setHosts(String[] hosts) { + this.hosts = hosts; + } + } + private static class CustomMapper implements ConfigurationMapper { + @Override + public void populateConfiguration(CustomContainerConfiguration containerConfiguration, ContainerDef definition) { + String property = definition.getContainerProperty("property"); + containerConfiguration.setProperty(property); + String hostsString = definition.getContainerProperty("hosts"); + String[] hosts = hostsString.split(","); + containerConfiguration.setHosts(hosts); + } + } } diff --git a/container/spi/src/main/java/org/jboss/arquillian/container/spi/Container.java b/container/spi/src/main/java/org/jboss/arquillian/container/spi/Container.java index 59f2b79ab..8ef4c6d37 100644 --- a/container/spi/src/main/java/org/jboss/arquillian/container/spi/Container.java +++ b/container/spi/src/main/java/org/jboss/arquillian/container/spi/Container.java @@ -30,7 +30,7 @@ * @author Aslak Knutsen * @version $Revision: $ */ -public interface Container { +public interface Container { /** * @return the name @@ -40,7 +40,7 @@ public interface Container { /** * @return the deployableContainer */ - DeployableContainer getDeployableContainer(); + DeployableContainer getDeployableContainer(); /** * @return the containerConfiguration @@ -50,7 +50,7 @@ public interface Container { /** * @return the configuration */ - ContainerConfiguration createDeployableConfiguration() throws Exception; + T createDeployableConfiguration() throws Exception; boolean hasProtocolConfiguration(ProtocolDescription description); @@ -73,4 +73,4 @@ public interface Container { enum State { SETUP, SETUP_FAILED, STARTED, STARTED_FAILED, STOPPED, STOPPED_FAILED, KILLED, KILLED_FAILED; } -} \ No newline at end of file +} diff --git a/container/spi/src/main/java/org/jboss/arquillian/container/spi/client/container/ConfigurationMapper.java b/container/spi/src/main/java/org/jboss/arquillian/container/spi/client/container/ConfigurationMapper.java new file mode 100644 index 000000000..d0d715e85 --- /dev/null +++ b/container/spi/src/main/java/org/jboss/arquillian/container/spi/client/container/ConfigurationMapper.java @@ -0,0 +1,36 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2024 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.spi.client.container; + +import org.jboss.arquillian.config.descriptor.api.ContainerDef; + +/** + * An interface that {@link DeployableContainer} can use to control how the mapping + * from the externalized container definition, as found in an arquillian.xml file + * for example, is applied to the {@link ContainerConfiguration} instances + * + * @param the type of ContainerConfiguration + */ +public interface ConfigurationMapper { + /** + * + * @param containerConfiguration - the deployable container configuration instance to populate + * @param definition - the container definition from the ArquillianDescriptor that + * was parsed + */ + void populateConfiguration(T containerConfiguration, ContainerDef definition); +} diff --git a/container/spi/src/main/java/org/jboss/arquillian/container/spi/client/container/DeployableContainer.java b/container/spi/src/main/java/org/jboss/arquillian/container/spi/client/container/DeployableContainer.java index 9e4425a91..513356a7b 100644 --- a/container/spi/src/main/java/org/jboss/arquillian/container/spi/client/container/DeployableContainer.java +++ b/container/spi/src/main/java/org/jboss/arquillian/container/spi/client/container/DeployableContainer.java @@ -37,6 +37,17 @@ public interface DeployableContainer { // ControllableContainer Class getConfigurationClass(); + /** + * Provide a mapping instance that takes the {@link org.jboss.arquillian.config.descriptor.api.ContainerDef} + * for the arquillian.xml or other configured descriptor and populates the container configuration + * instance from the descriptor values. + * + * @return A possibly null ConfigurationMapper. If null, the default logic to map from string based + * properties as implemented in org.jboss.arquillian.container.impl.MapObject will be used. + */ + default ConfigurationMapper getConfigurationMapper() { + return null; + } default void setup(T configuration) { }