summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/src/com/vaadin/client/ApplicationConfiguration.java2
-rw-r--r--client/src/com/vaadin/client/ApplicationConnection.java30
-rw-r--r--client/src/com/vaadin/client/Profiler.java260
-rw-r--r--client/src/com/vaadin/client/ui/VScrollTable.java16
-rw-r--r--client/src/com/vaadin/client/ui/embedded/EmbeddedConnector.java7
-rw-r--r--pom-template.xml6
-rwxr-xr-xscripts/merge-check.sh4
-rw-r--r--server/src/com/vaadin/data/Property.java6
-rw-r--r--server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java2
-rw-r--r--server/src/com/vaadin/data/util/BeanContainer.java3
-rw-r--r--server/src/com/vaadin/data/util/BeanItemContainer.java3
-rw-r--r--server/src/com/vaadin/server/BootstrapHandler.java12
-rw-r--r--server/src/com/vaadin/server/StreamResource.java6
-rw-r--r--server/tests/src/com/vaadin/data/fieldgroup/BeanFieldGroupTest.java71
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/ui/CustomUIClassLoader.java5
-rw-r--r--uitest/src/com/vaadin/tests/components/table/TableRowScrolledBottom.html52
-rw-r--r--uitest/src/com/vaadin/tests/components/table/TableRowScrolledBottom.java55
-rw-r--r--uitest/src/com/vaadin/tests/components/ui/CustomUITest.html27
-rw-r--r--uitest/src/com/vaadin/tests/components/ui/CustomUITest.java43
-rw-r--r--uitest/src/com/vaadin/tests/components/uitest/base_theme_test.html4
-rw-r--r--uitest/src/com/vaadin/tests/components/uitest/chameleon_theme_test.html4
-rw-r--r--uitest/src/com/vaadin/tests/components/uitest/liferay_theme_test.html4
-rw-r--r--uitest/src/com/vaadin/tests/components/uitest/reindeer_theme_test.html4
-rw-r--r--uitest/src/com/vaadin/tests/components/uitest/runo_theme_test.html4
-rw-r--r--uitest/src/com/vaadin/tests/extensions/BasicExtensionTest.html4
-rw-r--r--uitest/src/com/vaadin/tests/performance/BasicPerformanceTest.java5
-rw-r--r--uitest/src/com/vaadin/tests/util/TestUtils.java11
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml5
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/CustomUIConnector.java41
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/CustomUIConnectorRpc.java23
30 files changed, 633 insertions, 86 deletions
diff --git a/client/src/com/vaadin/client/ApplicationConfiguration.java b/client/src/com/vaadin/client/ApplicationConfiguration.java
index 9ba660626e..2291f21361 100644
--- a/client/src/com/vaadin/client/ApplicationConfiguration.java
+++ b/client/src/com/vaadin/client/ApplicationConfiguration.java
@@ -535,7 +535,7 @@ public class ApplicationConfiguration implements EntryPoint {
@Override
public void onModuleLoad() {
- Profiler.reset();
+ Profiler.initialize();
Profiler.enter("ApplicationConfiguration.onModuleLoad");
BrowserInfo browserInfo = BrowserInfo.get();
diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java
index 1a637e3161..62827feffb 100644
--- a/client/src/com/vaadin/client/ApplicationConnection.java
+++ b/client/src/com/vaadin/client/ApplicationConnection.java
@@ -16,7 +16,7 @@
package com.vaadin.client;
-import java.util.ArrayList;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
@@ -500,6 +500,7 @@ public class ApplicationConnection {
ap.@com.vaadin.client.ApplicationConnection::totalProcessingTime
];
pd = pd.concat(ap.@com.vaadin.client.ApplicationConnection::serverTimingInfo);
+ pd[pd.length] = ap.@com.vaadin.client.ApplicationConnection::bootstrapTime;
return pd;
});
@@ -513,6 +514,16 @@ public class ApplicationConnection {
$wnd.vaadin.clients[TTAppId] = client;
}-*/;
+ private static native final int calculateBootstrapTime()
+ /*-{
+ if ($wnd.performance && $wnd.performance.timing) {
+ return (new Date).getTime() - $wnd.performance.timing.responseStart;
+ } else {
+ // performance.timing not supported
+ return -1;
+ }
+ }-*/;
+
/**
* Helper for tt initialization
*/
@@ -948,6 +959,15 @@ public class ApplicationConnection {
protected int totalProcessingTime;
/**
+ * Holds the time it took to load the page and render the first view. 0
+ * means that this value has not yet been calculated because the first view
+ * has not yet been rendered (or that your browser is very fast). -1 means
+ * that the browser does not support the performance.timing feature used to
+ * get this measurement.
+ */
+ private int bootstrapTime;
+
+ /**
* Holds the timing information from the server-side. How much time was
* spent servicing the last request and how much time has been spent
* servicing the session so far. These values are always one request behind,
@@ -1512,6 +1532,12 @@ public class ApplicationConnection {
lastProcessingTime = (int) ((new Date().getTime()) - start
.getTime());
totalProcessingTime += lastProcessingTime;
+ if (bootstrapTime == 0) {
+ bootstrapTime = calculateBootstrapTime();
+ if (Profiler.isEnabled() && bootstrapTime != -1) {
+ Profiler.logBootstrapTimings();
+ }
+ }
VConsole.log(" Processing time was "
+ String.valueOf(lastProcessingTime) + "ms for "
@@ -1775,7 +1801,7 @@ public class ApplicationConnection {
.getConnectorClassByEncodedTag(connectorType);
// Connector does not exist so we must create it
- if (connectorClass != UIConnector.class) {
+ if (connectorClass != uIConnector.getClass()) {
// create, initialize and register the paintable
Profiler.enter("ApplicationConnection.getConnector");
connector = getConnector(connectorId, connectorType);
diff --git a/client/src/com/vaadin/client/Profiler.java b/client/src/com/vaadin/client/Profiler.java
index be26da859f..6e8f2f5f9a 100644
--- a/client/src/com/vaadin/client/Profiler.java
+++ b/client/src/com/vaadin/client/Profiler.java
@@ -54,25 +54,45 @@ public class Profiler {
}
}
- private static JsArray<ProfilerEvent> events;
+ private static final String evtGroup = "VaadinProfiler";
- private static final class ProfilerEvent extends JavaScriptObject {
- protected ProfilerEvent() {
+ private static final class GwtStatsEvent extends JavaScriptObject {
+ protected GwtStatsEvent() {
// JSO constructor
}
- public native String getName()
+ private native String getEvtGroup()
/*-{
- return this.name;
+ return this.evtGroup;
}-*/;
- private native double getRawTime()
+ private native double getMillis()
/*-{
- return this.time;
+ return this.millis;
}-*/;
- private boolean isStart() {
- return getRawTime() <= 0;
+ private native String getSubSystem()
+ /*-{
+ return this.subSystem;
+ }-*/;
+
+ private native String getType()
+ /*-{
+ return this.type;
+ }-*/;
+
+ private native String getModuleName()
+ /*-{
+ return this.moduleName;
+ }-*/;
+
+ public final String getEventName() {
+ String group = getEvtGroup();
+ if (evtGroup.equals(group)) {
+ return getSubSystem();
+ } else {
+ return group + "." + getSubSystem();
+ }
}
}
@@ -91,21 +111,17 @@ public class Profiler {
return name;
}
- public Node addEvent(ProfilerEvent event) {
- Node child = children.get(event.getName());
+ private Node accessChild(String name, double time) {
+ Node child = children.get(name);
if (child == null) {
- child = new Node(event.getName());
- children.put(event.getName(), child);
+ child = new Node(name);
+ children.put(name, child);
}
- child.time += event.getRawTime();
+ child.time -= time;
child.count++;
return child;
}
- public void registerEnd(ProfilerEvent event) {
- time += event.getRawTime();
- }
-
public double getTimeSpent() {
return time;
}
@@ -148,6 +164,11 @@ public class Profiler {
}
}
+ @Override
+ public String toString() {
+ return getStringRepresentation("");
+ }
+
private String getStringRepresentation(String prefix) {
if (getName() == null) {
return "";
@@ -229,7 +250,7 @@ public class Profiler {
*/
public static void enter(String name) {
if (isEnabled()) {
- pushEvent(events, name, -Duration.currentTimeMillis());
+ logGwtEvent(name, "begin");
}
}
@@ -243,14 +264,20 @@ public class Profiler {
*/
public static void leave(String name) {
if (isEnabled()) {
- pushEvent(events, name, Duration.currentTimeMillis());
+ logGwtEvent(name, "end");
}
}
- private static native final void pushEvent(JsArray<ProfilerEvent> target,
- String name, double time)
+ private static native final void logGwtEvent(String name, String type)
/*-{
- target[target.length] = {name: name, time: time};
+ $wnd.__gwtStatsEvent({
+ evtGroup: @com.vaadin.client.Profiler::evtGroup,
+ moduleName: @com.google.gwt.core.client.GWT::getModuleName()(),
+ millis: (new Date).getTime(),
+ sessionId: undefined,
+ subSystem: name,
+ type: type
+ });
}-*/;
/**
@@ -259,7 +286,35 @@ public class Profiler {
*/
public static void reset() {
if (isEnabled()) {
- events = JavaScriptObject.createArray().cast();
+ /*
+ * Old implementations might call reset for initialization, so
+ * ensure it is initialized here as well. Initialization has no side
+ * effects if already done.
+ */
+ initialize();
+
+ clearEventsList();
+ }
+ }
+
+ /**
+ * Initializes the profiler. This should be done before calling any other
+ * function in this class. Failing to do so might cause undesired behavior.
+ * This method has no side effects if the initialization has already been
+ * done.
+ * <p>
+ * Please note that this method should be called even if the profiler is not
+ * enabled because it will then remove a logger function that might have
+ * been included in the HTML page and that would leak memory unless removed.
+ * </p>
+ *
+ * @since 7.0.2
+ */
+ public static void initialize() {
+ if (isEnabled()) {
+ ensureLogger();
+ } else {
+ ensureNoLogger();
}
}
@@ -275,25 +330,52 @@ public class Profiler {
LinkedList<Node> stack = new LinkedList<Node>();
Node rootNode = new Node(null);
stack.add(rootNode);
- for (int i = 0; i < events.length(); i++) {
- ProfilerEvent event = events.get(i);
- if (event.isStart()) {
- Node stackTop = stack.getLast().addEvent(event);
- stack.add(stackTop);
- } else {
- Node stackTop = stack.removeLast();
- if (stackTop == null) {
- VConsole.error("Leaving " + event.getName()
- + " that was never entered.");
+ JsArray<GwtStatsEvent> gwtStatsEvents = getGwtStatsEvents();
+ if (gwtStatsEvents.length() == 0) {
+ VConsole.log("No profiling events recorded, this might happen if another __gwtStatsEvent handler is installed.");
+ return;
+ }
+
+ for (int i = 0; i < gwtStatsEvents.length(); i++) {
+ GwtStatsEvent gwtStatsEvent = gwtStatsEvents.get(i);
+ String eventName = gwtStatsEvent.getEventName();
+ String type = gwtStatsEvent.getType();
+ boolean isBeginEvent = "begin".equals(type);
+
+ Node stackTop = stack.getLast();
+ boolean inEvent = eventName.equals(stackTop.getName())
+ && !isBeginEvent;
+
+ if (!inEvent && stack.size() >= 2
+ && eventName.equals(stack.get(stack.size() - 2).name)
+ && !isBeginEvent) {
+ // back out of sub event
+ stackTop.time += gwtStatsEvent.getMillis();
+ stack.removeLast();
+ stackTop = stack.getLast();
+
+ inEvent = true;
+ }
+
+ if (type.equals("end")) {
+ if (!inEvent) {
+ VConsole.error("Got end event for " + eventName
+ + " but is currently in " + stackTop.getName());
return;
}
- if (!stackTop.getName().equals(event.getName())) {
- VConsole.error("Invalid profiling event order, leaving "
- + event.getName() + " but " + stackTop.getName()
- + " was expected");
- return;
+ Node previousStackTop = stack.removeLast();
+ previousStackTop.time += gwtStatsEvent.getMillis();
+ } else {
+ if (!inEvent) {
+ stackTop = stackTop.accessChild(eventName,
+ gwtStatsEvent.getMillis());
+ stack.add(stackTop);
+ }
+ if (!isBeginEvent) {
+ // Create sub event
+ stack.add(stackTop.accessChild(eventName + "." + type,
+ gwtStatsEvent.getMillis()));
}
- stackTop.registerEnd(event);
}
}
@@ -362,4 +444,102 @@ public class Profiler {
return false;
}
+ /**
+ * Outputs the time passed since various events recored in
+ * performance.timing if supported by the browser.
+ */
+ public static void logBootstrapTimings() {
+ if (isEnabled()) {
+ double now = Duration.currentTimeMillis();
+
+ StringBuilder stringBuilder = new StringBuilder(
+ "Time since window.performance.timing events");
+ SimpleTree tree = new SimpleTree(stringBuilder.toString());
+
+ String[] keys = new String[] { "navigationStart",
+ "unloadEventStart", "unloadEventEnd", "redirectStart",
+ "redirectEnd", "fetchStart", "domainLookupStart",
+ "domainLookupEnd", "connectStart", "connectEnd",
+ "requestStart", "responseStart", "responseEnd",
+ "domLoading", "domInteractive",
+ "domContentLoadedEventStart", "domContentLoadedEventEnd",
+ "domComplete", "loadEventStart", "loadEventEnd" };
+
+ for (String key : keys) {
+ double value = getPerformanceTiming(key);
+ if (value == 0) {
+ // Ignore missing value
+ continue;
+ }
+ String text = key + ": " + (now - value);
+ tree.add(new Label(text));
+ stringBuilder.append("\n * ");
+ stringBuilder.append(text);
+ }
+
+ if (tree.getWidgetCount() == 0) {
+ VConsole.log("Bootstrap timings not supported, please ensure your browser supports performance.timing");
+ return;
+ }
+
+ Console implementation = VConsole.getImplementation();
+ if (implementation instanceof VDebugConsole) {
+ VDebugConsole console = (VDebugConsole) implementation;
+ console.showTree(tree, stringBuilder.toString());
+ } else {
+ VConsole.log(stringBuilder.toString());
+ }
+ }
+ }
+
+ private static final native double getPerformanceTiming(String name)
+ /*-{
+ if ($wnd.performance && $wnd.performance.timing && $wnd.performance.timing[name]) {
+ return $wnd.performance.timing[name];
+ } else {
+ return 0;
+ }
+ }-*/;
+
+ private static native JsArray<GwtStatsEvent> getGwtStatsEvents()
+ /*-{
+ return $wnd.vaadin.gwtStatsEvents || [];
+ }-*/;
+
+ /**
+ * Add logger if it's not already there, also initializing the event array
+ * if needed.
+ */
+ private static native void ensureLogger()
+ /*-{
+ if (typeof $wnd.__gwtStatsEvent != 'function') {
+ if (typeof $wnd.vaadin.gwtStatsEvents != 'object') {
+ $wnd.vaadin.gwtStatsEvents = [];
+ }
+ $wnd.__gwtStatsEvent = function(event) {
+ $wnd.vaadin.gwtStatsEvents.push(event);
+ return true;
+ }
+ }
+ }-*/;
+
+ /**
+ * Remove logger function and event array if it seems like the function has
+ * been added by us.
+ */
+ private static native void ensureNoLogger()
+ /*-{
+ if (typeof $wnd.vaadin.gwtStatsEvents == 'object') {
+ delete $wnd.vaadin.gwtStatsEvents;
+ if (typeof $wnd.__gwtStatsEvent == 'function') {
+ $wnd.__gwtStatsEvent = function(){};
+ }
+ }
+ }-*/;
+
+ private static native JsArray<GwtStatsEvent> clearEventsList()
+ /*-{
+ $wnd.vaadin.gwtStatsEvents = [];
+ }-*/;
+
}
diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java
index c76dd38d8f..6f9fd6da88 100644
--- a/client/src/com/vaadin/client/ui/VScrollTable.java
+++ b/client/src/com/vaadin/client/ui/VScrollTable.java
@@ -1098,6 +1098,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
}
+ private ScheduledCommand lazyScroller = new ScheduledCommand() {
+ @Override
+ public void execute() {
+ int offsetTop = measureRowHeightOffset(firstvisible);
+ scrollBodyPanel.setScrollPosition(offsetTop);
+ }
+ };
+
/** For internal use only. May be removed or replaced in the future. */
public void updateFirstVisibleAndScrollIfNeeded(UIDL uidl) {
firstvisible = uidl.hasVariable("firstvisible") ? uidl
@@ -1105,8 +1113,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
if (firstvisible != lastRequestedFirstvisible && scrollBody != null) {
// received 'surprising' firstvisible from server: scroll there
firstRowInViewPort = firstvisible;
- scrollBodyPanel
- .setScrollPosition(measureRowHeightOffset(firstvisible));
+
+ /*
+ * Schedule the scrolling to be executed last so no updates to the rows
+ * affect scrolling measurements.
+ */
+ Scheduler.get().scheduleFinally(lazyScroller);
}
}
diff --git a/client/src/com/vaadin/client/ui/embedded/EmbeddedConnector.java b/client/src/com/vaadin/client/ui/embedded/EmbeddedConnector.java
index bce4242557..c6e4883fa9 100644
--- a/client/src/com/vaadin/client/ui/embedded/EmbeddedConnector.java
+++ b/client/src/com/vaadin/client/ui/embedded/EmbeddedConnector.java
@@ -137,7 +137,8 @@ public class EmbeddedConnector extends AbstractComponentConnector implements
getWidget().getSrc(uidl, client));
clearBrowserElement = false;
} else {
- VConsole.log("Unknown Embedded type '" + getWidget().type + "'");
+ VConsole.error("Unknown Embedded type '" + getWidget().type
+ + "'");
}
} else if (uidl.hasAttribute("mimetype")) {
// remove old style name related to type
@@ -203,10 +204,10 @@ public class EmbeddedConnector extends AbstractComponentConnector implements
.getStringAttribute(EmbeddedConstants.ALTERNATE_TEXT));
}
} else {
- VConsole.log("Unknown Embedded mimetype '" + mime + "'");
+ VConsole.error("Unknown Embedded mimetype '" + mime + "'");
}
} else {
- VConsole.log("Unknown Embedded; no type or mimetype attribute");
+ VConsole.error("Unknown Embedded; no type or mimetype attribute");
}
if (clearBrowserElement) {
diff --git a/pom-template.xml b/pom-template.xml
index 33e6be623e..1716abc82a 100644
--- a/pom-template.xml
+++ b/pom-template.xml
@@ -30,9 +30,9 @@
</license>
</licenses>
<scm>
- <connection>scm:http:http://dev.vaadin.com/git/vaadin.git</connection>
- <developerConnection>scm:ssh:git@dev.vaadin.com/vaadin</developerConnection>
- <url>http://dev.vaadin.com/git/?p=vaadin.git</url>
+ <connection>scm:https:https://github.com/vaadin/vaadin.git</connection>
+ <developerConnection>scm:https:https://github.com/vaadin/vaadin.git</developerConnection>
+ <url>https://github.com/vaadin/vaadin</url>
</scm>
<developers>
<developer>
diff --git a/scripts/merge-check.sh b/scripts/merge-check.sh
index 9e0d5e1e75..e3adf39115 100755
--- a/scripts/merge-check.sh
+++ b/scripts/merge-check.sh
@@ -24,9 +24,7 @@ else
echo $message
echo ""
$command
- # Escape []|' and newline with | to make teamcity happy
- details=`$command|sed "s/[]['\|]/|&/g"|perl -p -e 's/\n/|n/'`
- echo "##teamcity[testFailed name='$testname' message='$message' details='|n$details']"
+ echo "##teamcity[testFailed name='$testname' message='$message']"
fi
echo "##teamcity[testFinished name='$testname']"
diff --git a/server/src/com/vaadin/data/Property.java b/server/src/com/vaadin/data/Property.java
index 8316d765ce..0aa6de1c2e 100644
--- a/server/src/com/vaadin/data/Property.java
+++ b/server/src/com/vaadin/data/Property.java
@@ -116,9 +116,9 @@ public interface Property<T> extends Serializable {
* or rollback.
*
* Note that this does not refer to e.g. database transactions but rather
- * two-phase commit that allows resetting old field values on a form etc. if
- * the commit of one of the properties fails after others have already been
- * committed. If
+ * two-phase commit that allows resetting old field values (in e.g. a
+ * FieldGroup) if the commit of one of the properties fails after other
+ * properties have already been committed.
*
* @param <T>
* The type of the property
diff --git a/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java b/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java
index 502394f38a..0b4e3a8049 100644
--- a/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java
+++ b/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java
@@ -89,7 +89,7 @@ public class BeanFieldGroup<T> extends FieldGroup {
java.lang.reflect.Field field1 = cls
.getDeclaredField(propertyId);
return field1;
- } catch (NoSuchFieldError e) {
+ } catch (NoSuchFieldException e) {
// Try super classes until we reach Object
Class<?> superClass = cls.getSuperclass();
if (superClass != null && superClass != Object.class) {
diff --git a/server/src/com/vaadin/data/util/BeanContainer.java b/server/src/com/vaadin/data/util/BeanContainer.java
index 36ac414ad6..4e435aabcc 100644
--- a/server/src/com/vaadin/data/util/BeanContainer.java
+++ b/server/src/com/vaadin/data/util/BeanContainer.java
@@ -55,8 +55,7 @@ import java.util.Collection;
* </p>
*
* <p>
- * It is not possible to add additional properties to the container and nested
- * bean properties are not supported.
+ * It is not possible to add additional properties to the container.
* </p>
*
* @param <IDTYPE>
diff --git a/server/src/com/vaadin/data/util/BeanItemContainer.java b/server/src/com/vaadin/data/util/BeanItemContainer.java
index b501c06426..e7b38d8b88 100644
--- a/server/src/com/vaadin/data/util/BeanItemContainer.java
+++ b/server/src/com/vaadin/data/util/BeanItemContainer.java
@@ -43,8 +43,7 @@ import java.util.Collection;
* </p>
*
* <p>
- * It is not possible to add additional properties to the container and nested
- * bean properties are not supported.
+ * It is not possible to add additional properties to the container.
* </p>
*
* @param <BEANTYPE>
diff --git a/server/src/com/vaadin/server/BootstrapHandler.java b/server/src/com/vaadin/server/BootstrapHandler.java
index f280bc80b7..03421ce487 100644
--- a/server/src/com/vaadin/server/BootstrapHandler.java
+++ b/server/src/com/vaadin/server/BootstrapHandler.java
@@ -372,6 +372,18 @@ public abstract class BootstrapHandler implements RequestHandler {
boolean isDebug = !context.getSession().getConfiguration()
.isProductionMode();
+ if (isDebug) {
+ /*
+ * Add tracking needed for getting bootstrap metrics to the client
+ * side Profiler if another implementation hasn't already been
+ * added.
+ */
+ builder.append("if (typeof window.__gwtStatsEvent != 'function') {\n");
+ builder.append("vaadin.gwtStatsEvents = [];\n");
+ builder.append("window.__gwtStatsEvent = function(event) {vaadin.gwtStatsEvents.push(event); return true;};\n");
+ builder.append("}\n");
+ }
+
builder.append("vaadin.initApplication(\"");
builder.append(context.getAppId());
builder.append("\",");
diff --git a/server/src/com/vaadin/server/StreamResource.java b/server/src/com/vaadin/server/StreamResource.java
index adc2e23a3c..7210bcaffb 100644
--- a/server/src/com/vaadin/server/StreamResource.java
+++ b/server/src/com/vaadin/server/StreamResource.java
@@ -23,9 +23,7 @@ import com.vaadin.util.FileTypeResolver;
/**
* <code>StreamResource</code> is a resource provided to the client directly by
- * the application. The strean resource is fetched from URI that is most often
- * in the context of the application or window. The resource is automatically
- * registered to window in creation.
+ * the application.
*
* @author Vaadin Ltd.
* @since 3.0
@@ -65,8 +63,6 @@ public class StreamResource implements ConnectorResource {
* the source Stream.
* @param filename
* the name of the file.
- * @param application
- * the Application object.
*/
public StreamResource(StreamSource streamSource, String filename) {
setFilename(filename);
diff --git a/server/tests/src/com/vaadin/data/fieldgroup/BeanFieldGroupTest.java b/server/tests/src/com/vaadin/data/fieldgroup/BeanFieldGroupTest.java
new file mode 100644
index 0000000000..a01c2dea8f
--- /dev/null
+++ b/server/tests/src/com/vaadin/data/fieldgroup/BeanFieldGroupTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2012 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.data.fieldgroup;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+public class BeanFieldGroupTest {
+
+ class Main {
+ private String mainField;
+
+ public String getMainField() {
+ return mainField;
+ }
+
+ public void setMainField(String mainField) {
+ this.mainField = mainField;
+ }
+
+ }
+
+ class Sub1 extends Main {
+ private Integer sub1Field;
+
+ public Integer getSub1Field() {
+ return sub1Field;
+ }
+
+ public void setSub1Field(Integer sub1Field) {
+ this.sub1Field = sub1Field;
+ }
+
+ }
+
+ class Sub2 extends Sub1 {
+ private boolean sub2field;
+
+ public boolean isSub2field() {
+ return sub2field;
+ }
+
+ public void setSub2field(boolean sub2field) {
+ this.sub2field = sub2field;
+ }
+
+ }
+
+ @Test
+ public void propertyTypeWithoutItem() {
+ BeanFieldGroup<Sub2> s = new BeanFieldGroup<BeanFieldGroupTest.Sub2>(
+ Sub2.class);
+ Assert.assertEquals(boolean.class, s.getPropertyType("sub2field"));
+ Assert.assertEquals(Integer.class, s.getPropertyType("sub1Field"));
+ Assert.assertEquals(String.class, s.getPropertyType("mainField"));
+ }
+}
diff --git a/server/tests/src/com/vaadin/tests/server/component/ui/CustomUIClassLoader.java b/server/tests/src/com/vaadin/tests/server/component/ui/CustomUIClassLoader.java
index e02fafeaff..8884c0c27c 100644
--- a/server/tests/src/com/vaadin/tests/server/component/ui/CustomUIClassLoader.java
+++ b/server/tests/src/com/vaadin/tests/server/component/ui/CustomUIClassLoader.java
@@ -52,13 +52,14 @@ public class CustomUIClassLoader extends TestCase {
* @throws Exception
* if thrown
*/
- public void testWithNullClassLoader() throws Exception {
+ public void testWithDefaultClassLoader() throws Exception {
VaadinSession application = createStubApplication();
application.setConfiguration(createConfigurationMock());
DefaultUIProvider uiProvider = new DefaultUIProvider();
Class<? extends UI> uiClass = uiProvider
- .getUIClass(new UIClassSelectionEvent(createRequestMock(null)));
+ .getUIClass(new UIClassSelectionEvent(
+ createRequestMock(getClass().getClassLoader())));
assertEquals(MyUI.class, uiClass);
}
diff --git a/uitest/src/com/vaadin/tests/components/table/TableRowScrolledBottom.html b/uitest/src/com/vaadin/tests/components/table/TableRowScrolledBottom.html
new file mode 100644
index 0000000000..e5b1f47f2d
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/table/TableRowScrolledBottom.html
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://localhost:8888/" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.table.TableRowScrolledBottom?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableRowScrolledBottom::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VButton[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>500</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableRowScrolledBottom::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VScrollTable[0]/FocusableScrollPanel[0]/VScrollTable$VScrollTableBody[0]/VScrollTable$VScrollTableBody$VScrollTableRow[44]/VLabel[0]</td>
+ <td>This is a test item with long text so that there is something to see Nr. 100. This text must be long otherwise the timing issue on Firefox does not occur. This works fine in IE</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableRowScrolledBottom::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>500</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableRowScrolledBottom::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VScrollTable[0]/FocusableScrollPanel[0]/VScrollTable$VScrollTableBody[0]/VScrollTable$VScrollTableBody$VScrollTableRow[44]/VLabel[0]</td>
+ <td>This is a test item with long text so that there is something to see Nr. 200. This text must be long otherwise the timing issue on Firefox does not occur. This works fine in IE</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/table/TableRowScrolledBottom.java b/uitest/src/com/vaadin/tests/components/table/TableRowScrolledBottom.java
new file mode 100644
index 0000000000..9823fc1859
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/table/TableRowScrolledBottom.java
@@ -0,0 +1,55 @@
+package com.vaadin.tests.components.table;
+
+import com.vaadin.shared.ui.label.ContentMode;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.VerticalLayout;
+
+public class TableRowScrolledBottom extends TestBase {
+
+ @Override
+ protected void setup() {
+
+ final Table table = new Table();
+ table.setSizeFull();
+ table.addContainerProperty("Test", Label.class, null);
+ table.setHeight("100%");
+
+ Button button = new Button("Add 100 items");
+ button.addClickListener(new Button.ClickListener() {
+ int i = 0;
+
+ @Override
+ public void buttonClick(Button.ClickEvent event) {
+ for (int j = 0; j < 100; j++) {
+ ++i;
+ table.addItem(
+ new Object[] { new Label(
+ "This is a test item with long text so that there is something to see Nr. <b>"
+ + i
+ + "</b>. This text must be long otherwise the timing issue on Firefox does not occur. This works fine in IE",
+ ContentMode.HTML) }, i);
+ table.setCurrentPageFirstItemIndex(table
+ .getContainerDataSource().size() - 1);
+ }
+ }
+ });
+
+ addComponent(table);
+ addComponent(button);
+ getLayout().setExpandRatio(table, 1f);
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Table should be scrolled to bottom when adding rows and updating currentPageFirstItemIndex to last item";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 10970;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/ui/CustomUITest.html b/uitest/src/com/vaadin/tests/components/ui/CustomUITest.html
new file mode 100644
index 0000000000..90f7df44d2
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/ui/CustomUITest.html
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.ui.CustomUITest?restartApplication&amp;debug=</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>//span</td>
+ <td>This is the CustomUIConnector</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/ui/CustomUITest.java b/uitest/src/com/vaadin/tests/components/ui/CustomUITest.java
new file mode 100644
index 0000000000..3542806a92
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/ui/CustomUITest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2000-2013 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.tests.components.ui;
+
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.tests.widgetset.TestingWidgetSet;
+import com.vaadin.tests.widgetset.client.CustomUIConnectorRpc;
+
+@Widgetset(TestingWidgetSet.NAME)
+public class CustomUITest extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ getRpcProxy(CustomUIConnectorRpc.class).test();
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "It should be possible to change the implementation of the UIConnector class";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return Integer.valueOf(10867);
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/uitest/base_theme_test.html b/uitest/src/com/vaadin/tests/components/uitest/base_theme_test.html
index 99051a9e7b..0308a09a16 100644
--- a/uitest/src/com/vaadin/tests/components/uitest/base_theme_test.html
+++ b/uitest/src/com/vaadin/tests/components/uitest/base_theme_test.html
@@ -202,9 +202,9 @@
<td>tables</td>
</tr>
<tr>
- <td>contextmenu</td>
+ <td>contextMenuAt</td>
<td>//div[@id='table0']/div[2]/div[1]/table/tbody/tr[2]/td[1]/div</td>
- <td></td>
+ <td>0,0</td>
</tr>
<tr>
<td>screenCapture</td>
diff --git a/uitest/src/com/vaadin/tests/components/uitest/chameleon_theme_test.html b/uitest/src/com/vaadin/tests/components/uitest/chameleon_theme_test.html
index c4534b8064..fb00029d8f 100644
--- a/uitest/src/com/vaadin/tests/components/uitest/chameleon_theme_test.html
+++ b/uitest/src/com/vaadin/tests/components/uitest/chameleon_theme_test.html
@@ -202,9 +202,9 @@
<td>tables</td>
</tr>
<tr>
- <td>contextmenu</td>
+ <td>contextMenuAt</td>
<td>//div[@id='table0']/div[2]/div[1]/table/tbody/tr[2]/td[1]/div</td>
- <td></td>
+ <td>0,0</td>
</tr>
<tr>
<td>screenCapture</td>
diff --git a/uitest/src/com/vaadin/tests/components/uitest/liferay_theme_test.html b/uitest/src/com/vaadin/tests/components/uitest/liferay_theme_test.html
index 0a073b5384..193c648916 100644
--- a/uitest/src/com/vaadin/tests/components/uitest/liferay_theme_test.html
+++ b/uitest/src/com/vaadin/tests/components/uitest/liferay_theme_test.html
@@ -202,9 +202,9 @@
<td>tables</td>
</tr>
<tr>
- <td>contextmenu</td>
+ <td>contextMenuAt</td>
<td>//div[@id='table0']/div[2]/div[1]/table/tbody/tr[2]/td[1]/div</td>
- <td></td>
+ <td>0,0</td>
</tr>
<tr>
<td>screenCapture</td>
diff --git a/uitest/src/com/vaadin/tests/components/uitest/reindeer_theme_test.html b/uitest/src/com/vaadin/tests/components/uitest/reindeer_theme_test.html
index 441a87a088..b1340831bc 100644
--- a/uitest/src/com/vaadin/tests/components/uitest/reindeer_theme_test.html
+++ b/uitest/src/com/vaadin/tests/components/uitest/reindeer_theme_test.html
@@ -202,9 +202,9 @@
<td>tables</td>
</tr>
<tr>
- <td>contextmenu</td>
+ <td>contextMenuAt</td>
<td>//div[@id='table0']/div[2]/div[1]/table/tbody/tr[2]/td[1]/div</td>
- <td></td>
+ <td>0,0</td>
</tr>
<tr>
<td>screenCapture</td>
diff --git a/uitest/src/com/vaadin/tests/components/uitest/runo_theme_test.html b/uitest/src/com/vaadin/tests/components/uitest/runo_theme_test.html
index 33939ef076..fadc503abd 100644
--- a/uitest/src/com/vaadin/tests/components/uitest/runo_theme_test.html
+++ b/uitest/src/com/vaadin/tests/components/uitest/runo_theme_test.html
@@ -202,9 +202,9 @@
<td>tables</td>
</tr>
<tr>
- <td>contextmenu</td>
+ <td>contextMenuAt</td>
<td>//div[@id='table0']/div[2]/div[1]/table/tbody/tr[2]/td[1]/div</td>
- <td></td>
+ <td>0,0</td>
</tr>
<tr>
<td>screenCapture</td>
diff --git a/uitest/src/com/vaadin/tests/extensions/BasicExtensionTest.html b/uitest/src/com/vaadin/tests/extensions/BasicExtensionTest.html
index c57882b3f4..85a5900b74 100644
--- a/uitest/src/com/vaadin/tests/extensions/BasicExtensionTest.html
+++ b/uitest/src/com/vaadin/tests/extensions/BasicExtensionTest.html
@@ -24,7 +24,7 @@
<tr>
<td>assertText</td>
<td>//div[2]</td>
- <td>BasicExtensionTestConnector extending UIConnector</td>
+ <td>BasicExtensionTestConnector extending CustomUIConnector</td>
</tr>
<tr>
<td>click</td>
@@ -34,7 +34,7 @@
<tr>
<td>assertText</td>
<td>//div[1]</td>
- <td>BasicExtensionTestConnector removed for UIConnector</td>
+ <td>BasicExtensionTestConnector removed for CustomUIConnector</td>
</tr>
</tbody></table>
</body>
diff --git a/uitest/src/com/vaadin/tests/performance/BasicPerformanceTest.java b/uitest/src/com/vaadin/tests/performance/BasicPerformanceTest.java
index b0047d6b62..04fe18fc08 100644
--- a/uitest/src/com/vaadin/tests/performance/BasicPerformanceTest.java
+++ b/uitest/src/com/vaadin/tests/performance/BasicPerformanceTest.java
@@ -22,13 +22,14 @@ public class BasicPerformanceTest extends UI {
private int clientLimit;
private int serverLimit;
+ private boolean reportBootstap = true;
private String performanceTopic;
private final Button reportPerformanceButton = new Button(
"Report some performance", new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
TestUtils.reportPerformance(performanceTopic, serverLimit,
- clientLimit);
+ clientLimit, reportBootstap);
event.getButton().setEnabled(false);
}
});
@@ -37,6 +38,7 @@ public class BasicPerformanceTest extends UI {
public void init(VaadinRequest request) {
setContent(buildMainLayout());
updatePerformanceReporting("first load", 100, 100);
+ reportBootstap = true;
}
private void updatePerformanceReporting(String performanceTopic,
@@ -47,6 +49,7 @@ public class BasicPerformanceTest extends UI {
reportPerformanceButton.setCaption("Report performance for "
+ performanceTopic);
reportPerformanceButton.setEnabled(true);
+ reportBootstap = false;
}
private ComponentContainer buildMainLayout() {
diff --git a/uitest/src/com/vaadin/tests/util/TestUtils.java b/uitest/src/com/vaadin/tests/util/TestUtils.java
index 6cb6e79c1c..5c6315a23a 100644
--- a/uitest/src/com/vaadin/tests/util/TestUtils.java
+++ b/uitest/src/com/vaadin/tests/util/TestUtils.java
@@ -120,20 +120,23 @@ public class TestUtils {
public static void installPerformanceReporting(TextArea targetTextArea) {
targetTextArea.setId("performanceTestTarget");
JavaScript
- .eval("window.reportVaadinPerformance = function(topic, serverLimit, clientLimit) {"
+ .eval("window.reportVaadinPerformance = function(topic, serverLimit, clientLimit, bootstrapTime) {"
+ "var element = document.getElementById('performanceTestTarget');"
+ "var text = topic + ': \\n';"
+ "for(var k in window.vaadin.clients) {"
+ "var p = window.vaadin.clients[k].getProfilingData();"
+ "text += ' Server time: ' + (p[3] > serverLimit?'FAIL':'OK') + ' (' + p[3] +')\\n';"
+ "text += ' Client time: ' + (p[0] > clientLimit?'FAIL':'OK') + ' (' + p[0] +')\\n';"
+ + "if (bootstrapTime) text += ' Bootstrap time: ' + (p[4] > clientLimit?'FAIL':'OK') + ' (' + p[4] +')\\n';"
+ "}" + "element.value = text;" + "}");
}
public static void reportPerformance(String topic, int serverLimit,
- int totalLimit) {
- JavaScript.eval("window.reportVaadinPerformance(\"" + topic + "\", "
- + serverLimit + ", " + totalLimit + ");");
+ int clientLimit, boolean bootstrapTime) {
+ JavaScript
+ .eval("window.reportVaadinPerformance(\"" + topic + "\", "
+ + serverLimit + ", " + clientLimit + ","
+ + bootstrapTime + ");");
}
public static IndexedContainer getISO3166Container() {
diff --git a/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml b/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml
index c127d3bb21..919a4a5d69 100644
--- a/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml
+++ b/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml
@@ -3,4 +3,9 @@
<!-- Inherit the DefaultWidgetSet -->
<inherits name="com.vaadin.DefaultWidgetSet" />
+
+ <replace-with class="com.vaadin.tests.widgetset.client.CustomUIConnector">
+ <when-type-is class="com.vaadin.client.ui.ui.UIConnector" />
+ </replace-with>
+
</module>
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/CustomUIConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/CustomUIConnector.java
new file mode 100644
index 0000000000..ddf6763f1b
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/CustomUIConnector.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2000-2013 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.tests.widgetset.client;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.SpanElement;
+import com.vaadin.client.Util;
+import com.vaadin.client.ui.ui.UIConnector;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.ui.UI;
+
+@Connect(UI.class)
+public class CustomUIConnector extends UIConnector {
+ @Override
+ protected void init() {
+ super.init();
+ registerRpc(CustomUIConnectorRpc.class, new CustomUIConnectorRpc() {
+ @Override
+ public void test() {
+ SpanElement span = Document.get().createSpanElement();
+ span.setInnerText("This is the "
+ + Util.getSimpleName(CustomUIConnector.this));
+ Document.get().getBody().insertFirst(span);
+ }
+ });
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/CustomUIConnectorRpc.java b/uitest/src/com/vaadin/tests/widgetset/client/CustomUIConnectorRpc.java
new file mode 100644
index 0000000000..217d906137
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/CustomUIConnectorRpc.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2000-2013 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.tests.widgetset.client;
+
+import com.vaadin.shared.communication.ClientRpc;
+
+public interface CustomUIConnectorRpc extends ClientRpc {
+ public void test();
+}