| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * 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 com.android.tradefed.config; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * Holds a record of a configuration, its associated objects and their options. |
| */ |
| public class ConfigurationDef { |
| |
| /** a map of object type names to config object class name(s). */ |
| private final Map<String, List<String>> mObjectClassMap; |
| /** a list of option name/value pairs. */ |
| private final List<OptionDef> mOptionList; |
| /** a cache of the frequency of every classname */ |
| private final Map<String, Integer> mClassFrequency; |
| |
| static class OptionDef { |
| final String name; |
| final String key; |
| final String value; |
| |
| OptionDef(String optionName, String optionValue) { |
| this(optionName, null, optionValue); |
| } |
| |
| OptionDef(String optionName, String optionKey, String optionValue) { |
| this.name = optionName; |
| this.key = optionKey; |
| this.value = optionValue; |
| } |
| } |
| |
| /** the unique name of the configuration definition */ |
| private final String mName; |
| |
| /** a short description of the configuration definition */ |
| private String mDescription = ""; |
| |
| public ConfigurationDef(String name) { |
| mName = name; |
| // use LinkedHashMap to keep objects in same order they were added. |
| mObjectClassMap = new LinkedHashMap<String, List<String>>(); |
| mOptionList = new ArrayList<OptionDef>(); |
| mClassFrequency = new HashMap<String, Integer>(); |
| } |
| |
| /** |
| * Returns a short description of the configuration |
| */ |
| public String getDescription() { |
| return mDescription; |
| } |
| |
| /** |
| * Sets the configuration definition description |
| */ |
| void setDescription(String description) { |
| mDescription = description; |
| } |
| |
| /** |
| * Adds a config object to the definition |
| * |
| * @param typeName the config object type name |
| * @param className the class name of the config object |
| * @return the number of times this className has appeared in this {@link ConfigurationDef}, |
| * including this time. Because all {@link ConfigurationDef} methods return these |
| * classes with a constant ordering, this index can serve as a unique identifier for the |
| * just-added instance of <code>clasName</code>. |
| */ |
| int addConfigObjectDef(String typeName, String className) { |
| List<String> classList = mObjectClassMap.get(typeName); |
| if (classList == null) { |
| classList = new ArrayList<String>(); |
| mObjectClassMap.put(typeName, classList); |
| } |
| classList.add(className); |
| |
| // Increment and store count for this className |
| Integer freq = mClassFrequency.get(className); |
| freq = freq == null ? 1 : freq + 1; |
| mClassFrequency.put(className, freq); |
| |
| return freq; |
| } |
| |
| /** |
| * Adds option to the definition |
| * |
| * @param optionName the name of the option |
| * @param optionValue the option value |
| */ |
| void addOptionDef(String optionName, String optionKey, String optionValue) { |
| if (optionKey == null) { |
| mOptionList.add(new OptionDef(optionName, optionValue)); |
| } else { |
| mOptionList.add(new OptionDef(optionName, optionKey, optionValue)); |
| } |
| } |
| |
| /** |
| * Get the object type name-class map. |
| * <p/> |
| * Exposed for unit testing |
| */ |
| Map<String, List<String>> getObjectClassMap() { |
| return mObjectClassMap; |
| } |
| |
| /** |
| * Get the option name-value map. |
| * <p/> |
| * Exposed for unit testing |
| */ |
| List<OptionDef> getOptionList() { |
| return mOptionList; |
| } |
| |
| /** |
| * Creates a configuration from the info stored in this definition, and populates its fields |
| * with the provided option values. |
| * |
| * @return the created {@link IConfiguration} |
| * @throws ConfigurationException if configuration could not be created |
| */ |
| IConfiguration createConfiguration() throws ConfigurationException { |
| IConfiguration config = new Configuration(getName(), getDescription()); |
| |
| for (Map.Entry<String, List<String>> objClassEntry : mObjectClassMap.entrySet()) { |
| List<Object> objectList = new ArrayList<Object>(objClassEntry.getValue().size()); |
| for (String className : objClassEntry.getValue()) { |
| Object configObject = createObject(objClassEntry.getKey(), className); |
| objectList.add(configObject); |
| } |
| config.setConfigurationObjectList(objClassEntry.getKey(), objectList); |
| } |
| for (OptionDef optionEntry : mOptionList) { |
| if (optionEntry.key == null) { |
| config.injectOptionValue(optionEntry.name, optionEntry.value); |
| } else { |
| config.injectOptionValue(optionEntry.name, optionEntry.key, optionEntry.value); |
| } |
| } |
| |
| return config; |
| } |
| |
| /** |
| * Creates a global configuration from the info stored in this definition, and populates its |
| * fields with the provided option values. |
| * |
| * @return the created {@link IGlobalConfiguration} |
| * @throws ConfigurationException if configuration could not be created |
| */ |
| IGlobalConfiguration createGlobalConfiguration() throws ConfigurationException { |
| IGlobalConfiguration config = new GlobalConfiguration(getName(), getDescription()); |
| |
| for (Map.Entry<String, List<String>> objClassEntry : mObjectClassMap.entrySet()) { |
| List<Object> objectList = new ArrayList<Object>(objClassEntry.getValue().size()); |
| for (String className : objClassEntry.getValue()) { |
| Object configObject = createObject(objClassEntry.getKey(), className); |
| objectList.add(configObject); |
| } |
| config.setConfigurationObjectList(objClassEntry.getKey(), objectList); |
| } |
| for (OptionDef optionEntry : mOptionList) { |
| if (optionEntry.key == null) { |
| config.injectOptionValue(optionEntry.name, optionEntry.value); |
| } else { |
| config.injectOptionValue(optionEntry.name, optionEntry.key, optionEntry.value); |
| } |
| } |
| |
| return config; |
| } |
| |
| /** |
| * Gets the name of this configuration definition |
| * |
| * @return |
| */ |
| public String getName() { |
| return mName; |
| } |
| |
| /** |
| * Creates a config object associated with this definition. |
| * |
| * @param objectTypeName the name of the object. Used to generate more descriptive error |
| * messages |
| * @param className the class name of the object to load |
| * @return the config object |
| * @throws ConfigurationException if config object could not be created |
| */ |
| private Object createObject(String objectTypeName, String className) |
| throws ConfigurationException { |
| try { |
| Class<?> objectClass = getClassForObject(objectTypeName, className); |
| Object configObject = objectClass.newInstance(); |
| return configObject; |
| } catch (InstantiationException e) { |
| throw new ConfigurationException(String.format( |
| "Could not instantiate class %s for config object type %s", className, |
| objectTypeName), e); |
| } catch (IllegalAccessException e) { |
| throw new ConfigurationException(String.format( |
| "Could not access class %s for config object type %s", className, |
| objectTypeName), e); |
| } |
| } |
| |
| /** |
| * Loads the class for the given the config object associated with this definition. |
| * |
| * @param objectTypeName the name of the config object type. Used to generate more descriptive |
| * error messages |
| * @param className the class name of the object to load |
| * @return the config object populated with default option values |
| * @throws ConfigurationException if config object could not be created |
| */ |
| private Class<?> getClassForObject(String objectTypeName, String className) |
| throws ConfigurationException { |
| try { |
| return Class.forName(className); |
| } catch (ClassNotFoundException e) { |
| throw new ConfigurationException( |
| String.format("Could not find class %s for config object type %s", className, |
| objectTypeName), e); |
| } |
| } |
| |
| /** |
| * Add a included ConfigurationDef to this. |
| * |
| * @param includedDef |
| */ |
| void includeConfigDef(ConfigurationDef includedDef) { |
| for (Map.Entry<String, List<String>> mapEntry : |
| includedDef.getObjectClassMap().entrySet()) { |
| for (String configClass : mapEntry.getValue()) { |
| addConfigObjectDef(mapEntry.getKey(), configClass); |
| } |
| } |
| mOptionList.addAll(includedDef.getOptionList()); |
| } |
| } |