From 5e46aa3dd23c194a741c4e7c6c5821b6eb3d7a2d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Leif=20=C3=85strand?= Date: Thu, 28 Jun 2012 15:55:02 +0300 Subject: [PATCH] Support connector:// and use it for relative dependency urls (#9048) --- .../gwt/client/ApplicationConnection.java | 17 ++- .../server/AbstractApplicationServlet.java | 27 +++- .../server/AbstractCommunicationManager.java | 115 +++++++++++++++++- 3 files changed, 148 insertions(+), 11 deletions(-) diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index c6320f941b..8484d4abea 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -1621,7 +1621,7 @@ public class ApplicationConnection { ApplicationConfiguration.runWhenDependenciesLoaded(c); } - private static void loadStyleDependencies(JsArrayString dependencies) { + private void loadStyleDependencies(JsArrayString dependencies) { // Assuming no reason to interpret in a defined order ResourceLoadListener resourceLoadListener = new ResourceLoadListener() { public void onLoad(ResourceLoadEvent event) { @@ -1637,12 +1637,13 @@ public class ApplicationConnection { }; ResourceLoader loader = ResourceLoader.get(); for (int i = 0; i < dependencies.length(); i++) { + String url = translateVaadinUri(dependencies.get(i)); ApplicationConfiguration.startDependencyLoading(); - loader.loadStylesheet(dependencies.get(i), resourceLoadListener); + loader.loadStylesheet(url, resourceLoadListener); } } - private static void loadScriptDependencies(final JsArrayString dependencies) { + private void loadScriptDependencies(final JsArrayString dependencies) { if (dependencies.length() == 0) { return; } @@ -1651,10 +1652,10 @@ public class ApplicationConnection { ResourceLoadListener resourceLoadListener = new ResourceLoadListener() { public void onLoad(ResourceLoadEvent event) { if (dependencies.length() != 0) { + String url = translateVaadinUri(dependencies.shift()); ApplicationConfiguration.startDependencyLoading(); // Load next in chain (hopefully already preloaded) - event.getResourceLoader().loadScript(dependencies.shift(), - this); + event.getResourceLoader().loadScript(url, this); } // Call start for next before calling end for current ApplicationConfiguration.endDependencyLoading(); @@ -1670,8 +1671,9 @@ public class ApplicationConnection { ResourceLoader loader = ResourceLoader.get(); // Start chain by loading first + String url = translateVaadinUri(dependencies.shift()); ApplicationConfiguration.startDependencyLoading(); - loader.loadScript(dependencies.shift(), resourceLoadListener); + loader.loadScript(url, resourceLoadListener); // Preload all remaining for (int i = 0; i < dependencies.length(); i++) { @@ -2284,6 +2286,9 @@ public class ApplicationConnection { } if (uidlUri.startsWith("app://")) { uidlUri = getAppUri() + uidlUri.substring(6); + } else if (uidlUri.startsWith("connector://")) { + uidlUri = getAppUri() + "APP/CONNECTOR/" + + uidlUri.substring("connector://".length()); } return uidlUri; } diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java index f7e46a7ca9..6930961497 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java @@ -136,6 +136,8 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements static final String UPLOAD_URL_PREFIX = "APP/UPLOAD/"; + static final String CONNECTOR_RESOURCE_PREFIX = "/APP/CONNECTOR/"; + /** * Called by the servlet container to indicate to a servlet that the servlet * is being placed into service. @@ -396,6 +398,19 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements CommunicationManager applicationManager = webApplicationContext .getApplicationManager(application, this); + if (requestType == RequestType.CONNECTOR_RESOURCE) { + String pathInfo = getRequestPathInfo(request); + String resourceName = pathInfo + .substring(CONNECTOR_RESOURCE_PREFIX.length()); + + final String mimetype = getServletContext().getMimeType( + resourceName); + + applicationManager.serveConnectorResource(resourceName, + request, response, mimetype); + return; + } + /* Update browser information from the request */ webApplicationContext.getBrowser().updateRequestDetails(request); @@ -1250,12 +1265,14 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements } protected enum RequestType { - FILE_UPLOAD, BROWSER_DETAILS, UIDL, OTHER, STATIC_FILE, APPLICATION_RESOURCE; + FILE_UPLOAD, BROWSER_DETAILS, UIDL, OTHER, STATIC_FILE, APPLICATION_RESOURCE, CONNECTOR_RESOURCE; } protected RequestType getRequestType(HttpServletRequest request) { if (isFileUploadRequest(request)) { return RequestType.FILE_UPLOAD; + } else if (isConnectorResourceRequest(request)) { + return RequestType.CONNECTOR_RESOURCE; } else if (isBrowserDetailsRequest(request)) { return RequestType.BROWSER_DETAILS; } else if (isUIDLRequest(request)) { @@ -1276,6 +1293,14 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements && request.getParameter("browserDetails") != null; } + private boolean isConnectorResourceRequest(HttpServletRequest request) { + String path = getRequestPathInfo(request); + if (path != null && path.startsWith(CONNECTOR_RESOURCE_PREFIX)) { + return true; + } + return false; + } + private boolean isApplicationRequest(HttpServletRequest request) { String path = getRequestPathInfo(request); if (path != null && path.startsWith("/APP/")) { diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java index c65b8947d6..4ee300edac 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java @@ -18,6 +18,8 @@ import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; +import java.net.URI; +import java.net.URISyntaxException; import java.security.GeneralSecurityException; import java.text.CharacterIterator; import java.text.DateFormat; @@ -25,7 +27,6 @@ import java.text.DateFormatSymbols; import java.text.SimpleDateFormat; import java.text.StringCharacterIterator; import java.util.ArrayList; -import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; @@ -43,6 +44,8 @@ import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; +import javax.servlet.http.HttpServletResponse; + import com.vaadin.Application; import com.vaadin.Application.SystemMessages; import com.vaadin.RootRequiresMoreInformationException; @@ -157,6 +160,8 @@ public abstract class AbstractCommunicationManager implements Serializable { private Connector highlightedConnector; + private Map> connectoResourceContexts = new HashMap>(); + /** * TODO New constructor - document me! * @@ -1177,13 +1182,16 @@ public abstract class AbstractCommunicationManager implements Serializable { for (Class class1 : newConnectorTypes) { JavaScript jsAnnotation = class1.getAnnotation(JavaScript.class); if (jsAnnotation != null) { - scriptDependencies.addAll(Arrays.asList(jsAnnotation.value())); + for (String resource : jsAnnotation.value()) { + scriptDependencies.add(registerResource(resource, class1)); + } } StyleSheet styleAnnotation = class1.getAnnotation(StyleSheet.class); if (styleAnnotation != null) { - styleDependencies - .addAll(Arrays.asList(styleAnnotation.value())); + for (String resource : styleAnnotation.value()) { + styleDependencies.add(registerResource(resource, class1)); + } } } @@ -1209,6 +1217,51 @@ public abstract class AbstractCommunicationManager implements Serializable { writePerformanceData(outWriter); } + private String registerResource(String resource, Class context) { + try { + URI uri = new URI(resource); + String protocol = uri.getScheme(); + + if ("connector".equals(protocol)) { + return registerContextResource(uri, context); + } + + if (protocol != null || uri.getHost() != null) { + return resource; + } + + String path = uri.getPath(); + if (path.startsWith("/")) { + return resource; + } + + // Default if just simple relative url + return registerContextResource(uri, context); + } catch (URISyntaxException e) { + getLogger().log(Level.WARNING, + "Could not parse resource url " + resource, e); + return resource; + } + } + + private String registerContextResource(URI uri, Class context) { + String path = uri.getPath(); + synchronized (connectoResourceContexts) { + // Connector resource + if (connectoResourceContexts.containsKey(path)) { + Class oldContext = connectoResourceContexts.get(path); + getLogger().warning( + "Resource " + path + " defined by both " + context + + " and " + oldContext + ". Resource from " + + oldContext + " will be used."); + } else { + connectoResourceContexts.put(path, context); + } + } + + return "connector://" + path; + } + /** * Adds the performance timing data (used by TestBench 3) to the UIDL * response. @@ -2332,6 +2385,60 @@ public abstract class AbstractCommunicationManager implements Serializable { return initialUIDL; } + public void serveConnectorResource(String resourceName, + WrappedRequest request, WrappedResponse response, String mimetype) + throws IOException { + if (resourceName.startsWith("/")) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, resourceName); + return; + } + + Class context; + synchronized (connectoResourceContexts) { + context = connectoResourceContexts.get(resourceName); + } + + if (context == null) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, resourceName); + return; + } + + InputStream in = context.getResourceAsStream(resourceName); + if (in == null) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, resourceName); + return; + } + OutputStream out = null; + try { + if (mimetype != null) { + response.setContentType(mimetype); + } + + out = response.getOutputStream(); + + final byte[] buffer = new byte[Constants.DEFAULT_BUFFER_SIZE]; + + int bytesRead = 0; + while ((bytesRead = in.read(buffer)) > 0) { + out.write(buffer, 0, bytesRead); + } + out.flush(); + } finally { + try { + in.close(); + } catch (Exception e) { + // Do nothing + } + if (out != null) { + try { + out.close(); + } catch (Exception e) { + // Do nothing + } + } + } + } + /** * Stream that extracts content from another stream until the boundary * string is encountered. -- 2.39.5