When frameworks such Struts that provide TLD descriptor files are located in a shared library, applications that use them fail to process the tag libraries.
Here is what Kinman mentioned in a private thread to Bruno ...
In GlassFish3, system jars that contain TLDs need to implement TldProvider interface somewhere. The purpose of such
instances is to to tell the JSP engine that TLDs are present in the jars and need to be scanned. This is needed for performance and to cope with the new classloader hierarchy. We have such implementations for JSTL and JSF, but not for struts, since it is not bundled with GF.
Can you attach a simple test war?
How bad is its impact? (Severity)
medium. Workaround: put the jars in WEB-INF/lib
How often does it happen? Will many users see this problem? (Frequency)
common library outside the application with tld
How much effort is required to fix it? (Cost)
low. Add a new TldProvider to scan jars in lib and domains/domain1/lib
What is the risk of fixing it and how will the risk be mitigated? (Risk)
To test this issue, install Struts2 essential libraries to GlassFish's shared lib location.
Then deploy 'glassfish-nonworking.ear'
To test the application running fine, make sure there are no struts2 libraries at GF's SL.
So we have to rebuild every single application to deploy our third party jars inside each one (to improve performance no less)? One of the nice things with having system jars is removing the risk of differing versions of shared libraries from getting deployed.
Regardless, in trying to follow the work around for this bug I can't for the life of me figure out how TldProvider is supposed to be implemented. There is marginally more than 0 documentation for it. I have added an implementation to my system jar, but none of the methods in it are ever called. (And I feel funky about adding an import for org.glassfish.api.web.TldProvider, feels very non-portable).
Am I just stupid here or what? Is there an example of an external taglib library that implements this anywhere that can be used as a reference?
Since there are several jars in $INSTALL_ROOT/lib, scanning it in startup will increase the startup time.
So, we plan to scan $DOMAIN_ROOT/lib only at this moment.
In this case, any custom libraries jar can be put there and the tld will be scanned. I have verified that Bruno's test case is working if one put all those jar under $DOMAIN_ROOT/lib (eg. domains/domain1/lib).
You say "we plan to scan $DOMAIN_ROOT/lib only at this moment". Does that mean that 3.0.1 b22 is supposed to work that way right now, or do you mean in some newer version?
Right now 3.0.1 b22 does not work (for me at least) if the jar is placed in $DOMAIN_ROOT/lib or any of its subdirectories. If I put the jar in WEB-INF/lib then it does.
I tried this with Bruno's test case, moving all of the libs from the webapp's META-INF/lib to $DOMAIN_ROOT/lib and it does not work for me: org.apache.jasper.JasperException: /index.jsp(1,42) PWC6117: File "/struts-tags" not found
Chan, I ran my tests on top of GF 3.0.1 b22.
It does not work.
And when I say "shared library" I mean domains/domain1/lib.
I also tried putting Struts2 JAR files in domains/domain1/lib/applibs.
Didn't work either.
I am still waiting for approval to checkin the code.
What if the JAR scan process of shared library was parallel to the startup process?
And while it does not finish and "parent first" apps do not find something, a thread would wait.
Useless feature for production environment, but a must at development time.
Since this setup already seems to stray from the spec a little, how about a properties file or something to point to shared libs that have embedded tld's. I would have to think that would be much faster than this contract arrangement, and a whole lot simpler. Plus, it would give you the ability to identify tlds in 3rd party libs that you can't modify (it isn't clear to me whether the TldProvider mechanism makes this possible or not since I couldn't get it to work). Just my $.02
We plan to scan the customize jars as follows:
1. those in domains/domain1/lib
2. those specified in --libraries during the deployment time
Isn't it too late to make any change in GlassFish 3.1 to support this requirement which seems like an RFE to me. Does the Servlet/JSP spec say whether shared jars need to be scanned for TLDs?
Even though the glassfish-working.ear run, I see the following in server.log:
Caused by: java.lang.ClassNotFoundException: javassist.ClassPool
at java.lang.Class.forName0(Native Method)
... 63 more
I have searched through the ear files, there is no such class.
It would be good to update the applications so that we can verify it end to end here without problem.
Sanjeeb appears to be correct in that the spec makes no requirement to scan shared jars as I read it. I had always presumed that it did. So this is really just a loss of a non-standard feature from v2 to v3. I guess I can deal with that as long as the resultant implementation complies with the spec.
As a follow up for anyone else running into this: What we did to make this work was move our tlds out of our shared library into a separate jar. That separate jar gets packaged with our app, but the shared library still goes in $DOMAIN_ROOT/lib. This configuration works, and actually makes sense to me. You then only have to deal with updating deployed applications on changes to the shared library if one of the tags that they use gets modified in a manner that requires a change to the tld. And in this case you would likely have had to update your deployed app anyway.
This issue could also be implemented as a configurable option (either enabling/disabling TLD scan on shared libraries; disabled by default).
Corporate deployments usually throw common JARs of corporate frameworks to shared lib to reduce size of EARs and facilitate delivery and deployment of projects by having a small EAR file without JARs.
One of our customers have 300+ apps deployed on WebSphere servers, and they are used to do this.
If GlassFish wants to be an option for such use case, this issue is a must have.
Although I am in favor of improving tld packaging to encourage modularity, I must say that this request has come in way too late for 3.1 release and that's my primary objection. We should look into this in next release. Currently we are in high resistance mode . Again, this is just my opinion, not the opinion of the people who actually approve a change in high resistance mode.
I find the issue in the test jar. javassist-3.7.ga.jar is missing. After adding the jar, the exception is resolved.
This is what I think about this issue, considering the Change Control Process:
1. How bad?
2. How often?
3. How much?
4. What risk?
5. Workaround exist?
6. Describe in release note?
Approved for 3.1 limiting the change to only scanning <domain>/lib and --libraries.
Transmitting file data ...
Committed revision 44519.
Looking at the changes, I think it is incomplete as it does not seem to be processing Class-Path manifest entries of library jars for potential source of TLDs. More over, it does not exclude jars from library directory that that are excluded from server runtime.
Per discussion with Sahoo, since we don't process the glassfish/lib, then there is no need to process Exclude marker.
Scanning jars referenced in Manifest Class-Path is currently limited to only the set of referencing jars (i.e. those with Manifest Class_path) that are in the application (i.e. under WEB-INF). See TldScanner for further details. This is a design decision to limit the amount scanning at server startup time. This should not be an issue in practice, as it is extremely unlikely to happen for system jars. The user can always make sure to put all the necessary jar in domain1/lib.
Now I understood Sahoos' previous comment.
Yes, there's no need to scan for referenced jars on MANIFEST Class-Path, since most certainly they are side-by-side on domain1/lib
IIUC, the fix made by Shing Wai also covers per application libraries (domain/lib/applib). Now, it is often recommended to use Class-Path in application libraries to make sure classpath order is maintained. If you search glassfish forum, you will find examples of such usage.