Nexus / Jetty doesn't want to start anymore: Unresolved address - jetty

We have a Nexus server which worked fine until friday. Nexus was stopped and since we are unable to start it again but I can't figure out why ?
I think it's a Jetty problem. Here is the stack strace:
jvm 1 | 2012-08-13 09:31:10 WARN [er_start_runner] - org.mortbay.log - failed SelectChannelConnector#*:8080
jvm 1 | java.net.SocketException: Unresolved address
jvm 1 | at sun.nio.ch.Net.translateToSocketException(Net.java:58)
jvm 1 | at sun.nio.ch.Net.translateException(Net.java:84)
jvm 1 | at sun.nio.ch.Net.translateException(Net.java:90)
jvm 1 | at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:61)
jvm 1 | at org.mortbay.jetty.nio.SelectChannelConnector.open(SelectChannelConnector.java:216)
The configuration is (jetty.xml):
<Configure id="Server" class="org.mortbay.jetty.Server">
<Call name="addConnector">
<Arg>
<New class="org.mortbay.jetty.nio.SelectChannelConnector">
<Set name="host">${application-host}</Set>
<Set name="port">${application-port}</Set>
</New>
</Arg>
</Call>
<Set name="handler">
<New id="Contexts" class="org.mortbay.jetty.handler.ContextHandlerCollection">
<!-- The following configuration is REQUIRED, and MUST BE FIRST.
It makes the Plexus container available for use in the Nexus webapp. -->
<Call name="addLifeCycleListener">
<Arg>
<New class="org.sonatype.plexus.jetty.custom.InjectExistingPlexusListener" />
</Arg>
</Call>
<!-- The following configuration disables JSP taglib support, the validation of which
slows down Jetty's startup significantly. -->
<Call name="addLifeCycleListener">
<Arg>
<New class="org.sonatype.plexus.jetty.custom.DisableTagLibsListener" />
</Arg>
</Call>
</New>
</Set>
<New id="NexusWebAppContext" class="org.mortbay.jetty.webapp.WebAppContext">
<Arg><Ref id="Contexts"/></Arg>
<Arg>${webapp}</Arg>
<Arg>${webapp-context-path}</Arg>
<Set name="extractWAR">false</Set>
</New>
<Set name="stopAtShutdown">true</Set>
<Set name="sendServerVersion">true</Set>
<Set name="sendDateHeader">true</Set>
<Set name="gracefulShutdown">1000</Set>
</Configure>
and the plexus.properties:
application-port=8081
application-host=0.0.0.0
runtime=${basedir}/runtime
apps=${runtime}/apps
nexus-work=${basedir}/../../data/nexus/sonatype-work/nexus
nexus-app=${runtime}/apps/nexus
webapp=${runtime}/apps/nexus/webapp
webapp-context-path=/nexus
security-xml-file=${nexus-work}/conf/security.xml
application-conf=${nexus-work}/conf
runtime-tmp=${runtime}/tmp
# If this file is present, it will be used to configure Jetty.
jetty.xml=${basedir}/conf/jetty.xml
# Uncomment this to use the debug js files
#index.template.file=templates/index-debug.vm
Nexus version is 1.9.2.3
I can't understand:
why it wants to start a connector at port 8080 (while I only set port 8081) and
what means the address * (and why not 0.0.0.0) ? And of course why it doesn't want to start anymore ?
Thanks a lot for all your ideas!

