1

We have a number of webapps that all use a certain JSF library. We'd like to place the library in a common location or on the main classpath. The trouble is that the system expects the library to be in WEB-INF/lib so the webapp classloader can scan it and load it.

We are the creators of this particular library, and during development it's way easier to have it on the main classpath.

Is this possible? Can anyone give an example of what to put in web.xml to make this happen (if that's the right mechanism)?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
ccleve
  • 15,239
  • 27
  • 91
  • 157
  • 2
    Have you tried to set the JSF libraries in the server common lib folder? – Luiggi Mendoza Mar 28 '13 at 16:04
  • What servlet container are you using? They all have a lib folder that spans all their webapps. In tomcat you would add it to `$CATALINA_BASE/lib/` – Lucas Mar 28 '13 at 16:05
  • It sounds like you're using Tomcat. If so, you can install your .jar(s) in the $CATALINA_BASE/lib folder. If you're using an app server (e.g. JBoss or WebSphere) you have even more options. – paulsm4 Mar 28 '13 at 16:07
  • Jetty. Adding it to that lib folder doesn't seem to work. – ccleve Mar 28 '13 at 16:08
  • I've added "jetty" to your tags. Check out this link: http://docs.codehaus.org/display/JETTY/Classloading. – paulsm4 Mar 28 '13 at 16:10
  • We could write a custom Jetty webapp classloader, but I'm looking for something a little more standard. – ccleve Mar 28 '13 at 16:12

3 Answers3

4

We are the creators of this particular library, and during development it's way easier to have it on the main classpath. Is this possible?

For Facelets resources this is possible with a custom ResourceResolver in webapp itself.

public class FaceletsResourceResolver extends ResourceResolver {

    private ResourceResolver parent;
    private String basePath;

    public FaceletsResourceResolver(ResourceResolver parent) {
        this.parent = parent;
        this.basePath = "META-INF/resources"; // TODO: Make configureable?
    }

    @Override
    public URL resolveUrl(String path) {
        URL url = parent.resolveUrl(path); // Resolves from WAR which would also do META-INF/resources of JARs in WAR.

        if (url == null) {
            url = getClass().getResource("/" + basePath + path); // Resolves from JARs in WAR when base path is not META-INF/resources.
        }

        if (url == null) {
            url = Thread.currentThread().getContextClassLoader().getResource(basePath + path); // Resolves also from anywhere else in classpath.
        }

        return url;
    }

}

To get it to run, configure it as follows in webapp's web.xml:

<context-param>
    <param-name>javax.faces.FACELETS_RESOURCE_RESOLVER</param-name>
    <param-value>com.example.FaceletsResourceResolver</param-value>
</context-param>

For annotated JSF artifacts like managed beans, etc which needs to be scanned by the JSF annotation scanner, this is not possible. The JAR has really to end up in /WEB-INF/lib. See also How to reference JSF managed beans which are provided in a JAR file?

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Is it possible to get this ResourceResolver to pull from the main classpath, even if the resource isn't in a jar? At development time we use Eclipse, and Eclipse puts the /classes directory of an open project on the classpath. – ccleve Mar 28 '13 at 16:24
  • The `Thread.currentThread().getContextClassLoader()` does that also. – BalusC Mar 28 '13 at 16:25
0

You can try the shared folder mechanism provided with the web server. Put your jar files in that folder. you can access them anywhere.

Mehul Kaklotar
  • 365
  • 1
  • 19
0

Since you're using jetty, perhaps your best choice is to put your libraries in $jetty.home/lib/ext:

http://docs.codehaus.org/display/JETTY/Classloading

At startup, the jetty runtime will automatically load all jars from the top level $jetty.home/lib, along with certain subdirectories such as $jetty.home/lib/management/, $jetty.home/lib/naming/ etc, which are named explicity in the start.config file contained in the start.jar. In addition, it will recursively load all jars from $jetty.home/lib/ext. So, to add extra jars to jetty, you can simply create a file hierarchy as deep as you wish within $jetty.home/lib/ext to contain these jars. Of course, you can always change this default behaviour by creating your own start.config file and using that instead.

paulsm4
  • 114,292
  • 17
  • 138
  • 190
  • Perhaps you missed the "JSF" part in the question? This just puts the JAR in "global" classpath, not in webapp's classpath. See also http://stackoverflow.com/questions/7663818/how-to-reference-jsf-managed-beans-which-are-provided-in-a-jar-file/7663898#7663898 – BalusC Mar 28 '13 at 16:17
  • 1
    No, doesn't work. JSF libs are different. The webapp classloader needs to know to scan the jar file for certain specific things, like face-config.xml, whatever.taglib.xml, etc. If it's in a common lib directory that doesn't happen. – ccleve Mar 28 '13 at 16:17