This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 36993 - web/jspparser uses ant.jar in an illegal fashion
Summary: web/jspparser uses ant.jar in an illegal fashion
Status: VERIFIED FIXED
Alias: None
Product: javaee
Classification: Unclassified
Component: Code (show other bugs)
Version: 3.x
Hardware: All All
: P2 blocker (vote)
Assignee: Petr Jiricka
URL:
Keywords: ARCH
: 39658 (view as bug list)
Depends on:
Blocks:
 
Reported: 2003-11-03 19:30 UTC by Chris Webster
Modified: 2007-07-31 13:48 UTC (History)
2 users (show)

See Also:
Issue Type: DEFECT
Exception Reporter:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Chris Webster 2003-11-03 19:30:28 UTC
Startup warnings are being generated from
jsp-parser.jar
Comment 1 Petr Jiricka 2003-11-04 07:54:58 UTC
The text of the warning is the following:

[org.netbeans.core.modules #4] WARNING: Class-Path value
../../ant/lib/ant.jar from
E:\software\ide\nb_prj_20031029\modules\eager\jsp-parser.jar is
illegal according to the Java Extension Mechanism: must be relative
and not move up directories

This warning was introduced by the integration of the new Tomcat JSP
parser library, which has a runtime dependency on Ant. Additionally,
Ant binaries were moved to a separate directory $IDE_HOME/ant, which
also contributed to this warning.

I must say I have no idea how this warning could be fixed, without
introducing other architecture problems, such as duplication of jar
files. I suggest that the displaying of this warning is simply
suppressed towards the end of the release cycle.
Comment 2 Petr Jiricka 2004-01-15 19:34:04 UTC
Jarda, I am assuming that the startup warnings that will still be
present in the build (like this one) after the creation of the
NetBeans 3.6 branch, will be simply suppressed in this branch in the
openide/core code. Correct?
Comment 3 Petr Jiricka 2004-01-21 13:33:02 UTC
Per private discussions with Jarda Tulach, warnings will be suppressed
after we create the 3.6 branch. Changing target milestone to 3.6.

Comment 4 Jesse Glick 2004-01-28 14:50:23 UTC
IMHO the problem in this case should be fixed, rather than suppressing
the startup warning.

0. I know jasper-compiler.jar currently hardcodes use of Ant task
classes to run internal javac. It is quite gratuitous, however; it
would probably require less code and be more readable to just launch
javac directly. If it is straightforward to use a patched
jasper-compiler.jar that just does that, I would recommend that.
Otherwise, assuming this is not an option...

1. Remove the Class-Path entry, as well as those of any JARs like
jasper-compiler.jar directly or indirectly depending on ant.jar. You
may keep them in modules/ext if you like.

2. Use InstalledFileLocator at runtime to locate these JARs as well as
ant.jar in the NB installation, and create a URLClassLoader based on
them. Invoke whatever entry points you need from this class loader.

3. Currently web/jspparser takes no steps to ensure that ant.jar
actually exists in the distribution, meaning it would break with
NoClassDefFoundError's if it weren't, which is not good. You should
either:

a. Declare a module dependency on the Ant module to make sure it is
there. However this also requires it to be enabled.

b. Or, using the class loader mentioned in #2, fail gracefully if
ant.jar cannot be found.

c. Or, use ModuleInstall.validate() to check that ant.jar is present
before permitting web/jspparser to be enabled.

For promo-D we will likely have a comprehensive system of managing
dependencies from modules on common installed system libraries like
ant.jar, but in the meantime something should be done.
Comment 5 Petr Jiricka 2004-02-02 13:17:18 UTC
I haven't explored option 0 yet (technically this is trivial, but
licensing might be an issue).

I tried the other option (classloading changes), and what I found is
that I had to write quite a lot of reflection code, this mechanism is
hard to debug, and it still does not work. This basically means that
all jasper code has to be called using reflection, correct?

From the point of view of the JSP parser module, the resulting code is
definitely uglier than the original code - if we can make it work at
all.  So I'd like to precisely know the reasons why this is preferable
to using the Class-Path tag to load ant.jar. 

Is that because the Class-Path mechanism will not work under the new
installation structure proposal, when ant.jar may end up in a
different cluster than japparser.jar? Are there any other compelling
reasons? Thanks.

Comment 6 Jesse Glick 2004-02-02 17:39:09 UTC
Yes, using the simplest version of #1/#2 any entry points to the
Jasper parser need to be called via reflection. You can also avoid all
but one use of reflection using a callback interface defined in the
module and implemented in the loader used for Jasper and Ant; the Ant
module (e.g.) currently does this to interact with an ant.jar which
may be located anywhere (user-switchable installation) without
resorting to lots of reflection code. You just create the loader, load
the impl class, newInstance, cast to the interface, and everything
else is typechecked.

