View Javadoc

1   package org.apache.velocity.runtime.log;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.    
20   */
21  
22  import java.util.List;
23  import java.util.ArrayList;
24  import java.util.Iterator;
25  
26  import org.apache.velocity.runtime.RuntimeServices;
27  import org.apache.velocity.runtime.RuntimeConstants;
28  import org.apache.velocity.util.ClassUtils;
29  
30  /**
31   * <p>
32   * This class is responsible for instantiating the correct LogChute
33   * </p>
34   *
35   * <p>
36   * The approach is :
37   * </p>
38   * <ul>
39   * <li>
40   *      First try to see if the user is passing in a living object
41   *      that is a LogChute, allowing the app to give its living
42   *      custom loggers.
43   *  </li>
44   *  <li>
45   *       Next, run through the (possible) list of classes specified
46   *       specified as loggers, taking the first one that appears to
47   *       work.  This is how we support finding logkit, log4j or
48   *       jdk logging, whichever is in the classpath and found first,
49   *       as all three are listed as defaults.
50   *  </li>
51   *  <li>
52   *      Finally, we turn to the System.err stream and print log messages
53   *      to it if nothing else works.
54   *  </li>
55   *
56   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
57   * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
58   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
59   * @author <a href="mailto:nbubna@apache.org">Nathan Bubna</a>
60   * @version $Id: LogManager.java 530526 2007-04-19 19:16:16Z nbubna $
61   */
62  public class LogManager
63  {
64      // Creates a new logging system or returns an existing one
65      // specified by the application.
66      private static LogChute createLogChute(RuntimeServices rsvc) throws Exception
67      {
68          Log log = rsvc.getLog();
69  
70          /* If a LogChute or LogSystem instance was set as a configuration
71           * value, use that.  This is any class the user specifies.
72           */
73          Object o = rsvc.getProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM);
74          if (o != null)
75          {
76              // first check for a LogChute
77              if (o instanceof LogChute)
78              {
79                  try
80                  {
81                      ((LogChute)o).init(rsvc);
82                      return (LogChute)o;
83                  }
84                  catch (Exception e)
85                  {
86                      log.error("Could not init runtime.log.logsystem " + o, e);
87                  }
88              }
89              // then check for a LogSystem
90              else if (o instanceof LogSystem)
91              {
92                  // inform the user about the deprecation
93                  log.info("LogSystem has been deprecated. Please use a LogChute implementation.");
94                  try
95                  {
96                      // wrap the LogSystem into a chute.
97                      LogChute chute = new LogChuteSystem((LogSystem)o);
98                      chute.init(rsvc);
99                      return chute;
100                 }
101                 catch (Exception e)
102                 {
103                     log.error("Could not init runtime.log.logsystem " + o, e);
104                 }
105             }
106             else
107             {
108                 log.warn(o.getClass().getName() + " object set as runtime.log.logsystem is not a valid log implementation.");
109             }
110         }
111 
112         /* otherwise, see if a class was specified.  You can put multiple
113          * classes, and we use the first one we find.
114          *
115          * Note that the default value of this property contains the
116          * AvalonLogChute, the Log4JLogChute, CommonsLogLogChute,
117          * ServletLogChute, and the JdkLogChute for
118          * convenience - so we use whichever we works first.
119          */
120         List classes = new ArrayList();
121         Object obj = rsvc.getProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS );
122 
123         /*
124          *  we might have a list, or not - so check
125          */
126         if ( obj instanceof List)
127         {
128             classes = (List) obj;
129         }
130         else if ( obj instanceof String)
131         {
132             classes.add( obj );
133         }
134 
135         /*
136          *  now run through the list, trying each.  It's ok to
137          *  fail with a class not found, as we do this to also
138          *  search out a default simple file logger
139          */
140         for( Iterator ii = classes.iterator(); ii.hasNext(); )
141         {
142             String claz = (String) ii.next();
143             if (claz != null && claz.length() > 0 )
144             {
145                 log.debug("Trying to use logger class " + claz );
146                 try
147                 {
148                     o = ClassUtils.getNewInstance( claz );
149                     if (o instanceof LogChute)
150                     {
151                         ((LogChute)o).init(rsvc);
152                         log.debug("Using logger class " + claz);
153                         return (LogChute)o;
154                     }
155                     else if (o instanceof LogSystem)
156                     {
157                         // inform the user about the deprecation
158                         log.info("LogSystem has been deprecated. Please use a LogChute implementation.");
159                         LogChute chute = new LogChuteSystem((LogSystem)o);
160                         chute.init(rsvc);
161                         return chute;
162                     }
163                     else
164                     {
165                         log.error("The specified logger class " + claz +
166                                   " does not implement the "+LogChute.class.getName()+" interface.");
167                         // be extra informative if it appears to be a classloader issue
168                         // this should match all our provided LogChutes
169                         if (isProbablyProvidedLogChute(claz))
170                         {
171                             // if it's likely to be ours, tip them off about classloader stuff
172                             log.error("This appears to be a ClassLoader issue.  Check for multiple Velocity jars in your classpath.");
173                         }
174                     }
175                 }
176                 catch(NoClassDefFoundError ncdfe)
177                 {
178                     // note these errors for anyone debugging the app
179                     if (isProbablyProvidedLogChute(claz))
180                     {
181                         log.debug("Target log system for " + claz +
182                                   " is not available (" + ncdfe.toString() +
183                                   ").  Falling back to next log system...");
184                     }
185                     else
186                     {
187                         log.debug("Couldn't find class " + claz +
188                                   " or necessary supporting classes in classpath.",
189                                   ncdfe);
190                     }
191                 }
192                 catch(Exception e)
193                 {
194                     // log init exception at slightly higher priority
195                     log.info("Failed to initialize an instance of " + claz +
196                              " with the current runtime configuration.", e);
197                 }
198             }
199         }
200 
201         /* If the above failed, that means either the user specified a
202          * logging class that we can't find, there weren't the necessary
203          * dependencies in the classpath for it, or there were the same
204          * problems for the default loggers, log4j and Java1.4+.
205          * Since we really don't know and we want to be sure the user knows
206          * that something went wrong with the logging, let's fall back to the
207          * surefire SystemLogChute. No panicking or failing to log!!
208          */
209         LogChute slc = new SystemLogChute();
210         slc.init(rsvc);
211         log.debug("Using SystemLogChute.");
212         return slc;
213     }
214 
215     /**
216      * Simply tells whether the specified classname probably is provided
217      * by Velocity or is implemented by someone else.  Not surefire, but
218      * it'll probably always be right.  In any case, this method shouldn't
219      * be relied upon for anything important.
220      */
221     private static boolean isProbablyProvidedLogChute(String claz)
222     {
223         if (claz == null)
224         {
225             return false;
226         }
227         else
228         {
229             return (claz.startsWith("org.apache.velocity.runtime.log")
230                     && claz.endsWith("LogChute"));
231         }
232     }
233 
234     /**
235      * Update the Log instance with the appropriate LogChute and other
236      * settings determined by the RuntimeServices.
237      * @param log
238      * @param rsvc
239      * @throws Exception
240      */
241     public static void updateLog(Log log, RuntimeServices rsvc) throws Exception
242     {
243         // create a new LogChute using the RuntimeServices
244         LogChute newLogChute = createLogChute(rsvc);
245         LogChute oldLogChute = log.getLogChute();
246 
247         // If the old LogChute was the pre-Init logger,
248         // dump its messages into the new system first.
249         if (oldLogChute instanceof HoldingLogChute)
250         {
251             HoldingLogChute hlc = (HoldingLogChute)oldLogChute;
252             hlc.transferTo(newLogChute);
253         }
254 
255         // pass the new LogChute to the log
256         log.setLogChute(newLogChute);
257     }
258 
259 }
260