blob: 403055c2d0f11ae860dbf5e0c99a88003888a81e [file] [log] [blame]
Brett Chabote278a5b2010-06-01 16:20:14 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.tradefed.config;
17
18import java.io.PrintStream;
19import java.lang.reflect.Field;
20import java.util.HashMap;
21import java.util.Map;
22
23/**
24 * Holds a record of a configuration, its associated objects and their options.
25 */
26public class ConfigurationDef {
27
28 /** a map of names to config object class names. */
29 private final Map<String, String> mObjectClassMap;
30 /** a map of option names to values. */
31 private final Map<String, String> mOptionMap;
32
33 /** the unique name of the configuration definition */
34 private final String mName;
35
36 /** a short description of the configuration definition */
37 private String mDescription = "";
38
39 public ConfigurationDef(String name) {
40 mName = name;
41 mObjectClassMap = new HashMap<String, String>();
42 mOptionMap = new HashMap<String, String>();
43 }
44
45 /**
46 * Returns a short description of the configuration
47 */
48 public String getDescription() {
49 return mDescription;
50 }
51
52 /**
53 * Sets the configuration definition description
54 */
55 void setDescription(String description) {
56 mDescription = description;
57 }
58
59 /**
60 * Adds a config object to the definition
61 * @param name the config object name
62 * @param className the class name of the config object
63 */
64 void addConfigObjectDef(String name, String className) {
65 mObjectClassMap.put(name, className);
66 }
67
68 /**
69 * Adds option to the definition
70 * @param optionName the name of the option
71 * @param optionValue the option value
72 */
73 void addOptionDef(String optionName, String optionValue) {
74 mOptionMap.put(optionName, optionValue);
75 }
76
77 /**
78 * Get the object name-class map.
79 * <p/>
80 * Exposed for unit testing
81 */
82 Map<String, String> getObjectClassMap() {
83 return mObjectClassMap;
84 }
85
86 /**
87 * Get the option name-value map.
88 * <p/>
89 * Exposed for unit testing
90 */
91 Map<String, String> getOptionMap() {
92 return mOptionMap;
93 }
94
95 /**
96 * Creates a configuration from the info stored in this definition
97 * @return the created {@link IConfiguration}
98 * @throws ConfigurationException if configuration could not be created
99 */
100 IConfiguration createConfiguration() throws ConfigurationException {
101 Map<String, Object> configObjectMap = new HashMap<String, Object>(mObjectClassMap.size());
102 for (Map.Entry<String, String> objClassEntry : mObjectClassMap.entrySet()) {
103 Object configObject = createObject(objClassEntry.getKey(), objClassEntry.getValue());
104 configObjectMap.put(objClassEntry.getKey(), configObject);
105 }
106 OptionSetter setter = new OptionSetter(configObjectMap.values());
107 for (Map.Entry<String, String> optionEntry : mOptionMap.entrySet()) {
108 setter.setOptionValue(optionEntry.getKey(), optionEntry.getValue());
109 }
110
111 return new Configuration(configObjectMap);
112 }
113
114 /**
115 * Gets the name of this configuration definition
116 * @return
117 */
118 public String getName() {
119 return mName;
120 }
121
122 /**
123 * Outputs a command line usage help text for this configuration to given printStream.
124 *
125 * @param out the {@link PrintStream} to use.
126 * @throws {@link ConfigurationException}
127 */
128 public void printCommandUsage(PrintStream out) throws ConfigurationException {
129 out.println(String.format("'%s' configuration: %s", getName(), getDescription()));
130 out.println();
131 for (Map.Entry<String, String> configObjectEntry : mObjectClassMap.entrySet()) {
132 String optionHelp = printOptionsForObject(configObjectEntry.getKey(),
133 configObjectEntry.getValue());
134 // only print help for object if optionHelp is non zero length
135 if (optionHelp.length() > 0) {
136 out.printf(" %s options:", configObjectEntry.getKey());
137 out.println();
138 out.print(optionHelp);
139 out.println();
140 }
141 }
142 }
143
144 /**
145 * Prints out the available config options for given configuration object.
146 *
147 * @param objectName the name of the object. Used to generate more descriptive error messages
148 * @param className the class name of the object to load
149 * @return a {@link String} of option help text
150 * @throws ConfigurationException
151 */
152 private String printOptionsForObject(String objectName, String objectClass)
153 throws ConfigurationException {
154 String eol = System.getProperty("line.separator");
155 StringBuilder out = new StringBuilder();
156 final Class<?> optionClass = getClassForObject(objectName, objectClass);
157 for (Field field : optionClass.getDeclaredFields()) {
158 // TODO: consider moving this logic to ArgsOptionParser
159 if (field.isAnnotationPresent(Option.class)) {
160 final Option option = field.getAnnotation(Option.class);
161 out.append(String.format(" %s%s: %s", ArgsOptionParser.OPTION_NAME_PREFIX,
162 option.name(), option.description()));
163 out.append(eol);
164 }
165 }
166 return out.toString();
167 }
168
169 /**
170 * Creates a config object associated with this definition.
171 *
172 * @param objectName the name of the object. Used to generate more descriptive error messages
173 * @param className the class name of the object to load
174 * @return the config object
175 * @throws ConfigurationException if config object could not be created
176 */
177 private Object createObject(String objectName, String className) throws ConfigurationException {
178 try {
179 Class<?> objectClass = getClassForObject(objectName, className);
180 Object configObject = objectClass.newInstance();
181 return configObject;
182 } catch (InstantiationException e) {
183 throw new ConfigurationException(String.format(
184 "Could not instantiate class %s for config object name %s", className,
185 objectName), e);
186 } catch (IllegalAccessException e) {
187 throw new ConfigurationException(String.format(
188 "Could not access class %s for config object name %s", className, objectName),
189 e);
190 }
191 }
192
193 /**
194 * Loads the class for the given the config object associated with this definition.
195 *
196 * @param objectName the name of the object. Used to generate more descriptive error messages
197 * @param className the class name of the object to load
198 * @return the config object populated with default option values
199 * @throws ConfigurationException if config object could not be created
200 */
201 private Class<?> getClassForObject(String objectName, String className)
202 throws ConfigurationException {
203 try {
204 return Class.forName(className);
205 } catch (ClassNotFoundException e) {
206 throw new ConfigurationException(String.format(
207 "Could not find class %s for config object name %s", className, objectName), e);
208 }
209 }
210}