Spring application with embedded jetty can't find webdefault.xml if running from jar

20,490

Solution 1

I had a similar problem and I solve it with this main class implementation:

private static final int PORT = 8080;
private static final String WAR_LOCATION = "src/webapps"; //in your case I guess
private static final String CONTEXT_PATH = "/movence"; //change it if you want

public static void main(String[] args) throws Exception {
    Server server = new Server();
    WebAppContext context = new WebAppContext();
    SocketConnector connector = new SocketConnector();

    setupConnector(connector);
    setupContext(server, context);
    setupServer(server, context, connector);
    startServer(server);
}

private static void startServer(Server server) throws Exception, InterruptedException {
    server.start();
    server.join();
}

private static void setupServer(Server server, WebAppContext context, SocketConnector connector) {
    server.setConnectors(new Connector[] { connector });
    server.addHandler(context);
}

private static void setupConnector(SocketConnector connector) {
    connector.setPort(PORT);
}

private static void setupContext(Server server, WebAppContext context) {
    context.setServer(server);
    context.setContextPath(CONTEXT_PATH);
    context.setWar(WAR_LOCATION);
}

Solution 2

From @Trein's post, setting the WAR_LOCATION is important. I have seen jetty failing to deploy the web app when this is missing.

Assuming that you are using Jetty to test your app, if you are using Maven POM below is how I test my web app

pom.xml

 <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>jetty-servlet-tester</artifactId>
            <version>6.1.22</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>maven-jetty-plugin</artifactId>
            <version>6.1.19</version>
            <scope>test</scope>
        </dependency>
    </dependencies>


    <profiles>
        <profile>
            <id>tomcat</id>
 <build>
        <plugins>
                    <plugin>
                        <groupId>org.mortbay.jetty</groupId>
                        <artifactId>maven-jetty-plugin</artifactId>
                        <version>6.1.22</version>
                        <configuration>
                            <scanIntervalSeconds>10</scanIntervalSeconds>
                            <stopKey>foo</stopKey>
                            <stopPort>9999</stopPort>
                            <contextPath>/</contextPath>
                            <webAppSourceDirectory>src/main/webapp</webAppSourceDirectory>
                            <systemProperties>
                                <systemProperty>
                                    <name>RESOURCE_PATH</name>
                                    <value>${project.build.outputDirectory}</value>
                                </systemProperty>
                            </systemProperties>
                            <connectors>
                                <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
                                    <port>9090</port>
                                    <maxIdleTime>60000</maxIdleTime>
                                </connector>
                            </connectors>
                        </configuration>
                        <executions>
                            <execution>
                                <phase>test-compile</phase>
                                <goals>
                                    <goal>run</goal>
                                </goals>
                                <configuration>
                                    <scanIntervalSeconds>0</scanIntervalSeconds>
                                    <daemon>true</daemon>
                                </configuration>
                            </execution>
                            <execution>
                                <id>stop-jetty</id>
                                <phase>package</phase>
                                <goals>
                                    <goal>stop</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
</profiles>

To run the webapp you can either run mvn jetty:start or run mvn package. This starts the Jetty server on port 9090 and runs the tests (run your http based tests here) and shutdown the server/webapp. If you want to run as standalone webapp, use mvn jetty:start and use your webapp just like any webapp container.

This all assumes you are using Maven. The code above provided by @Trein does the same programatically and the one I provided is the maven configuration equivalent of the above.

Note: You shouldn't worry about webdefault.xml as the default is already packaged in the jetty jar file. You should use your own webdefault.xml only when you need to extend/alter the defaults. There is either something wrong with your Jetty jar (if its reporting this or something to do with your CLASSPATH settings)

Solution 3

It seems that jetty's trying to parse the web.xml (descriptor) file, but thinks its in

.../...../...../webdefault.xml

or something like that.

You should explicitly set the web.xml path:

