You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by Dan Martens <dl...@hotmail.com> on 2000/07/27 23:23:58 UTC
Bug found when calling init methods of defined web apps
Hello all.
This is my first message to this group so please let me know if you have
heard of this behaviour before. There is a bug in
org.apache.tomcat.core.ContextManager which allows for the loading of every
defined servlet in the web.xml file four times at startup. Not only is each
servlets init() method called four times, but four different objects are
created. Since the code base is fairly thick and requires a lot of debugging
(speaking from experience) this code segment in the init() method of
ContextManager seems to be producing the error indirectly.
<-- begin code
while(enum.hasMoreElements()) {
context = getContext((String)enum.nextElement());
try {
initContext( context );
end code--->
Each object of this enumeration is a different Context, the problem is
during the creation of each context, the conf/web.xml file is scanned and
it's information stored in each seperate object. Then upon the
initialization of each context, the servlets which it references are
initialized. This includes such servlets as the DefaultErrorPage, invoker
and the jsp servlet. The reason for this behaviour occuring exactly four
times seems to be because in a clean drop of the 3.1 release, there are four
subdirectories in the WebApps directory, each of which is loaded as a
seperate context.
I have created a simple fix to this situation which prevents the servlets
from being loaded repeatedly, but since this other things may be loaded
repeatedly as well, it is worth further investigation into the actual root
of the problem. The fix is in
org.apache.tomcat.context.LoadOnStartupInterceptor.contextInit(Context)
method. Currently as it stands the method looks like this
<------begin code
public void contextInit(Context ctx) {
Hashtable loadableServlets = new Hashtable();
init(ctx,loadableServlets);
Vector orderedKeys = new Vector();
Enumeration e= loadableServlets.keys();
// order keys
while (e.hasMoreElements()) {
Integer key = (Integer)e.nextElement();
int slot = -1;
for (int i = 0; i < orderedKeys.size(); i++) {
if (key.intValue() <
((Integer)(orderedKeys.elementAt(i))).intValue()) {
slot = i;
break;
}
}
if (slot > -1) {
orderedKeys.insertElementAt(key, slot);
} else {
orderedKeys.addElement(key);
}
}
// loaded ordered servlets
// Priorities IMO, should start with 0.
// Only System Servlets should be at 0 and rest of the
// servlets should be +ve integers.
// WARNING: Please do not change this without talking to:
// harishp@eng.sun.com (J2EE impact)
for (int i = 0; i < orderedKeys.size(); i ++) {
Integer key = (Integer)orderedKeys.elementAt(i);
Enumeration sOnLevel = ((Vector)loadableServlets.get( key
)).elements();
while (sOnLevel.hasMoreElements()) {
String servletName = (String)sOnLevel.nextElement();
ServletWrapper result = ctx.getServletByName(servletName);
if( ctx.getDebug() > 0 ) ctx.log("Loading " + key + " " + servletName );
if(result==null)
System.out.println("Warning: we try to load an undefined servlet " +
servletName);
else {
try {
if( result.getPath() != null )
loadJsp( ctx, result );
else
result.loadServlet();
} catch (Exception ee) {
String msg = sm.getString("context.loadServlet.e",
servletName);
System.out.println(msg);
}
}
}
}
}
----end code>
If you make the Hashtable loadableServlets a class variable and add a simple
if statement encompassing the entire method, it will skip the repeat loading
of servlets. Therefore the method fix is:
<-----begin code
public void contextInit(Context ctx) {
if(loadableServlets == null){
loadableServlets = new Hashtable();
init(ctx,loadableServlets);
Vector orderedKeys = new Vector();
Enumeration e= loadableServlets.keys();
// order keys
while (e.hasMoreElements()) {
Integer key = (Integer)e.nextElement();
int slot = -1;
for (int i = 0; i < orderedKeys.size(); i++) {
if (key.intValue() <
((Integer)(orderedKeys.elementAt(i))).intValue()) {
slot = i;
break;
}
}
if (slot > -1) {
orderedKeys.insertElementAt(key, slot);
} else {
orderedKeys.addElement(key);
}
}
// loaded ordered servlets
// Priorities IMO, should start with 0.
// Only System Servlets should be at 0 and rest of the
// servlets should be +ve integers.
// WARNING: Please do not change this without talking to:
// harishp@eng.sun.com (J2EE impact)
for (int i = 0; i < orderedKeys.size(); i ++) {
Integer key = (Integer)orderedKeys.elementAt(i);
Enumeration sOnLevel = ((Vector)loadableServlets.get( key
)).elements();
while (sOnLevel.hasMoreElements()) {
String servletName = (String)sOnLevel.nextElement();
ServletWrapper result = ctx.getServletByName(servletName);
if( ctx.getDebug() > 0 ) ctx.log("Loading " + key + " " + servletName );
if(result==null)
System.out.println("Warning: we try to load an undefined servlet " +
servletName);
else {
try {
if( result.getPath() != null )
loadJsp( ctx, result );
else
result.loadServlet();
} catch (Exception ee) {
String msg = sm.getString("context.loadServlet.e",
servletName);
System.out.println(msg);
}
}
}
}
}
}
-----end code>
This code fix ensures that if the Hashtable was not set up by a previous
call to this method, then it will commence loading servlets. Otherwise, if
loadableServlets is non-null, then this method has been called before so
skip the initialization process.
I hope I have helped here, please let me know. You can reach me either at
this address or dmartens@ca.ibm.com . Thankyou for your time.
________________________________________________________________________
Get Your Private, Free E-mail from MSN Hotmail at http://www.hotmail.com
Re: Bug found when calling init methods of defined web apps
Posted by "Craig R. McClanahan" <Cr...@eng.sun.com>.
Dan Martens wrote:
> Hello all.
> This is my first message to this group so please let me know if you have
> heard of this behaviour before. There is a bug in
> org.apache.tomcat.core.ContextManager which allows for the loading of every
> defined servlet in the web.xml file four times at startup.
If you are talking about the "conf/web.xml" file, and you have four web
apps in your
"webapps" directory, what you are seeing is actually the correct
behavior. To understand
why, consider the following points:
* The "conf/web.xml" file in Tomcat 3.1 contains defaults that are
common to all web applications. When a context is started up,
this file is read and processed before the "WEB-INF/web.xml" file
for your own application is processed. You can pretend that there
is an invisible "include" for this file at the top of your
application's
web.xml file, if that makes things clearer.
* By the rules of the servlet specification, every single <servlet>
definition that is processed from a "web.xml" file must cause the
creation of a separate servlet instance (of the appropriate class).
This would be true even if you had two <servlet> instances that
named the same Java class file. The reason you want this is that
you may well have the same servlet class, under two different
mappings, with two different sets of initialization parameters.
* Because the "conf/web.xml" file contains commonly used servlets
(like the JSP page compiler servlet), an instance of that servlet
gets created for each web application.
* This is a "good thing", because each web application has its own
custom class path (to access the WEB-INF/classes and WEB-INF/lib
directories of each application). If Tomcat were changed in the way
that you are describing, the JSP page compiler for all four web apps
would reference only the classes from the web app that was initialized
first.
Craig McClanahan