From 14c7c17ffa25f6f3e48695927d24d21008b1b089 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Leif=20=C3=85strand?= Date: Tue, 8 Nov 2011 13:21:56 +0200 Subject: [PATCH] Created and integrated a RequestHandler for application resources --- src/com/vaadin/Application.java | 13 +- src/com/vaadin/RootTestApplication.java | 44 +++++- src/com/vaadin/terminal/RequestHandler.java | 6 +- src/com/vaadin/terminal/WrappedRequest.java | 2 + src/com/vaadin/terminal/WrappedResponse.java | 2 +- .../server/AbstractApplicationPortlet.java | 100 +----------- .../server/AbstractApplicationServlet.java | 147 +----------------- .../server/AbstractCommunicationManager.java | 89 ++--------- .../server/ApplicationResourceHandler.java | 138 ++++++++++++++++ .../gwt/server/CommunicationManager.java | 79 +++++----- .../server/PortletCommunicationManager.java | 49 ++++-- 11 files changed, 287 insertions(+), 382 deletions(-) create mode 100644 src/com/vaadin/terminal/gwt/server/ApplicationResourceHandler.java diff --git a/src/com/vaadin/Application.java b/src/com/vaadin/Application.java index 32a17a126b..e501561274 100644 --- a/src/com/vaadin/Application.java +++ b/src/com/vaadin/Application.java @@ -4,6 +4,7 @@ package com.vaadin; +import java.io.IOException; import java.io.Serializable; import java.net.SocketException; import java.net.URL; @@ -160,7 +161,7 @@ public abstract class Application implements URIHandler, */ private Terminal.ErrorListener errorHandler = this; - private Collection requestHandlers = new ArrayList(); + private LinkedList requestHandlers = new LinkedList(); /** * Gets the user of the application. @@ -1496,10 +1497,10 @@ public abstract class Application implements URIHandler, public abstract Root getRoot(WrappedRequest request); public boolean handleRequest(WrappedRequest request, - WrappedResponse response) { + WrappedResponse response) throws IOException { for (RequestHandler handler : new ArrayList( requestHandlers)) { - if (handler.handleRequest(request, response)) { + if (handler.handleRequest(this, request, response)) { return true; } } @@ -1508,7 +1509,7 @@ public abstract class Application implements URIHandler, } public void addRequestHandler(RequestHandler handler) { - requestHandlers.add(handler); + requestHandlers.addFirst(handler); } public void removeRequestHandler(RequestHandler handler) { @@ -1518,4 +1519,8 @@ public abstract class Application implements URIHandler, public Collection getRequestHandlers() { return Collections.unmodifiableCollection(requestHandlers); } + + public ApplicationResource getResource(String key) { + return keyResourceMap.get(key); + } } diff --git a/src/com/vaadin/RootTestApplication.java b/src/com/vaadin/RootTestApplication.java index cc9fb25466..983c3d48be 100644 --- a/src/com/vaadin/RootTestApplication.java +++ b/src/com/vaadin/RootTestApplication.java @@ -1,14 +1,19 @@ package com.vaadin; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import com.vaadin.terminal.ApplicationResource; +import com.vaadin.terminal.DownloadStream; import com.vaadin.terminal.RequestHandler; import com.vaadin.terminal.WrappedRequest; import com.vaadin.terminal.WrappedResponse; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; +import com.vaadin.ui.Link; import com.vaadin.ui.Root; import com.vaadin.ui.RootLayout; import com.vaadin.ui.VerticalLayout; @@ -35,6 +40,40 @@ public class RootTestApplication extends Application { "window.alert(\"Here\");"); } })); + ApplicationResource resource = new ApplicationResource() { + + public String getMIMEType() { + return "text/plain"; + } + + public DownloadStream getStream() { + try { + return new DownloadStream(new ByteArrayInputStream( + "Roots".getBytes("UTF-8")), getMIMEType(), + getFilename()); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + public String getFilename() { + return "roots.txt"; + } + + public long getCacheTime() { + return 60 * 60 * 1000; + } + + public int getBufferSize() { + return 0; + } + + public Application getApplication() { + return MyRootLayout.this.getApplication(); + } + }; + getApplication().addResource(resource); + addComponent(new Link("Resource", resource)); } } @@ -43,8 +82,8 @@ public class RootTestApplication extends Application { @Override public void init() { addRequestHandler(new RequestHandler() { - public boolean handleRequest(WrappedRequest request, - WrappedResponse response) { + public boolean handleRequest(Application application, + WrappedRequest request, WrappedResponse response) { if (request.getParameter("myhandler") != null) { response.setContentType("text/plain"); try { @@ -70,6 +109,7 @@ public class RootTestApplication extends Application { // TODO Should be done by Application during init root.setApplication(this); + root.init(); } return root; diff --git a/src/com/vaadin/terminal/RequestHandler.java b/src/com/vaadin/terminal/RequestHandler.java index 2024d99df9..b7d2cfd77b 100644 --- a/src/com/vaadin/terminal/RequestHandler.java +++ b/src/com/vaadin/terminal/RequestHandler.java @@ -1,8 +1,12 @@ package com.vaadin.terminal; +import java.io.IOException; + +import com.vaadin.Application; public interface RequestHandler { - boolean handleRequest(WrappedRequest request, WrappedResponse response); + boolean handleRequest(Application application, WrappedRequest request, WrappedResponse response) + throws IOException; } diff --git a/src/com/vaadin/terminal/WrappedRequest.java b/src/com/vaadin/terminal/WrappedRequest.java index 9320a81d28..0676818699 100644 --- a/src/com/vaadin/terminal/WrappedRequest.java +++ b/src/com/vaadin/terminal/WrappedRequest.java @@ -7,4 +7,6 @@ public interface WrappedRequest { public Map getParameterMap(); + public String getRequestPathInfo(); + } diff --git a/src/com/vaadin/terminal/WrappedResponse.java b/src/com/vaadin/terminal/WrappedResponse.java index 384cf26aa5..c6ffcf4a98 100644 --- a/src/com/vaadin/terminal/WrappedResponse.java +++ b/src/com/vaadin/terminal/WrappedResponse.java @@ -10,7 +10,7 @@ public interface WrappedResponse { public void setContentType(String contentType); - public void setContentLenght(int contentLength); + public void setHeader(String name, String value); public OutputStream getOutputStream() throws IOException; diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java index deadc46fb7..d785d4c699 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java @@ -51,7 +51,6 @@ import com.liferay.portal.kernel.util.PortalClassInvoker; import com.liferay.portal.kernel.util.PropsUtil; import com.vaadin.Application; import com.vaadin.Application.SystemMessages; -import com.vaadin.terminal.DownloadStream; import com.vaadin.terminal.Terminal; import com.vaadin.terminal.gwt.client.ApplicationConfiguration; import com.vaadin.terminal.gwt.client.ApplicationConnection; @@ -543,8 +542,9 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet // } if (requestType == RequestType.APPLICATION_RESOURCE) { - handleURI(applicationManager, root, (ResourceRequest) request, - (ResourceResponse) response); + if (!applicationManager.handleApplicationRequest(request, response)) { + response.setProperty(ResourceResponse.HTTP_STATUS_CODE, "404"); + } } else if (requestType == RequestType.RENDER) { writeAjaxPage((RenderRequest) request, (RenderResponse) response, root, application); @@ -582,100 +582,6 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet handleRequest(request, response); } - private boolean handleURI(PortletCommunicationManager applicationManager, - Root root, ResourceRequest request, ResourceResponse response) - throws IOException { - // Handles the URI - DownloadStream download = applicationManager.handleURI(root, request, - response, this); - - // A download request - if (download != null) { - // Client downloads an resource - handleDownload(download, request, response); - return true; - } - - return false; - } - - private void handleDownload(DownloadStream stream, ResourceRequest request, - ResourceResponse response) throws IOException { - - if (stream.getParameter("Location") != null) { - response.setProperty(ResourceResponse.HTTP_STATUS_CODE, - Integer.toString(HttpServletResponse.SC_MOVED_TEMPORARILY)); - response.setProperty("Location", stream.getParameter("Location")); - return; - } - - // Download from given stream - final InputStream data = stream.getStream(); - if (data != null) { - - OutputStream out = null; - try { - - // Sets content type - response.setContentType(stream.getContentType()); - - // Sets cache headers - final long cacheTime = stream.getCacheTime(); - if (cacheTime <= 0) { - response.setProperty("Cache-Control", "no-cache"); - response.setProperty("Pragma", "no-cache"); - response.setProperty("Expires", "0"); - } else { - response.setProperty("Cache-Control", "max-age=" - + cacheTime / 1000); - response.setProperty("Expires", - "" + System.currentTimeMillis() + cacheTime); - // Required to apply caching in some Tomcats - response.setProperty("Pragma", "cache"); - } - - // Copy download stream parameters directly - // to HTTP headers. - final Iterator i = stream.getParameterNames(); - if (i != null) { - while (i.hasNext()) { - final String param = i.next(); - response.setProperty(param, stream.getParameter(param)); - } - } - - // suggest local filename from DownloadStream if - // Content-Disposition - // not explicitly set - String contentDispositionValue = stream - .getParameter("Content-Disposition"); - if (contentDispositionValue == null) { - contentDispositionValue = "filename=\"" - + stream.getFileName() + "\""; - response.setProperty("Content-Disposition", - contentDispositionValue); - } - - int bufferSize = stream.getBufferSize(); - if (bufferSize <= 0 || bufferSize > MAX_BUFFER_SIZE) { - bufferSize = DEFAULT_BUFFER_SIZE; - } - final byte[] buffer = new byte[bufferSize]; - int bytesRead = 0; - - out = response.getPortletOutputStream(); - - while ((bytesRead = data.read(buffer)) > 0) { - out.write(buffer, 0, bytesRead); - out.flush(); - } - } finally { - AbstractCommunicationManager.tryToCloseStream(data); - AbstractCommunicationManager.tryToCloseStream(out); - } - } - } - private void serveStaticResources(ResourceRequest request, ResourceResponse response) throws IOException, PortletException { final String resourceID = request.getResourceID(); diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java index 11450ea63f..865d173f4d 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java @@ -37,7 +37,6 @@ import javax.servlet.http.HttpSession; import com.vaadin.Application; import com.vaadin.Application.SystemMessages; -import com.vaadin.terminal.DownloadStream; import com.vaadin.terminal.ParameterHandler; import com.vaadin.terminal.Terminal; import com.vaadin.terminal.ThemeResource; @@ -479,7 +478,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements /* Handle the request */ if (requestType == RequestType.FILE_UPLOAD) { - applicationManager.handleFileUpload(request, response); + applicationManager.handleFileUpload(request, response, this); return; } else if (requestType == RequestType.UIDL) { // Handles AJAX UIDL requests @@ -497,9 +496,8 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements return; } - if (application.handleRequest( - new WrappedHttpServletRequest(request), - new WrappedHttpServletResponse(response))) { + if (applicationManager.handleApplicationRequest(request, response, + this)) { return; } // TODO Should return 404 error here and not do anything more @@ -516,21 +514,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements root.setTerminal(webApplicationContext.getBrowser()); } - // Handle parameters - // final Map parameters = - // request.getParameterMap(); - // if (root != null && parameters != null) { - // root.handleParameters(parameters); - // } - - /* - * Call the URI handlers and if this turns out to be a download - * request, send the file to the client - */ - // if (handleURI(applicationManager, root, request, response)) { - // return; - // } - // Send initial AJAX page that kickstarts a Vaadin application writeAjaxPage(request, response, root, application); @@ -863,101 +846,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements return resultPath; } - /** - * Handles the requested URI. An application can add handlers to do special - * processing, when a certain URI is requested. The handlers are invoked - * before any windows URIs are processed and if a DownloadStream is returned - * it is sent to the client. - * - * @param stream - * the download stream. - * - * @param request - * the HTTP request instance. - * @param response - * the HTTP response to write to. - * @throws IOException - * - * @see com.vaadin.terminal.URIHandler - */ - private void handleDownload(DownloadStream stream, - HttpServletRequest request, HttpServletResponse response) - throws IOException { - - if (stream.getParameter("Location") != null) { - response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); - response.addHeader("Location", stream.getParameter("Location")); - return; - } - - // Download from given stream - final InputStream data = stream.getStream(); - if (data != null) { - - OutputStream out = null; - try { - // Sets content type - response.setContentType(stream.getContentType()); - - // Sets cache headers - final long cacheTime = stream.getCacheTime(); - if (cacheTime <= 0) { - response.setHeader("Cache-Control", "no-cache"); - response.setHeader("Pragma", "no-cache"); - response.setDateHeader("Expires", 0); - } else { - response.setHeader("Cache-Control", "max-age=" + cacheTime - / 1000); - response.setDateHeader("Expires", - System.currentTimeMillis() + cacheTime); - response.setHeader("Pragma", "cache"); // Required to apply - // caching in some - // Tomcats - } - - // Copy download stream parameters directly - // to HTTP headers. - final Iterator i = stream.getParameterNames(); - if (i != null) { - while (i.hasNext()) { - final String param = i.next(); - response.setHeader(param, stream.getParameter(param)); - } - } - - // suggest local filename from DownloadStream if - // Content-Disposition - // not explicitly set - String contentDispositionValue = stream - .getParameter("Content-Disposition"); - if (contentDispositionValue == null) { - contentDispositionValue = "filename=\"" - + stream.getFileName() + "\""; - response.setHeader("Content-Disposition", - contentDispositionValue); - } - - int bufferSize = stream.getBufferSize(); - if (bufferSize <= 0 || bufferSize > MAX_BUFFER_SIZE) { - bufferSize = DEFAULT_BUFFER_SIZE; - } - final byte[] buffer = new byte[bufferSize]; - int bytesRead = 0; - - out = response.getOutputStream(); - - while ((bytesRead = data.read(buffer)) > 0) { - out.write(buffer, 0, bytesRead); - out.flush(); - } - } finally { - AbstractCommunicationManager.tryToCloseStream(out); - AbstractCommunicationManager.tryToCloseStream(data); - } - } - - } - /** * Creates a new application and registers it into WebApplicationContext * (aka session). This is not meant to be overridden. Override @@ -1071,35 +959,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements return DEFAULT_THEME_NAME; } - // /** - // * Calls URI handlers for the request. If an URI handler returns a - // * DownloadStream the stream is passed to the client for downloading. - // * - // * @param applicationManager - // * @param window - // * @param request - // * @param response - // * @return true if an DownloadStream was sent to the client, false - // otherwise - // * @throws IOException - // */ - // protected boolean handleURI(CommunicationManager applicationManager, - // Root window, HttpServletRequest request, - // HttpServletResponse response) throws IOException { - // // Handles the URI - // DownloadStream download = applicationManager.handleURI(window, request, - // response, this); - // - // // A download request - // if (download != null) { - // // Client downloads an resource - // handleDownload(download, request, response); - // return true; - // } - // - // return false; - // } - void handleServiceSessionExpired(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java index ba00b19604..07547124fa 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java @@ -48,12 +48,11 @@ import javax.servlet.ServletResponse; import com.vaadin.Application; import com.vaadin.Application.SystemMessages; -import com.vaadin.terminal.ApplicationResource; -import com.vaadin.terminal.DownloadStream; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Paintable; import com.vaadin.terminal.Paintable.RepaintRequestEvent; +import com.vaadin.terminal.RequestHandler; import com.vaadin.terminal.StreamVariable; import com.vaadin.terminal.StreamVariable.StreamingEndEvent; import com.vaadin.terminal.StreamVariable.StreamingErrorEvent; @@ -62,6 +61,7 @@ import com.vaadin.terminal.Terminal.ErrorListener; import com.vaadin.terminal.URIHandler; import com.vaadin.terminal.VariableOwner; import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedResponse; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.server.ComponentSizeValidator.InvalidLayout; import com.vaadin.ui.AbstractComponent; @@ -95,6 +95,8 @@ public abstract class AbstractCommunicationManager implements private static final Logger logger = Logger .getLogger(AbstractCommunicationManager.class.getName()); + private static final RequestHandler APP_RESOURCE_HANDLER = new ApplicationResourceHandler(); + /** * Generic interface of a (HTTP or Portlet) request to the application. * @@ -183,6 +185,8 @@ public abstract class AbstractCommunicationManager implements */ public Object getWrappedRequest(); + public abstract String getRequestPathInfo(); + } /** @@ -196,7 +200,7 @@ public abstract class AbstractCommunicationManager implements * * @author peholmst */ - public interface Response { + public interface Response extends WrappedResponse { /** * Gets the output stream to which the response can be written. @@ -351,6 +355,7 @@ public abstract class AbstractCommunicationManager implements */ public AbstractCommunicationManager(Application application) { this.application = application; + application.addRequestHandler(APP_RESOURCE_HANDLER); requireLocale(application.getLocale().toString()); } @@ -2204,79 +2209,6 @@ public abstract class AbstractCommunicationManager implements } - /** - * Calls the Window URI handler for a request and returns the - * {@link DownloadStream} returned by the handler. - * - * If the window is the main window of an application, the (deprecated) - * {@link Application#handleURI(java.net.URL, String)} is called first to - * handle {@link ApplicationResource}s, and the window handler is only - * called if it returns null. - * - * @param window - * the target window of the request - * @param request - * the request instance - * @param response - * the response to write to - * @return DownloadStream if the request was handled and further processing - * should be suppressed, null otherwise. - * @see com.vaadin.terminal.URIHandler - */ - @SuppressWarnings("deprecation") - protected DownloadStream handleURI(Root root, Request request, - Response response, Callback callback) { - - String uri = callback.getRequestPathInfo(request); - - // If no URI is available - if (uri == null) { - uri = ""; - } else { - // Removes the leading / - while (uri.startsWith("/") && uri.length() > 0) { - uri = uri.substring(1); - } - } - - // Handles the uri - try { - throw new RuntimeException("Not ported to use roots"); - // URL context = application.getURL(); - // if (window == application.getMainWindow()) { - // DownloadStream stream = null; - // /* - // * Application.handleURI run first. Handles possible - // * ApplicationResources. - // */ - // stream = application.handleURI(context, uri); - // if (stream == null) { - // stream = window.handleURI(context, uri); - // } - // return stream; - // } else { - // // Resolve the prefix end index - // final int index = uri.indexOf('/'); - // if (index > 0) { - // String prefix = uri.substring(0, index); - // URL windowContext; - // windowContext = new URL(context, prefix + "/"); - // final String windowUri = (uri.length() > prefix.length() + 1) ? - // uri - // .substring(prefix.length() + 1) : ""; - // return window.handleURI(windowContext, windowUri); - // } else { - // return null; - // } - // } - - } catch (final Throwable t) { - application.getErrorHandler().terminalError( - new URIHandlerErrorImpl(application, t)); - return null; - } - } - private final HashMap, Integer> typeToKey = new HashMap, Integer>(); private int nextTypeKey = 0; @@ -2319,6 +2251,11 @@ public abstract class AbstractCommunicationManager implements abstract protected void cleanStreamVariable(VariableOwner owner, String name); + protected boolean handleApplicationRequest(WrappedRequest request, + WrappedResponse response) throws IOException { + return application.handleRequest(request, response); + } + /** * Stream that extracts content from another stream until the boundary * string is encountered. diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationResourceHandler.java b/src/com/vaadin/terminal/gwt/server/ApplicationResourceHandler.java new file mode 100644 index 0000000000..5c89b64754 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/ApplicationResourceHandler.java @@ -0,0 +1,138 @@ +package com.vaadin.terminal.gwt.server; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Iterator; +import java.util.Locale; +import java.util.TimeZone; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletResponse; + +import com.vaadin.Application; +import com.vaadin.terminal.ApplicationResource; +import com.vaadin.terminal.DownloadStream; +import com.vaadin.terminal.RequestHandler; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedResponse; + +public class ApplicationResourceHandler implements RequestHandler { + private static final DateFormat HTTP_DATE_FORMAT = new SimpleDateFormat( + "EEE, dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH); + static { + HTTP_DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT")); + } + private static final Pattern APP_RESOURCE_PATTERN = Pattern + .compile("/APP/(\\d+)/.*"); + + public boolean handleRequest(Application application, + WrappedRequest request, WrappedResponse response) + throws IOException { + // Check for application resources + String requestPath = request.getRequestPathInfo(); + Matcher resourceMatcher = APP_RESOURCE_PATTERN.matcher(requestPath); + + if (resourceMatcher.matches()) { + ApplicationResource resource = application + .getResource(resourceMatcher.group(1)); + if (resource != null) { + DownloadStream stream = resource.getStream(); + if (stream != null) { + stream.setCacheTime(resource.getCacheTime()); + serveResource(stream, response); + return true; + } + } + } + + return false; + } + + protected void serveResource(DownloadStream stream, WrappedResponse response) + throws IOException { + if (stream.getParameter("Location") != null) { + response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); + response.setHeader("Location", stream.getParameter("Location")); + return; + } + + // Download from given stream + final InputStream data = stream.getStream(); + if (data != null) { + + OutputStream out = null; + try { + // Sets content type + response.setContentType(stream.getContentType()); + + // Sets cache headers + final long cacheTime = stream.getCacheTime(); + if (cacheTime <= 0) { + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("Pragma", "no-cache"); + response.setHeader("Expires", + HTTP_DATE_FORMAT.format(new Date(0))); + } else { + response.setHeader("Cache-Control", "max-age=" + cacheTime + / 1000); + response.setHeader( + "Expires", + HTTP_DATE_FORMAT.format(new Date(System + .currentTimeMillis() + cacheTime))); + // Required to apply caching in some Tomcats + response.setHeader("Pragma", "cache"); + } + + // Copy download stream parameters directly + // to HTTP headers. + final Iterator i = stream.getParameterNames(); + if (i != null) { + while (i.hasNext()) { + final String param = i.next(); + response.setHeader(param, stream.getParameter(param)); + } + } + + // suggest local filename from DownloadStream if + // Content-Disposition + // not explicitly set + String contentDispositionValue = stream + .getParameter("Content-Disposition"); + if (contentDispositionValue == null) { + contentDispositionValue = "filename=\"" + + stream.getFileName() + "\""; + response.setHeader("Content-Disposition", + contentDispositionValue); + } + + int bufferSize = stream.getBufferSize(); + if (bufferSize <= 0 || bufferSize > Constants.MAX_BUFFER_SIZE) { + bufferSize = Constants.DEFAULT_BUFFER_SIZE; + } + final byte[] buffer = new byte[bufferSize]; + int bytesRead = 0; + + out = response.getOutputStream(); + + long totalWritten = 0; + while ((bytesRead = data.read(buffer)) > 0) { + out.write(buffer, 0, bytesRead); + + totalWritten += bytesRead; + if (totalWritten >= buffer.length) { + // Avoid chunked encoding for small resources + out.flush(); + } + } + } finally { + AbstractCommunicationManager.tryToCloseStream(out); + AbstractCommunicationManager.tryToCloseStream(data); + } + } + } +} diff --git a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java index 2ac0780f08..16d44e6771 100644 --- a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java @@ -7,6 +7,7 @@ package com.vaadin.terminal.gwt.server; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -17,14 +18,11 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import com.vaadin.Application; -import com.vaadin.terminal.ApplicationResource; -import com.vaadin.terminal.DownloadStream; import com.vaadin.terminal.Paintable; import com.vaadin.terminal.StreamVariable; import com.vaadin.terminal.VariableOwner; import com.vaadin.ui.Component; import com.vaadin.ui.Root; -import com.vaadin.ui.Window; /** * Application manager processes changes and paints for single application @@ -50,9 +48,12 @@ public class CommunicationManager extends AbstractCommunicationManager { private static class HttpServletRequestWrapper implements Request { private final HttpServletRequest request; + private final AbstractApplicationServlet servlet; - public HttpServletRequestWrapper(HttpServletRequest request) { + public HttpServletRequestWrapper(HttpServletRequest request, + AbstractApplicationServlet servlet) { this.request = request; + this.servlet = servlet; } public Object getAttribute(String name) { @@ -94,6 +95,10 @@ public class CommunicationManager extends AbstractCommunicationManager { public void setAttribute(String name, Object o) { request.setAttribute(name, o); } + + public String getRequestPathInfo() { + return servlet.getRequestPathInfo(request); + } } /** @@ -121,6 +126,18 @@ public class CommunicationManager extends AbstractCommunicationManager { response.setContentType(type); } + public PrintWriter getWriter() throws IOException { + return response.getWriter(); + } + + public void setStatus(int responseStatus) { + response.setStatus(responseStatus); + } + + public void setHeader(String name, String value) { + response.setHeader(name, value); + } + } /** @@ -217,12 +234,13 @@ public class CommunicationManager extends AbstractCommunicationManager { * * @param request * @param response + * @param servlet * @throws IOException * @throws InvalidUIDLSecurityKeyException */ public void handleFileUpload(HttpServletRequest request, - HttpServletResponse response) throws IOException, - InvalidUIDLSecurityKeyException { + HttpServletResponse response, AbstractApplicationServlet servlet) + throws IOException, InvalidUIDLSecurityKeyException { /* * URI pattern: APP/UPLOAD/[PID]/[NAME]/[SECKEY] See #createReceiverUrl @@ -248,15 +266,15 @@ public class CommunicationManager extends AbstractCommunicationManager { if (request.getContentType().contains("boundary")) { // Multipart requests contain boundary string doHandleSimpleMultipartFileUpload( - new HttpServletRequestWrapper(request), + new HttpServletRequestWrapper(request, servlet), new HttpServletResponseWrapper(response), streamVariable, variableName, source, contentType.split("boundary=")[1]); } else { // if boundary string does not exist, the posted file is from // XHR2.post(File) - doHandleXhrFilePost(new HttpServletRequestWrapper(request), - new HttpServletResponseWrapper(response), + doHandleXhrFilePost(new HttpServletRequestWrapper(request, + servlet), new HttpServletResponseWrapper(response), streamVariable, variableName, source, request.getContentLength()); } @@ -286,8 +304,8 @@ public class CommunicationManager extends AbstractCommunicationManager { AbstractApplicationServlet applicationServlet, Root root) throws IOException, ServletException, InvalidUIDLSecurityKeyException { - doHandleUidlRequest(new HttpServletRequestWrapper(request), - new HttpServletResponseWrapper(response), + doHandleUidlRequest(new HttpServletRequestWrapper(request, + applicationServlet), new HttpServletResponseWrapper(response), new AbstractApplicationServletWrapper(applicationServlet), root); } @@ -310,35 +328,9 @@ public class CommunicationManager extends AbstractCommunicationManager { Root getApplicationRoot(HttpServletRequest request, AbstractApplicationServlet applicationServlet, Application application, Root assumedRoot) throws ServletException { - return doGetApplicationWindow(new HttpServletRequestWrapper(request), - new AbstractApplicationServletWrapper(applicationServlet), - application, assumedRoot); - } - - /** - * Calls the Window URI handler for a request and returns the - * {@link DownloadStream} returned by the handler. - * - * If the window is the main window of an application, the deprecated - * {@link Application#handleURI(java.net.URL, String)} is called first to - * handle {@link ApplicationResource}s and the window handler is only called - * if it returns null. - * - * @see AbstractCommunicationManager#handleURI(Window, Request, Response, - * Callback) - * - * @param root - * @param request - * @param response - * @param applicationServlet - * @return - */ - DownloadStream handleURI(Root root, HttpServletRequest request, - HttpServletResponse response, - AbstractApplicationServlet applicationServlet) { - return handleURI(root, new HttpServletRequestWrapper(request), - new HttpServletResponseWrapper(response), - new AbstractApplicationServletWrapper(applicationServlet)); + return doGetApplicationWindow(new HttpServletRequestWrapper(request, + applicationServlet), new AbstractApplicationServletWrapper( + applicationServlet), application, assumedRoot); } @Override @@ -414,4 +406,11 @@ public class CommunicationManager extends AbstractCommunicationManager { } } + public boolean handleApplicationRequest(HttpServletRequest request, + HttpServletResponse response, AbstractApplicationServlet servlet) + throws IOException { + return handleApplicationRequest(new HttpServletRequestWrapper(request, + servlet), new HttpServletResponseWrapper(response)); + } + } diff --git a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java index dc3b2e9ec8..f428a46643 100644 --- a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java @@ -6,6 +6,7 @@ package com.vaadin.terminal.gwt.server; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.PrintWriter; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; @@ -22,7 +23,6 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequestWrapper; import com.vaadin.Application; -import com.vaadin.terminal.DownloadStream; import com.vaadin.terminal.Paintable; import com.vaadin.terminal.StreamVariable; import com.vaadin.terminal.VariableOwner; @@ -102,6 +102,16 @@ public class PortletCommunicationManager extends AbstractCommunicationManager { request.setAttribute(name, o); } + public String getRequestPathInfo() { + if (request instanceof ResourceRequest) { + return ((ResourceRequest) request).getResourceID(); + } else { + // We do not use paths in portlet mode + throw new UnsupportedOperationException( + "PathInfo only available when using ResourceRequests"); + } + } + } private static class PortletResponseWrapper implements Response { @@ -123,6 +133,19 @@ public class PortletCommunicationManager extends AbstractCommunicationManager { public void setContentType(String type) { ((MimeResponse) response).setContentType(type); } + + public PrintWriter getWriter() throws IOException { + return ((MimeResponse) response).getWriter(); + } + + public void setStatus(int responseStatus) { + response.setProperty(ResourceResponse.HTTP_STATUS_CODE, + Integer.toString(responseStatus)); + } + + public void setHeader(String name, String value) { + response.setProperty(name, value); + } } private static class PortletSessionWrapper implements Session { @@ -174,14 +197,7 @@ public class PortletCommunicationManager extends AbstractCommunicationManager { } public String getRequestPathInfo(Request request) { - if (request.getWrappedRequest() instanceof ResourceRequest) { - return ((ResourceRequest) request.getWrappedRequest()) - .getResourceID(); - } else { - // We do not use paths in portlet mode - throw new UnsupportedOperationException( - "PathInfo only available when using ResourceRequests"); - } + return request.getRequestPathInfo(); } public InputStream getThemeResourceAsStream(String themeName, @@ -238,14 +254,6 @@ public class PortletCommunicationManager extends AbstractCommunicationManager { currentUidlResponse = null; } - DownloadStream handleURI(Root root, ResourceRequest request, - ResourceResponse response, - AbstractApplicationPortlet applicationPortlet) { - return handleURI(root, new PortletRequestWrapper(request), - new PortletResponseWrapper(response), - new AbstractApplicationPortletWrapper(applicationPortlet)); - } - /** * Gets the existing application or creates a new one. Get a window within * an application based on the requested URI. @@ -306,4 +314,11 @@ public class PortletCommunicationManager extends AbstractCommunicationManager { } } + public boolean handleApplicationRequest(PortletRequest request, + PortletResponse response) + throws IOException { + return handleApplicationRequest(new PortletRequestWrapper(request), + new PortletResponseWrapper(response)); + } + } -- 2.39.5