]> source.dussan.org Git - vaadin-framework.git/commitdiff
#3117 inter-portlet event support (JSR-286), some support for custom portlet actions
authorHenri Sara <henri.sara@itmill.com>
Tue, 1 Dec 2009 15:00:49 +0000 (15:00 +0000)
committerHenri Sara <henri.sara@itmill.com>
Tue, 1 Dec 2009 15:00:49 +0000 (15:00 +0000)
svn changeset:10119/svn branch:6.2

WebContent/WEB-INF/liferay-display.xml
WebContent/WEB-INF/portlet.xml
WebContent/WEB-INF/web.xml
build/package/WebContent/WEB-INF/web.xml
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/PortletApplicationContext2.java

index 2981e08fd456ce703d77c494c890276df537b9d4..302f9961dd18ff28db2bbd86605e08ebb5531fa6 100644 (file)
@@ -18,6 +18,9 @@
                                <portlet id="AddressBookPortlet" />
                                <portlet id="CalcPortlet"/>
                                <portlet id="SamplerPortlet"/>
-                               <portlet id="HelloWorldEventPortlet"/>
+                               <!--
+                               <portlet id="InterPortletEventPortlet" />
+                               <portlet id="VaadinInterPortletEventPortlet" />
+                               -->
         </category>
 </display>
\ No newline at end of file
index c91bac7589d5da0a7c9165e08484e78a2d51a4db..b4a40e77aa2e03244e613eb99d10d9e04688799b 100644 (file)
                        <title>HelloWorld</title>
                        <short-title>HelloWorld</short-title>
                </portlet-info>         
+       </portlet>
+       
+       <!--
+       <portlet>
+               <portlet-name>VaadinInterPortletEventPortlet</portlet-name>
+               <display-name>Hello World Event</display-name>
+               <portlet-class>com.vaadin.terminal.gwt.server.ApplicationPortlet2</portlet-class>
+               <init-param>
+                       <name>application</name>
+                       <value>com.vaadin.demo.portlet.VaadinInterPortletEventPortlet</value>
+               </init-param>
+               <init-param>
+                       <name>widgetset</name>
+                       <value>com.vaadin.demo.sampler.gwt.SamplerWidgetSet</value>
+               </init-param>
+               <supports>
+                       <mime-type>text/html</mime-type>
+                       <portlet-mode>view</portlet-mode>
+               </supports>
+               <portlet-info>
+                       <title>Inter-portlet events</title>
+                       <short-title>Inter-portlet events</short-title>
+               </portlet-info>         
                <supported-processing-event>
                <qname xmlns:vaadin="http://www.vaadin.com/hello">vaadin:Hello</qname>
                </supported-processing-event>
+               <supported-processing-event>
+               <qname xmlns:vaadin="http://www.vaadin.com/hello">vaadin:ReplyToVaadin</qname>
+               </supported-processing-event>
                <supported-publishing-event>
                <qname xmlns:vaadin="http://www.vaadin.com/hello">vaadin:Reply</qname>
                </supported-publishing-event>
+               <supported-publishing-event>
+               <qname xmlns:vaadin="http://www.vaadin.com/hello">vaadin:FromVaadin</qname>
+               </supported-publishing-event>
        </portlet>
        
        <portlet>
-               <portlet-name>HelloWorldEventPortlet</portlet-name>
+               <portlet-name>InterPortletEventPortlet</portlet-name>
                <display-name>Hello World Event (non-Vaadin)</display-name>
-               <portlet-class>com.vaadin.demo.HelloWorldEventPortlet</portlet-class>
+               <portlet-class>com.vaadin.demo.portlet.InterPortletEventPortlet</portlet-class>
                <supports>
                        <mime-type>text/html</mime-type>
                        <portlet-mode>view</portlet-mode>
                </supports>
                <portlet-info>
-                       <title>HelloWorldEvent (non-Vaadin)</title>
-                       <short-title>HelloWorldEvent (non-Vaadin)</short-title>
+                       <title>Inter-portlet events (non-Vaadin)</title>
+                       <short-title>Inter-portlet events (non-Vaadin)</short-title>
                </portlet-info>
                <supported-processing-event>
                <qname xmlns:vaadin="http://www.vaadin.com/hello">vaadin:Reply</qname>
                </supported-processing-event>
