Coverage Report - org.apache.commons.configuration.interpol.ConstantLookup
 
Classes in this File Line Coverage Branch Coverage Complexity
ConstantLookup
100%
31/31
100%
4/4
3
 
 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  
 package org.apache.commons.configuration.interpol;
 18  
 
 19  
 import java.lang.reflect.Field;
 20  
 import java.util.HashMap;
 21  
 import java.util.Map;
 22  
 
 23  
 import org.apache.commons.lang.ClassUtils;
 24  
 import org.apache.commons.lang.text.StrLookup;
 25  
 import org.apache.commons.logging.Log;
 26  
 import org.apache.commons.logging.LogFactory;
 27  
 
 28  
 /**
 29  
  * <p>
 30  
  * A specialized lookup implementation that allows access to constant fields of
 31  
  * classes.
 32  
  * </p>
 33  
  * <p>
 34  
  * Sometimes it is necessary in a configuration file to refer to a constant
 35  
  * defined in a class. This can be done with this lookup implementation.
 36  
  * Variable names passed in must be of the form
 37  
  * <code>mypackage.MyClass.FIELD</code>. The <code>lookup()</code> method
 38  
  * will split the passed in string at the last dot, separating the fully
 39  
  * qualified class name and the name of the constant (i.e. <strong>static final</strong>)
 40  
  * member field. Then the class is loaded and the field's value is obtained
 41  
  * using reflection.
 42  
  * </p>
 43  
  * <p>
 44  
  * Once retrieved values are cached for fast access. This class is thread-safe.
 45  
  * It can be used as a standard (i.e. global) lookup object and serve multiple
 46  
  * clients concurrently.
 47  
  * </p>
 48  
  *
 49  
  * @version $Id: ConstantLookup.java 588329 2007-10-25 20:01:31Z oheger $
 50  
  * @since 1.4
 51  
  * @author <a
 52  
  * href="http://commons.apache.org/configuration/team-list.html">Commons
 53  
  * Configuration team</a>
 54  
  */
 55  63
 public class ConstantLookup extends StrLookup
 56  
 {
 57  
     /** Constant for the field separator. */
 58  
     private static final char FIELD_SEPRATOR = '.';
 59  
 
 60  
     /** An internally used cache for already retrieved values. */
 61  55
     private static Map constantCache = new HashMap();
 62  
 
 63  
     /** The logger. */
 64  63
     private Log log = LogFactory.getLog(getClass());
 65  
 
 66  
     /**
 67  
      * Tries to resolve the specified variable. The passed in variable name is
 68  
      * interpreted as the name of a <b>static final</b> member field of a
 69  
      * class. If the value has already been obtained, it can be retrieved from
 70  
      * an internal cache. Otherwise this method will invoke the
 71  
      * <code>resolveField()</code> method and pass in the name of the class
 72  
      * and the field.
 73  
      *
 74  
      * @param var the name of the variable to be resolved
 75  
      * @return the value of this variable or <b>null</b> if it cannot be
 76  
      * resolved
 77  
      */
 78  
     public String lookup(String var)
 79  
     {
 80  17
         if (var == null)
 81  
         {
 82  1
             return null;
 83  
         }
 84  
 
 85  
         String result;
 86  16
         synchronized (constantCache)
 87  
         {
 88  16
             result = (String) constantCache.get(var);
 89  16
         }
 90  16
         if (result != null)
 91  
         {
 92  6
             return result;
 93  
         }
 94  
 
 95  10
         int fieldPos = var.lastIndexOf(FIELD_SEPRATOR);
 96  10
         if (fieldPos < 0)
 97  
         {
 98  1
             return null;
 99  
         }
 100  
         try
 101  
         {
 102  9
             Object value = resolveField(var.substring(0, fieldPos), var
 103  
                     .substring(fieldPos + 1));
 104  6
             if (value != null)
 105  
             {
 106  6
                 synchronized (constantCache)
 107  
                 {
 108  
                     // In worst case, the value will be fetched multiple times
 109  
                     // because of this lax synchronisation, but for constant
 110  
                     // values this shouldn't be a problem.
 111  6
                     constantCache.put(var, String.valueOf(value));
 112  6
                 }
 113  6
                 result = value.toString();
 114  
             }
 115  
         }
 116  3
         catch (Exception ex)
 117  
         {
 118  3
             log.warn("Could not obtain value for variable " + var, ex);
 119  6
         }
 120  
 
 121  9
         return result;
 122  
     }
 123  
 
 124  
     /**
 125  
      * Clears the shared cache with the so far resolved constants.
 126  
      */
 127  
     public static void clear()
 128  
     {
 129  8
         synchronized (constantCache)
 130  
         {
 131  8
             constantCache.clear();
 132  8
         }
 133  8
     }
 134  
 
 135  
     /**
 136  
      * Determines the value of the specified constant member field of a class.
 137  
      * This implementation will call <code>fetchClass()</code> to obtain the
 138  
      * <code>java.lang.Class</code> object for the target class. Then it will
 139  
      * use reflection to obtain the field's value. For this to work the field
 140  
      * must be accessable.
 141  
      *
 142  
      * @param className the name of the class
 143  
      * @param fieldName the name of the member field of that class to read
 144  
      * @return the field's value
 145  
      * @throws Exception if an error occurs
 146  
      */
 147  
     protected Object resolveField(String className, String fieldName)
 148  
             throws Exception
 149  
     {
 150  9
         Class clazz = fetchClass(className);
 151  8
         Field field = clazz.getField(fieldName);
 152  6
         return field.get(null);
 153  
     }
 154  
 
 155  
     /**
 156  
      * Loads the class with the specified name. If an application has special
 157  
      * needs regarding the class loaders to be used, it can hook in here. This
 158  
      * implementation delegates to the <code>getClass()</code> method of
 159  
      * Commons Lang's
 160  
      * <code><a href="http://commons.apache.org/lang/api-release/org/apache/commons/lang/ClassUtils.html">
 161  
      * ClassUtils</a></code>.
 162  
      *
 163  
      * @param className the name of the class to be loaded
 164  
      * @return the corresponding class object
 165  
      * @throws ClassNotFoundException if the class cannot be loaded
 166  
      */
 167  
     protected Class fetchClass(String className) throws ClassNotFoundException
 168  
     {
 169  9
         return ClassUtils.getClass(className);
 170  
     }
 171  
 }