GoogleCloudPlatform / gradle-appengine-templates

Freemarker based templates that build with the gradle-appengine-plugin
438 stars 205 forks source link

Error Code: 503 [java.lang.IllegalStateException: You have not started an Objectify context. You are probably missing the ObjectifyFilter. If you are not running in the context of an http request, see the ObjectifyService.run() method.] #73

Open hardyt opened 8 years ago

hardyt commented 8 years ago

After copying all the file contents into my existing backend I receive this error when trying to send a message:

Error Code: 503 [java.lang.IllegalStateException: You have not started an Objectify context. You are probably missing the ObjectifyFilter. If you are not running in the context of an http request, see the ObjectifyService.run() method.]

I have the following in my web.xml:

<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
    <filter>
        <filter-name>ObjectifyFilter</filter-name>
        <filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>ObjectifyFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <servlet>
        <servlet-name>SystemServiceServlet</servlet-name>
        <servlet-class>com.google.api.server.spi.SystemServiceServlet</servlet-class>
        <init-param>
            <param-name>services</param-name>
            <param-value>com.atrware.gcphealthcare.backend.RegistrationEndpoint, com.atrware.gcphealthcare.backend.MessagingEndpoint</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>SystemServiceServlet</servlet-name>
        <url-pattern>/_ah/spi/*</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>com.atrware.gcphealthcare.backend.MyServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

What could be the issue?

patflynn commented 8 years ago

Hey there,

are you using Android Studio to generate this backend? What does your backend build.gradle look like?

On Tue, Apr 19, 2016 at 5:22 PM, Tom notifications@github.com wrote:

After copying all the file contents into my existing backend I receive this error when trying to send a message:

Error Code: 503 [java.lang.IllegalStateException: You have not started an Objectify context. You are probably missing the ObjectifyFilter. If you are not running in the context of an http request, see the ObjectifyService.run() method.]

I have the following in my web.xml:

<?xml version="1.0" encoding="utf-8"?>

ObjectifyFilter com.googlecode.objectify.ObjectifyFilter ObjectifyFilter /_ SystemServiceServlet com.google.api.server.spi.SystemServiceServlet services com.atrware.gcphealthcare.backend.RegistrationEndpoint, com.atrware.gcphealthcare.backend.MessagingEndpoint SystemServiceServlet /_ah/spi/_ MyServlet com.atrware.gcphealthcare.backend.MyServlet MyServlet /hello ``` index.html ```

What could be the issue?

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub https://github.com/GoogleCloudPlatform/gradle-appengine-templates/issues/73

hardyt commented 8 years ago

Wow, thanks for the super quick response! Yes, I used Android Studio 2.0 to generate the backend using a slightly different GCM tutorial. I can't find the link at the moment, but it implemented GcmSender.java.

backend build.gradle:

// If you would like more information on the gradle-appengine-plugin please refer to the github page
// https://github.com/GoogleCloudPlatform/gradle-appengine-plugin

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.google.appengine:gradle-appengine-plugin:1.9.28'
    }
}

repositories {
    jcenter();
}

apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'appengine'
apply plugin: 'application'

mainClassName = "com.atrware.gcphealthcare.backend.GcmSender"

sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7

//sourceCompatibility = JavaVersion.VERSION_1_8
//targetCompatibility = JavaVersion.VERSION_1_8

run {
    def params = []
    if (project.hasProperty('msg')) {
        params.add(project.msg)
        if (project.hasProperty('to')) {
            params.add(project.to)
        }
    }
    args params
}

dependencies {
    appengineSdk 'com.google.appengine:appengine-java-sdk:1.9.28'
    compile 'javax.servlet:servlet-api:2.5'
    compile 'com.firebase:firebase-client-jvm:2.5.2'
    compile 'org.apache.httpcomponents:httpclient:4.5.2'
    compile 'com.google.appengine:appengine-api-1.0-sdk:1.9.34'
    compile 'com.google.appengine:appengine-endpoints:1.9.34'
    compile 'com.google.appengine:appengine-endpoints-deps:1.9.34'
    compile 'org.apache.commons:commons-io:1.3.2'
    compile 'com.googlecode.objectify:objectify:5.1.12'
    compile 'com.ganyo:gcm-server:1.0.2'
    compile 'org.json:json:20140107'
}

appengine {
  downloadSdk = true
  appcfg {
    oauth2 = true
  }
    endpoints {
        getClientLibsOnBuild = true
        getDiscoveryDocsOnBuild = true
    }
}
patflynn commented 8 years ago

Hi Tom,

I think there's a chance you're making an Objectify call outside of the scope of a servlet request.

Without the full code it's hard for me to say. I'd need a link to the tutorial you followed to say for sure.

On Tue, Apr 19, 2016 at 5:34 PM, Tom notifications@github.com wrote:

Wow, thanks for the super quick response! Yes, I used Android Studio 2.0 to generate the backend using a slightly different GCM tutorial. I can't find the link at the moment, but it implemented GcmSender.java.

backend build.gradle:

// If you would like more information on the gradle-appengine-plugin please refer to the github page // https://github.com/GoogleCloudPlatform/gradle-appengine-plugin

buildscript { repositories { jcenter() } dependencies { classpath 'com.google.appengine:gradle-appengine-plugin:1.9.28' } }

repositories { jcenter(); }

apply plugin: 'java' apply plugin: 'war' apply plugin: 'appengine' apply plugin: 'application'

mainClassName = "com.atrware.gcphealthcare.backend.GcmSender"

sourceCompatibility = JavaVersion.VERSION_1_7 targetCompatibility = JavaVersion.VERSION_1_7

//sourceCompatibility = JavaVersion.VERSION_1_8 //targetCompatibility = JavaVersion.VERSION_1_8

run { def params = [] if (project.hasProperty('msg')) { params.add(project.msg) if (project.hasProperty('to')) { params.add(project.to) } } args params }

dependencies { appengineSdk 'com.google.appengine:appengine-java-sdk:1.9.28' compile 'javax.servlet:servlet-api:2.5' compile 'com.firebase:firebase-client-jvm:2.5.2' compile 'org.apache.httpcomponents:httpclient:4.5.2' compile 'com.google.appengine:appengine-api-1.0-sdk:1.9.34' compile 'com.google.appengine:appengine-endpoints:1.9.34' compile 'com.google.appengine:appengine-endpoints-deps:1.9.34' compile 'org.apache.commons:commons-io:1.3.2' compile 'com.googlecode.objectify:objectify:5.1.12' compile 'com.ganyo:gcm-server:1.0.2' compile 'org.json:json:20140107' }

appengine { downloadSdk = true appcfg { oauth2 = true } endpoints { getClientLibsOnBuild = true getDiscoveryDocsOnBuild = true } }

— You are receiving this because you commented. Reply to this email directly or view it on GitHub https://github.com/GoogleCloudPlatform/gradle-appengine-templates/issues/73#issuecomment-212139361

hardyt commented 8 years ago

I found the code that breaks it. It's inside appengine-web.xml. The Google/Android/Appengine/Firebase tutorial specifies manual scaling. This breaks this tutorial. Any idea on how to work around this?

<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <application>atrware</application>
    <version>1</version>
    <threadsafe>true</threadsafe>
    <manual-scaling> <------------------- This element breaks this GCM tutorial/template
        <instances>1</instances>
    </manual-scaling>
    <system-properties>
        <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
        <property name="gcm.api.key" value="AIzaSyD6rHzF0MvHWiU47RLLbupQDEal4y3mUbM"/>
    </system-properties>
</appengine-web-app>

"To use Firebase with App Engine, you must use manual scaling. This is because Firebase uses background threads to listen for changes and App Engine only allows long-lived background threads on manually scaled backend instances."

So this means I can only use Firebase or GCM? Not both?

The full code is here, but all the pertinent files are the same as this tutorial with the exception of adding my app's information (name/api key).

hardyt commented 8 years ago

Another note: When that element is removed, I get a success message on the local instance and am able to receive a push notification on the Android emulator client. When the app is deployed, I don't see any result - no success and no error- if that element is included or removed. No notification is sent to the client. The client does say it has sent the token to the server.

I see this in Chrome's console:

cb=gapi.loaded_0:160 GET https://www.atrware.com/_ah/api/static/proxy.html?jsh=m%3B%2F_%2Fscs%2Fapps…res__%2Fam%3DAQ%2Frt%3Dj%2Fd%3D1%2Frs%3DAGLTcCMCp0KeucYH1ftSCLjBQaTZ3eOfcA net::ERR_CONNECTION_CLOSED

The Appengine log only shows a successful GET:

23:11:01.730 GET 200 0 B 2 ms Chrome 49 /?
 ipaddress - - [19/Apr/2016:23:11:01 -0600] "GET /? HTTP/1.1" 200 - http://www.atrware.com/? "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36" "www.atrware.com" ms=2 cpu_ms=0 cpm_usd=0 instance=- app_engine_release=1.9.36 trace_id=284b75fa284b9a9a25c28b1aeccf5b0b

Update: Removing the manual scaling, I can run it fine from http://atrware.appspot.com/, but not from http://www.atrware.com/ (getting that ERR_CONNECTION_CLOSED). What should I change to run it from my domain?

patflynn commented 8 years ago

You should be able to use Firebase and GCM. Your problem is actually around setting up the Objectify context. The Objectify filter does so automatically for all servlet request threads, but if you're trying to use Objectify from a background thread you'll need to set it up manually.

It's not my area of expertise but looking at what the filter actually does: https://github.com/objectify/objectify/blob/master/src/main/java/com/googlecode/objectify/ObjectifyFilter.java, it looks like you may be able to simply use a try with resources block around your objectify operations like this: try (Closeable closeable = ObjectifyService.begin()) { // do your objectify read and writes here }

On Wed, Apr 20, 2016 at 1:13 AM, Tom notifications@github.com wrote:

Another note: When that element is removed, I get a success message on the local instance. When the app is deployed, I don't see any result - no success and no error. The Appengine log only shows a successful GET:

23:11:01.730 GET 200 0 B 2 ms Chrome 49 /? ipaddress - - [19/Apr/2016:23:11:01 -0600] "GET /? HTTP/1.1" 200 - http://www.atrware.com/? "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36" "www.atrware.com" ms=2 cpu_ms=0 cpm_usd=0 instance=- app_engine_release=1.9.36 trace_id=284b75fa284b9a9a25c28b1aeccf5b0b

— You are receiving this because you commented. Reply to this email directly or view it on GitHub https://github.com/GoogleCloudPlatform/gradle-appengine-templates/issues/73#issuecomment-212259777

hardyt commented 8 years ago

Pat, thanks for your quick answers. It's too bad there is no clear resolution to this.

I think there are multiple "gotchas" I'm running into. In addition to the possible ObjectifyFilter modification, at least one other "gotcha" is that Google Cloud Endpoints doesn't work on custom domains. That should be a note/requirement in the README for this tutorial

As for a way forward to close this out, Firebase was important, but not critical to my backend. I'll explore more in a few weeks since there is no clear resolution and I have lots of other work to finish before the end of the semester. I can't spend hours troubleshooting what should be a one line requirement either here, in notes for Objectify, or in notes for GCM.

patflynn commented 8 years ago

Sorry we couldn't more helpful. I am actually not very well versed in using GCM. This project is owned by the Android Studio cloud plugin team so our focus is on the IDE integration. You may want to try using the GCM stackoverflow tag http://stackoverflow.com/questions/tagged/google-cloud-messaging to ask your question. You may find someone there who might be able to help you.

On Wed, Apr 20, 2016 at 1:59 PM, Tom notifications@github.com wrote:

Pat, thanks for your quick answers. It's too bad there is no clear resolution to this.

I think there are multiple "gotchas" I'm running into. In addition to the possible ObjectifyFilter modification, at least one other "gotcha" is that GCM doesn't work on custom domains. That should be a note/requirement in the README for this tutorial

As for a way forward to close this out, Firebase was important, but not critical to my backend. I'll explore more in a few weeks since there is no clear resolution and I have lots of other work to finish before the end of the semester. I can't spend hours troubleshooting what should be a one line requirement either here, in notes for Objectify, or in notes for GCM.

— You are receiving this because you commented. Reply to this email directly or view it on GitHub https://github.com/GoogleCloudPlatform/gradle-appengine-templates/issues/73#issuecomment-212536173

tsanidas commented 8 years ago

Leaving this here for posterity... It seems that only when using basic-scaling or manual-scaling that GAE uses a RequestDispatcher.forward() to route this to your backend module. This means that we can tell the Objectify filter to honor that by making your web.xml entry look like this:

    <filter>
        <filter-name>ObjectifyFilter</filter-name>
        <filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>ObjectifyFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <!-- Next three lines are for request dispatcher actions -->
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>

Good luck!

stsandro commented 7 years ago

`REQUEST

INCLUDE FORWARD` Had the same problem. Those three lines somehow magically solved it.