gcv/appengine-magic

Mail Service throws java.lang.ClassNotFoundException: MailHandlerServlet

Folcon opened this issue · 3 comments

I've setup the mail service as described.

Adding:

  <inbound-services>
    <service>mail</service>
  </inbound-services>

to appengine-web.xml and

<servlet>
        <servlet-name>mailhandler</servlet-name>
        <servlet-class>MailHandlerServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>mailhandler</servlet-name>
        <url-pattern>/_ah/mail/*</url-pattern>
    </servlet-mapping>
    <security-constraint>
        <web-resource-collection>
            <url-pattern>/_ah/mail/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>

to web.xml.

Here is the log message from GAE.

2011-08-01 12:19:37.571
EXCEPTION 
java.lang.ClassNotFoundException: MailHandlerServlet
    at com.google.appengine.runtime.Request.process-74166ddc42b4a59b(Request.java)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
    at org.mortbay.util.Loader.loadClass(Loader.java:91)
    at org.mortbay.util.Loader.loadClass(Loader.java:71)
    at org.mortbay.jetty.servlet.Holder.doStart(Holder.java:73)
    at org.mortbay.jetty.servlet.ServletHolder.doStart(ServletHolder.java:242)
    at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:685)
    at org.mortbay.jetty.servlet.Context.startContext(Context.java:140)
    at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1250)
    at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517)
    at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:467)
    at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    at com.google.net.rpc.impl.RpcUtil.runRpcInApplication(RpcUtil.java:422)
    at com.google.net.rpc.impl.Server$RpcTask.runInContext(Server.java:579)
    at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:449)
    at com.google.tracing.TraceContext.runInContext(TraceContext.java:689)
    at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:327)
    at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:319)
    at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:447)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:636)
E 2011-08-01 12:19:37.572
javax.servlet.ServletContext log: unavailable
javax.servlet.UnavailableException: MailHandlerServlet
    at org.mortbay.jetty.servlet.Holder.doStart(Holder.java:79)
    at org.mortbay.jetty.servlet.ServletHolder.doStart(ServletHolder.java:242)
    at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:685)
    at org.mortbay.jetty.servlet.Context.startContext(Context.java:140)
    at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1250)
    at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517)
    at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:467)
    at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.createHandler(AppVersionHandlerMap.java:202)
    at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.getHandler(AppVersionHandlerMap.java:171)
    at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:123)
    at com.google.apphosting.runtime.JavaRuntime.handleRequest(JavaRuntime.java:260)
    at com.google.apphosting.base.RuntimePb$EvaluationRuntime$2.handleRequest(RuntimePb.java:9805)
    at com.google.net.rpc.impl.RpcUtil.runRpcInApplication(RpcUtil.java:422)
    at com.google.net.rpc.impl.Server$RpcTask.runInContext(Server.java:579)
    at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:449)
    at com.google.tracing.TraceContext.runInContext(TraceContext.java:689)
    at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:327)
    at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:319)
    at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:447)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:636)
W 2011-08-01 12:19:37.580
Failed startup of context com.google.apphosting.utils.jetty.RuntimeAppEngineWebAppContext@5bd978{/,/base/data/home/apps/cashewmanager/1.352248060040957903}
java.lang.NullPointerException
    at java.lang.Class.isAssignableFrom(Native Method)
    at org.mortbay.jetty.servlet.ServletHolder.doStart(ServletHolder.java:256)
    at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:685)
    at org.mortbay.jetty.servlet.Context.startContext(Context.java:140)
    at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1250)
    at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517)
    at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:467)
    at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.createHandler(AppVersionHandlerMap.java:202)
    at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.getHandler(AppVersionHandlerMap.java:171)
    at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:123)
    at com.google.apphosting.runtime.JavaRuntime.handleRequest(JavaRuntime.java:260)
    at com.google.apphosting.base.RuntimePb$EvaluationRuntime$2.handleRequest(RuntimePb.java:9805)
    at com.google.net.rpc.impl.RpcUtil.runRpcInApplication(RpcUtil.java:422)
    at com.google.net.rpc.impl.Server$RpcTask.runInContext(Server.java:579)
    at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:449)
    at com.google.tracing.TraceContext.runInContext(TraceContext.java:689)
    at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:327)
    at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:319)
    at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:447)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:636)
C 2011-08-01 12:19:37.583
Uncaught exception from servlet
javax.servlet.UnavailableException: Initialization failed.
    at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.createHandler(AppVersionHandlerMap.java:211)
    at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.getHandler(AppVersionHandlerMap.java:171)
    at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:123)
    at com.google.apphosting.runtime.JavaRuntime.handleRequest(JavaRuntime.java:260)
    at com.google.apphosting.base.RuntimePb$EvaluationRuntime$2.handleRequest(RuntimePb.java:9805)
    at com.google.net.rpc.impl.RpcUtil.runRpcInApplication(RpcUtil.java:422)
    at com.google.net.rpc.impl.Server$RpcTask.runInContext(Server.java:579)
    at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:449)
    at com.google.tracing.TraceContext.runInContext(TraceContext.java:689)
    at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:327)
    at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:319)
    at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:447)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:636)
I 2011-08-01 12:19:37.586
This request caused a new process to be started for your application, and thus caused your application code to be loaded for the first time. This request may thus take longer and use more CPU than a typical request for your application.

Hope you can help.

Regards,
Folcon

gcv commented

Unless you use gen-class for it, you shouldn't add MailHandlerServlet to web.xml.

I suggest that you add the needed routes to your main application (see the example in the README), and just let the resulting servlet handle it. Basically, just removing the <servlet> and <servlet-mapping> stuff you added to web.xml should fix your problem.

I'm assuming then that I should leave:

    <security-constraint>
        <web-resource-collection>
            <url-pattern>/_ah/mail/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>

in web.xml?

Also with regards to the blob/upload-hack how would I upload file attachments to the blobstore?

I'm currently using:

(map #(blobs/upload-hack {:field "file" :filename (.getFileName %) :bytes (.getBytes %)} "/upload/file") attachments))

where "upload/file" is:

(defn process-files [req]
  (let [blob-map (blobs/uploaded-blobs req)]
    (ds/save! (UploadedFile. (.getKeyString (blob-map "file")) (session-get :user)
                             (str (now)) ""
                             )))
  (blobs/callback-complete req "/upload/file/success"))

Regards,
Folcon

gcv commented

Yes, you should leave the security constraint.

Your code for the upload hack doesn't look quite right. The :field entries should be distinct for each attachment.