Sitebricks and Channel Presence Service (GAE); Als

2019-09-19 00:08发布

问题:

In my Java Google App Engine server application, I would like to enable Channel Presence servlets in order to track connections/disconnections to/from my channels using the Channel API (as described here. I have already edited my WEB-INF/appengine-web.xml file like described.

Most servlets in my application use Sitebricks, instead of classes extending HttpServlet, to provide an easy way for me to create REST endpoints in my app. BUT, it seems like using Sitebricks in my class, like so, does not work because I get WARNING: No file found for: /_ah/channel/connected/ when the URL is hit:

@At("/_ah/channel")
@Service
public class MyChannelPresenceServlet {
    ...
    @Post("/connected")
    public void connectedMethod() {
        ...
    }

    @Post("/disconnected")
    public void disconnectedMethod() {
        ...
    }
    ...
}

Is there any way for me to use Sitebricks at all to provide a REST URL endpoint, for Channel Presence, for /-ah/channel/connected/ and /_ah/channel/disconnected/?

BONUS QUESTION

Let's say that Sitebricks is not the way to go and, instead, I need to stick to normal servlet classes that extends HttpServlet and are configured via WEB-INF/web.xml. This other solution still does not work for me. Let's say that I were to put this into my web.xml file:

<servlet>
    <servlet-name>channel_connect</servlet-name>
    <servlet-class>com.example.PresenceServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>channel_connect</servlet-name>
    <url-pattern>/_ah/channel/connected/</url-pattern>
</servlet-mapping>

In this example, com.example.PresenceServlet is a child of HttpServlet and overrides the doPost(HttpServletRequest, HttpServletResponse) method from the parent. I STILL run into problems:

WARNING: /_ah/channel/connected/
java.lang.InstantiationException: com.ea.pogosocial.rest.ChannelServiceServlet
at java.lang.Class.newInstance0(Class.java:357)
at java.lang.Class.newInstance(Class.java:325)
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.api.socket.dev.DevSocketFilter.doFilter(DevSocketFilter.java:74)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:66)
at com.google.sitebricks.SitebricksFilter.doFilter(SitebricksFilter.java:88)
at com.google.inject.servlet.FilterDefinition.doFilter(FilterDefinition.java:163)
at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:58)
at com.google.sitebricks.HiddenMethodFilter.doFilter(HiddenMethodFilter.java:75)
at com.google.inject.servlet.FilterDefinition.doFilter(FilterDefinition.java:163)
at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:58)
at com.googlecode.objectify.cache.AsyncCacheFilter.doFilter(AsyncCacheFilter.java:59)
at com.googlecode.objectify.ObjectifyFilter.doFilter(ObjectifyFilter.java:49)
at com.google.inject.servlet.FilterDefinition.doFilter(FilterDefinition.java:163)
at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:58)
at com.google.inject.servlet.ManagedFilterPipeline.dispatch(ManagedFilterPipeline.java:118)
at com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:113)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.appstats.AppstatsFilter.doFilter(AppstatsFilter.java:141)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.api.socket.dev.DevSocketFilter.doFilter(DevSocketFilter.java:74)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.ResponseRewriterFilter.doFilter(ResponseRewriterFilter.java:110)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:34)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:61)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:125)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.BackendServersFilter.doFilter(BackendServersFilter.java:97)
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:380)
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.content(HttpConnection.java:938)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:755)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
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)

All help much appreciated. Especially from a Google employee.

(PS: I am using GAE SDK 1.7.2. I am eagerly awaiting the release of 1.7.3)


Update

There was one more experiment I tried. In the <servlet> tag of web.xml for my servlet class, I added this tag in order to force my servlet to be loaded upon server startup (which, by the way, is done using mvn gae:run in my example). Now I get this output

WARNING: /_ah/channel/connected/: javax.servlet.UnavailableException: java.lang.InstantiationException: com.ea.pogosocial.rest.ChannelServiceServlet

回答1:

Hmm that is too bad. It looks as though GAE introspects the servlet chain to try and discover a registered handler for /_ah/channel/*

Disclaimer: I am the creator of both Sitebricks and Guice Servlet so I find this rather frustrating. The one time I did implement a channel setup in GAE I managed to do it using the Channel API directly: https://github.com/dhanji/crosstalk/blob/master/src/main/java/com/wideplay/crosstalk/web/RoomPage.java



回答2:

If anyone still cares...

Problem was that I could use neither Sitebricks nor Guice Injection for a Servlet that handles POST requests to Channel Presence Service URIs. Once I removed both, the servlet worked like a charm.