- * It also accepts "key1," and ",key2". - * - * @param key - * the key to resolve - * @param props - * the properties to use - * - * @return the resolved key or null - */ - private static String resolveCompositeKey(String key, Properties props) { - String value = null; - - // Look for the comma - int comma = key.indexOf(','); - if (comma > -1) { - // If we have a first part, try resolve it - if (comma > 0) { - // Check the first part - String key1 = key.substring(0, comma); - if (props != null) { - value = props.getProperty(key1); - } else { - value = System.getProperty(key1); + + public interface PropertyResolver { + String getValue(String key); + } + + static class ClasspathPropertyResolver implements PropertyResolver { + + /** + * Classpath base property + */ + private static final String CLASSPATH = "classpath("; + + public String getValue(String key) { + + if (key.startsWith(CLASSPATH)) { + final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + String classpathResource = key.substring(CLASSPATH.length(), key.length() - 1); + final URL resource = contextClassLoader.getResource(classpathResource); + + //If resource is not found it is returned as null so no change is applicable. + if (resource == null) { + return null; } + + return resource.toString(); } - // Check the second part, if there is one and first lookup failed - if (value == null && comma < key.length() - 1) { - String key2 = key.substring(comma + 1); + + return null; + } + } + + static class PropertiesPropertyResolver implements PropertyResolver { + + /** + * File separator value + */ + private static final String FILE_SEPARATOR = File.separator; + + /** + * Path separator value + */ + private static final String PATH_SEPARATOR = File.pathSeparator; + + /** + * File separator alias + */ + private static final String FILE_SEPARATOR_ALIAS = "/"; + + /** + * Path separator alias + */ + private static final String PATH_SEPARATOR_ALIAS = ":"; + + + private final Properties props; + + PropertiesPropertyResolver(Properties props) { + this.props = props; + } + + public String getValue(String key) { + + String value; + + if (FILE_SEPARATOR_ALIAS.equals(key)) { + value = FILE_SEPARATOR; + } else if (PATH_SEPARATOR_ALIAS.equals(key)) { + value = PATH_SEPARATOR; + } else { + // check from the properties if (props != null) { - value = props.getProperty(key2); + value = props.getProperty(key); } else { - value = System.getProperty(key2); + value = System.getProperty(key); + } + + if (value == null) { + // Check for a default value ${key:default} + int colon = key.indexOf(':'); + if (colon > 0) { + String realKey = key.substring(0, colon); + if (props != null) { + value = props.getProperty(realKey); + } else { + value = System.getProperty(realKey); + } + + if (value == null) { + // Check for a composite key, "key1,key2" + value = resolveCompositeKey(realKey, props); + + // Not a composite key either, use the specified default + if (value == null) { + value = key.substring(colon + 1); + } + } + } else { + // No default, check for a composite key, "key1,key2" + value = resolveCompositeKey(key, props); + } } } + + return value; + } + + /** + * Try to resolve a "key" from the provided properties by + * checking if it is actually a "key1,key2", in which case + * try first "key1", then "key2". If all fails, return null. + *
+ * It also accepts "key1," and ",key2".
+ *
+ * @param key
+ * the key to resolve
+ * @param props
+ * the properties to use
+ *
+ * @return the resolved key or null
+ */
+ private String resolveCompositeKey(String key, Properties props) {
+ String value = null;
+
+ // Look for the comma
+ int comma = key.indexOf(',');
+ if (comma > -1) {
+ // If we have a first part, try resolve it
+ if (comma > 0) {
+ // Check the first part
+ String key1 = key.substring(0, comma);
+ if (props != null) {
+ value = props.getProperty(key1);
+ } else {
+ value = System.getProperty(key1);
+ }
+ }
+ // Check the second part, if there is one and first lookup failed
+ if (value == null && comma < key.length() - 1) {
+ String key2 = key.substring(comma + 1);
+ if (props != null) {
+ value = props.getProperty(key2);
+ } else {
+ value = System.getProperty(key2);
+ }
+ }
+ }
+ // Return whatever we've found or null
+ return value;
}
- // Return whatever we've found or null
- return value;
}
+
}
diff --git a/config/impl-base/src/test/java/org/jboss/arquillian/config/impl/extension/ArquillianDescriptorClasspathPropertiesTestCase.java b/config/impl-base/src/test/java/org/jboss/arquillian/config/impl/extension/ArquillianDescriptorClasspathPropertiesTestCase.java
new file mode 100644
index 000000000..c42cfea99
--- /dev/null
+++ b/config/impl-base/src/test/java/org/jboss/arquillian/config/impl/extension/ArquillianDescriptorClasspathPropertiesTestCase.java
@@ -0,0 +1,73 @@
+package org.jboss.arquillian.config.impl.extension;
+
+import java.net.URL;
+import org.jboss.arquillian.config.descriptor.api.ArquillianDescriptor;
+import org.jboss.shrinkwrap.descriptor.api.Descriptors;
+import org.junit.Test;
+
+import static org.jboss.arquillian.config.descriptor.impl.AssertXPath.assertXPath;
+
+public class ArquillianDescriptorClasspathPropertiesTestCase {
+
+
+ @Test
+ public void should_replace_properties_with_classpath_location() throws Exception {
+ // given
+ String element = "arquillian_sysprop.xml";
+ ArquillianDescriptor desc = create()
+ .container("daemon")
+ .property("javaVmArguments", "-Djavax.net.ssl.trustStore=${classpath(" + element + ")}");
+ final ClasspathConfigurationPlaceholderResolver classpathConfigurationPlaceholderResolver = new ClasspathConfigurationPlaceholderResolver();
+
+ // when
+ desc = classpathConfigurationPlaceholderResolver.resolve(desc);
+
+ // then
+ final String descString = desc.exportAsString();
+ final URL resource = Thread.currentThread().getContextClassLoader().getResource(element);
+ assertXPath(descString, "/arquillian/container/configuration/property",
+ String.format("-Djavax.net.ssl.trustStore=%s", resource.toString()));
+
+ }
+
+ @Test
+ public void should_not_replace_placeholder_if_classpath_resource_not_found() throws Exception {
+ String element = "notfound.txt";
+ ArquillianDescriptor desc = create()
+ .container("daemon")
+ .property("javaVmArguments", "-Djavax.net.ssl.trustStore=${classpath(" + element + ")}");
+ final ClasspathConfigurationPlaceholderResolver classpathConfigurationPlaceholderResolver = new ClasspathConfigurationPlaceholderResolver();
+
+ // when
+ desc = classpathConfigurationPlaceholderResolver.resolve(desc);
+
+ // then
+ final String descString = desc.exportAsString();
+ assertXPath(descString, "/arquillian/container/configuration/property",
+ String.format("-Djavax.net.ssl.trustStore=${classpath(%s)}", element));
+ }
+
+ @Test
+ public void should_not_replace_other_placeholders() throws Exception {
+
+ ArquillianDescriptor desc = create()
+ .container("daemon")
+ .property("javaVmArguments", "-Djavax.net.ssl.trustStore=${env.LAUNCHER_TESTS_TRUSTSTORE_PATH}");
+ final ClasspathConfigurationPlaceholderResolver classpathConfigurationPlaceholderResolver = new ClasspathConfigurationPlaceholderResolver();
+
+ // when
+ desc = classpathConfigurationPlaceholderResolver.resolve(desc);
+
+ // then
+ final String descString = desc.exportAsString();
+ assertXPath(descString, "/arquillian/container/configuration/property",
+ "-Djavax.net.ssl.trustStore=${env.LAUNCHER_TESTS_TRUSTSTORE_PATH}");
+
+ }
+
+
+ private ArquillianDescriptor create() {
+ return Descriptors.create(ArquillianDescriptor.class);
+ }
+
+}
diff --git a/config/impl-base/src/test/java/org/jboss/arquillian/config/impl/extension/ArquillianDescriptorPropertiesTestCase.java b/config/impl-base/src/test/java/org/jboss/arquillian/config/impl/extension/ArquillianDescriptorPropertiesTestCase.java
index f17c20823..601b69397 100644
--- a/config/impl-base/src/test/java/org/jboss/arquillian/config/impl/extension/ArquillianDescriptorPropertiesTestCase.java
+++ b/config/impl-base/src/test/java/org/jboss/arquillian/config/impl/extension/ArquillianDescriptorPropertiesTestCase.java
@@ -100,7 +100,7 @@ public void shouldBeAbleToSetEngineProperties() throws Exception {
.deploymentExportPath(setPropKey(KEY_PROPERTY_VALUE_1))
.maxTestClassesBeforeRestart(PROPERTY_INT_VALUE_1)
.maxTestClassesBeforeRestart(PROPERTY_INT_VALUE_1);
- desc = ConfigurationSysPropResolver.resolveSystemProperties(desc);
+ desc = new ConfigurationSysPropResolver().resolve(desc);
final String descString = desc.exportAsString();
assertXPath(descString, "/arquillian/engine/property[@name='deploymentExportPath']/text()", PROPERTY_VALUE_1);
@@ -118,7 +118,7 @@ public void shouldReturnNullOnEnginePropertiesIfNotSet() throws Exception {
// add multiple times to see only one property added
desc = create()
.engine();
- desc = ConfigurationSysPropResolver.resolveSystemProperties(desc);
+ desc = new ConfigurationSysPropResolver().resolve(desc);
final String descString = desc.exportAsString();
ArquillianDescriptor descriptor = create(descString);
@@ -135,7 +135,7 @@ public void shouldBeAbleToAddContainer() throws Exception {
desc = create()
.container(setPropKey(KEY_CONTAINER_NAME_1)).setDefault()
.container(setPropKey(KEY_CONTAINER_NAME_2));
- desc = ConfigurationSysPropResolver.resolveSystemProperties(desc);
+ desc = new ConfigurationSysPropResolver().resolve(desc);
final String descString = desc.exportAsString();
assertXPath(descString, "/arquillian/container/@qualifier", CONTAINER_NAME_1, CONTAINER_NAME_2);
@@ -156,7 +156,7 @@ public void shouldBeAbleToAddContainerAndOverwrite() throws Exception {
desc = create()
.container(CONTAINER_NAME_1).setDefault()
.container(CONTAINER_NAME_1).setContainerName(setPropKey(KEY_CONTAINER_NAME_2));
- desc = ConfigurationSysPropResolver.resolveSystemProperties(desc);
+ desc = new ConfigurationSysPropResolver().resolve(desc);
final String descString = desc.exportAsString();
assertXPath(descString, "/arquillian/container/@qualifier", CONTAINER_NAME_2);
@@ -175,7 +175,7 @@ public void shouldBeAbleToAddDefaultProtocol() throws Exception {
desc = create()
.defaultProtocol(PROTOCOL_TYPE_1)
.property(PROPERTY_NAME_1, setPropKey(KEY_PROPERTY_VALUE_1));
- desc = ConfigurationSysPropResolver.resolveSystemProperties(desc);
+ desc = new ConfigurationSysPropResolver().resolve(desc);
final String descString = desc.exportAsString();
assertXPath(descString, "/arquillian/defaultProtocol/@type", PROTOCOL_TYPE_1);
@@ -197,7 +197,7 @@ public void shouldBeAbleToAddDefaultProtocolAndOverwriteProperty() throws Except
.defaultProtocol(PROTOCOL_TYPE_1)
.property(PROPERTY_NAME_1, setPropKey(KEY_PROPERTY_VALUE_1))
.property(PROPERTY_NAME_1, setPropKey(KEY_PROPERTY_VALUE_2));
- desc = ConfigurationSysPropResolver.resolveSystemProperties(desc);
+ desc = new ConfigurationSysPropResolver().resolve(desc);
final String descString = desc.exportAsString();
assertXPath(descString, "/arquillian/defaultProtocol/@type", PROTOCOL_TYPE_1);
@@ -221,7 +221,7 @@ public void shouldBeAbleToAddContainerWithDependencies() throws Exception {
.container(CONTAINER_NAME_1)
.dependency(setPropKey(KEY_DEPENDENCY_1))
.dependency(setPropKey(KEY_DEPENDENCY_2));
- desc = ConfigurationSysPropResolver.resolveSystemProperties(desc);
+ desc = new ConfigurationSysPropResolver().resolve(desc);
final String descString = desc.exportAsString();
assertXPath(descString, "/arquillian/container/dependencies/dependency", DEPENDENCY_1, DEPENDENCY_2);
@@ -243,7 +243,7 @@ public void shouldBeAbleToAddContainerWithDependenciesAndOverwrite() throws Exce
.container(CONTAINER_NAME_1)
.dependency(setPropKey(KEY_DEPENDENCY_1))
.dependency(setPropKey(KEY_DEPENDENCY_1));
- desc = ConfigurationSysPropResolver.resolveSystemProperties(desc);
+ desc = new ConfigurationSysPropResolver().resolve(desc);
final String descString = desc.exportAsString();
assertXPath(descString, "/arquillian/container/dependencies/dependency", DEPENDENCY_1);
@@ -266,7 +266,7 @@ public void shouldBeAbleToAddContainerWithMultipleProtocols() throws Exception {
.property(PROPERTY_NAME_1, setPropKey(KEY_PROPERTY_VALUE_1))
.protocol(PROTOCOL_TYPE_2)
.property(PROPERTY_NAME_2, setPropKey(KEY_PROPERTY_VALUE_2));
- desc = ConfigurationSysPropResolver.resolveSystemProperties(desc);
+ desc = new ConfigurationSysPropResolver().resolve(desc);
final String descString = desc.exportAsString();
assertXPath(descString, "/arquillian/container/@qualifier", CONTAINER_NAME_1);
@@ -302,7 +302,7 @@ public void shouldBeAbleToAddContainerAndOverwriteProtocol() throws Exception {
.property(PROPERTY_NAME_1, setPropKey(KEY_PROPERTY_VALUE_1))
.protocol(PROTOCOL_TYPE_1)
.property(PROPERTY_NAME_1, setPropKey(KEY_PROPERTY_VALUE_2));
- desc = ConfigurationSysPropResolver.resolveSystemProperties(desc);
+ desc = new ConfigurationSysPropResolver().resolve(desc);
final String descString = desc.exportAsString();
assertXPath(descString, "/arquillian/container/@qualifier", CONTAINER_NAME_1);
@@ -331,7 +331,7 @@ public void shouldBeAbleToAddContainerWithConfiguration() throws Exception {
.container(CONTAINER_NAME_2)
.property(PROPERTY_NAME_2, setPropKey(KEY_PROPERTY_VALUE_2))
.property(PROPERTY_NAME_4, setPropKey(KEY_ENV_NAME_1));
- desc = ConfigurationSysPropResolver.resolveSystemProperties(desc);
+ desc = new ConfigurationSysPropResolver().resolve(desc);
final String descString = desc.exportAsString();
assertXPath(descString, "/arquillian/container[1]/@qualifier", CONTAINER_NAME_1);
@@ -366,7 +366,7 @@ public void shouldBeAbleToAddContainerWithConfigurationAndOverwriteProperty() th
.container(CONTAINER_NAME_1)
.property(PROPERTY_NAME_1, setPropKey(KEY_PROPERTY_VALUE_1))
.property(PROPERTY_NAME_1, setPropKey(KEY_PROPERTY_VALUE_2));
- desc = ConfigurationSysPropResolver.resolveSystemProperties(desc);
+ desc = new ConfigurationSysPropResolver().resolve(desc);
final String descString = desc.exportAsString();
assertXPath(descString, "/arquillian/container[1]/@qualifier", CONTAINER_NAME_1);
@@ -395,7 +395,7 @@ public void shouldBeAbleToAddGroupWithContainer() throws Exception {
.container(setPropKey(KEY_CONTAINER_NAME_2))
.group(GROUP_NAME_2)
.container(setPropKey(KEY_CONTAINER_NAME_3));
- desc = ConfigurationSysPropResolver.resolveSystemProperties(desc);
+ desc = new ConfigurationSysPropResolver().resolve(desc);
final String descString = desc.exportAsString();
assertXPath(descString, "/arquillian/group/@qualifier", GROUP_NAME_1, GROUP_NAME_2);
@@ -425,7 +425,7 @@ public void shouldBeAbleToAddGroupWithContainerAndOverwriteContainer() throws Ex
.group(GROUP_NAME_1)
.container(setPropKey(KEY_CONTAINER_NAME_1))
.container(setPropKey(KEY_CONTAINER_NAME_1));
- desc = ConfigurationSysPropResolver.resolveSystemProperties(desc);
+ desc = new ConfigurationSysPropResolver().resolve(desc);
final String descString = desc.exportAsString();
assertXPath(descString, "/arquillian/group/@qualifier", GROUP_NAME_1);
@@ -450,7 +450,7 @@ public void shouldBeAbleToAddExtension() throws Exception {
.property(PROPERTY_NAME_2, setPropKey(KEY_PROPERTY_VALUE_2))
.extension(EXTENSION_NAME_2)
.property(PROPERTY_NAME_3, setPropKey(KEY_PROPERTY_VALUE_3));
- desc = ConfigurationSysPropResolver.resolveSystemProperties(desc);
+ desc = new ConfigurationSysPropResolver().resolve(desc);
final String descString = desc.exportAsString();
assertXPath(descString, "/arquillian/extension/@qualifier", EXTENSION_NAME_1, EXTENSION_NAME_2);
@@ -484,7 +484,7 @@ public void shouldBeAbleToRenameExtension() throws Exception {
.property(PROPERTY_NAME_1, PROPERTY_VALUE_1)
.extension(EXTENSION_NAME_1)
.setExtensionName(EXTENSION_NAME_2);
- desc = ConfigurationSysPropResolver.resolveSystemProperties(desc);
+ desc = new ConfigurationSysPropResolver().resolve(desc);
final String descString = desc.exportAsString();
assertXPath(descString, "/arquillian/extension/@qualifier", EXTENSION_NAME_2);
@@ -506,7 +506,7 @@ public void shouldBeAbleToAddExtensionAndOverwriteProperty() throws Exception {
.extension(EXTENSION_NAME_1)
.property(PROPERTY_NAME_1, setPropKey(KEY_PROPERTY_VALUE_1))
.property(PROPERTY_NAME_1, setPropKey(KEY_PROPERTY_VALUE_2));
- desc = ConfigurationSysPropResolver.resolveSystemProperties(desc);
+ desc = new ConfigurationSysPropResolver().resolve(desc);
final String descString = desc.exportAsString();
assertXPath(descString, "/arquillian/extension/@qualifier", EXTENSION_NAME_1);
diff --git a/config/impl-base/src/test/java/org/jboss/arquillian/config/impl/extension/ClasspathReplacementInArqXmlTestCase.java b/config/impl-base/src/test/java/org/jboss/arquillian/config/impl/extension/ClasspathReplacementInArqXmlTestCase.java
new file mode 100644
index 000000000..1e240c9ab
--- /dev/null
+++ b/config/impl-base/src/test/java/org/jboss/arquillian/config/impl/extension/ClasspathReplacementInArqXmlTestCase.java
@@ -0,0 +1,119 @@
+package org.jboss.arquillian.config.impl.extension;
+
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+import org.jboss.arquillian.config.descriptor.api.ArquillianDescriptor;
+import org.jboss.arquillian.config.descriptor.impl.AssertXPath;
+import org.jboss.arquillian.config.spi.ConfigurationPlaceholderResolver;
+import org.jboss.arquillian.core.api.Instance;
+import org.jboss.arquillian.core.api.annotation.Inject;
+import org.jboss.arquillian.core.spi.Manager;
+import org.jboss.arquillian.core.spi.ServiceLoader;
+import org.jboss.arquillian.core.spi.context.Context;
+import org.jboss.arquillian.core.test.AbstractManagerTestBase;
+import org.jboss.arquillian.test.impl.context.SuiteContextImpl;
+import org.jboss.arquillian.test.spi.annotation.SuiteScoped;
+import org.jboss.arquillian.test.spi.context.SuiteContext;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.jboss.arquillian.config.descriptor.impl.AssertXPath.assertXPath;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ClasspathReplacementInArqXmlTestCase extends AbstractManagerTestBase {
+
+ @Mock
+ private ServiceLoader serviceLoader;
+
+ /**
+ * Name of the arquillian.xml to test
+ */
+ private static final String NAME_ARQ_XML = "arquillian_classpathprop.xml";
+
+ /**
+ * Name of the system property for EL expressions
+ */
+ private static final String SYSPROP_ARQ_CONTAINER = "arquillian.container";
+
+ private static final String VALUE_EL_OVERRIDE = "ALR";
+
+ /**
+ * The loaded arquillian.xml
+ */
+ @Inject
+ private Instance