@@ -1,6 +1,7 @@ | |||
/* | |||
@VaadinApache2LicenseForJavaFiles@ | |||
*/ | |||
package com.vaadin.annotations; | |||
import java.lang.annotation.ElementType; | |||
@@ -8,17 +9,8 @@ import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
/** | |||
* Temporary hack used for ensuring external javascript libraries are included. | |||
* To add a javascript, add this annotation to your Root class. | |||
* | |||
* @deprecated Will be removed in favor of a more robust solution before version | |||
* 7.0.0 | |||
*/ | |||
@Retention(RetentionPolicy.RUNTIME) | |||
@Target(ElementType.TYPE) | |||
@Deprecated | |||
public @interface LoadScripts { | |||
public @interface JavaScript { | |||
public String[] value(); | |||
} |
@@ -0,0 +1,16 @@ | |||
/* | |||
@VaadinApache2LicenseForJavaFiles@ | |||
*/ | |||
package com.vaadin.annotations; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
@Retention(RetentionPolicy.RUNTIME) | |||
@Target(ElementType.TYPE) | |||
public @interface StyleSheet { | |||
public String[] value(); | |||
} |
@@ -40,6 +40,8 @@ import com.google.gwt.user.client.Timer; | |||
import com.google.gwt.user.client.ui.HasWidgets; | |||
import com.google.gwt.user.client.ui.Widget; | |||
import com.vaadin.terminal.gwt.client.ApplicationConfiguration.ErrorMessage; | |||
import com.vaadin.terminal.gwt.client.ResourceLoader.ResourceLoadEvent; | |||
import com.vaadin.terminal.gwt.client.ResourceLoader.ResourceLoadListener; | |||
import com.vaadin.terminal.gwt.client.communication.HasJavaScriptConnectorHelper; | |||
import com.vaadin.terminal.gwt.client.communication.JsonDecoder; | |||
import com.vaadin.terminal.gwt.client.communication.JsonEncoder; | |||
@@ -1067,6 +1069,14 @@ public class ApplicationConnection { | |||
json.getValueMap("typeMappings"), widgetSet); | |||
} | |||
VConsole.log("Handling resource dependencies"); | |||
if (json.containsKey("scriptDependencies")) { | |||
loadScriptDependencies(json.getJSStringArray("scriptDependencies")); | |||
} | |||
if (json.containsKey("styleDependencies")) { | |||
loadStyleDependencies(json.getJSStringArray("styleDependencies")); | |||
} | |||
handleUIDLDuration.logDuration( | |||
" * Handling type mappings from server completed", 10); | |||
/* | |||
@@ -1611,6 +1621,51 @@ public class ApplicationConnection { | |||
ApplicationConfiguration.runWhenWidgetsLoaded(c); | |||
} | |||
private static void loadStyleDependencies(JsArrayString dependencies) { | |||
// Assuming no reason to interpret in a defined order | |||
ResourceLoadListener resourceLoadListener = new ResourceLoadListener() { | |||
public void onResourceLoad(ResourceLoadEvent event) { | |||
ApplicationConfiguration.endWidgetLoading(); | |||
} | |||
}; | |||
ResourceLoader loader = ResourceLoader.get(); | |||
for (int i = 0; i < dependencies.length(); i++) { | |||
ApplicationConfiguration.startWidgetLoading(); | |||
loader.loadStylesheet(dependencies.get(i), resourceLoadListener); | |||
} | |||
} | |||
private static void loadScriptDependencies(final JsArrayString dependencies) { | |||
if (dependencies.length() == 0) { | |||
return; | |||
} | |||
// Listener that loads the next when one is completed | |||
ResourceLoadListener resourceLoadListener = new ResourceLoadListener() { | |||
public void onResourceLoad(ResourceLoadEvent event) { | |||
if (dependencies.length() != 0) { | |||
ApplicationConfiguration.startWidgetLoading(); | |||
// Load next in chain (hopefully already preloaded) | |||
event.getResourceLoader().loadScript(dependencies.shift(), | |||
this); | |||
} | |||
// Call start for next before calling end for current | |||
ApplicationConfiguration.endWidgetLoading(); | |||
} | |||
}; | |||
ResourceLoader loader = ResourceLoader.get(); | |||
// Start chain by loading first | |||
ApplicationConfiguration.startWidgetLoading(); | |||
loader.loadScript(dependencies.shift(), resourceLoadListener); | |||
// Preload all remaining | |||
for (int i = 0; i < dependencies.length(); i++) { | |||
loader.loadScript(dependencies.get(i), null); | |||
} | |||
} | |||
// Redirect browser, null reloads current page | |||
private static native void redirect(String url) | |||
/*-{ |
@@ -0,0 +1,401 @@ | |||
/* | |||
@VaadinApache2LicenseForJavaFiles@ | |||
*/ | |||
package com.vaadin.terminal.gwt.client; | |||
import java.util.Collection; | |||
import java.util.HashMap; | |||
import java.util.HashSet; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import com.google.gwt.core.client.GWT; | |||
import com.google.gwt.core.client.Scheduler; | |||
import com.google.gwt.core.client.Scheduler.RepeatingCommand; | |||
import com.google.gwt.dom.client.AnchorElement; | |||
import com.google.gwt.dom.client.Document; | |||
import com.google.gwt.dom.client.Element; | |||
import com.google.gwt.dom.client.LinkElement; | |||
import com.google.gwt.dom.client.NodeList; | |||
import com.google.gwt.dom.client.ObjectElement; | |||
import com.google.gwt.dom.client.ScriptElement; | |||
/** | |||
* ResourceLoader lets you dynamically include external scripts and styles on | |||
* the page and lets you know when the resource has been loaded. | |||
* | |||
* You can also preload resources, allowing them to get cached by the browser | |||
* without being evaluated. This enables downloading multiple resources at once | |||
* while still controlling in which order e.g. scripts are executed. | |||
* | |||
* @author Vaadin Ltd | |||
* @version @VERSION@ | |||
* @since 7.0.0 | |||
*/ | |||
public class ResourceLoader { | |||
/** | |||
* Event fired when a resource has been loaded. | |||
*/ | |||
public static class ResourceLoadEvent { | |||
private ResourceLoader loader; | |||
private String resourceUrl; | |||
private final boolean preload; | |||
/** | |||
* Creates a new event. | |||
* | |||
* @param loader | |||
* the resource loader that has loaded the resource | |||
* @param resourceUrl | |||
* the url of the loaded resource | |||
* @param preload | |||
* true if the resource has only been preloaded, false if | |||
* it's fully loaded | |||
*/ | |||
public ResourceLoadEvent(ResourceLoader loader, String resourceUrl, | |||
boolean preload) { | |||
this.loader = loader; | |||
this.resourceUrl = resourceUrl; | |||
this.preload = preload; | |||
} | |||
/** | |||
* Gets the resource loader that has fired this event | |||
* | |||
* @return the resource loader | |||
*/ | |||
public ResourceLoader getResourceLoader() { | |||
return loader; | |||
} | |||
/** | |||
* Gets the absolute url of the loaded resource. | |||
* | |||
* @return the absolute url of the loaded resource | |||
*/ | |||
public String getResourceUrl() { | |||
return resourceUrl; | |||
} | |||
/** | |||
* Returns true if the resource has been preloaded, false if it's fully | |||
* loaded | |||
* | |||
* @see ResourceLoader#preloadResource(String, ResourceLoadListener) | |||
* | |||
* @return true if the resource has been preloaded, false if it's fully | |||
* loaded | |||
*/ | |||
public boolean isPreload() { | |||
return preload; | |||
} | |||
} | |||
/** | |||
* Event listener that gets notified when a resource has been loaded | |||
*/ | |||
public interface ResourceLoadListener { | |||
/** | |||
* Notified this ResourceLoadListener that a resource has been loaded | |||
* | |||
* @see ResourceLoadEvent | |||
* | |||
* @param event | |||
* a resource load event with information about the loaded | |||
* resource | |||
*/ | |||
public void onResourceLoad(ResourceLoadEvent event); | |||
} | |||
private static final ResourceLoader INSTANCE = GWT | |||
.create(ResourceLoader.class); | |||
private ApplicationConnection connection; | |||
private final Set<String> loadedResources = new HashSet<String>(); | |||
private final Set<String> preloadedResources = new HashSet<String>(); | |||
private final Map<String, Collection<ResourceLoadListener>> loadListeners = new HashMap<String, Collection<ResourceLoadListener>>(); | |||
private final Map<String, Collection<ResourceLoadListener>> preloadListeners = new HashMap<String, Collection<ResourceLoadListener>>(); | |||
private final Element head; | |||
/** | |||
* Creates a new resource loader. You should generally not create you own | |||
* resource loader, but instead use {@link ResourceLoader#get()} to get an | |||
* instance. | |||
*/ | |||
protected ResourceLoader() { | |||
Document document = Document.get(); | |||
head = document.getElementsByTagName("head").getItem(0); | |||
// detect already loaded scripts and stylesheets | |||
NodeList<Element> scripts = document.getElementsByTagName("script"); | |||
for (int i = 0; i < scripts.getLength(); i++) { | |||
ScriptElement element = ScriptElement.as(scripts.getItem(i)); | |||
String src = element.getSrc(); | |||
if (src != null && src.length() != 0) { | |||
loadedResources.add(src); | |||
} | |||
} | |||
NodeList<Element> links = document.getElementsByTagName("link"); | |||
for (int i = 0; i < links.getLength(); i++) { | |||
LinkElement linkElement = LinkElement.as(links.getItem(i)); | |||
String rel = linkElement.getRel(); | |||
String href = linkElement.getHref(); | |||
if ("stylesheet".equalsIgnoreCase(rel) && href != null | |||
&& href.length() != 0) { | |||
loadedResources.add(href); | |||
} | |||
} | |||
} | |||
/** | |||
* Returns the default ResourceLoader | |||
* | |||
* @return the default ResourceLoader | |||
*/ | |||
public static ResourceLoader get() { | |||
return INSTANCE; | |||
} | |||
/** | |||
* Load a script and notify a listener when the script is loaded. Calling | |||
* this method when the script is currently loading or already loaded | |||
* doesn't cause the script to be loaded again, but the listener will still | |||
* be notified when appropriate. | |||
* | |||
* | |||
* @param scriptUrl | |||
* the url of the script to load | |||
* @param resourceLoadListener | |||
* the listener that will get notified when the script is loaded | |||
*/ | |||
public void loadScript(final String scriptUrl, | |||
final ResourceLoadListener resourceLoadListener) { | |||
final String url = getAbsoluteUrl(scriptUrl); | |||
if (loadedResources.contains(url)) { | |||
if (resourceLoadListener != null) { | |||
resourceLoadListener.onResourceLoad(new ResourceLoadEvent(this, | |||
url, false)); | |||
} | |||
return; | |||
} | |||
if (preloadListeners.containsKey(url)) { | |||
preloadResource(url, new ResourceLoadListener() { | |||
public void onResourceLoad(ResourceLoadEvent event) { | |||
loadScript(url, resourceLoadListener); | |||
} | |||
}); | |||
return; | |||
} | |||
if (addListener(url, resourceLoadListener, loadListeners)) { | |||
ScriptElement scriptTag = Document.get().createScriptElement(); | |||
scriptTag.setSrc(url); | |||
scriptTag.setType("text/javascript"); | |||
addOnloadHandler(scriptTag, url, false); | |||
head.appendChild(scriptTag); | |||
} | |||
} | |||
private static String getAbsoluteUrl(String url) { | |||
AnchorElement a = Document.get().createAnchorElement(); | |||
a.setHref(url); | |||
return a.getHref(); | |||
} | |||
/** | |||
* Download a resource and notify a listener when the resource is loaded | |||
* without attempting to interpret the resource. When a resource has been | |||
* preloaded, it will be present in the browser's cache (provided the HTTP | |||
* headers allow caching), making a subsequent load operation complete | |||
* without having to wait for the resource to be downloaded again. | |||
* | |||
* Calling this method when the resource is currently loading, currently | |||
* preloading, already preloaded or already loaded doesn't cause the | |||
* resource to be preloaded again, but the listener will still be notified | |||
* when appropriate. | |||
* | |||
* @param url | |||
* the url of the resource to preload | |||
* @param resourceLoadListener | |||
* the listener that will get notified when the resource is | |||
* preloaded | |||
*/ | |||
public void preloadResource(String url, | |||
ResourceLoadListener resourceLoadListener) { | |||
url = getAbsoluteUrl(url); | |||
if (loadedResources.contains(url) || preloadedResources.contains(url)) { | |||
if (resourceLoadListener != null) { | |||
resourceLoadListener.onResourceLoad(new ResourceLoadEvent(this, | |||
url, !loadedResources.contains(url))); | |||
} | |||
return; | |||
} | |||
if (addListener(url, resourceLoadListener, preloadListeners) | |||
&& !loadListeners.containsKey(url)) { | |||
// Inject loader element if this is the first time this is preloaded | |||
// AND the resources isn't already being loaded in the normal way | |||
Element element = getPreloadElement(url); | |||
addOnloadHandler(element, url, true); | |||
// TODO Remove object when loaded (without causing spinner in FF) | |||
Document.get().getBody().appendChild(element); | |||
} | |||
} | |||
private static Element getPreloadElement(String url) { | |||
if (BrowserInfo.get().isIE()) { | |||
ScriptElement element = Document.get().createScriptElement(); | |||
element.setSrc(url); | |||
element.setType("text/cache"); | |||
return element; | |||
} else { | |||
ObjectElement element = Document.get().createObjectElement(); | |||
element.setData(url); | |||
element.setType("text/plain"); | |||
element.setHeight("0px"); | |||
element.setWidth("0px"); | |||
return element; | |||
} | |||
} | |||
private native void addOnloadHandler(Element element, String url, | |||
boolean preload) | |||
/*-{ | |||
var self = this; | |||
var done = $entry(function() { | |||
element.onloadDone = true; | |||
element.onload = null; | |||
element.onreadystatechange = null; | |||
self.@com.vaadin.terminal.gwt.client.ResourceLoader::onResourceLoad(Ljava/lang/String;Z)(url, preload); | |||
}); | |||
element.onload = function() { | |||
if (!element.onloadDone) { | |||
done(); | |||
} | |||
}; | |||
element.onreadystatechange = function() { | |||
if (("loaded" === element.readyState || "complete" === element.readyState) && !element.onloadDone ) { | |||
done(); | |||
} | |||
}; | |||
}-*/; | |||
/** | |||
* Load a stylesheet and notify a listener when the stylesheet is loaded. | |||
* Calling this method when the stylesheet is currently loading or already | |||
* loaded doesn't cause the stylesheet to be loaded again, but the listener | |||
* will still be notified when appropriate. | |||
* | |||
* @param stylesheetUrl | |||
* the url of the stylesheet to load | |||
* @param resourceLoadListener | |||
* the listener that will get notified when the stylesheet is | |||
* loaded | |||
*/ | |||
public void loadStylesheet(final String stylesheetUrl, | |||
final ResourceLoadListener resourceLoadListener) { | |||
final String url = getAbsoluteUrl(stylesheetUrl); | |||
if (loadedResources.contains(url)) { | |||
if (resourceLoadListener != null) { | |||
resourceLoadListener.onResourceLoad(new ResourceLoadEvent(this, | |||
url, false)); | |||
} | |||
return; | |||
} | |||
if (preloadListeners.containsKey(url)) { | |||
preloadResource(url, new ResourceLoadListener() { | |||
public void onResourceLoad(ResourceLoadEvent event) { | |||
loadStylesheet(url, resourceLoadListener); | |||
} | |||
}); | |||
return; | |||
} | |||
if (addListener(url, resourceLoadListener, loadListeners)) { | |||
LinkElement linkElement = Document.get().createLinkElement(); | |||
linkElement.setRel("stylesheet"); | |||
linkElement.setType("text/css"); | |||
linkElement.setHref(url); | |||
if (BrowserInfo.get().isSafari()) { | |||
// Safari doesn't fire onload events for link elements | |||
// See http://www.phpied.com/when-is-a-stylesheet-really-loaded/ | |||
// TODO Stop checking after some timeout | |||
Scheduler.get().scheduleFixedPeriod(new RepeatingCommand() { | |||
public boolean execute() { | |||
if (isStyleSheetPresent(url)) { | |||
onResourceLoad(url, false); | |||
return false; // Stop repeating | |||
} else { | |||
return true; // Continue repeating | |||
} | |||
} | |||
}, 10); | |||
} else { | |||
addOnloadHandler(linkElement, url, false); | |||
} | |||
head.appendChild(linkElement); | |||
} | |||
} | |||
private static native boolean isStyleSheetPresent(String url) | |||
/*-{ | |||
for(var i = 0; i < $doc.styleSheets.length; i++) { | |||
if ($doc.styleSheets[i].href === url) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
}-*/; | |||
private static boolean addListener(String url, | |||
ResourceLoadListener listener, | |||
Map<String, Collection<ResourceLoadListener>> listenerMap) { | |||
Collection<ResourceLoadListener> listeners = listenerMap.get(url); | |||
if (listeners == null) { | |||
listeners = new HashSet<ResourceLoader.ResourceLoadListener>(); | |||
listeners.add(listener); | |||
listenerMap.put(url, listeners); | |||
return true; | |||
} else { | |||
listeners.add(listener); | |||
return false; | |||
} | |||
} | |||
private void onResourceLoad(String resource, boolean preload) { | |||
Collection<ResourceLoadListener> listeners; | |||
if (preload) { | |||
preloadedResources.add(resource); | |||
listeners = preloadListeners.remove(resource); | |||
} else { | |||
if (preloadListeners.containsKey(resource)) { | |||
// Also fire preload events for potential listeners | |||
onResourceLoad(resource, true); | |||
} | |||
preloadedResources.remove(resource); | |||
loadedResources.add(resource); | |||
listeners = loadListeners.remove(resource); | |||
} | |||
if (listeners != null && !listeners.isEmpty()) { | |||
ResourceLoadEvent event = new ResourceLoadEvent(this, resource, | |||
preload); | |||
for (ResourceLoadListener listener : listeners) { | |||
if (listener != null) { | |||
listener.onResourceLoad(event); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -25,6 +25,7 @@ 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; | |||
@@ -46,6 +47,8 @@ import com.vaadin.Application; | |||
import com.vaadin.Application.SystemMessages; | |||
import com.vaadin.RootRequiresMoreInformationException; | |||
import com.vaadin.Version; | |||
import com.vaadin.annotations.JavaScript; | |||
import com.vaadin.annotations.StyleSheet; | |||
import com.vaadin.external.json.JSONArray; | |||
import com.vaadin.external.json.JSONException; | |||
import com.vaadin.external.json.JSONObject; | |||
@@ -497,10 +500,11 @@ public abstract class AbstractCommunicationManager implements Serializable { | |||
* found | |||
* @throws IOException | |||
* @throws InvalidUIDLSecurityKeyException | |||
* @throws JSONException | |||
*/ | |||
public void handleUidlRequest(WrappedRequest request, | |||
WrappedResponse response, Callback callback, Root root) | |||
throws IOException, InvalidUIDLSecurityKeyException { | |||
throws IOException, InvalidUIDLSecurityKeyException, JSONException { | |||
checkWidgetsetVersion(request); | |||
requestThemeName = request.getParameter("theme"); | |||
@@ -696,11 +700,12 @@ public abstract class AbstractCommunicationManager implements Serializable { | |||
* @param analyzeLayouts | |||
* @throws PaintException | |||
* @throws IOException | |||
* @throws JSONException | |||
*/ | |||
private void paintAfterVariableChanges(WrappedRequest request, | |||
WrappedResponse response, Callback callback, boolean repaintAll, | |||
final PrintWriter outWriter, Root root, boolean analyzeLayouts) | |||
throws PaintException, IOException { | |||
throws PaintException, IOException, JSONException { | |||
// Removes application if it has stopped during variable changes | |||
if (!application.isRunning()) { | |||
@@ -764,7 +769,7 @@ public abstract class AbstractCommunicationManager implements Serializable { | |||
@SuppressWarnings("unchecked") | |||
public void writeUidlResponse(WrappedRequest request, boolean repaintAll, | |||
final PrintWriter outWriter, Root root, boolean analyzeLayouts) | |||
throws PaintException { | |||
throws PaintException, JSONException { | |||
ArrayList<ClientConnector> dirtyVisibleConnectors = new ArrayList<ClientConnector>(); | |||
Application application = root.getApplication(); | |||
// Paints components | |||
@@ -1095,10 +1100,14 @@ public abstract class AbstractCommunicationManager implements Serializable { | |||
boolean typeMappingsOpen = false; | |||
ClientCache clientCache = getClientCache(root); | |||
List<Class<? extends ClientConnector>> newConnectorTypes = new ArrayList<Class<? extends ClientConnector>>(); | |||
for (Class<? extends ClientConnector> class1 : usedClientConnectors) { | |||
if (clientCache.cache(class1)) { | |||
// client does not know the mapping key for this type, send | |||
// mapping to client | |||
newConnectorTypes.add(class1); | |||
if (!typeMappingsOpen) { | |||
typeMappingsOpen = true; | |||
outWriter.print(", \"typeMappings\" : { "); | |||
@@ -1142,6 +1151,54 @@ public abstract class AbstractCommunicationManager implements Serializable { | |||
} | |||
} | |||
/* | |||
* Ensure super classes come before sub classes to get script dependency | |||
* order right. Sub class @JavaScript might assume that @JavaScript | |||
* defined by super class is already loaded. | |||
*/ | |||
Collections.sort(newConnectorTypes, new Comparator<Class<?>>() { | |||
public int compare(Class<?> o1, Class<?> o2) { | |||
// TODO optimize using Class.isAssignableFrom? | |||
return hierarchyDepth(o1) - hierarchyDepth(o2); | |||
} | |||
private int hierarchyDepth(Class<?> type) { | |||
if (type == Object.class) { | |||
return 0; | |||
} else { | |||
return hierarchyDepth(type.getSuperclass()) + 1; | |||
} | |||
} | |||
}); | |||
List<String> scriptDependencies = new ArrayList<String>(); | |||
List<String> styleDependencies = new ArrayList<String>(); | |||
for (Class<? extends ClientConnector> class1 : newConnectorTypes) { | |||
JavaScript jsAnnotation = class1.getAnnotation(JavaScript.class); | |||
if (jsAnnotation != null) { | |||
scriptDependencies.addAll(Arrays.asList(jsAnnotation.value())); | |||
} | |||
StyleSheet styleAnnotation = class1.getAnnotation(StyleSheet.class); | |||
if (styleAnnotation != null) { | |||
styleDependencies | |||
.addAll(Arrays.asList(styleAnnotation.value())); | |||
} | |||
} | |||
// Include script dependencies in output if there are any | |||
if (!scriptDependencies.isEmpty()) { | |||
outWriter.print(", \"scriptDependencies\": " | |||
+ new JSONArray(scriptDependencies).toString()); | |||
} | |||
// Include style dependencies in output if there are any | |||
if (!styleDependencies.isEmpty()) { | |||
outWriter.print(", \"styleDependencies\": " | |||
+ new JSONArray(styleDependencies).toString()); | |||
} | |||
// add any pending locale definitions requested by the client | |||
printLocaleDeclarations(outWriter); | |||
@@ -1380,7 +1437,7 @@ public abstract class AbstractCommunicationManager implements Serializable { | |||
private boolean handleVariables(WrappedRequest request, | |||
WrappedResponse response, Callback callback, | |||
Application application2, Root root) throws IOException, | |||
InvalidUIDLSecurityKeyException { | |||
InvalidUIDLSecurityKeyException, JSONException { | |||
boolean success = true; | |||
String changes = getRequestPayload(request); | |||
@@ -2256,9 +2313,11 @@ public abstract class AbstractCommunicationManager implements Serializable { | |||
* @return a string with the initial UIDL message | |||
* @throws PaintException | |||
* if an exception occurs while painting | |||
* @throws JSONException | |||
* if an exception occurs while encoding output | |||
*/ | |||
protected String getInitialUIDL(WrappedRequest request, Root root) | |||
throws PaintException { | |||
throws PaintException, JSONException { | |||
// TODO maybe unify writeUidlResponse()? | |||
StringWriter sWriter = new StringWriter(); | |||
PrintWriter pWriter = new PrintWriter(sWriter); |
@@ -9,10 +9,6 @@ import java.io.IOException; | |||
import java.io.OutputStreamWriter; | |||
import java.io.Serializable; | |||
import java.io.Writer; | |||
import java.lang.annotation.Annotation; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.Map; | |||
import javax.servlet.http.HttpServletResponse; | |||
@@ -20,7 +16,6 @@ import javax.servlet.http.HttpServletResponse; | |||
import com.vaadin.Application; | |||
import com.vaadin.RootRequiresMoreInformationException; | |||
import com.vaadin.Version; | |||
import com.vaadin.annotations.LoadScripts; | |||
import com.vaadin.external.json.JSONException; | |||
import com.vaadin.external.json.JSONObject; | |||
import com.vaadin.terminal.DeploymentConfiguration; | |||
@@ -490,50 +485,6 @@ public abstract class BootstrapHandler implements RequestHandler { | |||
page.write("<title>" | |||
+ AbstractApplicationServlet.safeEscapeForHtml(title) | |||
+ "</title>\n"); | |||
if (root != null) { | |||
List<LoadScripts> loadScriptsAnnotations = getAnnotationsFor( | |||
root.getClass(), LoadScripts.class); | |||
Collections.reverse(loadScriptsAnnotations); | |||
// Begin from the end as a class might requests scripts that depend | |||
// on script loaded by a super class | |||
for (int i = loadScriptsAnnotations.size() - 1; i >= 0; i--) { | |||
LoadScripts loadScripts = loadScriptsAnnotations.get(i); | |||
String[] value = loadScripts.value(); | |||
if (value != null) { | |||
for (String script : value) { | |||
page.write("<script type='text/javascript' src='"); | |||
page.write(script); | |||
page.write("'></script>\n"); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
private static <T extends Annotation> List<T> getAnnotationsFor( | |||
Class<?> type, Class<T> annotationType) { | |||
List<T> list = new ArrayList<T>(); | |||
// Find from the class hierarchy | |||
Class<?> currentType = type; | |||
while (currentType != Object.class) { | |||
T annotation = currentType.getAnnotation(annotationType); | |||
if (annotation != null) { | |||
list.add(annotation); | |||
} | |||
currentType = currentType.getSuperclass(); | |||
} | |||
// Find from an implemented interface | |||
for (Class<?> iface : type.getInterfaces()) { | |||
T annotation = iface.getAnnotation(annotationType); | |||
if (annotation != null) { | |||
list.add(annotation); | |||
} | |||
} | |||
return list; | |||
} | |||
/** | |||
@@ -645,8 +596,10 @@ public abstract class BootstrapHandler implements RequestHandler { | |||
* @return a string with the initial UIDL message | |||
* @throws PaintException | |||
* if an exception occurs while painting the components | |||
* @throws JSONException | |||
* if an exception occurs while formatting the output | |||
*/ | |||
protected abstract String getInitialUIDL(WrappedRequest request, Root root) | |||
throws PaintException; | |||
throws PaintException, JSONException; | |||
} |
@@ -15,6 +15,7 @@ import java.util.UUID; | |||
import javax.servlet.ServletContext; | |||
import com.vaadin.Application; | |||
import com.vaadin.external.json.JSONException; | |||
import com.vaadin.terminal.PaintException; | |||
import com.vaadin.terminal.StreamVariable; | |||
import com.vaadin.terminal.WrappedRequest; | |||
@@ -245,7 +246,7 @@ public class CommunicationManager extends AbstractCommunicationManager { | |||
@Override | |||
protected String getInitialUIDL(WrappedRequest request, Root root) | |||
throws PaintException { | |||
throws PaintException, JSONException { | |||
return CommunicationManager.this.getInitialUIDL(request, root); | |||
} | |||
}; |
@@ -104,7 +104,7 @@ public class PortletCommunicationManager extends AbstractCommunicationManager { | |||
@Override | |||
public void handleUidlRequest(WrappedRequest request, | |||
WrappedResponse response, Callback callback, Root root) | |||
throws IOException, InvalidUIDLSecurityKeyException { | |||
throws IOException, InvalidUIDLSecurityKeyException, JSONException { | |||
setCurrentMimeReponse(response); | |||
super.handleUidlRequest(request, response, callback, root); | |||
currentMimeResponse = null; | |||
@@ -253,7 +253,7 @@ public class PortletCommunicationManager extends AbstractCommunicationManager { | |||
@Override | |||
protected String getInitialUIDL(WrappedRequest request, Root root) | |||
throws PaintException { | |||
throws PaintException, JSONException { | |||
return PortletCommunicationManager.this.getInitialUIDL(request, | |||
root); | |||
} |
@@ -6,7 +6,7 @@ package com.vaadin.tests.components.javascriptcomponent; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import com.vaadin.annotations.LoadScripts; | |||
import com.vaadin.annotations.JavaScript; | |||
import com.vaadin.external.json.JSONArray; | |||
import com.vaadin.external.json.JSONException; | |||
import com.vaadin.terminal.WrappedRequest; | |||
@@ -17,7 +17,6 @@ import com.vaadin.ui.AbstractJavaScriptComponent; | |||
import com.vaadin.ui.JavaScriptCallback; | |||
import com.vaadin.ui.Notification; | |||
@LoadScripts({ "/statictestfiles/jsconnector.js" }) | |||
public class BasicJavaScriptComponent extends AbstractTestRoot { | |||
public interface ExampleClickRpc extends ServerRpc { | |||
@@ -36,6 +35,7 @@ public class BasicJavaScriptComponent extends AbstractTestRoot { | |||
} | |||
} | |||
@JavaScript("/statictestfiles/jsconnector.js") | |||
public static class ExampleWidget extends AbstractJavaScriptComponent { | |||
public ExampleWidget() { | |||
registerRpc(new ExampleClickRpc() { |
@@ -4,7 +4,8 @@ | |||
package com.vaadin.tests.extensions; | |||
import com.vaadin.annotations.LoadScripts; | |||
import com.vaadin.annotations.JavaScript; | |||
import com.vaadin.annotations.StyleSheet; | |||
import com.vaadin.external.json.JSONArray; | |||
import com.vaadin.external.json.JSONException; | |||
import com.vaadin.terminal.AbstractJavaScriptExtension; | |||
@@ -18,7 +19,6 @@ import com.vaadin.ui.Button.ClickEvent; | |||
import com.vaadin.ui.JavaScriptCallback; | |||
import com.vaadin.ui.Notification; | |||
@LoadScripts({ "/statictestfiles/jsextension.js" }) | |||
public class SimpleJavaScriptExtensionTest extends AbstractTestRoot { | |||
public static class SimpleJavaScriptExtensionState extends | |||
@@ -44,6 +44,8 @@ public class SimpleJavaScriptExtensionTest extends AbstractTestRoot { | |||
public void greet(String message); | |||
} | |||
@JavaScript("/statictestfiles/jsextension.js") | |||
@StyleSheet("/VAADIN/external1.css") | |||
public static class SimpleJavascriptExtension extends | |||
AbstractJavaScriptExtension { | |||