Quellcode durchsuchen

UIDL can now be included in initial html, or second 'browser details' response, to avoid an extra UIDL request. For #8049

tags/7.0.0.alpha1
Marc Englund vor 12 Jahren
Ursprung
Commit
07d18034f1

+ 15
- 0
src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java Datei anzeigen

@@ -143,6 +143,11 @@ public class ApplicationConfiguration implements EntryPoint {
/*-{
return this.getConfig("versionInfo").applicationVersion;
}-*/;

private native String getUIDL()
/*-{
return this.getConfig("uidl");
}-*/;
}

/**
@@ -242,6 +247,16 @@ public class ApplicationConfiguration implements EntryPoint {
id = appId;
}

/**
* Gets the initial UIDL from the DOM, if it was provided during the init
* process.
*
* @return
*/
public String getUIDL() {
return getJsoConfiguration(id).getUIDL();
}

/**
* @return true if the application is served by std. Vaadin servlet and is
* considered to be the only or main content of the host page.

+ 76
- 32
src/com/vaadin/terminal/gwt/client/ApplicationConnection.java Datei anzeigen

@@ -125,6 +125,8 @@ public class ApplicationConnection {

private int activeRequests = 0;

protected boolean cssLoaded = false;

/** Parameters for this application connection loaded from the web-page */
private ApplicationConfiguration configuration;

