]> source.dussan.org Git - vaadin-framework.git/commitdiff
Remove Google App Engine support, tests and documentation (#8034)
authorPekka Hyvönen <pekka@vaadin.com>
Tue, 20 Dec 2016 12:36:53 +0000 (14:36 +0200)
committerGitHub <noreply@github.com>
Tue, 20 Dec 2016 12:36:53 +0000 (14:36 +0200)
* Remove Google App Engine support and tests

Fixes #8033

12 files changed:
compatibility-server/pom.xml
compatibility-server/src/main/java/com/vaadin/server/GAEVaadinServlet.java [new file with mode: 0644]
compatibility-server/src/main/java/com/vaadin/v7/data/util/MethodProperty.java
compatibility-server/src/main/java/com/vaadin/v7/data/util/MethodPropertyDescriptor.java
compatibility-server/src/main/java/com/vaadin/v7/util/SerializerHelper.java [new file with mode: 0644]
server/pom.xml
server/src/main/java/com/vaadin/server/GAEVaadinServlet.java [deleted file]
server/src/main/java/com/vaadin/server/VaadinServlet.java
server/src/main/java/com/vaadin/util/SerializerHelper.java [deleted file]
uitest/ivy.xml
uitest/pom.xml
uitest/src/main/java/com/vaadin/tests/appengine/GAESyncTest.java [deleted file]

index 0dc0432c56236eea3af015f3382376fd285e29b5..6902c525365eb7a2497ec9af7da893f1743c2cfe 100644 (file)
             <scope>provided</scope>
             <optional>true</optional>
         </dependency>
+
+        <!-- Google App Engine -->
+        <dependency>
+            <groupId>com.google.appengine</groupId>
+            <artifactId>appengine-api-1.0-sdk</artifactId>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/compatibility-server/src/main/java/com/vaadin/server/GAEVaadinServlet.java b/compatibility-server/src/main/java/com/vaadin/server/GAEVaadinServlet.java
new file mode 100644 (file)
index 0000000..edf9f24
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.server;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import com.google.appengine.api.datastore.Blob;
+import com.google.appengine.api.datastore.DatastoreService;
+import com.google.appengine.api.datastore.DatastoreServiceFactory;
+import com.google.appengine.api.datastore.Entity;
+import com.google.appengine.api.datastore.EntityNotFoundException;
+import com.google.appengine.api.datastore.FetchOptions.Builder;
+import com.google.appengine.api.datastore.Key;
+import com.google.appengine.api.datastore.KeyFactory;
+import com.google.appengine.api.datastore.PreparedQuery;
+import com.google.appengine.api.datastore.Query;
+import com.google.appengine.api.datastore.Query.FilterOperator;
+import com.google.appengine.api.memcache.Expiration;
+import com.google.appengine.api.memcache.MemcacheService;
+import com.google.appengine.api.memcache.MemcacheServiceFactory;
+import com.google.apphosting.api.DeadlineExceededException;
+
+/**
+ * ApplicationServlet to be used when deploying to Google App Engine, in
+ * web.xml:
+ *
+ * <pre>
+ *      &lt;servlet&gt;
+ *              &lt;servlet-name&gt;HelloWorld&lt;/servlet-name&gt;
+ *              &lt;servlet-class&gt;com.vaadin.server.GAEApplicationServlet&lt;/servlet-class&gt;
+ *              &lt;init-param&gt;
+ *                      &lt;param-name&gt;UI&lt;/param-name&gt;
+ *                      &lt;param-value&gt;com.vaadin.demo.HelloWorld&lt;/param-value&gt;
+ *              &lt;/init-param&gt;
+ *      &lt;/servlet&gt;
+ * </pre>
+ *
+ * Session support must be enabled in appengine-web.xml:
+ *
+ * <pre>
+ *      &lt;sessions-enabled&gt;true&lt;/sessions-enabled&gt;
+ * </pre>
+ *
+ * Appengine datastore cleanup can be invoked by calling one of the applications
+ * with an additional path "/CLEAN". This can be set up as a cron-job in
+ * cron.xml (see appengine documentation for more information):
+ *
+ * <pre>
+ * &lt;cronentries&gt;
+ *   &lt;cron&gt;
+ *     &lt;url&gt;/HelloWorld/CLEAN&lt;/url&gt;
+ *     &lt;description&gt;Clean up sessions&lt;/description&gt;
+ *     &lt;schedule&gt;every 2 hours&lt;/schedule&gt;
+ *   &lt;/cron&gt;
+ * &lt;/cronentries&gt;
+ * </pre>
+ *
+ * It is recommended (but not mandatory) to extract themes and widgetsets and
+ * have App Engine server these statically. Extract VAADIN folder (and it's
+ * contents) 'next to' the WEB-INF folder, and add the following to
+ * appengine-web.xml:
+ *
+ * <pre>
+ *      &lt;static-files&gt;
+ *           &lt;include path=&quot;/VAADIN/**&quot; /&gt;
+ *      &lt;/static-files&gt;
+ * </pre>
+ *
+ * Additional limitations:
+ * <ul>
+ * <li/>Do not change application state when serving an ApplicationResource.
+ * <li/>Avoid changing application state in transaction handlers, unless you're
+ * confident you fully understand the synchronization issues in App Engine.
+ * <li/>The application remains locked while uploading - no progressbar is
+ * possible.
+ * </ul>
+ *
+ * @deprecated No longer supported with Vaadin 8.0
+ */
+@Deprecated
+public class GAEVaadinServlet extends VaadinServlet {
+
+    // memcache mutex is MUTEX_BASE + sessio id
+    private static final String MUTEX_BASE = "_vmutex";
+
+    // used identify ApplicationContext in memcache and datastore
+    private static final String AC_BASE = "_vac";
+
+    // UIDL requests will attempt to gain access for this long before telling
+    // the client to retry
+    private static final int MAX_UIDL_WAIT_MILLISECONDS = 5000;
+
+    // Tell client to retry after this delay.
+    // Note: currently interpreting Retry-After as ms, not sec
+    private static final int RETRY_AFTER_MILLISECONDS = 100;
+
+    // Properties used in the datastore
+    private static final String PROPERTY_EXPIRES = "expires";
+    private static final String PROPERTY_DATA = "data";
+
+    // path used for cleanup
+    private static final String CLEANUP_PATH = "/CLEAN";
+    // max entities to clean at once
+    private static final int CLEANUP_LIMIT = 200;
+    // appengine session kind
+    private static final String APPENGINE_SESSION_KIND = "_ah_SESSION";
+    // appengine session expires-parameter
+    private static final String PROPERTY_APPENGINE_EXPIRES = "_expires";
+
+    // sessions with undefined (-1) expiration are limited to this, but explicit
+    // longer timeouts can be used
+    private static final int DEFAULT_MAX_INACTIVE_INTERVAL = 24 * 3600;
+
+    protected void sendDeadlineExceededNotification(
+            VaadinServletRequest request, VaadinServletResponse response)
+            throws IOException {
+        criticalNotification(request, response, "Deadline Exceeded",
+                "I'm sorry, but the operation took too long to complete. We'll try reloading to see where we're at, please take note of any unsaved data...",
+                "", null);
+    }
+
+    protected void sendNotSerializableNotification(VaadinServletRequest request,
+            VaadinServletResponse response) throws IOException {
+        criticalNotification(request, response, "NotSerializableException",
+                "I'm sorry, but there seems to be a serious problem, please contact the administrator. And please take note of any unsaved data...",
+                "",
+                getApplicationUrl(request).toString() + "?restartApplication");
+    }
+
+    protected void sendCriticalErrorNotification(VaadinServletRequest request,
+            VaadinServletResponse response) throws IOException {
+        criticalNotification(request, response, "Critical error",
+                "I'm sorry, but there seems to be a serious problem, please contact the administrator. And please take note of any unsaved data...",
+                "",
+                getApplicationUrl(request).toString() + "?restartApplication");
+    }
+
+    @Override
+    protected void service(HttpServletRequest unwrappedRequest,
+            HttpServletResponse unwrappedResponse)
+            throws ServletException, IOException {
+        VaadinServletRequest request = new VaadinServletRequest(
+                unwrappedRequest, getService());
+        VaadinServletResponse response = new VaadinServletResponse(
+                unwrappedResponse, getService());
+
+        if (isCleanupRequest(request)) {
+            cleanDatastore();
+            return;
+        }
+
+        if (isStaticResourceRequest(request)) {
+            // no locking needed, let superclass handle
+            super.service(request, response);
+            cleanSession(request);
+            return;
+        }
+
+        if (ServletPortletHelper.isAppRequest(request)) {
+            // no locking needed, let superclass handle
+            getApplicationContext(request,
+                    MemcacheServiceFactory.getMemcacheService());
+            super.service(request, response);
+            cleanSession(request);
+            return;
+        }
+
+        final HttpSession session = request
+                .getSession(getService().requestCanCreateSession(request));
+        if (session == null) {
+            try {
+                getService().handleSessionExpired(request, response);
+            } catch (ServiceException e) {
+                throw new ServletException(e);
+            }
+            cleanSession(request);
+            return;
+        }
+
+        boolean locked = false;
+        MemcacheService memcache = null;
+        String mutex = MUTEX_BASE + session.getId();
+        memcache = MemcacheServiceFactory.getMemcacheService();
+        try {
+            // try to get lock
+            long started = System.currentTimeMillis();
+            while (System.currentTimeMillis()
+                    - started < MAX_UIDL_WAIT_MILLISECONDS) {
+                locked = memcache.put(mutex, 1, Expiration.byDeltaSeconds(40),
+                        MemcacheService.SetPolicy.ADD_ONLY_IF_NOT_PRESENT);
+                if (locked || ServletPortletHelper.isUIDLRequest(request)) {
+                    /*
+                     * Done if we got a lock. Will also avoid retrying if
+                     * there's a UIDL request because those are retried from the
+                     * client without keeping the server thread stalled.
+                     */
+                    break;
+                }
+                try {
+                    Thread.sleep(RETRY_AFTER_MILLISECONDS);
+                } catch (InterruptedException e) {
+                    getLogger()
+                            .finer("Thread.sleep() interrupted while waiting for lock. Trying again. "
+                                    + e);
+                }
+            }
+
+            if (!locked) {
+                // Not locked; only UIDL can get trough here unlocked: tell
+                // client to retry
+                response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+                // Note: currently interpreting Retry-After as ms, not sec
+                response.setHeader("Retry-After",
+                        "" + RETRY_AFTER_MILLISECONDS);
+                return;
+            }
+
+            // de-serialize or create application context, store in session
+            VaadinSession ctx = getApplicationContext(request, memcache);
+
+            super.service(request, response);
+
+            // serialize
+            started = new Date().getTime();
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ObjectOutputStream oos = new ObjectOutputStream(baos);
+            oos.writeObject(ctx);
+            oos.flush();
+            byte[] bytes = baos.toByteArray();
+
+            started = new Date().getTime();
+
+            String id = AC_BASE + session.getId();
+            Date expire = new Date(
+                    started + getMaxInactiveIntervalSeconds(session) * 1000);
+            Expiration expires = Expiration.onDate(expire);
+
+            memcache.put(id, bytes, expires);
+
+            DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
+            Entity entity = new Entity(AC_BASE, id);
+            entity.setProperty(PROPERTY_EXPIRES, expire.getTime());
+            entity.setProperty(PROPERTY_DATA, new Blob(bytes));
+            ds.put(entity);
+
+        } catch (DeadlineExceededException e) {
+            getLogger().log(Level.WARNING, "DeadlineExceeded for {0}",
+                    session.getId());
+            sendDeadlineExceededNotification(request, response);
+        } catch (NotSerializableException e) {
+            getLogger().log(Level.SEVERE, "Not serializable!", e);
+
+            // TODO this notification is usually not shown - should we redirect
+            // in some other way - can we?
+            sendNotSerializableNotification(request, response);
+        } catch (Exception e) {
+            getLogger().log(Level.WARNING,
+                    "An exception occurred while servicing request.", e);
+
+            sendCriticalErrorNotification(request, response);
+        } finally {
+            // "Next, please!"
+            if (locked) {
+                memcache.delete(mutex);
+            }
+            cleanSession(request);
+        }
+    }
+
+    /**
+     * Returns the maximum inactive time for a session. This is used for
+     * handling the expiration of session related information in caches etc.
+     *
+     * @param session
+     * @return inactive timeout in seconds, greater than zero
+     */
+    protected int getMaxInactiveIntervalSeconds(final HttpSession session) {
+        int interval = session.getMaxInactiveInterval();
+        if (interval <= 0) {
+            getLogger().log(Level.FINE,
+                    "Undefined session expiration time, using default value instead.");
+            return DEFAULT_MAX_INACTIVE_INTERVAL;
+        }
+        return interval;
+    }
+
+    protected VaadinSession getApplicationContext(HttpServletRequest request,
+            MemcacheService memcache) throws ServletException {
+        HttpSession session = request.getSession();
+        String id = AC_BASE + session.getId();
+        byte[] serializedAC = (byte[]) memcache.get(id);
+        if (serializedAC == null) {
+            DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
+            Key key = KeyFactory.createKey(AC_BASE, id);
+            Entity entity = null;
+            try {
+                entity = ds.get(key);
+            } catch (EntityNotFoundException e) {
+                // Ok, we were a bit optimistic; we'll create a new one later
+            }
+            if (entity != null) {
+                Blob blob = (Blob) entity.getProperty(PROPERTY_DATA);
+                serializedAC = blob.getBytes();
+                // bring it to memcache
+                memcache.put(AC_BASE + session.getId(), serializedAC,
+                        Expiration.byDeltaSeconds(
+                                getMaxInactiveIntervalSeconds(session)),
+                        MemcacheService.SetPolicy.ADD_ONLY_IF_NOT_PRESENT);
+            }
+        }
+        if (serializedAC != null) {
+            ByteArrayInputStream bais = new ByteArrayInputStream(serializedAC);
+            ObjectInputStream ois;
+            try {
+                ois = new ObjectInputStream(bais);
+                VaadinSession vaadinSession = (VaadinSession) ois.readObject();
+                getService().storeSession(vaadinSession,
+                        new WrappedHttpSession(session));
+            } catch (IOException | ClassNotFoundException e) {
+                getLogger().log(Level.WARNING,
+                        "Could not de-serialize ApplicationContext for "
+                                + session.getId()
+                                + " A new one will be created. ",
+                        e);
+            }
+        }
+
+        // will create new context if the above did not
+        try {
+            return getService().findVaadinSession(createVaadinRequest(request));
+        } catch (Exception e) {
+            throw new ServletException(e);
+        }
+    }
+
+    private boolean isCleanupRequest(HttpServletRequest request) {
+        String path = request.getPathInfo();
+        if (path != null && path.equals(CLEANUP_PATH)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Removes the ApplicationContext from the session in order to minimize the
+     * data serialized to datastore and memcache.
+     *
+     * @param request
+     */
+    private void cleanSession(VaadinServletRequest request) {
+        // Should really be replaced with a session storage API...
+        WrappedSession wrappedSession = request.getWrappedSession(false);
+        if (wrappedSession == null) {
+            return;
+        }
+        VaadinSession serviceSession = getService().loadSession(wrappedSession);
+        if (serviceSession == null) {
+            return;
+        }
+
+        /*
+         * Inform VaadinSession.valueUnbound that it should not kill the session
+         * even though it gets unbound.
+         */
+        serviceSession.setAttribute(
+                VaadinService.PRESERVE_UNBOUND_SESSION_ATTRIBUTE, Boolean.TRUE);
+        getService().removeSession(serviceSession.getSession());
+
+        // Remove preservation marker
+        serviceSession.setAttribute(
+                VaadinService.PRESERVE_UNBOUND_SESSION_ATTRIBUTE, null);
+    }
+
+    /**
+     * This will look at the timestamp and delete expired persisted Vaadin and
+     * appengine sessions from the datastore.
+     *
+     * TODO Possible improvements include: 1. Use transactions (requires entity
+     * groups - overkill?) 2. Delete one-at-a-time, catch possible exception,
+     * continue w/ next.
+     */
+    private void cleanDatastore() {
+        long expire = new Date().getTime();
+        try {
+            DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
+            // Vaadin stuff first
+            {
+                Query q = new Query(AC_BASE);
+                q.setKeysOnly();
+
+                q.addFilter(PROPERTY_EXPIRES, FilterOperator.LESS_THAN_OR_EQUAL,
+                        expire);
+                PreparedQuery pq = ds.prepare(q);
+                List<Entity> entities = pq
+                        .asList(Builder.withLimit(CLEANUP_LIMIT));
+                if (entities != null) {
+                    getLogger().log(Level.INFO,
+                            "Vaadin cleanup deleting {0} expired Vaadin sessions.",
+                            entities.size());
+                    List<Key> keys = new ArrayList<>();
+                    for (Entity e : entities) {
+                        keys.add(e.getKey());
+                    }
+                    ds.delete(keys);
+                }
+            }
+            // Also cleanup GAE sessions
+            {
+                Query q = new Query(APPENGINE_SESSION_KIND);
+                q.setKeysOnly();
+                q.addFilter(PROPERTY_APPENGINE_EXPIRES,
+                        FilterOperator.LESS_THAN_OR_EQUAL, expire);
+                PreparedQuery pq = ds.prepare(q);
+                List<Entity> entities = pq
+                        .asList(Builder.withLimit(CLEANUP_LIMIT));
+                if (entities != null) {
+                    getLogger().log(Level.INFO,
+                            "Vaadin cleanup deleting {0} expired appengine sessions.",
+                            entities.size());
+                    List<Key> keys = new ArrayList<>();
+                    for (Entity e : entities) {
+                        keys.add(e.getKey());
+                    }
+                    ds.delete(keys);
+                }
+            }
+        } catch (Exception e) {
+            getLogger().log(Level.WARNING, "Exception while cleaning.", e);
+        }
+    }
+
+    private static final Logger getLogger() {
+        return Logger.getLogger(GAEVaadinServlet.class.getName());
+    }
+}
index 1a68b14207a73084f6b38cec07efe1b5544b79aa..ba5edbb146eedd98868ec0e2a6862884af0f2c00 100644 (file)
@@ -26,8 +26,8 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import com.vaadin.shared.util.SharedUtil;
-import com.vaadin.util.SerializerHelper;
 import com.vaadin.v7.data.Property;
+import com.vaadin.v7.util.SerializerHelper;
 
 /**
  * <p>
index 7f98c5dd11b56fab8b6f2ed2476278073e67f356..9f0584962ff4a2a4c3cefe334984ec0297a01b53 100644 (file)
@@ -21,8 +21,8 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import com.vaadin.util.ReflectTools;
-import com.vaadin.util.SerializerHelper;
 import com.vaadin.v7.data.Property;
+import com.vaadin.v7.util.SerializerHelper;
 
 /**
  * Property descriptor that is able to create simple {@link MethodProperty}
diff --git a/compatibility-server/src/main/java/com/vaadin/v7/util/SerializerHelper.java b/compatibility-server/src/main/java/com/vaadin/v7/util/SerializerHelper.java
new file mode 100644 (file)
index 0000000..d0ad569
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.v7.util;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+/**
+ * Helper class for performing serialization. Most of the methods are here are
+ * workarounds for problems in Google App Engine. Used internally by Vaadin and
+ * should not be used by application developers. Subject to change at any time.
+ *
+ * @since 6.0
+ * @deprecated Only used for compatibility-server
+ */
+@Deprecated
+public class SerializerHelper {
+
+    /**
+     * Serializes the class reference so {@link #readClass(ObjectInputStream)}
+     * can deserialize it. Supports null class references.
+     *
+     * @param out
+     *            The {@link ObjectOutputStream} to serialize to.
+     * @param cls
+     *            A class or null.
+     * @throws IOException
+     *             Rethrows any IOExceptions from the ObjectOutputStream
+     */
+    public static void writeClass(ObjectOutputStream out, Class<?> cls)
+            throws IOException {
+        if (cls == null) {
+            out.writeObject(null);
+        } else {
+            out.writeObject(cls.getName());
+        }
+
+    }
+
+    /**
+     * Serializes the class references so
+     * {@link #readClassArray(ObjectInputStream)} can deserialize it. Supports
+     * null class arrays.
+     *
+     * @param out
+     *            The {@link ObjectOutputStream} to serialize to.
+     * @param classes
+     *            An array containing class references or null.
+     * @throws IOException
+     *             Rethrows any IOExceptions from the ObjectOutputStream
+     */
+    public static void writeClassArray(ObjectOutputStream out,
+            Class<?>[] classes) throws IOException {
+        if (classes == null) {
+            out.writeObject(null);
+        } else {
+            String[] classNames = new String[classes.length];
+            for (int i = 0; i < classes.length; i++) {
+                classNames[i] = classes[i].getName();
+            }
+            out.writeObject(classNames);
+        }
+    }
+
+    /**
+     * Deserializes a class references serialized by
+     * {@link #writeClassArray(ObjectOutputStream, Class[])}. Supports null
+     * class arrays.
+     *
+     * @param in
+     *            {@link ObjectInputStream} to read from.
+     * @return Class array with the class references or null.
+     * @throws ClassNotFoundException
+     *             If one of the classes could not be resolved.
+     * @throws IOException
+     *             Rethrows IOExceptions from the ObjectInputStream
+     */
+    public static Class<?>[] readClassArray(ObjectInputStream in)
+            throws ClassNotFoundException, IOException {
+        String[] classNames = (String[]) in.readObject();
+        if (classNames == null) {
+            return null;
+        }
+        Class<?>[] classes = new Class<?>[classNames.length];
+        for (int i = 0; i < classNames.length; i++) {
+            classes[i] = resolveClass(classNames[i]);
+        }
+
+        return classes;
+    }
+
+    /**
+     * List of primitive classes. Google App Engine has problems
+     * serializing/deserializing these (#3064).
+     */
+    private static final Class<?>[] primitiveClasses = new Class<?>[] {
+            byte.class, short.class, int.class, long.class, float.class,
+            double.class, boolean.class, char.class };
+
+    /**
+     * Resolves the class given by {@code className}.
+     *
+     * @param className
+     *            The fully qualified class name.
+     * @return A {@code Class} reference.
+     * @throws ClassNotFoundException
+     *             If the class could not be resolved.
+     */
+    public static Class<?> resolveClass(String className)
+            throws ClassNotFoundException {
+        for (Class<?> c : primitiveClasses) {
+            if (className.equals(c.getName())) {
+                return c;
+            }
+        }
+
+        return Class.forName(className);
+    }
+
+    /**
+     * Deserializes a class reference serialized by
+     * {@link #writeClass(ObjectOutputStream, Class)}. Supports null class
+     * references.
+     *
+     * @param in
+     *            {@code ObjectInputStream} to read from.
+     * @return Class reference to the resolved class
+     * @throws ClassNotFoundException
+     *             If the class could not be resolved.
+     * @throws IOException
+     *             Rethrows IOExceptions from the ObjectInputStream
+     */
+    public static Class<?> readClass(ObjectInputStream in)
+            throws IOException, ClassNotFoundException {
+        String className = (String) in.readObject();
+        if (className == null) {
+            return null;
+        } else {
+            return resolveClass(className);
+
+        }
+
+    }
+
+    private SerializerHelper() {
+    }
+
+}
index ef586bd6dda537c36dfce0839e28610bcf608b58..07da0ff9fbe7b100efbed9401249f5543eb448cf 100644 (file)
             <scope>provided</scope>
         </dependency>
 
-        <!-- Google App Engine -->
-        <dependency>
-            <groupId>com.google.appengine</groupId>
-            <artifactId>appengine-api-1.0-sdk</artifactId>
-            <scope>provided</scope>
-        </dependency>
-
         <!-- Bean Validation API -->
         <dependency>
             <groupId>javax.validation</groupId>
diff --git a/server/src/main/java/com/vaadin/server/GAEVaadinServlet.java b/server/src/main/java/com/vaadin/server/GAEVaadinServlet.java
deleted file mode 100644 (file)
index bfa2925..0000000
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * Copyright 2000-2016 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.vaadin.server;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.NotSerializableException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-import com.google.appengine.api.datastore.Blob;
-import com.google.appengine.api.datastore.DatastoreService;
-import com.google.appengine.api.datastore.DatastoreServiceFactory;
-import com.google.appengine.api.datastore.Entity;
-import com.google.appengine.api.datastore.EntityNotFoundException;
-import com.google.appengine.api.datastore.FetchOptions.Builder;
-import com.google.appengine.api.datastore.Key;
-import com.google.appengine.api.datastore.KeyFactory;
-import com.google.appengine.api.datastore.PreparedQuery;
-import com.google.appengine.api.datastore.Query;
-import com.google.appengine.api.datastore.Query.FilterOperator;
-import com.google.appengine.api.memcache.Expiration;
-import com.google.appengine.api.memcache.MemcacheService;
-import com.google.appengine.api.memcache.MemcacheServiceFactory;
-import com.google.apphosting.api.DeadlineExceededException;
-
-/**
- * ApplicationServlet to be used when deploying to Google App Engine, in
- * web.xml:
- *
- * <pre>
- *      &lt;servlet&gt;
- *              &lt;servlet-name&gt;HelloWorld&lt;/servlet-name&gt;
- *              &lt;servlet-class&gt;com.vaadin.server.GAEApplicationServlet&lt;/servlet-class&gt;
- *              &lt;init-param&gt;
- *                      &lt;param-name&gt;UI&lt;/param-name&gt;
- *                      &lt;param-value&gt;com.vaadin.demo.HelloWorld&lt;/param-value&gt;
- *              &lt;/init-param&gt;
- *      &lt;/servlet&gt;
- * </pre>
- *
- * Session support must be enabled in appengine-web.xml:
- *
- * <pre>
- *      &lt;sessions-enabled&gt;true&lt;/sessions-enabled&gt;
- * </pre>
- *
- * Appengine datastore cleanup can be invoked by calling one of the applications
- * with an additional path "/CLEAN". This can be set up as a cron-job in
- * cron.xml (see appengine documentation for more information):
- *
- * <pre>
- * &lt;cronentries&gt;
- *   &lt;cron&gt;
- *     &lt;url&gt;/HelloWorld/CLEAN&lt;/url&gt;
- *     &lt;description&gt;Clean up sessions&lt;/description&gt;
- *     &lt;schedule&gt;every 2 hours&lt;/schedule&gt;
- *   &lt;/cron&gt;
- * &lt;/cronentries&gt;
- * </pre>
- *
- * It is recommended (but not mandatory) to extract themes and widgetsets and
- * have App Engine server these statically. Extract VAADIN folder (and it's
- * contents) 'next to' the WEB-INF folder, and add the following to
- * appengine-web.xml:
- *
- * <pre>
- *      &lt;static-files&gt;
- *           &lt;include path=&quot;/VAADIN/**&quot; /&gt;
- *      &lt;/static-files&gt;
- * </pre>
- *
- * Additional limitations:
- * <ul>
- * <li/>Do not change application state when serving an ApplicationResource.
- * <li/>Avoid changing application state in transaction handlers, unless you're
- * confident you fully understand the synchronization issues in App Engine.
- * <li/>The application remains locked while uploading - no progressbar is
- * possible.
- * </ul>
- */
-public class GAEVaadinServlet extends VaadinServlet {
-
-    // memcache mutex is MUTEX_BASE + sessio id
-    private static final String MUTEX_BASE = "_vmutex";
-
-    // used identify ApplicationContext in memcache and datastore
-    private static final String AC_BASE = "_vac";
-
-    // UIDL requests will attempt to gain access for this long before telling
-    // the client to retry
-    private static final int MAX_UIDL_WAIT_MILLISECONDS = 5000;
-
-    // Tell client to retry after this delay.
-    // Note: currently interpreting Retry-After as ms, not sec
-    private static final int RETRY_AFTER_MILLISECONDS = 100;
-
-    // Properties used in the datastore
-    private static final String PROPERTY_EXPIRES = "expires";
-    private static final String PROPERTY_DATA = "data";
-
-    // path used for cleanup
-    private static final String CLEANUP_PATH = "/CLEAN";
-    // max entities to clean at once
-    private static final int CLEANUP_LIMIT = 200;
-    // appengine session kind
-    private static final String APPENGINE_SESSION_KIND = "_ah_SESSION";
-    // appengine session expires-parameter
-    private static final String PROPERTY_APPENGINE_EXPIRES = "_expires";
-
-    // sessions with undefined (-1) expiration are limited to this, but explicit
-    // longer timeouts can be used
-    private static final int DEFAULT_MAX_INACTIVE_INTERVAL = 24 * 3600;
-
-    protected void sendDeadlineExceededNotification(
-            VaadinServletRequest request, VaadinServletResponse response)
-            throws IOException {
-        criticalNotification(request, response, "Deadline Exceeded",
-                "I'm sorry, but the operation took too long to complete. We'll try reloading to see where we're at, please take note of any unsaved data...",
-                "", null);
-    }
-
-    protected void sendNotSerializableNotification(VaadinServletRequest request,
-            VaadinServletResponse response) throws IOException {
-        criticalNotification(request, response, "NotSerializableException",
-                "I'm sorry, but there seems to be a serious problem, please contact the administrator. And please take note of any unsaved data...",
-                "",
-                getApplicationUrl(request).toString() + "?restartApplication");
-    }
-
-    protected void sendCriticalErrorNotification(VaadinServletRequest request,
-            VaadinServletResponse response) throws IOException {
-        criticalNotification(request, response, "Critical error",
-                "I'm sorry, but there seems to be a serious problem, please contact the administrator. And please take note of any unsaved data...",
-                "",
-                getApplicationUrl(request).toString() + "?restartApplication");
-    }
-
-    @Override
-    protected void service(HttpServletRequest unwrappedRequest,
-            HttpServletResponse unwrappedResponse)
-            throws ServletException, IOException {
-        VaadinServletRequest request = new VaadinServletRequest(
-                unwrappedRequest, getService());
-        VaadinServletResponse response = new VaadinServletResponse(
-                unwrappedResponse, getService());
-
-        if (isCleanupRequest(request)) {
-            cleanDatastore();
-            return;
-        }
-
-        if (isStaticResourceRequest(request)) {
-            // no locking needed, let superclass handle
-            super.service(request, response);
-            cleanSession(request);
-            return;
-        }
-
-        if (ServletPortletHelper.isAppRequest(request)) {
-            // no locking needed, let superclass handle
-            getApplicationContext(request,
-                    MemcacheServiceFactory.getMemcacheService());
-            super.service(request, response);
-            cleanSession(request);
-            return;
-        }
-
-        final HttpSession session = request
-                .getSession(getService().requestCanCreateSession(request));
-        if (session == null) {
-            try {
-                getService().handleSessionExpired(request, response);
-            } catch (ServiceException e) {
-                throw new ServletException(e);
-            }
-            cleanSession(request);
-            return;
-        }
-
-        boolean locked = false;
-        MemcacheService memcache = null;
-        String mutex = MUTEX_BASE + session.getId();
-        memcache = MemcacheServiceFactory.getMemcacheService();
-        try {
-            // try to get lock
-            long started = System.currentTimeMillis();
-            while (System.currentTimeMillis()
-                    - started < MAX_UIDL_WAIT_MILLISECONDS) {
-                locked = memcache.put(mutex, 1, Expiration.byDeltaSeconds(40),
-                        MemcacheService.SetPolicy.ADD_ONLY_IF_NOT_PRESENT);
-                if (locked || ServletPortletHelper.isUIDLRequest(request)) {
-                    /*
-                     * Done if we got a lock. Will also avoid retrying if
-                     * there's a UIDL request because those are retried from the
-                     * client without keeping the server thread stalled.
-                     */
-                    break;
-                }
-                try {
-                    Thread.sleep(RETRY_AFTER_MILLISECONDS);
-                } catch (InterruptedException e) {
-                    getLogger()
-                            .finer("Thread.sleep() interrupted while waiting for lock. Trying again. "
-                                    + e);
-                }
-            }
-
-            if (!locked) {
-                // Not locked; only UIDL can get trough here unlocked: tell
-                // client to retry
-                response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
-                // Note: currently interpreting Retry-After as ms, not sec
-                response.setHeader("Retry-After",
-                        "" + RETRY_AFTER_MILLISECONDS);
-                return;
-            }
-
-            // de-serialize or create application context, store in session
-            VaadinSession ctx = getApplicationContext(request, memcache);
-
-            super.service(request, response);
-
-            // serialize
-            started = new Date().getTime();
-            ByteArrayOutputStream baos = new ByteArrayOutputStream();
-            ObjectOutputStream oos = new ObjectOutputStream(baos);
-            oos.writeObject(ctx);
-            oos.flush();
-            byte[] bytes = baos.toByteArray();
-
-            started = new Date().getTime();
-
-            String id = AC_BASE + session.getId();
-            Date expire = new Date(
-                    started + (getMaxInactiveIntervalSeconds(session) * 1000));
-            Expiration expires = Expiration.onDate(expire);
-
-            memcache.put(id, bytes, expires);
-
-            DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
-            Entity entity = new Entity(AC_BASE, id);
-            entity.setProperty(PROPERTY_EXPIRES, expire.getTime());
-            entity.setProperty(PROPERTY_DATA, new Blob(bytes));
-            ds.put(entity);
-
-        } catch (DeadlineExceededException e) {
-            getLogger().log(Level.WARNING, "DeadlineExceeded for {0}",
-                    session.getId());
-            sendDeadlineExceededNotification(request, response);
-        } catch (NotSerializableException e) {
-            getLogger().log(Level.SEVERE, "Not serializable!", e);
-
-            // TODO this notification is usually not shown - should we redirect
-            // in some other way - can we?
-            sendNotSerializableNotification(request, response);
-        } catch (Exception e) {
-            getLogger().log(Level.WARNING,
-                    "An exception occurred while servicing request.", e);
-
-            sendCriticalErrorNotification(request, response);
-        } finally {
-            // "Next, please!"
-            if (locked) {
-                memcache.delete(mutex);
-            }
-            cleanSession(request);
-        }
-    }
-
-    /**
-     * Returns the maximum inactive time for a session. This is used for
-     * handling the expiration of session related information in caches etc.
-     *
-     * @param session
-     * @return inactive timeout in seconds, greater than zero
-     */
-    protected int getMaxInactiveIntervalSeconds(final HttpSession session) {
-        int interval = session.getMaxInactiveInterval();
-        if (interval <= 0) {
-            getLogger().log(Level.FINE,
-                    "Undefined session expiration time, using default value instead.");
-            return DEFAULT_MAX_INACTIVE_INTERVAL;
-        }
-        return interval;
-    }
-
-    protected VaadinSession getApplicationContext(HttpServletRequest request,
-            MemcacheService memcache) throws ServletException {
-        HttpSession session = request.getSession();
-        String id = AC_BASE + session.getId();
-        byte[] serializedAC = (byte[]) memcache.get(id);
-        if (serializedAC == null) {
-            DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
-            Key key = KeyFactory.createKey(AC_BASE, id);
-            Entity entity = null;
-            try {
-                entity = ds.get(key);
-            } catch (EntityNotFoundException e) {
-                // Ok, we were a bit optimistic; we'll create a new one later
-            }
-            if (entity != null) {
-                Blob blob = (Blob) entity.getProperty(PROPERTY_DATA);
-                serializedAC = blob.getBytes();
-                // bring it to memcache
-                memcache.put(AC_BASE + session.getId(), serializedAC,
-                        Expiration.byDeltaSeconds(
-                                getMaxInactiveIntervalSeconds(session)),
-                        MemcacheService.SetPolicy.ADD_ONLY_IF_NOT_PRESENT);
-            }
-        }
-        if (serializedAC != null) {
-            ByteArrayInputStream bais = new ByteArrayInputStream(serializedAC);
-            ObjectInputStream ois;
-            try {
-                ois = new ObjectInputStream(bais);
-                VaadinSession vaadinSession = (VaadinSession) ois.readObject();
-                getService().storeSession(vaadinSession,
-                        new WrappedHttpSession(session));
-            } catch (IOException | ClassNotFoundException e) {
-                getLogger().log(Level.WARNING,
-                        "Could not de-serialize ApplicationContext for "
-                                + session.getId()
-                                + " A new one will be created. ",
-                        e);
-            }
-        }
-
-        // will create new context if the above did not
-        try {
-            return getService().findVaadinSession(createVaadinRequest(request));
-        } catch (Exception e) {
-            throw new ServletException(e);
-        }
-    }
-
-    private boolean isCleanupRequest(HttpServletRequest request) {
-        String path = request.getPathInfo();
-        if (path != null && path.equals(CLEANUP_PATH)) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Removes the ApplicationContext from the session in order to minimize the
-     * data serialized to datastore and memcache.
-     *
-     * @param request
-     */
-    private void cleanSession(VaadinServletRequest request) {
-        // Should really be replaced with a session storage API...
-        WrappedSession wrappedSession = request.getWrappedSession(false);
-        if (wrappedSession == null) {
-            return;
-        }
-        VaadinSession serviceSession = getService().loadSession(wrappedSession);
-        if (serviceSession == null) {
-            return;
-        }
-
-        /*
-         * Inform VaadinSession.valueUnbound that it should not kill the session
-         * even though it gets unbound.
-         */
-        serviceSession.setAttribute(
-                VaadinService.PRESERVE_UNBOUND_SESSION_ATTRIBUTE, Boolean.TRUE);
-        getService().removeSession(serviceSession.getSession());
-
-        // Remove preservation marker
-        serviceSession.setAttribute(
-                VaadinService.PRESERVE_UNBOUND_SESSION_ATTRIBUTE, null);
-    }
-
-    /**
-     * This will look at the timestamp and delete expired persisted Vaadin and
-     * appengine sessions from the datastore.
-     *
-     * TODO Possible improvements include: 1. Use transactions (requires entity
-     * groups - overkill?) 2. Delete one-at-a-time, catch possible exception,
-     * continue w/ next.
-     */
-    private void cleanDatastore() {
-        long expire = new Date().getTime();
-        try {
-            DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
-            // Vaadin stuff first
-            {
-                Query q = new Query(AC_BASE);
-                q.setKeysOnly();
-
-                q.addFilter(PROPERTY_EXPIRES, FilterOperator.LESS_THAN_OR_EQUAL,
-                        expire);
-                PreparedQuery pq = ds.prepare(q);
-                List<Entity> entities = pq
-                        .asList(Builder.withLimit(CLEANUP_LIMIT));
-                if (entities != null) {
-                    getLogger().log(Level.INFO,
-                            "Vaadin cleanup deleting {0} expired Vaadin sessions.",
-                            entities.size());
-                    List<Key> keys = new ArrayList<>();
-                    for (Entity e : entities) {
-                        keys.add(e.getKey());
-                    }
-                    ds.delete(keys);
-                }
-            }
-            // Also cleanup GAE sessions
-            {
-                Query q = new Query(APPENGINE_SESSION_KIND);
-                q.setKeysOnly();
-                q.addFilter(PROPERTY_APPENGINE_EXPIRES,
-                        FilterOperator.LESS_THAN_OR_EQUAL, expire);
-                PreparedQuery pq = ds.prepare(q);
-                List<Entity> entities = pq
-                        .asList(Builder.withLimit(CLEANUP_LIMIT));
-                if (entities != null) {
-                    getLogger().log(Level.INFO,
-                            "Vaadin cleanup deleting {0} expired appengine sessions.",
-                            entities.size());
-                    List<Key> keys = new ArrayList<>();
-                    for (Entity e : entities) {
-                        keys.add(e.getKey());
-                    }
-                    ds.delete(keys);
-                }
-            }
-        } catch (Exception e) {
-            getLogger().log(Level.WARNING, "Exception while cleaning.", e);
-        }
-    }
-
-    private static final Logger getLogger() {
-        return Logger.getLogger(GAEVaadinServlet.class.getName());
-    }
-}
index a8b9a0b90a53e48eba8bc0bf4f627e5c61b66e7b..f0d01bce0891218f9267e33eefdce1c99f37d342 100644 (file)
@@ -298,9 +298,9 @@ public class VaadinServlet extends HttpServlet implements Constants {
      * Gets the currently used Vaadin servlet. The current servlet is
      * automatically defined when initializing the servlet and when processing
      * requests to the server (see {@link ThreadLocal}) and in
-     * {@link VaadinSession#access(Runnable)} and {@link UI#access(Runnable)}. In
-     * other cases, (e.g. from background threads), the current servlet is not
-     * automatically defined.
+     * {@link VaadinSession#access(Runnable)} and {@link UI#access(Runnable)}.
+     * In other cases, (e.g. from background threads), the current servlet is
+     * not automatically defined.
      * <p>
      * The current servlet is derived from the current service using
      * {@link VaadinService#getCurrent()}
@@ -553,7 +553,7 @@ public class VaadinServlet extends HttpServlet implements Constants {
      *             if the writing failed due to input/output error.
      *
      * @deprecated As of 7.0. This method is retained only for backwards
-     *             compatibility and for {@link GAEVaadinServlet}.
+     *             compatibility and for GAEVaadinServlet.
      */
     @Deprecated
     protected void criticalNotification(VaadinServletRequest request,
@@ -778,7 +778,7 @@ public class VaadinServlet extends HttpServlet implements Constants {
         }
         response.setHeader("Cache-Control", cacheControl);
         response.setDateHeader("Expires",
-                System.currentTimeMillis() + (resourceCacheTime * 1000));
+                System.currentTimeMillis() + resourceCacheTime * 1000);
 
         // Find the modification timestamp
         long lastModifiedTime = 0;
@@ -1339,10 +1339,9 @@ public class VaadinServlet extends HttpServlet implements Constants {
             throws MalformedURLException {
         final URL reqURL = new URL((request.isSecure() ? "https://" : "http://")
                 + request.getServerName()
-                + ((request.isSecure() && request.getServerPort() == 443)
-                        || (!request.isSecure()
-                                && request.getServerPort() == 80) ? ""
-                                        : ":" + request.getServerPort())
+                + (request.isSecure() && request.getServerPort() == 443
+                        || !request.isSecure() && request.getServerPort() == 80
+                                ? "" : ":" + request.getServerPort())
                 + request.getRequestURI());
         String servletPath = "";
         if (request
diff --git a/server/src/main/java/com/vaadin/util/SerializerHelper.java b/server/src/main/java/com/vaadin/util/SerializerHelper.java
deleted file mode 100644 (file)
index 41ef150..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright 2000-2016 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.vaadin.util;
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-
-/**
- * Helper class for performing serialization. Most of the methods are here are
- * workarounds for problems in Google App Engine. Used internally by Vaadin and
- * should not be used by application developers. Subject to change at any time.
- *
- * @since 6.0
- */
-public class SerializerHelper {
-
-    /**
-     * Serializes the class reference so {@link #readClass(ObjectInputStream)}
-     * can deserialize it. Supports null class references.
-     *
-     * @param out
-     *            The {@link ObjectOutputStream} to serialize to.
-     * @param cls
-     *            A class or null.
-     * @throws IOException
-     *             Rethrows any IOExceptions from the ObjectOutputStream
-     */
-    public static void writeClass(ObjectOutputStream out, Class<?> cls)
-            throws IOException {
-        if (cls == null) {
-            out.writeObject(null);
-        } else {
-            out.writeObject(cls.getName());
-        }
-
-    }
-
-    /**
-     * Serializes the class references so
-     * {@link #readClassArray(ObjectInputStream)} can deserialize it. Supports
-     * null class arrays.
-     *
-     * @param out
-     *            The {@link ObjectOutputStream} to serialize to.
-     * @param classes
-     *            An array containing class references or null.
-     * @throws IOException
-     *             Rethrows any IOExceptions from the ObjectOutputStream
-     */
-    public static void writeClassArray(ObjectOutputStream out,
-            Class<?>[] classes) throws IOException {
-        if (classes == null) {
-            out.writeObject(null);
-        } else {
-            String[] classNames = new String[classes.length];
-            for (int i = 0; i < classes.length; i++) {
-                classNames[i] = classes[i].getName();
-            }
-            out.writeObject(classNames);
-        }
-    }
-
-    /**
-     * Deserializes a class references serialized by
-     * {@link #writeClassArray(ObjectOutputStream, Class[])}. Supports null
-     * class arrays.
-     *
-     * @param in
-     *            {@link ObjectInputStream} to read from.
-     * @return Class array with the class references or null.
-     * @throws ClassNotFoundException
-     *             If one of the classes could not be resolved.
-     * @throws IOException
-     *             Rethrows IOExceptions from the ObjectInputStream
-     */
-    public static Class<?>[] readClassArray(ObjectInputStream in)
-            throws ClassNotFoundException, IOException {
-        String[] classNames = (String[]) in.readObject();
-        if (classNames == null) {
-            return null;
-        }
-        Class<?>[] classes = new Class<?>[classNames.length];
-        for (int i = 0; i < classNames.length; i++) {
-            classes[i] = resolveClass(classNames[i]);
-        }
-
-        return classes;
-    }
-
-    /**
-     * List of primitive classes. Google App Engine has problems
-     * serializing/deserializing these (#3064).
-     */
-    private static final Class<?>[] primitiveClasses = new Class<?>[] { byte.class,
-            short.class, int.class, long.class, float.class, double.class,
-            boolean.class, char.class };
-
-    /**
-     * Resolves the class given by {@code className}.
-     *
-     * @param className
-     *            The fully qualified class name.
-     * @return A {@code Class} reference.
-     * @throws ClassNotFoundException
-     *             If the class could not be resolved.
-     */
-    public static Class<?> resolveClass(String className)
-            throws ClassNotFoundException {
-        for (Class<?> c : primitiveClasses) {
-            if (className.equals(c.getName())) {
-                return c;
-            }
-        }
-
-        return Class.forName(className);
-    }
-
-    /**
-     * Deserializes a class reference serialized by
-     * {@link #writeClass(ObjectOutputStream, Class)}. Supports null class
-     * references.
-     *
-     * @param in
-     *            {@code ObjectInputStream} to read from.
-     * @return Class reference to the resolved class
-     * @throws ClassNotFoundException
-     *             If the class could not be resolved.
-     * @throws IOException
-     *             Rethrows IOExceptions from the ObjectInputStream
-     */
-    public static Class<?> readClass(ObjectInputStream in)
-            throws IOException, ClassNotFoundException {
-        String className = (String) in.readObject();
-        if (className == null) {
-            return null;
-        } else {
-            return resolveClass(className);
-
-        }
-
-    }
-
-    private SerializerHelper() {
-    }
-
-}
index fa0005a5523cab490f7d62cedfdc3ec976fa4fb8..04dc6a1c6a7d2dcbd4950b6d15bdfbb03f751983 100644 (file)
@@ -24,9 +24,6 @@
             rev="1.0.0.GA" conf="build -> default,sources" />
         <dependency org="org.hibernate" name="hibernate-validator"
             rev="4.2.0.Final" conf="build -> default" />
-        <!-- Google App Engine -->
-        <dependency org="com.google.appengine" name="appengine-api-1.0-sdk"
-            rev="1.7.7" conf="build-provided -> default" />
 
         <!-- LIBRARY DEPENDENCIES (compile time) -->
         <!-- Project modules -->
index 4b183e578b3dff08f8862c26de5cdccdb59d7d77..8f9fb5375871b71632975082ec005aae52725022 100644 (file)
             <groupId>org.hibernate</groupId>
             <artifactId>hibernate-validator</artifactId>
         </dependency>
-        <!-- Google App Engine -->
-        <dependency>
-            <groupId>com.google.appengine</groupId>
-            <artifactId>appengine-api-1.0-sdk</artifactId>
-            <scope>provided</scope>
-        </dependency>
 
         <!-- jetty-servlets needed by ProxyTest, but not by jetty-runner -->
         <!-- Jetty before vaadin-* on the classpath to make Eclipse use the 
diff --git a/uitest/src/main/java/com/vaadin/tests/appengine/GAESyncTest.java b/uitest/src/main/java/com/vaadin/tests/appengine/GAESyncTest.java
deleted file mode 100644 (file)
index 89b9219..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-package com.vaadin.tests.appengine;
-
-import com.google.apphosting.api.DeadlineExceededException;
-import com.vaadin.server.ClassResource;
-import com.vaadin.server.DownloadStream;
-import com.vaadin.server.LegacyApplication;
-import com.vaadin.ui.Button;
-import com.vaadin.ui.Button.ClickEvent;
-import com.vaadin.ui.Embedded;
-import com.vaadin.ui.GridLayout;
-import com.vaadin.ui.Label;
-import com.vaadin.ui.LegacyWindow;
-import com.vaadin.ui.Notification;
-import com.vaadin.v7.data.Property;
-import com.vaadin.v7.data.Property.ValueChangeEvent;
-import com.vaadin.v7.ui.TextField;
-
-public class GAESyncTest extends LegacyApplication {
-
-    /**
-     *
-     */
-    private static final long serialVersionUID = -3724319151122707926l;
-
-    @Override
-    public void init() {
-        setMainWindow(new IntrWindow(this));
-
-    }
-
-    @Override
-    public void error(com.vaadin.server.ErrorEvent event) {
-        Throwable t = event.getThrowable();
-        // Was this caused by a GAE timeout?
-        while (t != null) {
-            if (t instanceof DeadlineExceededException) {
-                getMainWindow().showNotification("Bugger!", "Deadline Exceeded",
-                        Notification.TYPE_ERROR_MESSAGE);
-                return;
-            }
-            t = t.getCause();
-        }
-
-        super.error(event);
-
-    }
-
-    private class IntrWindow extends LegacyWindow {
-        private int n = 0;
-        private static final long serialVersionUID = -6521351715072191625l;
-        TextField tf;
-        Label l;
-        LegacyApplication app;
-        GridLayout gl;
-
-        private IntrWindow(LegacyApplication app) {
-
-            this.app = app;
-            tf = new TextField("Echo thingie");
-            tf.setImmediate(true);
-            tf.addListener(new Property.ValueChangeListener() {
-                @Override
-                public void valueChange(ValueChangeEvent event) {
-                    IntrWindow.this.showNotification(
-                            (String) event.getProperty().getValue());
-
-                }
-
-            });
-            addComponent(tf);
-
-            l = new Label("" + n);
-            addComponent(l);
-
-            {
-                Button b = new Button("Slow", new Button.ClickListener() {
-                    @Override
-                    public void buttonClick(ClickEvent event) {
-                        try {
-                            Thread.sleep(15000);
-                        } catch (InterruptedException e) {
-                            // TODO Auto-generated catch block
-                            e.printStackTrace();
-                        }
-                    }
-
-                });
-                addComponent(b);
-            }
-
-            {
-                Button b = new Button("Add", new Button.ClickListener() {
-
-                    @Override
-                    public void buttonClick(ClickEvent event) {
-                        if (getUI() == getMainWindow()) {
-                            getUI().getPage()
-                                    .showNotification(new Notification("main"));
-                            try {
-                                Thread.sleep((5000));
-                            } catch (InterruptedException e) {
-                                // TODO Auto-generated catch block
-                                e.printStackTrace();
-                            }
-                        }
-                        addImage();
-                    }
-
-                });
-                addComponent(b);
-            }
-
-            gl = new GridLayout(30, 50);
-            addComponent(gl);
-
-        }
-
-        private void addImage() {
-            ClassResource res = new ClassResource("img1.png") {
-
-                private static final long serialVersionUID = 1L;
-
-                @Override
-                public DownloadStream getStream() {
-                    try {
-                        Thread.sleep((long) (Math.random() * 5000));
-                    } catch (InterruptedException e) {
-                        // TODO Auto-generated catch block
-                        e.printStackTrace();
-                    }
-                    return super.getStream();
-                }
-
-            };
-            res.setCacheTime(0);
-            Embedded emb = new Embedded("" + n, res);
-            emb.setWidth("30px");
-            emb.setHeight("5px");
-            gl.addComponent(emb);
-            l.setValue("" + n++);
-        }
-
-    }
-
-    @Override
-    public LegacyWindow getWindow(String name) {
-        LegacyWindow w = super.getWindow(name);
-        if (w == null) {
-            w = new IntrWindow(this);
-            addWindow(w);
-        }
-        return w;
-
-    }
-
-}