X-Git-Url: http://source.jalview.org/gitweb/?p=jalview.git;a=blobdiff_plain;f=srcjar%2Forg%2Fapache%2Flog4j%2Fhelpers%2FOptionConverter.java;fp=srcjar%2Forg%2Fapache%2Flog4j%2Fhelpers%2FOptionConverter.java;h=e16b195f03c41dd22e0a1ac5d31777126609cfdc;hp=0000000000000000000000000000000000000000;hb=2d6292c0377bc6b773c6844a45d3f2c5fac352c7;hpb=954af328a2a6a0055572cd1a09ee035301222574 diff --git a/srcjar/org/apache/log4j/helpers/OptionConverter.java b/srcjar/org/apache/log4j/helpers/OptionConverter.java new file mode 100644 index 0000000..e16b195 --- /dev/null +++ b/srcjar/org/apache/log4j/helpers/OptionConverter.java @@ -0,0 +1,543 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.helpers; + +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.net.URL; +import java.util.Properties; + +import org.apache.log4j.Level; +import org.apache.log4j.PropertyConfigurator; +import org.apache.log4j.spi.Configurator; +import org.apache.log4j.spi.LoggerRepository; + +// Contributors: Avy Sharell (sharell@online.fr) +// Matthieu Verbert (mve@zurich.ibm.com) +// Colin Sampaleanu + +/** + A convenience class to convert property values to specific types. + + @author Ceki Gülcü + @author Simon Kitching; + @author Anders Kristensen +*/ +public class OptionConverter { + + static String DELIM_START = "${"; + static char DELIM_STOP = '}'; + static int DELIM_START_LEN = 2; + static int DELIM_STOP_LEN = 1; + + /** OptionConverter is a static class. */ + private OptionConverter() {} + + public + static + String[] concatanateArrays(String[] l, String[] r) { + int len = l.length + r.length; + String[] a = new String[len]; + + System.arraycopy(l, 0, a, 0, l.length); + System.arraycopy(r, 0, a, l.length, r.length); + + return a; + } + + public + static + String convertSpecialChars(String s) { + char c; + int len = s.length(); + StringBuffer sbuf = new StringBuffer(len); + + int i = 0; + while(i < len) { + c = s.charAt(i++); + if (c == '\\') { + c = s.charAt(i++); + if(c == 'n') { + c = '\n'; + } else if(c == 'r') { + c = '\r'; + } else if(c == 't') { + c = '\t'; + } else if(c == 'f') { + c = '\f'; + } else if(c == '\b') { + c = '\b'; + } else if(c == '\"') { + c = '\"'; + } else if(c == '\'') { + c = '\''; + } else if(c == '\\') { + c = '\\'; + } + } + sbuf.append(c); + } + return sbuf.toString(); + } + + + /** + Very similar to System.getProperty except + that the {@link SecurityException} is hidden. + + @param key The key to search for. + @param def The default value to return. + @return the string value of the system property, or the default + value if there is no property with that key. + + @since 1.1 */ + public + static + String getSystemProperty(String key, String def) { + try { + return System.getProperty(key, def); + } catch(Throwable e) { // MS-Java throws com.ms.security.SecurityExceptionEx + LogLog.debug("Was not allowed to read system property \""+key+"\"."); + return def; + } + } + + + public + static + Object instantiateByKey(Properties props, String key, Class superClass, + Object defaultValue) { + + // Get the value of the property in string form + String className = findAndSubst(key, props); + if(className == null) { + LogLog.error("Could not find value for key " + key); + return defaultValue; + } + // Trim className to avoid trailing spaces that cause problems. + return OptionConverter.instantiateByClassName(className.trim(), superClass, + defaultValue); + } + + /** + If value is "true", then true is + returned. If value is "false", then + true is returned. Otherwise, default is + returned. + +

