From d2240c3ace8ebca936037c5fbac1a0cc18e8937b Mon Sep 17 00:00:00 2001 From: Henri Sara Date: Tue, 1 Dec 2009 15:00:49 +0000 Subject: [PATCH] #3117 inter-portlet event support (JSR-286), some support for custom portlet actions svn changeset:10119/svn branch:6.2 --- WebContent/WEB-INF/liferay-display.xml | 5 +- WebContent/WEB-INF/portlet.xml | 44 ++++++- WebContent/WEB-INF/web.xml | 2 +- build/package/WebContent/WEB-INF/web.xml | 2 +- src/com/vaadin/Application.java | 6 +- .../vaadin/service/ApplicationContext.java | 8 +- .../server/AbstractApplicationPortlet.java | 31 +++-- .../server/PortletApplicationContext2.java | 115 ++++++++++++++++-- 8 files changed, 177 insertions(+), 36 deletions(-) diff --git a/WebContent/WEB-INF/liferay-display.xml b/WebContent/WEB-INF/liferay-display.xml index 2981e08fd4..302f9961dd 100644 --- a/WebContent/WEB-INF/liferay-display.xml +++ b/WebContent/WEB-INF/liferay-display.xml @@ -18,6 +18,9 @@ - + \ No newline at end of file diff --git a/WebContent/WEB-INF/portlet.xml b/WebContent/WEB-INF/portlet.xml index c91bac7589..b4a40e77aa 100644 --- a/WebContent/WEB-INF/portlet.xml +++ b/WebContent/WEB-INF/portlet.xml @@ -136,33 +136,69 @@ HelloWorld HelloWorld + + + AddressBookPortlet diff --git a/WebContent/WEB-INF/web.xml b/WebContent/WEB-INF/web.xml index ce3c2bba13..2e2c1b680e 100644 --- a/WebContent/WEB-INF/web.xml +++ b/WebContent/WEB-INF/web.xml @@ -120,7 +120,7 @@ com.vaadin.terminal.gwt.server.ApplicationServlet application - com.vaadin.demo.PortletDemo + com.vaadin.demo.portlet.PortletDemo diff --git a/build/package/WebContent/WEB-INF/web.xml b/build/package/WebContent/WEB-INF/web.xml index f80129b810..cfbe2b41bc 100644 --- a/build/package/WebContent/WEB-INF/web.xml +++ b/build/package/WebContent/WEB-INF/web.xml @@ -149,7 +149,7 @@ com.vaadin.terminal.gwt.server.ApplicationServlet application - com.vaadin.demo.PortletDemo + com.vaadin.demo.portlet.PortletDemo diff --git a/src/com/vaadin/Application.java b/src/com/vaadin/Application.java index 2b132fee64..5d10b215e4 100644 --- a/src/com/vaadin/Application.java +++ b/src/com/vaadin/Application.java @@ -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) { diff --git a/src/com/vaadin/service/ApplicationContext.java b/src/com/vaadin/service/ApplicationContext.java index ab201a4bd4..3d2c76c8d0 100644 --- a/src/com/vaadin/service/ApplicationContext.java +++ b/src/com/vaadin/service/ApplicationContext.java @@ -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 diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java index 5c1396b449..9a5f4f0fb0 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java @@ -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 diff --git a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java b/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java index 3af45acfaf..f6217774e2 100644 --- a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java +++ b/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java @@ -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 portletWindowIdToApplicationMap = new HashMap(); - private MimeResponse mimeResponse; + private PortletResponse response; + + private Map eventActionDestinationMap = new HashMap(); + private Map eventActionValueMap = new HashMap(); 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 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 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"); + } + } } -- 2.39.5