@@ -191,10 +193,16 @@ public class ApplicationConnection {
* failed to start. This ensures that the applications are started in order,
* to avoid session-id problems.
*
* @return
*/
public void start() {
repaintAll();
String jsonText = configuration.getUIDL();
if (jsonText == null) {
// inital UIDL not in DOM, request later
repaintAll();
} else {
// initial UIDL provided in DOM, continue as if returned by request
handleJSONText(jsonText);
}
}

private native void initializeTestbenchHooks(
@@ -348,6 +356,20 @@ public class ApplicationConnection {
return (activeRequests > 0);
}

public void incrementActiveRequests() {
if (activeRequests < 0) {
activeRequests = 1;
} else {
activeRequests++;
}
}

public void decrementActiveRequests() {
if (activeRequests > 0) {
activeRequests--;
}
}

private String getRepaintAllParameters() {
// collect some client side data that will be sent to server on
// initial uidl request
@@ -496,7 +518,7 @@ public class ApplicationConnection {
(new Timer() {
@Override
public void run() {
activeRequests--;
decrementActiveRequests();
doUidlRequest(uri, payload, synchronous);
}
}).schedule(delay);
@@ -513,28 +535,10 @@ public class ApplicationConnection {
return;
}

final Date start = new Date();
// for(;;);[realjson]
final String jsonText = response.getText().substring(9,
response.getText().length() - 1);
final ValueMap json;
try {
json = parseJSONResponse(jsonText);
} catch (final Exception e) {
endRequest();
showCommunicationError(e.getMessage()
+ " - Original JSON-text:" + jsonText);
return;
}

VConsole.log("JSON parsing took "
+ (new Date().getTime() - start.getTime()) + "ms");
if (applicationRunning) {
handleReceivedJSONMessage(start, jsonText, json);
} else {
applicationRunning = true;
handleWhenCSSLoaded(jsonText, json);
}
handleJSONText(jsonText);
}

};
@@ -558,6 +562,34 @@ public class ApplicationConnection {

}

/**
* Handles received UIDL JSON text, parsing it, and passing it on to the
* appropriate handlers, while logging timiing information.
*
* @param jsonText
*/
private void handleJSONText(String jsonText) {
final Date start = new Date();
final ValueMap json;
try {
json = parseJSONResponse(jsonText);
} catch (final Exception e) {
endRequest();
showCommunicationError(e.getMessage() + " - Original JSON-text:"
+ jsonText);
return;
}

VConsole.log("JSON parsing took "
+ (new Date().getTime() - start.getTime()) + "ms");
if (applicationRunning) {
handleReceivedJSONMessage(start, jsonText, json);
} else {
applicationRunning = true;
handleWhenCSSLoaded(jsonText, json);
}
}

/**
* Sends an asynchronous UIDL request to the server using the given URI.
*
@@ -587,9 +619,7 @@ public class ApplicationConnection {

protected void handleWhenCSSLoaded(final String jsonText,
final ValueMap json) {
int heightOfLoadElement = DOM.getElementPropertyInt(loadElement,
"offsetHeight");
if (heightOfLoadElement == 0 && cssWaits < MAX_CSS_WAITS) {
if (!isCSSLoaded() && cssWaits < MAX_CSS_WAITS) {
(new Timer() {
@Override
public void run() {
@@ -601,6 +631,7 @@ public class ApplicationConnection {
+ "(.v-loading-indicator height == 0)");
cssWaits++;
} else {
cssLoaded = true;
handleReceivedJSONMessage(new Date(), jsonText, json);
if (cssWaits >= MAX_CSS_WAITS) {
VConsole.error("CSS files may have not loaded properly.");
@@ -608,6 +639,17 @@ public class ApplicationConnection {
}
}

/**
* Checks whether or not the CSS is loaded. By default checks the size of
* the loading indicator element.
*
* @return
*/
protected boolean isCSSLoaded() {
return cssLoaded
|| DOM.getElementPropertyInt(loadElement, "offsetHeight") != 0;
}

/**
* Shows the communication error notification.
*
@@ -672,7 +714,7 @@ public class ApplicationConnection {
}

protected void startRequest() {
activeRequests++;
incrementActiveRequests();
requestStartTime = new Date();
// show initial throbber
if (loadTimer == null) {
@@ -700,11 +742,11 @@ public class ApplicationConnection {
checkForPendingVariableBursts();
runPostRequestHooks(configuration.getRootPanelId());
}
activeRequests--;
decrementActiveRequests();
// deferring to avoid flickering
Scheduler.get().scheduleDeferred(new Command() {
public void execute() {
if (activeRequests == 0) {
if (!hasActiveRequest()) {
hideLoadingIndicator();
}
}
@@ -785,12 +827,14 @@ public class ApplicationConnection {
private void hideLoadingIndicator() {
if (loadTimer != null) {
loadTimer.cancel();
if (loadTimer2 != null) {
loadTimer2.cancel();
loadTimer3.cancel();
}
loadTimer = null;
}
if (loadTimer2 != null) {
loadTimer2.cancel();
loadTimer3.cancel();
loadTimer2 = null;
loadTimer3 = null;
}
if (loadElement != null) {
DOM.setStyleAttribute(loadElement, "display", "none");
}

+ 78
- 20
src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java Datei anzeigen

@@ -14,6 +14,7 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.GeneralSecurityException;
@@ -94,7 +95,7 @@ public abstract class AbstractCommunicationManager implements
.getLogger(AbstractCommunicationManager.class.getName());

private static final RequestHandler APP_RESOURCE_HANDLER = new ApplicationResourceHandler();
private static final AjaxPageHandler AJAX_PAGE_HANDLER = new AjaxPageHandler() {
private final AjaxPageHandler ajaxPageHandler = new AjaxPageHandler() {

@Override
protected String getApplicationOrSystemProperty(WrappedRequest request,
@@ -108,6 +109,11 @@ public abstract class AbstractCommunicationManager implements
defaultValue);
}

@Override
protected AbstractCommunicationManager getCommunicationManager() {
return AbstractCommunicationManager.this;
}

};

/**
@@ -203,7 +209,7 @@ public abstract class AbstractCommunicationManager implements
*/
public AbstractCommunicationManager(Application application) {
this.application = application;
application.addRequestHandler(AJAX_PAGE_HANDLER);
application.addRequestHandler(ajaxPageHandler);
application.addRequestHandler(APP_RESOURCE_HANDLER);
requireLocale(application.getLocale().toString());
}
@@ -521,7 +527,7 @@ public abstract class AbstractCommunicationManager implements
* Internally process a UIDL request from the client.
*
* This method calls
* {@link #handleVariables(Request, Response, Callback, Application, Window)}
* {@link #handleVariables(WrappedRequest, WrappedResponse, Callback, Application, Root)}
* to process any changes to variables by the client and then repaints
* affected components using {@link #paintAfterVariableChanges()}.
*
@@ -725,17 +731,7 @@ public abstract class AbstractCommunicationManager implements
.getAttribute(WRITE_SECURITY_TOKEN_FLAG);

if (writeSecurityTokenFlag != null) {
String seckey = (String) request
.getSessionAttribute(ApplicationConnection.UIDL_SECURITY_TOKEN_ID);
if (seckey == null) {
seckey = UUID.randomUUID().toString();
request.setSessionAttribute(
ApplicationConnection.UIDL_SECURITY_TOKEN_ID, seckey);
}
outWriter.print("\"" + ApplicationConnection.UIDL_SECURITY_TOKEN_ID
+ "\":\"");
outWriter.print(seckey);
outWriter.print("\",");
outWriter.print(getSecurityKeyUIDL(request));
}

writeUidlResponce(callback, repaintAll, outWriter, root, analyzeLayouts);
@@ -746,6 +742,41 @@ public abstract class AbstractCommunicationManager implements

}

/**
* Gets the security key (and generates one if needed) as UIDL.
*
* @param request
* @return the security key UIDL or "" if the feature is turned off
*/
public String getSecurityKeyUIDL(WrappedRequest request) {
final String seckey = getSecurityKey(request);
if (seckey != null) {
return "\"" + ApplicationConnection.UIDL_SECURITY_TOKEN_ID
+ "\":\"" + seckey + "\",";
} else {
return "";
}
}

/**
* Gets the security key (and generates one if needed).
*
* @param request
* @return the security key
*/
protected String getSecurityKey(WrappedRequest request) {
String seckey = null;
seckey = (String) request
.getSessionAttribute(ApplicationConnection.UIDL_SECURITY_TOKEN_ID);
if (seckey == null) {
seckey = UUID.randomUUID().toString();
request.setSessionAttribute(
ApplicationConnection.UIDL_SECURITY_TOKEN_ID, seckey);
}

return seckey;
}

public void writeUidlResponce(Callback callback, boolean repaintAll,
final PrintWriter outWriter, Root root, boolean analyzeLayouts)
throws PaintException {
@@ -1075,6 +1106,18 @@ public abstract class AbstractCommunicationManager implements
p.removeListener(this);
}

/**
* Returns false if the cross site request forgery protection is turned off.
*
* @param application
* @return false if the XSRF is turned off, true otherwise
*/
public boolean isXSRFEnabled(Application application) {
return !"true"
.equals(application
.getProperty(AbstractApplicationServlet.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION));
}

/**
* TODO document
*
@@ -1099,9 +1142,7 @@ public abstract class AbstractCommunicationManager implements

// Security: double cookie submission pattern unless disabled by
// property
if (!"true"
.equals(application2
.getProperty(AbstractApplicationServlet.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION))) {
if (isXSRFEnabled(application2)) {
if (bursts.length == 1 && "init".equals(bursts[0])) {
// init request; don't handle any variables, key sent in
// response.
@@ -1936,6 +1977,10 @@ public abstract class AbstractCommunicationManager implements
WrappedResponse response, Application application)
throws IOException {

// if we do not yet have a currentRoot, it should be initialized
// shortly, and we should send the initial UIDL
boolean sendUIDL = Root.getCurrentRoot() == null;

// TODO Handle npe if id has not been registered
CombinedRequest combinedRequest = application
.getCombinedRequest(request);
@@ -1944,11 +1989,11 @@ public abstract class AbstractCommunicationManager implements
Root root = application.getRootForRequest(combinedRequest);

// Use the same logic as for determined roots
String widgetset = AJAX_PAGE_HANDLER.getWidgetsetForRoot(
String widgetset = ajaxPageHandler.getWidgetsetForRoot(
combinedRequest, root);
String theme = AJAX_PAGE_HANDLER.getThemeForRoot(combinedRequest,
String theme = ajaxPageHandler.getThemeForRoot(combinedRequest,
root);
String themeUri = AJAX_PAGE_HANDLER.getThemeUri(theme,
String themeUri = ajaxPageHandler.getThemeUri(theme,
combinedRequest);

// TODO These are not required if it was only the init of the root
@@ -1959,6 +2004,19 @@ public abstract class AbstractCommunicationManager implements
// Root id might have changed based on e.g. window.name
params.put(ApplicationConnection.ROOT_ID_PARAMETER,
root.getRootId());
if (sendUIDL) {
// TODO maybe unify w/ AjaxPageHandler & writeUidlResponCe()?
this.makeAllPaintablesDirty(root);
StringWriter sWriter = new StringWriter();
PrintWriter pWriter = new PrintWriter(sWriter);
pWriter.print("{");
if (isXSRFEnabled(application)) {
pWriter.print(getSecurityKeyUIDL(combinedRequest));
}
writeUidlResponce(null, true, pWriter, root, false);
pWriter.print("}");
params.put("uidl", sWriter.toString());
}
response.getWriter().write(params.toString());
} catch (RootRequiresMoreInformation e) {
// Requiring more information at this point is not allowed

+ 24
- 0
src/com/vaadin/terminal/gwt/server/AjaxPageHandler.java Datei anzeigen

@@ -7,6 +7,8 @@ package com.vaadin.terminal.gwt.server;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringWriter;

import javax.servlet.http.HttpServletResponse;

@@ -22,6 +24,14 @@ import com.vaadin.ui.Root;

public abstract class AjaxPageHandler implements RequestHandler {

/**
* Returns the {@link AbstractCommunicationManager} that is handling the
* communication for the active application.
*
* @return the {@link AbstractCommunicationManager}
*/
protected abstract AbstractCommunicationManager getCommunicationManager();

public boolean handleRequest(Application application,
WrappedRequest request, WrappedResponse response)
throws IOException {
@@ -294,6 +304,20 @@ public abstract class AjaxPageHandler implements RequestHandler {

if (application.isRootInitPending(rootId)) {
appConfig.put("initPending", true);
} else {
// write the initial UIDL into the config
AbstractCommunicationManager manager = getCommunicationManager();
Root root = Root.getCurrentRoot();
manager.makeAllPaintablesDirty(root);
StringWriter sWriter = new StringWriter();
PrintWriter pWriter = new PrintWriter(sWriter);
pWriter.print("{");
if (manager.isXSRFEnabled(application)) {
pWriter.print(manager.getSecurityKeyUIDL(request));
}
manager.writeUidlResponce(null, true, pWriter, root, false);
pWriter.print("}");
appConfig.put("uidl", sWriter.toString());
}

page.write("vaadin.setDefaults(");

Laden…
Abbrechen
Speichern