1 /* 2 * Copyright (C) 2023 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.command.remote.DeviceDescriptor; 20 import com.android.tradefed.log.LogUtil.CLog; 21 import com.android.tradefed.targetprep.TargetSetupError; 22 23 import com.google.common.annotations.VisibleForTesting; 24 25 import org.xmlpull.v1.XmlPullParser; 26 import org.xmlpull.v1.XmlPullParserException; 27 import org.xmlpull.v1.XmlPullParserFactory; 28 29 import java.io.File; 30 import java.io.FileInputStream; 31 import java.io.IOException; 32 import java.io.InputStream; 33 import java.io.InputStreamReader; 34 import java.net.URISyntaxException; 35 import java.security.CodeSource; 36 import java.util.HashMap; 37 import java.util.Map; 38 39 /** 40 * Reads URL replacement configurations from the config file UrlReplacement.xml in the 41 * android-cts/tools directory (if it exists), or from the file path set in the env variable 42 * URL_REPLACEMENT_PATH. 43 * 44 * <p>Example usage: UrlReplacement.init(); // MUST be the first call to this class. String 45 * dynamicConfigUrl = UrlReplacement.getDynamicConfigServerUrl(); ... 46 * UrlReplacement.getUrlReplacementMap(); 47 */ 48 public final class UrlReplacement { 49 private static final String NS = null; 50 private static final String DYNAMIC_CONFIG_URL_TAG = "dynamicConfigUrl"; 51 private static final String URL_REPLACEMENT_TAG = "urlReplacement"; 52 private static final String ENTRY_TAG = "entry"; 53 private static final String REPLACEMENT_TAG = "replacement"; 54 private static final String URL_ATTR = "url"; 55 private static final String URL_REPLACEMENT_FILENAME = "UrlReplacement.xml"; 56 57 private static final String URL_REPLACEMENT_PATH_ENV = "URL_REPLACEMENT_PATH"; 58 59 private static String dynamicConfigServerUrl = null; 60 private static Map<String, String> urlReplacementMap = new HashMap<>(); 61 62 @VisibleForTesting static Boolean initialized = false; 63 64 /** Initializes the Dynamic Config Server URL and URL replacements from the xml file. */ init()65 public static void init() throws TargetSetupError { 66 init(getUrlReplacementConfigFile()); 67 } 68 69 /** Gets the URL for the DynamicConfigServer. Must be called after init(). */ getDynamicConfigServerUrl()70 public static String getDynamicConfigServerUrl() { 71 return dynamicConfigServerUrl; 72 } 73 74 /** Gets the URL replacement map. Must be called after init(). */ getUrlReplacementMap()75 public static Map<String, String> getUrlReplacementMap() { 76 return new HashMap<>(urlReplacementMap); 77 } 78 79 @VisibleForTesting init(File urlReplacementConfigFile)80 static void init(File urlReplacementConfigFile) throws TargetSetupError { 81 if (initialized) { 82 return; 83 } 84 synchronized (UrlReplacement.class) { 85 if (initialized) { 86 return; 87 } 88 try { 89 if (urlReplacementConfigFile.exists()) { 90 InputStream inputStream = new FileInputStream(urlReplacementConfigFile); 91 XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); 92 parser.setInput(new InputStreamReader(inputStream)); 93 parser.nextTag(); 94 95 parser.require(XmlPullParser.START_TAG, NS, URL_REPLACEMENT_TAG); 96 parser.nextTag(); 97 98 parser.require(XmlPullParser.START_TAG, NS, DYNAMIC_CONFIG_URL_TAG); 99 dynamicConfigServerUrl = parser.nextText(); 100 parser.require(XmlPullParser.END_TAG, NS, DYNAMIC_CONFIG_URL_TAG); 101 102 while (parser.nextTag() == XmlPullParser.START_TAG) { 103 parser.require(XmlPullParser.START_TAG, NS, ENTRY_TAG); 104 String key = parser.getAttributeValue(NS, URL_ATTR); 105 parser.nextTag(); 106 parser.require(XmlPullParser.START_TAG, NS, REPLACEMENT_TAG); 107 String value = parser.nextText(); 108 parser.require(XmlPullParser.END_TAG, NS, REPLACEMENT_TAG); 109 parser.nextTag(); 110 parser.require(XmlPullParser.END_TAG, NS, ENTRY_TAG); 111 if (key != null && value != null) { 112 urlReplacementMap.put(key, value); 113 } 114 } 115 116 parser.require(XmlPullParser.END_TAG, NS, URL_REPLACEMENT_TAG); 117 } else { 118 CLog.i( 119 "UrlReplacement file [%s] does not exist", 120 urlReplacementConfigFile.getAbsolutePath()); 121 } 122 initialized = true; 123 } catch (XmlPullParserException | IOException e) { 124 throw new TargetSetupError( 125 "Failed to parse URL replacement config", e, (DeviceDescriptor) null); 126 } 127 } 128 } 129 130 @VisibleForTesting getUrlReplacementConfigFile()131 static File getUrlReplacementConfigFile() throws TargetSetupError { 132 // Try to get the config file from the .jar directory. 133 CodeSource codeSource = UrlReplacement.class.getProtectionDomain().getCodeSource(); 134 String toolDirectory; 135 try { 136 toolDirectory = new File(codeSource.getLocation().toURI()).getParent(); 137 } catch (URISyntaxException e) { 138 throw new TargetSetupError( 139 "Failed to locate urlReplacement.xml file", e, (DeviceDescriptor) null); 140 } 141 File file = new File(toolDirectory + File.separator + URL_REPLACEMENT_FILENAME); 142 143 // Try to get the config file from environment variable. 144 if (!file.exists()) { 145 String urlReplacementPathEnv = System.getenv(URL_REPLACEMENT_PATH_ENV); 146 if (urlReplacementPathEnv != null) { 147 return new File(urlReplacementPathEnv); 148 } 149 } 150 return file; 151 } 152 UrlReplacement()153 private UrlReplacement() {} 154 } 155