Whether you choose to go with #1/#2, or just suppress the warning for
B and think about what to do with consolidations for D, you still need
to pay attention to #3 for B.
Comment 7 Petr Jiricka 2004-02-05 17:28:09 UTC
*** Issue 39658 has been marked as a duplicate of this issue. ***
Comment 8 Petr Jiricka 2004-02-19 19:25:28 UTC
I am trying Jesse's suggestion with the interface, and I can't get it
to work. I use the following code (in class JspParserImpl):

URL urls[] = ...  // URLs of the external libraries including Ant 
                  // needed by the jspparser module
URLClassLoader urlCL = new URLClassLoader(urls,   
       JspParserImpl.class.getClassLoader());

This classloader is able to load my implementation class, but not the
library classes. Is it supposed to work this way? 

I saw that the Ant module uses a rather more complicated approach - it
has its own classloader class. What's the purpose of that class and
what does it do? Isn't a plain URLClassLoader sufficient? Thanks.


Comment 9 Jesse Glick 2004-02-19 19:42:44 UTC
JspParserImpl cannot be in the module, it must be in a separate JAR,
e.g. in modules/ext. (Or you need a special URLClassLoader which
refuses to load it from the module JAR, but that is messier.)
Otherwise it will not be able to access the library classes because it
is in the module class loader (think about how class linking works:
requesting loader != defining loader).

The Ant module uses some special class loaders to achieve multiple
inheritance, which you do not need. However you may need to subclass
URLClassLoader in order to return e.g. AllPermissions from
getPermissions(CodeSource).
Comment 10 Petr Jiricka 2004-02-20 16:03:51 UTC
Jesse, thanks for useful advice. You are saying that class XYZ has to
be in a separate jar file. By this, do you mean a) the class which
constructs the classloader and loads the impl class, or b) the class
that provides the implementation and that is loaded by reflection?

Does this also mean that this class can not depend on other IDE code,
e.g. OpenAPIs or my module classes? This would be a significant
constraint, which would make the whole architecture substantially more
complex than it is now.

BTW, I also tried a dependency check that you suggested earlier:

> c. Or, use ModuleInstall.validate() to check that ant.jar is present
> before permitting web/jspparser to be enabled.

This did not have any effect, though, as the loading of the modules
fails before this code gets executed, if the required classpath item
can not be found.

BTW, do you know any details about the Promo D architecture that you
mentioned before? Thanks.

> For promo-D we will likely have a comprehensive system of managing
> dependencies from modules on common installed system libraries like
> ant.jar, but in the meantime something should be done.

Comment 11 Jesse Glick 2004-02-20 16:24:31 UTC
(b) I suppose. If JspParserImpl provides the impl of some interface
JspParser and is loaded by reflection, then it cannot live in the
module JAR, because then it would be loaded by the module class loader
(simply because it can be and that is a lower loader), and it would
thus not be able to refer to the libraries. Just put this class (and
whatever else needs to refer to the libraries) in a separate JAR - the
impl JAR - which can then depend on the module (and anything the
module depends on incl. Open APIs), and the libraries.

It is really pretty simple. You have some interfaces in the module
defining what you want to be able to do, and module code calls them; a
separate source root (compiled against module classes and libraries)
provides impls; some static setup code makes a URLCL with the impl JAR
plus the libraries, with the parent loader being the module loader. If
you set it up right, there should only be about ten lines of code
dealing with class loaders and reflection at all. In the Ant module,
see AntBridge, BridgeInterface, and BridgeImpl as an example.

I don't know exactly what the promo-D architecture for this will look
like. Maybe Yarda does. It may look different on different platforms.
Comment 12 Petr Jiricka 2004-02-23 14:58:08 UTC
Fixed the subissue that JSP parser effectively depends on ant.jar, but
this dependency is not enforced. Used mechanism a. - declared a
dependency on the Ant module.
Comment 13 Petr Jiricka 2004-02-26 14:13:04 UTC
Ok, this issue is now fixed following Jesse's suggestion. However, the
fix was not as straightforward as outlined. The area of JSP parser
integration is very intensive on classloading and sensitive to the
correct behavior of classloaders. Notably, the class loader that loads
user classes that are a part of the web application, has to adhere to
the servlet specification in many respects. Similarly, the context
classloader for the parser thread is constrained by the specification.
A problem arises when the user applications contains some of the
classes that are used by the classloader itself - at one point I had
two different classloaders which loaded these, which was causing
problems. The final solution is that some JSP parser jar files
continue to be in the JSP parser module's classloader.

Jesse, BTW., what's the behavior of Thread.getContextClassLoader() in
the IDE? I didn't see this described at

http://www.netbeans.org/download/dev/javadoc/OpenAPIs/org/openide/modules/doc-files/api.html

Thanks.
Comment 15 Dan Kolar 2007-07-31 13:48:29 UTC
v