I am using jetty v9.2.10.v20150310 with java version "1.8.0_45" on a linux box with a 3.18.9 kernel.
The problem is that if I set the context path to a non root value; i.e., /embed I can access my web page on my embedded jetty server. However if I set the context path to root; i.e., "/" I cannot access the page. Interestingly this problem does not show up when I interact with the servlet via curl.
Here is the code:
final ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
final String servletWebDir = "/";
servletHandler.setContextPath( servletWebDir );
final customServlet iass = new customServlet();
final ServletHolder servletHolder = new ServletHolder( iass );
servletHolder.setInitOrder(0);
servletHandler.addServlet( servletHolder, "/customServlet" );
final ResourceHandler resourceHandler = new ResourceHandler();
resourceHandler.setDirectoriesListed(false);
resourceHandler.setResourceBase(".");
final HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[]{ servletHandler, resourceHandler } );
server.setHandler( handlers );
If I change servletWebDir from "/" to "/embed" everything works as it should. If not I get a 404.
I can interact successfully with the servlet via curl commands a follows:
If I attempt to use http://host:8080/customServlet in either firefox or chrome with servletWebDir set to "/" I get a 404. Note that this code works fine under jetty v8.1.16.v20140903.
What am I doing wrong? What have I missed in Jetty v9.x?
Updated code that uses setBaseResource and drops the ResourceHandler:
final ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
final String servletWebDir = "/";
final String theBaseResourceDir = "/aa/bb/cc";
Resource theBaseResource = null;
try{
theBaseResource = Resource.newResource( theBaseResourceDir );
}
catch( MalformedURLException e ){
System.err.println( "setup failed on newResource with the exception " + e.toString() );
System.exit(0);
}
servletHandler.setBaseResource( theBaseResource );
System.err.println("Class path->" + servletHandler.getClassPath() );
final customServlet iass = new customServlet();
final ServletHolder servletHolder = new ServletHolder( iass );
servletHolder.setInitOrder(0);
servletHandler.addServlet( servletHolder, "/customServlet" );
final HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[]{ servletHandler } );
server.setHandler( handlers );
This new code no longer serves a static page to a web browser regardless of the value of servletWebDir. Interacting with the custom servlet via curl still works. If the above new code is correct have I missed something? The class path is reported as null in the error logs. What can I try next?
Joakim:
I tried the code you suggested. I really appreciate the time and effort you took to prepare the code sample. However the code fails at run time. The error log states:
STDERR: 2015-05-09 15:51:32.278:WARN:/embed:main: unavailable java.lang.IllegalAccessException: Class org.eclipse.jetty.server.handler.ContextHandler$Context can not access a member of class customServlet with modifiers "private" at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
The exception does not identify the exact member that should be made public. My updated code does work and I do not have to change a whole bunch of methods from private to public.
Joakim could you please explain the benefits of your solution which, if I am not mistaken, requires changing private methods and data members to public data members and methods and therefore losing some of the benefits of encapsulation.
Updated Code that fixes this problem:
server = new Server();
final ServerConnector connector = getConnector( server );
connector.setReuseAddress(false);
connector.setSoLingerTime(0);
final int port = 8080;
connector.setHost( theHostName );
connector.setPort( port );
server.addConnector(connector);
final String theRootContextDir = "/";
final ContextHandler rootContext = new ContextHandler(theRootContextDir);
final String theBaseResourceDir = ".";
rootContext.setResourceBase( theBaseResourceDir );
final ResourceHandler rhx = new ResourceHandler();
rootContext.setHandler( rhx );
/**
* I want to replace the default jetty error handler with my
* custom error handler. However I have not figured out how
* to do it under jetty v9.x, yet-(May.08.2015,W.S.)
* final ErrorHandler uiErrHandler = new userInputErrorHandler( logger );
* rootContext.setErrorHandler( uiErrHandler );
***/
final ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
final String theServletContextPath = "/";
servletHandler.setContextPath( theServletContextPath );
servletHandler.setResourceBase( "." );
final customServlet iass = new customServlet();
final ServletHolder servletHolder = new ServletHolder( iass );
final MultipartConfigElement mce = new MultipartConfigElement( fileUploadTmpDir );
servletHolder.getRegistration().setMultipartConfig( mce );
servletHolder.setInitOrder(0);
final String theServletName = "/customServlet";
servletHandler.addServlet( servletHolder, theServletName );
final HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[]{ rootContext, servletHandler } );
server.setHandler( handlers );