I cannot comment on the 8080 vs 8081 issue, but as for the SocketException ...
The SocketException: unresolved address is usually due to some sort of host/dns/resolve configuration issue present on your system.
The most basic testcase for java that might help identify the issue would be the following
import java.net.InetAddress;
import java.net.InetSocketAddress;
public class AddrTest
{
public static void main(String[] args)
{
try
{
InetAddress addr = InetAddress.getByName("0.0.0.0");
System.out.println("InetAddress => " + addr);
System.out.println("InetAddress.isAnyLocalAddress = " + addr.isAnyLocalAddress());
System.out.println("InetAddress.isLinkLocalAddress = " + addr.isLinkLocalAddress());
System.out.println("InetAddress.isLoopbackAddress = " + addr.isLoopbackAddress());
InetSocketAddress isockaddr = new InetSocketAddress(addr,8080);
System.out.println("InetSocketAddr = " + isockaddr);
System.out.println("InetSocketAddr.isUnresolved = " + isockaddr.isUnresolved());
}
catch (Throwable e)
{
e.printStackTrace();
}
}
}
Run this, and you should have the output
InetAddress => /0.0.0.0
InetAddress.isAnyLocalAddress = true
InetAddress.isLinkLocalAddress = false
InetAddress.isLoopbackAddress = false
InetSocketAddr = /0.0.0.0:8080
InetSocketAddr.isUnresolved = false
What's important to note are the 2 lines...
InetAddress.isAnyLocalAddress = true - means that java + OS reports this as the ANY addr
InetSocketAddr.isUnresolved = false - means that java + OS was able to resolve this socket address
If you get an exception during this test, then you have some sort of fundamental host resolution issue on your system (dns, dhcp. vpn, etc/hosts, no IPv4 available, etc...), nothing you do in java, jetty, or nexus can fix this sort of issue. You'll need to address this (no pun intended) at the OS / Networking level.

I had a similar issue. Jetty was running inside docker container (jetty:9.3.24-jre8). You need to comment out line about http.host in start.ini:
#jetty.http.host='0.0.0.0'
Network interfaces get mixed up for some reason.

