]> source.dussan.org Git - vaadin-framework.git/commitdiff
Refactoring in Portlet 2.0 support
authorHenri Sara <henri.sara@itmill.com>
Mon, 30 Nov 2009 10:07:26 +0000 (10:07 +0000)
committerHenri Sara <henri.sara@itmill.com>
Mon, 30 Nov 2009 10:07:26 +0000 (10:07 +0000)
svn changeset:10103/svn branch:6.2

src/com/vaadin/Application.java
src/com/vaadin/service/ApplicationContext.java
src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java
src/com/vaadin/terminal/gwt/server/WebApplicationContext.java

index a97ce0d682f5fbc23a9c8644f82fffd80285c8fb..2b132fee646e318eeea1ce36afd9b9906b82b458 100644 (file)
@@ -121,11 +121,6 @@ public abstract class Application implements URIHandler,
      */
     private URL applicationUrl;
 
-    /**
-     * The ID of the portlet window that this application runs in.
-     */
-    private String portletWindowId;
-
     /**
      * Name of the theme currently used by the application.
      */
@@ -188,92 +183,6 @@ public abstract class Application implements URIHandler,
      */
     private Terminal.ErrorListener errorHandler = this;
 
-    // TODO Document me!
-    public String getPortletWindowId() {
-        return portletWindowId;
-    }
-
-    // TODO Document me!
-    public void setPortletWindowId(String portletWindowId) {
-        this.portletWindowId = portletWindowId;
-    }
-
-    // TODO Document me!
-    @Deprecated
-    public static interface ResourceURLGenerator extends Serializable {
-
-        public String generateResourceURL(ApplicationResource resource,
-                String mapKey);
-
-        public boolean isResourceURL(URL context, String relativeUri);
-
-        public String getMapKey(URL context, String relativeUri);
-
-    }
-
-    /*
-     * Default resource URL generator for servlets
-     */
-    @Deprecated
-    private static ResourceURLGenerator defaultResourceURLGenerator = new ResourceURLGenerator() {
-        public String generateResourceURL(ApplicationResource resource,
-                String mapKey) {
-
-            final String filename = resource.getFilename();
-            if (filename == null) {
-                return "APP/" + mapKey + "/";
-            } else {
-                return "APP/" + mapKey + "/" + filename;
-            }
-
-        }
-
-        public boolean isResourceURL(URL context, String relativeUri) {
-            // If the relative uri is null, we are ready
-            if (relativeUri == null) {
-                return false;
-            }
-
-            // Resolves the prefix
-            String prefix = relativeUri;
-            final int index = relativeUri.indexOf('/');
-            if (index >= 0) {
-                prefix = relativeUri.substring(0, index);
-            }
-
-            // Handles the resource requests
-            return (prefix.equals("APP"));
-        }
-
-        public String getMapKey(URL context, String relativeUri) {
-            final int index = relativeUri.indexOf('/');
-            final int next = relativeUri.indexOf('/', index + 1);
-            if (next < 0) {
-                return null;
-            }
-            return relativeUri.substring(index + 1, next);
-        };
-
-    };
-
-    @Deprecated
-    private ResourceURLGenerator resourceURLGenerator = defaultResourceURLGenerator;
-
-    @Deprecated
-    public ResourceURLGenerator getResourceURLGenerator() {
-        return resourceURLGenerator;
-    }
-
-    @Deprecated
-    public void setResourceURLGenerator(
-            ResourceURLGenerator resourceURLGenerator) {
-        if (resourceURLGenerator == null) {
-            this.resourceURLGenerator = defaultResourceURLGenerator;
-        } else {
-            this.resourceURLGenerator = resourceURLGenerator;
-        }
-    }
-
     /**
      * <p>
      * Gets a window by name. Returns <code>null</code> if the application is
@@ -821,7 +730,7 @@ public abstract class Application implements URIHandler,
     @Deprecated
     public String getRelativeLocation(ApplicationResource resource) {
 
-        // FIXME Move to ApplicationContext
+        // FIXME Move to ApplicationContext?
 
         // Gets the key
         final String key = resourceKeyMap.get(resource);
@@ -831,7 +740,7 @@ public abstract class Application implements URIHandler,
             return null;
         }
 
-        return resourceURLGenerator.generateResourceURL(resource, key);
+        return context.generateApplicationResourceURL(resource, key);
     }
 
     /**
@@ -854,12 +763,13 @@ public abstract class Application implements URIHandler,
     @Deprecated
     public DownloadStream handleURI(URL context, String relativeUri) {
 
-        // FIXME Move to ApplicationContext
+        // FIXME Move to ApplicationContext? - public API, need to leave hook
+        // here
 
-        if (resourceURLGenerator.isResourceURL(context, relativeUri)) {
+        if (this.context.isApplicationResourceURL(context, relativeUri)) {
 
             // Handles the resource request
-            final String key = resourceURLGenerator.getMapKey(context,
+            final String key = this.context.getURLKey(context,
                     relativeUri);
             final ApplicationResource resource = keyResourceMap
                     .get(key);
index 756a8e50c86798eb271db4c2f15c6c48792d4f3d..ab201a4bd45b92db504fc6554d279cd391022bb9 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
 @ITMillApache2LicenseForJavaFiles@
  */
 
