aboutsummaryrefslogtreecommitdiff
path: root/src/com/android/tradefed/config/ConfigurationUtil.java
blob: f3eb748918a6c3a85237c1d8bc26f245c62b3220 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/*
 * Copyright (C) 2017 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 com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.MultiMap;

import org.kxml2.io.KXmlSerializer;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/** Utility functions to handle configuration files. */
public class ConfigurationUtil {

    // Element names used for emitting the configuration XML.
    public static final String CONFIGURATION_NAME = "configuration";
    public static final String OPTION_NAME = "option";
    public static final String CLASS_NAME = "class";
    public static final String NAME_NAME = "name";
    public static final String KEY_NAME = "key";
    public static final String VALUE_NAME = "value";

    /**
     * Create a serializer to be used to create a new configuration file.
     *
     * @param outputXml the XML file to write to
     * @return a {@link KXmlSerializer}
     */
    static KXmlSerializer createSerializer(File outputXml) throws IOException {
        PrintWriter output = new PrintWriter(outputXml);
        KXmlSerializer serializer = new KXmlSerializer();
        serializer.setOutput(output);
        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
        serializer.startDocument("UTF-8", null);
        return serializer;
    }

    /**
     * Add a class to the configuration XML dump.
     *
     * @param serializer a {@link KXmlSerializer} to create the XML dump
     * @param classTypeName a {@link String} of the class type's name
     * @param obj {@link Object} to be added to the XML dump
     * @param excludeClassTypes list of object configuration type to be excluded from the dump. for
     *     example: {@link Configuration#TARGET_PREPARER_TYPE_NAME}.
     */
    static void dumpClassToXml(
            KXmlSerializer serializer,
            String classTypeName,
            Object obj,
            List<String> excludeClassTypes)
            throws IOException {
        if (excludeClassTypes.contains(classTypeName)) {
            return;
        }
        serializer.startTag(null, classTypeName);
        serializer.attribute(null, CLASS_NAME, obj.getClass().getName());
        dumpOptionsToXml(serializer, obj);
        serializer.endTag(null, classTypeName);
    }

    /**
     * Add all the options of class to the command XML dump.
     *
     * @param serializer a {@link KXmlSerializer} to create the XML dump
     * @param obj {@link Object} to be added to the XML dump
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    private static void dumpOptionsToXml(KXmlSerializer serializer, Object obj) throws IOException {
        for (Field field : OptionSetter.getOptionFieldsForClass(obj.getClass())) {
            Option option = field.getAnnotation(Option.class);
            Object fieldVal = OptionSetter.getFieldValue(field, obj);
            if (fieldVal == null) {
                continue;
            } else if (fieldVal instanceof Collection) {
                for (Object entry : (Collection) fieldVal) {
                    dumpOptionToXml(serializer, option.name(), null, entry.toString());
                }
            } else if (fieldVal instanceof Map) {
                Map map = (Map) fieldVal;
                for (Object entryObj : map.entrySet()) {
                    Map.Entry entry = (Entry) entryObj;
                    dumpOptionToXml(
                            serializer,
                            option.name(),
                            entry.getKey().toString(),
                            entry.getValue().toString());
                }
            } else if (fieldVal instanceof MultiMap) {
                MultiMap multimap = (MultiMap) fieldVal;
                for (Object keyObj : multimap.keySet()) {
                    for (Object valueObj : multimap.get(keyObj)) {
                        dumpOptionToXml(
                                serializer, option.name(), keyObj.toString(), valueObj.toString());
                    }
                }
            } else {
                dumpOptionToXml(serializer, option.name(), null, fieldVal.toString());
            }
        }
    }

    /**
     * Add a single option to the command XML dump.
     *
     * @param serializer a {@link KXmlSerializer} to create the XML dump
     * @param name a {@link String} of the option's name
     * @param key a {@link String} of the option's key, used as name if param name is null
     * @param value a {@link String} of the option's value
     */
    private static void dumpOptionToXml(
            KXmlSerializer serializer, String name, String key, String value) throws IOException {
        serializer.startTag(null, OPTION_NAME);
        serializer.attribute(null, NAME_NAME, name);
        if (key != null) {
            serializer.attribute(null, KEY_NAME, key);
        }
        serializer.attribute(null, VALUE_NAME, value);
        serializer.endTag(null, OPTION_NAME);
    }

    /**
     * Helper to get the test config files from given directories.
     *
     * @param subPath where to look for configuration. Can be null.
     * @param dirs a list of {@link File} of extra directories to search for test configs
     */
    public static Set<String> getConfigNamesFromDirs(String subPath, List<File> dirs) {
        Set<String> configNames = new HashSet<String>();
        for (File dir : dirs) {
            if (subPath != null) {
                dir = new File(dir, subPath);
            }
            if (!dir.isDirectory()) {
                CLog.d("%s doesn't exist or is not a directory.", dir.getAbsolutePath());
                continue;
            }
            try {
                configNames.addAll(FileUtil.findFiles(dir, ".*.config"));
                configNames.addAll(FileUtil.findFiles(dir, ".*.xml"));
            } catch (IOException e) {
                CLog.w("Failed to get test config files from directory %s", dir.getAbsolutePath());
            }
        }
        return configNames;
    }
}