Home » apache-log4j-1.2.15 » org.apache » log4j » helpers » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   package org.apache.log4j.helpers;
   19   
   20   import java.util.Properties;
   21   import java.net.URL;
   22   import org.apache.log4j.Level;
   23   import org.apache.log4j.spi.Configurator;
   24   import org.apache.log4j.spi.LoggerRepository;
   25   import org.apache.log4j.PropertyConfigurator;
   26   
   27   // Contributors:   Avy Sharell (sharell@online.fr)
   28   //                 Matthieu Verbert (mve@zurich.ibm.com)
   29   //                 Colin Sampaleanu
   30   
   31   /**
   32      A convenience class to convert property values to specific types.
   33   
   34      @author Ceki Gülcü
   35      @author Simon Kitching;
   36      @author Anders Kristensen
   37   */
   38   public class OptionConverter {
   39   
   40     static String DELIM_START = "${";
   41     static char   DELIM_STOP  = '}';
   42     static int DELIM_START_LEN = 2;
   43     static int DELIM_STOP_LEN  = 1;
   44   
   45     /** OptionConverter is a static class. */
   46     private OptionConverter() {}
   47   
   48     public
   49     static
   50     String[] concatanateArrays(String[] l, String[] r) {
   51       int len = l.length + r.length;
   52       String[] a = new String[len];
   53   
   54       System.arraycopy(l, 0, a, 0, l.length);
   55       System.arraycopy(r, 0, a, l.length, r.length);
   56   
   57       return a;
   58     }
   59   
   60     public
   61     static
   62     String convertSpecialChars(String s) {
   63       char c;
   64       int len = s.length();
   65       StringBuffer sbuf = new StringBuffer(len);
   66   
   67       int i = 0;
   68       while(i < len) {
   69         c = s.charAt(i++);
   70         if (c == '\\') {
   71   	c =  s.charAt(i++);
   72   	if(c == 'n')      c = '\n';
   73   	else if(c == 'r') c = '\r';
   74   	else if(c == 't') c = '\t';
   75   	else if(c == 'f') c = '\f';
   76   	else if(c == '\b') c = '\b';
   77   	else if(c == '\"') c = '\"';
   78   	else if(c == '\'') c = '\'';
   79   	else if(c == '\\') c = '\\';
   80         }
   81         sbuf.append(c);
   82       }
   83       return sbuf.toString();
   84     }
   85   
   86   
   87     /**
   88        Very similar to <code>System.getProperty</code> except
   89        that the {@link SecurityException} is hidden.
   90   
   91        @param key The key to search for.
   92        @param def The default value to return.
   93        @return the string value of the system property, or the default
   94        value if there is no property with that key.
   95   
   96        @since 1.1 */
   97     public
   98     static
   99     String getSystemProperty(String key, String def) {
  100       try {
  101         return System.getProperty(key, def);
  102       } catch(Throwable e) { // MS-Java throws com.ms.security.SecurityExceptionEx
  103         LogLog.debug("Was not allowed to read system property \""+key+"\".");
  104         return def;
  105       }
  106     }
  107   
  108   
  109     public
  110     static
  111     Object instantiateByKey(Properties props, String key, Class superClass,
  112   				Object defaultValue) {
  113   
  114       // Get the value of the property in string form
  115       String className = findAndSubst(key, props);
  116       if(className == null) {
  117         LogLog.error("Could not find value for key " + key);
  118         return defaultValue;
  119       }
  120       // Trim className to avoid trailing spaces that cause problems.
  121       return OptionConverter.instantiateByClassName(className.trim(), superClass,
  122   						  defaultValue);
  123     }
  124   
  125     /**
  126        If <code>value</code> is "true", then <code>true</code> is
  127        returned. If <code>value</code> is "false", then
  128        <code>true</code> is returned. Otherwise, <code>default</code> is
  129        returned.
  130   
  131        <p>Case of value is unimportant.  */
  132     public
  133     static
  134     boolean toBoolean(String value, boolean dEfault) {
  135       if(value == null)
  136         return dEfault;
  137       String trimmedVal = value.trim();
  138       if("true".equalsIgnoreCase(trimmedVal))
  139         return true;
  140       if("false".equalsIgnoreCase(trimmedVal))
  141         return false;
  142       return dEfault;
  143     }
  144   
  145     public
  146     static
  147     int toInt(String value, int dEfault) {
  148       if(value != null) {
  149         String s = value.trim();
  150         try {
  151   	return Integer.valueOf(s).intValue();
  152         }
  153         catch (NumberFormatException e) {
  154   	 LogLog.error("[" + s + "] is not in proper int form.");
  155   	e.printStackTrace();
  156         }
  157       }
  158       return dEfault;
  159     }
  160   
  161     /**
  162        Converts a standard or custom priority level to a Level
  163        object.  <p> If <code>value</code> is of form
  164        "level#classname", then the specified class' toLevel method
  165        is called to process the specified level string; if no '#'
  166        character is present, then the default {@link org.apache.log4j.Level}
  167        class is used to process the level value.
  168   
  169        <p>As a special case, if the <code>value</code> parameter is
  170        equal to the string "NULL", then the value <code>null</code> will
  171        be returned.
  172   
  173        <p> If any error occurs while converting the value to a level,
  174        the <code>defaultValue</code> parameter, which may be
  175        <code>null</code>, is returned.
  176   
  177        <p> Case of <code>value</code> is insignificant for the level level, but is
  178        significant for the class name part, if present.
  179   
  180        @since 1.1 */
  181     public
  182     static
  183     Level toLevel(String value, Level defaultValue) {
  184       if(value == null)
  185         return defaultValue;
  186         
  187       value = value.trim();
  188   
  189       int hashIndex = value.indexOf('#');
  190       if (hashIndex == -1) {
  191         if("NULL".equalsIgnoreCase(value)) {
  192   	return null;
  193         } else {
  194   	// no class name specified : use standard Level class
  195   	return(Level) Level.toLevel(value, defaultValue);
  196         }
  197       }
  198   
  199       Level result = defaultValue;
  200   
  201       String clazz = value.substring(hashIndex+1);
  202       String levelName = value.substring(0, hashIndex);
  203   
  204       // This is degenerate case but you never know.
  205       if("NULL".equalsIgnoreCase(levelName)) {
  206   	return null;
  207       }
  208   
  209       LogLog.debug("toLevel" + ":class=[" + clazz + "]"
  210   		 + ":pri=[" + levelName + "]");
  211   
  212       try {
  213         Class customLevel = Loader.loadClass(clazz);
  214   
  215         // get a ref to the specified class' static method
  216         // toLevel(String, org.apache.log4j.Level)
  217         Class[] paramTypes = new Class[] { String.class,
  218   					 org.apache.log4j.Level.class
  219                                          };
  220         java.lang.reflect.Method toLevelMethod =
  221                         customLevel.getMethod("toLevel", paramTypes);
  222   
  223         // now call the toLevel method, passing level string + default
  224         Object[] params = new Object[] {levelName, defaultValue};
  225         Object o = toLevelMethod.invoke(null, params);
  226   
  227         result = (Level) o;
  228       } catch(ClassNotFoundException e) {
  229         LogLog.warn("custom level class [" + clazz + "] not found.");
  230       } catch(NoSuchMethodException e) {
  231         LogLog.warn("custom level class [" + clazz + "]"
  232           + " does not have a class function toLevel(String, Level)", e);
  233       } catch(java.lang.reflect.InvocationTargetException e) {
  234         LogLog.warn("custom level class [" + clazz + "]"
  235   		   + " could not be instantiated", e);
  236       } catch(ClassCastException e) {
  237         LogLog.warn("class [" + clazz
  238           + "] is not a subclass of org.apache.log4j.Level", e);
  239       } catch(IllegalAccessException e) {
  240         LogLog.warn("class ["+clazz+
  241   		   "] cannot be instantiated due to access restrictions", e);
  242       } catch(Exception e) {
  243         LogLog.warn("class ["+clazz+"], level ["+levelName+
  244   		   "] conversion failed.", e);
  245       }
  246       return result;
  247      }
  248   
  249     public
  250     static
  251     long toFileSize(String value, long dEfault) {
  252       if(value == null)
  253         return dEfault;
  254   
  255       String s = value.trim().toUpperCase();
  256       long multiplier = 1;
  257       int index;
  258   
  259       if((index = s.indexOf("KB")) != -1) {
  260         multiplier = 1024;
  261         s = s.substring(0, index);
  262       }
  263       else if((index = s.indexOf("MB")) != -1) {
  264         multiplier = 1024*1024;
  265         s = s.substring(0, index);
  266       }
  267       else if((index = s.indexOf("GB")) != -1) {
  268         multiplier = 1024*1024*1024;
  269         s = s.substring(0, index);
  270       }
  271       if(s != null) {
  272         try {
  273   	return Long.valueOf(s).longValue() * multiplier;
  274         }
  275         catch (NumberFormatException e) {
  276   	LogLog.error("[" + s + "] is not in proper int form.");
  277   	LogLog.error("[" + value + "] not in expected format.", e);
  278         }
  279       }
  280       return dEfault;
  281     }
  282   
  283     /**
  284        Find the value corresponding to <code>key</code> in
  285        <code>props</code>. Then perform variable substitution on the
  286        found value.
  287   
  288    */
  289     public
  290     static
  291     String findAndSubst(String key, Properties props) {
  292       String value = props.getProperty(key);
  293       if(value == null)
  294         return null;
  295   
  296       try {
  297         return substVars(value, props);
  298       } catch(IllegalArgumentException e) {
  299         LogLog.error("Bad option value ["+value+"].", e);
  300         return value;
  301       }
  302     }
  303   
  304     /**
  305        Instantiate an object given a class name. Check that the
  306        <code>className</code> is a subclass of
  307        <code>superClass</code>. If that test fails or the object could
  308        not be instantiated, then <code>defaultValue</code> is returned.
  309   
  310        @param className The fully qualified class name of the object to instantiate.
  311        @param superClass The class to which the new object should belong.
  312        @param defaultValue The object to return in case of non-fulfillment
  313      */
  314     public
  315     static
  316     Object instantiateByClassName(String className, Class superClass,
  317   				Object defaultValue) {
  318       if(className != null) {
  319         try {
  320   	Class classObj = Loader.loadClass(className);
  321   	if(!superClass.isAssignableFrom(classObj)) {
  322   	  LogLog.error("A \""+className+"\" object is not assignable to a \""+
  323   		       superClass.getName() + "\" variable.");
  324   	  LogLog.error("The class \""+ superClass.getName()+"\" was loaded by ");
  325   	  LogLog.error("["+superClass.getClassLoader()+"] whereas object of type ");
  326   	  LogLog.error("\"" +classObj.getName()+"\" was loaded by ["
  327   		       +classObj.getClassLoader()+"].");
  328   	  return defaultValue;
  329   	}
  330   	return classObj.newInstance();
  331         } catch (Exception e) {
  332   	LogLog.error("Could not instantiate class [" + className + "].", e);
  333         }
  334       }
  335       return defaultValue;
  336     }
  337   
  338   
  339     /**
  340        Perform variable substitution in string <code>val</code> from the
  341        values of keys found in the system propeties.
  342   
  343        <p>The variable substitution delimeters are <b>${</b> and <b>}</b>.
  344   
  345        <p>For example, if the System properties contains "key=value", then
  346        the call
  347        <pre>
  348        String s = OptionConverter.substituteVars("Value of key is ${key}.");
  349        </pre>
  350   
  351        will set the variable <code>s</code> to "Value of key is value.".
  352   
  353        <p>If no value could be found for the specified key, then the
  354        <code>props</code> parameter is searched, if the value could not
  355        be found there, then substitution defaults to the empty string.
  356   
  357        <p>For example, if system propeties contains no value for the key
  358        "inexistentKey", then the call
  359   
  360        <pre>
  361        String s = OptionConverter.subsVars("Value of inexistentKey is [${inexistentKey}]");
  362        </pre>
  363        will set <code>s</code> to "Value of inexistentKey is []"
  364   
  365        <p>An {@link java.lang.IllegalArgumentException} is thrown if
  366        <code>val</code> contains a start delimeter "${" which is not
  367        balanced by a stop delimeter "}". </p>
  368   
  369        <p><b>Author</b> Avy Sharell</a></p>
  370   
  371        @param val The string on which variable substitution is performed.
  372        @throws IllegalArgumentException if <code>val</code> is malformed.
  373   
  374     */
  375     public static
  376     String substVars(String val, Properties props) throws
  377                           IllegalArgumentException {
  378   
  379       StringBuffer sbuf = new StringBuffer();
  380   
  381       int i = 0;
  382       int j, k;
  383   
  384       while(true) {
  385         j=val.indexOf(DELIM_START, i);
  386         if(j == -1) {
  387   	// no more variables
  388   	if(i==0) { // this is a simple string
  389   	  return val;
  390   	} else { // add the tail string which contails no variables and return the result.
  391   	  sbuf.append(val.substring(i, val.length()));
  392   	  return sbuf.toString();
  393   	}
  394         } else {
  395   	sbuf.append(val.substring(i, j));
  396   	k = val.indexOf(DELIM_STOP, j);
  397   	if(k == -1) {
  398   	  throw new IllegalArgumentException('"'+val+
  399   		      "\" has no closing brace. Opening brace at position " + j
  400   					     + '.');
  401   	} else {
  402   	  j += DELIM_START_LEN;
  403   	  String key = val.substring(j, k);
  404   	  // first try in System properties
  405   	  String replacement = getSystemProperty(key, null);
  406   	  // then try props parameter
  407   	  if(replacement == null && props != null) {
  408   	    replacement =  props.getProperty(key);
  409   	  }
  410   
  411   	  if(replacement != null) {
  412   	    // Do variable substitution on the replacement string
  413   	    // such that we can solve "Hello ${x2}" as "Hello p1" 
  414               // the where the properties are
  415   	    // x1=p1
  416               // x2=${x1}
  417   	    String recursiveReplacement = substVars(replacement, props);
  418   	    sbuf.append(recursiveReplacement);
  419   	  }
  420   	  i = k + DELIM_STOP_LEN;
  421   	}
  422         }
  423       }
  424     }
  425   
  426   
  427     /**
  428        Configure log4j given a URL.
  429   
  430        <p>The url must point to a file or resource which will be interpreted by
  431        a new instance of a log4j configurator.
  432   
  433        <p>All configurations steps are taken on the
  434        <code>hierarchy</code> passed as a parameter.
  435   
  436        <p>
  437        @param url The location of the configuration file or resource.
  438        @param clazz The classname, of the log4j configurator which will parse
  439        the file or resource at <code>url</code>. This must be a subclass of
  440        {@link Configurator}, or null. If this value is null then a default
  441        configurator of {@link PropertyConfigurator} is used, unless the
  442        filename pointed to by <code>url</code> ends in '.xml', in which case
  443        {@link org.apache.log4j.xml.DOMConfigurator} is used.
  444        @param hierarchy The {@link org.apache.log4j.Hierarchy} to act on.
  445   
  446        @since 1.1.4 */
  447   
  448     static
  449     public
  450     void selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy) {
  451      Configurator configurator = null;
  452      String filename = url.getFile();
  453   
  454      if(clazz == null && filename != null && filename.endsWith(".xml")) {
  455        clazz = "org.apache.log4j.xml.DOMConfigurator";
  456      }
  457   
  458      if(clazz != null) {
  459        LogLog.debug("Preferred configurator class: " + clazz);
  460        configurator = (Configurator) instantiateByClassName(clazz,
  461   							  Configurator.class,
  462   							  null);
  463        if(configurator == null) {
  464      	  LogLog.error("Could not instantiate configurator ["+clazz+"].");
  465      	  return;
  466        }
  467      } else {
  468        configurator = new PropertyConfigurator();
  469      }
  470   
  471      configurator.doConfigure(url, hierarchy);
  472     }
  473   }

Save This Page
Home » apache-log4j-1.2.15 » org.apache » log4j » helpers » [javadoc | source]