context.setDescriptor("WEB-INF/web.xml"); `

or, assuming that your jar really does include the aformentioned 'project' dir (which isn't standard jar intrernal layout):

context.setDescriptor("project/src/webapps/WEB-INF/web.xml");

Solution 4

Probably a little bit out-dated. However I recently encountered this problem in the context of embedding Jetty in an Eclipse OSGi application using the version of Jetty packaged with Eclipse (Jetty 8.x).

The way I sorted this out is the following :

  1. Get the URL of the webdefault.xml relative to the org.eclipse.jetty.webapp bundle
  2. Pass this URL to the context default descriptor
Bundle bundle = FrameworkUtil.getBundle(WebAppContext.class);
Enumeration<URL> urls = bundle.findEntries("/", "webdefault.xml", true);
String webdefaultURL = urls.nextElement().toExternalForm(); // Should check returned value 
mycontext.setDefaultsDescriptor(webdefaultURL);

Hope it helps

seb

Solution 5

Found this github project : https://github.com/steveliles/jetty-embedded-spring-mvc

This gives a basic startup template project based on maven. It embedded jetty with spring mvc. Good place to start from scratch or to compare and debug what's wrong with current implementation.

The author has done a nice documentation here : http://steveliles.github.io/setting_up_embedded_jetty_8_and_spring_mvc_with_maven.html

Share:
20,490
Daniel Kim
Author by

Daniel Kim

java + script raw coder

Updated on March 15, 2020

Comments

  • Daniel Kim
    Daniel Kim about 4 years

    I have spring application which uses embedded Jetty instance.

    project
       | src
          | controller
          | webapps
              | jsp
              | WEB-INF
                  | web.xml
                  | applicationContext.xml
                  | spring-servlet.xml
    

    my jar has the same tree structure but I keep getting

        d:\test>java -jar springtest.jar
    2011-11-22 15:37:02.576:INFO::jetty-7.x.y-SNAPSHOT
    2011-11-22 15:37:02.686:WARN::Failed startup of context o.e.j.w.WebAppContext{/,[file:/C:/Users/me/AppData/Local/Temp/jetty-0.0.0.0-8080-webapps-_-any-/webinf
    /, jar:file:/d:/test/springtest.jar!/org/jcvi/webapps/]}
    java.io.FileNotFoundException: d:\test\org\eclipse\jetty\webapp\webdefault.xml (The system cannot find
    the path specified)
            at java.io.FileInputStream.open(Native Method)
            at java.io.FileInputStream.<init>(FileInputStream.java:106)
            at java.io.FileInputStream.<init>(FileInputStream.java:66)
            at sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:70)
            at sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:161)
            at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:653)
            at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:186)
            at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:772)
            at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
            at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119)
            at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1205)
            at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
            at javax.xml.parsers.SAXParser.parse(SAXParser.java:395)
            at org.eclipse.jetty.xml.XmlParser.parse(XmlParser.java:188)
            at org.eclipse.jetty.xml.XmlParser.parse(XmlParser.java:204)
            at org.eclipse.jetty.webapp.Descriptor.parse(Descriptor.java:60)
            at org.eclipse.jetty.webapp.WebDescriptor.parse(WebDescriptor.java:140)
            at org.eclipse.jetty.webapp.MetaData.setDefaults(MetaData.java:141)
            at org.eclipse.jetty.webapp.WebXmlConfiguration.preConfigure(WebXmlConfiguration.java:46)
            at org.eclipse.jetty.webapp.WebAppContext.preConfigure(WebAppContext.java:412)
            at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:448)
            at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:58)
            at org.eclipse.jetty.server.handler.HandlerWrapper.doStart(HandlerWrapper.java:89)
            at org.eclipse.jetty.server.Server.doStart(Server.java:258)
            at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:58)
            at org.jcvi.ServerRunner.startServer(ServerRunner.java:83)
            at org.jcvi.MainServer.main(MainServer.java:18)
    2011-11-22 15:37:02.748:INFO::Started [email protected]:8080 STARTING
    

    I have following java class which runs jetty server instance

    String webDir = this.getClass().getClassLoader().getResource("webapps").toExternalForm();
    Server server = new Server(8080);
    
    WebAppContext context = new WebAppContext();
    context.setContextPath("/");
    context.setResourceBase(webDir);
    context.setParentLoaderPriority(true);
    HandlerList handlers = new HandlerList();
    handlers.setHandlers(new Handler[] { context, new DefaultHandler() });
    server.setHandler(context);
    server.start();
    

    my web.xml looks like

    <welcome-file-list>
            <welcome-file>index.jsp</welcome-file>
        </welcome-file-list>
    
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/applicationContext.xml</param-value>
        </context-param>
    
        <listener>
            <listener-class>
                org.springframework.web.context.ContextLoaderListener
            </listener-class>
        </listener>
    
        <servlet>
            <servlet-name>spring</servlet-name>
                <servlet-class>
                    org.springframework.web.servlet.DispatcherServlet
                </servlet-class>
            <load-on-startup>2</load-on-startup>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>spring</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    

    this application runs fine if I run inside IDE, but it fails with JAR. How can I resolve this issue so that I can have single jar file which has the web application in it?