All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.arquillian.drone.configuration.ConfigurationMapper Maven / Gradle / Ivy

The newest version!
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2011, Red Hat Middleware LLC, 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.arquillian.drone.configuration;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.arquillian.config.descriptor.api.ArquillianDescriptor;
import org.jboss.arquillian.config.descriptor.api.ExtensionDef;
import org.jboss.arquillian.core.spi.Validate;
import org.jboss.arquillian.drone.configuration.legacy.LegacyConfigurationMapper;
import org.jboss.arquillian.drone.configuration.mapping.BooleanValueMapper;
import org.jboss.arquillian.drone.configuration.mapping.DoubleValueMapper;
import org.jboss.arquillian.drone.configuration.mapping.FileValueMapper;
import org.jboss.arquillian.drone.configuration.mapping.IntegerValueMapper;
import org.jboss.arquillian.drone.configuration.mapping.LogLevelMapper;
import org.jboss.arquillian.drone.configuration.mapping.LongValueMapper;
import org.jboss.arquillian.drone.configuration.mapping.StringValueMapper;
import org.jboss.arquillian.drone.configuration.mapping.URIValueMapper;
import org.jboss.arquillian.drone.configuration.mapping.URLValueMapper;
import org.jboss.arquillian.drone.configuration.mapping.ValueMapper;
import org.jboss.arquillian.drone.spi.DroneConfiguration;

