Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#159): Creates Arquillian SPI to resolve placeholders in configuration files #162

Merged
merged 4 commits into from
Feb 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions config/impl-base/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@
<artifactId>arquillian-config-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.config</groupId>
<artifactId>arquillian-config-spi</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.core</groupId>
<artifactId>arquillian-core-api</artifactId>
Expand All @@ -51,7 +56,6 @@
<artifactId>shrinkwrap-descriptors-spi</artifactId>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>org.jboss.arquillian.core</groupId>
<artifactId>arquillian-core-impl-base</artifactId>
Expand All @@ -65,12 +69,22 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jboss.arquillian.test</groupId>
<artifactId>arquillian-test-impl-base</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>

</dependencies>
</project>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.jboss.arquillian.config.impl.extension;

import org.jboss.arquillian.config.descriptor.api.ArquillianDescriptor;
import org.jboss.arquillian.config.spi.ConfigurationPlaceholderResolver;
import org.jboss.shrinkwrap.descriptor.api.Descriptors;

class ClasspathConfigurationPlaceholderResolver implements ConfigurationPlaceholderResolver {

public ArquillianDescriptor resolve(ArquillianDescriptor descriptor) {

final String descriptorAsString = descriptor.exportAsString();
return Descriptors.importAs(ArquillianDescriptor.class)
.fromString(StringPropertyReplacer.replaceClasspath(descriptorAsString));

}

public int precedence() {
return 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.jboss.arquillian.config.impl.extension;

import java.net.URL;
import java.util.logging.Logger;

class ClasspathPropertyResolver implements PropertyResolver {

private final static Logger logger = Logger.getLogger(ClasspathConfigurationPlaceholderResolver.class.getName());

/**
* 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) {
logger.warning(String.format("Resource %s is not found on the classspath so the property %s is not replaced.", classpathResource, key));
return null;
}

return resource.toString();
}

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
package org.jboss.arquillian.config.impl.extension;

import org.jboss.arquillian.config.spi.ConfigurationPlaceholderResolver;
import org.jboss.arquillian.core.spi.LoadableExtension;

/**
Expand All @@ -29,5 +30,8 @@ public class ConfigExtension implements LoadableExtension {
@Override
public void register(ExtensionBuilder builder) {
builder.observer(ConfigurationRegistrar.class);

builder.service(ConfigurationPlaceholderResolver.class, SystemPropertiesConfigurationPlaceholderResolver.class);
builder.service(ConfigurationPlaceholderResolver.class, ClasspathConfigurationPlaceholderResolver.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,26 @@
*/
package org.jboss.arquillian.config.impl.extension;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.jboss.arquillian.config.descriptor.api.ArquillianDescriptor;
import org.jboss.arquillian.config.spi.ConfigurationPlaceholderResolver;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.InstanceProducer;
import org.jboss.arquillian.core.api.annotation.ApplicationScoped;
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.arquillian.core.api.annotation.Observes;
import org.jboss.arquillian.core.api.event.ManagerStarted;
import org.jboss.arquillian.core.spi.ServiceLoader;
import org.jboss.shrinkwrap.descriptor.api.Descriptors;

import java.io.InputStream;
import java.util.Map;
import java.util.Properties;

import static org.jboss.arquillian.config.impl.extension.ConfigurationSysPropResolver.resolveSystemProperties;

/**
* Configurator
*
Expand All @@ -49,6 +55,9 @@ public class ConfigurationRegistrar {
@ApplicationScoped
private InstanceProducer<ArquillianDescriptor> descriptorInst;

@Inject
private Instance<ServiceLoader> serviceLoaderInstance;

public void loadConfiguration(@Observes ManagerStarted event) {
final InputStream input = FileUtils.loadArquillianXml(ARQUILLIAN_XML_PROPERTY, ARQUILLIAN_XML_DEFAULT);

Expand All @@ -67,11 +76,32 @@ public void loadConfiguration(@Observes ManagerStarted event) {
propertiesParser.addProperties(descriptor, envProperties);

//Placeholder resolver
final ArquillianDescriptor resolvedDesc = resolveSystemProperties(descriptor);
ArquillianDescriptor resolvedDesc = descriptor;

final List<ConfigurationPlaceholderResolver> configurationPlaceholderResolvers =
loadAndOrderPlaceholderResolvers();

for (ConfigurationPlaceholderResolver configurationPlaceholderResolver : configurationPlaceholderResolvers) {
resolvedDesc = configurationPlaceholderResolver.resolve(resolvedDesc);
}

descriptorInst.set(resolvedDesc);
}

private List<ConfigurationPlaceholderResolver> loadAndOrderPlaceholderResolvers() {
final List<ConfigurationPlaceholderResolver> configurationPlaceholderResolvers =
new ArrayList<ConfigurationPlaceholderResolver>(serviceLoaderInstance.get().all(ConfigurationPlaceholderResolver.class));

Collections.sort(configurationPlaceholderResolvers, new Comparator<ConfigurationPlaceholderResolver>() {
public int compare(ConfigurationPlaceholderResolver firstResolver, ConfigurationPlaceholderResolver secondResolver) {
Integer a = firstResolver.precedence();
Integer b = secondResolver.precedence();
return b.compareTo(a);
}
});
return configurationPlaceholderResolvers;
}

private ArquillianDescriptor resolveDescriptor(final InputStream input) {
final ArquillianDescriptor descriptor;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package org.jboss.arquillian.config.impl.extension;

import java.io.File;
import java.util.Properties;

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(key);
} else {
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.
* <p>
* 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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.jboss.arquillian.config.impl.extension;

interface PropertyResolver {
String getValue(String key);
}
Loading