user3890731
user3890731

Reputation: 1

Embedded Jetty 9 PWC6188 Error

As many others, I'm facing the PWC6188-Error saying

"http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application". This is a quite common problem, however, I didn't make it to find a suitable solution.

First off, some background. We just migrated to Maven. Switching from a fat Tomcat web-server to an embedded Jetty 9 web-server.

Following, I already read this very usefull documentation: https://stackoverflow.com/tags/jstl/info Regarding this doc, following might be useful...

JSP - Taglib reference:

.<.%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%.>.

web.xml header

<web-app 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="YourWebAppID"
    version="2.5">

In conclusion, I need at least JSTL 1.1 and a servletcontainer with support for 2.5 Servlet specification. Thus, Jetty 9 with JSTL 1.2 might fit. <-- Really?

Furthermore, I want to talk about building and deploying of the webapp. Regarding this post:

cannot load JSTL taglib within embedded Jetty server

I might have some dependency issues. Here you can see all the dependencies defined in pom.xml of the web-application:

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
    </dependency>
    <!-- Parent container, which contains embedded Jetty 9 also uses log4j and provides the lib. -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>${log4j.version}</version>
        <scope>provided</scope>
    </dependency>
    <!-- Some project related libs... -->
    <dependency>
        <groupId>org.apache.struts</groupId>
        <artifactId>struts-core</artifactId>
        <version>${struts.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.struts</groupId>
        <artifactId>struts-taglib</artifactId>
        <version>${struts.version}</version>
    </dependency>
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.3.1</version>
    </dependency>
    <!-- Some more proprietary libs... -->
    <!-- ... -->

    <!-- Now it's getting interesting... -->
    <!-- Following dependencies are necessary to run 'mvn package'. 
        Scope is set to provided, so it's not transferred to resulting *.war. 
        Thus, containerserver must provide those.
    -->
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-webapp</artifactId>
        <version>${jetty.version}</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

Running 'mvn jetty:run' works just fine. It packages the war-file, containing the following libs:

ls target/ROOT/WEB-INF/lib
    antlr-2.7.2.jar
    commons-beanutils-1.8.0.jar
    commons-chain-1.2.jar
    commons-digester-1.8.jar
    commons-fileupload-1.3.1.jar
    commons-io-2.2.jar
    commons-logging-1.0.4.jar
    commons-validator-1.3.1.jar
    oro-2.0.8.jar

For me, this looks just fine. All web-app related libs are packed inside war. So, this war might not work properly in Tomcat web-server, thus the JSTL tag lib is not provided by the web-app. However, I'm going to use embedded Jetty 9... and here are all the dependencies defined in pom.xml from my server-container:

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>${lib.log4j.version}</version>
    </dependency>
    <!-- Some more proprietary libs... -->
    <!-- ... -->

    <!-- Project-related libs. -->
    <dependency>
        <groupId>javax.mail</groupId>
        <artifactId>mail</artifactId>
        <version>1.4.7</version>
    </dependency>
    <dependency>
        <groupId>org.apache.derby</groupId>
        <artifactId>derby</artifactId>
        <version>10.10.2.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-email</artifactId>
        <version>1.3.3</version>
    </dependency>

    <!-- Jetty Web-Server -->
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-webapp</artifactId>
        <version>${jetty.version}</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-jsp</artifactId>
        <version>${jetty.version}</version>
    </dependency>
</dependencies>

Because of licensing of some included libraries, I need to provide all jars as they are. Meaning, I might not extract and include classes to my resulting jar. Thus, my maven assembly creates a following structure:

*prefix*
    /bin
    myexecute.sh (calls java -jar ${prefix}/lib/java/main_app.jar)
    /lib/java
    *.jar (all the jar files)

prefix/lib/java lists following libraries:

ls
    activation-1.1.jar
    commons-email-1.3.3.jar
    derby-10.10.2.0.jar
    main_app.jar
    javax.el-3.0.0.jar
    javax.servlet-api-3.1.0.jar
    javax.servlet.jsp-2.3.2.jar
    javax.servlet.jsp-api-2.3.1.jar
    javax.servlet.jsp.jstl-1.2.0.v201105211821.jar
    javax.servlet.jsp.jstl-1.2.2.jar
    jetty-http-9.2.2.v20140723.jar
    jetty-io-9.2.2.v20140723.jar
    jetty-jsp-9.2.2.v20140723.jar
    jetty-schemas-3.1.M0.jar
    jetty-security-9.2.2.v20140723.jar
    jetty-server-9.2.2.v20140723.jar
    jetty-servlet-9.2.2.v20140723.jar
    jetty-util-9.2.2.v20140723.jar
    jetty-webapp-9.2.2.v20140723.jar
    jetty-xml-9.2.2.v20140723.jar
    log4j-1.2.17.jar
    mail-1.4.7.jar
    org.eclipse.jdt.core-3.8.2.v20130121.jar

The classpath inside the main_app.jar looks just fine. All necessary java libraries are listed and the application works just fine. However, I can't access the web-app, because of the PWC6188. Please notice, There is no PWC6188-error, when running the application using eclipse. I set up the project using 'mvn eclipse:eclipse' btw. Following, regarding this thread

Jetty 9 The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved

just jetty-webapp and jetty-jsp artifacts are required, to set up Jetty containerserver with JSP, JSTL, Servlet etc. support.

What else have I done? I read some useful info about Jetty class loading.

http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html It states, that libraries defined in WEB-INF folder has a higher priority than libs from it's container server. However, even if I switch priority, I'm facing PWC6188. As mentioned here

cannot load JSTL taglib within embedded Jetty server

it might be a solution to set a classloader - I tried, without success.

In conclusion, as you might notice, I tried a lot and got quite deep into all this JSTL lib. However, I can't manage to get rid of PWC6188 error. I bet it's something trivial, however, it might also be a major problem of Jetty 9. Thus, I like to say thanks for any help!

Upvotes: 0

Views: 762

Answers (1)

Tan
Tan

Reputation: 155

If you are using jetty in an embedded scenario, and you need to use JSTL, then you must ensure that the JSTL jars are included on the container's classpath - that is the classpath that is the parent of the webapp's classpath. This is a restriction that arises from the Java EE specification.

So, you can solve your problem like this:

WebAppContext webapp = new WebAppContext();
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
URLClassLoader subClassLoader = new URLClassLoader(new URL[]{}, currentClassLoader);//this is the point.
webapp.setClassLoader(subClassLoader); //this is the point.
webapp.setContextPath("/");
webapp.setResourceBase("src/main/webapp");
server.setHandler(webapp);
server.start();
server.join();

Upvotes: 0

Related Questions