Google Application Engine Google App Engine GAE !Compatible Spring EntityManager Injector [Google Application Engine/PersistenceAnnotationBeanPostProcessor.java] {{{ <bean class="com.intersult.jsf2.PersistenceAnnotationBeanPostProcessor"/> }}} !Test für lokalen Datastore {{{ public class ObjectifyTest { private static LocalServiceTestHelper helper; @BeforeClass public static void setupClass() { LocalDatastoreServiceTestConfig config = new LocalDatastoreServiceTestConfig(); helper = new LocalServiceTestHelper(config); ObjectifyService.register(User.class); } @Before public void setUp() { helper.setUp(); } @After public void tearDown() { helper.tearDown(); } @Test public void test() { Objectify objectify = ObjectifyService.begin(); User user = objectify.find(User.class, 1); } }}} !Eclipse GAE Plugin mit Maven # GAE Plugin in Eclipse installieren # GAE Runtime Installieren # GAE Runtime in Preferences -> Google -> App Engine eintragen # Im importierten Maven Projekt GAE Support anschalten ## WAR-Dir ist src/main/webapp ## Class Output Folder ist target/classes ## App Engine ist die installierte GAE, nicht die Maven Library # In Preferences -> Build Path -> Order and Export die Maven Dependencies ganz nach unten. (Sonst versucht das GAE Plugin die Maven GAE-Runtime JAR als Runtime Home zu benutzen.) # Als Faceted Projekt konfigurieren, damit XHTML-Editor konfiguriert wird ## Dynamic Web Project 2.5, keine web.xml generieren ## Gegebenenfalls JSF 2.0, keine Library-Konfiguration # Im Deployment-Assembly Maven-Dependencies hinzufügen. Falls Projekte im Workspace referenziert sind, diese extra nochmal zufügen (damit JARs gebaut werden) Um die Libs zur Verfügung zu stellen, wird das maven-war-plugin auf exploded umgestellt: {{{ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.1.1</version> <configuration> <webResources> <resource> <directory>src/main/webapp</directory> <filtering>true</filtering> <includes> <include>**/appengine-web.xml</include> </includes> </resource> </webResources> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>exploded</goal> </goals> </execution> </executions> </plugin> }}} !EL-Expressions 2, 2.2 Die Glassfish el-impl 2.2 arbeitet leider nicht mit der GAE zusammen, dort ist JBoss zu verwenden. Die Version 2.* führt zu Access Violations in der GAE, daher 1.* verwenden: {{{ <dependency> <groupId>javax.el</groupId> <artifactId>el-api</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>org.jboss.el</groupId> <artifactId>jboss-el</artifactId> <version>1.0_02.CR6</version> </dependency> <repository> <id>jboss</id> <name>Jboss Maven Repository</name> <url>https://repository.jboss.org/nexus/content/repositories/releases</url> </repository> }}} In der web.xml: {{{ <context-param> <param-name>com.sun.faces.expressionFactory</param-name> <param-value>org.jboss.el.ExpressionFactoryImpl</param-value> </context-param> }}} !Proxy Das Maven-Plugin arbeitet mit dem für Maven konfigurierten Proxy. Die GAE-Runtime prüft im Netzwerk auf Update. Beim Starten aus Maven oder Eclipse, ist das Proxy in die Launch-Config einzutragen: {{{ -DproxyHost=<host> -DproxyPort=<port> }}} oder in Maven {{{ <plugin> <groupId>net.kindleit</groupId> <artifactId>maven-gae-plugin</artifactId> <version>0.9.2</version> <dependencies> <dependency> <groupId>net.kindleit</groupId> <artifactId>gae-runtime</artifactId> <version>${version.gae}</version> <type>pom</type> </dependency> </dependencies> <configuration> <proxy>host:port</proxy> </configuration> </plugin> }}} !SDK Fehler bei Starten aus Eclipse {{{ Exception in thread "main" java.lang.ExceptionInInitializerError at com.google.appengine.tools.util.Logging.initializeLogging(Logging.java:35) at com.google.appengine.tools.development.DevAppServerMain.main(DevAppServerMain.java:82) Caused by: java.lang.RuntimeException: Unable to discover the Google App Engine SDK root. This code should be loaded from the SDK directory, but was instead loaded from file:/C:/Users/<profile>/.m2/repository/com/google/appengine/appengine-tools-sdk/1.6.0/appengine-tools-sdk-1.6.0.jar. Specify -Dappengine.sdk.root to override the SDK location. at com.google.appengine.tools.info.SdkInfo.findSdkRoot(SdkInfo.java:102) at com.google.appengine.tools.info.SdkInfo.init(SdkInfo.java:194) at com.google.appengine.tools.info.SdkInfo.getSdkRoot(SdkInfo.java:149) at com.google.appengine.tools.info.SdkImplInfo.<clinit>(SdkImplInfo.java:19) ... 2 more }}} Lösung: Es befindet sich ein Projekt im Deployment-Assembly mit einer Abhängigkeit zur Google-Engine. Entweder das Projekt herausnehmen oder die Abhängigkeit ändern, sodass sie nicht im Deployment-Assembly erscheint. !SAX-Parser Probleme Der SAX-Parser aus dem JDK kann auf der GAE nicht benutzt werden: {{{ javax.xml.parsers.FactoryConfigurationError: Provider org.apache.xerces.jaxp.SAXParserFactoryImpl not found at javax.xml.parsers.SAXParserFactory.newInstance(SAXParserFactory.java:134) at org.mortbay.xml.XmlParser.setValidating(XmlParser.java:91) at org.mortbay.xml.XmlParser.<init>(XmlParser.java:83) at org.mortbay.jetty.webapp.TagLibConfiguration.configureWebApp(TagLibConfiguration.java:210) at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1247) 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 org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130) at org.mortbay.jetty.Server.doStart(Server.java:224) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at com.google.appengine.tools.development.JettyContainerService.startContainer(JettyContainerService.java:191) at com.google.appengine.tools.development.AbstractContainerService.startup(AbstractContainerService.java:239) at com.google.appengine.tools.development.DevAppServerImpl.start(DevAppServerImpl.java:146) at com.google.appengine.tools.development.DevAppServerMain$StartAction.apply(DevAppServerMain.java:164) at com.google.appengine.tools.util.Parser$ParseResult.applyArgs(Parser.java:48) at com.google.appengine.tools.development.DevAppServerMain.<init>(DevAppServerMain.java:113) at com.google.appengine.tools.development.DevAppServerMain.main(DevAppServerMain.java:89) 06.12.2011 10:22:26 com.google.apphosting.utils.jetty.JettyLogger warn WARNUNG: Nested in javax.xml.parsers.FactoryConfigurationError: Provider org.apache.xerces.jaxp.SAXParserFactoryImpl not found: java.lang.ClassNotFoundException: org.apache.xerces.jaxp.SAXParserFactoryImpl at java.net.URLClassLoader$1.run(URLClassLoader.java:202) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at com.google.appengine.tools.development.IsolatedAppClassLoader.loadClass(IsolatedAppClassLoader.java:176) at java.lang.ClassLoader.loadClass(ClassLoader.java:247) at javax.xml.parsers.FactoryFinder.getProviderClass(FactoryFinder.java:111) at javax.xml.parsers.FactoryFinder.newInstance(FactoryFinder.java:146) at javax.xml.parsers.FactoryFinder.findJarServiceProvider(FactoryFinder.java:298) at javax.xml.parsers.FactoryFinder.find(FactoryFinder.java:223) at javax.xml.parsers.SAXParserFactory.newInstance(SAXParserFactory.java:128) at org.mortbay.xml.XmlParser.setValidating(XmlParser.java:91) at org.mortbay.xml.XmlParser.<init>(XmlParser.java:83) at org.mortbay.jetty.webapp.TagLibConfiguration.configureWebApp(TagLibConfiguration.java:210) at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1247) 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 org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130) at org.mortbay.jetty.Server.doStart(Server.java:224) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at com.google.appengine.tools.development.JettyContainerService.startContainer(JettyContainerService.java:191) at com.google.appengine.tools.development.AbstractContainerService.startup(AbstractContainerService.java:239) at com.google.appengine.tools.development.DevAppServerImpl.start(DevAppServerImpl.java:146) at com.google.appengine.tools.development.DevAppServerMain$StartAction.apply(DevAppServerMain.java:164) at com.google.appengine.tools.util.Parser$ParseResult.applyArgs(Parser.java:48) at com.google.appengine.tools.development.DevAppServerMain.<init>(DevAppServerMain.java:113) at com.google.appengine.tools.development.DevAppServerMain.main(DevAppServerMain.java:89) }}} Ursache: JARs nicht deployed Lösung: Die Bibliotheken deployen * Faceted Project * Dynamic Web Application * Im Deployment Assembly "Java Build Path Entry" hinzufügen, Maven Dependencies auswählen * Folgende Dependencies einfügen: {{{ <dependency> <groupId>xalan</groupId> <artifactId>serializer</artifactId> <version>2.7.1</version> </dependency> <dependency> <groupId>xalan</groupId> <artifactId>xalan</artifactId> <version>2.7.1</version> </dependency> <dependency> <groupId>xerces</groupId> <artifactId>xercesImpl</artifactId> <version>2.9.1</version> </dependency> <dependency> <groupId>xml-apis</groupId> <artifactId>xml-apis</artifactId> <version>1.3.04</version> </dependency> }}} !Class-Cast-Problem bei ApiProxyLocal {{{ WARNUNG: failed _ah_ServeBlobFilter: java.lang.ClassCastException: com.google.appengine.tools.development.ApiProxyLocalImpl cannot be cast to com.google.appengine.tools.development.ApiProxyLocal 06.12.2011 10:27:26 com.google.apphosting.utils.jetty.JettyLogger warn WARNUNG: Failed startup of context com.google.appengine.tools.development.DevAppEngineWebAppContext@b05eb6f{/,C:\Java\workspace\com.intersult\internal\subflow\subflow-war\target\subflow} java.lang.ClassCastException: com.google.appengine.tools.development.ApiProxyLocalImpl cannot be cast to com.google.appengine.tools.development.ApiProxyLocal at com.google.appengine.api.blobstore.dev.ServeBlobFilter.init(ServeBlobFilter.java:53) at org.mortbay.jetty.servlet.FilterHolder.doStart(FilterHolder.java:97) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:662) 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 org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130) at org.mortbay.jetty.Server.doStart(Server.java:224) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at com.google.appengine.tools.development.JettyContainerService.startContainer(JettyContainerService.java:191) at com.google.appengine.tools.development.AbstractContainerService.startup(AbstractContainerService.java:239) at com.google.appengine.tools.development.DevAppServerImpl.start(DevAppServerImpl.java:146) at com.google.appengine.tools.development.DevAppServerMain$StartAction.apply(DevAppServerMain.java:164) at com.google.appengine.tools.util.Parser$ParseResult.applyArgs(Parser.java:48) at com.google.appengine.tools.development.DevAppServerMain.<init>(DevAppServerMain.java:113) at com.google.appengine.tools.development.DevAppServerMain.main(DevAppServerMain.java:89) }}} Ursache: Die Test-JARs appengine-testing, appengine-api-labs, appengine-api-stubs befinden sich im Classpath. Lösung: Entfernen der Dependencies aus dem Classpath. !SDK Utils Die SDK-Utils enthalten die Kommandozeilen-Utils für die Arbeit mit der GAE. Das Deployment eines WAR-Verzeichnis erfolgt durch: {{{ appcfg update <exploded war dir> }}} Voraussetzung zum Uploaden, ist eine vorhandene Application mit eigener App-Id. Diese App-Id ist in der WEB-INF/appengine-web.xml einzutragen, unter appengine-web-app/application. Es ist möglich --proxy=<host>[:<port>] mit anzugeben.