/**
 * Utility which maps Arquillian Descriptor to a Drone configuration.
 * 

* Configuration mapper does inspect a configuration for available fields and it tries to fill the values according to * what is * provided in arquillian.xml or in system properties. *

* All properties, which does not have an appropriate fields to be assigned, are stored in each available map, given that * configuration provides a {@code Map} fields. Properties using their name as a key. * * @author Karel Piwko * @see DroneConfiguration */ public class ConfigurationMapper { // FIXME this should be in SPI with a proper event model public static final List> VALUE_MAPPERS; private static final Logger log = Logger.getLogger(ConfigurationMapper.class.getName()); static { VALUE_MAPPERS = new ArrayList>(); VALUE_MAPPERS.add(BooleanValueMapper.INSTANCE); VALUE_MAPPERS.add(DoubleValueMapper.INSTANCE); VALUE_MAPPERS.add(IntegerValueMapper.INSTANCE); VALUE_MAPPERS.add(LongValueMapper.INSTANCE); VALUE_MAPPERS.add(StringValueMapper.INSTANCE); VALUE_MAPPERS.add(URIValueMapper.INSTANCE); VALUE_MAPPERS.add(URLValueMapper.INSTANCE); VALUE_MAPPERS.add(FileValueMapper.INSTANCE); VALUE_MAPPERS.add(LogLevelMapper.INSTANCE); } // FIXME this should not be a static helper class but a proper observer on ArquillianDescriptor private ConfigurationMapper() { throw new InstantiationError(); } /** * Maps a configuration using Arquillian Descriptor file * * @param * Type of the configuration * @param descriptor * Arquillian Descriptor * @param configuration * Configuration object * @param qualifier * Qualifier annotation * * @return Configured configuration */ public static > T fromArquillianDescriptor(ArquillianDescriptor descriptor, T configuration, Class qualifier) { Validate.notNull(descriptor, "Descriptor must not be null"); Validate.notNull(configuration, "Configuration object must not be null"); Validate.notNull(qualifier, "Qualifier object must not be null"); String descriptorQualifier = configuration.getConfigurationName(); String qualifierName = qualifier.getSimpleName().toLowerCase(); Map nameValuePairs = loadNameValuePairs(descriptor, descriptorQualifier, qualifierName); // ARQ-1882 Map sanitizedNameValuePairs = new HashMap(nameValuePairs.size()); for (Map.Entry entry : nameValuePairs.entrySet()) { if (entry.getKey() != null) { sanitizedNameValuePairs.put(entry.getKey(), entry.getValue()); } } return mapFromNameValuePairs(configuration, sanitizedNameValuePairs); } /** * Maps configuration values from Arquillian Descriptor * * @param * A type of configuration * @param configuration * Configuration object * * @return Configured configuration of given type */ // @SuppressWarnings("unchecked") static > T mapFromNameValuePairs(T configuration, Map nameValuePairs) { Map fields = SecurityActions.getAccessableFields(configuration.getClass()); // extract all Map in the configuration and initialize them List maps = SecurityActions.getMapFields(configuration.getClass(), String.class, Object.class); for (Field mapField : maps) { try { // get or create a map @SuppressWarnings("unchecked") Map map = (Map) mapField.get(configuration); if (map == null) { map = new HashMap(); } mapField.set(configuration, map); } catch (Exception e) { throw new RuntimeException("Could not map Drone configuration(" + configuration.getConfigurationName() + ") for " + configuration.getClass().getName() + " from Arquillian Descriptor", e); } } // map basic fields for (Map.Entry nameValue : nameValuePairs.entrySet()) { String name = nameValue.getKey(); String reversedName = keyTransformReverse(name); // map a field which has a field directly available in the configuration if (fields.containsKey(name)) { injectField(configuration, maps, fields, name, nameValue.getValue()); } // map a field which comes from a system property which has a field available in the configuration // note, due to multiple deprecation, it might be possible that field we deprecated in favor of capability // has reversed name value exactly the same as capability - ARQ-1638 else if (fields.containsKey(reversedName) && !LegacyConfigurationMapper.isLegacy(reversedName)) { // we prefer new format arquillian.mockdriver.intField over arquillian.mockdriver.int.field log.log(Level.WARNING, "The system property \"{0}\" used in Arquillian \"{1}\" configuration is deprecated, please rather use new format \"{2}\"", new Object[] {name, configuration.getConfigurationName(), keyTransformReverse(name)}); injectField(configuration, maps, fields, keyTransformReverse(name), nameValue.getValue()); } // map a field which does not have this luck into all available maps in configuration else { injectMapProperty(configuration, maps, fields, name, nameValue.getValue()); } } return configuration; } /** * Parses Arquillian Descriptor into property name - value pairs value * * @param descriptor * An Arquillian Descriptor * @param descriptorQualifier * A qualifier used for extension configuration in the descriptor * @param qualifierName * Name of the qualifier passed */ static Map loadNameValuePairs(ArquillianDescriptor descriptor, String descriptorQualifier, String qualifierName) { String fullDescriptorQualifier = new StringBuilder(descriptorQualifier).append("-").append(qualifierName).toString(); ExtensionDef match = null; for (ExtensionDef extension : descriptor.getExtensions()) { if (fullDescriptorQualifier.equals(extension.getExtensionName())) { Map nameValuePairs = extension.getExtensionProperties(); if (log.isLoggable(Level.FINE)) { log.fine( "Using for Drone Configuration"); } return nameValuePairs; } else if (descriptorQualifier.equals(extension.getExtensionName())) { match = extension; } } // found generic only if (match != null) { Map nameValuePairs = match.getExtensionProperties(); if (log.isLoggable(Level.FINE)) { log.fine("Using for Drone Configuration"); } return nameValuePairs; } return Collections.emptyMap(); } /** * Maps a property key to a field name. *

* Replaces dot ('.') and lower case character with an upper case character * * @param propertyName * The name of field * * @return Corresponding field name */ static String keyTransformReverse(String propertyName) { StringBuilder sb = new StringBuilder(); boolean upperCaseFlag = false; for (int i = 0; i < propertyName.length(); i++) { char c = propertyName.charAt(i); if (c == '.') { upperCaseFlag = true; } else if (upperCaseFlag && Character.isLowerCase(c)) { sb.append(Character.toUpperCase(c)); upperCaseFlag = false; } else { sb.append(c); } } return sb.toString(); } static > Field injectField(T configuration, List maps, Map fields, String fieldName, String value) { try { Field f = fields.get(fieldName); if (f.getAnnotation(Deprecated.class) != null) { log.log(Level.WARNING, "The property \"{0}\" used in Arquillian \"{1}\" configuration is deprecated.", new Object[] {f.getName(), configuration.getConfigurationName()}); } // remap the property into capability if this is a legacy one // or remap the property into different property field if (LegacyConfigurationMapper.isLegacy(fieldName)) { String newKey = LegacyConfigurationMapper.remapKey(fieldName); String newValue = LegacyConfigurationMapper.remapValue(fieldName, value); if (LegacyConfigurationMapper.remapsToCapability(fieldName)) { injectMapProperty(configuration, maps, fields, newKey, newValue); } else { injectField(configuration, maps, fields, newKey, newValue); } } f.set(configuration, convert(f.getType(), value)); return f; } catch (Exception e) { throw new RuntimeException( "Could not map Drone configuration(" + configuration.getConfigurationName() + ") for " + configuration.getClass().getName() + " from Arquillian Descriptor", e); } } static > void injectMapProperty(T configuration, List maps, Map fields, String propertyName, String value) { try { for (Field mapField : maps) { Object typedValue = value; if (CapabilityTypeMapper.isCastNeeded(propertyName)) { typedValue = CapabilityTypeMapper.createTypedObjectFromString(propertyName, value); } // put property into a map @SuppressWarnings("unchecked") Map map = (Map) mapField.get(configuration); map.put(propertyName, typedValue); } } catch (Exception e) { throw new RuntimeException( "Could not map Drone configuration(" + configuration.getConfigurationName() + ") for " + configuration.getClass().getName() + " from Arquillian Descriptor", e); } } /** * A helper converting method. *

* Converts string to a class of given type * * @param * Type of returned value * @param clazz * Type of desired value * @param value * String value to be converted * * @return Value converted to a appropriate type */ static Object convert(Class clazz, String value) { for (ValueMapper mapper : VALUE_MAPPERS) { if (mapper.handles(clazz)) { return mapper.transform(value); } } throw new IllegalArgumentException("Unable to convert value " + value + "to a class: " + clazz.getName()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy