• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.compatibility.common.util;
18 
19 import com.android.tradefed.util.FileUtil;
20 
21 import org.json.JSONArray;
22 import org.json.JSONException;
23 import org.json.JSONObject;
24 import org.json.JSONTokener;
25 import org.xmlpull.v1.XmlPullParserException;
26 import org.xmlpull.v1.XmlPullParserFactory;
27 import org.xmlpull.v1.XmlSerializer;
28 
29 import java.io.File;
30 import java.io.FileOutputStream;
31 import java.io.IOException;
32 import java.io.OutputStream;
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 
39 public class DynamicConfigHandler {
40 
41     private final static String FILE_EXT = ".dynamic";
42     private static final String NS = null; //xml constant representing null namespace
43     private static final String ENCODING = "UTF-8";
44 
getMergedDynamicConfigFile( File localConfigFile, String apbsConfigJson, String moduleName, Map<String, String> valueReplacementMap)45     public static File getMergedDynamicConfigFile(
46             File localConfigFile,
47             String apbsConfigJson,
48             String moduleName,
49             Map<String, String> valueReplacementMap)
50             throws IOException, XmlPullParserException, JSONException {
51         Map<String, List<String>> dynamicConfig = new HashMap<>();
52 
53         Map<String, List<String>> localConfig = DynamicConfig.createConfigMap(localConfigFile);
54         Map<String, List<String>> apbsConfig = parseJsonToConfigMap(apbsConfigJson);
55         localConfig.putAll(apbsConfig);
56 
57         localConfig.forEach(
58                 (k, v) -> {
59                     dynamicConfig.put(k, updateValues(v, valueReplacementMap));
60                 });
61 
62         setRemoteConfigRetrieved(dynamicConfig, apbsConfigJson != null);
63         return storeMergedConfigFile(dynamicConfig, moduleName);
64     }
65 
updateValues( List<String> values, Map<String, String> valueReplacementMap)66     private static List<String> updateValues(
67             List<String> values, Map<String, String> valueReplacementMap) {
68         List<String> updatedValues = new ArrayList<>();
69         values.forEach(
70                 v -> {
71                     String updatedValue = v;
72                     for (Map.Entry<String, String> entry : valueReplacementMap.entrySet()) {
73                         updatedValue = updatedValue.replace(entry.getKey(), entry.getValue());
74                     }
75                     updatedValues.add(updatedValue);
76                 });
77         return updatedValues;
78     }
79 
setRemoteConfigRetrieved(Map<String, List<String>> config, boolean retrieved)80     private static void setRemoteConfigRetrieved(Map<String, List<String>> config,
81             boolean retrieved) {
82         List<String> val = Collections.singletonList(Boolean.toString(retrieved));
83         config.put(DynamicConfig.REMOTE_CONFIG_RETRIEVED_KEY, val);
84     }
85 
parseJsonToConfigMap(String apbsConfigJson)86     private static Map<String, List<String>> parseJsonToConfigMap(String apbsConfigJson)
87             throws JSONException {
88 
89         Map<String, List<String>> configMap = new HashMap<String, List<String>>();
90         if (apbsConfigJson == null) {
91             return configMap;
92         }
93 
94         JSONObject rootObj  = new JSONObject(new JSONTokener(apbsConfigJson));
95         JSONObject configObject  = null;
96         try {
97             configObject = rootObj.getJSONObject("dynamicConfigEntries");
98         } catch (JSONException e) {
99             // no config key-value(s) pairs have been defined remotely, return empty map
100             return configMap;
101         }
102         JSONArray keys = configObject.names();
103         for (int i = 0; i < keys.length(); i++) {
104             String key = keys.getString(i);
105             JSONArray jsonValues = configObject.getJSONObject(key).getJSONArray("configValues");
106             List<String> values = new ArrayList<>();
107             for (int j = 0; j < jsonValues.length(); j ++) {
108                 values.add(jsonValues.getString(j));
109             }
110             configMap.put(key, values);
111         }
112         return configMap;
113     }
114 
storeMergedConfigFile(Map<String, List<String>> configMap, String moduleName)115     private static File storeMergedConfigFile(Map<String, List<String>> configMap,
116             String moduleName) throws XmlPullParserException, IOException {
117 
118         File mergedConfigFile = FileUtil.createTempFile(moduleName, FILE_EXT);
119         OutputStream stream = new FileOutputStream(mergedConfigFile);
120         XmlSerializer serializer = XmlPullParserFactory.newInstance().newSerializer();
121         serializer.setOutput(stream, ENCODING);
122         serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
123         serializer.startDocument(ENCODING, false);
124 
125         serializer.startTag(NS, DynamicConfig.CONFIG_TAG);
126         for (String key : configMap.keySet()) {
127             serializer.startTag(NS, DynamicConfig.ENTRY_TAG);
128             serializer.attribute(NS, DynamicConfig.KEY_ATTR, key);
129             for (String value : configMap.get(key)) {
130                 serializer.startTag(NS, DynamicConfig.VALUE_TAG);
131                 serializer.text(value);
132                 serializer.endTag(NS, DynamicConfig.VALUE_TAG);
133             }
134             serializer.endTag(NS, DynamicConfig.ENTRY_TAG);
135         }
136         serializer.endTag(NS, DynamicConfig.CONFIG_TAG);
137         serializer.endDocument();
138         return mergedConfigFile;
139     }
140 }
141