Home | History | Annotate | Download | only in config
      1 /*
      2  * Copyright (C) 2017 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  */
     16 
     17 package com.android.tradefed.config;
     18 
     19 import com.android.tradefed.log.LogUtil.CLog;
     20 import com.android.tradefed.util.FileUtil;
     21 import com.android.tradefed.util.MultiMap;
     22 
     23 import org.kxml2.io.KXmlSerializer;
     24 
     25 import java.io.File;
     26 import java.io.IOException;
     27 import java.io.PrintWriter;
     28 import java.lang.reflect.Field;
     29 import java.util.Collection;
     30 import java.util.HashSet;
     31 import java.util.List;
     32 import java.util.Map;
     33 import java.util.Map.Entry;
     34 import java.util.Set;
     35 
     36 /** Utility functions to handle configuration files. */
     37 public class ConfigurationUtil {
     38 
     39     // Element names used for emitting the configuration XML.
     40     public static final String CONFIGURATION_NAME = "configuration";
     41     public static final String OPTION_NAME = "option";
     42     public static final String CLASS_NAME = "class";
     43     public static final String NAME_NAME = "name";
     44     public static final String KEY_NAME = "key";
     45     public static final String VALUE_NAME = "value";
     46 
     47     /**
     48      * Create a serializer to be used to create a new configuration file.
     49      *
     50      * @param outputXml the XML file to write to
     51      * @return a {@link KXmlSerializer}
     52      */
     53     static KXmlSerializer createSerializer(File outputXml) throws IOException {
     54         PrintWriter output = new PrintWriter(outputXml);
     55         KXmlSerializer serializer = new KXmlSerializer();
     56         serializer.setOutput(output);
     57         serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
     58         serializer.startDocument("UTF-8", null);
     59         return serializer;
     60     }
     61 
     62     /**
     63      * Add a class to the configuration XML dump.
     64      *
     65      * @param serializer a {@link KXmlSerializer} to create the XML dump
     66      * @param classTypeName a {@link String} of the class type's name
     67      * @param obj {@link Object} to be added to the XML dump
     68      * @param excludeClassTypes list of object configuration type to be excluded from the dump. for
     69      *     example: {@link Configuration#TARGET_PREPARER_TYPE_NAME}.
     70      */
     71     static void dumpClassToXml(
     72             KXmlSerializer serializer,
     73             String classTypeName,
     74             Object obj,
     75             List<String> excludeClassTypes)
     76             throws IOException {
     77         if (excludeClassTypes.contains(classTypeName)) {
     78             return;
     79         }
     80         serializer.startTag(null, classTypeName);
     81         serializer.attribute(null, CLASS_NAME, obj.getClass().getName());
     82         dumpOptionsToXml(serializer, obj);
     83         serializer.endTag(null, classTypeName);
     84     }
     85 
     86     /**
     87      * Add all the options of class to the command XML dump.
     88      *
     89      * @param serializer a {@link KXmlSerializer} to create the XML dump
     90      * @param obj {@link Object} to be added to the XML dump
     91      */
     92     @SuppressWarnings({"rawtypes", "unchecked"})
     93     private static void dumpOptionsToXml(KXmlSerializer serializer, Object obj) throws IOException {
     94         for (Field field : OptionSetter.getOptionFieldsForClass(obj.getClass())) {
     95             Option option = field.getAnnotation(Option.class);
     96             Object fieldVal = OptionSetter.getFieldValue(field, obj);
     97             if (fieldVal == null) {
     98                 continue;
     99             } else if (fieldVal instanceof Collection) {
    100                 for (Object entry : (Collection) fieldVal) {
    101                     dumpOptionToXml(serializer, option.name(), null, entry.toString());
    102                 }
    103             } else if (fieldVal instanceof Map) {
    104                 Map map = (Map) fieldVal;
    105                 for (Object entryObj : map.entrySet()) {
    106                     Map.Entry entry = (Entry) entryObj;
    107                     dumpOptionToXml(
    108                             serializer,
    109                             option.name(),
    110                             entry.getKey().toString(),
    111                             entry.getValue().toString());
    112                 }
    113             } else if (fieldVal instanceof MultiMap) {
    114                 MultiMap multimap = (MultiMap) fieldVal;
    115                 for (Object keyObj : multimap.keySet()) {
    116                     for (Object valueObj : multimap.get(keyObj)) {
    117                         dumpOptionToXml(
    118                                 serializer, option.name(), keyObj.toString(), valueObj.toString());
    119                     }
    120                 }
    121             } else {
    122                 dumpOptionToXml(serializer, option.name(), null, fieldVal.toString());
    123             }
    124         }
    125     }
    126 
    127     /**
    128      * Add a single option to the command XML dump.
    129      *
    130      * @param serializer a {@link KXmlSerializer} to create the XML dump
    131      * @param name a {@link String} of the option's name
    132      * @param key a {@link String} of the option's key, used as name if param name is null
    133      * @param value a {@link String} of the option's value
    134      */
    135     private static void dumpOptionToXml(
    136             KXmlSerializer serializer, String name, String key, String value) throws IOException {
    137         serializer.startTag(null, OPTION_NAME);
    138         serializer.attribute(null, NAME_NAME, name);
    139         if (key != null) {
    140             serializer.attribute(null, KEY_NAME, key);
    141         }
    142         serializer.attribute(null, VALUE_NAME, value);
    143         serializer.endTag(null, OPTION_NAME);
    144     }
    145 
    146     /**
    147      * Helper to get the test config files from given directories.
    148      *
    149      * @param subPath where to look for configuration. Can be null.
    150      * @param dirs a list of {@link File} of extra directories to search for test configs
    151      */
    152     public static Set<String> getConfigNamesFromDirs(String subPath, List<File> dirs) {
    153         Set<String> configNames = new HashSet<String>();
    154         for (File dir : dirs) {
    155             if (subPath != null) {
    156                 dir = new File(dir, subPath);
    157             }
    158             if (!dir.isDirectory()) {
    159                 CLog.d("%s doesn't exist or is not a directory.", dir.getAbsolutePath());
    160                 continue;
    161             }
    162             try {
    163                 configNames.addAll(FileUtil.findFiles(dir, ".*.config"));
    164                 configNames.addAll(FileUtil.findFiles(dir, ".*.xml"));
    165             } catch (IOException e) {
    166                 CLog.w("Failed to get test config files from directory %s", dir.getAbsolutePath());
    167             }
    168         }
    169         return configNames;
    170     }
    171 }
    172