Case of value is unimportant. */ + public + static + boolean toBoolean(String value, boolean dEfault) { + if(value == null) { + return dEfault; + } + String trimmedVal = value.trim(); + if("true".equalsIgnoreCase(trimmedVal)) { + return true; + } + if("false".equalsIgnoreCase(trimmedVal)) { + return false; + } + return dEfault; + } + + public + static + int toInt(String value, int dEfault) { + if(value != null) { + String s = value.trim(); + try { + return Integer.valueOf(s).intValue(); + } + catch (NumberFormatException e) { + LogLog.error("[" + s + "] is not in proper int form."); + e.printStackTrace(); + } + } + return dEfault; + } + + /** + Converts a standard or custom priority level to a Level + object.

If value is of form + "level#classname", then the specified class' toLevel method + is called to process the specified level string; if no '#' + character is present, then the default {@link org.apache.log4j.Level} + class is used to process the level value. + +

As a special case, if the value parameter is + equal to the string "NULL", then the value null will + be returned. + +

If any error occurs while converting the value to a level, + the defaultValue parameter, which may be + null, is returned. + +

Case of value is insignificant for the level level, but is + significant for the class name part, if present. + + @since 1.1 */ + public + static + Level toLevel(String value, Level defaultValue) { + if(value == null) { + return defaultValue; + } + + value = value.trim(); + + int hashIndex = value.indexOf('#'); + if (hashIndex == -1) { + if("NULL".equalsIgnoreCase(value)) { + return null; + } else { + // no class name specified : use standard Level class + return Level.toLevel(value, defaultValue); + } + } + + Level result = defaultValue; + + String clazz = value.substring(hashIndex+1); + String levelName = value.substring(0, hashIndex); + + // This is degenerate case but you never know. + if("NULL".equalsIgnoreCase(levelName)) { + return null; + } + + LogLog.debug("toLevel" + ":class=[" + clazz + "]" + + ":pri=[" + levelName + "]"); + + try { + Class customLevel = Loader.loadClass(clazz); + + // get a ref to the specified class' static method + // toLevel(String, org.apache.log4j.Level) + Class[] paramTypes = new Class[] { String.class, + org.apache.log4j.Level.class + }; + java.lang.reflect.Method toLevelMethod = + customLevel.getMethod("toLevel", paramTypes); + + // now call the toLevel method, passing level string + default + Object[] params = new Object[] {levelName, defaultValue}; + Object o = toLevelMethod.invoke(null, params); + + result = (Level) o; + } catch(ClassNotFoundException e) { + LogLog.warn("custom level class [" + clazz + "] not found."); + } catch(NoSuchMethodException e) { + LogLog.warn("custom level class [" + clazz + "]" + + " does not have a class function toLevel(String, Level)", e); + } catch(java.lang.reflect.InvocationTargetException e) { + if (e.getTargetException() instanceof InterruptedException + || e.getTargetException() instanceof InterruptedIOException) { + Thread.currentThread().interrupt(); + } + LogLog.warn("custom level class [" + clazz + "]" + + " could not be instantiated", e); + } catch(ClassCastException e) { + LogLog.warn("class [" + clazz + + "] is not a subclass of org.apache.log4j.Level", e); + } catch(IllegalAccessException e) { + LogLog.warn("class ["+clazz+ + "] cannot be instantiated due to access restrictions", e); + } catch(RuntimeException e) { + LogLog.warn("class ["+clazz+"], level ["+levelName+ + "] conversion failed.", e); + } + return result; + } + + public + static + long toFileSize(String value, long dEfault) { + if(value == null) { + return dEfault; + } + + String s = value.trim().toUpperCase(); + long multiplier = 1; + int index; + + if((index = s.indexOf("KB")) != -1) { + multiplier = 1024; + s = s.substring(0, index); + } + else if((index = s.indexOf("MB")) != -1) { + multiplier = 1024*1024; + s = s.substring(0, index); + } + else if((index = s.indexOf("GB")) != -1) { + multiplier = 1024*1024*1024; + s = s.substring(0, index); + } + if(s != null) { + try { + return Long.valueOf(s).longValue() * multiplier; + } + catch (NumberFormatException e) { + LogLog.error("[" + s + "] is not in proper int form."); + LogLog.error("[" + value + "] not in expected format.", e); + } + } + return dEfault; + } + + /** + Find the value corresponding to key in + props. Then perform variable substitution on the + found value. + + */ + public + static + String findAndSubst(String key, Properties props) { + String value = props.getProperty(key); + if(value == null) { + return null; + } + + try { + return substVars(value, props); + } catch(IllegalArgumentException e) { + LogLog.error("Bad option value ["+value+"].", e); + return value; + } + } + + /** + Instantiate an object given a class name. Check that the + className is a subclass of + superClass. If that test fails or the object could + not be instantiated, then defaultValue is returned. + + @param className The fully qualified class name of the object to instantiate. + @param superClass The class to which the new object should belong. + @param defaultValue The object to return in case of non-fulfillment + */ + public + static + Object instantiateByClassName(String className, Class superClass, + Object defaultValue) { + if(className != null) { + try { + Class classObj = Loader.loadClass(className); + if(!superClass.isAssignableFrom(classObj)) { + LogLog.error("A \""+className+"\" object is not assignable to a \""+ + superClass.getName() + "\" variable."); + LogLog.error("The class \""+ superClass.getName()+"\" was loaded by "); + LogLog.error("["+superClass.getClassLoader()+"] whereas object of type "); + LogLog.error("\"" +classObj.getName()+"\" was loaded by [" + +classObj.getClassLoader()+"]."); + return defaultValue; + } + return classObj.newInstance(); + } catch (ClassNotFoundException e) { + LogLog.error("Could not instantiate class [" + className + "].", e); + } catch (IllegalAccessException e) { + LogLog.error("Could not instantiate class [" + className + "].", e); + } catch (InstantiationException e) { + LogLog.error("Could not instantiate class [" + className + "].", e); + } catch (RuntimeException e) { + LogLog.error("Could not instantiate class [" + className + "].", e); + } + } + return defaultValue; + } + + + /** + Perform variable substitution in string val from the + values of keys found in the system propeties. + +

The variable substitution delimeters are ${ and }. + +

For example, if the System properties contains "key=value", then + the call +

+     String s = OptionConverter.substituteVars("Value of key is ${key}.");
+     
+ + will set the variable s to "Value of key is value.". + +

If no value could be found for the specified key, then the + props parameter is searched, if the value could not + be found there, then substitution defaults to the empty string. + +

For example, if system propeties contains no value for the key + "inexistentKey", then the call + +

+     String s = OptionConverter.subsVars("Value of inexistentKey is [${inexistentKey}]");
+     
+ will set s to "Value of inexistentKey is []" + +

An {@link java.lang.IllegalArgumentException} is thrown if + val contains a start delimeter "${" which is not + balanced by a stop delimeter "}".

+ +

Author Avy Sharell

+ + @param val The string on which variable substitution is performed. + @throws IllegalArgumentException if val is malformed. + + */ + public static + String substVars(String val, Properties props) throws + IllegalArgumentException { + + StringBuffer sbuf = new StringBuffer(); + + int i = 0; + int j, k; + + while(true) { + j=val.indexOf(DELIM_START, i); + if(j == -1) { + // no more variables + if(i==0) { // this is a simple string + return val; + } else { // add the tail string which contails no variables and return the result. + sbuf.append(val.substring(i, val.length())); + return sbuf.toString(); + } + } else { + sbuf.append(val.substring(i, j)); + k = val.indexOf(DELIM_STOP, j); + if(k == -1) { + throw new IllegalArgumentException('"'+val+ + "\" has no closing brace. Opening brace at position " + j + + '.'); + } else { + j += DELIM_START_LEN; + String key = val.substring(j, k); + // first try in System properties + String replacement = getSystemProperty(key, null); + // then try props parameter + if(replacement == null && props != null) { + replacement = props.getProperty(key); + } + + if(replacement != null) { + // Do variable substitution on the replacement string + // such that we can solve "Hello ${x2}" as "Hello p1" + // the where the properties are + // x1=p1 + // x2=${x1} + String recursiveReplacement = substVars(replacement, props); + sbuf.append(recursiveReplacement); + } + i = k + DELIM_STOP_LEN; + } + } + } + } + + /** + * Configure log4j given an {@link InputStream}. + * + *

+ * The InputStream will be interpreted by a new instance of a log4j configurator. + *

+ *

+ * All configurations steps are taken on the hierarchy passed as a parameter. + *

+ * + * @param inputStream + * The configuration input stream. + * @param clazz + * The class name, of the log4j configurator which will parse the inputStream. This must be a + * subclass of {@link Configurator}, or null. If this value is null then a default configurator of + * {@link PropertyConfigurator} is used. + * @param hierarchy + * The {@link org.apache.log4j.Hierarchy} to act on. + * @since 1.2.17 + */ + +static +public +void selectAndConfigure(InputStream inputStream, String clazz, LoggerRepository hierarchy) { +Configurator configurator = null; + +if(clazz != null) { + LogLog.debug("Preferred configurator class: " + clazz); + configurator = (Configurator) instantiateByClassName(clazz, + Configurator.class, + null); + if(configurator == null) { + LogLog.error("Could not instantiate configurator ["+clazz+"]."); + return; + } +} else { + configurator = new PropertyConfigurator(); +} + +configurator.doConfigure(inputStream, hierarchy); +} + + + /** + Configure log4j given a URL. + +

The url must point to a file or resource which will be interpreted by + a new instance of a log4j configurator. + +

All configurations steps are taken on the + hierarchy passed as a parameter. + +

+ @param url The location of the configuration file or resource. + @param clazz The classname, of the log4j configurator which will parse + the file or resource at url. This must be a subclass of + {@link Configurator}, or null. If this value is null then a default + configurator of {@link PropertyConfigurator} is used, unless the + filename pointed to by url ends in '.xml', in which case + {@link org.apache.log4j.xml.DOMConfigurator} is used. + @param hierarchy The {@link org.apache.log4j.Hierarchy} to act on. + + @since 1.1.4 */ + + static + public + void selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy) { + Configurator configurator = null; + String filename = url.getFile(); + + if(clazz == null && filename != null && filename.endsWith(".xml")) { + clazz = "org.apache.log4j.xml.DOMConfigurator"; + } + + if(clazz != null) { + LogLog.debug("Preferred configurator class: " + clazz); + configurator = (Configurator) instantiateByClassName(clazz, + Configurator.class, + null); + if(configurator == null) { + LogLog.error("Could not instantiate configurator ["+clazz+"]."); + return; + } + } else { + configurator = new PropertyConfigurator(); + } + + configurator.doConfigure(url, hierarchy); + } +}