Kaynağa Gözat

Support @Delayable and change window size update to use it (#8421)

tags/7.0.0.beta1
Leif Åstrand 11 yıl önce
ebeveyn
işleme
890356e6ab

+ 6
- 1
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java Dosyayı Görüntüle

@@ -29,6 +29,7 @@ import com.google.gwt.core.ext.typeinfo.JParameter;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.vaadin.shared.annotations.Delayed;
import com.vaadin.shared.communication.MethodInvocation;
import com.vaadin.shared.communication.ServerRpc;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
@@ -129,6 +130,10 @@ public class RpcProxyGenerator extends Generator {
writer.println(" {");
writer.indent();

Delayed delayedAnnotation = m.getAnnotation(Delayed.class);
boolean delayed = delayedAnnotation != null;
boolean lastonly = delayed && delayedAnnotation.lastonly();

writer.print("this.connector.getConnection().addMethodInvocationToQueue(new MethodInvocation(this.connector.getConnectorId(), \""
+ requestedType.getQualifiedBinaryName() + "\", \"");
writer.print(m.getName());
@@ -145,7 +150,7 @@ public class RpcProxyGenerator extends Generator {

writer.print(p.getName());
}
writer.println("}), true);");
writer.println("}), " + delayed + ", " + lastonly + ");");

writer.outdent();
writer.println("}");

+ 60
- 30
client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java Dosyayı Görüntüle

@@ -22,6 +22,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -54,9 +55,9 @@ import com.google.gwt.user.client.ui.Widget;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.ComponentState;
import com.vaadin.shared.Version;
import com.vaadin.shared.communication.LegacyChangeVariablesInvocation;
import com.vaadin.shared.communication.MethodInvocation;
import com.vaadin.shared.communication.SharedState;
import com.vaadin.shared.communication.UidlValue;
import com.vaadin.terminal.gwt.client.ApplicationConfiguration.ErrorMessage;
import com.vaadin.terminal.gwt.client.ResourceLoader.ResourceLoadEvent;
import com.vaadin.terminal.gwt.client.ResourceLoader.ResourceLoadListener;
@@ -132,7 +133,18 @@ public class ApplicationConnection {

private final HashMap<String, String> resourcesMap = new HashMap<String, String>();

private ArrayList<MethodInvocation> pendingInvocations = new ArrayList<MethodInvocation>();
/**
* The pending method invocations that will be send to the server by
* {@link #sendPendingCommand}. The key is defined differently based on
* whether the method invocation is enqueued with lastonly. With lastonly
* enabled, the method signature ( {@link MethodInvocation#getLastonlyTag()}
* ) is used as the key to make enable removing a previously enqueued
* invocation. Without lastonly, an incremental id based on
* {@link #lastInvocationTag} is used to get unique values.
*/
private LinkedHashMap<String, MethodInvocation> pendingInvocations = new LinkedHashMap<String, MethodInvocation>();

private int lastInvocationTag = 0;

private WidgetSet widgetSet;

@@ -155,7 +167,7 @@ public class ApplicationConnection {
private ApplicationConfiguration configuration;

/** List of pending variable change bursts that must be submitted in order */
private final ArrayList<ArrayList<MethodInvocation>> pendingBursts = new ArrayList<ArrayList<MethodInvocation>>();
private final ArrayList<LinkedHashMap<String, MethodInvocation>> pendingBursts = new ArrayList<LinkedHashMap<String, MethodInvocation>>();

/** Timer for automatic refirect to SessionExpiredURL */
private Timer redirectTimer;
@@ -886,12 +898,11 @@ public class ApplicationConnection {
private void checkForPendingVariableBursts() {
cleanVariableBurst(pendingInvocations);
if (pendingBursts.size() > 0) {
for (Iterator<ArrayList<MethodInvocation>> iterator = pendingBursts
.iterator(); iterator.hasNext();) {
cleanVariableBurst(iterator.next());
for (LinkedHashMap<String, MethodInvocation> pendingBurst : pendingBursts) {
cleanVariableBurst(pendingBurst);
}
ArrayList<MethodInvocation> nextBurst = pendingBursts.get(0);
pendingBursts.remove(0);
LinkedHashMap<String, MethodInvocation> nextBurst = pendingBursts
.remove(0);
buildAndSendVariableBurst(nextBurst, false);
}
}
@@ -902,13 +913,15 @@ public class ApplicationConnection {
*
* @param variableBurst
*/
private void cleanVariableBurst(ArrayList<MethodInvocation> variableBurst) {
for (int i = 1; i < variableBurst.size(); i++) {
String id = variableBurst.get(i).getConnectorId();
private void cleanVariableBurst(
LinkedHashMap<String, MethodInvocation> variableBurst) {
Iterator<MethodInvocation> iterator = variableBurst.values().iterator();
while (iterator.hasNext()) {
String id = iterator.next().getConnectorId();
if (!getConnectorMap().hasConnector(id)
&& !getConnectorMap().isDragAndDropPaintable(id)) {
// variable owner does not exist anymore
variableBurst.remove(i);
iterator.remove();
VConsole.log("Removed variable from removed component: " + id);
}
}
@@ -1693,12 +1706,10 @@ public class ApplicationConnection {

private void addVariableToQueue(String connectorId, String variableName,
Object value, boolean immediate) {
boolean lastOnly = !immediate;
// note that type is now deduced from value
// TODO could eliminate invocations of same shared variable setter
addMethodInvocationToQueue(new MethodInvocation(connectorId,
ApplicationConstants.UPDATE_VARIABLE_INTERFACE,
ApplicationConstants.UPDATE_VARIABLE_METHOD, new Object[] {
variableName, new UidlValue(value) }), immediate);
addMethodInvocationToQueue(new LegacyChangeVariablesInvocation(
connectorId, variableName, value), lastOnly, lastOnly);
}

/**
@@ -1708,16 +1719,31 @@ public class ApplicationConnection {
*
* @param invocation
* RPC method invocation
* @param immediate
* true to trigger sending within a short time window (possibly
* combining subsequent calls to a single request), false to let
* the framework delay sending of RPC calls and variable changes
* until the next immediate change
* @param delayed
* <code>false</code> to trigger sending within a short time
* window (possibly combining subsequent calls to a single
* request), <code>true</code> to let the framework delay sending
* of RPC calls and variable changes until the next non-delayed
* change
* @param lastonly
* <code>true</code> to remove all previously delayed invocations
* of the same method that were also enqueued with lastonly set
* to <code>true</code>. <code>false</code> to add invocation to
* the end of the queue without touching previously enqueued
* invocations.
*/
public void addMethodInvocationToQueue(MethodInvocation invocation,
boolean immediate) {
pendingInvocations.add(invocation);
if (immediate) {
boolean delayed, boolean lastonly) {
String tag;
if (lastonly) {
tag = invocation.getLastonlyTag();
assert !tag.matches("\\d+") : "getLastonlyTag value must have at least one non-digit character";
pendingInvocations.remove(tag);
} else {
tag = Integer.toString(lastInvocationTag++);
}
pendingInvocations.put(tag, invocation);
if (!delayed) {
sendPendingVariableChanges();
}
}
@@ -1748,14 +1774,15 @@ public class ApplicationConnection {
};
private boolean deferedSendPending = false;

@SuppressWarnings("unchecked")
private void doSendPendingVariableChanges() {
if (applicationRunning) {
if (hasActiveRequest()) {
// skip empty queues if there are pending bursts to be sent
if (pendingInvocations.size() > 0 || pendingBursts.size() == 0) {
pendingBursts.add(pendingInvocations);
pendingInvocations = new ArrayList<MethodInvocation>();
pendingInvocations = new LinkedHashMap<String, MethodInvocation>();
// Keep tag string short
lastInvocationTag = 0;
}
} else {
buildAndSendVariableBurst(pendingInvocations, false);
@@ -1776,17 +1803,18 @@ public class ApplicationConnection {
* Should we use synchronous request?
*/
private void buildAndSendVariableBurst(
ArrayList<MethodInvocation> pendingInvocations, boolean forceSync) {
LinkedHashMap<String, MethodInvocation> pendingInvocations,
boolean forceSync) {
final StringBuffer req = new StringBuffer();

while (!pendingInvocations.isEmpty()) {
if (ApplicationConfiguration.isDebugMode()) {
Util.logVariableBurst(this, pendingInvocations);
Util.logVariableBurst(this, pendingInvocations.values());
}

JSONArray reqJson = new JSONArray();

for (MethodInvocation invocation : pendingInvocations) {
for (MethodInvocation invocation : pendingInvocations.values()) {
JSONArray invocationJson = new JSONArray();
invocationJson.set(0,
new JSONString(invocation.getConnectorId()));
@@ -1810,6 +1838,8 @@ public class ApplicationConnection {
req.append(escapeBurstContents(reqJson.toString()));

pendingInvocations.clear();
// Keep tag string short
lastInvocationTag = 0;
// Append all the bursts to this synchronous request
if (forceSync && !pendingBursts.isEmpty()) {
pendingInvocations = pendingBursts.get(0);

+ 3
- 2
client/src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java Dosyayı Görüntüle

@@ -267,7 +267,7 @@ public class JavaScriptConnectorHelper {
}
connector.getConnection().addMethodInvocationToQueue(
new MethodInvocation(connector.getConnectorId(), iface, method,
parameters), true);
parameters), false, false);
}

private String findWildcardInterface(String method) {
@@ -298,7 +298,8 @@ public class JavaScriptConnectorHelper {
connector.getConnectorId(),
"com.vaadin.ui.JavaScript$JavaScriptCallbackRpc", "call",
new Object[] { name, new JSONArray(arguments) });
connector.getConnection().addMethodInvocationToQueue(invocation, true);
connector.getConnection().addMethodInvocationToQueue(invocation, false,
false);
}

public void setNativeState(JavaScriptObject state) {

+ 4
- 4
client/src/com/vaadin/terminal/gwt/client/Util.java Dosyayı Görüntüle

@@ -874,13 +874,13 @@ public class Util {
}

static void logVariableBurst(ApplicationConnection c,
ArrayList<MethodInvocation> loggedBurst) {
Collection<MethodInvocation> loggedBurst) {
try {
VConsole.log("Variable burst to be sent to server:");
String curId = null;
ArrayList<MethodInvocation> invocations = new ArrayList<MethodInvocation>();
for (int i = 0; i < loggedBurst.size(); i++) {
String id = loggedBurst.get(i).getConnectorId();
for (MethodInvocation methodInvocation : loggedBurst) {
String id = methodInvocation.getConnectorId();

if (curId == null) {
curId = id;
@@ -889,7 +889,7 @@ public class Util {
invocations.clear();
curId = id;
}
invocations.add(loggedBurst.get(i));
invocations.add(methodInvocation);
}
if (!invocations.isEmpty()) {
printConnectorInvocations(invocations, curId, c);

+ 1
- 1
client/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavaScriptManagerConnector.java Dosyayı Görüntüle

@@ -124,7 +124,7 @@ public class JavaScriptManagerConnector extends AbstractExtensionConnector {
getConnection().addMethodInvocationToQueue(
new MethodInvocation(getConnectorId(),
"com.vaadin.ui.JavaScript$JavaScriptCallbackRpc",
"call", parameters), true);
"call", parameters), false, false);
}

@Override

+ 12
- 0
client/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java Dosyayı Görüntüle

@@ -23,6 +23,8 @@ import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
@@ -98,6 +100,16 @@ public class RootConnector extends AbstractComponentContainerConnector
schedule(heartbeatInterval);
}
}.schedule(heartbeatInterval);
getWidget().addResizeHandler(new ResizeHandler() {
@Override
public void onResize(ResizeEvent event) {
rpc.resize(event.getHeight(), event.getWidth(),
Window.getClientWidth(), Window.getClientHeight());
if (getState().isImmediate()) {
getConnection().sendPendingVariableChanges();
}
}
});
}

@Override

+ 9
- 11
client/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java Dosyayı Görüntüle

@@ -20,6 +20,7 @@ import java.util.ArrayList;

import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.logical.shared.HasResizeHandlers;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
@@ -50,7 +51,8 @@ import com.vaadin.terminal.gwt.client.ui.textfield.VTextField;
*
*/
public class VRoot extends SimplePanel implements ResizeHandler,
Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable {
Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable,
HasResizeHandlers {

private static final String CLASSNAME = "v-view";

@@ -401,16 +403,7 @@ public class VRoot extends SimplePanel implements ResizeHandler,
int viewHeight = parentElement.getClientHeight();
int viewWidth = parentElement.getClientWidth();

connection.updateVariable(id, "height", viewHeight, false);
connection.updateVariable(id, "width", viewWidth, false);

int windowWidth = Window.getClientWidth();
int windowHeight = Window.getClientHeight();

connection.updateVariable(id, RootConstants.BROWSER_WIDTH_VAR,
windowWidth, false);
connection.updateVariable(id, RootConstants.BROWSER_HEIGHT_VAR,
windowHeight, immediate);
ResizeEvent.fire(this, viewWidth, viewHeight);
}

public native static void goTo(String url)
@@ -458,4 +451,9 @@ public class VRoot extends SimplePanel implements ResizeHandler,
touchScrollHandler.addElement(getElement());
}

@Override
public HandlerRegistration addResizeHandler(ResizeHandler resizeHandler) {
return addHandler(resizeHandler, ResizeEvent.getType());
}

}

+ 7
- 13
server/src/com/vaadin/terminal/Page.java Dosyayı Görüntüle

@@ -376,23 +376,17 @@ public class Page implements Serializable {
.getBrowser();
}

public void setBrowserWindowSize(Integer width, Integer height) {
public void setBrowserWindowSize(int width, int height) {
boolean fireEvent = false;

if (width != null) {
int newWidth = width.intValue();
if (newWidth != browserWindowWidth) {
browserWindowWidth = newWidth;
fireEvent = true;
}
if (width != browserWindowWidth) {
browserWindowWidth = width;
fireEvent = true;
}

if (height != null) {
int newHeight = height.intValue();
if (newHeight != browserWindowHeight) {
browserWindowHeight = newHeight;
fireEvent = true;
}
if (height != browserWindowHeight) {
browserWindowHeight = height;
fireEvent = true;
}

if (fireEvent) {

+ 1
- 0
server/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java Dosyayı Görüntüle

@@ -69,6 +69,7 @@ import com.vaadin.external.json.JSONObject;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.Connector;
import com.vaadin.shared.Version;
import com.vaadin.shared.communication.LegacyChangeVariablesInvocation;
import com.vaadin.shared.communication.MethodInvocation;
import com.vaadin.shared.communication.SharedState;
import com.vaadin.shared.communication.UidlValue;

+ 7
- 6
server/src/com/vaadin/ui/Root.java Dosyayı Görüntüle

@@ -434,6 +434,13 @@ public abstract class Root extends AbstractComponentContainer implements
public void click(MouseEventDetails mouseDetails) {
fireEvent(new ClickEvent(Root.this, mouseDetails));
}

@Override
public void resize(int viewWidth, int viewHeight, int windowWidth,
int windowHeight) {
// TODO We're not doing anything with the view dimensions
getPage().setBrowserWindowSize(windowWidth, windowHeight);
}
};

/**
@@ -582,12 +589,6 @@ public abstract class Root extends AbstractComponentContainer implements
.get(RootConstants.FRAGMENT_VARIABLE);
getPage().setFragment(fragment, true);
}

if (variables.containsKey("height") || variables.containsKey("width")) {
getPage().setBrowserWindowSize((Integer) variables.get("width"),
(Integer) variables.get("height"));
}

}

/*

+ 0
- 19
server/src/com/vaadin/ui/Window.java Dosyayı Görüntüle

@@ -32,7 +32,6 @@ import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.event.ShortcutAction.ModifierKey;
import com.vaadin.event.ShortcutListener;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.root.RootConstants;
import com.vaadin.shared.ui.window.WindowServerRpc;
import com.vaadin.shared.ui.window.WindowState;
import com.vaadin.terminal.PaintException;
@@ -76,10 +75,6 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
}
};

private int browserWindowWidth = -1;

private int browserWindowHeight = -1;

/**
* Creates a new unnamed window with a default layout.
*/
@@ -170,20 +165,6 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
.get("width") != getWidth())) {
sizeHasChanged = true;
}
Integer browserHeightVar = (Integer) variables
.get(RootConstants.BROWSER_HEIGHT_VAR);
if (browserHeightVar != null
&& browserHeightVar.intValue() != browserWindowHeight) {
browserWindowHeight = browserHeightVar.intValue();
sizeHasChanged = true;
}
Integer browserWidthVar = (Integer) variables
.get(RootConstants.BROWSER_WIDTH_VAR);
if (browserWidthVar != null
&& browserWidthVar.intValue() != browserWindowWidth) {
browserWindowWidth = browserWidthVar.intValue();
sizeHasChanged = true;
}

super.changeVariables(source, variables);


+ 54
- 0
shared/src/com/vaadin/shared/annotations/Delayed.java Dosyayı Görüntüle

@@ -0,0 +1,54 @@
/*
* Copyright 2011 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package com.vaadin.shared.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

import com.vaadin.shared.communication.ServerRpc;

/**
* Invoking a method in a {@link ServerRpc} interface marked with this
* annotation will only add the invocation to a queue of outgoing RPC
* invocations, but it will not cause the queue to be purged and sent to the
* server. The queue will instead be sent when any RPC method not marked as @Delayed
* has been invoked.
*
* @author Vaadin Ltd
* @version @VERSION@
* @since 7.0.0
*/
@Target(ElementType.METHOD)
@Documented
public @interface Delayed {
/**
* By setting lastonly to <code>true</code>, any previous invocations of the
* same method will be removed from the queue when a new invocation is
* added. This can be used in cases where only the last value is of
* interest.
* <p>
* The default value is <code>false</code> which means that invoking the
* method multiple times will cause multiple invocations to be enqueued and
* eventually sent to the server.
*
* @return <code>true</code> if only the last invocation of the annotated
* method should be sent to the server, <code>false</code> if all
* enqueued invocations should be sent.
*/
public boolean lastonly() default false;
}

server/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java → shared/src/com/vaadin/shared/communication/LegacyChangeVariablesInvocation.java Dosyayı Görüntüle

@@ -13,13 +13,12 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.terminal.gwt.server;
package com.vaadin.shared.communication;

import java.util.HashMap;
import java.util.Map;

import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.communication.MethodInvocation;

public class LegacyChangeVariablesInvocation extends MethodInvocation {
private Map<String, Object> variableChanges = new HashMap<String, Object>();
@@ -27,7 +26,8 @@ public class LegacyChangeVariablesInvocation extends MethodInvocation {
public LegacyChangeVariablesInvocation(String connectorId,
String variableName, Object value) {
super(connectorId, ApplicationConstants.UPDATE_VARIABLE_INTERFACE,
ApplicationConstants.UPDATE_VARIABLE_METHOD);
ApplicationConstants.UPDATE_VARIABLE_METHOD, new Object[] {
variableName, new UidlValue(value) });
setVariableChange(variableName, value);
}

@@ -47,4 +47,11 @@ public class LegacyChangeVariablesInvocation extends MethodInvocation {
return variableChanges;
}

@Override
public String getLastonlyTag() {
assert variableChanges.size() == 1;
return super.getLastonlyTag()
+ variableChanges.keySet().iterator().next();
}

}

+ 14
- 0
shared/src/com/vaadin/shared/communication/MethodInvocation.java Dosyayı Görüntüle

@@ -71,4 +71,18 @@ public class MethodInvocation implements Serializable {
+ Arrays.toString(parameters) + ")";
}

/**
* Gets a String tag that is used to uniquely identify previous method
* invocations that should be purged from the queue if
* <code>{@literal @}Delay(lastonly = true)</code> is used.
* <p>
* The returned string should contain at least one non-number char to ensure
* it doesn't collide with the keys used for invocations without lastonly.
*
* @return a string identifying this method invocation
*/
public String getLastonlyTag() {
return connectorId + "-" + getInterfaceName() + "-" + getMethodName();
}

}

+ 0
- 4
shared/src/com/vaadin/shared/ui/root/RootConstants.java Dosyayı Görüntüle

@@ -21,11 +21,7 @@ public class RootConstants {
*/
@Deprecated
public static final String RESIZE_LAZY = "rL";
@Deprecated
public static final String BROWSER_HEIGHT_VAR = "browserHeight";

@Deprecated
public static final String BROWSER_WIDTH_VAR = "browserWidth";
@Deprecated
public static final String NOTIFICATION_HTML_CONTENT_NOT_ALLOWED = "useplain";


+ 4
- 1
shared/src/com/vaadin/shared/ui/root/RootServerRpc.java Dosyayı Görüntüle

@@ -15,9 +15,12 @@
*/
package com.vaadin.shared.ui.root;

import com.vaadin.shared.annotations.Delayed;
import com.vaadin.shared.communication.ServerRpc;
import com.vaadin.shared.ui.ClickRpc;

public interface RootServerRpc extends ClickRpc, ServerRpc {

@Delayed(lastonly = true)
public void resize(int viewWidth, int viewHeight, int windowWidth,
int windowHeight);
}

Loading…
İptal
Kaydet