Solved!
The file jetty.xml had only the 'r' permission which is not enough: it must have the 'x' permission too. So Jetty was unable to read the file jetty.xml and in that case it tries to start a default connector on '*:8080' => * is not resolvable (I don't know why they used * instead of 0.0.0.0 ???)
So it was a configuration issue.

Related

WebSphere MQ call failed with compcode '2' ('MQCC_FAILED') reason '2397' ('MQRC_JSSE_ERROR') while using jetty config for MQ Connection

I'm configuring MQ connection in jetty-env.xml file as :
<New id="myJmsConnection" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg><Ref refid="wac"/></Arg>
<Arg>jms/mymq</Arg>
<Arg>
<New class="com.ibm.mq.jms.MQConnectionFactory">
<Set name="connectionNameList">x.x.x.x</Set>
<Set name="port">xxx</Set>
<Set name="queueManager">xxx</Set>
<Set name="channel">xxx.CHANNEL</Set>
<Set name="transportType">1</Set>
<Set name="SSLCipherSuite">xxxx</Set>
</New>
</Arg>
</New>
With the above configuration, when I run jetty I'm getting this error
nested exception is com.ibm.mq.MQException: JMSCMQ0001: WebSphere MQ call failed with compcode '2' ('MQCC_FAILED') reason '2397' ('MQRC_JSSE_ERROR')
But the same config values when I use in my Code to make MQ connection, I'm able to establish the connection
#Bean(name="MQConnectionFactory")
public ConnectionFactory connectionFactory() {
if (factory == null) {
factory = new MQConnectionFactory();
try {
factory.setConnectionNameList(env.getRequiredProperty(HOST));
factory.setPort(Integer.parseInt(env.getRequiredProperty(PORT)));
factory.setQueueManager(env.getRequiredProperty(QUEUE_MANAGER));
factory.setChannel(env.getRequiredProperty(CHANNEL));
factory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
factory.setSSLCipherSuite(env.getRequiredProperty(SSL_CIPHER_SUITE));
factory.setStringProperty(WMQConstants.USERID, env.getRequiredProperty(QUEUE_USERID));
factory.setStringProperty(WMQConstants.PASSWORD, env.getRequiredProperty(QUEUE_PASSWORD));
} catch (JMSException e) {
throw new RuntimeException(e);
}
}
return factory;
}
My question is why the connectivity is working from the Java code but it throws MQ exception when configured in jetty-env.xml?

defining webapp load order in jetty

I have two webapps that might be deployed separately or in the same jetty server. In my situation, one webapp must deploy before the other can complete its deployment, so I'm looking for a solution in the dual deployment case where I can define the deployment order.
I've defined a context xml file with the following:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN"
"http://www.eclipse.org/jetty/configure.dtd">
<Configure class="org.eclipse.jetty.server.handler.HandlerList">
<New class="org.eclipse.jetty.server.handler.HandlerList">
<Set name="handlers">
<Array type="org.eclipse.jetty.server.Handler">
<Item>
<New class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/security</Set>
<Set name="war"><SystemProperty name="jetty.home"/>/security_app/war/</Set>
<Call name="addAliasCheck">
<Arg>
<New class="org.eclipse.jetty.server.handler.ContextHandler$ApprovePathPrefixAliases"/>
</Arg>
</Call>
</New>
</Item>
<Item>
<New class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/</Set>
<Set name="war"><SystemProperty name="jetty.home"/>/main_app/war/</Set>
<Call name="addAliasCheck">
<Arg>
<New class="org.eclipse.jetty.server.handler.ContextHandler$ApprovePathPrefixAliases"/>
</Arg>
</Call>
</New>
</Item>
</Array>
</Set>
</New>
</Configure>
However, with this solution, I get the following error:
java.lang.ClassCastException: org.eclipse.jetty.server.handler.HandlerList cannot be cast to org.eclipse.jetty.server.handler.ContextHandler
at org.eclipse.jetty.deploy.providers.WebAppProvider.createContextHandler(WebAppProvider.java:292)
at org.eclipse.jetty.deploy.App.getContextHandler(App.java:101)
at org.eclipse.jetty.deploy.bindings.StandardDeployer.processBinding(StandardDeployer.java:36)
at org.eclipse.jetty.deploy.AppLifeCycle.runBindings(AppLifeCycle.java:186)
at org.eclipse.jetty.deploy.DeploymentManager.requestAppGoal(DeploymentManager.java:498)
at org.eclipse.jetty.deploy.DeploymentManager.addApp(DeploymentManager.java:146)
at org.eclipse.jetty.deploy.providers.ScanningAppProvider.fileAdded(ScanningAppProvider.java:180)
at org.eclipse.jetty.deploy.providers.ScanningAppProvider$1.fileAdded(ScanningAppProvider.java:64)
at org.eclipse.jetty.util.Scanner.reportAddition(Scanner.java:605)
at org.eclipse.jetty.util.Scanner.reportDifferences(Scanner.java:528)
at org.eclipse.jetty.util.Scanner.scan(Scanner.java:391)
at org.eclipse.jetty.util.Scanner.doStart(Scanner.java:313)
which of course, is true, though they both are AbstractHandlers in the end. What might I be doing wrong or is there another way to pull this off?
Using Jetty 9.2.1
Thanks
You have hardcoded deployments, don't use the deploy module.
The exception you are getting is the deploy module attempting to find and deploy webapps itself, and is failing to find the org.eclipse.jetty.server.handler.ContextHandler entry it is expecting.
The best way to fix this is to not have separate webapps that depend on each other during deploy/init (that is out of scope for the servlet spec). Make the /main_app/war/ webapp init on demand, not on startup.
Now back to your specific problem ...
Important: do not work / edit / run / configure the ${jetty.home} directory directly.
The ${jetty.base} directory exists for a reason, use it, you'll be much happier when you do.
http://www.eclipse.org/jetty/documentation/current/startup.html
For those things that are load order sensitive, do not use the deploy module with those artifacts. (its safe to use the deploy module for other webapps you have that don't have load order dependencies)
To accomplish this, we'll configure a ${jetty.base} directory to use a custom xml file on startup, along with a /special/ directory for these load order dependent WebAppContexts, making sure that these contexts are not loaded, and managed by the deploy module.
$ cd my-jetty-base
$ mkdir etc
$ gvim etc/special-deploy.xml
$ echo "etc/special-deploy.xml" >> start.ini
$ ls -F
etc/ special/ start.ini webapps
$ ls -F special/
main.war security.war
$ cat start.ini
--module=http
jetty.port=8080
--module=deploy
etc/special-deploy.xml
The special-deploy.xml looks like this ...
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<!-- =============================================================== -->
<!-- Add Load Order Dependant Webapps -->
<!-- =============================================================== -->
<Configure id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection">
<Call name="addHandler">
<Arg>
<New class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/security</Set>
<Set name="war"><SystemProperty name="jetty.base"/>/special/security.war</Set>
<Call name="addAliasCheck">
<Arg>
<New class="org.eclipse.jetty.server.handler.ContextHandler$ApprovePathPrefixAliases"/>
</Arg>
</Call>
</New>
</Arg>
</Call>
<Call name="addHandler">
<Arg>
<New class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/</Set>
<Set name="war"><SystemProperty name="jetty.base"/>/special/main.war</Set>
<Call name="addAliasCheck">
<Arg>
<New class="org.eclipse.jetty.server.handler.ContextHandler$ApprovePathPrefixAliases"/>
</Arg>
</Call>
</New>
</Arg>
</Call>
</Configure>
When you run you'll see the following ...
$ java -jar /path/to/jetty-distribution-9.2.10.v20150310/start.jar
2015-04-29 12:18:55.929:INFO::main: Logging initialized #275ms
2015-04-29 12:18:56.093:WARN:oejsh.ContextHandler:main: ApprovePathPrefixAliases is not safe for production
2015-04-29 12:18:56.094:WARN:oejsh.ContextHandler:main: ApprovePathPrefixAliases is not safe for production
2015-04-29 12:18:56.097:INFO:oejs.Server:main: jetty-9.2.10.v20150310
2015-04-29 12:18:56.150:INFO:oejw.StandardDescriptorProcessor:main: NO JSP Support for /security, did not find org.eclipse.jetty.jsp.JettyJspServlet
2015-04-29 12:18:56.166:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext#751d30f6{/security,file:/tmp/jetty-0.0.0.0-8080-security.war-_security-any-3863723758166154575.dir/webapp/,AVAILABLE}{/home/joakim/examples/load-order-example/special/security.war}
2015-04-29 12:18:56.181:INFO:oejw.StandardDescriptorProcessor:main: NO JSP Support for /, did not find org.eclipse.jetty.jsp.JettyJspServlet
2015-04-29 12:18:56.183:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext#4f79a28b{/,file:/tmp/jetty-0.0.0.0-8080-main.war-_-any-2704851460101920295.dir/webapp/,AVAILABLE}{/home/joakim/examples/load-order-example/special/main.war}
2015-04-29 12:18:56.184:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:/home/joakim/examples/load-order-example/webapps/] at interval 1
2015-04-29 12:18:56.195:INFO:oejs.ServerConnector:main: Started ServerConnector#4ef6d773{HTTP/1.1}{0.0.0.0:8080}
2015-04-29 12:18:56.196:INFO:oejs.Server:main: Started #542ms
^C2015-04-29 12:19:09.594:INFO:oejs.ServerConnector:Thread-0: Stopped ServerConnector#4ef6d773{HTTP/1.1}{0.0.0.0:8080}
2015-04-29 12:19:09.599:INFO:oejsh.ContextHandler:Thread-0: Stopped o.e.j.w.WebAppContext#4f79a28b{/,file:/tmp/jetty-0.0.0.0-8080-main.war-_-any-2704851460101920295.dir/webapp/,UNAVAILABLE}{/home/joakim/examples/load-order-example/special/main.war}
2015-04-29 12:19:09.602:INFO:oejsh.ContextHandler:Thread-0: Stopped o.e.j.w.WebAppContext#751d30f6{/security,file:/tmp/jetty-0.0.0.0-8080-security.war-_security-any-3863723758166154575.dir/webapp/,UNAVAILABLE}{/home/joakim/examples/load-order-example/special/security.war}

IllegalArgumentException when attempting to start jetty server using gradle plugin

I am trying to use the jetty gradle plugin to run a jetty server for functional testing. However, I am getting an java.lang.IllegalArgumentException: Object is not of type class org.mortbay.jetty.webapp.WebAppContext.
I have followed the example shown here and can't see what I am doing differently. The relevant part of the build file looks like this:
apply plugin: 'jetty'
dependencies {
providedRuntime 'com.h2database:h2:1.3.167'
providedRuntime 'commons-dbcp:commons-dbcp:1.4'
}
jettyRunWar {
httpPort = 8083
stopPort = 8085
stopKey = "stopKey"
jettyConfig = file("$projectDir/jetty-config/jetty.xml")
}
jettyStop {
stopPort = 8085
stopKey = "stopKey"
}
And my jetty.xml looks like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure class="org.mortbay.jetty.webapp.WebAppContext">
<Set name="contextPath">/gateway</Set>
<New class="org.mortbay.jetty.plus.naming.Resource">
<Arg>
</Arg>
<Arg>jdbc/gateway</Arg>
<Arg>
<New class="org.apache.commons.dbcp.BasicDataSource">
<Set name="url">jdbc:h2:tcp://localhost/build/db; USER=sa</Set>
</New>
</Arg>
</New>
</Configure>
The stacktrace can be found here.
Any suggestions would be greatly appreciated.
My best guess is that it's a bug in the Jetty plugin. In general, the Jetty plugin is quite limited and outdated, and I recommend to try the arquillian-gradle-plugin instead. This is where Gradle's container support is heading.

How to get Jetty to use JVM scoped JNDI?

I'm trying to setup a JNDI resource for a Jackrabbit repository factory in Jetty. The problem is that I seem to be getting thhe JNDI as webapp scoped. I need it to be JVM scoped. As far as I understood from the docs, you need to specify a null arg as shown below (<Arg></Arg>) in order to do so (explained here).
I have two webapps deployed to Jetty and I need them to be sharing the same JNDI. If they're not sharing it, Jackrabbit tries to get initialized twice and fails which breaks my whole app.
I ran the code through a debugger and I can see that the first webapp that gets accessed and needs a JNDI lookup for the Jackrabbit repository, gets an instance of the BindableRepositoryFactory and correctly adds records to the cache object. However, a completely different object is created for the cache upon JNDI lookup. That is obviously still empty and thus a new instance gets created, which screws things up.
I am using Jetty 7.6.2.v20120308.
Here's my jetty-jndi.xml:
<New class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jndi:comp/env/jcr/repository</Arg>
<Arg>
<New class="javax.naming.Reference" id="reference">
<Arg>javax.jcr.Repository</Arg>
<Arg>org.apache.jackrabbit.core.jndi.BindableRepositoryFactory</Arg>
<Arg>null</Arg>
<Call name="add" id="reference">
<Arg>
<New class="javax.naming.StringRefAddr">
<Arg>configFilePath</Arg>
<Arg><SystemProperty name="jetty.home" default="."/>/jackrabbit/repository.xml</Arg>
</New>
</Arg>
</Call>
<Call name="add" id="reference">
<Arg>
<New class="javax.naming.StringRefAddr">
<Arg>repHomeDir</Arg>
<Arg><SystemProperty name="jetty.home" default="."/>/jackrabbit</Arg>
</New>
</Arg>
</Call>
</New>
</Arg>
</New>
In the pom file where I'm invoking jetty from, I have the following relevant settings that tell Jetty to use the JNDI and Plus settings xml-s:
<jettyConfig>${project.build.directory}/jetty/etc/jetty-plus.xml,${project.build.directory}/jetty/etc/jetty-jndi.xml</jettyConfig>
In the jetty-plus.xml I have:
<!-- =========================================================== -->
<!-- Sequence of configurations to defining Plus features. -->
<!-- =========================================================== -->
<Array id="plusConfig" type="java.lang.String">
<Item>org.eclipse.jetty.webapp.WebInfConfiguration</Item>
<Item>org.eclipse.jetty.webapp.WebXmlConfiguration</Item>
<Item>org.eclipse.jetty.webapp.MetaInfConfiguration</Item>
<Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item>
<Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item> <!-- Add for JNDI -->
<Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item> <!-- Add for JNDI -->
<Item>org.eclipse.jetty.annotations.AnnotationConfiguration</Item>
<Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item>
<Item>org.eclipse.jetty.webapp.TagLibConfiguration</Item> <!-- Not needed for Jetty-8 -->
</Array>
<!-- =========================================================== -->
<!-- Apply plusConfig to all webapps for this Server -->
<!-- =========================================================== -->
<Call name="setAttribute">
<Arg>org.eclipse.jetty.webapp.configuration</Arg>
<Arg>
<Ref id="plusConfig"/>
</Arg>
</Call>
Any ideas what I might be doing wrong?
Many thanks in advance! :)
This appears to be a bug in Jetty's global JNDI resource configuration.
I have filed a bug in Jetty's bugzilla and will accept this answer as correct, despite the fact it is no solution.