@@ -6,6 +6,7 @@ package com.vaadin.service;
 
 import java.io.File;
 import java.io.Serializable;
+import java.net.URL;
 import java.util.Collection;
 
 import com.vaadin.Application;
@@ -16,7 +17,7 @@ import com.vaadin.terminal.ApplicationResource;
  * context of the application. Each context is shared by all applications that
  * are open for one user. In a web-environment this corresponds to a
  * HttpSession.
- * 
+ *
  * @author IT Mill Ltd.
  * @version
  * @VERSION@
@@ -26,13 +27,13 @@ public interface ApplicationContext extends Serializable {
 
     /**
      * Returns application context base directory.
-     * 
+     *
      * Typically an application is deployed in a such way that is has an
      * application directory. For web applications this directory is the root
      * directory of the web applications. In some cases applications might not
      * have an application directory (for example web applications running
      * inside a war).
-     * 
+     *
      * @return The application base directory or null if the application has no
      *         base directory.
      */
@@ -40,46 +41,89 @@ public interface ApplicationContext extends Serializable {
 
     /**
      * Returns a collection of all the applications in this context.
-     * 
+     *
      * Each application context contains all active applications for one user.
-     * 
+     *
      * @return A collection containing all the applications in this context.
      */
     public Collection<Application> getApplications();
-    
+
     /**
-     * Adds a transaction listener to this context.
-     * 
-     * @param listener
-     *            the listener to be added.
-     * @see TransactionListener
+     * Adds a transaction listener to this context. The transaction listener is
+     * called before and after each each request related to this session except
+     * when serving static resources.
+     *
+     *
+     * @see com.vaadin.service.ApplicationContext#addTransactionListener(com.vaadin.service.ApplicationContext.TransactionListener)
      */
     public void addTransactionListener(TransactionListener listener);
 
     /**
      * Removes a transaction listener from this context.
-     * 
+     *
      * @param listener
      *            the listener to be removed.
      * @see TransactionListener
      */
     public void removeTransactionListener(TransactionListener listener);
 
+    /**
+     * Generate a URL that can be used as the relative location of e.g. an
+     * {@link ApplicationResource}.
+     * 
+     * @deprecated this is subject to change/removal from the interface
+     *
+     * @param resource
+     * @param urlKey
+     *            a key for the resource that can later be extracted from a URL
+     *            with {@link #getURLKey(URL, String)}
+     */
+    @Deprecated
+    public String generateApplicationResourceURL(ApplicationResource resource,
+            String urlKey);
+
+    /**
+     * Tests if a URL is for an application resource (APP/...).
+     * 
+     * @deprecated this is subject to change/removal from the interface
+     *
+     * @param context
+     * @param relativeUri
+     * @return
+     */
+    @Deprecated
+    public boolean isApplicationResourceURL(URL context, String relativeUri);
+
+    /**
+     * Gets the identifier (key) from an application resource URL. This key is
+     * the one that was given to
+     * {@link #generateApplicationResourceURL(ApplicationResource, String)} when
+     * creating the URL.
+     * 
+     * @deprecated this is subject to change/removal from the interface
+     *
+     * @param context
+     * @param relativeUri
+     * @return
+     */
+    @Deprecated
+    public String getURLKey(URL context, String relativeUri);
+
     /**
      * Interface for listening to transaction events. Implement this interface
      * to listen to all transactions between the client and the application.
-     * 
+     *
      */
     public interface TransactionListener extends Serializable {
 
         /**
          * Invoked at the beginning of every transaction.
-         * 
+         *
          * The transaction is linked to the context, not the application so if
          * you have multiple applications running in the same context you need
          * to check that the request is associated with the application you are
          * interested in. This can be done looking at the application parameter.
-         * 
+         *
          * @param application
          *            the Application object.
          * @param transactionData
@@ -90,12 +134,12 @@ public interface ApplicationContext extends Serializable {
 
         /**
          * Invoked at the end of every transaction.
-         * 
+         *
          * The transaction is linked to the context, not the application so if
          * you have multiple applications running in the same context you need
          * to check that the request is associated with the application you are
          * interested in. This can be done looking at the application parameter.
-         * 
+         *
          * @param applcation
          *            the Application object.
          * @param transactionData
index 0cfb04bb9123ca3d6f4fadc3daede6e17635d6b6..b465bf22588b374b0c24d5dedb5ef693230c1673 100644 (file)
@@ -10,9 +10,7 @@ import java.io.Serializable;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.net.MalformedURLException;
-import java.net.URL;
 import java.security.GeneralSecurityException;
-import java.util.Collection;
 import java.util.Date;
 import java.util.Enumeration;
 import java.util.Iterator;
@@ -45,7 +43,6 @@ import com.liferay.portal.kernel.util.PropsUtil;
 import com.vaadin.Application;
 import com.vaadin.Application.SystemMessages;
 import com.vaadin.external.org.apache.commons.fileupload.portlet.PortletFileUpload;
-import com.vaadin.terminal.ApplicationResource;
 import com.vaadin.terminal.DownloadStream;
 import com.vaadin.terminal.Terminal;
 import com.vaadin.ui.Window;
@@ -60,11 +57,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
 
     private static final String PORTAL_PARAMETER_VAADIN_THEME = "vaadin.theme";
 
-    /*
-     * TODO Big parts of this class are directly copy-pasted from
-     * AbstractApplicationServlet. On the long term, it would probably be wise
-     * to try to integrate the common parts into a shared super class.
-     */
+    // TODO some parts could be shared with AbstractApplicationServlet
 
     // TODO Can we close the application when the portlet is removed? Do we know
     // when the portlet is removed?
@@ -76,54 +69,6 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
 
     private boolean productionMode = false;
 
-    private static class PortletResourceURLGenerator implements
-            Application.ResourceURLGenerator {
-
-        private final MimeResponse response;
-
-        public PortletResourceURLGenerator(MimeResponse response) {
-            this.response = response;
-        }
-
-        public boolean isResourceURL(URL context, String relativeUri) {
-            // If the relative uri is null, we are ready
-            if (relativeUri == null) {
-                return false;
-            }
-
-            // Resolves the prefix
-            String prefix = relativeUri;
-            final int index = relativeUri.indexOf('/');
-            if (index >= 0) {
-                prefix = relativeUri.substring(0, index);
-            }
-
-            // Handles the resource requests
-            return (prefix.equals("APP"));
-        }
-
-        public String getMapKey(URL context, String relativeUri) {
-            final int index = relativeUri.indexOf('/');
-            final int next = relativeUri.indexOf('/', index + 1);
-            if (next < 0) {
-                return null;
-            }
-            return relativeUri.substring(index + 1, next);
-        }
-
-        public String generateResourceURL(ApplicationResource resource,
-                String mapKey) {
-            ResourceURL resourceURL = response.createResourceURL();
-            final String filename = resource.getFilename();
-            if (filename == null) {
-                resourceURL.setResourceID("APP/" + mapKey + "/");
-            } else {
-                resourceURL.setResourceID("APP/" + mapKey + "/" + filename);
-            }
-            return resourceURL.toString();
-        }
-    };
-
     @SuppressWarnings("unchecked")
     @Override
     public void init(PortletConfig config) throws PortletException {
@@ -376,11 +321,6 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
                 if (application == null) {
                     return;
                 }
-                if (response instanceof MimeResponse) {
-                    application
-                            .setResourceURLGenerator(new PortletResourceURLGenerator(
-                                    (MimeResponse) response));
-                }
 
                 /*
                  * Get or create an application context and an application
@@ -388,6 +328,10 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
                  */
                 PortletApplicationContext2 applicationContext = PortletApplicationContext2
                         .getApplicationContext(request.getPortletSession());
+                if (response instanceof MimeResponse) {
+                    applicationContext.setMimeResponse((MimeResponse) response);
+                }
+
                 PortletCommunicationManager applicationManager = applicationContext
                         .getApplicationManager(application);
 
@@ -756,10 +700,9 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
     private Application createApplication(PortletRequest request)
             throws PortletException, MalformedURLException {
         Application newApplication = getNewApplication(request);
-        newApplication.setPortletWindowId(request.getWindowID());
         final PortletApplicationContext2 context = PortletApplicationContext2
                 .getApplicationContext(request.getPortletSession());
-        context.addApplication(newApplication);
+        context.addApplication(newApplication, request.getWindowID());
         return newApplication;
     }
 
@@ -776,19 +719,17 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
 
         PortletApplicationContext2 context = PortletApplicationContext2
                 .getApplicationContext(session);
-
-        final Collection<Application> applications = context.getApplications();
-        for (Application sessionApplication : applications) {
-            if (request.getWindowID().equals(
-                    sessionApplication.getPortletWindowId())) {
-                if (sessionApplication.isRunning()) {
-                    return sessionApplication;
-                }
-                PortletApplicationContext2.getApplicationContext(session)
-                        .removeApplication(sessionApplication);
-                break;
-            }
+        Application application = context.getApplicationForWindowId(request
+                .getWindowID());
+        if (application == null) {
+            return null;
+        }
+        if (application.isRunning()) {
+            return application;
         }
+        // application found but not running
+        PortletApplicationContext2.getApplicationContext(session)
+                .removeApplication(application);
 
         return null;
     }
@@ -846,7 +787,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
             systemMessages = getSystemMessages();
         } catch (SystemMessageException e) {
             // failing to get the system messages is always a problem
-            throw new PortletException("CommunicationError!", e);
+            throw new PortletException("Failed to obtain system messages!", e);
         }
 
         page.write("<script type=\"text/javascript\">\n");
index 59a1827f62d7fe4d44b130ef6f9ed53288897ac0..46a4d8bb5b02dc58f92e90a3d6a0eaef589e431b 100644 (file)
@@ -68,12 +68,12 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
      */
     public static final String VERSION;
     /**
-     * Major version number. For example 5 in 6.2.0.
+     * Major version number. For example 6 in 6.2.0.
      */
     public static final int VERSION_MAJOR;
 
     /**
-     * Minor version number. For example 1 in 6.2.0.
+     * Minor version number. For example 2 in 6.2.0.
      */
     public static final int VERSION_MINOR;
 
@@ -119,7 +119,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
     /**
      * This request attribute forces widgetsets to be loaded from under the
      * specified base path; e.g shared widgetset for all portlets in a portal.
-     * 
+     *
      * It is set by the {@link ApplicationPortlet} (Portlet 1.0) based on
      * {@link Constants.PORTAL_PARAMETER_VAADIN_RESOURCE_PATH} and read by
      * {@link AbstractApplicationServlet}.
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java b/src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java
new file mode 100644 (file)
index 0000000..39d660c
--- /dev/null
@@ -0,0 +1,191 @@
+package com.vaadin.terminal.gwt.server;\r
+\r
+import java.io.PrintWriter;\r
+import java.io.Serializable;\r
+import java.io.StringWriter;\r
+import java.net.URL;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.LinkedList;\r
+\r
+import javax.servlet.http.HttpSessionBindingEvent;\r
+import javax.servlet.http.HttpSessionBindingListener;\r
+\r
+import com.vaadin.Application;\r
+import com.vaadin.service.ApplicationContext;\r
+import com.vaadin.terminal.ApplicationResource;\r
+\r
+/**\r
+ * Base class for web application contexts (including portlet contexts) that\r
+ * handles the common tasks.\r
+ */\r
+public abstract class AbstractWebApplicationContext implements\r
+        ApplicationContext, HttpSessionBindingListener, Serializable {\r
+\r
+    protected Collection<TransactionListener> listeners = Collections\r
+            .synchronizedList(new LinkedList<TransactionListener>());\r
+\r
+    protected final HashSet<Application> applications = new HashSet<Application>();\r
+\r
+    protected WebBrowser browser = new WebBrowser();\r
+\r
+    protected HashMap<Application, AbstractCommunicationManager> applicationToAjaxAppMgrMap = new HashMap<Application, AbstractCommunicationManager>();\r
+\r
+    public void addTransactionListener(TransactionListener listener) {\r
+        listeners.add(listener);\r
+    }\r
+\r
+    public void removeTransactionListener(TransactionListener listener) {\r
+        listeners.remove(listener);\r
+    }\r
+\r
+    /**\r
+     * Sends a notification that a transaction is starting.\r
+     *\r
+     * @param application\r
+     *            The application associated with the transaction.\r
+     * @param request\r
+     *            the HTTP or portlet request that triggered the transaction.\r
+     */\r
+    protected void startTransaction(Application application, Object request) {\r
+        synchronized (listeners) {\r
+            for (TransactionListener listener : listeners) {\r
+                listener.transactionStart(application, request);\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Sends a notification that a transaction has ended.\r
+     *\r
+     * @param application\r
+     *            The application associated with the transaction.\r
+     * @param request\r
+     *            the HTTP or portlet request that triggered the transaction.\r
+     */\r
+    protected void endTransaction(Application application, Object request) {\r
+        LinkedList<Exception> exceptions = null;\r
+\r
+        synchronized (listeners) {\r
+            for (TransactionListener listener : listeners) {\r
+                try {\r
+                    listener.transactionEnd(application, request);\r
+                } catch (final RuntimeException t) {\r
+                    if (exceptions == null) {\r
+                        exceptions = new LinkedList<Exception>();\r
+                    }\r
+                    exceptions.add(t);\r
+                }\r
+            }\r
+        }\r
+\r
+        // If any runtime exceptions occurred, throw a combined exception\r
+        if (exceptions != null) {\r
+            final StringBuffer msg = new StringBuffer();\r
+            for (Exception e : exceptions) {\r
+                if (msg.length() == 0) {\r
+                    msg.append("\n\n--------------------------\n\n");\r
+                }\r
+                msg.append(e.getMessage() + "\n");\r
+                final StringWriter trace = new StringWriter();\r
+                e.printStackTrace(new PrintWriter(trace, true));\r
+                msg.append(trace.toString());\r
+            }\r
+            throw new RuntimeException(msg.toString());\r
+        }\r
+    }\r
+\r
+    /**\r
+     * @see javax.servlet.http.HttpSessionBindingListener#valueBound(HttpSessionBindingEvent)\r
+     */\r
+    public void valueBound(HttpSessionBindingEvent arg0) {\r
+        // We are not interested in bindings\r
+    }\r
+\r
+    /**\r
+     * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(HttpSessionBindingEvent)\r
+     */\r
+    public void valueUnbound(HttpSessionBindingEvent event) {\r
+        // If we are going to be unbound from the session, the session must be\r
+        // closing\r
+        try {\r
+            while (!applications.isEmpty()) {\r
+                final Application app = applications.iterator().next();\r
+                app.close();\r
+                removeApplication(app);\r
+            }\r
+        } catch (Exception e) {\r
+            // This should never happen but is possible with rare\r
+            // configurations (e.g. robustness tests). If you have one\r
+            // thread doing HTTP socket write and another thread trying to\r
+            // remove same application here. Possible if you got e.g. session\r
+            // lifetime 1 min but socket write may take longer than 1 min.\r
+            // FIXME: Handle exception\r
+            System.err.println("Could not remove application, leaking memory.");\r
+            e.printStackTrace();\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Get the web browser associated with this application context.\r
+     *\r
+     * Because application context is related to the http session and server\r
+     * maintains one session per browser-instance, each context has exactly one\r
+     * web browser associated with it.\r
+     *\r
+     * @return\r
+     */\r
+    public WebBrowser getBrowser() {\r
+        return browser;\r
+    }\r
+\r
+    public Collection<Application> getApplications() {\r
+        return Collections.unmodifiableCollection(applications);\r
+    }\r
+\r
+    protected void removeApplication(Application application) {\r
+        applications.remove(application);\r
+        applicationToAjaxAppMgrMap.remove(application);\r
+    }\r
+\r
+    public String generateApplicationResourceURL(\r
+            ApplicationResource resource, String mapKey) {\r
+\r
+        final String filename = resource.getFilename();\r
+        if (filename == null) {\r
+            return "APP/" + mapKey + "/";\r
+        } else {\r
+            return "APP/" + mapKey + "/" + filename;\r
+        }\r
+\r
+    }\r
+\r
+    public boolean isApplicationResourceURL(URL context, String relativeUri) {\r
+        // If the relative uri is null, we are ready\r
+        if (relativeUri == null) {\r
+            return false;\r
+        }\r
+\r
+        // Resolves the prefix\r
+        String prefix = relativeUri;\r
+        final int index = relativeUri.indexOf('/');\r
+        if (index >= 0) {\r
+            prefix = relativeUri.substring(0, index);\r
+        }\r
+\r
+        // Handles the resource requests\r
+        return (prefix.equals("APP"));\r
+    }\r
+\r
+    public String getURLKey(URL context, String relativeUri) {\r
+        final int index = relativeUri.indexOf('/');\r
+        final int next = relativeUri.indexOf('/', index + 1);\r
+        if (next < 0) {\r
+            return null;\r
+        }\r
+        return relativeUri.substring(index + 1, next);\r
+    }\r
+\r
+}
\ No newline at end of file
index fce8ac405e2d22edb980d800be1b9e495b8c86f5..3af45acfafc3957703dcb8ba3cf80894f174cc0c 100644 (file)
@@ -1,16 +1,10 @@
 package com.vaadin.terminal.gwt.server;
 
 import java.io.File;
-import java.io.PrintWriter;
 import java.io.Serializable;
-import java.io.StringWriter;
 import java.net.URL;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.LinkedHashSet;
-import java.util.LinkedList;
 import java.util.Map;
 import java.util.Set;
 
@@ -18,17 +12,17 @@ import javax.portlet.ActionRequest;
 import javax.portlet.ActionResponse;
 import javax.portlet.EventRequest;
 import javax.portlet.EventResponse;
-import javax.portlet.PortletRequest;
+import javax.portlet.MimeResponse;
 import javax.portlet.PortletSession;
 import javax.portlet.RenderRequest;
 import javax.portlet.RenderResponse;
 import javax.portlet.ResourceRequest;
 import javax.portlet.ResourceResponse;
-import javax.servlet.http.HttpSessionBindingEvent;
+import javax.portlet.ResourceURL;
 import javax.servlet.http.HttpSessionBindingListener;
 
 import com.vaadin.Application;
-import com.vaadin.service.ApplicationContext;
+import com.vaadin.terminal.ApplicationResource;
 
 /**
  * TODO Write documentation, fix JavaDoc tags.
@@ -39,24 +33,15 @@ import com.vaadin.service.ApplicationContext;
  * @author peholmst
  */
 @SuppressWarnings("serial")
-public class PortletApplicationContext2 implements ApplicationContext,
-        HttpSessionBindingListener, Serializable {
-
-    protected LinkedList<TransactionListener> listeners;
+public class PortletApplicationContext2 extends AbstractWebApplicationContext {
 
     protected Map<Application, Set<PortletListener>> portletListeners = new HashMap<Application, Set<PortletListener>>();
 
     protected transient PortletSession session;
 
-    protected final HashSet<Application> applications = new HashSet<Application>();
-
-    protected WebBrowser browser = new WebBrowser();
+    protected HashMap<String, Application> portletWindowIdToApplicationMap = new HashMap<String, Application>();
 
-    protected HashMap<Application, PortletCommunicationManager> applicationToAjaxAppMgrMap = new HashMap<Application, PortletCommunicationManager>();
-
-    public Collection<Application> getApplications() {
-        return Collections.unmodifiableCollection(applications);
-    }
+    private MimeResponse mimeResponse;
 
     public File getBaseDirectory() {
         String resultPath = session.getPortletContext().getRealPath("/");
@@ -74,22 +59,9 @@ public class PortletApplicationContext2 implements ApplicationContext,
         return null;
     }
 
-    public void addTransactionListener(TransactionListener listener) {
-        if (listeners == null) {
-            listeners = new LinkedList<TransactionListener>();
-        }
-        listeners.add(listener);
-    }
-
-    public void removeTransactionListener(TransactionListener listener) {
-        if (listeners != null) {
-            listeners.remove(listener);
-        }
-    }
-
     protected PortletCommunicationManager getApplicationManager(
             Application application) {
-        PortletCommunicationManager mgr = applicationToAjaxAppMgrMap
+        PortletCommunicationManager mgr = (PortletCommunicationManager) applicationToAjaxAppMgrMap
                 .get(application);
 
         if (mgr == null) {
@@ -116,90 +88,25 @@ public class PortletApplicationContext2 implements ApplicationContext,
         return cx;
     }
 
-    public WebBrowser getBrowser() {
-        return browser;
-    }
-
-    @SuppressWarnings("unchecked")
-    protected void startTransaction(Application application,
-            PortletRequest request) {
-        if (listeners == null) {
-            return;
-        }
-        for (TransactionListener listener : (LinkedList<TransactionListener>) listeners
-                .clone()) {
-            listener.transactionStart(application, request);
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    protected void endTransaction(Application application,
-            PortletRequest request) {
-        if (listeners == null) {
-            return;
-        }
-
-        LinkedList<Exception> exceptions = null;
-        for (TransactionListener listener : (LinkedList<TransactionListener>) listeners
-                .clone()) {
-            try {
-                listener.transactionEnd(application, request);
-            } catch (final RuntimeException e) {
-                if (exceptions == null) {
-                    exceptions = new LinkedList<Exception>();
-                }
-                exceptions.add(e);
-            }
-        }
-
-        // If any runtime exceptions occurred, throw a combined exception
-        if (exceptions != null) {
-            final StringBuffer msg = new StringBuffer();
-            for (Exception e : exceptions) {
-                if (msg.length() == 0) {
-                    msg.append("\n\n--------------------------\n\n");
-                }
-                msg.append(e.getMessage() + "\n");
-                final StringWriter trace = new StringWriter();
-                e.printStackTrace(new PrintWriter(trace, true));
-                msg.append(trace.toString());
-            }
-            throw new RuntimeException(msg.toString());
-        }
-    }
-
+    @Override
     protected void removeApplication(Application application) {
-        applications.remove(application);
-        applicationToAjaxAppMgrMap.remove(application);
+        super.removeApplication(application);
+        // values() is backed by map, removes the key-value pair from the map
+        portletWindowIdToApplicationMap.values().remove(application);
     }
 
-    protected void addApplication(Application application) {
+    protected void addApplication(Application application,
+            String portletWindowId) {
         applications.add(application);
+        portletWindowIdToApplicationMap.put(portletWindowId, application);
     }
 
-    public PortletSession getPortletSession() {
-        return session;
+    public Application getApplicationForWindowId(String portletWindowId) {
+        return portletWindowIdToApplicationMap.get(portletWindowId);
     }
 
-    public void valueBound(HttpSessionBindingEvent event) {
-        // We are not interested in bindings
-    }
-
-    public void valueUnbound(HttpSessionBindingEvent event) {
-        // If we are going to be unbound from the session, the session must be
-        // closing
-        try {
-            while (!applications.isEmpty()) {
-                final Application app = applications.iterator().next();
-                app.close();
-                applicationToAjaxAppMgrMap.remove(app);
-                removeApplication(app);
-            }
-        } catch (Exception e) {
-            // FIXME: Handle exception
-            System.err.println("Could not remove application, leaking memory.");
-            e.printStackTrace();
-        }
+    public PortletSession getPortletSession() {
+        return session;
     }
 
     public void addPortletListener(Application app, PortletListener listener) {
@@ -273,4 +180,29 @@ public class PortletApplicationContext2 implements ApplicationContext,
                 ResourceResponse response);
     }
 
+    /**
+     * This is for use by {@link AbstractApplicationPortlet} only.
+     *
+     * TODO cleaner implementation, now "semi-static"!
+     *
+     * @param mimeResponse
+     */
+    void setMimeResponse(MimeResponse mimeResponse) {
+        this.mimeResponse = mimeResponse;
+    }
+
+    @Override
+    public String generateApplicationResourceURL(
+            ApplicationResource resource,
+            String mapKey) {
+        ResourceURL resourceURL = mimeResponse.createResourceURL();
+        final String filename = resource.getFilename();
+        if (filename == null) {
+            resourceURL.setResourceID("APP/" + mapKey + "/");
+        } else {
+            resourceURL.setResourceID("APP/" + mapKey + "/" + filename);
+        }
+        return resourceURL.toString();
+    }
+
 }
index 109095e90736d2ab918d8cf421fd1a8330a3a3e9..a4a96500b144d50ad177720709e4b9cf5c846e65 100644 (file)
@@ -5,28 +5,15 @@
 package com.vaadin.terminal.gwt.server;
 
 import java.io.File;
-import java.io.PrintWriter;
-import java.io.Serializable;
-import java.io.StringWriter;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
 
-import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
-import javax.servlet.http.HttpSessionBindingEvent;
 import javax.servlet.http.HttpSessionBindingListener;
 
 import com.vaadin.Application;
-import com.vaadin.service.ApplicationContext;
 
 /**
  * Web application context for Vaadin applications.
- * 
+ *
  * This is automatically added as a {@link HttpSessionBindingListener} when
  * added to a {@link HttpSession}.
  *
@@ -36,20 +23,10 @@ import com.vaadin.service.ApplicationContext;
  * @since 3.1
  */
 @SuppressWarnings("serial")
-public class WebApplicationContext implements ApplicationContext,
-        HttpSessionBindingListener, Serializable {
-
-    protected List<TransactionListener> listeners = Collections
-            .synchronizedList(new LinkedList<TransactionListener>());
+public class WebApplicationContext extends AbstractWebApplicationContext {
 
     protected transient HttpSession session;
 
-    protected final HashSet<Application> applications = new HashSet<Application>();
-
-    protected WebBrowser browser = new WebBrowser();
-
-    protected HashMap<Application, CommunicationManager> applicationToAjaxAppMgrMap = new HashMap<Application, CommunicationManager>();
-
     /**
      * Creates a new Web Application Context.
      *
@@ -81,15 +58,6 @@ public class WebApplicationContext implements ApplicationContext,
         return session;
     }
 
-    /**
-     * Gets the applications in this context.
-     *
-     * @see com.vaadin.service.ApplicationContext#getApplications()
-     */
-    public Collection<Application> getApplications() {
-        return Collections.unmodifiableCollection(applications);
-    }
-
     /**
      * Gets the application context for an HttpSession.
      *
@@ -111,142 +79,10 @@ public class WebApplicationContext implements ApplicationContext,
         return cx;
     }
 
-    /**
-     * Adds a transaction listener to this context. The transaction listener is
-     * called before and after each each HTTP request related to this session
-     * except when serving static resources.
-     *
-     *
-     * @see com.vaadin.service.ApplicationContext#addTransactionListener(com.vaadin.service.ApplicationContext.TransactionListener)
-     */
-    public void addTransactionListener(TransactionListener listener) {
-        listeners.add(listener);
-    }
-
-    /**
-     * Removes a transaction listener from this context. The transaction
-     * listener is called before and after each each HTTP request related to
-     * this session except when serving static resources.
-     *
-     * @see com.vaadin.service.ApplicationContext#removeTransactionListener(com.vaadin.service.ApplicationContext.TransactionListener)
-     */
-    public void removeTransactionListener(TransactionListener listener) {
-        listeners.remove(listener);
-
-    }
-
-    /**
-     * Sends a notification that a transaction is starting.
-     *
-     * @param application
-     *            The application associated with the transaction.
-     * @param request
-     *            the HTTP request that triggered the transaction.
-     */
-    protected void startTransaction(Application application,
-            HttpServletRequest request) {
-        synchronized (listeners) {
-            for (TransactionListener listener : listeners) {
-                listener.transactionStart(application, request);
-            }
-        }
-    }
-
-    /**
-     * Sends a notification that a transaction has ended.
-     *
-     * @param application
-     *            The application associated with the transaction.
-     * @param request
-     *            the HTTP request that triggered the transaction.
-     */
-    protected void endTransaction(Application application,
-            HttpServletRequest request) {
-        LinkedList<Exception> exceptions = null;
-
-        synchronized (listeners) {
-            for (TransactionListener listener : listeners) {
-                try {
-                    listener.transactionEnd(application, request);
-                } catch (final RuntimeException t) {
-                    if (exceptions == null) {
-                        exceptions = new LinkedList<Exception>();
-                    }
-                    exceptions.add(t);
-                }
-            }
-        }
-
-        // If any runtime exceptions occurred, throw a combined exception
-        if (exceptions != null) {
-            final StringBuffer msg = new StringBuffer();
-            for (final Iterator i = exceptions.iterator(); i.hasNext();) {
-                final RuntimeException e = (RuntimeException) i.next();
-                if (msg.length() == 0) {
-                    msg.append("\n\n--------------------------\n\n");
-                }
-                msg.append(e.getMessage() + "\n");
-                final StringWriter trace = new StringWriter();
-                e.printStackTrace(new PrintWriter(trace, true));
-                msg.append(trace.toString());
-            }
-            throw new RuntimeException(msg.toString());
-        }
-    }
-
-    protected void removeApplication(Application application) {
-        applications.remove(application);
-        applicationToAjaxAppMgrMap.remove(application);
-    }
-
     protected void addApplication(Application application) {
         applications.add(application);
     }
 
-    /**
-     * @see javax.servlet.http.HttpSessionBindingListener#valueBound(HttpSessionBindingEvent)
-     */
-    public void valueBound(HttpSessionBindingEvent arg0) {
-        // We are not interested in bindings
-    }
-
-    /**
-     * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(HttpSessionBindingEvent)
-     */
-    public void valueUnbound(HttpSessionBindingEvent event) {
-        // If we are going to be unbound from the session, the session must be
-        // closing
-        try {
-            while (!applications.isEmpty()) {
-                final Application app = applications.iterator().next();
-                app.close();
-                removeApplication(app);
-            }
-        } catch (Exception e) {
-            // This should never happen but is possible with rare
-            // configurations (e.g. robustness tests). If you have one
-            // thread doing HTTP socket write and another thread trying to
-            // remove same application here. Possible if you got e.g. session
-            // lifetime 1 min but socket write may take longer than 1 min.
-            // FIXME: Handle exception
-            System.err.println("Could not remove application, leaking memory.");
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     * Get the web browser associated with this application context.
-     *
-     * Because application context is related to the http session and server
-     * maintains one session per browser-instance, each context has exactly one
-     * web browser associated with it.
-     *
-     * @return
-     */
-    public WebBrowser getBrowser() {
-        return browser;
-    }
-
     /**
      * Gets communication manager for an application.
      *
@@ -258,7 +94,8 @@ public class WebApplicationContext implements ApplicationContext,
      */
     protected CommunicationManager getApplicationManager(
             Application application, AbstractApplicationServlet servlet) {
-        CommunicationManager mgr = applicationToAjaxAppMgrMap.get(application);
+        CommunicationManager mgr = (CommunicationManager) applicationToAjaxAppMgrMap
+                .get(application);
 
         if (mgr == null) {
             // Creates new manager