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)45 public static File getMergedDynamicConfigFile(File localConfigFile, String apbsConfigJson, 46 String moduleName) throws IOException, XmlPullParserException, JSONException { 47 48 Map<String, List<String>> localConfig = DynamicConfig.createConfigMap(localConfigFile); 49 Map<String, List<String>> apbsConfig = parseJsonToConfigMap(apbsConfigJson); 50 localConfig.putAll(apbsConfig); 51 setRemoteConfigRetrieved(localConfig, apbsConfigJson != null); 52 return storeMergedConfigFile(localConfig, moduleName); 53 } 54 setRemoteConfigRetrieved(Map<String, List<String>> config, boolean retrieved)55 private static void setRemoteConfigRetrieved(Map<String, List<String>> config, 56 boolean retrieved) { 57 List<String> val = Collections.singletonList(Boolean.toString(retrieved)); 58 config.put(DynamicConfig.REMOTE_CONFIG_RETRIEVED_KEY, val); 59 } 60 parseJsonToConfigMap(String apbsConfigJson)61 private static Map<String, List<String>> parseJsonToConfigMap(String apbsConfigJson) 62 throws JSONException { 63 64 Map<String, List<String>> configMap = new HashMap<String, List<String>>(); 65 if (apbsConfigJson == null) { 66 return configMap; 67 } 68 69 JSONObject rootObj = new JSONObject(new JSONTokener(apbsConfigJson)); 70 JSONObject configObject = null; 71 try { 72 configObject = rootObj.getJSONObject("dynamicConfigEntries"); 73 } catch (JSONException e) { 74 // no config key-value(s) pairs have been defined remotely, return empty map 75 return configMap; 76 } 77 JSONArray keys = configObject.names(); 78 for (int i = 0; i < keys.length(); i++) { 79 String key = keys.getString(i); 80 JSONArray jsonValues = configObject.getJSONObject(key).getJSONArray("configValues"); 81 List<String> values = new ArrayList<>(); 82 for (int j = 0; j < jsonValues.length(); j ++) { 83 values.add(jsonValues.getString(j)); 84 } 85 configMap.put(key, values); 86 } 87 return configMap; 88 } 89 storeMergedConfigFile(Map<String, List<String>> configMap, String moduleName)90 private static File storeMergedConfigFile(Map<String, List<String>> configMap, 91 String moduleName) throws XmlPullParserException, IOException { 92 93 File mergedConfigFile = FileUtil.createTempFile(moduleName, FILE_EXT); 94 OutputStream stream = new FileOutputStream(mergedConfigFile); 95 XmlSerializer serializer = XmlPullParserFactory.newInstance().newSerializer(); 96 serializer.setOutput(stream, ENCODING); 97 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 98 serializer.startDocument(ENCODING, false); 99 100 serializer.startTag(NS, DynamicConfig.CONFIG_TAG); 101 for (String key : configMap.keySet()) { 102 serializer.startTag(NS, DynamicConfig.ENTRY_TAG); 103 serializer.attribute(NS, DynamicConfig.KEY_ATTR, key); 104 for (String value : configMap.get(key)) { 105 serializer.startTag(NS, DynamicConfig.VALUE_TAG); 106 serializer.text(value); 107 serializer.endTag(NS, DynamicConfig.VALUE_TAG); 108 } 109 serializer.endTag(NS, DynamicConfig.ENTRY_TAG); 110 } 111 serializer.endTag(NS, DynamicConfig.CONFIG_TAG); 112 serializer.endDocument(); 113 return mergedConfigFile; 114 } 115 } 116