Browse Source

Support connector:// and use it for relative dependency urls (#9048)

tags/7.0.0.alpha3
Leif Åstrand 12 years ago
parent
commit
5e46aa3dd2

+ 11
- 6
src/com/vaadin/terminal/gwt/client/ApplicationConnection.java View 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;
}

+ 26
- 1
src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java View 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/")) {

+ 111
- 4
src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java View 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.

Loading…
Cancel
Save