]> source.dussan.org Git - vaadin-framework.git/commitdiff
Support connector:// and use it for relative dependency urls (#9048)
authorLeif Åstrand <leif@vaadin.com>
Thu, 28 Jun 2012 12:55:02 +0000 (15:55 +0300)
committerLeif Åstrand <leif@vaadin.com>
Thu, 28 Jun 2012 12:55:02 +0000 (15:55 +0300)
src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java

index c6320f941b9bf7dca1fb16ee2037231c367cfd23..8484d4abea501dd416302e370bda62765f4418b7 100644 (file)
@@ -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;
     }
index f7e46a7ca9787bd7e235da6f8445667d94990b02..693096149791ce8d14764fa494e4c8617e92d60f 100644 (file)
@@ -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/")) {
index c65b8947d6c74f09993a3fb5e60eeb9e548fbc12..4ee300edacd6a4bccd3e542d9957fe05d333a446 100644 (file)
@@ -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<String, Class<?>> connectoResourceContexts = new HashMap<String, Class<?>>();
+
     /**
      * TODO New constructor - document me!
      * 
@@ -1177,13 +1182,16 @@ public abstract class AbstractCommunicationManager implements Serializable {
         for (Class<? extends ClientConnector> 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.