Map external directory to web.xml

Is there an easy way to map a directory in the web.xml or other deployment descriptor (jetty.xml, etc) files?
For example, if I have a directory /opt/files/ is there a way that I can access its files and sub-directories by visiting http://localhost/some-mapping/? It strikes me that there should be some simple way of doing this, but I haven't been able to find out how (via google, stackoverflow, etc). All I've found are servlets that mimic fileservers, which is not what I would like.
For reference I am using jetty on an AIX box.
No idea how to do it with Jetty, but in Tomcat you can just add a new <Context> to server.xml:
<Context docBase="/opt/files" path="/files" />
This way it's accessible by http://example.com/files/.... See if something similar exist for Jetty.
Update: after Googling, the "normal Java code" equivalent would be something like:
WebAppContext files = new WebAppContext("/opt/files", "/files");
Server server = new Server(8080);
server.setHandler(files);
server.start();
Now yet to translate that into jetty.xml flavor. I am a bit guessing based on the documentation and examples found on the web, so don't pin me on it:
<Configure class="org.mortbay.jetty.webapp.WebAppContext">
<Set name="webApp">/opt/files</Set>
<Set name="contextPath">/files</Set>
</Configure>
Another possibility may be this:
<Configure class="org.mortbay.jetty.Server">
<Call name="addHandler">
<Arg>
<New class="org.mortbay.jetty.webapp.WebAppContext">
<Arg name="webApp">/opt/files</Arg>
<Arg name="contextPath">/files</Arg>
</New>
</Arg>
</Call>
</Configure>
After some more fiddling around, the best way to do this (for jetty) is to deploy a descriptor in the context directory that looks like the following...
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<!-- Configuration of a custom context. -->
<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
<Call class="org.eclipse.jetty.util.log.Log" name="debug">
<!-- The default message to show if our context breaks. -->
<Arg>Configure context.xml</Arg>
</Call>
<!--
The context path is the web location of the context in relation to the
server address.
-->
<Set name="contextPath">/context</Set>
<!--
The resource base is the server directory to use for fetching files.
-->
<Set name="resourceBase">/path/to/files/on/server</Set>
<Set name="handler">
<New class="org.eclipse.jetty.server.handler.ResourceHandler">
<Set name="directoriesListed">true</Set>
<!-- For now we don't need any welcome files -->
<!--
<Set name="welcomeFiles"> <Array type="String">
<Item>index.html</Item> </Array> </Set>
-->
<!--
The cache time limit in seconds (ie max-age=3600 means that if the
document is older than 1 hour a fresh copy will be fetched).
-->
<Set name="cacheControl">max-age=3600,public</Set>
</New>
</Set>
</Configure>
I hope that this helps someone else!
I don't know that you can do that as a URL mapping, however files and folders in the same directory that your web.xml file is in will be accessible in the way you describe, although you can't control the mapping under your webapp.
Does that suit your needs?