+               <supported-processing-event>
+               <qname xmlns:vaadin="http://www.vaadin.com/hello">vaadin:FromVaadin</qname>
+               </supported-processing-event>
                <supported-publishing-event>
                <qname xmlns:vaadin="http://www.vaadin.com/hello">vaadin:Hello</qname>
                </supported-publishing-event>
+               <supported-publishing-event>
+               <qname xmlns:vaadin="http://www.vaadin.com/hello">vaadin:ReplyToVaadin</qname>
+               </supported-publishing-event>
        </portlet>
+       -->
 
        <portlet>
                <portlet-name>AddressBookPortlet</portlet-name>
index ce3c2bba13564986a7a2be78958a2aecb0d899d3..2e2c1b680e825760771261e8ef35133fba969622 100644 (file)
                <servlet-class>com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class>\r
                <init-param>\r
                        <param-name>application</param-name>\r
-                       <param-value>com.vaadin.demo.PortletDemo</param-value>\r
+                       <param-value>com.vaadin.demo.portlet.PortletDemo</param-value>\r
                </init-param>\r
        </servlet>      \r
 \r
index f80129b810e3921f8f3f827e076e2bd2289fff9c..cfbe2b41bc68c9cdf6ae15f9de9f1146aaa36dff 100644 (file)
                <servlet-class>com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class>
                <init-param>
                        <param-name>application</param-name>
-                       <param-value>com.vaadin.demo.PortletDemo</param-value>
+                       <param-value>com.vaadin.demo.portlet.PortletDemo</param-value>
                </init-param>
        </servlet>
 
