You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@velocity.apache.org by bu...@apache.org on 2004/10/14 21:32:16 UTC

DO NOT REPLY [Bug 31721] New: - LogManager.createLogSystem does not use contextClassLoader

DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG 
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://issues.apache.org/bugzilla/show_bug.cgi?id=31721>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND 
INSERTED IN THE BUG DATABASE.

http://issues.apache.org/bugzilla/show_bug.cgi?id=31721

LogManager.createLogSystem does not use contextClassLoader

           Summary: LogManager.createLogSystem does not use
                    contextClassLoader
           Product: Velocity
           Version: 1.4
          Platform: All
        OS/Version: Linux
            Status: NEW
          Severity: Normal
          Priority: Other
         Component: Source
        AssignedTo: velocity-dev@jakarta.apache.org
        ReportedBy: srevilak@f7.net


We use velocity-1.4 as part of a web application; it processes
templates that are served to clients as html files.  The servlet
container used is tomcat 5.0.18.  Things are laid out like this:

  * CATALINA_HOME/shared/lib/velocity.jar
    (along with other third-party libraries)

Our class files:

  * CATALINA_HOME/webapps/<context>/WEB-INF/classes
  * CATALINA_HOME/webapps/<context>/WEB-INF/lib

Recently, we attempted to add our own logging class
(implements org.apache.velocity.runtime.log.LogSystem).  In doing so,
I believe I have discovered a bug in velocity's LogManager class.

Our logger is com.r9.nucleus.velocity.Logger

  runtime.log.logsystem.class=com.r9.nucleus.velocity.Logger

com.r9.nucleus.velocity.Logger lives in a jar in WEB-INF/lib.

A servlet (in the same jar file) can locate, instantiate, and use this
class directly.  However, when velocity attempts to use it, we get
this:

   java.lang.ClassNotFoundException: com.r9.nucleus.velocity.Logger
        at org.apache.catalina.loader.StandardClassLoader.loadClass(StandardClassLoader.java:891)
        at org.apache.catalina.loader.StandardClassLoader.loadClass(StandardClassLoader.java:756)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:302)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:141)
        at org.apache.velocity.runtime.log.LogManager.createLogSystem(LogManager.java:123)
        at org.apache.velocity.runtime.RuntimeInstance.initializeLogger(RuntimeInstance.java:553)
        at org.apache.velocity.runtime.RuntimeInstance.init(RuntimeInstance.java:226)
        at org.apache.velocity.runtime.RuntimeInstance.init(RuntimeInstance.java:461)
        at org.apache.velocity.app.VelocityEngine.init(VelocityEngine.java:106)
        at com.r9.nucleus.velocity.VelocityUtils.createVelocityEngine(VelocityUtils.java:83)
        at com.r9.seeker.template.FormTemplate.getEngine(FormTemplate.java:519)
        at com.r9.seeker.template.FormTemplate.parse(FormTemplate.java:99)
        at com.r9.seeker.scrape.AirScraper.populateAndParseTemplate(AirScraper.java:200)
        at com.r9.seeker.scrape.AirScraper.retrieveResultsPage(AirScraper.java:174)
        at com.r9.seeker.scrape.AirScraper.specificSearch(AirScraper.java:104)
        at com.r9.seeker.core.MultiSearcher.search(MultiSearcher.java:167)
        at com.r9.seeker.core.SearchThreadPool$RunnableSearch.run(SearchThreadPool.java:82)
        at EDU.oswego.cs.dl.util.concurrent.PooledExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:534)


Here is the relevant section of LogManager.createLogSystem (w/line
numbers).


   107	        /*
   108	         *  now run through the list, trying each.  It's ok to 
   109	         *  fail with a class not found, as we do this to also
   110	         *  search out a default simple file logger
   111	         */
   112	
   113	        for( Iterator ii = classes.iterator(); ii.hasNext(); )
   114	        {
   115	            String claz = (String) ii.next();
   116	
   117	            if (claz != null && claz.length() > 0 )
   118	            {
   119	                rsvc.info("Trying to use logger class " + claz );
   120	          
   121	                try
   122	                {
   123	>>> HERE >>>        o = Class.forName( claz ).newInstance();
   124	
   125	                    if ( o instanceof LogSystem )
   126	                    {
   127	                        ((LogSystem) o).init( rsvc );
   128	
   129	                        rsvc.info("Using logger class " + claz );
   130	
   131	                        return (LogSystem) o;
   132	                    }
   133	                    else
   134	                    {
   135	                        rsvc.error("The specifid logger class " + claz + 
   136	                                   " isn't a valid LogSystem");
   137	                    }
   138	                }
   139	                catch( NoClassDefFoundError ncdfe )
   140	                {
   141	                    rsvc.debug("Couldn't find class " + claz 
   142	                               + " or necessary supporting classes in "
   143	                               + "classpath. Exception : " + ncdfe);
   144	                }
   145	            }
   146	        }


This is what appears to be happening:

 - velocity.jar is loaded by tomcat's shared loader.

 - a servlet can instantiate and use our Logger class directly; they
   both fall under the same tomcat WebAppClassLoader.

 - LogManager fails because it's using Class.forName() - attempting to
   use the Shared classloader that loaded velocity.jar.  This
   classloader cannot has no visibility into the webapp classloader
   repository.


Would it be possible to consider changing this:

   123	>>> HERE >>>        o = Class.forName( claz ).newInstance();


to something like:

   ClassLoader loader = Thread.currentThread().getContextClassLoader();
   if (loader == null) {
      loader = getClass().getClassLoader();
   }

   o = Class.forName(claz, true, loader).newInstance();


This should allow LogManager to have the same class visibility as the
executing servlet thread.

---------------------------------------------------------------------
To unsubscribe, e-mail: velocity-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: velocity-dev-help@jakarta.apache.org