@@ -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; | |||
} |
@@ -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/")) { |
@@ -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. |