index 2b132fee646e318eeea1ce36afd9b9906b82b458..5d10b215e4c6d25d80c80ea899119994ce56c311 100644 (file)
@@ -722,10 +722,14 @@ public abstract class Application implements URIHandler,
 
     /**
      * Gets the relative uri of the resource.
+     * 
+     * This method can only be called from within the processing of a UIDL
+     * request, not from a background thread.
      *
      * @param resource
      *            the resource to get relative location.
-     * @return the relative uri of the resource.
+     * @return the relative uri of the resource or null if called in a
+     *         background thread
      */
     @Deprecated
     public String getRelativeLocation(ApplicationResource resource) {
index ab201a4bd45b92db504fc6554d279cd391022bb9..3d2c76c8d0baf71fcf1571127bbf547f9794fd47 100644 (file)
@@ -71,6 +71,10 @@ public interface ApplicationContext extends Serializable {
      * Generate a URL that can be used as the relative location of e.g. an
      * {@link ApplicationResource}.
      * 
+     * This method should only be called from the processing of a UIDL request,
+     * not from a background thread. The return value is null if used outside a
+     * suitable request.
+     * 
      * @deprecated this is subject to change/removal from the interface
      *
      * @param resource
@@ -84,7 +88,7 @@ public interface ApplicationContext extends Serializable {
 
     /**
      * Tests if a URL is for an application resource (APP/...).
-     * 
+     *
      * @deprecated this is subject to change/removal from the interface
      *
      * @param context
@@ -99,7 +103,7 @@ public interface ApplicationContext extends Serializable {
      * 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
index 5c1396b449df7bf200a3d8fa51ac6d130ae8536d..9a5f4f0fb0d8d97a6c21624e3be41156467a4d78 100644 (file)
@@ -49,7 +49,7 @@ import com.vaadin.ui.Window;
 
 /**
  * TODO Document me!
- * 
+ *
  * @author peholmst
  */
 public abstract class AbstractApplicationPortlet extends GenericPortlet
@@ -128,7 +128,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
 
     /**
      * Gets an application property value.
-     * 
+     *
      * @param parameterName
      *            the Name or the parameter.
      * @return String value or null if not found
@@ -149,7 +149,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
 
     /**
      * Gets an system property value.
-     * 
+     *
      * @param parameterName
      *            the Name or the parameter.
      * @return String value or null if not found
@@ -178,7 +178,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
 
     /**
      * Gets an application or system property value.
-     * 
+     *
      * @param parameterName
      *            the Name or the parameter.
      * @param defaultValue
@@ -209,7 +209,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
      * Return the URL from where static files, e.g. the widgetset and the theme,
      * are served. In a standard configuration the VAADIN folder inside the
      * returned folder is what is used for widgetsets and themes.
-     * 
+     *
      * @param request
      * @return The location of static resources (inside which there should be a
      *         VAADIN directory). Does not end with a slash (/).
@@ -233,7 +233,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
     }
 
     enum RequestType {
-        FILE_UPLOAD, UIDL, RENDER, STATIC_FILE, APPLICATION_RESOURCE, DUMMY, EVENT, UNKNOWN;
+        FILE_UPLOAD, UIDL, RENDER, STATIC_FILE, APPLICATION_RESOURCE, DUMMY, EVENT, ACTION, UNKNOWN;
     }
 
     protected RequestType getRequestType(PortletRequest request) {
@@ -252,6 +252,9 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
         } else if (request instanceof ActionRequest) {
             if (isFileUploadRequest((ActionRequest) request)) {
                 return RequestType.FILE_UPLOAD;
+            } else {
+                // action other than upload
+                return RequestType.ACTION;
             }
         } else if (request instanceof EventRequest) {
             return RequestType.EVENT;
@@ -281,7 +284,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
     /**
      * Returns true if the servlet is running in production mode. Production
      * mode disables all debug facilities.
-     * 
+     *
      * @return true if in production mode, false if in debug mode
      */
     public boolean isProductionMode() {
@@ -331,9 +334,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
                  */
                 PortletApplicationContext2 applicationContext = PortletApplicationContext2
                         .getApplicationContext(request.getPortletSession());
-                if (response instanceof MimeResponse) {
-                    applicationContext.setMimeResponse((MimeResponse) response);
-                }
+                applicationContext.setResponse(response);
 
                 PortletCommunicationManager applicationManager = applicationContext
                         .getApplicationManager(application);
@@ -445,6 +446,10 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
                     } else if (requestType == RequestType.RENDER) {
                         writeAjaxPage((RenderRequest) request,
                                 (RenderResponse) response, window, application);
+                    } else if (requestType == RequestType.EVENT) {
+                        // nothing to do, listeners do all the work
+                    } else if (requestType == RequestType.ACTION) {
+                        // nothing to do, listeners do all the work
                     } else {
                         throw new IllegalStateException(
                                 "handleRequest() without anything to do - should never happen!");
@@ -929,7 +934,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
 
     /**
      * Returns the theme for given request/window
-     * 
+     *
      * @param request
      * @param window
      * @return
@@ -980,7 +985,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
 
     /**
      * Get system messages from the current application class
-     * 
+     *
      * @return
      */
     protected SystemMessages getSystemMessages() {
@@ -1053,7 +1058,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
      * Send notification to client's application. Used to notify client of
      * critical errors and session expiration due to long inactivity. Server has
      * no knowledge of what application client refers to.
-     * 
+     *
      * @param request
      *            the Portlet request instance.
      * @param response
index 3af45acfafc3957703dcb8ba3cf80894f174cc0c..f6217774e2e8e38ad65e249c766c0018198a138f 100644 (file)
@@ -13,16 +13,22 @@ import javax.portlet.ActionResponse;
 import javax.portlet.EventRequest;
 import javax.portlet.EventResponse;
 import javax.portlet.MimeResponse;
+import javax.portlet.PortletResponse;
 import javax.portlet.PortletSession;
+import javax.portlet.PortletURL;
 import javax.portlet.RenderRequest;
 import javax.portlet.RenderResponse;
 import javax.portlet.ResourceRequest;
 import javax.portlet.ResourceResponse;
 import javax.portlet.ResourceURL;
+import javax.portlet.StateAwareResponse;
 import javax.servlet.http.HttpSessionBindingListener;
+import javax.xml.namespace.QName;
 
 import com.vaadin.Application;
 import com.vaadin.terminal.ApplicationResource;
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.ui.Window;
 
 /**
  * TODO Write documentation, fix JavaDoc tags.
@@ -41,7 +47,10 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
 
     protected HashMap<String, Application> portletWindowIdToApplicationMap = new HashMap<String, Application>();
 
-    private MimeResponse mimeResponse;
+    private PortletResponse response;
+
+    private Map<String, QName> eventActionDestinationMap = new HashMap<String, QName>();
+    private Map<String, Serializable> eventActionValueMap = new HashMap<String, Serializable>();
 
     public File getBaseDirectory() {
         String resultPath = session.getPortletContext().getRealPath("/");
@@ -137,10 +146,20 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
 
     public void firePortletActionRequest(Application app,
             ActionRequest request, ActionResponse response) {
-        Set<PortletListener> listeners = portletListeners.get(app);
-        if (listeners != null) {
-            for (PortletListener l : listeners) {
-                l.handleActionRequest(request, response);
+        String key = request.getParameter(ActionRequest.ACTION_NAME);
+        if (eventActionDestinationMap.containsKey(key)) {
+            // this action request is only to send queued portlet events
+            response.setEvent(eventActionDestinationMap.get(key), eventActionValueMap
+                    .get(key));
+            // cleanup
+            eventActionDestinationMap.remove(key);
+            eventActionValueMap.remove(key);
+        } else {
+            Set<PortletListener> listeners = portletListeners.get(app);
+            if (listeners != null) {
+                for (PortletListener l : listeners) {
+                    l.handleActionRequest(request, response);
+                }
             }
         }
     }
@@ -187,22 +206,92 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
      *
      * @param mimeResponse
      */
-    void setMimeResponse(MimeResponse mimeResponse) {
-        this.mimeResponse = mimeResponse;
+    void setResponse(PortletResponse response) {
+        this.response = response;
     }
 
     @Override
     public String generateApplicationResourceURL(
             ApplicationResource resource,
             String mapKey) {
-        ResourceURL resourceURL = mimeResponse.createResourceURL();
-        final String filename = resource.getFilename();
-        if (filename == null) {
-            resourceURL.setResourceID("APP/" + mapKey + "/");
+        if (response instanceof MimeResponse) {
+            ResourceURL resourceURL = ((MimeResponse) response)
+                    .createResourceURL();
+            final String filename = resource.getFilename();
+            if (filename == null) {
+                resourceURL.setResourceID("APP/" + mapKey + "/");
+            } else {
+                resourceURL.setResourceID("APP/" + mapKey + "/" + filename);
+            }
+            return resourceURL.toString();
+        } else {
+            // in a background thread or otherwise outside a request
+            return null;
+        }
+    }
+
+    /**
+     * Creates a new action URL.
+     *
+     * @param action
+     * @return action URL or null if called outside a MimeRequest (outside a
+     *         UIDL request or similar)
+     */
+    public PortletURL generateActionURL(String action) {
+        PortletURL url = null;
+        if (response instanceof MimeResponse) {
+            url = ((MimeResponse) response).createActionURL();
+            url.setParameter("javax.portlet.action", action);
         } else {
-            resourceURL.setResourceID("APP/" + mapKey + "/" + filename);
+            return null;
         }
-        return resourceURL.toString();
+        return url;
     }
 
+    /**
+     * Sends a portlet event to the indicated destination.
+     * 
+     * Internally, an action may be created and opened, as an event cannot be
+     * sent directly from all types of requests.
+     * 
+     * The event destinations and values need to be kept in the context until
+     * sent. Any memory leaks if the action fails are limited to the session.
+     * 
+     * Event names for events sent and received by a portlet need to be declared
+     * in portlet.xml .
+     * 
+     * @param window
+     *            a window in which a temporary action URL can be opened if
+     *            necessary
+     * @param name
+     *            event name
+     * @param value
+     *            event value object that is Serializable and, if appropriate,
+     *            has a valid JAXB annotation
+     */
+    public void sendPortletEvent(Window window, QName name, Serializable value)
+            throws IllegalStateException {
+        if (response instanceof MimeResponse) {
+            String actionKey = "" + System.currentTimeMillis();
+            while (eventActionDestinationMap.containsKey(actionKey)) {
+                actionKey = actionKey + ".";
+            }
+            PortletURL actionUrl = generateActionURL(actionKey);
+            if (actionUrl != null) {
+                eventActionDestinationMap.put(actionKey, name);
+                eventActionValueMap.put(actionKey, value);
+                window.open(new ExternalResource(actionUrl.toString()));
+            } else {
+                // this should never happen as we already know the response is a
+                // MimeResponse
+                throw new IllegalStateException(
+                        "Portlet events can only be sent from a portlet request");
+            }
+        } else if (response instanceof StateAwareResponse) {
+            ((StateAwareResponse) response).setEvent(name, value);
+        } else {
+            throw new IllegalStateException(
+                    "Portlet events can only be sent from a portlet request");
+        }
+    }
 }