/* * JBoss, Home of Professional Open Source * Copyright 2010, Red Hat, Inc., and individual 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.cdi.tck.impl; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Enumeration; import java.util.HashSet; import java.util.Properties; import java.util.Set; import org.jboss.cdi.tck.api.Configuration; import org.jboss.cdi.tck.spi.Beans; import org.jboss.cdi.tck.spi.Contexts; import org.jboss.cdi.tck.spi.EL; /** * CDI TCK configuration builder. * * Mostly based on jboss-test-harness code from <code>org.jboss.testharness.impl.PropertiesBasedConfigurationBuilder</code> and * <code>org.jboss.testharness.properties.PropertiesManager</code>. */ public class PropertiesBasedConfigurationBuilder { public static final String RESOURCE_BUNDLE = "META-INF/cdi-tck.properties"; private final Configuration configuration; /** * */ public PropertiesBasedConfigurationBuilder() { configuration = new ConfigurationImpl(); } /** * @return built configuration */ public Configuration getConfiguration() { return configuration; } /** * @param deploymentPhase Deployment phase (building test archive) initialization includes deployment specific properties * @return initialized self */ @SuppressWarnings("unchecked") public PropertiesBasedConfigurationBuilder init(boolean deploymentPhase) { configuration.setBeans(getInstanceValue(Beans.PROPERTY_NAME, Beans.class, !deploymentPhase)); configuration.setEl(getInstanceValue(EL.PROPERTY_NAME, EL.class, !deploymentPhase)); configuration.setContexts((Contexts<?>)getInstanceValue(Contexts.PROPERTY_NAME, Contexts.class, !deploymentPhase)); configuration.setLibraryDirectory(getStringValue(Configuration.LIBRARY_DIRECTORY_PROPERTY_NAME, null, deploymentPhase)); configuration.setTestDataSource(getStringValue(Configuration.TEST_DATASOURCE_PROPERTY_NAME, null, deploymentPhase)); configuration.setTestJmsConnectionFactory(getStringValue(Configuration.TEST_JMS_CONNECTION_FACTORY, null, deploymentPhase)); configuration.setTestJmsQueue(getStringValue(Configuration.TEST_JMS_QUEUE, null, deploymentPhase)); configuration.setTestJmsTopic(getStringValue(Configuration.TEST_JMS_TOPIC, null, deploymentPhase)); configuration.setTestTimeoutFactor(getIntegerValue(Configuration.TEST_TIMEOUT_FACTOR, Configuration.TEST_TIMEOUT_FACTOR_DEFAULT_VALUE, false)); return this; } /** * Get a list of possible values for a given key. * * First, System properties are tried, followed by the specified resource bundle (first in classpath only). * * @param key The key to search for * @return A list of possible values. An empty list is returned if there are no matches. */ public Set<String> getPropertyValues(String key) { Set<String> values = new HashSet<String>(); addPropertiesFromSystem(key, values); addPropertiesFromResourceBundle(key, values); return values; } /** * * @param propertyName * @param defaultValue * @param required * @return */ public String getStringValue(String propertyName, String defaultValue, boolean required) { String value = getValue(propertyName, required); return value != null ? value : defaultValue; } /** * * @param propertyName * @param defaultValue * @param required * @return */ public long getLongValue(String propertyName, long defaultValue, boolean required) { try { String value = getValue(propertyName, required); return value != null ? Long.valueOf(value) : defaultValue; } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid property value", e); } } /** * * @param propertyName * @param defaultValue * @param required * @return */ public int getIntegerValue(String propertyName, int defaultValue, boolean required) { try { String value = getValue(propertyName, required); return value != null ? Integer.valueOf(value) : defaultValue; } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid property value", e); } } /** * Adds matches from system properties * * @param key The key to match * @param values The currently found values */ private void addPropertiesFromSystem(String key, Set<String> values) { addProperty(key, System.getProperty(key), values); } /** * Adds matches from detected resource bundles * * @param key The key to match * @param values The currently found values */ private void addPropertiesFromResourceBundle(String key, Set<String> values) { try { for (Enumeration<URL> e = getResources(RESOURCE_BUNDLE); e.hasMoreElements();) { URL url = e.nextElement(); Properties properties = new Properties(); InputStream propertyStream = url.openStream(); try { properties.load(propertyStream); addProperty(key, properties.getProperty(key), values); } finally { if (propertyStream != null) { propertyStream.close(); } } } } catch (IOException e) { // No-op, file is optional } } /** * Add the property to the set of properties only if it hasn't already been added * * @param key The key searched for * @param value The value of the property * @param values The currently found values */ private void addProperty(String key, String value, Set<String> values) { if (value != null) { values.add(value); } } /** * * @param name * @return * @throws IOException */ public Enumeration<URL> getResources(String name) throws IOException { if (Thread.currentThread().getContextClassLoader() != null) { return Thread.currentThread().getContextClassLoader().getResources(name); } else { return getClass().getClassLoader().getResources(name); } } /** * * @param <T> * @param propertyName * @param expectedType * @param required * @return */ protected <T> T getInstanceValue(String propertyName, Class<T> expectedType, boolean required) { T instance = null; Class<T> clazz = getClassValue(propertyName, expectedType, required); if (clazz != null) { try { instance = clazz.newInstance(); } catch (InstantiationException e) { throw new IllegalStateException("Error instantiating " + clazz + " specified by " + propertyName, e); } catch (IllegalAccessException e) { throw new IllegalStateException("Error instantiating " + clazz + " specified by " + propertyName, e); } } return instance; } /** * * @param <T> * @param propertyName * @param expectedType * @param required * @return */ @SuppressWarnings("unchecked") protected <T> Class<T> getClassValue(String propertyName, Class<T> expectedType, boolean required) { Set<Class<T>> classes = new HashSet<Class<T>>(); for (String className : getPropertyValues(propertyName)) { ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader(); try { if (currentThreadClassLoader != null) { classes.add((Class<T>) currentThreadClassLoader.loadClass(className)); } else { classes.add((Class<T>) Class.forName(className)); } } catch (ClassNotFoundException e) { throw new IllegalArgumentException("Implementation class with name " + className + " not found using classloader " + (currentThreadClassLoader != null ? currentThreadClassLoader : this.getClass().getClassLoader()), e); } } if (classes.size() == 0) { if (required) { throw new IllegalArgumentException("Cannot find any implementations of " + expectedType.getSimpleName() + ", check that " + propertyName + " is specified"); } else { return null; } } else if (classes.size() > 1) { throw new IllegalArgumentException("More than one implementation of " + expectedType.getSimpleName() + " specified by " + propertyName + ", not sure which one to use!"); } else { return classes.iterator().next(); } } private String getValue(String propertyName, boolean required) { Set<String> values = getPropertyValues(propertyName); if (values.size() == 0) { if (required) { throw new IllegalArgumentException("Cannot find required property " + propertyName + ", check that it is specified"); } return null; } else if (values.size() > 1) { throw new IllegalArgumentException("More than one value given for " + propertyName + ", not sure which one to use!"); } else { return values.iterator().next(); } } }