I have a dilemma in my GAE Java app: I am trying to write a servlet that will be handled by GAE backends and it must also use Guice dependency injection to initiate all the servlet's fields. I have tried multiple approaches but none seems to be doing the trick for me.
I first tried to use Sitebricks in the servlet, but it seemed that doing so results in GAE being unable to detect the class as a legit servlet when the backend URL is being queried: a 404 Not Found is always returned from the backend. Despite this, I know for sure that the class is annotated correctly with Sitebricks annotations because the same URI path works fine with the frontend instance.
Next, I tried to use Guice Servlet Extension (see this link); in my class that creates the global Injector
, I used this binding:
return Guice.createInjector(..., new ServletModule() {
@Override
protected void configureServlets() {
serve("/backend/*").with(MyBackend.class);
}
}, ...);
Unfortunately, the same exact issue as with Sitebricks happens: I am returned a 404 error on the backend but not on the frontend.
The last feasible approach would be to configure the servlet-mapping in web.xml
; the traditional approach. This finally allows my backend to detect the URI mapping (which follows along with what is writen in Google's documentation of Java GAE backends: "Backends share the servlets defined in web.xml with the main application version."). Unfortunately, I would not be able to take advantage of Guice injection using this procedure and hence it is extremely undesirable for me to use web.xml
.
I even tried combining the second and third approach: use both the Guice Servlet Extension and web.xml. This resuled in a 500 error being returned from the backend with this error:
java.lang.InstantiationException: com.example.MyBackend
at java.lang.Class.newInstance0(Class.java:340)
at java.lang.Class.newInstance(Class.java:308)
at org.mortbay.jetty.servlet.Holder.newInstance(Holder.java:153)
at org.mortbay.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:428)
at org.mortbay.jetty.servlet.ServletHolder.getServlet(ServletHolder.java:339)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
at com.google.appengine.tools.development.BackendServersFilter.doRedirectedServerRequest(BackendServersFilter.java:292)
at com.google.appengine.tools.development.BackendServersFilter.doFilter(BackendServersFilter.java:106)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:94)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:327)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:126)
at com.google.appengine.tools.development.BackendServers.forwardToServer(BackendServers.java:56)
at com.google.appengine.tools.development.BackendServersFilter.doServerRedirect(BackendServersFilter.java:237)
at com.google.appengine.tools.development.BackendServersFilter.doFilter(BackendServersFilter.java:100)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:94)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:383)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:547)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
20-Dec-2012 3:23:53 AM com.google.apphosting.utils.jetty.JettyLogger warn
WARNING: /backend/example/rest/call
java.lang.InstantiationException: com.example.MyBackend
at java.lang.Class.newInstance0(Class.java:340)
at java.lang.Class.newInstance(Class.java:308)
at org.mortbay.jetty.servlet.Holder.newInstance(Holder.java:153)
at org.mortbay.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:428)
at org.mortbay.jetty.servlet.ServletHolder.getServlet(ServletHolder.java:339)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
at com.google.appengine.tools.development.BackendServersFilter.doRedirectedServerRequest(BackendServersFilter.java:292)
at com.google.appengine.tools.development.BackendServersFilter.doFilter(BackendServersFilter.java:106)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:94)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:327)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:126)
at com.google.appengine.tools.development.BackendServers.forwardToServer(BackendServers.java:56)
at com.google.appengine.tools.development.BackendServersFilter.doServerRedirect(BackendServersFilter.java:237)
at com.google.appengine.tools.development.BackendServersFilter.doFilter(BackendServersFilter.java:100)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:94)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:383)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:547)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
One final thing to note: I configured my backends.xml file to have <public>true</public>
, but I am testing these HTTP request calls by querying the backend from the frontend of my GAE app. Also, note that my frontend instance is properly retrieving the backend address using BackendService
(javadoc here).