001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017 package org.apache.logging.log4j.core.helpers; 018 019 import org.apache.logging.log4j.Logger; 020 import org.apache.logging.log4j.status.StatusLogger; 021 022 import java.util.Locale; 023 import java.util.Properties; 024 025 /** 026 * A convenience class to convert property values to specific types. 027 */ 028 public final class OptionConverter { 029 030 private static final Logger LOGGER = StatusLogger.getLogger(); 031 032 private static final String DELIM_START = "${"; 033 private static final char DELIM_STOP = '}'; 034 private static final int DELIM_START_LEN = 2; 035 private static final int DELIM_STOP_LEN = 1; 036 private static final int ONE_K = 1024; 037 038 /** 039 * OptionConverter is a static class. 040 */ 041 private OptionConverter() { 042 } 043 044 public static String[] concatanateArrays(String[] l, String[] r) { 045 int len = l.length + r.length; 046 String[] a = new String[len]; 047 048 System.arraycopy(l, 0, a, 0, l.length); 049 System.arraycopy(r, 0, a, l.length, r.length); 050 051 return a; 052 } 053 054 public static String convertSpecialChars(String s) { 055 char c; 056 int len = s.length(); 057 StringBuffer sbuf = new StringBuffer(len); 058 059 int i = 0; 060 while (i < len) { 061 c = s.charAt(i++); 062 if (c == '\\') { 063 c = s.charAt(i++); 064 if (c == 'n') { 065 c = '\n'; 066 } else if (c == 'r') { 067 c = '\r'; 068 } else if (c == 't') { 069 c = '\t'; 070 } else if (c == 'f') { 071 c = '\f'; 072 } else if (c == '\b') { 073 c = '\b'; 074 } else if (c == '\"') { 075 c = '\"'; 076 } else if (c == '\'') { 077 c = '\''; 078 } else if (c == '\\') { 079 c = '\\'; 080 } 081 } 082 sbuf.append(c); 083 } 084 return sbuf.toString(); 085 } 086 087 088 /** 089 * Very similar to <code>System.getProperty</code> except 090 * that the {@link SecurityException} is hidden. 091 * 092 * @param key The key to search for. 093 * @param def The default value to return. 094 * @return the string value of the system property, or the default 095 * value if there is no property with that key. 096 */ 097 public static String getSystemProperty(String key, String def) { 098 try { 099 return System.getProperty(key, def); 100 } catch (Throwable e) { // MS-Java throws com.ms.security.SecurityExceptionEx 101 LOGGER.debug("Was not allowed to read system property \"" + key + "\"."); 102 return def; 103 } 104 } 105 106 107 public static Object instantiateByKey(Properties props, String key, Class<?> superClass, 108 Object defaultValue) { 109 110 // Get the value of the property in string form 111 String className = findAndSubst(key, props); 112 if (className == null) { 113 LOGGER.error("Could not find value for key " + key); 114 return defaultValue; 115 } 116 // Trim className to avoid trailing spaces that cause problems. 117 return OptionConverter.instantiateByClassName(className.trim(), superClass, 118 defaultValue); 119 } 120 121 /** 122 * If <code>value</code> is "true", then {@code true} is 123 * returned. If <code>value</code> is "false", then 124 * {@code true} is returned. Otherwise, <code>default</code> is 125 * returned. 126 * <p/> 127 * <p>Case of value is unimportant. 128 * @param value The value to convert. 129 * @param dEfault The default value. 130 * @return true or false, depending on the value and/or default. 131 */ 132 public static boolean toBoolean(String value, boolean dEfault) { 133 if (value == null) { 134 return dEfault; 135 } 136 String trimmedVal = value.trim(); 137 if ("true".equalsIgnoreCase(trimmedVal)) { 138 return true; 139 } 140 if ("false".equalsIgnoreCase(trimmedVal)) { 141 return false; 142 } 143 return dEfault; 144 } 145 146 /** 147 * Convert the String value to an int. 148 * @param value The value as a String. 149 * @param dEfault The default value. 150 * @return The value as an int. 151 */ 152 public static int toInt(String value, int dEfault) { 153 if (value != null) { 154 String s = value.trim(); 155 try { 156 return Integer.valueOf(s); 157 } catch (NumberFormatException e) { 158 LOGGER.error("[" + s + "] is not in proper int form."); 159 e.printStackTrace(); 160 } 161 } 162 return dEfault; 163 } 164 165 /** 166 * 167 * @param value The size of the file as a String. 168 * @param defaultValue The default value. 169 * @return The size of the file as a long. 170 */ 171 public static long toFileSize(String value, long defaultValue) { 172 if (value == null) { 173 return defaultValue; 174 } 175 176 String s = value.trim().toUpperCase(Locale.ENGLISH); 177 long multiplier = 1; 178 int index; 179 180 if ((index = s.indexOf("KB")) != -1) { 181 multiplier = ONE_K; 182 s = s.substring(0, index); 183 } else if ((index = s.indexOf("MB")) != -1) { 184 multiplier = ONE_K * ONE_K; 185 s = s.substring(0, index); 186 } else if ((index = s.indexOf("GB")) != -1) { 187 multiplier = ONE_K * ONE_K * ONE_K; 188 s = s.substring(0, index); 189 } 190 if (s != null) { 191 try { 192 return Long.valueOf(s) * multiplier; 193 } catch (NumberFormatException e) { 194 LOGGER.error("[" + s + "] is not in proper int form."); 195 LOGGER.error("[" + value + "] not in expected format.", e); 196 } 197 } 198 return defaultValue; 199 } 200 201 /** 202 * Find the value corresponding to <code>key</code> in 203 * <code>props</code>. Then perform variable substitution on the 204 * found value. 205 * @param key The key to locate. 206 * @param props The properties. 207 * @return The String after substitution. 208 */ 209 public static String findAndSubst(String key, Properties props) { 210 String value = props.getProperty(key); 211 if (value == null) { 212 return null; 213 } 214 215 try { 216 return substVars(value, props); 217 } catch (IllegalArgumentException e) { 218 LOGGER.error("Bad option value [" + value + "].", e); 219 return value; 220 } 221 } 222 223 /** 224 * Instantiate an object given a class name. Check that the 225 * <code>className</code> is a subclass of 226 * <code>superClass</code>. If that test fails or the object could 227 * not be instantiated, then <code>defaultValue</code> is returned. 228 * 229 * @param className The fully qualified class name of the object to instantiate. 230 * @param superClass The class to which the new object should belong. 231 * @param defaultValue The object to return in case of non-fulfillment 232 * @return The created object. 233 */ 234 public static Object instantiateByClassName(String className, Class<?> superClass, 235 Object defaultValue) { 236 if (className != null) { 237 try { 238 Class<?> classObj = Loader.loadClass(className); 239 if (!superClass.isAssignableFrom(classObj)) { 240 LOGGER.error("A \"" + className + "\" object is not assignable to a \"" + 241 superClass.getName() + "\" variable."); 242 LOGGER.error("The class \"" + superClass.getName() + "\" was loaded by "); 243 LOGGER.error("[" + superClass.getClassLoader() + "] whereas object of type "); 244 LOGGER.error("\"" + classObj.getName() + "\" was loaded by [" 245 + classObj.getClassLoader() + "]."); 246 return defaultValue; 247 } 248 return classObj.newInstance(); 249 } catch (ClassNotFoundException e) { 250 LOGGER.error("Could not instantiate class [" + className + "].", e); 251 } catch (IllegalAccessException e) { 252 LOGGER.error("Could not instantiate class [" + className + "].", e); 253 } catch (InstantiationException e) { 254 LOGGER.error("Could not instantiate class [" + className + "].", e); 255 } catch (RuntimeException e) { 256 LOGGER.error("Could not instantiate class [" + className + "].", e); 257 } 258 } 259 return defaultValue; 260 } 261 262 263 /** 264 * Perform variable substitution in string <code>val</code> from the 265 * values of keys found in the system propeties. 266 * <p/> 267 * <p>The variable substitution delimeters are <b>${</b> and <b>}</b>. 268 * <p/> 269 * <p>For example, if the System properties contains "key=value", then 270 * the call 271 * <pre> 272 * String s = OptionConverter.substituteVars("Value of key is ${key}."); 273 * </pre> 274 * <p/> 275 * will set the variable <code>s</code> to "Value of key is value.". 276 * <p/> 277 * <p>If no value could be found for the specified key, then the 278 * <code>props</code> parameter is searched, if the value could not 279 * be found there, then substitution defaults to the empty string. 280 * <p/> 281 * <p>For example, if system propeties contains no value for the key 282 * "inexistentKey", then the call 283 * <p/> 284 * <pre> 285 * String s = OptionConverter.subsVars("Value of inexistentKey is [${inexistentKey}]"); 286 * </pre> 287 * will set <code>s</code> to "Value of inexistentKey is []" 288 * <p/> 289 * <p>An {@link java.lang.IllegalArgumentException} is thrown if 290 * <code>val</code> contains a start delimeter "${" which is not 291 * balanced by a stop delimeter "}". </p> 292 * <p/> 293 * <p><b>Author</b> Avy Sharell</a></p> 294 * 295 * @param val The string on which variable substitution is performed. 296 * @param props The properties to use for substitution. 297 * @return The String after substitution. 298 * @throws IllegalArgumentException if <code>val</code> is malformed. 299 */ 300 public static String substVars(String val, Properties props) throws 301 IllegalArgumentException { 302 303 StringBuilder sbuf = new StringBuilder(); 304 305 int i = 0; 306 int j; 307 int k; 308 309 while (true) { 310 j = val.indexOf(DELIM_START, i); 311 if (j == -1) { 312 // no more variables 313 if (i == 0) { // this is a simple string 314 return val; 315 } else { // add the tail string which contails no variables and return the result. 316 sbuf.append(val.substring(i, val.length())); 317 return sbuf.toString(); 318 } 319 } else { 320 sbuf.append(val.substring(i, j)); 321 k = val.indexOf(DELIM_STOP, j); 322 if (k == -1) { 323 throw new IllegalArgumentException('"' + val + 324 "\" has no closing brace. Opening brace at position " + j 325 + '.'); 326 } else { 327 j += DELIM_START_LEN; 328 String key = val.substring(j, k); 329 // first try in System properties 330 String replacement = getSystemProperty(key, null); 331 // then try props parameter 332 if (replacement == null && props != null) { 333 replacement = props.getProperty(key); 334 } 335 336 if (replacement != null) { 337 // Do variable substitution on the replacement string 338 // such that we can solve "Hello ${x2}" as "Hello p1" 339 // the where the properties are 340 // x1=p1 341 // x2=${x1} 342 String recursiveReplacement = substVars(replacement, props); 343 sbuf.append(recursiveReplacement); 344 } 345 i = k + DELIM_STOP_LEN; 346 } 347 } 348 } 349 } 350 }