Browse Source

Merge branch 'master' into root-cleanup

Rename Root -> UI in root cleanup code

Conflicts:
	client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
	server/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java
	server/src/com/vaadin/ui/UI.java
tags/7.0.0.beta1
Johannes Dahlström 11 years ago
parent
commit
a67ca492c1
100 changed files with 4546 additions and 3672 deletions
  1. 11
    3
      build/build.xml
  2. 0
    157
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/AbstractConnectorClassBasedFactoryGenerator.java
  3. 681
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java
  4. 0
    41
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorStateFactoryGenerator.java
  5. 0
    41
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorWidgetFactoryGenerator.java
  6. 0
    223
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/GeneratedRpcMethodProviderGenerator.java
  7. 0
    138
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyCreatorGenerator.java
  8. 0
    159
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java
  9. 0
    484
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java
  10. 0
    377
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java
  11. 2
    2
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java
  12. 90
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ArraySerializer.java
  13. 45
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ClientRpcVisitor.java
  14. 608
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java
  15. 24
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorInitVisitor.java
  16. 43
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/CustomSerializer.java
  17. 58
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/EnumSerializer.java
  18. 86
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/FieldProperty.java
  19. 8
    14
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/GeneratedSerializer.java
  20. 88
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/JsonSerializer.java
  21. 130
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/MethodProperty.java
  22. 89
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/Property.java
  23. 48
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ServerRpcVisitor.java
  24. 25
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/StateInitVisitor.java
  25. 58
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/TypeVisitor.java
  26. 73
    0
      client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/WidgetInitVisitor.java
  27. 2
    44
      client/src/com/vaadin/Vaadin.gwt.xml
  28. 54
    97
      client/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
  29. 98
    59
      client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
  30. 2
    2
      client/src/com/vaadin/terminal/gwt/client/ComponentLocator.java
  31. 10
    0
      client/src/com/vaadin/terminal/gwt/client/ServerConnector.java
  32. 2
    2
      client/src/com/vaadin/terminal/gwt/client/VDebugConsole.java
  33. 38
    27
      client/src/com/vaadin/terminal/gwt/client/WidgetSet.java
  34. 1
    0
      client/src/com/vaadin/terminal/gwt/client/communication/DiffJSONSerializer.java
  35. 0
    39
      client/src/com/vaadin/terminal/gwt/client/communication/InitializableServerRpc.java
  36. 1
    0
      client/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java
  37. 38
    11
      client/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java
  38. 29
    5
      client/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java
  39. 25
    29
      client/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java
  40. 0
    46
      client/src/com/vaadin/terminal/gwt/client/communication/RpcMethod.java
  41. 34
    17
      client/src/com/vaadin/terminal/gwt/client/communication/RpcProxy.java
  42. 0
    44
      client/src/com/vaadin/terminal/gwt/client/communication/SerializerMap.java
  43. 0
    52
      client/src/com/vaadin/terminal/gwt/client/communication/Type.java
  44. 1
    0
      client/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java
  45. 86
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/AsyncBundleLoader.java
  46. 11
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/BundleLoadCallback.java
  47. 99
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/ConnectorBundleLoader.java
  48. 21
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/InvokationHandler.java
  49. 9
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/Invoker.java
  50. 71
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/Method.java
  51. 25
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/NoDataException.java
  52. 69
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/Property.java
  53. 23
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/ProxyHandler.java
  54. 97
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/Type.java
  55. 20
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/TypeData.java
  56. 33
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataBundle.java
  57. 226
    0
      client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataStore.java
  58. 18
    4
      client/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java
  59. 17
    1
      client/src/com/vaadin/terminal/gwt/client/ui/AbstractConnector.java
  60. 0
    52
      client/src/com/vaadin/terminal/gwt/client/ui/ConnectorClassBasedFactory.java
  61. 0
    43
      client/src/com/vaadin/terminal/gwt/client/ui/ConnectorStateFactory.java
  62. 0
    55
      client/src/com/vaadin/terminal/gwt/client/ui/ConnectorWidgetFactory.java
  63. 0
    3
      client/src/com/vaadin/terminal/gwt/client/ui/MediaBaseConnector.java
  64. 20
    20
      client/src/com/vaadin/terminal/gwt/client/ui/UI/UIConnector.java
  65. 5
    5
      client/src/com/vaadin/terminal/gwt/client/ui/UI/VUI.java
  66. 1
    32
      client/src/com/vaadin/terminal/gwt/client/ui/dd/DDUtil.java
  67. 0
    8
      client/src/com/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent.java
  68. 38
    0
      client/src/com/vaadin/terminal/gwt/client/ui/embeddedbrowser/EmbeddedBrowserConnector.java
  69. 120
    0
      client/src/com/vaadin/terminal/gwt/client/ui/embeddedbrowser/VEmbeddedBrowser.java
  70. 44
    0
      client/src/com/vaadin/terminal/gwt/client/ui/flash/FlashConnector.java
  71. 228
    0
      client/src/com/vaadin/terminal/gwt/client/ui/flash/VFlash.java
  72. 67
    0
      client/src/com/vaadin/terminal/gwt/client/ui/image/ImageConnector.java
  73. 10
    0
      client/src/com/vaadin/terminal/gwt/client/ui/image/VImage.java
  74. 4
    4
      client/src/com/vaadin/terminal/gwt/client/ui/label/LabelConnector.java
  75. 32
    28
      client/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java
  76. 40
    49
      client/src/com/vaadin/terminal/gwt/client/ui/slider/SliderConnector.java
  77. 168
    83
      client/src/com/vaadin/terminal/gwt/client/ui/slider/VSlider.java
  78. 0
    3
      client/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelConnector.java
  79. 0
    9
      client/src/com/vaadin/terminal/gwt/client/ui/textarea/TextAreaConnector.java
  80. 236
    245
      server/src/com/vaadin/Application.java
  81. 3
    3
      server/src/com/vaadin/UIRequiresMoreInformationException.java
  82. 3
    3
      server/src/com/vaadin/annotations/EagerInit.java
  83. 2
    2
      server/src/com/vaadin/annotations/Theme.java
  84. 2
    2
      server/src/com/vaadin/annotations/Widgetset.java
  85. 0
    76
      server/src/com/vaadin/data/Buffered.java
  86. 0
    685
      server/src/com/vaadin/data/util/QueryContainer.java
  87. 4
    2
      server/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java
  88. 1
    1
      server/src/com/vaadin/event/ActionManager.java
  89. 77
    33
      server/src/com/vaadin/terminal/AbstractClientConnector.java
  90. 1
    1
      server/src/com/vaadin/terminal/AbstractJavaScriptExtension.java
  91. 4
    4
      server/src/com/vaadin/terminal/AbstractUIProvider.java
  92. 13
    13
      server/src/com/vaadin/terminal/DefaultUIProvider.java
  93. 6
    6
      server/src/com/vaadin/terminal/DeploymentConfiguration.java
  94. 1
    5
      server/src/com/vaadin/terminal/JavaScriptCallbackHelper.java
  95. 43
    43
      server/src/com/vaadin/terminal/Page.java
  96. 7
    7
      server/src/com/vaadin/terminal/UIProvider.java
  97. 11
    0
      server/src/com/vaadin/terminal/Vaadin6Component.java
  98. 6
    5
      server/src/com/vaadin/terminal/WrappedRequest.java
  99. 22
    24
      server/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
  100. 0
    0
      server/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java

+ 11
- 3
build/build.xml View File

@@ -129,6 +129,7 @@
<property name="result-classes-sass" value="${result-path}/classes/sass"/>
<property name="result-classes-sass-junit" value="${result-path}/classes/sass-junit"/>
<property name="result-precompiled-widgetsets" value="${result-path}/classes/widgetsets"/>
<property name="result-classes-gwt" value="${result-path}/classes/gwt" />

<!-- Default classpath for building widgetsets, overridden for testing widgetset -->
<path id="compile.classpath.widgetset">
@@ -848,9 +849,12 @@
<!-- Create Vaadin JAR -->
<mkdir dir="${output-dir}/META-INF"/>
<echo file="${output-dir}/META-INF/VERSION">${version.full}</echo>
<!-- Replace GWT versioning with Vaadin versioning -->
<echo file="${result-classes-gwt}/com/google/gwt/dev/About.properties">gwt.version=${gwt-version}.vaadin${version.full}</echo>
<jarjar jarfile="${output-dir}/WebContent/WEB-INF/lib/${lib-jar-name}"
compress="true" manifest="build/package/META-INF/MANIFEST.MF" duplicate="preserve" index="true">
compress="true" manifest="build/package/META-INF/MANIFEST.MF" duplicate="preserve" index="true" >
<metainf dir="${output-dir}/META-INF"/>
<manifest>
<attribute name="Vaadin-Package-Version" value="1" />
@@ -874,6 +878,7 @@
<fileset dir="${result-src-shared}"/>
<fileset dir="${result-src-sass}"/>
<fileset dir="${result-src-client-compiler}"/>
<fileset dir="${result-classes-gwt}"/>
<fileset dir="${output-dir}/WebContent">
<patternset>
<include name="VAADIN/widgetsets/com.vaadin.terminal.gwt.DefaultWidgetSet/**/*" />
@@ -899,7 +904,7 @@
<!-- GWT -->
<!-- Precompiled GWT modules (.gwtar file) not included to limit JAR size -->
<zipfileset src="${gwt.user.jar}" excludes="META-INF/**,javax/servlet/**,**/*.gwtar" />
<!-- TODO depends on locally compiled gwt-user -->
<!--
<fileset dir="${gwt.user.dir}/src" excludes="**/package.html" />
@@ -912,7 +917,9 @@
-->

<!-- GWT development JAR contents including many external dependencies -->
<zipfileset src="${gwt.dev.jar}" excludes="javax/servlet/**,javax/xml/**" />
<zipfileset src="${gwt.dev.jar}" excludes="javax/servlet/**,javax/xml/**" >
<exclude name="com/google/gwt/dev/About.properties"/>
</zipfileset>

<!-- Alternative approach: GWT compiler and its dependencies only from the dev JAR -->
<!--
@@ -974,6 +981,7 @@
<rule pattern="org.hibernate.validator.**" result="com.vaadin.external.@0"/>
<rule pattern="org.jdesktop.swingworker.**" result="com.vaadin.external.@0"/>
<rule pattern="org.kohsuke.args4j.**" result="com.vaadin.external.@0"/>
</jarjar>
<!-- Generate the Export-Package attribute in the manifest of the JAR -->

+ 0
- 157
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/AbstractConnectorClassBasedFactoryGenerator.java View File

@@ -1,157 +0,0 @@
/*
* 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.terminal.gwt.widgetsetutils;

import java.io.PrintWriter;
import java.util.Date;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
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.terminal.gwt.client.ServerConnector;
import com.vaadin.terminal.gwt.client.ui.ConnectorClassBasedFactory;
import com.vaadin.terminal.gwt.client.ui.ConnectorClassBasedFactory.Creator;

/**
* GWT generator that creates a lookup method for
* {@link ConnectorClassBasedFactory} instances.
*
* @since 7.0
*/
public abstract class AbstractConnectorClassBasedFactoryGenerator extends
Generator {

@Override
public String generate(TreeLogger logger, GeneratorContext context,
String typeName) throws UnableToCompleteException {

try {
// get classType and save instance variables
return generateConnectorClassBasedFactory(typeName, logger, context);
} catch (Exception e) {
logger.log(TreeLogger.ERROR, typeName + " creation failed", e);
throw new UnableToCompleteException();
}
}

private String generateConnectorClassBasedFactory(String typeName,
TreeLogger logger, GeneratorContext context)
throws NotFoundException {
TypeOracle typeOracle = context.getTypeOracle();

JClassType classType = typeOracle.getType(typeName);
String superName = classType.getSimpleSourceName();
String packageName = classType.getPackage().getName();
String className = superName + "Impl";

// get print writer that receives the source code
PrintWriter printWriter = null;
printWriter = context.tryCreate(logger, packageName, className);
// print writer if null, source code has ALREADY been generated
if (printWriter == null) {
return packageName + "." + className;
}

Date date = new Date();

// init composer, set class properties, create source writer
ClassSourceFileComposerFactory composer = null;
composer = new ClassSourceFileComposerFactory(packageName, className);
composer.addImport(GWT.class.getName());
composer.addImport(Creator.class.getCanonicalName());
composer.setSuperclass(superName);

SourceWriter sourceWriter = composer.createSourceWriter(context,
printWriter);
sourceWriter.indent();

// public ConnectorStateFactoryImpl() {
sourceWriter.println("public " + className + "() {");
sourceWriter.indent();

JClassType serverConnectorType = typeOracle.getType(getConnectorType()
.getCanonicalName());
for (JClassType connector : serverConnectorType.getSubtypes()) {
// addCreator(TextAreaConnector.class, new Creator<SharedState>() {
if (connector.isInterface() != null || connector.isAbstract()) {
continue;
}

JClassType targetType = getTargetType(connector);
if (targetType.isAbstract()) {
continue;
}

sourceWriter.println("addCreator("
+ connector.getQualifiedSourceName()
+ ".class, new Creator<"
+ targetType.getQualifiedSourceName() + ">() {");
// public SharedState create() {
sourceWriter.println("public "
+ targetType.getQualifiedSourceName() + " create() {");
// return GWT.create(TextAreaState.class);
sourceWriter.println("return GWT.create("
+ targetType.getQualifiedSourceName() + ".class);");
// }
sourceWriter.println("}");
// });
sourceWriter.println("});");
}

// End of constructor
sourceWriter.outdent();
sourceWriter.println("}");

// close generated class
sourceWriter.outdent();
sourceWriter.println("}");

// commit generated class
context.commit(logger, printWriter);
logger.log(Type.INFO,
"Done. (" + (new Date().getTime() - date.getTime()) / 1000
+ "seconds)");
return packageName + "." + className;

}

protected abstract Class<? extends ServerConnector> getConnectorType();

protected abstract JClassType getTargetType(JClassType connectorType);

protected JClassType getGetterReturnType(JClassType connector,
String getterName) {
try {
JMethod getMethod = connector.getMethod(getterName, new JType[] {});
return (JClassType) getMethod.getReturnType();
} catch (NotFoundException e) {
return getGetterReturnType(connector.getSuperclass(), getterName);
}

}

}

+ 681
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java View File

@@ -0,0 +1,681 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.widgetsetutils;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
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.annotations.DelegateToWidget;
import com.vaadin.shared.communication.ClientRpc;
import com.vaadin.shared.communication.ServerRpc;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.Connect.LoadStyle;
import com.vaadin.terminal.gwt.client.ServerConnector;
import com.vaadin.terminal.gwt.client.metadata.ConnectorBundleLoader;
import com.vaadin.terminal.gwt.client.metadata.InvokationHandler;
import com.vaadin.terminal.gwt.client.metadata.ProxyHandler;
import com.vaadin.terminal.gwt.client.metadata.TypeData;
import com.vaadin.terminal.gwt.client.metadata.TypeDataBundle;
import com.vaadin.terminal.gwt.client.metadata.TypeDataStore;
import com.vaadin.terminal.gwt.widgetsetutils.metadata.ClientRpcVisitor;
import com.vaadin.terminal.gwt.widgetsetutils.metadata.ConnectorBundle;
import com.vaadin.terminal.gwt.widgetsetutils.metadata.ConnectorInitVisitor;
import com.vaadin.terminal.gwt.widgetsetutils.metadata.GeneratedSerializer;
import com.vaadin.terminal.gwt.widgetsetutils.metadata.Property;
import com.vaadin.terminal.gwt.widgetsetutils.metadata.ServerRpcVisitor;
import com.vaadin.terminal.gwt.widgetsetutils.metadata.StateInitVisitor;
import com.vaadin.terminal.gwt.widgetsetutils.metadata.TypeVisitor;
import com.vaadin.terminal.gwt.widgetsetutils.metadata.WidgetInitVisitor;

public class ConnectorBundleLoaderFactory extends Generator {

@Override
public String generate(TreeLogger logger, GeneratorContext context,
String typeName) throws UnableToCompleteException {
TypeOracle typeOracle = context.getTypeOracle();

try {
JClassType classType = typeOracle.getType(typeName);
String packageName = classType.getPackage().getName();
String className = classType.getSimpleSourceName() + "Impl";

generateClass(logger, context, packageName, className, typeName);

return packageName + "." + className;
} catch (UnableToCompleteException e) {
// Just rethrow
throw e;
} catch (Exception e) {
logger.log(Type.ERROR, getClass() + " failed", e);
throw new UnableToCompleteException();
}

}

private void generateClass(TreeLogger logger, GeneratorContext context,
String packageName, String className, String requestedType)
throws Exception {
PrintWriter printWriter = context.tryCreate(logger, packageName,
className);
if (printWriter == null) {
return;
}

List<ConnectorBundle> bundles = buildBundles(logger,
context.getTypeOracle());

ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(
packageName, className);
composer.setSuperclass(requestedType);

SourceWriter w = composer.createSourceWriter(context, printWriter);

w.println("public void init() {");
w.indent();

for (ConnectorBundle bundle : bundles) {
String name = bundle.getName();
boolean isEager = name
.equals(ConnectorBundleLoader.EAGER_BUNDLE_NAME);

w.print("addAsyncBlockLoader(new AsyncBundleLoader(\"");
w.print(escape(name));
w.print("\", ");

w.print("new String[] {");
for (Entry<JClassType, Set<String>> entry : bundle.getIdentifiers()
.entrySet()) {
Set<String> identifiers = entry.getValue();
for (String id : identifiers) {
w.print("\"");
w.print(escape(id));
w.print("\",");
}
}
w.println("}) {");
w.indent();

w.print("protected void load(final ");
w.print(TypeDataStore.class.getName());
w.println(" store) {");
w.indent();

if (!isEager) {
w.print(GWT.class.getName());
w.print(".runAsync(");
}

w.print("new ");
w.print(TypeDataBundle.class.getName());
w.println("(getName()) {");
w.indent();

w.println("public void load() {");
w.indent();

printBundleData(logger, w, bundle);

// Close load method
w.outdent();
w.println("}");

// Close new TypeDataBundle() {}
w.outdent();
w.print("}");

if (isEager) {
w.println(".onSuccess();");
} else {
w.println(");");
}

// Close load method
w.outdent();
w.println("}");

// Close add(new ...
w.outdent();
w.println("});");
}

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

w.commit(logger);
}

private void printBundleData(TreeLogger logger, SourceWriter w,
ConnectorBundle bundle) throws UnableToCompleteException {
writeIdentifiers(w, bundle);
writeGwtConstructors(w, bundle);
writeReturnTypes(w, bundle);
writeInvokers(w, bundle);
writeParamTypes(w, bundle);
writeProxys(w, bundle);
wirteDelayedInfo(w, bundle);
writeProperites(logger, w, bundle);
writePropertyTypes(w, bundle);
writeSetters(logger, w, bundle);
writeGetters(logger, w, bundle);
writeSerializers(logger, w, bundle);
writeDelegateToWidget(logger, w, bundle);
}

private void writeDelegateToWidget(TreeLogger logger, SourceWriter w,
ConnectorBundle bundle) {
Set<Property> needsDelegateToWidget = bundle.getNeedsDelegateToWidget();
for (Property property : needsDelegateToWidget) {
w.println("store.setDelegateToWidget(%s, \"%s\", \"%s\");",
getClassLiteralString(property.getBeanType()),
property.getName(),
property.getAnnotation(DelegateToWidget.class).value());
}
}

private void writeSerializers(TreeLogger logger, SourceWriter w,
ConnectorBundle bundle) throws UnableToCompleteException {
Map<JType, GeneratedSerializer> serializers = bundle.getSerializers();
for (Entry<JType, GeneratedSerializer> entry : serializers.entrySet()) {
JType type = entry.getKey();
GeneratedSerializer serializer = entry.getValue();

w.print("store.setSerializerFactory(");
writeClassLiteral(w, type);
w.print(", ");
w.println("new Invoker() {");
w.indent();

w.println("public Object invoke(Object target, Object[] params) {");
w.indent();

serializer.writeSerializerInstantiator(logger, w);

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

w.outdent();
w.print("}");
w.println(");");
}
}

private void writeGetters(TreeLogger logger, SourceWriter w,
ConnectorBundle bundle) {
Set<Property> properties = bundle.getNeedsSetter();
for (Property property : properties) {
w.print("store.setGetter(");
writeClassLiteral(w, property.getBeanType());
w.print(", \"");
w.print(escape(property.getName()));
w.println("\", new Invoker() {");
w.indent();

w.println("public Object invoke(Object bean, Object[] params) {");
w.indent();

property.writeGetterBody(logger, w, "bean");
w.println();

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

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

private void writeSetters(TreeLogger logger, SourceWriter w,
ConnectorBundle bundle) {
Set<Property> properties = bundle.getNeedsSetter();
for (Property property : properties) {
w.print("store.setSetter(");
writeClassLiteral(w, property.getBeanType());
w.print(", \"");
w.print(escape(property.getName()));
w.println("\", new Invoker() {");
w.indent();

w.println("public Object invoke(Object bean, Object[] params) {");
w.indent();

property.writeSetterBody(logger, w, "bean", "params[0]");

w.println("return null;");

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

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

private void writePropertyTypes(SourceWriter w, ConnectorBundle bundle) {
Set<Property> properties = bundle.getNeedsType();
for (Property property : properties) {
w.print("store.setPropertyType(");
writeClassLiteral(w, property.getBeanType());
w.print(", \"");
w.print(escape(property.getName()));
w.print("\", ");
writeTypeCreator(w, property.getPropertyType());
w.println(");");
}
}

private void writeProperites(TreeLogger logger, SourceWriter w,
ConnectorBundle bundle) throws UnableToCompleteException {
Set<JClassType> needsPropertyListing = bundle.getNeedsPropertyListing();
for (JClassType type : needsPropertyListing) {
w.print("store.setProperties(");
writeClassLiteral(w, type);
w.print(", new String[] {");

Set<String> usedPropertyNames = new HashSet<String>();
Collection<Property> properties = bundle.getProperties(type);
for (Property property : properties) {
String name = property.getName();
if (!usedPropertyNames.add(name)) {
logger.log(
Type.ERROR,
type.getQualifiedSourceName()
+ " has multiple properties with the name "
+ name
+ ". This can happen if there are multiple setters with identical names exect casing.");
throw new UnableToCompleteException();
}

w.print("\"");
w.print(name);
w.print("\", ");
}

w.println("});");
}
}

private void wirteDelayedInfo(SourceWriter w, ConnectorBundle bundle) {
Map<JClassType, Set<JMethod>> needsDelayedInfo = bundle
.getNeedsDelayedInfo();
Set<Entry<JClassType, Set<JMethod>>> entrySet = needsDelayedInfo
.entrySet();
for (Entry<JClassType, Set<JMethod>> entry : entrySet) {
JClassType type = entry.getKey();
Set<JMethod> methods = entry.getValue();
for (JMethod method : methods) {
Delayed annotation = method.getAnnotation(Delayed.class);
if (annotation != null) {
w.print("store.setDelayed(");
writeClassLiteral(w, type);
w.print(", \"");
w.print(escape(method.getName()));
w.println("\");");

if (annotation.lastonly()) {
w.print("store.setLastonly(");
writeClassLiteral(w, type);
w.print(", \"");
w.print(escape(method.getName()));
w.println("\");");
}
}
}
}
}

private void writeProxys(SourceWriter w, ConnectorBundle bundle) {
Set<JClassType> needsProxySupport = bundle.getNeedsProxySupport();
for (JClassType type : needsProxySupport) {
w.print("store.setProxyHandler(");
writeClassLiteral(w, type);
w.print(", new ");
w.print(ProxyHandler.class.getCanonicalName());
w.println("() {");
w.indent();

w.println("public Object createProxy(final "
+ InvokationHandler.class.getName() + " handler) {");
w.indent();

w.print("return new ");
w.print(type.getQualifiedSourceName());
w.println("() {");
w.indent();

JMethod[] methods = type.getOverridableMethods();
for (JMethod method : methods) {
if (method.isAbstract()) {
w.print("public ");
w.print(method.getReturnType().getQualifiedSourceName());
w.print(" ");
w.print(method.getName());
w.print("(");

JType[] types = method.getParameterTypes();
for (int i = 0; i < types.length; i++) {
if (i != 0) {
w.print(", ");
}
w.print(types[i].getQualifiedSourceName());
w.print(" p");
w.print(Integer.toString(i));
}

w.println(") {");
w.indent();

if (!method.getReturnType().getQualifiedSourceName()
.equals("void")) {
w.print("return ");
}

w.print("handler.invoke(this, ");
w.print(TypeData.class.getCanonicalName());
w.print(".getType(");
writeClassLiteral(w, type);
w.print(").getMethod(\"");
w.print(escape(method.getName()));
w.print("\"), new Object [] {");
for (int i = 0; i < types.length; i++) {
w.print("p" + i + ", ");
}
w.println("});");

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

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

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

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

}
}

private void writeParamTypes(SourceWriter w, ConnectorBundle bundle) {
Map<JClassType, Set<JMethod>> needsParamTypes = bundle
.getNeedsParamTypes();
for (Entry<JClassType, Set<JMethod>> entry : needsParamTypes.entrySet()) {
JClassType type = entry.getKey();

Set<JMethod> methods = entry.getValue();
for (JMethod method : methods) {
w.print("store.setParamTypes(");
writeClassLiteral(w, type);
w.print(", \"");
w.print(escape(method.getName()));
w.print("\", new Type[] {");

for (JType parameter : method.getParameterTypes()) {
ConnectorBundleLoaderFactory.writeTypeCreator(w, parameter);
w.print(", ");
}

w.println("});");

}
}
}

private void writeInvokers(SourceWriter w, ConnectorBundle bundle) {
Map<JClassType, Set<JMethod>> needsInvoker = bundle.getNeedsInvoker();
for (Entry<JClassType, Set<JMethod>> entry : needsInvoker.entrySet()) {
JClassType type = entry.getKey();

Set<JMethod> methods = entry.getValue();
for (JMethod method : methods) {
w.print("store.setInvoker(");
writeClassLiteral(w, type);
w.print(", \"");
w.print(escape(method.getName()));
w.println("\", new Invoker() {");
w.indent();

w.println("public Object invoke(Object target, Object[] params) {");
w.indent();

JType returnType = method.getReturnType();
boolean hasReturnType = !"void".equals(returnType
.getQualifiedSourceName());
if (hasReturnType) {
w.print("return ");
}

JType[] parameterTypes = method.getParameterTypes();

w.print("((" + type.getQualifiedSourceName() + ") target)."
+ method.getName() + "(");
for (int i = 0; i < parameterTypes.length; i++) {
JType parameterType = parameterTypes[i];
if (i != 0) {
w.print(", ");
}
String parameterTypeName = getBoxedTypeName(parameterType);
w.print("(" + parameterTypeName + ") params[" + i + "]");
}
w.println(");");

if (!hasReturnType) {
w.println("return null;");
}

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

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

}
}
}

private void writeReturnTypes(SourceWriter w, ConnectorBundle bundle) {
Map<JClassType, Set<JMethod>> methodReturnTypes = bundle
.getMethodReturnTypes();
for (Entry<JClassType, Set<JMethod>> entry : methodReturnTypes
.entrySet()) {
JClassType type = entry.getKey();

Set<JMethod> methods = entry.getValue();
for (JMethod method : methods) {
// setReturnType(Class<?> type, String methodName, Type
// returnType)
w.print("store.setReturnType(");
writeClassLiteral(w, type);
w.print(", \"");
w.print(escape(method.getName()));
w.print("\", ");
writeTypeCreator(w, method.getReturnType());
w.println(");");
}
}
}

private void writeGwtConstructors(SourceWriter w, ConnectorBundle bundle) {
Set<JClassType> constructors = bundle.getGwtConstructors();
for (JClassType type : constructors) {
w.print("store.setConstructor(");
writeClassLiteral(w, type);
w.println(", new Invoker() {");
w.indent();

w.println("public Object invoke(Object target, Object[] params) {");
w.indent();

w.print("return ");
w.print(GWT.class.getName());
w.print(".create(");
writeClassLiteral(w, type);
w.println(");");

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

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

public static void writeClassLiteral(SourceWriter w, JType type) {
w.print(getClassLiteralString(type));
}

public static String getClassLiteralString(JType type) {
return type.getQualifiedSourceName() + ".class";
}

private void writeIdentifiers(SourceWriter w, ConnectorBundle bundle) {
Map<JClassType, Set<String>> identifiers = bundle.getIdentifiers();
for (Entry<JClassType, Set<String>> entry : identifiers.entrySet()) {
Set<String> ids = entry.getValue();
JClassType type = entry.getKey();
for (String id : ids) {
w.print("store.setClass(\"");
w.print(escape(id));
w.print("\", ");
writeClassLiteral(w, type);
w.println(");");
}
}
}

private List<ConnectorBundle> buildBundles(TreeLogger logger,
TypeOracle typeOracle) throws NotFoundException,
UnableToCompleteException {

Map<LoadStyle, Collection<JClassType>> connectorsByLoadStyle = new HashMap<LoadStyle, Collection<JClassType>>();
for (LoadStyle loadStyle : LoadStyle.values()) {
connectorsByLoadStyle.put(loadStyle, new ArrayList<JClassType>());
}

JClassType connectorType = typeOracle.getType(ServerConnector.class
.getName());
JClassType[] subtypes = connectorType.getSubtypes();
for (JClassType connectorSubtype : subtypes) {
if (!connectorSubtype.isAnnotationPresent(Connect.class)) {
continue;
}
LoadStyle loadStyle = getLoadStyle(connectorSubtype);
if (loadStyle != null) {
connectorsByLoadStyle.get(loadStyle).add(connectorSubtype);
}
}

List<ConnectorBundle> bundles = new ArrayList<ConnectorBundle>();

Collection<TypeVisitor> visitors = getVisitors(typeOracle);

ConnectorBundle eagerBundle = new ConnectorBundle(
ConnectorBundleLoader.EAGER_BUNDLE_NAME, visitors, typeOracle);
TreeLogger eagerLogger = logger.branch(Type.TRACE,
"Populating eager bundle");

// Eager connectors and all RPC interfaces are loaded by default
eagerBundle.processTypes(eagerLogger,
connectorsByLoadStyle.get(LoadStyle.EAGER));
eagerBundle.processSubTypes(eagerLogger,
typeOracle.getType(ClientRpc.class.getName()));
eagerBundle.processSubTypes(eagerLogger,
typeOracle.getType(ServerRpc.class.getName()));

bundles.add(eagerBundle);

ConnectorBundle deferredBundle = new ConnectorBundle(
ConnectorBundleLoader.DEFERRED_BUNDLE_NAME, eagerBundle);
TreeLogger deferredLogger = logger.branch(Type.TRACE,
"Populating deferred bundle");
deferredBundle.processTypes(deferredLogger,
connectorsByLoadStyle.get(LoadStyle.DEFERRED));

bundles.add(deferredBundle);

Collection<JClassType> lazy = connectorsByLoadStyle.get(LoadStyle.LAZY);
for (JClassType type : lazy) {
ConnectorBundle bundle = new ConnectorBundle(type.getName(),
eagerBundle);
TreeLogger subLogger = logger.branch(Type.TRACE, "Populating "
+ type.getName() + " bundle");
bundle.processType(subLogger, type);

bundles.add(bundle);
}

return bundles;
}

private Collection<TypeVisitor> getVisitors(TypeOracle oracle)
throws NotFoundException {
List<TypeVisitor> visitors = Arrays.<TypeVisitor> asList(
new ConnectorInitVisitor(), new StateInitVisitor(),
new WidgetInitVisitor(), new ClientRpcVisitor(),
new ServerRpcVisitor());
for (TypeVisitor typeVisitor : visitors) {
typeVisitor.init(oracle);
}
return visitors;
}

protected LoadStyle getLoadStyle(JClassType connectorType) {
Connect annotation = connectorType.getAnnotation(Connect.class);
return annotation.loadStyle();
}

public static String getBoxedTypeName(JType type) {
if (type.isPrimitive() != null) {
// Used boxed types for primitives
return type.isPrimitive().getQualifiedBoxedSourceName();
} else {
return type.getErasedType().getQualifiedSourceName();
}
}

public static void writeTypeCreator(SourceWriter sourceWriter, JType type) {
String typeName = ConnectorBundleLoaderFactory.getBoxedTypeName(type);
JParameterizedType parameterized = type.isParameterized();
if (parameterized != null) {
sourceWriter.print("new Type(\"" + typeName + "\", ");
sourceWriter.print("new Type[] {");
JClassType[] typeArgs = parameterized.getTypeArgs();
for (JClassType jClassType : typeArgs) {
writeTypeCreator(sourceWriter, jClassType);
sourceWriter.print(", ");
}
sourceWriter.print("}");
} else {
sourceWriter.print("new Type(" + typeName + ".class");
}
sourceWriter.print(")");
}

}

+ 0
- 41
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorStateFactoryGenerator.java View File

@@ -1,41 +0,0 @@
/*
* 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.terminal.gwt.widgetsetutils;

import com.google.gwt.core.ext.typeinfo.JClassType;
import com.vaadin.terminal.gwt.client.ServerConnector;

/**
* GWT generator that creates a SharedState class for a given Connector class,
* based on the return type of getState()
*
* @since 7.0
*/
public class ConnectorStateFactoryGenerator extends
AbstractConnectorClassBasedFactoryGenerator {

@Override
protected JClassType getTargetType(JClassType connectorType) {
return getGetterReturnType(connectorType, "getState");
}

@Override
protected Class<? extends ServerConnector> getConnectorType() {
return ServerConnector.class;
}

}

+ 0
- 41
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorWidgetFactoryGenerator.java View File

@@ -1,41 +0,0 @@
/*
* 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.terminal.gwt.widgetsetutils;

import com.google.gwt.core.ext.typeinfo.JClassType;
import com.vaadin.terminal.gwt.client.ComponentConnector;
import com.vaadin.terminal.gwt.client.ServerConnector;

/**
* GWT generator that creates a Widget class for a given Connector class, based
* on the return type of getWidget()
*
* @since 7.0
*/
public class ConnectorWidgetFactoryGenerator extends
AbstractConnectorClassBasedFactoryGenerator {
@Override
protected JClassType getTargetType(JClassType connectorType) {
return getGetterReturnType(connectorType, "getWidget");
}

@Override
protected Class<? extends ServerConnector> getConnectorType() {
return ComponentConnector.class;
}

}

+ 0
- 223
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/GeneratedRpcMethodProviderGenerator.java View File

@@ -1,223 +0,0 @@
/*
* 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.terminal.gwt.widgetsetutils;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JType;
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.communication.ClientRpc;
import com.vaadin.terminal.gwt.client.communication.GeneratedRpcMethodProvider;
import com.vaadin.terminal.gwt.client.communication.RpcManager;
import com.vaadin.terminal.gwt.client.communication.RpcMethod;

/**
* GWT generator that creates an implementation for {@link RpcManager} on the
* client side classes for executing RPC calls received from the the server.
*
* @since 7.0
*/
public class GeneratedRpcMethodProviderGenerator extends Generator {

@Override
public String generate(TreeLogger logger, GeneratorContext context,
String typeName) throws UnableToCompleteException {

String packageName = null;
String className = null;
try {
TypeOracle typeOracle = context.getTypeOracle();

// get classType and save instance variables
JClassType classType = typeOracle.getType(typeName);
packageName = classType.getPackage().getName();
className = classType.getSimpleSourceName() + "Impl";
// Generate class source code for SerializerMapImpl
generateClass(logger, context, packageName, className);
} catch (Exception e) {
logger.log(TreeLogger.ERROR,
"SerializerMapGenerator creation failed", e);
}
// return the fully qualifed name of the class generated
return packageName + "." + className;
}

/**
* Generate source code for RpcManagerImpl
*
* @param logger
* Logger object
* @param context
* Generator context
* @param packageName
* package name for the class to generate
* @param className
* class name for the class to generate
*/
private void generateClass(TreeLogger logger, GeneratorContext context,
String packageName, String className) {
// get print writer that receives the source code
PrintWriter printWriter = null;
printWriter = context.tryCreate(logger, packageName, className);
// print writer if null, source code has ALREADY been generated
if (printWriter == null) {
return;
}
logger.log(Type.INFO,
"Detecting server to client RPC interface types...");
Date date = new Date();
TypeOracle typeOracle = context.getTypeOracle();
JClassType serverToClientRpcType = typeOracle.findType(ClientRpc.class
.getName());
JClassType[] rpcInterfaceSubtypes = serverToClientRpcType.getSubtypes();

// init composer, set class properties, create source writer
ClassSourceFileComposerFactory composer = null;
composer = new ClassSourceFileComposerFactory(packageName, className);
composer.addImport("com.google.gwt.core.client.GWT");
composer.addImport(RpcMethod.class.getName());
composer.addImport(ClientRpc.class.getName());
composer.addImport(com.vaadin.terminal.gwt.client.communication.Type.class
.getName());
composer.addImplementedInterface(GeneratedRpcMethodProvider.class
.getName());
SourceWriter sourceWriter = composer.createSourceWriter(context,
printWriter);
sourceWriter.indent();

List<JMethod> rpcMethods = new ArrayList<JMethod>();

sourceWriter
.println("public java.util.Collection<RpcMethod> getGeneratedRpcMethods() {");
sourceWriter.indent();

sourceWriter
.println("java.util.ArrayList<RpcMethod> list = new java.util.ArrayList<RpcMethod>();");

// iterate over RPC interfaces and create helper methods for each
// interface
for (JClassType type : rpcInterfaceSubtypes) {
if (null == type.isInterface()) {
// only interested in interfaces here, not implementations
continue;
}

// loop over the methods of the interface and its superinterfaces
// methods
for (JClassType currentType : type.getFlattenedSupertypeHierarchy()) {
for (JMethod method : currentType.getMethods()) {

// RpcMethod(String interfaceName, String methodName,
// Type... parameterTypes)
sourceWriter.print("list.add(new RpcMethod(\""
+ type.getQualifiedSourceName() + "\", \""
+ method.getName() + "\"");
JType[] parameterTypes = method.getParameterTypes();
for (JType parameter : parameterTypes) {
sourceWriter.print(", ");
writeTypeCreator(sourceWriter, parameter);
}
sourceWriter.println(") {");
sourceWriter.indent();

sourceWriter
.println("public void applyInvocation(ClientRpc target, Object... parameters) {");
sourceWriter.indent();

sourceWriter.print("((" + type.getQualifiedSourceName()
+ ")target)." + method.getName() + "(");
for (int i = 0; i < parameterTypes.length; i++) {
JType parameterType = parameterTypes[i];
if (i != 0) {
sourceWriter.print(", ");
}
String parameterTypeName = getBoxedTypeName(parameterType);
sourceWriter.print("(" + parameterTypeName
+ ") parameters[" + i + "]");
}
sourceWriter.println(");");

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

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

sourceWriter.println("return list;");

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

// close generated class
sourceWriter.outdent();
sourceWriter.println("}");
// commit generated class
context.commit(logger, printWriter);
logger.log(Type.INFO,
"Done. (" + (new Date().getTime() - date.getTime()) / 1000
+ "seconds)");

}

public static void writeTypeCreator(SourceWriter sourceWriter, JType type) {
String typeName = getBoxedTypeName(type);
sourceWriter.print("new Type(\"" + typeName + "\", ");
JParameterizedType parameterized = type.isParameterized();
if (parameterized != null) {
sourceWriter.print("new Type[] {");
JClassType[] typeArgs = parameterized.getTypeArgs();
for (JClassType jClassType : typeArgs) {
writeTypeCreator(sourceWriter, jClassType);
sourceWriter.print(", ");
}
sourceWriter.print("}");
} else {
sourceWriter.print("null");
}
sourceWriter.print(")");
}

public static String getBoxedTypeName(JType type) {
if (type.isPrimitive() != null) {
// Used boxed types for primitives
return type.isPrimitive().getQualifiedBoxedSourceName();
} else {
return type.getErasedType().getQualifiedSourceName();
}
}

private String getInvokeMethodName(JClassType type) {
return "invoke" + type.getQualifiedSourceName().replaceAll("\\.", "_");
}
}

+ 0
- 138
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyCreatorGenerator.java View File

@@ -1,138 +0,0 @@
/*
* 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.terminal.gwt.widgetsetutils;

import java.io.PrintWriter;
import java.util.Date;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
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.communication.ServerRpc;
import com.vaadin.terminal.gwt.client.ServerConnector;
import com.vaadin.terminal.gwt.client.communication.InitializableServerRpc;
import com.vaadin.terminal.gwt.client.communication.RpcProxy.RpcProxyCreator;

public class RpcProxyCreatorGenerator extends Generator {

@Override
public String generate(TreeLogger logger, GeneratorContext ctx,
String requestedClassName) throws UnableToCompleteException {
logger.log(TreeLogger.DEBUG, "Running RpcProxyCreatorGenerator");
TypeOracle typeOracle = ctx.getTypeOracle();
assert (typeOracle != null);

JClassType requestedType = typeOracle.findType(requestedClassName);
if (requestedType == null) {
logger.log(TreeLogger.ERROR, "Unable to find metadata for type '"
+ requestedClassName + "'", null);
throw new UnableToCompleteException();
}
String packageName = requestedType.getPackage().getName();
String className = requestedType.getSimpleSourceName() + "Impl";

createType(logger, ctx, packageName, className);
return packageName + "." + className;
}

private void createType(TreeLogger logger, GeneratorContext context,
String packageName, String className) {
ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(
packageName, className);

PrintWriter printWriter = context.tryCreate(logger,
composer.getCreatedPackage(),
composer.getCreatedClassShortName());
if (printWriter == null) {
// print writer is null if source code has already been generated
return;
}
Date date = new Date();
TypeOracle typeOracle = context.getTypeOracle();

// init composer, set class properties, create source writer
composer.addImport(GWT.class.getCanonicalName());
composer.addImport(ServerRpc.class.getCanonicalName());
composer.addImport(ServerConnector.class.getCanonicalName());
composer.addImport(InitializableServerRpc.class.getCanonicalName());
composer.addImport(IllegalArgumentException.class.getCanonicalName());
composer.addImplementedInterface(RpcProxyCreator.class
.getCanonicalName());

SourceWriter sourceWriter = composer.createSourceWriter(context,
printWriter);
sourceWriter.indent();

sourceWriter
.println("public <T extends ServerRpc> T create(Class<T> rpcInterface, ServerConnector connector) {");
sourceWriter.indent();

sourceWriter
.println("if (rpcInterface == null || connector == null) {");
sourceWriter.indent();
sourceWriter
.println("throw new IllegalArgumentException(\"RpcInterface and/or connector cannot be null\");");
sourceWriter.outdent();

JClassType initializableInterface = typeOracle.findType(ServerRpc.class
.getCanonicalName());

for (JClassType rpcType : initializableInterface.getSubtypes()) {
String rpcClassName = rpcType.getQualifiedSourceName();
if (InitializableServerRpc.class.getCanonicalName().equals(
rpcClassName)) {
// InitializableClientToServerRpc is a special marker interface
// that should not get a generated class
continue;
}
sourceWriter.println("} else if (rpcInterface == " + rpcClassName
+ ".class) {");
sourceWriter.indent();
sourceWriter.println(rpcClassName + " rpc = GWT.create("
+ rpcClassName + ".class);");
sourceWriter.println("((" + InitializableServerRpc.class.getName()
+ ") rpc).initRpc(connector);");
sourceWriter.println("return (T) rpc;");
sourceWriter.outdent();
}

sourceWriter.println("} else {");
sourceWriter.indent();
sourceWriter
.println("throw new IllegalArgumentException(\"No RpcInterface of type \"+ rpcInterface.getName() + \" was found.\");");
sourceWriter.outdent();
// End of if
sourceWriter.println("}");
// End of method
sourceWriter.println("}");

// close generated class
sourceWriter.outdent();
sourceWriter.println("}");
// commit generated class
context.commit(logger, printWriter);
logger.log(Type.INFO, composer.getCreatedClassName() + " created in "
+ (new Date().getTime() - date.getTime()) / 1000 + "seconds");

}
}

+ 0
- 159
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java View File

@@ -1,159 +0,0 @@
/*
* 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.terminal.gwt.widgetsetutils;

import java.io.PrintWriter;

import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
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;
import com.vaadin.terminal.gwt.client.ServerConnector;
import com.vaadin.terminal.gwt.client.communication.InitializableServerRpc;

/**
* GWT generator that creates client side proxy classes for making RPC calls
* from the client to the server.
*
* GWT.create() calls for interfaces extending {@link ServerRpc} are affected,
* and a proxy implementation is created. Note that the init(...) method of the
* proxy must be called before the proxy is used.
*
* @since 7.0
*/
public class RpcProxyGenerator extends Generator {
@Override
public String generate(TreeLogger logger, GeneratorContext ctx,
String requestedClassName) throws UnableToCompleteException {
logger.log(TreeLogger.DEBUG, "Running RpcProxyGenerator", null);

TypeOracle typeOracle = ctx.getTypeOracle();
assert (typeOracle != null);

JClassType requestedType = typeOracle.findType(requestedClassName);
if (requestedType == null) {
logger.log(TreeLogger.ERROR, "Unable to find metadata for type '"
+ requestedClassName + "'", null);
throw new UnableToCompleteException();
}

String generatedClassName = "ServerRpc_"
+ requestedType.getName().replaceAll("[$.]", "_");

JClassType initializableInterface = typeOracle
.findType(InitializableServerRpc.class.getCanonicalName());

ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(
requestedType.getPackage().getName(), generatedClassName);
composer.addImplementedInterface(requestedType.getQualifiedSourceName());
composer.addImplementedInterface(initializableInterface
.getQualifiedSourceName());
composer.addImport(MethodInvocation.class.getCanonicalName());

PrintWriter printWriter = ctx.tryCreate(logger,
composer.getCreatedPackage(),
composer.getCreatedClassShortName());
if (printWriter != null) {
logger.log(Type.INFO, "Generating client proxy for RPC interface '"
+ requestedType.getQualifiedSourceName() + "'");
SourceWriter writer = composer.createSourceWriter(ctx, printWriter);

// constructor
writer.println("public " + generatedClassName + "() {}");

// initialization etc.
writeCommonFieldsAndMethods(logger, writer, typeOracle);

// actual proxy methods forwarding calls to the server
writeRemoteProxyMethods(logger, writer, typeOracle, requestedType,
requestedType.isClassOrInterface().getInheritableMethods());

// End of class
writer.outdent();
writer.println("}");

ctx.commit(logger, printWriter);
}

return composer.getCreatedClassName();
}

private void writeCommonFieldsAndMethods(TreeLogger logger,
SourceWriter writer, TypeOracle typeOracle) {
JClassType applicationConnectionClass = typeOracle
.findType(ApplicationConnection.class.getCanonicalName());

// fields
writer.println("private " + ServerConnector.class.getName()
+ " connector;");

// init method from the RPC interface
writer.println("public void initRpc(" + ServerConnector.class.getName()
+ " connector) {");
writer.indent();
writer.println("this.connector = connector;");
writer.outdent();
writer.println("}");
}

private static void writeRemoteProxyMethods(TreeLogger logger,
SourceWriter writer, TypeOracle typeOracle,
JClassType requestedType, JMethod[] methods) {
for (JMethod m : methods) {
writer.print(m.getReadableDeclaration(false, false, false, false,
true));
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());
writer.print("\", new Object[] {");
// new Object[] { ... } for parameters - autoboxing etc. by the
// compiler
JParameter[] parameters = m.getParameters();
boolean first = true;
for (JParameter p : parameters) {
if (!first) {
writer.print(", ");
}
first = false;

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

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

+ 0
- 484
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java View File

@@ -1,484 +0,0 @@
/*
* 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.terminal.gwt.widgetsetutils;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JEnumConstant;
import com.google.gwt.core.ext.typeinfo.JEnumType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JPackage;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.TypeOracleException;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.communication.DiffJSONSerializer;
import com.vaadin.terminal.gwt.client.communication.JSONSerializer;
import com.vaadin.terminal.gwt.client.communication.JsonDecoder;
import com.vaadin.terminal.gwt.client.communication.JsonEncoder;
import com.vaadin.terminal.gwt.client.communication.SerializerMap;

/**
* GWT generator for creating serializer classes for custom classes sent from
* server to client.
*
* Only fields with a correspondingly named setter are deserialized.
*
* @since 7.0
*/
public class SerializerGenerator extends Generator {

private static final String SUBTYPE_SEPARATOR = "___";

@Override
public String generate(TreeLogger logger, GeneratorContext context,
String typeName) throws UnableToCompleteException {
JClassType type;
try {
type = (JClassType) context.getTypeOracle().parse(typeName);
} catch (TypeOracleException e1) {
logger.log(Type.ERROR, "Could not find type " + typeName, e1);
throw new UnableToCompleteException();
}
String serializerClassName = getSerializerSimpleClassName(type);
try {
// Generate class source code
generateClass(logger, context, type,
getSerializerPackageName(type), serializerClassName);
} catch (Exception e) {
logger.log(TreeLogger.ERROR, "SerializerGenerator failed for "
+ type.getQualifiedSourceName(), e);
throw new UnableToCompleteException();
}

// return the fully qualifed name of the class generated
return getFullyQualifiedSerializerClassName(type);
}

/**
* Generate source code for a VaadinSerializer implementation.
*
* @param logger
* Logger object
* @param context
* Generator context
* @param type
* @param beanTypeName
* bean type for which the serializer is to be generated
* @param beanSerializerTypeName
* name of the serializer class to generate
* @throws UnableToCompleteException
*/
private void generateClass(TreeLogger logger, GeneratorContext context,
JClassType type, String serializerPackageName,
String serializerClassName) throws UnableToCompleteException {
// get print writer that receives the source code
PrintWriter printWriter = null;
printWriter = context.tryCreate(logger, serializerPackageName,
serializerClassName);

// print writer if null, source code has ALREADY been generated
if (printWriter == null) {
return;
}
boolean isEnum = (type.isEnum() != null);
boolean isArray = (type.isArray() != null);

String qualifiedSourceName = type.getQualifiedSourceName();
logger.log(Type.DEBUG, "Processing serializable type "
+ qualifiedSourceName + "...");

// init composer, set class properties, create source writer
ClassSourceFileComposerFactory composer = null;
composer = new ClassSourceFileComposerFactory(serializerPackageName,
serializerClassName);
composer.addImport(GWT.class.getName());
composer.addImport(JSONValue.class.getName());
composer.addImport(com.vaadin.terminal.gwt.client.communication.Type.class
.getName());
// composer.addImport(JSONObject.class.getName());
// composer.addImport(VPaintableMap.class.getName());
composer.addImport(JsonDecoder.class.getName());
// composer.addImport(VaadinSerializer.class.getName());

if (isEnum || isArray) {
composer.addImplementedInterface(JSONSerializer.class.getName()
+ "<" + qualifiedSourceName + ">");
} else {
composer.addImplementedInterface(DiffJSONSerializer.class.getName()
+ "<" + qualifiedSourceName + ">");
}

SourceWriter sourceWriter = composer.createSourceWriter(context,
printWriter);
sourceWriter.indent();

// Serializer

// public JSONValue serialize(Object value,
// ApplicationConnection connection) {
sourceWriter.println("public " + JSONValue.class.getName()
+ " serialize(" + qualifiedSourceName + " value, "
+ ApplicationConnection.class.getName() + " connection) {");
sourceWriter.indent();
// MouseEventDetails castedValue = (MouseEventDetails) value;
sourceWriter.println(qualifiedSourceName + " castedValue = ("
+ qualifiedSourceName + ") value;");

if (isEnum) {
writeEnumSerializer(logger, sourceWriter, type);
} else if (isArray) {
writeArraySerializer(logger, sourceWriter, type.isArray());
} else {
writeBeanSerializer(logger, sourceWriter, type);
}
// }
sourceWriter.outdent();
sourceWriter.println("}");
sourceWriter.println();

// Updater
// public void update(T target, Type type, JSONValue jsonValue,
// ApplicationConnection connection);
if (!isEnum && !isArray) {
sourceWriter.println("public void update(" + qualifiedSourceName
+ " target, Type type, " + JSONValue.class.getName()
+ " jsonValue, " + ApplicationConnection.class.getName()
+ " connection) {");
sourceWriter.indent();

writeBeanDeserializer(logger, sourceWriter, type);

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

// Deserializer
// T deserialize(Type type, JSONValue jsonValue, ApplicationConnection
// connection);
sourceWriter.println("public " + qualifiedSourceName
+ " deserialize(Type type, " + JSONValue.class.getName()
+ " jsonValue, " + ApplicationConnection.class.getName()
+ " connection) {");
sourceWriter.indent();

if (isEnum) {
writeEnumDeserializer(logger, sourceWriter, type.isEnum());
} else if (isArray) {
writeArrayDeserializer(logger, sourceWriter, type.isArray());
} else {
sourceWriter.println(qualifiedSourceName + " target = GWT.create("
+ qualifiedSourceName + ".class);");
sourceWriter
.println("update(target, type, jsonValue, connection);");
// return target;
sourceWriter.println("return target;");
}
sourceWriter.outdent();
sourceWriter.println("}");

// End of class
sourceWriter.outdent();
sourceWriter.println("}");

// commit generated class
context.commit(logger, printWriter);
logger.log(TreeLogger.INFO, "Generated Serializer class "
+ getFullyQualifiedSerializerClassName(type));
}

private void writeEnumDeserializer(TreeLogger logger,
SourceWriter sourceWriter, JEnumType enumType) {
sourceWriter.println("String enumIdentifier = (("
+ JSONString.class.getName() + ")jsonValue).stringValue();");
for (JEnumConstant e : enumType.getEnumConstants()) {
sourceWriter.println("if (\"" + e.getName()
+ "\".equals(enumIdentifier)) {");
sourceWriter.indent();
sourceWriter.println("return " + enumType.getQualifiedSourceName()
+ "." + e.getName() + ";");
sourceWriter.outdent();
sourceWriter.println("}");
}
sourceWriter.println("return null;");
}

private void writeArrayDeserializer(TreeLogger logger,
SourceWriter sourceWriter, JArrayType type) {
JType leafType = type.getLeafType();
int rank = type.getRank();

sourceWriter.println(JSONArray.class.getName()
+ " jsonArray = jsonValue.isArray();");

// Type value = new Type[jsonArray.size()][][];
sourceWriter.print(type.getQualifiedSourceName() + " value = new "
+ leafType.getQualifiedSourceName() + "[jsonArray.size()]");
for (int i = 1; i < rank; i++) {
sourceWriter.print("[]");
}
sourceWriter.println(";");

sourceWriter.println("for(int i = 0 ; i < value.length; i++) {");
sourceWriter.indent();

JType componentType = type.getComponentType();

sourceWriter.print("value[i] = ("
+ GeneratedRpcMethodProviderGenerator
.getBoxedTypeName(componentType) + ") "
+ JsonDecoder.class.getName() + ".decodeValue(");
GeneratedRpcMethodProviderGenerator.writeTypeCreator(sourceWriter,
componentType);
sourceWriter.print(", jsonArray.get(i), null, connection)");

sourceWriter.println(";");

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

sourceWriter.println("return value;");
}

private void writeBeanDeserializer(TreeLogger logger,
SourceWriter sourceWriter, JClassType beanType) {
String beanQualifiedSourceName = beanType.getQualifiedSourceName();

// JSONOBject json = (JSONObject)jsonValue;
sourceWriter.println(JSONObject.class.getName() + " json = ("
+ JSONObject.class.getName() + ")jsonValue;");

for (JMethod method : getSetters(beanType)) {
String setterName = method.getName();
String baseName = setterName.substring(3);
String fieldName = getTransportFieldName(baseName); // setZIndex()
// -> zIndex
JType setterParameterType = method.getParameterTypes()[0];

logger.log(Type.DEBUG, "* Processing field " + fieldName + " in "
+ beanQualifiedSourceName + " (" + beanType.getName() + ")");

// if (json.containsKey("height")) {
sourceWriter.println("if (json.containsKey(\"" + fieldName
+ "\")) {");
sourceWriter.indent();
String jsonFieldName = "json_" + fieldName;
// JSONValue json_Height = json.get("height");
sourceWriter.println("JSONValue " + jsonFieldName
+ " = json.get(\"" + fieldName + "\");");

String fieldType;
String getterName = "get" + baseName;
JPrimitiveType primitiveType = setterParameterType.isPrimitive();
if (primitiveType != null) {
// This is a primitive type -> must used the boxed type
fieldType = primitiveType.getQualifiedBoxedSourceName();
if (primitiveType == JPrimitiveType.BOOLEAN) {
getterName = "is" + baseName;
}
} else {
fieldType = setterParameterType.getQualifiedSourceName();
}

// String referenceValue = target.getHeight();
sourceWriter.println(fieldType + " referenceValue = target."
+ getterName + "();");

// target.setHeight((String)
// JsonDecoder.decodeValue(jsonFieldValue,referenceValue, idMapper,
// connection));
sourceWriter.print("target." + setterName + "((" + fieldType + ") "
+ JsonDecoder.class.getName() + ".decodeValue(");
GeneratedRpcMethodProviderGenerator.writeTypeCreator(sourceWriter,
setterParameterType);
sourceWriter.println(", " + jsonFieldName
+ ", referenceValue, connection));");

// } ... end of if contains
sourceWriter.outdent();
sourceWriter.println("}");
}
}

private void writeEnumSerializer(TreeLogger logger,
SourceWriter sourceWriter, JClassType beanType) {
// return new JSONString(castedValue.name());
sourceWriter.println("return new " + JSONString.class.getName()
+ "(castedValue.name());");
}

private void writeArraySerializer(TreeLogger logger,
SourceWriter sourceWriter, JArrayType array) {
sourceWriter.println(JSONArray.class.getName() + " values = new "
+ JSONArray.class.getName() + "();");
JType componentType = array.getComponentType();
// JPrimitiveType primitive = componentType.isPrimitive();
sourceWriter.println("for (int i = 0; i < castedValue.length; i++) {");
sourceWriter.indent();
sourceWriter.print("values.set(i, ");
sourceWriter.print(JsonEncoder.class.getName()
+ ".encode(castedValue[i], false, connection)");
sourceWriter.println(");");
sourceWriter.outdent();
sourceWriter.println("}");
sourceWriter.println("return values;");
}

private void writeBeanSerializer(TreeLogger logger,
SourceWriter sourceWriter, JClassType beanType)
throws UnableToCompleteException {

// JSONObject json = new JSONObject();
sourceWriter.println(JSONObject.class.getName() + " json = new "
+ JSONObject.class.getName() + "();");

HashSet<String> usedFieldNames = new HashSet<String>();

for (JMethod setterMethod : getSetters(beanType)) {
String setterName = setterMethod.getName();
String fieldName = getTransportFieldName(setterName.substring(3)); // setZIndex()
// -> zIndex
if (!usedFieldNames.add(fieldName)) {
logger.log(
TreeLogger.ERROR,
"Can't encode "
+ beanType.getQualifiedSourceName()
+ " as it has multiple fields with the name "
+ fieldName.toLowerCase()
+ ". This can happen if only casing distinguishes one property name from another.");
throw new UnableToCompleteException();
}
String getterName = findGetter(beanType, setterMethod);

if (getterName == null) {
logger.log(TreeLogger.ERROR, "No getter found for " + fieldName
+ ". Serialization will likely fail");
}
// json.put("button",
// JsonEncoder.encode(castedValue.getButton(), false, idMapper,
// connection));
sourceWriter.println("json.put(\"" + fieldName + "\", "
+ JsonEncoder.class.getName() + ".encode(castedValue."
+ getterName + "(), false, connection));");
}
// return json;
sourceWriter.println("return json;");

}

private static String getTransportFieldName(String baseName) {
return Character.toLowerCase(baseName.charAt(0))
+ baseName.substring(1);
}

private String findGetter(JClassType beanType, JMethod setterMethod) {
JType setterParameterType = setterMethod.getParameterTypes()[0];
String fieldName = setterMethod.getName().substring(3);
if (setterParameterType.getQualifiedSourceName().equals(
boolean.class.getName())) {
return "is" + fieldName;
} else {
return "get" + fieldName;
}
}

/**
* Returns a list of all setters found in the beanType or its parent class
*
* @param beanType
* The type to check
* @return A list of setter methods from the class and its parents
*/
protected static List<JMethod> getSetters(JClassType beanType) {

List<JMethod> setterMethods = new ArrayList<JMethod>();

while (beanType != null
&& !beanType.getQualifiedSourceName().equals(
Object.class.getName())) {
for (JMethod method : beanType.getMethods()) {
// Process all setters that have corresponding fields
if (!method.isPublic() || method.isStatic()
|| !method.getName().startsWith("set")
|| method.getParameterTypes().length != 1) {
// Not setter, skip to next method
continue;
}
setterMethods.add(method);
}
beanType = beanType.getSuperclass();
}

return setterMethods;
}

private static String getSerializerSimpleClassName(JClassType beanType) {
return getSimpleClassName(beanType) + "_Serializer";
}

private static String getSimpleClassName(JType type) {
JArrayType arrayType = type.isArray();
if (arrayType != null) {
return "Array" + getSimpleClassName(arrayType.getComponentType());
}
JClassType classType = type.isClass();
if (classType != null && classType.isMemberType()) {
// Assumed to be static sub class
String baseName = getSimpleClassName(classType.getEnclosingType());
String name = baseName + SUBTYPE_SEPARATOR
+ type.getSimpleSourceName();
return name;
}
return type.getSimpleSourceName();
}

public static String getFullyQualifiedSerializerClassName(JClassType type) {
return getSerializerPackageName(type) + "."
+ getSerializerSimpleClassName(type);
}

private static String getSerializerPackageName(JClassType type) {
JPackage typePackage = type.getPackage();
if (typePackage == null) {
return SerializerMap.class.getPackage().getName();
} else {
String packageName = typePackage.getName();
// Dev mode classloader gets unhappy for some java packages
if (packageName.startsWith("java.")) {
packageName = "com.vaadin." + packageName;
}
return packageName;
}
}
}

+ 0
- 377
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java View File

@@ -1,377 +0,0 @@
/*
* 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.terminal.gwt.widgetsetutils;

import java.io.PrintWriter;
import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.vaadin.shared.communication.ClientRpc;
import com.vaadin.shared.communication.ServerRpc;
import com.vaadin.shared.communication.SharedState;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.communication.JSONSerializer;
import com.vaadin.terminal.gwt.client.communication.SerializerMap;

/**
* GWT generator that creates a {@link SerializerMap} implementation (mapper
* from type string to serializer instance) and serializer classes for all
* subclasses of {@link SharedState}.
*
* @since 7.0
*/
public class SerializerMapGenerator extends Generator {

private static final String FAIL_IF_NOT_SERIALIZABLE = "vFailIfNotSerializable";
private String packageName;
private String className;

@Override
public String generate(TreeLogger logger, GeneratorContext context,
String typeName) throws UnableToCompleteException {

try {
TypeOracle typeOracle = context.getTypeOracle();
Set<JClassType> typesNeedingSerializers = findTypesNeedingSerializers(
typeOracle, logger);
checkForUnserializableTypes(typesNeedingSerializers, typeOracle,
logger);
Set<JClassType> typesWithExistingSerializers = findTypesWithExistingSerializers(
typeOracle, logger);
Set<JClassType> serializerMappings = new HashSet<JClassType>();
serializerMappings.addAll(typesNeedingSerializers);
serializerMappings.addAll(typesWithExistingSerializers);
// get classType and save instance variables
JClassType classType = typeOracle.getType(typeName);
packageName = classType.getPackage().getName();
className = classType.getSimpleSourceName() + "Impl";
// Generate class source code for SerializerMapImpl
generateSerializerMap(serializerMappings, logger, context);

SerializerGenerator sg = new SerializerGenerator();
for (JClassType type : typesNeedingSerializers) {
sg.generate(logger, context, type.getQualifiedSourceName());
}
} catch (Exception e) {
logger.log(TreeLogger.ERROR,
"SerializerMapGenerator creation failed", e);
throw new UnableToCompleteException();
}
// return the fully qualifed name of the class generated
return packageName + "." + className;
}

/**
* Emits a warning for all classes that are used in communication but do not
* implement java.io.Serializable. Implementing java.io.Serializable is not
* needed for communication but for the server side Application to be
* serializable i.e. work in GAE for instance.
*
* @param typesNeedingSerializers
* @param typeOracle
* @param logger
* @throws UnableToCompleteException
*/
private void checkForUnserializableTypes(
Set<JClassType> typesNeedingSerializers, TypeOracle typeOracle,
TreeLogger logger) throws UnableToCompleteException {
JClassType javaSerializable = typeOracle.findType(Serializable.class
.getName());
for (JClassType type : typesNeedingSerializers) {
if (type.isArray() != null) {
// Don't check for arrays
continue;
}
boolean serializable = type.isAssignableTo(javaSerializable);
if (!serializable) {
boolean abortCompile = "true".equals(System
.getProperty(FAIL_IF_NOT_SERIALIZABLE));
logger.log(
abortCompile ? Type.ERROR : Type.WARN,
type
+ " is used in RPC or shared state but does not implement "
+ Serializable.class.getName()
+ ". Communication will work but the Application on server side cannot be serialized if it refers to objects of this type. "
+ "If the system property "
+ FAIL_IF_NOT_SERIALIZABLE
+ " is set to \"true\", this causes the compilation to fail instead of just emitting a warning.");
if (abortCompile) {
throw new UnableToCompleteException();
}
}
}
}

private Set<JClassType> findTypesWithExistingSerializers(
TypeOracle typeOracle, TreeLogger logger)
throws UnableToCompleteException {
JClassType serializerInterface = typeOracle
.findType(JSONSerializer.class.getName());
JType[] deserializeParamTypes = new JType[] {
typeOracle
.findType(com.vaadin.terminal.gwt.client.communication.Type.class
.getName()),
typeOracle.findType(JSONValue.class.getName()),
typeOracle.findType(ApplicationConnection.class.getName()) };
String deserializeMethodName = "deserialize";
try {
serializerInterface.getMethod(deserializeMethodName,
deserializeParamTypes);
} catch (NotFoundException e) {
logger.log(Type.ERROR, "Could not find " + deserializeMethodName
+ " in " + serializerInterface);
throw new UnableToCompleteException();
}

Set<JClassType> types = new HashSet<JClassType>();
for (JClassType serializer : serializerInterface.getSubtypes()) {
JMethod deserializeMethod = serializer.findMethod(
deserializeMethodName, deserializeParamTypes);
if (deserializeMethod == null) {
logger.log(Type.DEBUG, "Could not find "
+ deserializeMethodName + " in " + serializer);
continue;
}
JType returnType = deserializeMethod.getReturnType();
logger.log(Type.DEBUG, "Found " + deserializeMethodName
+ " with return type " + returnType + " in " + serializer);

types.add(returnType.isClass());
}
return types;
}

/**
* Generate source code for SerializerMapImpl
*
* @param typesNeedingSerializers
*
* @param logger
* Logger object
* @param context
* Generator context
*/
private void generateSerializerMap(Set<JClassType> typesNeedingSerializers,
TreeLogger logger, GeneratorContext context) {
// get print writer that receives the source code
PrintWriter printWriter = null;
printWriter = context.tryCreate(logger, packageName, className);
// print writer if null, source code has ALREADY been generated
if (printWriter == null) {
return;
}
Date date = new Date();
TypeOracle typeOracle = context.getTypeOracle();

// init composer, set class properties, create source writer
ClassSourceFileComposerFactory composer = null;
composer = new ClassSourceFileComposerFactory(packageName, className);
composer.addImport("com.google.gwt.core.client.GWT");
composer.addImplementedInterface(SerializerMap.class.getName());
SourceWriter sourceWriter = composer.createSourceWriter(context,
printWriter);
sourceWriter.indent();

sourceWriter.println("public " + JSONSerializer.class.getName()
+ " getSerializer(String type) {");
sourceWriter.indent();

// TODO cache serializer instances in a map
for (JClassType type : typesNeedingSerializers) {
sourceWriter.print("if (type.equals(\""
+ type.getQualifiedSourceName() + "\")");
if (type instanceof JArrayType) {
// Also add binary name to support encoding based on
// object.getClass().getName()
sourceWriter.print("||type.equals(\"" + type.getJNISignature()
+ "\")");
}
sourceWriter.println(") {");
sourceWriter.indent();
String serializerName = SerializerGenerator
.getFullyQualifiedSerializerClassName(type);
sourceWriter.println("return GWT.create(" + serializerName
+ ".class);");
sourceWriter.outdent();
sourceWriter.println("}");
logger.log(Type.INFO, "Configured serializer (" + serializerName
+ ") for " + type.getName());
}
sourceWriter
.println("throw new RuntimeException(\"No serializer found for class \"+type);");
sourceWriter.outdent();
sourceWriter.println("}");

// close generated class
sourceWriter.outdent();
sourceWriter.println("}");
// commit generated class
context.commit(logger, printWriter);
logger.log(Type.INFO,
"Done. (" + (new Date().getTime() - date.getTime()) / 1000
+ "seconds)");

}

public Set<JClassType> findTypesNeedingSerializers(TypeOracle typeOracle,
TreeLogger logger) {
logger.log(Type.DEBUG, "Detecting serializable data types...");

HashSet<JClassType> types = new HashSet<JClassType>();

// Generate serializer classes for each subclass of SharedState
JClassType serializerType = typeOracle.findType(SharedState.class
.getName());
types.add(serializerType);
JClassType[] serializerSubtypes = serializerType.getSubtypes();
for (JClassType type : serializerSubtypes) {
types.add(type);
}

// Serializer classes might also be needed for RPC methods
for (Class<?> cls : new Class[] { ServerRpc.class, ClientRpc.class }) {
JClassType rpcType = typeOracle.findType(cls.getName());
JClassType[] serverRpcSubtypes = rpcType.getSubtypes();
for (JClassType type : serverRpcSubtypes) {
addMethodParameterTypes(type, types, logger);
}
}

// Add all types used from/in the types
for (Object t : types.toArray()) {
findSubTypesNeedingSerializers((JClassType) t, types);
}
logger.log(Type.DEBUG, "Serializable data types: " + types.toString());

return types;
}

private void addMethodParameterTypes(JClassType classContainingMethods,
Set<JClassType> types, TreeLogger logger) {
for (JMethod method : classContainingMethods.getMethods()) {
if (method.getName().equals("initRpc")) {
continue;
}
for (JType type : method.getParameterTypes()) {
addTypeIfNeeded(types, type);
}
}
}

public void findSubTypesNeedingSerializers(JClassType type,
Set<JClassType> serializableTypes) {
// Find all setters and look at their parameter type to determine if a
// new serializer is needed
for (JMethod setterMethod : SerializerGenerator.getSetters(type)) {
// The one and only parameter for the setter
JType setterType = setterMethod.getParameterTypes()[0];
addTypeIfNeeded(serializableTypes, setterType);
}
}

private void addTypeIfNeeded(Set<JClassType> serializableTypes, JType type) {
if (serializableTypes.contains(type)) {
return;
}
JParameterizedType parametrized = type.isParameterized();
if (parametrized != null) {
for (JClassType parameterType : parametrized.getTypeArgs()) {
addTypeIfNeeded(serializableTypes, parameterType);
}
}

if (serializationHandledByFramework(type)) {
return;
}

if (serializableTypes.contains(type)) {
return;
}

JClassType typeClass = type.isClass();
if (typeClass != null) {
// setterTypeClass is null at least for List<String>. It is
// possible that we need to handle the cases somehow, for
// instance for List<MyObject>.
serializableTypes.add(typeClass);
findSubTypesNeedingSerializers(typeClass, serializableTypes);
}

// Generate (n-1)-dimensional array serializer for n-dimensional array
JArrayType arrayType = type.isArray();
if (arrayType != null) {
serializableTypes.add(arrayType);
addTypeIfNeeded(serializableTypes, arrayType.getComponentType());
}

}

Set<Class<?>> frameworkHandledTypes = new HashSet<Class<?>>();
{
frameworkHandledTypes.add(String.class);
frameworkHandledTypes.add(Boolean.class);
frameworkHandledTypes.add(Integer.class);
frameworkHandledTypes.add(Float.class);
frameworkHandledTypes.add(Double.class);
frameworkHandledTypes.add(Long.class);
frameworkHandledTypes.add(Enum.class);
frameworkHandledTypes.add(String[].class);
frameworkHandledTypes.add(Object[].class);
frameworkHandledTypes.add(Map.class);
frameworkHandledTypes.add(List.class);
frameworkHandledTypes.add(Set.class);
frameworkHandledTypes.add(Byte.class);
frameworkHandledTypes.add(Character.class);

}

private boolean serializationHandledByFramework(JType setterType) {
// Some types are handled by the framework at the moment. See #8449
// This method should be removed at some point.
if (setterType.isPrimitive() != null) {
return true;
}

String qualifiedName = setterType.getQualifiedSourceName();
for (Class<?> cls : frameworkHandledTypes) {
if (qualifiedName.equals(cls.getName())) {
return true;
}
}

return false;
}
}

+ 2
- 2
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java View File

@@ -40,7 +40,7 @@ import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.Connect.LoadStyle;
import com.vaadin.terminal.gwt.client.ServerConnector;
import com.vaadin.terminal.gwt.client.ui.UnknownComponentConnector;
import com.vaadin.terminal.gwt.client.ui.root.RootConnector;
import com.vaadin.terminal.gwt.client.ui.UI.UIConnector;
import com.vaadin.terminal.gwt.server.ClientConnector;

/**
@@ -284,7 +284,7 @@ public class WidgetMapGenerator extends Generator {
if (connectorsWithInstantiator.contains(clientClass)) {
continue;
}
if (clientClass == RootConnector.class) {
if (clientClass == UIConnector.class) {
// Roots are not instantiated by widgetset
continue;
}

+ 90
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ArraySerializer.java View File

@@ -0,0 +1,90 @@
/*
* 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.terminal.gwt.widgetsetutils.metadata;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.user.rebind.SourceWriter;
import com.vaadin.terminal.gwt.client.communication.JsonDecoder;
import com.vaadin.terminal.gwt.client.communication.JsonEncoder;
import com.vaadin.terminal.gwt.widgetsetutils.ConnectorBundleLoaderFactory;

public class ArraySerializer extends JsonSerializer {

private final JArrayType arrayType;

public ArraySerializer(JArrayType arrayType) {
super(arrayType);
this.arrayType = arrayType;
}

@Override
protected void printDeserializerBody(TreeLogger logger, SourceWriter w,
String type, String jsonValue, String connection) {
JType leafType = arrayType.getLeafType();
int rank = arrayType.getRank();

w.println(JSONArray.class.getName() + " jsonArray = " + jsonValue
+ ".isArray();");

// Type value = new Type[jsonArray.size()][][];
w.print(arrayType.getQualifiedSourceName() + " value = new "
+ leafType.getQualifiedSourceName() + "[jsonArray.size()]");
for (int i = 1; i < rank; i++) {
w.print("[]");
}
w.println(";");

w.println("for(int i = 0 ; i < value.length; i++) {");
w.indent();

JType componentType = arrayType.getComponentType();

w.print("value[i] = ("
+ ConnectorBundleLoaderFactory.getBoxedTypeName(componentType)
+ ") " + JsonDecoder.class.getName() + ".decodeValue(");
ConnectorBundleLoaderFactory.writeTypeCreator(w, componentType);
w.print(", jsonArray.get(i), null, " + connection + ")");

w.println(";");

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

w.println("return value;");
}

@Override
protected void printSerializerBody(TreeLogger logger, SourceWriter w,
String value, String applicationConnection) {
w.println(JSONArray.class.getName() + " values = new "
+ JSONArray.class.getName() + "();");
// JPrimitiveType primitive = componentType.isPrimitive();
w.println("for (int i = 0; i < " + value + ".length; i++) {");
w.indent();
w.print("values.set(i, ");
w.print(JsonEncoder.class.getName() + ".encode(" + value
+ "[i], false, " + applicationConnection + ")");
w.println(");");
w.outdent();
w.println("}");
w.println("return values;");
}

}

+ 45
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ClientRpcVisitor.java View File

@@ -0,0 +1,45 @@
/*
* 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.terminal.gwt.widgetsetutils.metadata;

import java.util.Set;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JType;

public class ClientRpcVisitor extends TypeVisitor {
@Override
public void visitClientRpc(TreeLogger logger, JClassType type,
ConnectorBundle bundle) {
Set<? extends JClassType> hierarchy = type
.getFlattenedSupertypeHierarchy();
for (JClassType subType : hierarchy) {
JMethod[] methods = subType.getMethods();
for (JMethod method : methods) {
bundle.setNeedsInvoker(type, method);
bundle.setNeedsParamTypes(type, method);

JType[] parameterTypes = method.getParameterTypes();
for (JType paramType : parameterTypes) {
bundle.setNeedsSerialize(paramType);
}
}
}
}
}

+ 608
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java View File

@@ -0,0 +1,608 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.widgetsetutils.metadata;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JEnumType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.json.client.JSONValue;
import com.vaadin.shared.communication.ClientRpc;
import com.vaadin.shared.communication.ServerRpc;
import com.vaadin.shared.ui.Connect;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.ComponentConnector;
import com.vaadin.terminal.gwt.client.ServerConnector;
import com.vaadin.terminal.gwt.client.communication.JSONSerializer;

public class ConnectorBundle {
private static final String FAIL_IF_NOT_SERIALIZABLE = "vFailIfNotSerializable";

private final String name;
private final ConnectorBundle previousBundle;
private final Collection<TypeVisitor> visitors;
private final Map<JType, JClassType> customSerializers;

private final Set<JType> hasSerializeSupport = new HashSet<JType>();
private final Set<JType> needsSerializeSupport = new HashSet<JType>();
private final Map<JType, GeneratedSerializer> serializers = new HashMap<JType, GeneratedSerializer>();

private final Set<JClassType> needsPropertyList = new HashSet<JClassType>();
private final Set<JClassType> needsGwtConstructor = new HashSet<JClassType>();
private final Set<JClassType> visitedTypes = new HashSet<JClassType>();
private final Set<JClassType> needsProxySupport = new HashSet<JClassType>();

private final Map<JClassType, Set<String>> identifiers = new HashMap<JClassType, Set<String>>();
private final Map<JClassType, Set<JMethod>> needsReturnType = new HashMap<JClassType, Set<JMethod>>();
private final Map<JClassType, Set<JMethod>> needsInvoker = new HashMap<JClassType, Set<JMethod>>();
private final Map<JClassType, Set<JMethod>> needsParamTypes = new HashMap<JClassType, Set<JMethod>>();
private final Map<JClassType, Set<JMethod>> needsDelayedInfo = new HashMap<JClassType, Set<JMethod>>();

private final Set<Property> needsSetter = new HashSet<Property>();
private final Set<Property> needsType = new HashSet<Property>();
private final Set<Property> needsGetter = new HashSet<Property>();
private final Set<Property> needsDelegateToWidget = new HashSet<Property>();

private ConnectorBundle(String name, ConnectorBundle previousBundle,
Collection<TypeVisitor> visitors,
Map<JType, JClassType> customSerializers) {
this.name = name;
this.previousBundle = previousBundle;
this.visitors = visitors;
this.customSerializers = customSerializers;
}

public ConnectorBundle(String name, ConnectorBundle previousBundle) {
this(name, previousBundle, previousBundle.visitors,
previousBundle.customSerializers);
}

public ConnectorBundle(String name, Collection<TypeVisitor> visitors,
TypeOracle oracle) throws NotFoundException {
this(name, null, visitors, findCustomSerializers(oracle));
}

private static Map<JType, JClassType> findCustomSerializers(
TypeOracle oracle) throws NotFoundException {
Map<JType, JClassType> serializers = new HashMap<JType, JClassType>();

JClassType serializerInterface = oracle.findType(JSONSerializer.class
.getName());
JType[] deserializeParamTypes = new JType[] {
oracle.findType(com.vaadin.terminal.gwt.client.metadata.Type.class
.getName()),
oracle.findType(JSONValue.class.getName()),
oracle.findType(ApplicationConnection.class.getName()) };
String deserializeMethodName = "deserialize";
// Just test that the method exists
serializerInterface.getMethod(deserializeMethodName,
deserializeParamTypes);

for (JClassType serializer : serializerInterface.getSubtypes()) {
JMethod deserializeMethod = serializer.findMethod(
deserializeMethodName, deserializeParamTypes);
if (deserializeMethod == null) {
continue;
}
JType returnType = deserializeMethod.getReturnType();

serializers.put(returnType, serializer);
}
return serializers;
}

public void setNeedsGwtConstructor(JClassType type) {
if (!needsGwtConstructor(type)) {
needsGwtConstructor.add(type);
}
}

private boolean needsGwtConstructor(JClassType type) {
if (needsGwtConstructor.contains(type)) {
return true;
} else {
return previousBundle != null
&& previousBundle.needsGwtConstructor(type);
}
}

public void setIdentifier(JClassType type, String identifier) {
if (!hasIdentifier(type, identifier)) {
addMapping(identifiers, type, identifier);
}
}

private boolean hasIdentifier(JClassType type, String identifier) {
if (hasMapping(identifiers, type, identifier)) {
return true;
} else {
return previousBundle != null
&& previousBundle.hasIdentifier(type, identifier);
}
}

public ConnectorBundle getPreviousBundle() {
return previousBundle;
}

public String getName() {
return name;
}

public Map<JClassType, Set<String>> getIdentifiers() {
return Collections.unmodifiableMap(identifiers);
}

public Set<JClassType> getGwtConstructors() {
return Collections.unmodifiableSet(needsGwtConstructor);
}

public void processTypes(TreeLogger logger, Collection<JClassType> types)
throws UnableToCompleteException {
for (JClassType type : types) {
processType(logger, type);
}
}

public void processType(TreeLogger logger, JClassType type)
throws UnableToCompleteException {
if (!isTypeVisited(type)) {
for (TypeVisitor typeVisitor : visitors) {
invokeVisitor(logger, type, typeVisitor);
}
visitedTypes.add(type);
purgeSerializeSupportQueue(logger);
}
}

private boolean isTypeVisited(JClassType type) {
if (visitedTypes.contains(type)) {
return true;
} else {
return previousBundle != null && previousBundle.isTypeVisited(type);
}
}

private void purgeSerializeSupportQueue(TreeLogger logger)
throws UnableToCompleteException {
while (!needsSerializeSupport.isEmpty()) {
Iterator<JType> iterator = needsSerializeSupport.iterator();
JType type = iterator.next();
iterator.remove();

if (hasSserializeSupport(type)) {
continue;
}

addSerializeSupport(logger, type);
}
}

private void addSerializeSupport(TreeLogger logger, JType type)
throws UnableToCompleteException {
hasSerializeSupport.add(type);

JParameterizedType parametrized = type.isParameterized();
if (parametrized != null) {
for (JClassType parameterType : parametrized.getTypeArgs()) {
setNeedsSerialize(parameterType);
}
}

if (serializationHandledByFramework(type)) {
return;
}

JClassType customSerializer = customSerializers.get(type);
JClassType typeAsClass = type.isClass();
JEnumType enumType = type.isEnum();
JArrayType arrayType = type.isArray();

if (customSerializer != null) {
logger.log(Type.INFO, "Will serialize " + type + " using "
+ customSerializer.getName());
setSerializer(type, new CustomSerializer(customSerializer));
} else if (arrayType != null) {
logger.log(Type.INFO, "Will serialize " + type + " as an array");
setSerializer(type, new ArraySerializer(arrayType));
setNeedsSerialize(arrayType.getComponentType());
} else if (enumType != null) {
logger.log(Type.INFO, "Will serialize " + type + " as an enum");
setSerializer(type, new EnumSerializer(enumType));
} else if (typeAsClass != null) {
// Bean
checkSerializable(logger, typeAsClass);

logger.log(Type.INFO, "Will serialize " + type + " as a bean");

setNeedsPropertyList(typeAsClass);

for (Property property : getProperties(typeAsClass)) {
setNeedsGwtConstructor(property.getBeanType());
setNeedsSetter(property);

// Getters needed for reading previous value that should be
// passed to sub encoder
setNeedsGetter(property);
setNeedsType(property);

JType propertyType = property.getPropertyType();
setNeedsSerialize(propertyType);
}
}
}

private void checkSerializable(TreeLogger logger, JClassType type)
throws UnableToCompleteException {
JClassType javaSerializable = type.getOracle().findType(
Serializable.class.getName());
boolean serializable = type.isAssignableTo(javaSerializable);
if (!serializable) {
boolean abortCompile = "true".equals(System
.getProperty(FAIL_IF_NOT_SERIALIZABLE));
logger.log(
abortCompile ? Type.ERROR : Type.WARN,
type
+ " is used in RPC or shared state but does not implement "
+ Serializable.class.getName()
+ ". Communication will work but the Application on server side cannot be serialized if it refers to objects of this type. "
+ "If the system property "
+ FAIL_IF_NOT_SERIALIZABLE
+ " is set to \"true\", this causes the compilation to fail instead of just emitting a warning.");
if (abortCompile) {
throw new UnableToCompleteException();
}
}
}

private void setSerializer(JType type, GeneratedSerializer serializer) {
if (!hasSerializer(type)) {
serializers.put(type, serializer);
}
}

private boolean hasSerializer(JType type) {
if (serializers.containsKey(type)) {
return true;
} else {
return previousBundle != null && previousBundle.hasSerializer(type);
}
}

public Map<JType, GeneratedSerializer> getSerializers() {
return Collections.unmodifiableMap(serializers);
}

private void setNeedsGetter(Property property) {
if (!isNeedsGetter(property)) {
needsGetter.add(property);
}
}

private boolean isNeedsGetter(Property property) {
if (needsGetter.contains(property)) {
return true;
} else {
return previousBundle != null
&& previousBundle.isNeedsGetter(property);
}
}

public Set<Property> getNeedsGetter() {
return Collections.unmodifiableSet(needsGetter);
}

private void setNeedsType(Property property) {
if (!isNeedsType(property)) {
needsType.add(property);
}
}

public Set<Property> getNeedsType() {
return Collections.unmodifiableSet(needsType);
}

private boolean isNeedsType(Property property) {
if (needsType.contains(property)) {
return true;
} else {
return previousBundle != null
&& previousBundle.isNeedsType(property);
}
}

public void setNeedsSetter(Property property) {
if (!isNeedsSetter(property)) {
needsSetter.add(property);
}
}

private boolean isNeedsSetter(Property property) {
if (needsSetter.contains(property)) {
return true;
} else {
return previousBundle != null
&& previousBundle.isNeedsSetter(property);
}
}

public Set<Property> getNeedsSetter() {
return Collections.unmodifiableSet(needsSetter);
}

private void setNeedsPropertyList(JClassType type) {
if (!isNeedsPropertyList(type)) {
needsPropertyList.add(type);
}
}

private boolean isNeedsPropertyList(JClassType type) {
if (needsPropertyList.contains(type)) {
return true;
} else {
return previousBundle != null
&& previousBundle.isNeedsPropertyList(type);
}
}

public Set<JClassType> getNeedsPropertyListing() {
return Collections.unmodifiableSet(needsPropertyList);
}

public Collection<Property> getProperties(JClassType type) {
HashSet<Property> properties = new HashSet<Property>();

properties.addAll(MethodProperty.findProperties(type));
properties.addAll(FieldProperty.findProperties(type));

return properties;
}

private void invokeVisitor(TreeLogger logger, JClassType type,
TypeVisitor typeVisitor) throws UnableToCompleteException {
TreeLogger subLogger = logger.branch(Type.TRACE,
"Visiting " + type.getName() + " with "
+ typeVisitor.getClass().getSimpleName());
if (isConnectedConnector(type)) {
typeVisitor.visitConnector(subLogger, type, this);
}
if (isClientRpc(type)) {
typeVisitor.visitClientRpc(subLogger, type, this);
}
if (isServerRpc(type)) {
typeVisitor.visitServerRpc(subLogger, type, this);
}
}

public void processSubTypes(TreeLogger logger, JClassType type)
throws UnableToCompleteException {
processTypes(logger, Arrays.asList(type.getSubtypes()));
}

public void setNeedsReturnType(JClassType type, JMethod method) {
if (!isNeedsReturnType(type, method)) {
addMapping(needsReturnType, type, method);
}
}

private boolean isNeedsReturnType(JClassType type, JMethod method) {
if (hasMapping(needsReturnType, type, method)) {
return true;
} else {
return previousBundle != null
&& previousBundle.isNeedsReturnType(type, method);
}
}

public Map<JClassType, Set<JMethod>> getMethodReturnTypes() {
return Collections.unmodifiableMap(needsReturnType);
}

private static boolean isClientRpc(JClassType type) {
return isType(type, ClientRpc.class);
}

private static boolean isServerRpc(JClassType type) {
return isType(type, ServerRpc.class);
}

public static boolean isConnectedConnector(JClassType type) {
return isConnected(type) && isType(type, ServerConnector.class);
}

private static boolean isConnected(JClassType type) {
return type.isAnnotationPresent(Connect.class);
}

public static boolean isConnectedComponentConnector(JClassType type) {
return isConnected(type) && isType(type, ComponentConnector.class);
}

private static boolean isType(JClassType type, Class<?> class1) {
try {
return type.getOracle().getType(class1.getName())
.isAssignableFrom(type);
} catch (NotFoundException e) {
throw new RuntimeException("Could not find " + class1.getName(), e);
}
}

public void setNeedsInvoker(JClassType type, JMethod method) {
if (!isNeedsInvoker(type, method)) {
addMapping(needsInvoker, type, method);
}
}

private <K, V> void addMapping(Map<K, Set<V>> map, K key, V value) {
Set<V> set = map.get(key);
if (set == null) {
set = new HashSet<V>();
map.put(key, set);
}
set.add(value);
}

private <K, V> boolean hasMapping(Map<K, Set<V>> map, K key, V value) {
return map.containsKey(key) && map.get(key).contains(value);
}

private boolean isNeedsInvoker(JClassType type, JMethod method) {
if (hasMapping(needsInvoker, type, method)) {
return true;
} else {
return previousBundle != null
&& previousBundle.isNeedsInvoker(type, method);
}
}

public Map<JClassType, Set<JMethod>> getNeedsInvoker() {
return Collections.unmodifiableMap(needsInvoker);
}

public void setNeedsParamTypes(JClassType type, JMethod method) {
if (!isNeedsParamTypes(type, method)) {
addMapping(needsParamTypes, type, method);
}
}

private boolean isNeedsParamTypes(JClassType type, JMethod method) {
if (hasMapping(needsParamTypes, type, method)) {
return true;
} else {
return previousBundle != null
&& previousBundle.isNeedsParamTypes(type, method);
}
}

public Map<JClassType, Set<JMethod>> getNeedsParamTypes() {
return Collections.unmodifiableMap(needsParamTypes);
}

public void setNeedsProxySupport(JClassType type) {
if (!isNeedsProxySupport(type)) {
needsProxySupport.add(type);
}
}

private boolean isNeedsProxySupport(JClassType type) {
if (needsProxySupport.contains(type)) {
return true;
} else {
return previousBundle != null
&& previousBundle.isNeedsProxySupport(type);
}
}

public Set<JClassType> getNeedsProxySupport() {
return Collections.unmodifiableSet(needsProxySupport);
}

public void setNeedsDelayedInfo(JClassType type, JMethod method) {
if (!isNeedsDelayedInfo(type, method)) {
addMapping(needsDelayedInfo, type, method);
}
}

private boolean isNeedsDelayedInfo(JClassType type, JMethod method) {
if (hasMapping(needsDelayedInfo, type, method)) {
return true;
} else {
return previousBundle != null
&& previousBundle.isNeedsDelayedInfo(type, method);
}
}

public Map<JClassType, Set<JMethod>> getNeedsDelayedInfo() {
return Collections.unmodifiableMap(needsDelayedInfo);
}

public void setNeedsSerialize(JType type) {
if (!hasSserializeSupport(type)) {
needsSerializeSupport.add(type);
}
}

private static Set<Class<?>> frameworkHandledTypes = new HashSet<Class<?>>();
{
frameworkHandledTypes.add(String.class);
frameworkHandledTypes.add(Boolean.class);
frameworkHandledTypes.add(Integer.class);
frameworkHandledTypes.add(Float.class);
frameworkHandledTypes.add(Double.class);
frameworkHandledTypes.add(Long.class);
frameworkHandledTypes.add(Enum.class);
frameworkHandledTypes.add(String[].class);
frameworkHandledTypes.add(Object[].class);
frameworkHandledTypes.add(Map.class);
frameworkHandledTypes.add(List.class);
frameworkHandledTypes.add(Set.class);
frameworkHandledTypes.add(Byte.class);
frameworkHandledTypes.add(Character.class);

}

private boolean serializationHandledByFramework(JType setterType) {
// Some types are handled by the framework at the moment. See #8449
// This method should be removed at some point.
if (setterType.isPrimitive() != null) {
return true;
}

String qualifiedName = setterType.getQualifiedSourceName();
for (Class<?> cls : frameworkHandledTypes) {
if (qualifiedName.equals(cls.getName())) {
return true;
}
}

return false;
}

private boolean hasSserializeSupport(JType type) {
if (hasSerializeSupport.contains(type)) {
return true;
} else {
return previousBundle != null
&& previousBundle.hasSserializeSupport(type);
}
}

public void setNeedsDelegateToWidget(Property property) {
if (!isNeedsDelegateToWidget(property)) {
needsDelegateToWidget.add(property);
}
}

private boolean isNeedsDelegateToWidget(Property property) {
if (needsDelegateToWidget.contains(property)) {
return true;
} else {
return previousBundle != null
&& previousBundle.isNeedsDelegateToWidget(property);
}
}

public Set<Property> getNeedsDelegateToWidget() {
return Collections.unmodifiableSet(needsDelegateToWidget);
}
}

+ 24
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorInitVisitor.java View File

@@ -0,0 +1,24 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.widgetsetutils.metadata;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.vaadin.shared.ui.Connect;

public class ConnectorInitVisitor extends TypeVisitor {

@Override
public void visitConnector(TreeLogger logger, JClassType type,
ConnectorBundle bundle) {
logger.log(Type.INFO, type.getName() + " will be in the "
+ bundle.getName().replaceAll("^_*", "") + " bundle");
Connect connectAnnotation = type.getAnnotation(Connect.class);
bundle.setIdentifier(type, connectAnnotation.value().getCanonicalName());
bundle.setNeedsGwtConstructor(type);
}

}

+ 43
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/CustomSerializer.java View File

@@ -0,0 +1,43 @@
/*
* 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.terminal.gwt.widgetsetutils.metadata;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.user.rebind.SourceWriter;
import com.vaadin.terminal.gwt.widgetsetutils.ConnectorBundleLoaderFactory;

public class CustomSerializer implements GeneratedSerializer {

private final JClassType serializerType;

public CustomSerializer(JClassType serializerType) {
this.serializerType = serializerType;
}

@Override
public void writeSerializerInstantiator(TreeLogger logger, SourceWriter w)
throws UnableToCompleteException {
w.print("return ");
w.print(GWT.class.getCanonicalName());
w.print(".create(");
ConnectorBundleLoaderFactory.writeClassLiteral(w, serializerType);
w.println(");");
}
}

+ 58
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/EnumSerializer.java View File

@@ -0,0 +1,58 @@
/*
* 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.terminal.gwt.widgetsetutils.metadata;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JEnumConstant;
import com.google.gwt.core.ext.typeinfo.JEnumType;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.user.rebind.SourceWriter;

public class EnumSerializer extends JsonSerializer {

private final JEnumType enumType;

public EnumSerializer(JEnumType type) {
super(type);
enumType = type;
}

@Override
protected void printDeserializerBody(TreeLogger logger, SourceWriter w,
String type, String jsonValue, String connection) {
w.println("String enumIdentifier = ((" + JSONString.class.getName()
+ ")" + jsonValue + ").stringValue();");
for (JEnumConstant e : enumType.getEnumConstants()) {
w.println("if (\"" + e.getName() + "\".equals(enumIdentifier)) {");
w.indent();
w.println("return " + enumType.getQualifiedSourceName() + "."
+ e.getName() + ";");
w.outdent();
w.println("}");
}
w.println("return null;");
}

@Override
protected void printSerializerBody(TreeLogger logger, SourceWriter w,
String value, String applicationConnection) {
// return new JSONString(castedValue.name());
w.println("return new " + JSONString.class.getName() + "(" + value
+ ".name());");
}

}

+ 86
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/FieldProperty.java View File

@@ -0,0 +1,86 @@
/*
* 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.terminal.gwt.widgetsetutils.metadata;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JField;
import com.google.gwt.user.rebind.SourceWriter;

public class FieldProperty extends Property {

private final JField field;

private FieldProperty(JClassType beanType, JField field) {
super(field.getName(), beanType, field.getType());
this.field = field;
}

@Override
public void writeSetterBody(TreeLogger logger, SourceWriter w,
String beanVariable, String valueVariable) {
w.print("((%s) %s).%s = (%s)%s;", getBeanType()
.getQualifiedSourceName(), beanVariable, getName(),
getUnboxedPropertyTypeName(), valueVariable);
}

@Override
public void writeGetterBody(TreeLogger logger, SourceWriter w,
String beanVariable) {
w.print("return ((%s) %s).%s;", getBeanType().getQualifiedSourceName(),
beanVariable, getName());
}

public static Collection<FieldProperty> findProperties(JClassType type) {
Collection<FieldProperty> properties = new ArrayList<FieldProperty>();

List<JField> fields = getPublicFields(type);
for (JField field : fields) {
properties.add(new FieldProperty(type, field));
}

return properties;
}

private static List<JField> getPublicFields(JClassType type) {
Set<String> names = new HashSet<String>();
ArrayList<JField> fields = new ArrayList<JField>();
for (JClassType subType : type.getFlattenedSupertypeHierarchy()) {
JField[] subFields = subType.getFields();
for (JField field : subFields) {
if (field.isPublic() && !field.isStatic()
&& names.add(field.getName())) {
fields.add(field);
}
}
}
return fields;
}

@Override
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
return field.getAnnotation(annotationClass);
}

}

client/src/com/vaadin/terminal/gwt/client/communication/GeneratedRpcMethodProvider.java → client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/GeneratedSerializer.java View File

@@ -1,4 +1,4 @@
/*
/*
* Copyright 2011 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
@@ -13,20 +13,14 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.terminal.gwt.client.communication;

import java.util.Collection;
package com.vaadin.terminal.gwt.widgetsetutils.metadata;

/**
* Provides runtime data about client side RPC calls received from the server to
* the client-side code.
*
* A GWT generator is used to create an implementation of this class at
* run-time.
*
* @since 7.0
*/
public interface GeneratedRpcMethodProvider {
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.user.rebind.SourceWriter;

public Collection<RpcMethod> getGeneratedRpcMethods();
public interface GeneratedSerializer {
public void writeSerializerInstantiator(TreeLogger logger, SourceWriter w)
throws UnableToCompleteException;
}

+ 88
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/JsonSerializer.java View File

@@ -0,0 +1,88 @@
/*
* 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.terminal.gwt.widgetsetutils.metadata;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.user.rebind.SourceWriter;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.communication.JSONSerializer;

public abstract class JsonSerializer implements GeneratedSerializer {

private final JType type;

public JsonSerializer(JType type) {
this.type = type;
}

@Override
public void writeSerializerInstantiator(TreeLogger logger, SourceWriter w)
throws UnableToCompleteException {

w.print("return new ");
w.print(JSONSerializer.class.getCanonicalName());
w.print("<");
w.print(type.getQualifiedSourceName());
w.println(">() {");
w.indent();

writeSerializerBody(logger, w);

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

protected void writeSerializerBody(TreeLogger logger, SourceWriter w) {
String qualifiedSourceName = type.getQualifiedSourceName();
w.println("public " + JSONValue.class.getName() + " serialize("
+ qualifiedSourceName + " value, "
+ ApplicationConnection.class.getName() + " connection) {");
w.indent();
// MouseEventDetails castedValue = (MouseEventDetails) value;
w.println(qualifiedSourceName + " castedValue = ("
+ qualifiedSourceName + ") value;");

printSerializerBody(logger, w, "castedValue", "connection");

// End of serializer method
w.outdent();
w.println("}");

// Deserializer
// T deserialize(Type type, JSONValue jsonValue, ApplicationConnection
// connection);
w.println("public " + qualifiedSourceName + " deserialize(Type type, "
+ JSONValue.class.getName() + " jsonValue, "
+ ApplicationConnection.class.getName() + " connection) {");
w.indent();

printDeserializerBody(logger, w, "type", "jsonValue", "connection");

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

protected abstract void printDeserializerBody(TreeLogger logger,
SourceWriter w, String type, String jsonValue, String connection);

protected abstract void printSerializerBody(TreeLogger logger,
SourceWriter w, String value, String applicationConnection);

}

+ 130
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/MethodProperty.java View File

@@ -0,0 +1,130 @@
/*
* 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.terminal.gwt.widgetsetutils.metadata;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.user.rebind.SourceWriter;

public class MethodProperty extends Property {

private final JMethod setter;

private MethodProperty(JClassType beanType, JMethod setter) {
super(getTransportFieldName(setter), beanType, setter
.getParameterTypes()[0]);
this.setter = setter;
}

public static Collection<MethodProperty> findProperties(JClassType type) {
Collection<MethodProperty> properties = new ArrayList<MethodProperty>();

List<JMethod> setters = getSetters(type);
for (JMethod setter : setters) {
properties.add(new MethodProperty(type, setter));
}

return properties;
}

/**
* Returns a list of all setters found in the beanType or its parent class
*
* @param beanType
* The type to check
* @return A list of setter methods from the class and its parents
*/
private static List<JMethod> getSetters(JClassType beanType) {
List<JMethod> setterMethods = new ArrayList<JMethod>();

while (beanType != null
&& !beanType.getQualifiedSourceName().equals(
Object.class.getName())) {
for (JMethod method : beanType.getMethods()) {
// Process all setters that have corresponding fields
if (!method.isPublic() || method.isStatic()
|| !method.getName().startsWith("set")
|| method.getParameterTypes().length != 1) {
// Not setter, skip to next method
continue;
}
setterMethods.add(method);
}
beanType = beanType.getSuperclass();
}

return setterMethods;
}

@Override
public void writeSetterBody(TreeLogger logger, SourceWriter w,
String beanVariable, String valueVariable) {
w.print("((");
w.print(getBeanType().getQualifiedSourceName());
w.print(") ");
w.print(beanVariable);
w.print(").");
w.print(setter.getName());
w.print("((");
w.print(getUnboxedPropertyTypeName());
w.print(") ");
w.print(valueVariable);
w.println(");");
}

@Override
public void writeGetterBody(TreeLogger logger, SourceWriter w,
String beanVariable) {
w.print("return ((");
w.print(getBeanType().getQualifiedSourceName());
w.print(") ");
w.print(beanVariable);
w.print(").");
w.print(findGetter(getBeanType(), setter));
w.print("();");
}

private String findGetter(JClassType beanType, JMethod setterMethod) {
JType setterParameterType = setterMethod.getParameterTypes()[0];
String fieldName = setterMethod.getName().substring(3);
if (setterParameterType.getQualifiedSourceName().equals(
boolean.class.getName())) {
return "is" + fieldName;
} else {
return "get" + fieldName;
}
}

private static String getTransportFieldName(JMethod setter) {
String baseName = setter.getName().substring(3);
return Character.toLowerCase(baseName.charAt(0))
+ baseName.substring(1);
}

@Override
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
return setter.getAnnotation(annotationClass);
}

}

+ 89
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/Property.java View File

@@ -0,0 +1,89 @@
/*
* 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.terminal.gwt.widgetsetutils.metadata;

import java.lang.annotation.Annotation;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.user.rebind.SourceWriter;

public abstract class Property {
private final String name;
private final JClassType beanType;
private final JType propertyType;

protected Property(String name, JClassType beanType, JType propertyType) {
this.name = name;
this.beanType = beanType;
this.propertyType = propertyType;
}

public String getName() {
return name;
}

public JType getPropertyType() {
return propertyType;
}

public String getUnboxedPropertyTypeName() {
JType propertyType = getPropertyType();
JPrimitiveType primitive = propertyType.isPrimitive();
if (primitive != null) {
return primitive.getQualifiedBoxedSourceName();
} else {
return propertyType.getQualifiedSourceName();
}
}

public JClassType getBeanType() {
return beanType;
}

public abstract void writeSetterBody(TreeLogger logger, SourceWriter w,
String beanVariable, String valueVariable);

public abstract void writeGetterBody(TreeLogger logger, SourceWriter w,
String beanVariable);

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj instanceof Property) {
Property other = (Property) obj;
return other.getClass() == getClass()
&& other.getBeanType().equals(getBeanType())
&& other.getName().equals(getName());
} else {
return false;
}
}

@Override
public int hashCode() {
return getClass().hashCode() * 31 ^ 2 + getBeanType().hashCode() * 31
+ getName().hashCode();
}

public abstract <T extends Annotation> T getAnnotation(
Class<T> annotationClass);

}

+ 48
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ServerRpcVisitor.java View File

@@ -0,0 +1,48 @@
/*
* 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.terminal.gwt.widgetsetutils.metadata;

import java.util.Set;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JType;

public class ServerRpcVisitor extends TypeVisitor {
@Override
public void visitServerRpc(TreeLogger logger, JClassType type,
ConnectorBundle bundle) {
bundle.setNeedsProxySupport(type);

Set<? extends JClassType> superTypes = type
.getFlattenedSupertypeHierarchy();
for (JClassType subType : superTypes) {
if (subType.isInterface() != null) {
JMethod[] methods = subType.getMethods();
for (JMethod method : methods) {
bundle.setNeedsDelayedInfo(type, method);

JType[] parameterTypes = method.getParameterTypes();
for (JType paramType : parameterTypes) {
bundle.setNeedsSerialize(paramType);
}
}
}
}
}
}

+ 25
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/StateInitVisitor.java View File

@@ -0,0 +1,25 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.widgetsetutils.metadata;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JType;

public class StateInitVisitor extends TypeVisitor {
@Override
public void visitConnector(TreeLogger logger, JClassType type,
ConnectorBundle bundle) {
JMethod getState = findInheritedMethod(type, "getState");
bundle.setNeedsReturnType(type, getState);

bundle.setNeedsSerialize(getState.getReturnType());

JType stateType = getState.getReturnType();
bundle.setNeedsGwtConstructor(stateType.isClass());
}

}

+ 58
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/TypeVisitor.java View File

@@ -0,0 +1,58 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.widgetsetutils.metadata;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;

public abstract class TypeVisitor {
public void init(TypeOracle oracle) throws NotFoundException {
// Default does nothing
}

public void visitConnector(TreeLogger logger, JClassType type,
ConnectorBundle bundle) throws UnableToCompleteException {
// Default does nothing
}

public void visitClientRpc(TreeLogger logger, JClassType type,
ConnectorBundle bundle) {
// Default does nothing
}

public void visitServerRpc(TreeLogger logger, JClassType type,
ConnectorBundle bundle) {
// Default does nothing
}

protected JMethod findInheritedMethod(JClassType type, String methodName,
JType... params) {

JClassType currentType = type;
while (currentType != null) {
JMethod method = currentType.findMethod(methodName, params);
if (method != null) {
return method;
}
currentType = currentType.getSuperclass();
}

JClassType[] interfaces = type.getImplementedInterfaces();
for (JClassType iface : interfaces) {
JMethod method = iface.findMethod(methodName, params);
if (method != null) {
return method;
}
}

return null;
}

}

+ 73
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/WidgetInitVisitor.java View File

@@ -0,0 +1,73 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.widgetsetutils.metadata;

import java.util.Collection;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.vaadin.shared.annotations.DelegateToWidget;
import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector;

public class WidgetInitVisitor extends TypeVisitor {

@Override
public void visitConnector(TreeLogger logger, JClassType type,
ConnectorBundle bundle) throws UnableToCompleteException {
if (ConnectorBundle.isConnectedComponentConnector(type)) {
JClassType createWidgetClass = findInheritedMethod(type,
"createWidget").getEnclosingType();
boolean createWidgetOverridden = !createWidgetClass
.getQualifiedSourceName()
.equals(AbstractComponentConnector.class.getCanonicalName());
if (createWidgetOverridden) {
// Don't generate if createWidget is already overridden
return;
}

JMethod getWidget = findInheritedMethod(type, "getWidget");
bundle.setNeedsReturnType(type, getWidget);

JClassType widgetType = getWidget.getReturnType().isClass();
bundle.setNeedsGwtConstructor(widgetType);

JMethod getState = findInheritedMethod(type, "getState");
JClassType stateType = getState.getReturnType().isClass();

Collection<Property> properties = bundle.getProperties(stateType);
for (Property property : properties) {
DelegateToWidget delegateToWidget = property
.getAnnotation(DelegateToWidget.class);
if (delegateToWidget != null) {
bundle.setNeedsDelegateToWidget(property);
String methodName = DelegateToWidget.Helper
.getDelegateTarget(property.getName(),
delegateToWidget.value());
JMethod delegatedSetter = findInheritedMethod(widgetType,
methodName, property.getPropertyType());
if (delegatedSetter == null) {
logger.log(
Type.ERROR,
widgetType.getName()
+ "."
+ methodName
+ "("
+ property.getPropertyType()
.getSimpleSourceName()
+ ") required by @DelegateToWidget for "
+ stateType.getName() + "."
+ property.getName()
+ " can not be found.");
throw new UnableToCompleteException();
}
bundle.setNeedsInvoker(widgetType, delegatedSetter);
}
}
}
}
}

+ 2
- 44
client/src/com/vaadin/Vaadin.gwt.xml View File

@@ -23,60 +23,18 @@
<when-type-is class="com.google.gwt.core.client.impl.SchedulerImpl" />
</replace-with>

<!-- Generators for serializators for classes used in communication between
server and client -->
<generate-with
class="com.vaadin.terminal.gwt.widgetsetutils.SerializerMapGenerator">
<when-type-is
class="com.vaadin.terminal.gwt.client.communication.SerializerMap" />
</generate-with>

<replace-with class="com.vaadin.terminal.gwt.client.VDebugConsole">
<when-type-is class="com.vaadin.terminal.gwt.client.Console" />
</replace-with>

<generate-with
class="com.vaadin.terminal.gwt.widgetsetutils.EagerWidgetMapGenerator">
<when-type-is class="com.vaadin.terminal.gwt.client.WidgetMap" />
</generate-with>

<generate-with
class="com.vaadin.terminal.gwt.widgetsetutils.AcceptCriteriaFactoryGenerator">
<when-type-is
class="com.vaadin.terminal.gwt.client.ui.dd.VAcceptCriterionFactory" />
</generate-with>

<!-- Generate client side proxies for client to server RPC interfaces -->
<generate-with
class="com.vaadin.terminal.gwt.widgetsetutils.RpcProxyGenerator">
<when-type-assignable
class="com.vaadin.shared.communication.ServerRpc" />
</generate-with>

<!-- Generate client side proxies for client to server RPC interfaces -->
<generate-with
class="com.vaadin.terminal.gwt.widgetsetutils.RpcProxyCreatorGenerator">
<when-type-assignable
class="com.vaadin.terminal.gwt.client.communication.RpcProxy.RpcProxyCreator" />
</generate-with>

<!-- Generate client side RPC manager for server to client RPC -->
<generate-with
class="com.vaadin.terminal.gwt.widgetsetutils.GeneratedRpcMethodProviderGenerator">
<when-type-assignable
class="com.vaadin.terminal.gwt.client.communication.GeneratedRpcMethodProvider" />
</generate-with>

<generate-with
class="com.vaadin.terminal.gwt.widgetsetutils.ConnectorWidgetFactoryGenerator">
<when-type-assignable
class="com.vaadin.terminal.gwt.client.ui.ConnectorWidgetFactory" />
</generate-with>

<generate-with
class="com.vaadin.terminal.gwt.widgetsetutils.ConnectorStateFactoryGenerator">
<when-type-assignable
class="com.vaadin.terminal.gwt.client.ui.ConnectorStateFactory" />
<generate-with class="com.vaadin.terminal.gwt.widgetsetutils.ConnectorBundleLoaderFactory">
<when-type-assignable class="com.vaadin.terminal.gwt.client.metadata.ConnectorBundleLoader" />
</generate-with>

<!-- Use the new cross site linker to get a nocache.js without document.write -->

+ 54
- 97
client/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java View File

@@ -29,9 +29,13 @@ import com.google.gwt.core.client.JsArrayString;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.terminal.gwt.client.metadata.BundleLoadCallback;
import com.vaadin.terminal.gwt.client.metadata.ConnectorBundleLoader;
import com.vaadin.terminal.gwt.client.metadata.NoDataException;
import com.vaadin.terminal.gwt.client.metadata.TypeData;
import com.vaadin.terminal.gwt.client.ui.UnknownComponentConnector;

public class ApplicationConfiguration implements EntryPoint {
@@ -199,7 +203,7 @@ public class ApplicationConfiguration implements EntryPoint {
private String id;
private String themeUri;
private String appUri;
private int rootId;
private int uiId;
private boolean standalone;
private ErrorMessage communicationError;
private ErrorMessage authorizationError;
@@ -208,7 +212,7 @@ public class ApplicationConfiguration implements EntryPoint {

private HashMap<Integer, String> unknownComponents;

private Class<? extends ServerConnector>[] classes = new Class[1024];
private Map<Integer, Class<? extends ServerConnector>> classes = new HashMap<Integer, Class<? extends ServerConnector>>();

private boolean browserDetailsSent = false;
private boolean widgetsetVersionSent = false;
@@ -282,12 +286,12 @@ public class ApplicationConfiguration implements EntryPoint {
/**
* Gets the root if of this application instance. The root id should be
* included in every request originating from this instance in order to
* associate it with the right Root instance on the server.
* associate it with the right UI instance on the server.
*
* @return the root id
*/
public int getRootId() {
return rootId;
public int getUIId() {
return uiId;
}

/**
@@ -320,7 +324,8 @@ public class ApplicationConfiguration implements EntryPoint {
appUri += '/';
}
themeUri = jsoConfiguration.getConfigString("themeUri");
rootId = jsoConfiguration.getConfigInteger("rootId").intValue();
uiId = jsoConfiguration.getConfigInteger(UIConstants.UI_ID_PARAMETER)
.intValue();

// null -> true
useDebugIdInDom = jsoConfiguration.getConfigBoolean("useDebugIdInDom") != Boolean.FALSE;
@@ -402,12 +407,32 @@ public class ApplicationConfiguration implements EntryPoint {

public Class<? extends ServerConnector> getConnectorClassByEncodedTag(
int tag) {
try {
return classes[tag];
} catch (Exception e) {
// component was not present in mappings
return UnknownComponentConnector.class;
Class<? extends ServerConnector> type = classes.get(tag);
if (type == null && !classes.containsKey(tag)) {
// Initialize if not already loaded
Integer currentTag = Integer.valueOf(tag);
while (type == null && currentTag != null) {
String serverSideClassNameForTag = getServerSideClassNameForTag(currentTag);
if (TypeData.hasIdentifier(serverSideClassNameForTag)) {
try {
type = (Class<? extends ServerConnector>) TypeData
.getClass(serverSideClassNameForTag);
} catch (NoDataException e) {
throw new RuntimeException(e);
}
}
currentTag = getParentTag(currentTag.intValue());
}
if (type == null) {
type = UnknownComponentConnector.class;
if (unknownComponents == null) {
unknownComponents = new HashMap<Integer, String>();
}
unknownComponents.put(tag, getServerSideClassNameForTag(tag));
}
classes.put(tag, type);
}
return type;
}

public void addComponentInheritanceInfo(ValueMap valueMap) {
@@ -430,13 +455,7 @@ public class ApplicationConfiguration implements EntryPoint {
for (int i = 0; i < keyArray.length(); i++) {
String key = keyArray.get(i).intern();
int value = valueMap.getInt(key);
classes[value] = widgetSet.getConnectorClassByTag(value, this);
if (classes[value] == UnknownComponentConnector.class) {
if (unknownComponents == null) {
unknownComponents = new HashMap<Integer, String>();
}
unknownComponents.put(value, key);
}
widgetSet.ensureConnectorLoaded(value, this);
}
}

@@ -478,86 +497,25 @@ public class ApplicationConfiguration implements EntryPoint {
cmd.execute();
}
callbacks.clear();
} else if (dependenciesLoading == 0 && deferredWidgetLoader != null) {
deferredWidgetLoader.trigger();
}

}

/*
* This loop loads widget implementation that should be loaded deferred.
*/
static class DeferredWidgetLoader extends Timer {
private static final int FREE_LIMIT = 4;
private static final int FREE_CHECK_TIMEOUT = 100;

int communicationFree = 0;
int nextWidgetIndex = 0;
private boolean pending;

public DeferredWidgetLoader() {
schedule(5000);
}

public void trigger() {
if (!pending) {
schedule(FREE_CHECK_TIMEOUT);
}
}

@Override
public void schedule(int delayMillis) {
super.schedule(delayMillis);
pending = true;
}

@Override
public void run() {
pending = false;
if (!isBusy()) {
Class<? extends ServerConnector> nextType = getNextType();
if (nextType == null) {
// ensured that all widgets are loaded
deferredWidgetLoader = null;
} else {
communicationFree = 0;
widgetSet.loadImplementation(nextType);
}
} else {
schedule(FREE_CHECK_TIMEOUT);
}
}

private Class<? extends ServerConnector> getNextType() {
Class<? extends ServerConnector>[] deferredLoadedConnectors = widgetSet
.getDeferredLoadedConnectors();
if (deferredLoadedConnectors.length <= nextWidgetIndex) {
return null;
} else {
return deferredLoadedConnectors[nextWidgetIndex++];
}
}

private boolean isBusy() {
if (dependenciesLoading > 0) {
communicationFree = 0;
return true;
}
for (ApplicationConnection app : runningApplications) {
if (app.hasActiveRequest()) {
// if an UIDL request or widget loading is active, mark as
// busy
communicationFree = 0;
return true;
}
}
communicationFree++;
return communicationFree < FREE_LIMIT;
} else if (dependenciesLoading == 0
&& !ConnectorBundleLoader.get().isBundleLoaded(
ConnectorBundleLoader.DEFERRED_BUNDLE_NAME)) {
ConnectorBundleLoader.get().loadBundle(
ConnectorBundleLoader.DEFERRED_BUNDLE_NAME,
new BundleLoadCallback() {
@Override
public void loaded() {
// Nothing to do
}

@Override
public void failed(Throwable reason) {
VConsole.error(reason);
}
});
}
}

private static DeferredWidgetLoader deferredWidgetLoader;

@Override
public void onModuleLoad() {

@@ -594,7 +552,6 @@ public class ApplicationConfiguration implements EntryPoint {
return;
}
registerCallback(GWT.getModuleName());
deferredWidgetLoader = new DeferredWidgetLoader();
}

/**

+ 98
- 59
client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java View File

@@ -58,6 +58,7 @@ 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.ui.ui.UIConstants;
import com.vaadin.terminal.gwt.client.ApplicationConfiguration.ErrorMessage;
import com.vaadin.terminal.gwt.client.ResourceLoader.ResourceLoadEvent;
import com.vaadin.terminal.gwt.client.ResourceLoader.ResourceLoadListener;
@@ -65,16 +66,19 @@ import com.vaadin.terminal.gwt.client.communication.HasJavaScriptConnectorHelper
import com.vaadin.terminal.gwt.client.communication.JsonDecoder;
import com.vaadin.terminal.gwt.client.communication.JsonEncoder;
import com.vaadin.terminal.gwt.client.communication.RpcManager;
import com.vaadin.terminal.gwt.client.communication.SerializerMap;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
import com.vaadin.terminal.gwt.client.communication.Type;
import com.vaadin.terminal.gwt.client.extensions.AbstractExtensionConnector;
import com.vaadin.terminal.gwt.client.metadata.ConnectorBundleLoader;
import com.vaadin.terminal.gwt.client.metadata.NoDataException;
import com.vaadin.terminal.gwt.client.metadata.Property;
import com.vaadin.terminal.gwt.client.metadata.Type;
import com.vaadin.terminal.gwt.client.metadata.TypeData;
import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector;
import com.vaadin.terminal.gwt.client.ui.VContextMenu;
import com.vaadin.terminal.gwt.client.ui.UI.UIConnector;
import com.vaadin.terminal.gwt.client.ui.dd.VDragAndDropManager;
import com.vaadin.terminal.gwt.client.ui.notification.VNotification;
import com.vaadin.terminal.gwt.client.ui.notification.VNotification.HideEvent;
import com.vaadin.terminal.gwt.client.ui.root.RootConnector;
import com.vaadin.terminal.gwt.client.ui.window.WindowConnector;

/**
@@ -105,8 +109,6 @@ public class ApplicationConnection {

public static final char VAR_ESCAPE_CHARACTER = '\u001b';

private static SerializerMap serializerMap;

/**
* A string that, if found in a non-JSON response to a UIDL request, will
* cause the browser to refresh the page. If followed by a colon, optional
@@ -155,7 +157,7 @@ public class ApplicationConnection {
private Timer loadTimer3;
private Element loadElement;

private final RootConnector rootConnector;
private final UIConnector uIConnector;

protected boolean applicationRunning = false;

@@ -207,11 +209,13 @@ public class ApplicationConnection {
}

public ApplicationConnection() {
rootConnector = GWT.create(RootConnector.class);
// Assuming UI data is eagerly loaded
ConnectorBundleLoader.get().loadBundle(
ConnectorBundleLoader.EAGER_BUNDLE_NAME, null);
uIConnector = GWT.create(UIConnector.class);
rpcManager = GWT.create(RpcManager.class);
layoutManager = GWT.create(LayoutManager.class);
layoutManager.setConnection(this);
serializerMap = GWT.create(SerializerMap.class);
}

public void init(WidgetSet widgetSet, ApplicationConfiguration cnf) {
@@ -240,7 +244,7 @@ public class ApplicationConnection {

initializeClientHooks();

rootConnector.init(cnf.getRootPanelId(), this);
uIConnector.init(cnf.getRootPanelId(), this);
showLoadingIndicator();

scheduleHeartbeat();
@@ -397,32 +401,6 @@ public class ApplicationConnection {
}
}-*/;

/**
* Get the active Console for writing debug messages. May return an actual
* logging console, or the NullConsole if debugging is not turned on.
*
* @deprecated Developers should use {@link VConsole} since 6.4.5
*
* @return the active Console
*/
@Deprecated
public static Console getConsole() {
return VConsole.getImplementation();
}

/**
* Checks if client side is in debug mode. Practically this is invoked by
* adding ?debug parameter to URI.
*
* @deprecated use ApplicationConfiguration isDebugMode instead.
*
* @return true if client side is currently been debugged
*/
@Deprecated
public static boolean isDebugMode() {
return ApplicationConfiguration.isDebugMode();
}

/**
* Gets the application base URI. Using this other than as the download
* action URI can cause problems in Portlet 2.0 deployments.
@@ -520,8 +498,8 @@ public class ApplicationConnection {
if (extraParams != null && extraParams.length() > 0) {
uri = addGetParameters(uri, extraParams);
}
uri = addGetParameters(uri, ApplicationConstants.ROOT_ID_PARAMETER
+ "=" + configuration.getRootId());
uri = addGetParameters(uri, UIConstants.UI_ID_PARAMETER + "="
+ configuration.getUIId());

doUidlRequest(uri, payload, forceSync);

@@ -934,7 +912,7 @@ public class ApplicationConnection {
if (loadElement == null) {
loadElement = DOM.createDiv();
DOM.setStyleAttribute(loadElement, "position", "absolute");
DOM.appendChild(rootConnector.getWidget().getElement(), loadElement);
DOM.appendChild(uIConnector.getWidget().getElement(), loadElement);
VConsole.log("inserting load indicator");
}
DOM.setElementProperty(loadElement, "className", "v-loading-indicator");
@@ -1118,7 +1096,7 @@ public class ApplicationConnection {
meta = json.getValueMap("meta");
if (meta.containsKey("repaintAll")) {
repaintAll = true;
rootConnector.getWidget().clear();
uIConnector.getWidget().clear();
getConnectorMap().clear();
if (meta.containsKey("invalidLayouts")) {
validatingLayouts = true;
@@ -1176,6 +1154,8 @@ public class ApplicationConnection {
" * Hierarchy state change event processing completed",
10);

delegateToWidget(pendingStateChangeEvents);

// Fire state change events.
sendStateChangeEvents(pendingStateChangeEvents);

@@ -1292,6 +1272,62 @@ public class ApplicationConnection {

}

private void delegateToWidget(
Collection<StateChangeEvent> pendingStateChangeEvents) {
VConsole.log(" * Running @DelegateToWidget");

for (StateChangeEvent sce : pendingStateChangeEvents) {
ServerConnector connector = sce.getConnector();
if (connector instanceof ComponentConnector) {
ComponentConnector component = (ComponentConnector) connector;
Type type = TypeData.getType(component.getClass());

Type stateType;
try {
stateType = type.getMethod("getState")
.getReturnType();
} catch (NoDataException e) {
throw new RuntimeException(
"Can not find the state type for "
+ type.getSignature(), e);
}

Set<String> changedProperties = sce
.getChangedProperties();
for (String propertyName : changedProperties) {
Property property = stateType
.getProperty(propertyName);
String method = property
.getDelegateToWidgetMethodName();
if (method != null) {
doDelegateToWidget(component, property, method);
}
}

}
}
}

private void doDelegateToWidget(ComponentConnector component,
Property property, String methodName) {
Type type = TypeData.getType(component.getClass());
try {
Type widgetType = type.getMethod("getWidget")
.getReturnType();
Widget widget = component.getWidget();

Object propertyValue = property.getValue(component
.getState());

widgetType.getMethod(methodName).invoke(widget,
propertyValue);
} catch (NoDataException e) {
throw new RuntimeException(
"Missing data needed to invoke @DelegateToWidget for "
+ Util.getSimpleName(component), e);
}
}

/**
* Sends the state change events created while updating the state
* information.
@@ -1328,17 +1364,17 @@ public class ApplicationConnection {
if (!c.getParent().getChildren().contains(c)) {
VConsole.error("ERROR: Connector is connected to a parent but the parent does not contain the connector");
}
} else if ((c instanceof RootConnector && c == getRootConnector())) {
// RootConnector for this connection, leave as-is
} else if ((c instanceof UIConnector && c == getRootConnector())) {
// UIConnector for this connection, leave as-is
} else if (c instanceof WindowConnector
&& getRootConnector().hasSubWindow(
(WindowConnector) c)) {
// Sub window attached to this RootConnector, leave
// Sub window attached to this UIConnector, leave
// as-is
} else {
// The connector has been detached from the
// hierarchy, unregister it and any possible
// children. The RootConnector should never be
// children. The UIConnector should never be
// unregistered even though it has no parent.
connectorMap.unregisterConnector(c);
unregistered++;
@@ -1373,17 +1409,17 @@ public class ApplicationConnection {
.getConnectorClassByEncodedTag(connectorType);

// Connector does not exist so we must create it
if (connectorClass != RootConnector.class) {
if (connectorClass != UIConnector.class) {
// create, initialize and register the paintable
getConnector(connectorId, connectorType);
} else {
// First RootConnector update. Before this the
// RootConnector has been created but not
// First UIConnector update. Before this the
// UIConnector has been created but not
// initialized as the connector id has not been
// known
connectorMap.registerConnector(connectorId,
rootConnector);
rootConnector.doInit(connectorId,
uIConnector);
uIConnector.doInit(connectorId,
ApplicationConnection.this);
}
} catch (final Throwable e) {
@@ -2444,8 +2480,8 @@ public class ApplicationConnection {
*
* @return the main view
*/
public RootConnector getRootConnector() {
return rootConnector;
public UIConnector getRootConnector() {
return uIConnector;
}

/**
@@ -2470,7 +2506,8 @@ public class ApplicationConnection {
* The identifier for the event
* @return true if at least one listener has been registered on server side
* for the event identified by eventIdentifier.
* @deprecated Use {@link ComponentState#hasEventListener(String)} instead
* @deprecated as of Vaadin 7. Use
* {@link ComponentState#hasEventListener(String)} instead
*/
@Deprecated
public boolean hasEventListeners(ComponentConnector paintable,
@@ -2523,11 +2560,13 @@ public class ApplicationConnection {
return connectorMap;
}

/**
* @deprecated No longer needed in Vaadin 7
*/
@Deprecated
public void unregisterPaintable(ServerConnector p) {
System.out.println("unregisterPaintable (unnecessarily) called for "
VConsole.log("unregisterPaintable (unnecessarily) called for "
+ Util.getConnectorString(p));
// connectorMap.unregisterConnector(p);
}

/**
@@ -2566,6 +2605,10 @@ public class ApplicationConnection {
return false;
}

/**
* @deprecated as of Vaadin 7. Use
* {@link ComponentState#hasEventListener(String)} instead
*/
@Deprecated
public boolean hasEventListeners(Widget widget, String eventIdentifier) {
return hasEventListeners(getConnectorMap().getConnector(widget),
@@ -2576,10 +2619,6 @@ public class ApplicationConnection {
return layoutManager;
}

public SerializerMap getSerializerMap() {
return serializerMap;
}

/**
* Schedules a heartbeat request to occur after the configured heartbeat
* interval elapses if the interval is a positive number. Otherwise, does
@@ -2616,8 +2655,8 @@ public class ApplicationConnection {
final String uri = addGetParameters(
translateVaadinUri(ApplicationConstants.APP_PROTOCOL_PREFIX
+ ApplicationConstants.HEARTBEAT_REQUEST_PATH),
ApplicationConstants.ROOT_ID_PARAMETER + "="
+ getConfiguration().getRootId());
UIConstants.UI_ID_PARAMETER + "="
+ getConfiguration().getUIId());

final RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, uri);


+ 2
- 2
client/src/com/vaadin/terminal/gwt/client/ComponentLocator.java View File

@@ -28,9 +28,9 @@ import com.vaadin.shared.ComponentState;
import com.vaadin.shared.Connector;
import com.vaadin.shared.communication.SharedState;
import com.vaadin.terminal.gwt.client.ui.SubPartAware;
import com.vaadin.terminal.gwt.client.ui.UI.VUI;
import com.vaadin.terminal.gwt.client.ui.gridlayout.VGridLayout;
import com.vaadin.terminal.gwt.client.ui.orderedlayout.VMeasuringOrderedLayout;
import com.vaadin.terminal.gwt.client.ui.root.VRoot;
import com.vaadin.terminal.gwt.client.ui.tabsheet.VTabsheetPanel;
import com.vaadin.terminal.gwt.client.ui.window.VWindow;
import com.vaadin.terminal.gwt.client.ui.window.WindowConnector;
@@ -385,7 +385,7 @@ public class ComponentLocator {
return null;
}

if (w instanceof VRoot) {
if (w instanceof VUI) {
return "";
} else if (w instanceof VWindow) {
Connector windowConnector = ConnectorMap.get(client)

+ 10
- 0
client/src/com/vaadin/terminal/gwt/client/ServerConnector.java View File

@@ -22,6 +22,7 @@ import com.google.gwt.event.shared.GwtEvent;
import com.google.web.bindery.event.shared.HandlerRegistration;
import com.vaadin.shared.Connector;
import com.vaadin.shared.communication.ClientRpc;
import com.vaadin.shared.communication.SharedState;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent.StateChangeHandler;

/**
@@ -142,4 +143,13 @@ public interface ServerConnector extends Connector {
public void setChildren(List<ServerConnector> children);

public List<ServerConnector> getChildren();

/**
* Gets the current shared state of the connector.
*
* @since 7.0.
* @return state The shared state object. Can be any sub type of
* {@link SharedState}. Never null.
*/
public SharedState getState();
}

+ 2
- 2
client/src/com/vaadin/terminal/gwt/client/VDebugConsole.java View File

@@ -70,8 +70,8 @@ import com.google.gwt.user.client.ui.Widget;
import com.vaadin.shared.Version;
import com.vaadin.terminal.gwt.client.ui.VLazyExecutor;
import com.vaadin.terminal.gwt.client.ui.VOverlay;
import com.vaadin.terminal.gwt.client.ui.UI.UIConnector;
import com.vaadin.terminal.gwt.client.ui.notification.VNotification;
import com.vaadin.terminal.gwt.client.ui.root.RootConnector;
import com.vaadin.terminal.gwt.client.ui.window.WindowConnector;

/**
@@ -924,7 +924,7 @@ public class VDebugConsole extends VOverlay implements Console {
}

protected void dumpConnectorInfo(ApplicationConnection a) {
RootConnector root = a.getRootConnector();
UIConnector root = a.getRootConnector();
log("================");
log("Connector hierarchy for Root: " + root.getState().getCaption()
+ " (" + root.getConnectorId() + ")");

+ 38
- 27
client/src/com/vaadin/terminal/gwt/client/WidgetSet.java View File

@@ -18,17 +18,13 @@ package com.vaadin.terminal.gwt.client;

import com.google.gwt.core.client.GWT;
import com.vaadin.terminal.gwt.client.communication.HasJavaScriptConnectorHelper;
import com.vaadin.terminal.gwt.client.metadata.BundleLoadCallback;
import com.vaadin.terminal.gwt.client.metadata.ConnectorBundleLoader;
import com.vaadin.terminal.gwt.client.metadata.NoDataException;
import com.vaadin.terminal.gwt.client.metadata.TypeData;
import com.vaadin.terminal.gwt.client.ui.UnknownComponentConnector;

public class WidgetSet {

/**
* WidgetSet (and its extensions) delegate instantiation of widgets and
* client-server matching to WidgetMap. The actual implementations are
* generated with gwts generators/deferred binding.
*/
private WidgetMap widgetMap = GWT.create(WidgetMap.class);

/**
* Create an uninitialized connector that best matches given UIDL. The
* connector must implement {@link ServerConnector}.
@@ -65,12 +61,21 @@ public class WidgetSet {
/*
* let the auto generated code instantiate this type
*/
ServerConnector connector = widgetMap.instantiate(classType);
if (connector instanceof HasJavaScriptConnectorHelper) {
((HasJavaScriptConnectorHelper) connector)
.getJavascriptConnectorHelper().setTag(tag);
try {
ServerConnector connector = (ServerConnector) TypeData.getType(
classType).createInstance();
if (connector instanceof HasJavaScriptConnectorHelper) {
((HasJavaScriptConnectorHelper) connector)
.getJavascriptConnectorHelper().setTag(tag);
}
return connector;
} catch (NoDataException e) {
throw new IllegalStateException(
"There is no information about "
+ classType
+ ". Did you remember to compile the right widgetset?",
e);
}
return connector;
}
}

@@ -102,26 +107,32 @@ public class WidgetSet {
* @param applicationConfiguration
* @return
*/
public Class<? extends ServerConnector> getConnectorClassByTag(int tag,
ApplicationConfiguration conf) {
Class<? extends ServerConnector> connectorClass = null;
public void ensureConnectorLoaded(int tag, ApplicationConfiguration conf) {
ConnectorBundleLoader loader = ConnectorBundleLoader.get();
String bundleName = null;
Integer t = tag;
do {
String serverSideClassName = conf.getServerSideClassNameForTag(t);
connectorClass = widgetMap
.getConnectorClassForServerSideClassName(serverSideClassName);
t = conf.getParentTag(t);
} while (connectorClass == UnknownComponentConnector.class && t != null);
bundleName = loader.getBundleForIdentifier(serverSideClassName);

return connectorClass;
}
t = conf.getParentTag(t);
} while (bundleName == null && t != null);

public Class<? extends ServerConnector>[] getDeferredLoadedConnectors() {
return widgetMap.getDeferredLoadedConnectors();
}
if (bundleName != null && !loader.isBundleLoaded(bundleName)) {
ApplicationConfiguration.startDependencyLoading();
loader.loadBundle(bundleName, new BundleLoadCallback() {
@Override
public void loaded() {
ApplicationConfiguration.endDependencyLoading();
}

public void loadImplementation(Class<? extends ServerConnector> nextType) {
widgetMap.ensureInstantiator(nextType);
@Override
public void failed(Throwable reason) {
VConsole.error(reason);
ApplicationConfiguration.endDependencyLoading();
}
});
}
}

}

+ 1
- 0
client/src/com/vaadin/terminal/gwt/client/communication/DiffJSONSerializer.java View File

@@ -17,6 +17,7 @@ package com.vaadin.terminal.gwt.client.communication;

import com.google.gwt.json.client.JSONValue;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.metadata.Type;

public interface DiffJSONSerializer<T> extends JSONSerializer<T> {
/**

+ 0
- 39
client/src/com/vaadin/terminal/gwt/client/communication/InitializableServerRpc.java View File

@@ -1,39 +0,0 @@
/*
* 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.terminal.gwt.client.communication;

import com.vaadin.shared.communication.ServerRpc;
import com.vaadin.terminal.gwt.client.ServerConnector;

/**
* Initialization support for client to server RPC interfaces.
*
* This is in a separate interface used by the GWT generator class. The init
* method is not in {@link ServerRpc} because then also server side proxies
* would have to implement the initialization method.
*
* @since 7.0
*/
public interface InitializableServerRpc extends ServerRpc {
/**
* Associates the RPC proxy with a connector. Called by generated code.
* Should never be called manually.
*
* @param connector
* The connector the ServerRPC instance is assigned to.
*/
public void initRpc(ServerConnector connector);
}

+ 1
- 0
client/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java View File

@@ -20,6 +20,7 @@ import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONValue;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.ConnectorMap;
import com.vaadin.terminal.gwt.client.metadata.Type;

/**
* Implementors of this interface knows how to serialize an Object of a given

+ 38
- 11
client/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java View File

@@ -31,6 +31,9 @@ import com.google.gwt.json.client.JSONValue;
import com.vaadin.shared.Connector;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.ConnectorMap;
import com.vaadin.terminal.gwt.client.metadata.NoDataException;
import com.vaadin.terminal.gwt.client.metadata.Property;
import com.vaadin.terminal.gwt.client.metadata.Type;

/**
* Client side decoder for decodeing shared state and other values from JSON
@@ -105,18 +108,42 @@ public class JsonDecoder {

private static Object decodeObject(Type type, JSONValue jsonValue,
Object target, ApplicationConnection connection) {
JSONSerializer<Object> serializer = connection.getSerializerMap()
.getSerializer(type.getBaseTypeName());
// TODO handle case with no serializer found
// Currently getSerializer throws exception if not found

if (target != null && serializer instanceof DiffJSONSerializer<?>) {
DiffJSONSerializer<Object> diffSerializer = (DiffJSONSerializer<Object>) serializer;
diffSerializer.update(target, type, jsonValue, connection);
return target;
JSONSerializer<Object> serializer = (JSONSerializer<Object>) type
.findSerializer();
if (serializer != null) {
if (target != null && serializer instanceof DiffJSONSerializer<?>) {
DiffJSONSerializer<Object> diffSerializer = (DiffJSONSerializer<Object>) serializer;
diffSerializer.update(target, type, jsonValue, connection);
return target;
} else {
Object object = serializer.deserialize(type, jsonValue,
connection);
return object;
}
} else {
Object object = serializer.deserialize(type, jsonValue, connection);
return object;
try {
Collection<Property> properties = type.getProperties();
if (target == null) {
target = type.createInstance();
}
JSONObject jsonObject = jsonValue.isObject();

for (Property property : properties) {
JSONValue encodedPropertyValue = jsonObject.get(property
.getName());
if (encodedPropertyValue == null) {
continue;
}
Object propertyReference = property.getValue(target);
Object decodedValue = decodeValue(property.getType(),
encodedPropertyValue, propertyReference, connection);
property.setValue(target, decodedValue);
}
return target;
} catch (NoDataException e) {
throw new RuntimeException("Can not deserialize "
+ type.getSignature(), e);
}
}
}


+ 29
- 5
client/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java View File

@@ -33,6 +33,9 @@ import com.vaadin.shared.Connector;
import com.vaadin.shared.JsonConstants;
import com.vaadin.shared.communication.UidlValue;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.metadata.NoDataException;
import com.vaadin.terminal.gwt.client.metadata.Property;
import com.vaadin.terminal.gwt.client.metadata.Type;

/**
* Encoder for converting RPC parameters and other values to JSON for transfer
@@ -99,12 +102,33 @@ public class JsonEncoder {
} else {
// Try to find a generated serializer object, class name is the
// type
transportType = value.getClass().getName();
JSONSerializer serializer = connection.getSerializerMap()
.getSerializer(transportType);
Type type = new Type(value.getClass());

JSONSerializer<Object> serializer = (JSONSerializer<Object>) type
.findSerializer();
if (serializer != null) {
return serializer.serialize(value, connection);
} else {
try {
Collection<Property> properties = type.getProperties();

JSONObject jsonObject = new JSONObject();
for (Property property : properties) {
Object propertyValue = property.getValue(value);
JSONValue encodedPropertyValue = encode(
propertyValue, restrictToInternalTypes,
connection);
jsonObject.put(property.getName(),
encodedPropertyValue);
}
return jsonObject;

} catch (NoDataException e) {
throw new RuntimeException("Can not encode "
+ type.getSignature(), e);
}
}

// TODO handle case with no serializer found
return serializer.serialize(value, connection);
}
}
}

+ 25
- 29
client/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java View File

@@ -17,10 +17,7 @@
package com.vaadin.terminal.gwt.client.communication;

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

import com.google.gwt.core.client.GWT;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONString;
import com.vaadin.shared.communication.ClientRpc;
@@ -29,6 +26,9 @@ import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.ConnectorMap;
import com.vaadin.terminal.gwt.client.ServerConnector;
import com.vaadin.terminal.gwt.client.VConsole;
import com.vaadin.terminal.gwt.client.metadata.Method;
import com.vaadin.terminal.gwt.client.metadata.NoDataException;
import com.vaadin.terminal.gwt.client.metadata.Type;

/**
* Client side RPC manager that can invoke methods based on RPC calls received
@@ -41,19 +41,6 @@ import com.vaadin.terminal.gwt.client.VConsole;
*/
public class RpcManager {

private final Map<String, RpcMethod> methodMap = new HashMap<String, RpcMethod>();

public RpcManager() {
GeneratedRpcMethodProvider provider = GWT
.create(GeneratedRpcMethodProvider.class);
Collection<RpcMethod> methods = provider.getGeneratedRpcMethods();
for (RpcMethod rpcMethod : methods) {
methodMap.put(
rpcMethod.getInterfaceName() + "."
+ rpcMethod.getMethodName(), rpcMethod);
}
}

/**
* Perform server to client RPC invocation.
*
@@ -62,24 +49,25 @@ public class RpcManager {
*/
public void applyInvocation(MethodInvocation invocation,
ServerConnector connector) {
String signature = getSignature(invocation);
Method method = getMethod(invocation);

RpcMethod rpcMethod = getRpcMethod(signature);
Collection<ClientRpc> implementations = connector
.getRpcImplementations(invocation.getInterfaceName());
for (ClientRpc clientRpc : implementations) {
rpcMethod.applyInvocation(clientRpc, invocation.getParameters());
try {
for (ClientRpc clientRpc : implementations) {
method.invoke(clientRpc, invocation.getParameters());
}
} catch (NoDataException e) {
throw new IllegalStateException("There is no information about "
+ method.getSignature()
+ ". Did you remember to compile the right widgetset?", e);
}
}

private RpcMethod getRpcMethod(String signature) {
RpcMethod rpcMethod = methodMap.get(signature);
if (rpcMethod == null) {
throw new IllegalStateException("There is no information about "
+ signature
+ ". Did you remember to compile the right widgetset?");
}
return rpcMethod;
private Method getMethod(MethodInvocation invocation) {
Type type = new Type(invocation.getInterfaceName(), null);
Method method = type.getMethod(invocation.getMethodName());
return method;
}

private static String getSignature(MethodInvocation invocation) {
@@ -87,7 +75,15 @@ public class RpcManager {
}

public Type[] getParameterTypes(MethodInvocation invocation) {
return getRpcMethod(getSignature(invocation)).getParameterTypes();
Method method = getMethod(invocation);
try {
Type[] parameterTypes = method.getParameterTypes();
return parameterTypes;
} catch (NoDataException e) {
throw new IllegalStateException("There is no information about "
+ method.getSignature()
+ ". Did you remember to compile the right widgetset?", e);
}
}

public void parseAndApplyInvocation(JSONArray rpcCall,

+ 0
- 46
client/src/com/vaadin/terminal/gwt/client/communication/RpcMethod.java View File

@@ -1,46 +0,0 @@
/*
* 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.terminal.gwt.client.communication;

import com.vaadin.shared.communication.ClientRpc;

public abstract class RpcMethod {
private String interfaceName;
private String methodName;
private Type[] parameterTypes;

public RpcMethod(String interfaceName, String methodName,
Type... parameterTypes) {
this.interfaceName = interfaceName;
this.methodName = methodName;
this.parameterTypes = parameterTypes;
}

public String getInterfaceName() {
return interfaceName;
}

public String getMethodName() {
return methodName;
}

public Type[] getParameterTypes() {
return parameterTypes;
}

public abstract void applyInvocation(ClientRpc target, Object... parameters);

}

+ 34
- 17
client/src/com/vaadin/terminal/gwt/client/communication/RpcProxy.java View File

@@ -15,9 +15,13 @@
*/
package com.vaadin.terminal.gwt.client.communication;

import com.google.gwt.core.client.GWT;
import com.vaadin.shared.communication.MethodInvocation;
import com.vaadin.shared.communication.ServerRpc;
import com.vaadin.terminal.gwt.client.ServerConnector;
import com.vaadin.terminal.gwt.client.metadata.InvokationHandler;
import com.vaadin.terminal.gwt.client.metadata.Method;
import com.vaadin.terminal.gwt.client.metadata.NoDataException;
import com.vaadin.terminal.gwt.client.metadata.TypeData;

/**
* Class for creating proxy instances for Client to Server RPC.
@@ -26,25 +30,38 @@ import com.vaadin.terminal.gwt.client.ServerConnector;
*/
public class RpcProxy {

private static RpcProxyCreator impl = GWT.create(RpcProxyCreator.class);

/**
* Create a proxy class for the given Rpc interface and assign it to the
* given connector.
*
* @param rpcInterface
* The rpc interface to construct a proxy for
* @param connector
* The connector this proxy is connected to
* @return A proxy class used for calling Rpc methods.
*/
public static <T extends ServerRpc> T create(Class<T> rpcInterface,
ServerConnector connector) {
return impl.create(rpcInterface, connector);
try {
return (T) TypeData.getType(rpcInterface).createProxy(
new RpcInvokationHandler(rpcInterface, connector));
} catch (NoDataException e) {
throw new IllegalStateException("There is no information about "
+ rpcInterface
+ ". Did you forget to compile the widgetset?");
}
}

public interface RpcProxyCreator {
<T extends ServerRpc> T create(Class<T> rpcInterface,
ServerConnector connector);
private static final class RpcInvokationHandler implements
InvokationHandler {
private final Class<?> rpcInterface;
private final ServerConnector connector;

private RpcInvokationHandler(Class<?> rpcInterface,
ServerConnector connector) {
this.rpcInterface = rpcInterface;
this.connector = connector;
}

@Override
public Object invoke(Object target, Method method, Object[] params) {
MethodInvocation invocation = new MethodInvocation(
connector.getConnectorId(), rpcInterface.getName(),
method.getName(), params);
connector.getConnection().addMethodInvocationToQueue(invocation,
method.isDelayed(), method.isLastonly());
// No RPC iface should have a return value
return null;
}
}
}

+ 0
- 44
client/src/com/vaadin/terminal/gwt/client/communication/SerializerMap.java View File

@@ -1,44 +0,0 @@
/*
* 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.terminal.gwt.client.communication;

/**
* Provide a mapping from a type (communicated between the server and the
* client) and a {@link JSONSerializer} instance.
*
* An implementation of this class is created at GWT compilation time by
* SerializerMapGenerator, so this interface can be instantiated with
* GWT.create().
*
* @since 7.0
*/
public interface SerializerMap {

/**
* Returns a serializer instance for a given type.
*
* @param type
* type communicated on between the server and the client
* (currently fully qualified class name)
* @return serializer instance, not null
* @throws RuntimeException
* if no serializer is found
*/
// TODO better error handling in javadoc and in generator
public JSONSerializer getSerializer(String type);

}

+ 0
- 52
client/src/com/vaadin/terminal/gwt/client/communication/Type.java View File

@@ -1,52 +0,0 @@
/*
* 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.terminal.gwt.client.communication;

public class Type {
private final String baseTypeName;
private final Type[] parameterTypes;

public Type(String baseTypeName, Type[] parameterTypes) {
this.baseTypeName = baseTypeName;
this.parameterTypes = parameterTypes;
}

public String getBaseTypeName() {
return baseTypeName;
}

public Type[] getParameterTypes() {
return parameterTypes;
}

@Override
public String toString() {
String string = baseTypeName;
if (parameterTypes != null) {
string += '<';
for (int i = 0; i < parameterTypes.length; i++) {
if (i != 0) {
string += ',';
}
string += parameterTypes[i].toString();
}
string += '>';
}

return string;
}

}

+ 1
- 0
client/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java View File

@@ -20,6 +20,7 @@ import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONValue;
import com.vaadin.shared.communication.URLReference;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.metadata.Type;

public class URLReference_Serializer implements JSONSerializer<URLReference> {


+ 86
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/AsyncBundleLoader.java View File

@@ -0,0 +1,86 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public abstract class AsyncBundleLoader {
public enum State {
NOT_STARTED, LOADING, LOADED, ERROR;
}

private State state = State.NOT_STARTED;

private Throwable error = null;

private List<BundleLoadCallback> callbacks = new ArrayList<BundleLoadCallback>();

private final String packageName;

private final String[] indentifiers;

public AsyncBundleLoader(String packageName, String[] indentifiers) {
this.packageName = packageName;
this.indentifiers = indentifiers;
}

protected abstract void load(TypeDataStore store);

public List<BundleLoadCallback> setError(Throwable error) {
assert state == State.LOADING;
state = State.ERROR;
this.error = error;

return clearCallbacks();
}

public Throwable getError() {
return error;
}

public State getState() {
return state;
}

public List<BundleLoadCallback> getCallback() {
return Collections.unmodifiableList(callbacks);
}

public void load(BundleLoadCallback callback, TypeDataStore store) {
assert state == State.NOT_STARTED;
state = State.LOADING;
callbacks.add(callback);
load(store);
}

public void addCallback(BundleLoadCallback callback) {
assert state == State.LOADING;
callbacks.add(callback);
}

public List<BundleLoadCallback> setLoaded() {
assert state == State.LOADING;
state = State.LOADED;

return clearCallbacks();
}

private List<BundleLoadCallback> clearCallbacks() {
List<BundleLoadCallback> callbacks = this.callbacks;
this.callbacks = null;
return callbacks;
}

public String getName() {
return packageName;
}

public String[] getIndentifiers() {
return indentifiers;
}

}

+ 11
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/BundleLoadCallback.java View File

@@ -0,0 +1,11 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

public interface BundleLoadCallback {
public void loaded();

public void failed(Throwable reason);
}

+ 99
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/ConnectorBundleLoader.java View File

@@ -0,0 +1,99 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

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

import com.google.gwt.core.shared.GWT;
import com.vaadin.terminal.gwt.client.metadata.AsyncBundleLoader.State;

public abstract class ConnectorBundleLoader {
public static final String EAGER_BUNDLE_NAME = "__eager";
public static final String DEFERRED_BUNDLE_NAME = "__deferred";

private static ConnectorBundleLoader impl;

private Map<String, AsyncBundleLoader> asyncBlockLoaders = new HashMap<String, AsyncBundleLoader>();
private Map<String, String> identifierToBundle = new HashMap<String, String>();

private final TypeDataStore datStore = new TypeDataStore();

public ConnectorBundleLoader() {
init();
}

public TypeDataStore getTypeDataStore() {
return datStore;
}

public static ConnectorBundleLoader get() {
if (impl == null) {
impl = GWT.create(ConnectorBundleLoader.class);
}
return impl;
}

public void loadBundle(String packageName, BundleLoadCallback callback) {
AsyncBundleLoader loader = asyncBlockLoaders.get(packageName);
switch (loader.getState()) {
case NOT_STARTED:
loader.load(callback, getTypeDataStore());
break;
case LOADING:
loader.addCallback(callback);
break;
case LOADED:
callback.loaded();
break;
case ERROR:
callback.failed(loader.getError());
}
}

public boolean isBundleLoaded(String bundleName) {
AsyncBundleLoader loader = asyncBlockLoaders.get(bundleName);
if (loader == null) {
throw new IllegalArgumentException("Bundle " + bundleName
+ " not recognized");
}
return loader.getState() == State.LOADED;
}

public void setLoaded(String packageName) {
List<BundleLoadCallback> callbacks = asyncBlockLoaders.get(packageName)
.setLoaded();
for (BundleLoadCallback callback : callbacks) {
if (callback != null) {
callback.loaded();
}
}
}

public void setLoadFailure(String bundleName, Throwable reason) {
List<BundleLoadCallback> callbacks = asyncBlockLoaders.get(bundleName)
.setError(reason);
for (BundleLoadCallback callback : callbacks) {
callback.failed(reason);
}
}

public String getBundleForIdentifier(String identifier) {
return identifierToBundle.get(identifier);
}

protected void addAsyncBlockLoader(AsyncBundleLoader loader) {
String name = loader.getName();
asyncBlockLoaders.put(name, loader);
String[] indentifiers = loader.getIndentifiers();
for (String identifier : indentifiers) {
identifierToBundle.put(identifier, name);
}
}

public abstract void init();

}

+ 21
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/InvokationHandler.java View File

@@ -0,0 +1,21 @@
/*
* 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.terminal.gwt.client.metadata;

public interface InvokationHandler {
public Object invoke(Object target, Method method, Object[] params);
}

+ 9
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/Invoker.java View File

@@ -0,0 +1,9 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

public interface Invoker {
public Object invoke(Object target, Object... params);
}

+ 71
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/Method.java View File

@@ -0,0 +1,71 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

public class Method {

private final Type type;
private final String name;

public Method(Type type, String name) {
this.type = type;
this.name = name;
}

public Type getType() {
return type;
}

public String getName() {
return name;
}

public Type getReturnType() throws NoDataException {
return TypeDataStore.getReturnType(this);
}

public void invoke(Object target, Object... params) throws NoDataException {
TypeDataStore.getInvoker(this).invoke(target, params);
}

public String getSignature() {
return type.toString() + "." + name;
}

@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj instanceof Method) {
Method other = (Method) obj;
return other.getSignature().equals(getSignature());
} else {
return false;
}
}

@Override
public String toString() {
return getSignature();
}

@Override
public int hashCode() {
return getSignature().hashCode();
}

public Type[] getParameterTypes() throws NoDataException {
return TypeDataStore.getParamTypes(this);
}

public boolean isDelayed() {
return TypeDataStore.isDelayed(this);
}

public boolean isLastonly() {
return TypeDataStore.isLastonly(this);
}

}

+ 25
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/NoDataException.java View File

@@ -0,0 +1,25 @@
/*
* 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.terminal.gwt.client.metadata;

public class NoDataException extends Exception {

public NoDataException(String message) {
super(message);
}

}

+ 69
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/Property.java View File

@@ -0,0 +1,69 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

import com.vaadin.shared.annotations.DelegateToWidget;

public class Property {
private final Type bean;
private final String name;

public Property(Type bean, String name) {
this.bean = bean;
this.name = name;
}

public Object getValue(Object bean) throws NoDataException {
return TypeDataStore.getGetter(this).invoke(bean);
}

public void setValue(Object bean, Object value) throws NoDataException {
TypeDataStore.getSetter(this).invoke(bean, value);
}

public String getDelegateToWidgetMethodName() {
String value = TypeDataStore.getDelegateToWidget(this);
if (value == null) {
return null;
} else {
return DelegateToWidget.Helper.getDelegateTarget(getName(), value);
}
}

public Type getType() throws NoDataException {
return TypeDataStore.getType(this);
}

public String getSignature() {
return bean.toString() + "." + name;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj instanceof Property) {
Property other = (Property) obj;
return getSignature().equals(other.getSignature());
} else {
return false;
}
}

@Override
public int hashCode() {
return getSignature().hashCode();
}

public String getName() {
return name;
}

@Override
public String toString() {
return getSignature();
}

}

+ 23
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/ProxyHandler.java View File

@@ -0,0 +1,23 @@
/*
* 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.terminal.gwt.client.metadata;

public interface ProxyHandler {

Object createProxy(InvokationHandler invokationHandler);

}

+ 97
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/Type.java View File

@@ -0,0 +1,97 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/
package com.vaadin.terminal.gwt.client.metadata;

import java.util.Collection;

import com.vaadin.terminal.gwt.client.communication.JSONSerializer;

public class Type {
private final String name;
private final Type[] parameterTypes;

public Type(Class<?> clazz) {
name = clazz.getName();
parameterTypes = null;
}

public Type(String baseTypeName, Type[] parameterTypes) {
name = baseTypeName;
this.parameterTypes = parameterTypes;
}

public String getBaseTypeName() {
return name;
}

public Type[] getParameterTypes() {
return parameterTypes;
}

public Object createInstance() throws NoDataException {
Invoker invoker = TypeDataStore.getConstructor(this);
return invoker.invoke(null);
}

public Method getMethod(String name) {
return new Method(this, name);
}

public Collection<Property> getProperties() throws NoDataException {
return TypeDataStore.getProperties(this);
}

public Property getProperty(String propertyName) {
return new Property(this, propertyName);
}

public String getSignature() {
String string = name;
if (parameterTypes != null && parameterTypes.length != 0) {
string += '<';
for (int i = 0; i < parameterTypes.length; i++) {
if (i != 0) {
string += ',';
}
string += parameterTypes[i].toString();
}
string += '>';
}

return string;
}

@Override
public String toString() {
return getSignature();
}

@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj instanceof Type) {
Type other = (Type) obj;
return other.getSignature().equals(getSignature());
} else {
return false;
}
}

@Override
public int hashCode() {
return getSignature().hashCode();
}

public Object createProxy(InvokationHandler invokationHandler)
throws NoDataException {
return TypeDataStore.get().getProxyHandler(this)
.createProxy(invokationHandler);
}

public JSONSerializer<?> findSerializer() {
return TypeDataStore.findSerializer(this);
}

}

+ 20
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/TypeData.java View File

@@ -0,0 +1,20 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

public class TypeData {

public static Type getType(Class<?> type) {
return TypeDataStore.getType(type);
}

public static Class<?> getClass(String identifier) throws NoDataException {
return TypeDataStore.getClass(identifier);
}

public static boolean hasIdentifier(String identifier) {
return TypeDataStore.hasIdentifier(identifier);
}
}

+ 33
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataBundle.java View File

@@ -0,0 +1,33 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

import com.google.gwt.core.client.RunAsyncCallback;

public abstract class TypeDataBundle implements RunAsyncCallback {
private final String name;

public TypeDataBundle(String name) {
this.name = name;
}

@Override
public void onSuccess() {
ConnectorBundleLoader loader = ConnectorBundleLoader.get();
load();
loader.setLoaded(getName());
}

@Override
public void onFailure(Throwable reason) {
ConnectorBundleLoader.get().setLoadFailure(getName(), reason);
}

public abstract void load();

public String getName() {
return name;
}
}

+ 226
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataStore.java View File

@@ -0,0 +1,226 @@
/*
@VaadinApache2LicenseForJavaFiles@
*/

package com.vaadin.terminal.gwt.client.metadata;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.vaadin.terminal.gwt.client.communication.JSONSerializer;

public class TypeDataStore {
private static final String CONSTRUCTOR_NAME = "!new";

private final Map<String, Class<?>> identifiers = new HashMap<String, Class<?>>();

private final Map<Type, Invoker> serializerFactories = new HashMap<Type, Invoker>();
private final Map<Type, ProxyHandler> proxyHandlers = new HashMap<Type, ProxyHandler>();
private final Map<Type, Collection<Property>> properties = new HashMap<Type, Collection<Property>>();

private final Set<Method> delayedMethods = new HashSet<Method>();
private final Set<Method> lastonlyMethods = new HashSet<Method>();

private final Map<Method, Type> returnTypes = new HashMap<Method, Type>();
private final Map<Method, Invoker> invokers = new HashMap<Method, Invoker>();
private final Map<Method, Type[]> paramTypes = new HashMap<Method, Type[]>();

private final Map<Property, Type> propertyTypes = new HashMap<Property, Type>();
private final Map<Property, Invoker> setters = new HashMap<Property, Invoker>();
private final Map<Property, Invoker> getters = new HashMap<Property, Invoker>();
private final Map<Property, String> delegateToWidget = new HashMap<Property, String>();

public static TypeDataStore get() {
return ConnectorBundleLoader.get().getTypeDataStore();
}

public void setClass(String identifier, Class<?> type) {
identifiers.put(identifier, type);
}

public static Class<?> getClass(String identifier) throws NoDataException {
Class<?> class1 = get().identifiers.get(identifier);
if (class1 == null) {
throw new NoDataException("There is not class for identifier "
+ identifier);
}
return class1;
}

public static Type getType(Class<?> clazz) {
return new Type(clazz);
}

public static Type getReturnType(Method method) throws NoDataException {
Type type = get().returnTypes.get(method);
if (type == null) {
throw new NoDataException("There is return type for "
+ method.getSignature());
}
return type;
}

public static Invoker getInvoker(Method method) throws NoDataException {
Invoker invoker = get().invokers.get(method);
if (invoker == null) {
throw new NoDataException("There is invoker for "
+ method.getSignature());
}
return invoker;
}

public static Invoker getConstructor(Type type) throws NoDataException {
Invoker invoker = get().invokers
.get(new Method(type, CONSTRUCTOR_NAME));
if (invoker == null) {
throw new NoDataException("There is constructor for "
+ type.getSignature());
}
return invoker;
}

public static Invoker getGetter(Property property) throws NoDataException {
Invoker getter = get().getters.get(property);
if (getter == null) {
throw new NoDataException("There is getter for "
+ property.getSignature());
}

return getter;
}

public void setGetter(Class<?> clazz, String propertyName, Invoker invoker) {
getters.put(new Property(getType(clazz), propertyName), invoker);
}

public static String getDelegateToWidget(Property property) {
return get().delegateToWidget.get(property);
}

public void setDelegateToWidget(Class<?> clazz, String propertyName,
String delegateValue) {
delegateToWidget.put(new Property(getType(clazz), propertyName),
delegateValue);
}

public void setReturnType(Class<?> type, String methodName, Type returnType) {
returnTypes.put(new Method(getType(type), methodName), returnType);
}

public void setConstructor(Class<?> type, Invoker constructor) {
setInvoker(type, CONSTRUCTOR_NAME, constructor);
}

public void setInvoker(Class<?> type, String methodName, Invoker invoker) {
invokers.put(new Method(getType(type), methodName), invoker);
}

public static Type[] getParamTypes(Method method) throws NoDataException {
Type[] types = get().paramTypes.get(method);
if (types == null) {
throw new NoDataException("There are no parameter type data for "
+ method.getSignature());
}
return types;
}

public void setParamTypes(Class<?> type, String methodName,
Type[] paramTypes) {
this.paramTypes.put(new Method(getType(type), methodName), paramTypes);
}

public static boolean hasIdentifier(String identifier) {
return get().identifiers.containsKey(identifier);
}

public static ProxyHandler getProxyHandler(Type type)
throws NoDataException {
ProxyHandler proxyHandler = get().proxyHandlers.get(type);
if (proxyHandler == null) {
throw new NoDataException("No proxy handler for "
+ type.getSignature());
}
return proxyHandler;
}

public void setProxyHandler(Class<?> type, ProxyHandler proxyHandler) {
proxyHandlers.put(getType(type), proxyHandler);
}

public static boolean isDelayed(Method method) {
return get().delayedMethods.contains(method);
}

public void setDelayed(Class<?> type, String methodName) {
delayedMethods.add(getType(type).getMethod(methodName));
}

public static boolean isLastonly(Method method) {
return get().lastonlyMethods.contains(method);
}

public void setLastonly(Class<?> clazz, String methodName) {
lastonlyMethods.add(getType(clazz).getMethod(methodName));
}

public static Collection<Property> getProperties(Type type)
throws NoDataException {
Collection<Property> properties = get().properties.get(type);
if (properties == null) {
throw new NoDataException("No property list for "
+ type.getSignature());
}
return properties;
}

public void setProperties(Class<?> clazz, String[] propertyNames) {
Set<Property> properties = new HashSet<Property>();
Type type = getType(clazz);
for (String name : propertyNames) {
properties.add(new Property(type, name));
}
this.properties.put(type, Collections.unmodifiableSet(properties));
}

public static Type getType(Property property) throws NoDataException {
Type type = get().propertyTypes.get(property);
if (type == null) {
throw new NoDataException("No return type for "
+ property.getSignature());
}
return type;
}

public void setPropertyType(Class<?> clazz, String propertName, Type type) {
propertyTypes.put(new Property(getType(clazz), propertName), type);
}

public static Invoker getSetter(Property property) throws NoDataException {
Invoker setter = get().setters.get(property);
if (setter == null) {
throw new NoDataException("No setter for "
+ property.getSignature());
}
return setter;
}

public void setSetter(Class<?> clazz, String propertyName, Invoker setter) {
setters.put(new Property(getType(clazz), propertyName), setter);
}

public void setSerializerFactory(Class<?> clazz, Invoker factory) {
serializerFactories.put(getType(clazz), factory);
}

public static JSONSerializer<?> findSerializer(Type type) {
Invoker factoryCreator = get().serializerFactories.get(type);
if (factoryCreator == null) {
return null;
}
return (JSONSerializer<?>) factoryCreator.invoke(null);
}
}

+ 18
- 4
client/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java View File

@@ -37,8 +37,11 @@ import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VConsole;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
import com.vaadin.terminal.gwt.client.metadata.NoDataException;
import com.vaadin.terminal.gwt.client.metadata.Type;
import com.vaadin.terminal.gwt.client.metadata.TypeData;
import com.vaadin.terminal.gwt.client.ui.UI.UIConnector;
import com.vaadin.terminal.gwt.client.ui.datefield.PopupDateFieldConnector;
import com.vaadin.terminal.gwt.client.ui.root.RootConnector;

public abstract class AbstractComponentConnector extends AbstractConnector
implements ComponentConnector {
@@ -77,7 +80,18 @@ public abstract class AbstractComponentConnector extends AbstractConnector
* @return
*/
protected Widget createWidget() {
return ConnectorWidgetFactory.createWidget(getClass());
Type type = TypeData.getType(getClass());
try {
Type widgetType = type.getMethod("getWidget").getReturnType();
Object instance = widgetType.createInstance();
return (Widget) instance;
} catch (NoDataException e) {
throw new IllegalStateException(
"There is no information about the widget for "
+ Util.getSimpleName(this)
+ ". Did you remember to compile the right widgetset?",
e);
}
}

/**
@@ -137,7 +151,7 @@ public abstract class AbstractComponentConnector extends AbstractConnector
ServerConnector parent = getParent();
if (parent instanceof ComponentContainerConnector) {
((ComponentContainerConnector) parent).updateCaption(this);
} else if (parent == null && !(this instanceof RootConnector)) {
} else if (parent == null && !(this instanceof UIConnector)) {
VConsole.error("Parent of connector "
+ Util.getConnectorString(this)
+ " is null. This is typically an indication of a broken component hierarchy");
@@ -167,7 +181,7 @@ public abstract class AbstractComponentConnector extends AbstractConnector
ServerConnector parent = getParent();
if (parent instanceof ComponentContainerConnector) {
((ComponentContainerConnector) parent).updateCaption(this);
} else if (parent == null && !(this instanceof RootConnector)) {
} else if (parent == null && !(this instanceof UIConnector)) {
VConsole.error("Parent of connector "
+ Util.getConnectorString(this)
+ " is null. This is typically an indication of a broken component hierarchy");

+ 17
- 1
client/src/com/vaadin/terminal/gwt/client/ui/AbstractConnector.java View File

@@ -33,6 +33,9 @@ import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VConsole;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent.StateChangeHandler;
import com.vaadin.terminal.gwt.client.metadata.NoDataException;
import com.vaadin.terminal.gwt.client.metadata.Type;
import com.vaadin.terminal.gwt.client.metadata.TypeData;

/**
* An abstract implementation of Connector.
@@ -265,7 +268,20 @@ public abstract class AbstractConnector implements ServerConnector,
* @return A new state object
*/
protected SharedState createState() {
return ConnectorStateFactory.createState(getClass());
Type connectorType = TypeData.getType(getClass());
try {
Type stateType = connectorType.getMethod("getState")
.getReturnType();
Object stateInstance = stateType.createInstance();
return (SharedState) stateInstance;
} catch (NoDataException e) {
throw new IllegalStateException(
"There is no information about the state for "
+ Util.getSimpleName(this)
+ ". Did you remember to compile the right widgetset?",
e);
}

}

@Override

+ 0
- 52
client/src/com/vaadin/terminal/gwt/client/ui/ConnectorClassBasedFactory.java View File

@@ -1,52 +0,0 @@
/*
* 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.terminal.gwt.client.ui;

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

import com.vaadin.shared.Connector;

public abstract class ConnectorClassBasedFactory<T> {
public interface Creator<T> {
public T create();
}

private Map<Class<? extends Connector>, Creator<? extends T>> creators = new HashMap<Class<? extends Connector>, Creator<? extends T>>();

protected void addCreator(Class<? extends Connector> cls,
Creator<? extends T> creator) {
creators.put(cls, creator);
}

/**
* Creates a widget using GWT.create for the given connector, based on its
* {@link AbstractComponentConnector#getWidget()} return type.
*
* @param connector
* @return
*/
public T create(Class<? extends Connector> connector) {
Creator<? extends T> foo = creators.get(connector);
if (foo == null) {
throw new RuntimeException(getClass().getName()
+ " could not find a creator for connector of type "
+ connector.getName());
}
return foo.create();
}

}

+ 0
- 43
client/src/com/vaadin/terminal/gwt/client/ui/ConnectorStateFactory.java View File

@@ -1,43 +0,0 @@
/*
* 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.terminal.gwt.client.ui;

import com.google.gwt.core.client.GWT;
import com.vaadin.shared.Connector;
import com.vaadin.shared.communication.SharedState;

public abstract class ConnectorStateFactory extends
ConnectorClassBasedFactory<SharedState> {
private static ConnectorStateFactory impl = null;

/**
* Creates a SharedState using GWT.create for the given connector, based on
* its {@link AbstractComponentConnector#getSharedState ()} return type.
*
* @param connector
* @return
*/
public static SharedState createState(Class<? extends Connector> connector) {
return getImpl().create(connector);
}

private static ConnectorStateFactory getImpl() {
if (impl == null) {
impl = GWT.create(ConnectorStateFactory.class);
}
return impl;
}
}

+ 0
- 55
client/src/com/vaadin/terminal/gwt/client/ui/ConnectorWidgetFactory.java View File

@@ -1,55 +0,0 @@
/*
* 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.terminal.gwt.client.ui;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ui.textfield.TextFieldConnector;
import com.vaadin.terminal.gwt.client.ui.textfield.VTextField;

public abstract class ConnectorWidgetFactory extends
ConnectorClassBasedFactory<Widget> {
private static ConnectorWidgetFactory impl = null;

// TODO Move to generator
{
addCreator(TextFieldConnector.class, new Creator<Widget>() {
@Override
public Widget create() {
return GWT.create(VTextField.class);
}
});
}

/**
* Creates a widget using GWT.create for the given connector, based on its
* {@link AbstractComponentConnector#getWidget()} return type.
*
* @param connector
* @return
*/
public static Widget createWidget(
Class<? extends AbstractComponentConnector> connector) {
return getImpl().create(connector);
}

private static ConnectorWidgetFactory getImpl() {
if (impl == null) {
impl = GWT.create(ConnectorWidgetFactory.class);
}
return impl;
}
}

+ 0
- 3
client/src/com/vaadin/terminal/gwt/client/ui/MediaBaseConnector.java View File

@@ -49,9 +49,6 @@ public abstract class MediaBaseConnector extends AbstractComponentConnector {
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);

getWidget().setControls(getState().isShowControls());
getWidget().setAutoplay(getState().isAutoplay());
getWidget().setMuted(getState().isMuted());
for (int i = 0; i < getState().getSources().size(); i++) {
URLReference source = getState().getSources().get(i);
String sourceType = getState().getSourceTypes().get(i);

client/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java → client/src/com/vaadin/terminal/gwt/client/ui/UI/UIConnector.java View File

@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.terminal.gwt.client.ui.root;
package com.vaadin.terminal.gwt.client.ui.UI;

import java.util.ArrayList;
import java.util.Iterator;
@@ -36,10 +36,10 @@ import com.google.web.bindery.event.shared.HandlerRegistration;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.Connect.LoadStyle;
import com.vaadin.shared.ui.root.PageClientRpc;
import com.vaadin.shared.ui.root.RootConstants;
import com.vaadin.shared.ui.root.RootServerRpc;
import com.vaadin.shared.ui.root.RootState;
import com.vaadin.shared.ui.ui.PageClientRpc;
import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.shared.ui.ui.UIServerRpc;
import com.vaadin.shared.ui.ui.UIState;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.ComponentConnector;
@@ -58,13 +58,13 @@ import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler;
import com.vaadin.terminal.gwt.client.ui.layout.MayScrollChildren;
import com.vaadin.terminal.gwt.client.ui.notification.VNotification;
import com.vaadin.terminal.gwt.client.ui.window.WindowConnector;
import com.vaadin.ui.Root;
import com.vaadin.ui.UI;

@Connect(value = Root.class, loadStyle = LoadStyle.EAGER)
public class RootConnector extends AbstractComponentContainerConnector
@Connect(value = UI.class, loadStyle = LoadStyle.EAGER)
public class UIConnector extends AbstractComponentContainerConnector
implements Paintable, MayScrollChildren {

private RootServerRpc rpc = RpcProxy.create(RootServerRpc.class, this);
private UIServerRpc rpc = RpcProxy.create(UIServerRpc.class, this);

private HandlerRegistration childStateChangeHandlerRegistration;

@@ -107,7 +107,7 @@ public class RootConnector extends AbstractComponentContainerConnector
getWidget().connection = client;

getWidget().immediate = getState().isImmediate();
getWidget().resizeLazy = uidl.hasAttribute(RootConstants.RESIZE_LAZY);
getWidget().resizeLazy = uidl.hasAttribute(UIConstants.RESIZE_LAZY);
String newTheme = uidl.getStringAttribute("theme");
if (getWidget().theme != null && !newTheme.equals(getWidget().theme)) {
// Complete page refresh is needed due css can affect layout
@@ -151,14 +151,14 @@ public class RootConnector extends AbstractComponentContainerConnector
Scheduler.get().scheduleDeferred(new Command() {
@Override
public void execute() {
VRoot.goTo(url);
VUI.goTo(url);
}
});
} else if ("_self".equals(target)) {
// This window is closing (for sure). Only other opens are
// relevant in this change. See #3558, #2144
isClosed = true;
VRoot.goTo(url);
VUI.goTo(url);
} else {
String options;
if (open.hasAttribute("border")) {
@@ -263,9 +263,9 @@ public class RootConnector extends AbstractComponentContainerConnector
scrollIntoView(connector);
}

if (uidl.hasAttribute(RootConstants.FRAGMENT_VARIABLE)) {
if (uidl.hasAttribute(UIConstants.FRAGMENT_VARIABLE)) {
getWidget().currentFragment = uidl
.getStringAttribute(RootConstants.FRAGMENT_VARIABLE);
.getStringAttribute(UIConstants.FRAGMENT_VARIABLE);
if (!getWidget().currentFragment.equals(History.getToken())) {
History.newItem(getWidget().currentFragment, true);
}
@@ -276,7 +276,7 @@ public class RootConnector extends AbstractComponentContainerConnector

// Include current fragment in the next request
client.updateVariable(getWidget().id,
RootConstants.FRAGMENT_VARIABLE,
UIConstants.FRAGMENT_VARIABLE,
getWidget().currentFragment, false);
}

@@ -333,8 +333,8 @@ public class RootConnector extends AbstractComponentContainerConnector
}

@Override
public VRoot getWidget() {
return (VRoot) super.getWidget();
public VUI getWidget() {
return (VUI) super.getWidget();
}

protected ComponentConnector getContent() {
@@ -359,7 +359,7 @@ public class RootConnector extends AbstractComponentContainerConnector
}

/**
* Checks if the given sub window is a child of this Root Connector
* Checks if the given sub window is a child of this UI Connector
*
* @deprecated Should be replaced by a more generic mechanism for getting
* non-ComponentConnector children
@@ -388,8 +388,8 @@ public class RootConnector extends AbstractComponentContainerConnector
}

@Override
public RootState getState() {
return (RootState) super.getState();
public UIState getState() {
return (UIState) super.getState();
}

@Override

client/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java → client/src/com/vaadin/terminal/gwt/client/ui/UI/VUI.java View File

@@ -14,7 +14,7 @@
* the License.
*/

package com.vaadin.terminal.gwt.client.ui.root;
package com.vaadin.terminal.gwt.client.ui.UI;

import java.util.ArrayList;

@@ -33,7 +33,7 @@ import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.SimplePanel;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.ui.root.RootConstants;
import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.ComponentConnector;
@@ -50,7 +50,7 @@ import com.vaadin.terminal.gwt.client.ui.textfield.VTextField;
/**
*
*/
public class VRoot extends SimplePanel implements ResizeHandler,
public class VUI extends SimplePanel implements ResizeHandler,
Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable,
HasResizeHandlers {

@@ -130,7 +130,7 @@ public class VRoot extends SimplePanel implements ResizeHandler,
// Send the new fragment to the server if it has changed
if (!newFragment.equals(currentFragment) && connection != null) {
currentFragment = newFragment;
connection.updateVariable(id, RootConstants.FRAGMENT_VARIABLE,
connection.updateVariable(id, UIConstants.FRAGMENT_VARIABLE,
newFragment, true);
}
}
@@ -146,7 +146,7 @@ public class VRoot extends SimplePanel implements ResizeHandler,

});

public VRoot() {
public VUI() {
super();
setStyleName(CLASSNAME);


+ 1
- 32
client/src/com/vaadin/terminal/gwt/client/ui/dd/DDUtil.java View File

@@ -24,23 +24,6 @@ import com.vaadin.terminal.gwt.client.Util;

public class DDUtil {

/**
* @deprecated use the version with the actual event instead of detected
* clientY value
*
* @param element
* @param clientY
* @param topBottomRatio
* @return
*/
@Deprecated
public static VerticalDropLocation getVerticalDropLocation(Element element,
int clientY, double topBottomRatio) {
int offsetHeight = element.getOffsetHeight();
return getVerticalDropLocation(element, offsetHeight, clientY,
topBottomRatio);
}

public static VerticalDropLocation getVerticalDropLocation(Element element,
NativeEvent event, double topBottomRatio) {
int offsetHeight = element.getOffsetHeight();
@@ -76,21 +59,7 @@ public class DDUtil {

public static HorizontalDropLocation getHorizontalDropLocation(
Element element, NativeEvent event, double leftRightRatio) {
int touchOrMouseClientX = Util.getTouchOrMouseClientX(event);
return getHorizontalDropLocation(element, touchOrMouseClientX,
leftRightRatio);
}

/**
* @deprecated use the version with the actual event
* @param element
* @param clientX
* @param leftRightRatio
* @return
*/
@Deprecated
public static HorizontalDropLocation getHorizontalDropLocation(
Element element, int clientX, double leftRightRatio) {
int clientX = Util.getTouchOrMouseClientX(event);

// Event coordinates are relative to the viewport, element absolute
// position is relative to the document. Make element position relative

+ 0
- 8
client/src/com/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent.java View File

@@ -53,14 +53,6 @@ public class VHtml5DragEvent extends NativeEvent {
return null;
}-*/;

/**
* @deprecated As of Vaadin 6.8, replaced by {@link #setDropEffect(String)}.
*/
@Deprecated
public final void setDragEffect(String effect) {
setDropEffect(effect);
}

public final native void setDropEffect(String effect)
/*-{
try {

+ 38
- 0
client/src/com/vaadin/terminal/gwt/client/ui/embeddedbrowser/EmbeddedBrowserConnector.java View File

@@ -0,0 +1,38 @@
package com.vaadin.terminal.gwt.client.ui.embeddedbrowser;

import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.embeddedbrowser.EmbeddedBrowserState;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector;

@Connect(com.vaadin.ui.EmbeddedBrowser.class)
public class EmbeddedBrowserConnector extends AbstractComponentConnector {

@Override
protected void init() {
super.init();
}

@Override
public VEmbeddedBrowser getWidget() {
return (VEmbeddedBrowser) super.getWidget();
}

@Override
public EmbeddedBrowserState getState() {
return (EmbeddedBrowserState) super.getState();
}

@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {

super.onStateChanged(stateChangeEvent);

getWidget().setAlternateText(getState().getAlternateText());
getWidget().setSource(
getState().getSource() != null ? getState().getSource()
.getURL() : null);
getWidget().setName(getConnectorId());
}

}

+ 120
- 0
client/src/com/vaadin/terminal/gwt/client/ui/embeddedbrowser/VEmbeddedBrowser.java View File

@@ -0,0 +1,120 @@
package com.vaadin.terminal.gwt.client.ui.embeddedbrowser;

import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.IFrameElement;
import com.google.gwt.user.client.ui.Widget;

public class VEmbeddedBrowser extends Widget {

protected IFrameElement iframe;
protected Element altElement;
protected String altText;

public VEmbeddedBrowser() {
Element root = Document.get().createDivElement();
setElement(root);

setStylePrimaryName("v-embeddedbrowser");

createAltTextElement();
}

/**
* Always creates new iframe inside widget. Will replace previous iframe.
*
* @return
*/
protected IFrameElement createIFrameElement(String src) {
String name = null;

// Remove alt text
if (altElement != null) {
getElement().removeChild(altElement);
altElement = null;
}

// Remove old iframe
if (iframe != null) {
name = iframe.getAttribute("name");
getElement().removeChild(iframe);
iframe = null;
}

iframe = Document.get().createIFrameElement();
iframe.setSrc(src);
iframe.setFrameBorder(0);
iframe.setAttribute("width", "100%");
iframe.setAttribute("height", "100%");
iframe.setAttribute("allowTransparency", "true");

getElement().appendChild(iframe);

// Reset old attributes (except src)
if (name != null) {
iframe.setName(name);
}

return iframe;
}

protected void createAltTextElement() {
if (iframe != null) {
return;
}

if (altElement == null) {
altElement = Document.get().createSpanElement();
getElement().appendChild(altElement);
}

if (altText != null) {
altElement.setInnerText(altText);
} else {
altElement.setInnerText("");
}
}

public void setAlternateText(String altText) {
if (this.altText != altText) {
this.altText = altText;
if (altElement != null) {
if (altText != null) {
altElement.setInnerText(altText);
} else {
altElement.setInnerText("");
}
}
}
}

/**
* Set the source (the "src" attribute) of iframe. Will replace old iframe
* with new.
*
* @param source
* Source of iframe.
*/
public void setSource(String source) {

if (source == null) {
if (iframe != null) {
getElement().removeChild(iframe);
iframe = null;
}
createAltTextElement();
setAlternateText(altText);
return;
}

if (iframe == null || iframe.getSrc() != source) {
createIFrameElement(source);
}
}

public void setName(String name) {
if (iframe != null) {
iframe.setName(name);
}
}
}

+ 44
- 0
client/src/com/vaadin/terminal/gwt/client/ui/flash/FlashConnector.java View File

@@ -0,0 +1,44 @@
package com.vaadin.terminal.gwt.client.ui.flash;

import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.flash.FlashState;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector;

@Connect(com.vaadin.ui.Flash.class)
public class FlashConnector extends AbstractComponentConnector {

@Override
protected void init() {
super.init();
}

@Override
public VFlash getWidget() {
return (VFlash) super.getWidget();
}

@Override
public FlashState getState() {
return (FlashState) super.getState();
}

@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {

super.onStateChanged(stateChangeEvent);

getWidget().setSource(
getState().getSource() != null ? getState().getSource()
.getURL() : null);
getWidget().setArchive(getState().getArchive());
getWidget().setClassId(getState().getClassId());
getWidget().setCodebase(getState().getCodebase());
getWidget().setCodetype(getState().getCodetype());
getWidget().setStandby(getState().getStandby());
getWidget().setAlternateText(getState().getAlternateText());
getWidget().setEmbedParams(getState().getEmbedParams());

getWidget().rebuildIfNeeded();
}
}

+ 228
- 0
client/src/com/vaadin/terminal/gwt/client/ui/flash/VFlash.java View File

@@ -0,0 +1,228 @@
package com.vaadin.terminal.gwt.client.ui.flash;

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

import com.google.gwt.user.client.ui.HTML;
import com.vaadin.terminal.gwt.client.Util;

public class VFlash extends HTML {

protected String source;
protected String altText;
protected String classId;
protected String codebase;
protected String codetype;
protected String standby;
protected String archive;
protected Map<String, String> embedParams = new HashMap<String, String>();
protected boolean needsRebuild = false;
protected String width;
protected String height;

public VFlash() {
setStylePrimaryName("v-flash");
}

public void setSource(String source) {
if (this.source != source) {
this.source = source;
needsRebuild = true;
}
}

public void setAlternateText(String altText) {
if (this.altText != altText) {
this.altText = altText;
needsRebuild = true;
}
}

public void setClassId(String classId) {
if (this.classId != classId) {
this.classId = classId;
needsRebuild = true;
}
}

public void setCodebase(String codebase) {
if (this.codebase != codebase) {
this.codebase = codebase;
needsRebuild = true;
}
}

public void setCodetype(String codetype) {
if (this.codetype != codetype) {
this.codetype = codetype;
needsRebuild = true;
}
}

public void setStandby(String standby) {
if (this.standby != standby) {
this.standby = standby;
needsRebuild = true;
}
}

public void setArchive(String archive) {
if (this.archive != archive) {
this.archive = archive;
needsRebuild = true;
}
}

/**
* Call this after changing values of widget. It will rebuild embedding
* structure if needed.
*/
public void rebuildIfNeeded() {
if (needsRebuild) {
needsRebuild = false;
this.setHTML(createFlashEmbed());
}
}

@Override
public void setWidth(String width) {
// super.setWidth(height);

if (this.width != width) {
this.width = width;
needsRebuild = true;
}
}

@Override
public void setHeight(String height) {
// super.setHeight(height);

if (this.height != height) {
this.height = height;
needsRebuild = true;
}
}

public void setEmbedParams(Map<String, String> params) {
if (params == null) {
if (!embedParams.isEmpty()) {
embedParams.clear();
needsRebuild = true;
}
return;
}

if (!embedParams.equals(params)) {
embedParams = new HashMap<String, String>(params);
needsRebuild = true;
}
}

protected String createFlashEmbed() {
/*
* To ensure cross-browser compatibility we are using the twice-cooked
* method to embed flash i.e. we add a OBJECT tag for IE ActiveX and
* inside it a EMBED for all other browsers.
*/

StringBuilder html = new StringBuilder();

// Start the object tag
html.append("<object ");

/*
* Add classid required for ActiveX to recognize the flash. This is a
* predefined value which ActiveX recognizes and must be the given
* value. More info can be found on
* http://kb2.adobe.com/cps/415/tn_4150.html. Allow user to override
* this by setting his own classid.
*/
if (classId != null) {
html.append("classid=\"" + Util.escapeAttribute(classId) + "\" ");
} else {
html.append("classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" ");
}

/*
* Add codebase required for ActiveX and must be exactly this according
* to http://kb2.adobe.com/cps/415/tn_4150.html to work with the above
* given classid. Again, see more info on
* http://kb2.adobe.com/cps/415/tn_4150.html. Limiting Flash version to
* 6.0.0.0 and above. Allow user to override this by setting his own
* codebase
*/
if (codebase != null) {
html.append("codebase=\"" + Util.escapeAttribute(codebase) + "\" ");
} else {
html.append("codebase=\"http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0\" ");
}

// Add width and height
html.append("width=\"" + Util.escapeAttribute(width) + "\" ");
html.append("height=\"" + Util.escapeAttribute(height) + "\" ");
html.append("type=\"application/x-shockwave-flash\" ");

// Codetype
if (codetype != null) {
html.append("codetype=\"" + Util.escapeAttribute(codetype) + "\" ");
}

// Standby
if (standby != null) {
html.append("standby=\"" + Util.escapeAttribute(standby) + "\" ");
}

// Archive
if (archive != null) {
html.append("archive=\"" + Util.escapeAttribute(archive) + "\" ");
}

// End object tag
html.append(">");

// Ensure we have an movie parameter
if (embedParams.get("movie") == null) {
embedParams.put("movie", source);
}

// Add parameters to OBJECT
for (String name : embedParams.keySet()) {
html.append("<param ");
html.append("name=\"" + Util.escapeAttribute(name) + "\" ");
html.append("value=\""
+ Util.escapeAttribute(embedParams.get(name)) + "\" ");
html.append("/>");
}

// Build inner EMBED tag
html.append("<embed ");
html.append("src=\"" + Util.escapeAttribute(source) + "\" ");
html.append("width=\"" + Util.escapeAttribute(width) + "\" ");
html.append("height=\"" + Util.escapeAttribute(height) + "\" ");
html.append("type=\"application/x-shockwave-flash\" ");

// Add the parameters to the Embed
for (String name : embedParams.keySet()) {
html.append(Util.escapeAttribute(name));
html.append("=");
html.append("\"" + Util.escapeAttribute(embedParams.get(name))
+ "\"");
}

// End embed tag
html.append("></embed>");

if (altText != null) {
html.append("<noembed>");
html.append(altText);
html.append("</noembed>");
}

// End object tag
html.append("</object>");

return html.toString();
}

}

+ 67
- 0
client/src/com/vaadin/terminal/gwt/client/ui/image/ImageConnector.java View File

@@ -0,0 +1,67 @@
package com.vaadin.terminal.gwt.client.ui.image;

import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.LoadEvent;
import com.google.gwt.event.dom.client.LoadHandler;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.image.ImageServerRpc;
import com.vaadin.shared.ui.image.ImageState;
import com.vaadin.terminal.gwt.client.communication.RpcProxy;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector;
import com.vaadin.terminal.gwt.client.ui.ClickEventHandler;

@Connect(com.vaadin.ui.Image.class)
public class ImageConnector extends AbstractComponentConnector {

ImageServerRpc rpc;

@Override
protected void init() {
super.init();
rpc = RpcProxy.create(ImageServerRpc.class, this);
getWidget().addHandler(new LoadHandler() {

@Override
public void onLoad(LoadEvent event) {
getLayoutManager().setNeedsMeasure(ImageConnector.this);
}

}, LoadEvent.getType());
}

@Override
public VImage getWidget() {
return (VImage) super.getWidget();
}

@Override
public ImageState getState() {
return (ImageState) super.getState();
}

@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);

clickEventHandler.handleEventHandlerRegistration();

getWidget().setUrl(
getState().getSource() != null ? getState().getSource()
.getURL() : null);
getWidget().setAltText(getState().getAlternateText());
}

protected final ClickEventHandler clickEventHandler = new ClickEventHandler(
this) {

@Override
protected void fireClick(NativeEvent event,
MouseEventDetails mouseDetails) {
rpc.click(mouseDetails);
}

};

}

+ 10
- 0
client/src/com/vaadin/terminal/gwt/client/ui/image/VImage.java View File

@@ -0,0 +1,10 @@
package com.vaadin.terminal.gwt.client.ui.image;

import com.google.gwt.user.client.ui.Image;

public class VImage extends Image {

public VImage() {
setStylePrimaryName("v-image");
}
}

+ 4
- 4
client/src/com/vaadin/terminal/gwt/client/ui/label/LabelConnector.java View File

@@ -43,10 +43,10 @@ public class LabelConnector extends AbstractComponentConnector {
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);
boolean sinkOnloads = false;
switch (getState().getContentMode()) {
switch (getState().contentMode) {
case PREFORMATTED:
PreElement preElement = Document.get().createPreElement();
preElement.setInnerText(getState().getText());
preElement.setInnerText(getState().text);
// clear existing content
getWidget().setHTML("");
// add preformatted text to dom
@@ -54,14 +54,14 @@ public class LabelConnector extends AbstractComponentConnector {
break;

case TEXT:
getWidget().setText(getState().getText());
getWidget().setText(getState().text);
break;

case XHTML:
case RAW:
sinkOnloads = true;
case XML:
getWidget().setHTML(getState().getText());
getWidget().setHTML(getState().text);
break;
default:
getWidget().setText("");

+ 32
- 28
client/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java View File

@@ -29,7 +29,8 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.shared.ui.root.RootConstants;
import com.vaadin.shared.Position;
import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.UIDL;
@@ -38,13 +39,13 @@ import com.vaadin.terminal.gwt.client.ui.VOverlay;

public class VNotification extends VOverlay {

public static final int CENTERED = 1;
public static final int CENTERED_TOP = 2;
public static final int CENTERED_BOTTOM = 3;
public static final int TOP_LEFT = 4;
public static final int TOP_RIGHT = 5;
public static final int BOTTOM_LEFT = 6;
public static final int BOTTOM_RIGHT = 7;
public static final Position CENTERED = Position.MIDDLE_CENTER;
public static final Position CENTERED_TOP = Position.TOP_CENTER;
public static final Position CENTERED_BOTTOM = Position.BOTTOM_CENTER;
public static final Position TOP_LEFT = Position.TOP_LEFT;
public static final Position TOP_RIGHT = Position.TOP_RIGHT;
public static final Position BOTTOM_LEFT = Position.BOTTOM_LEFT;
public static final Position BOTTOM_RIGHT = Position.BOTTOM_RIGHT;

public static final int DELAY_FOREVER = -1;
public static final int DELAY_NONE = 0;
@@ -144,21 +145,21 @@ public class VNotification extends VOverlay {
show(CENTERED, style);
}

public void show(int position) {
public void show(com.vaadin.shared.Position position) {
show(position, null);
}

public void show(Widget widget, int position, String style) {
public void show(Widget widget, Position position, String style) {
setWidget(widget);
show(position, style);
}

public void show(String html, int position, String style) {
public void show(String html, Position position, String style) {
setWidget(new HTML(html));
show(position, style);
}

public void show(int position, String style) {
public void show(Position position, String style) {
setOpacity(getElement(), startOpacity);
if (style != null) {
temporaryStyle = style;
@@ -231,7 +232,7 @@ public class VNotification extends VOverlay {
}
}

public void setPosition(int position) {
public void setPosition(com.vaadin.shared.Position position) {
final Element el = getElement();
DOM.setStyleAttribute(el, "top", "");
DOM.setStyleAttribute(el, "left", "");
@@ -260,17 +261,17 @@ public class VNotification extends VOverlay {
DOM.setStyleAttribute(el, "bottom", "0px");
DOM.setStyleAttribute(el, "left", "0px");
break;
case CENTERED_TOP:
case TOP_CENTER:
center();
DOM.setStyleAttribute(el, "top", "0px");
break;
case CENTERED_BOTTOM:
case BOTTOM_CENTER:
center();
DOM.setStyleAttribute(el, "top", "");
DOM.setStyleAttribute(el, "bottom", "0px");
break;
default:
case CENTERED:
case MIDDLE_CENTER:
center();
break;
}
@@ -383,19 +384,19 @@ public class VNotification extends VOverlay {
public static void showNotification(ApplicationConnection client,
final UIDL notification) {
boolean onlyPlainText = notification
.hasAttribute(RootConstants.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED);
.hasAttribute(UIConstants.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED);
String html = "";
if (notification
.hasAttribute(RootConstants.ATTRIBUTE_NOTIFICATION_ICON)) {
.hasAttribute(UIConstants.ATTRIBUTE_NOTIFICATION_ICON)) {
final String parsedUri = client
.translateVaadinUri(notification
.getStringAttribute(RootConstants.ATTRIBUTE_NOTIFICATION_ICON));
.getStringAttribute(UIConstants.ATTRIBUTE_NOTIFICATION_ICON));
html += "<img src=\"" + Util.escapeAttribute(parsedUri) + "\" />";
}
if (notification
.hasAttribute(RootConstants.ATTRIBUTE_NOTIFICATION_CAPTION)) {
.hasAttribute(UIConstants.ATTRIBUTE_NOTIFICATION_CAPTION)) {
String caption = notification
.getStringAttribute(RootConstants.ATTRIBUTE_NOTIFICATION_CAPTION);
.getStringAttribute(UIConstants.ATTRIBUTE_NOTIFICATION_CAPTION);
if (onlyPlainText) {
caption = Util.escapeHTML(caption);
caption = caption.replaceAll("\\n", "<br />");
@@ -403,9 +404,9 @@ public class VNotification extends VOverlay {
html += "<h1>" + caption + "</h1>";
}
if (notification
.hasAttribute(RootConstants.ATTRIBUTE_NOTIFICATION_MESSAGE)) {
.hasAttribute(UIConstants.ATTRIBUTE_NOTIFICATION_MESSAGE)) {
String message = notification
.getStringAttribute(RootConstants.ATTRIBUTE_NOTIFICATION_MESSAGE);
.getStringAttribute(UIConstants.ATTRIBUTE_NOTIFICATION_MESSAGE);
if (onlyPlainText) {
message = Util.escapeHTML(message);
message = message.replaceAll("\\n", "<br />");
@@ -414,13 +415,16 @@ public class VNotification extends VOverlay {
}

final String style = notification
.hasAttribute(RootConstants.ATTRIBUTE_NOTIFICATION_STYLE) ? notification
.getStringAttribute(RootConstants.ATTRIBUTE_NOTIFICATION_STYLE)
.hasAttribute(UIConstants.ATTRIBUTE_NOTIFICATION_STYLE) ? notification
.getStringAttribute(UIConstants.ATTRIBUTE_NOTIFICATION_STYLE)
: null;
final int position = notification
.getIntAttribute(RootConstants.ATTRIBUTE_NOTIFICATION_POSITION);

final int pos = notification
.getIntAttribute(UIConstants.ATTRIBUTE_NOTIFICATION_POSITION);
Position position = Position.values()[pos];

final int delay = notification
.getIntAttribute(RootConstants.ATTRIBUTE_NOTIFICATION_DELAY);
.getIntAttribute(UIConstants.ATTRIBUTE_NOTIFICATION_DELAY);
createNotification(delay).show(html, position, style);
}


+ 40
- 49
client/src/com/vaadin/terminal/gwt/client/ui/slider/SliderConnector.java View File

@@ -15,70 +15,61 @@
*/
package com.vaadin.terminal.gwt.client.ui.slider;

import com.google.gwt.core.client.Scheduler;
import com.google.gwt.user.client.Command;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.vaadin.shared.ui.Connect;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.shared.ui.slider.SliderServerRpc;
import com.vaadin.shared.ui.slider.SliderState;
import com.vaadin.terminal.gwt.client.communication.RpcProxy;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
import com.vaadin.terminal.gwt.client.ui.AbstractFieldConnector;
import com.vaadin.ui.Slider;

@Connect(Slider.class)
public class SliderConnector extends AbstractFieldConnector implements
Paintable {
ValueChangeHandler<Double> {

@Override
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {

getWidget().client = client;
getWidget().id = uidl.getId();

if (!isRealUpdate(uidl)) {
return;
}
protected SliderServerRpc rpc = RpcProxy
.create(SliderServerRpc.class, this);

getWidget().immediate = getState().isImmediate();
getWidget().disabled = !isEnabled();
getWidget().readonly = isReadOnly();
@Override
public void init() {
super.init();
getWidget().setConnection(getConnection());
getWidget().addValueChangeHandler(this);
}

getWidget().vertical = uidl.hasAttribute("vertical");
@Override
public VSlider getWidget() {
return (VSlider) super.getWidget();
}

// TODO should style names be used?
@Override
public SliderState getState() {
return (SliderState) super.getState();
}

if (getWidget().vertical) {
getWidget().addStyleName(VSlider.CLASSNAME + "-vertical");
} else {
getWidget().removeStyleName(VSlider.CLASSNAME + "-vertical");
}
@Override
public void onValueChange(ValueChangeEvent<Double> event) {
rpc.valueChanged(event.getValue());
}

getWidget().min = uidl.getDoubleAttribute("min");
getWidget().max = uidl.getDoubleAttribute("max");
getWidget().resolution = uidl.getIntAttribute("resolution");
getWidget().value = new Double(uidl.getDoubleVariable("value"));
@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);

getWidget().setFeedbackValue(getWidget().value);
getWidget().setId(getConnectorId());
getWidget().setImmediate(getState().isImmediate());
getWidget().setDisabled(!isEnabled());
getWidget().setReadOnly(isReadOnly());
getWidget().setOrientation(getState().getOrientation());
getWidget().setMinValue(getState().getMinValue());
getWidget().setMaxValue(getState().getMaxValue());
getWidget().setResolution(getState().getResolution());
getWidget().setValue(getState().getValue(), false);
getWidget().setFeedbackValue(getState().getValue());

getWidget().buildBase();

if (!getWidget().vertical) {
// Draw handle with a delay to allow base to gain maximum width
Scheduler.get().scheduleDeferred(new Command() {
@Override
public void execute() {
getWidget().buildHandle();
getWidget().setValue(getWidget().value, false);
}
});
} else {
getWidget().buildHandle();
getWidget().setValue(getWidget().value, false);
}
}

@Override
public VSlider getWidget() {
return (VSlider) super.getWidget();
}

}

+ 168
- 83
client/src/com/vaadin/terminal/gwt/client/ui/slider/VSlider.java View File

@@ -19,12 +19,17 @@ package com.vaadin.terminal.gwt.client.ui.slider;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasValue;
import com.vaadin.shared.ui.slider.SliderOrientation;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.ContainerResizedListener;
@@ -36,7 +41,7 @@ import com.vaadin.terminal.gwt.client.ui.VLazyExecutor;
import com.vaadin.terminal.gwt.client.ui.VOverlay;

public class VSlider extends SimpleFocusablePanel implements Field,
ContainerResizedListener {
ContainerResizedListener, HasValue<Double> {

public static final String CLASSNAME = "v-slider";

@@ -46,20 +51,22 @@ public class VSlider extends SimpleFocusablePanel implements Field,
*/
private static final int MIN_SIZE = 50;

ApplicationConnection client;
protected ApplicationConnection client;

String id;
protected String id;

boolean immediate;
boolean disabled;
boolean readonly;
protected boolean immediate;
protected boolean disabled;
protected boolean readonly;

private int acceleration = 1;
double min;
double max;
int resolution;
Double value;
boolean vertical;
protected double min;
protected double max;
protected int resolution;
protected Double value;
protected SliderOrientation orientation = SliderOrientation.HORIZONTAL;

private boolean valueChangeHandlerInitialized = false;

private final HTML feedback = new HTML("", false);
private final VOverlay feedbackPopup = new VOverlay(true, false, true) {
@@ -92,7 +99,7 @@ public class VSlider extends SimpleFocusablePanel implements Field,

@Override
public void execute() {
updateValueToServer();
fireValueChanged();
acceleration = 1;
}
});
@@ -137,7 +144,7 @@ public class VSlider extends SimpleFocusablePanel implements Field,
}

private void updateFeedbackPosition() {
if (vertical) {
if (isVertical()) {
feedbackPopup.setPopupPosition(
DOM.getAbsoluteLeft(handle) + handle.getOffsetWidth(),
DOM.getAbsoluteTop(handle) + handle.getOffsetHeight() / 2
@@ -152,16 +159,17 @@ public class VSlider extends SimpleFocusablePanel implements Field,
}

void buildBase() {
final String styleAttribute = vertical ? "height" : "width";
final String oppositeStyleAttribute = vertical ? "width" : "height";
final String domProperty = vertical ? "offsetHeight" : "offsetWidth";
final String styleAttribute = isVertical() ? "height" : "width";
final String oppositeStyleAttribute = isVertical() ? "width" : "height";
final String domProperty = isVertical() ? "offsetHeight"
: "offsetWidth";

// clear unnecessary opposite style attribute
DOM.setStyleAttribute(base, oppositeStyleAttribute, "");

final Element p = DOM.getParent(getElement());
if (DOM.getElementPropertyInt(p, domProperty) > 50) {
if (vertical) {
if (isVertical()) {
setHeight();
} else {
DOM.setStyleAttribute(base, styleAttribute, "");
@@ -176,7 +184,7 @@ public class VSlider extends SimpleFocusablePanel implements Field,
public void execute() {
final Element p = DOM.getParent(getElement());
if (DOM.getElementPropertyInt(p, domProperty) > (MIN_SIZE + 5)) {
if (vertical) {
if (isVertical()) {
setHeight();
} else {
DOM.setStyleAttribute(base, styleAttribute, "");
@@ -188,12 +196,27 @@ public class VSlider extends SimpleFocusablePanel implements Field,
});
}

if (!isVertical()) {
// Draw handle with a delay to allow base to gain maximum width
Scheduler.get().scheduleDeferred(new Command() {
@Override
public void execute() {
buildHandle();
setValue(value, false);
}
});
} else {
buildHandle();
setValue(value, false);
}

// TODO attach listeners for focusing and arrow keys
}

void buildHandle() {
final String handleAttribute = vertical ? "marginTop" : "marginLeft";
final String oppositeHandleAttribute = vertical ? "marginLeft"
final String handleAttribute = isVertical() ? "marginTop"
: "marginLeft";
final String oppositeHandleAttribute = isVertical() ? "marginLeft"
: "marginTop";

DOM.setStyleAttribute(handle, handleAttribute, "0");
@@ -206,59 +229,6 @@ public class VSlider extends SimpleFocusablePanel implements Field,

}

void setValue(Double value, boolean updateToServer) {
if (value == null) {
return;
}

if (value < min) {
value = min;
} else if (value > max) {
value = max;
}

// Update handle position
final String styleAttribute = vertical ? "marginTop" : "marginLeft";
final String domProperty = vertical ? "offsetHeight" : "offsetWidth";
final int handleSize = Integer.parseInt(DOM.getElementProperty(handle,
domProperty));
final int baseSize = Integer.parseInt(DOM.getElementProperty(base,
domProperty)) - (2 * BASE_BORDER_WIDTH);

final int range = baseSize - handleSize;
double v = value.doubleValue();

// Round value to resolution
if (resolution > 0) {
v = Math.round(v * Math.pow(10, resolution));
v = v / Math.pow(10, resolution);
} else {
v = Math.round(v);
}
final double valueRange = max - min;
double p = 0;
if (valueRange > 0) {
p = range * ((v - min) / valueRange);
}
if (p < 0) {
p = 0;
}
if (vertical) {
p = range - p;
}
final double pos = p;

DOM.setStyleAttribute(handle, styleAttribute, (Math.round(pos)) + "px");

// Update value
this.value = new Double(v);
setFeedbackValue(v);

if (updateToServer) {
updateValueToServer();
}
}

@Override
public void onBrowserEvent(Event event) {
if (disabled || readonly) {
@@ -386,7 +356,7 @@ public class VSlider extends SimpleFocusablePanel implements Field,
final int coord = getEventPosition(event);

final int handleSize, baseSize, baseOffset;
if (vertical) {
if (isVertical()) {
handleSize = handle.getOffsetHeight();
baseSize = base.getOffsetHeight();
baseOffset = base.getAbsoluteTop() - Window.getScrollTop()
@@ -398,7 +368,7 @@ public class VSlider extends SimpleFocusablePanel implements Field,
+ handleSize / 2;
}

if (vertical) {
if (isVertical()) {
v = ((baseSize - (coord - baseOffset)) / (double) (baseSize - handleSize))
* (max - min) + min;
} else {
@@ -423,7 +393,7 @@ public class VSlider extends SimpleFocusablePanel implements Field,
* @return
*/
protected int getEventPosition(Event event) {
if (vertical) {
if (isVertical()) {
return Util.getTouchOrMouseClientY(event);
} else {
return Util.getTouchOrMouseClientX(event);
@@ -432,7 +402,7 @@ public class VSlider extends SimpleFocusablePanel implements Field,

@Override
public void iLayout() {
if (vertical) {
if (isVertical()) {
setHeight();
}
// Update handle position
@@ -451,8 +421,8 @@ public class VSlider extends SimpleFocusablePanel implements Field,
DOM.setStyleAttribute(base, "overflow", "");
}

private void updateValueToServer() {
client.updateVariable(id, "value", value.doubleValue(), immediate);
private void fireValueChanged() {
ValueChangeEvent.fire(VSlider.this, value);
}

/**
@@ -469,8 +439,8 @@ public class VSlider extends SimpleFocusablePanel implements Field,
return false;
}

if ((keycode == getNavigationUpKey() && vertical)
|| (keycode == getNavigationRightKey() && !vertical)) {
if ((keycode == getNavigationUpKey() && isVertical())
|| (keycode == getNavigationRightKey() && !isVertical())) {
if (shift) {
for (int a = 0; a < acceleration; a++) {
increaseValue(false);
@@ -480,8 +450,8 @@ public class VSlider extends SimpleFocusablePanel implements Field,
increaseValue(false);
}
return true;
} else if (keycode == getNavigationDownKey() && vertical
|| (keycode == getNavigationLeftKey() && !vertical)) {
} else if (keycode == getNavigationDownKey() && isVertical()
|| (keycode == getNavigationLeftKey() && !isVertical())) {
if (shift) {
for (int a = 0; a < acceleration; a++) {
decreaseValue(false);
@@ -539,4 +509,119 @@ public class VSlider extends SimpleFocusablePanel implements Field,
protected int getNavigationRightKey() {
return KeyCodes.KEY_RIGHT;
}

public void setConnection(ApplicationConnection client) {
this.client = client;
}

public void setId(String id) {
this.id = id;
}

public void setImmediate(boolean immediate) {
this.immediate = immediate;
}

public void setDisabled(boolean disabled) {
this.disabled = disabled;
}

public void setReadOnly(boolean readonly) {
this.readonly = readonly;
}

private boolean isVertical() {
return orientation == SliderOrientation.VERTICAL;
}

public void setOrientation(SliderOrientation orientation) {
if (this.orientation != orientation) {
this.orientation = orientation;

if (isVertical()) {
addStyleName(VSlider.CLASSNAME + "-vertical");
} else {
removeStyleName(VSlider.CLASSNAME + "-vertical");
}
}
}

public void setMinValue(double value) {
min = value;
}

public void setMaxValue(double value) {
max = value;
}

public void setResolution(int resolution) {
this.resolution = resolution;
}

public HandlerRegistration addValueChangeHandler(
ValueChangeHandler<Double> handler) {
return addHandler(handler, ValueChangeEvent.getType());
}

public Double getValue() {
return value;
}

public void setValue(Double value) {
if (value < min) {
value = min;
} else if (value > max) {
value = max;
}

// Update handle position
final String styleAttribute = isVertical() ? "marginTop" : "marginLeft";
final String domProperty = isVertical() ? "offsetHeight"
: "offsetWidth";
final int handleSize = Integer.parseInt(DOM.getElementProperty(handle,
domProperty));
final int baseSize = Integer.parseInt(DOM.getElementProperty(base,
domProperty)) - (2 * BASE_BORDER_WIDTH);

final int range = baseSize - handleSize;
double v = value.doubleValue();

// Round value to resolution
if (resolution > 0) {
v = Math.round(v * Math.pow(10, resolution));
v = v / Math.pow(10, resolution);
} else {
v = Math.round(v);
}
final double valueRange = max - min;
double p = 0;
if (valueRange > 0) {
p = range * ((v - min) / valueRange);
}
if (p < 0) {
p = 0;
}
if (isVertical()) {
p = range - p;
}
final double pos = p;

DOM.setStyleAttribute(handle, styleAttribute, (Math.round(pos)) + "px");

// Update value
this.value = new Double(v);
setFeedbackValue(v);
}

public void setValue(Double value, boolean fireEvents) {
if (value == null) {
return;
}

setValue(value);

if (fireEvents) {
fireValueChanged();
}
}
}

+ 0
- 3
client/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelConnector.java View File

@@ -138,9 +138,6 @@ public abstract class AbstractSplitPanelConnector extends
// Splitter updates
SplitterState splitterState = getState().getSplitterState();

getWidget().setLocked(splitterState.isLocked());
getWidget().setPositionReversed(splitterState.isPositionReversed());

getWidget().setStylenames();

getWidget().minimumPosition = splitterState.getMinPosition()

+ 0
- 9
client/src/com/vaadin/terminal/gwt/client/ui/textarea/TextAreaConnector.java View File

@@ -18,7 +18,6 @@ package com.vaadin.terminal.gwt.client.ui.textarea;

import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.textarea.TextAreaState;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
import com.vaadin.terminal.gwt.client.ui.textfield.TextFieldConnector;
import com.vaadin.ui.TextArea;

@@ -30,14 +29,6 @@ public class TextAreaConnector extends TextFieldConnector {
return (TextAreaState) super.getState();
}

@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);

getWidget().setRows(getState().getRows());
getWidget().setWordwrap(getState().isWordwrap());
}

@Override
public VTextArea getWidget() {
return (VTextArea) super.getWidget();

+ 236
- 245
server/src/com/vaadin/Application.java View File

@@ -52,14 +52,14 @@ import com.vaadin.data.util.converter.ConverterFactory;
import com.vaadin.data.util.converter.DefaultConverterFactory;
import com.vaadin.event.EventRouter;
import com.vaadin.service.ApplicationContext;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.terminal.AbstractErrorMessage;
import com.vaadin.terminal.ApplicationResource;
import com.vaadin.terminal.CombinedRequest;
import com.vaadin.terminal.DeploymentConfiguration;
import com.vaadin.terminal.RequestHandler;
import com.vaadin.terminal.RootProvider;
import com.vaadin.terminal.Terminal;
import com.vaadin.terminal.UIProvider;
import com.vaadin.terminal.VariableOwner;
import com.vaadin.terminal.WrappedRequest;
import com.vaadin.terminal.WrappedRequest.BrowserDetails;
@@ -75,8 +75,8 @@ import com.vaadin.terminal.gwt.server.WebApplicationContext;
import com.vaadin.tools.ReflectTools;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.AbstractField;
import com.vaadin.ui.Root;
import com.vaadin.ui.Table;
import com.vaadin.ui.UI;
import com.vaadin.ui.Window;

/**
@@ -135,9 +135,9 @@ public class Application implements Terminal.ErrorListener, Serializable {

/**
* The name of the parameter that is by default used in e.g. web.xml to
* define the name of the default {@link Root} class.
* define the name of the default {@link UI} class.
*/
public static final String ROOT_PARAMETER = "root";
public static final String UI_PARAMETER = "UI";

private static final Method BOOTSTRAP_FRAGMENT_METHOD = ReflectTools
.findMethod(BootstrapListener.class, "modifyBootstrapFragment",
@@ -165,19 +165,19 @@ public class Application implements Terminal.ErrorListener, Serializable {
private static final Pattern WINDOW_NAME_PATTERN = Pattern
.compile("^/?([^/]+).*");

private Root.LegacyWindow mainWindow;
private UI.LegacyWindow mainWindow;
private String theme;

private Map<String, Root.LegacyWindow> legacyRootNames = new HashMap<String, Root.LegacyWindow>();
private Map<String, UI.LegacyWindow> legacyUINames = new HashMap<String, UI.LegacyWindow>();

/**
* Sets the main window of this application. Setting window as a main
* window of this application also adds the window to this application.
*
* @param mainWindow
* the root to set as the default window
* the UI to set as the default window
*/
public void setMainWindow(Root.LegacyWindow mainWindow) {
public void setMainWindow(UI.LegacyWindow mainWindow) {
if (this.mainWindow != null) {
throw new IllegalStateException(
"mainWindow has already been set");
@@ -202,9 +202,9 @@ public class Application implements Terminal.ErrorListener, Serializable {
* Note that each application must have at least one main window.
* </p>
*
* @return the root used as the default window
* @return the UI used as the default window
*/
public Root.LegacyWindow getMainWindow() {
public UI.LegacyWindow getMainWindow() {
return mainWindow;
}

@@ -216,11 +216,11 @@ public class Application implements Terminal.ErrorListener, Serializable {
* {@inheritDoc}
*
* @see #getWindow(String)
* @see Application#getRoot(WrappedRequest)
* @see Application#getUI(WrappedRequest)
*/

@Override
public Root.LegacyWindow getRoot(WrappedRequest request) {
public UI.LegacyWindow getUI(WrappedRequest request) {
String pathInfo = request.getRequestPathInfo();
String name = null;
if (pathInfo != null && pathInfo.length() > 0) {
@@ -230,7 +230,7 @@ public class Application implements Terminal.ErrorListener, Serializable {
name = matcher.group(1);
}
}
Root.LegacyWindow window = getWindow(name);
UI.LegacyWindow window = getWindow(name);
if (window != null) {
return window;
}
@@ -240,8 +240,8 @@ public class Application implements Terminal.ErrorListener, Serializable {
/**
* Sets the application's theme.
* <p>
* Note that this theme can be overridden for a specific root with
* {@link Application#getThemeForRoot(Root)}. Setting theme to be
* Note that this theme can be overridden for a specific UI with
* {@link Application#getThemeForUI(UI)}. Setting theme to be
* <code>null</code> selects the default theme. For the available theme
* names, see the contents of the VAADIN/themes directory.
* </p>
@@ -255,7 +255,7 @@ public class Application implements Terminal.ErrorListener, Serializable {

/**
* Gets the application's theme. The application's theme is the default
* theme used by all the roots for which a theme is not explicitly
* theme used by all the uIs for which a theme is not explicitly
* defined. If the application theme is not explicitly set,
* <code>null</code> is returned.
*
@@ -273,70 +273,70 @@ public class Application implements Terminal.ErrorListener, Serializable {
*/

@Override
public String getThemeForRoot(Root root) {
public String getThemeForUI(UI uI) {
return theme;
}

/**
* <p>
* Gets a root by name. Returns <code>null</code> if the application is
* Gets a UI by name. Returns <code>null</code> if the application is
* not running or it does not contain a window corresponding to the
* name.
* </p>
*
* @param name
* the name of the requested window
* @return a root corresponding to the name, or <code>null</code> to use
* @return a UI corresponding to the name, or <code>null</code> to use
* the default window
*/
public Root.LegacyWindow getWindow(String name) {
return legacyRootNames.get(name);
public UI.LegacyWindow getWindow(String name) {
return legacyUINames.get(name);
}

/**
* Counter to get unique names for windows with no explicit name
*/
private int namelessRootIndex = 0;
private int namelessUIIndex = 0;

/**
* Adds a new browser level window to this application. Please note that
* Root doesn't have a name that is used in the URL - to add a named
* window you should instead use {@link #addWindow(Root, String)}
* UI doesn't have a name that is used in the URL - to add a named
* window you should instead use {@link #addWindow(UI, String)}
*
* @param root
* the root window to add to the application
* @param uI
* the UI window to add to the application
* @return returns the name that has been assigned to the window
*
* @see #addWindow(Root, String)
* @see #addWindow(UI, String)
*/
public void addWindow(Root.LegacyWindow root) {
if (root.getName() == null) {
String name = Integer.toString(namelessRootIndex++);
root.setName(name);
public void addWindow(UI.LegacyWindow uI) {
if (uI.getName() == null) {
String name = Integer.toString(namelessUIIndex++);
uI.setName(name);
}

legacyRootNames.put(root.getName(), root);
root.setApplication(this);
legacyUINames.put(uI.getName(), uI);
uI.setApplication(this);
}

/**
* Removes the specified window from the application. This also removes
* all name mappings for the window (see
* {@link #addWindow(Root, String) and #getWindowName(Root)}.
* all name mappings for the window (see {@link #addWindow(UI, String)
* and #getWindowName(UI)}.
*
* <p>
* Note that removing window from the application does not close the
* browser window - the window is only removed from the server-side.
* </p>
*
* @param root
* the root to remove
* @param uI
* the UI to remove
*/
public void removeWindow(Root.LegacyWindow root) {
for (Entry<String, Root.LegacyWindow> entry : legacyRootNames
public void removeWindow(UI.LegacyWindow uI) {
for (Entry<String, UI.LegacyWindow> entry : legacyUINames
.entrySet()) {
if (entry.getValue() == root) {
legacyRootNames.remove(entry.getKey());
if (entry.getValue() == uI) {
legacyUINames.remove(entry.getKey());
}
}
}
@@ -350,8 +350,8 @@ public class Application implements Terminal.ErrorListener, Serializable {
*
* @return the unmodifiable collection of windows.
*/
public Collection<Root.LegacyWindow> getWindows() {
return Collections.unmodifiableCollection(legacyRootNames.values());
public Collection<UI.LegacyWindow> getWindows() {
return Collections.unmodifiableCollection(legacyUINames.values());
}
}

@@ -490,23 +490,23 @@ public class Application implements Terminal.ErrorListener, Serializable {

private LinkedList<RequestHandler> requestHandlers = new LinkedList<RequestHandler>();

private int nextRootId = 0;
private Map<Integer, Root> roots = new HashMap<Integer, Root>();
private int nextUIId = 0;
private Map<Integer, UI> uIs = new HashMap<Integer, UI>();

private final Map<String, Integer> retainOnRefreshRoots = new HashMap<String, Integer>();
private final Map<String, Integer> retainOnRefreshUIs = new HashMap<String, Integer>();

private final EventRouter eventRouter = new EventRouter();

/**
* Keeps track of which roots have been inited.
* Keeps track of which uIs have been inited.
* <p>
* TODO Investigate whether this might be derived from the different states
* in getRootForRrequest.
* in getUIForRrequest.
* </p>
*/
private Set<Integer> initedRoots = new HashSet<Integer>();
private Set<Integer> initedUIs = new HashSet<Integer>();

private List<RootProvider> rootProviders = new LinkedList<RootProvider>();
private List<UIProvider> uiProviders = new LinkedList<UIProvider>();

/**
* Gets the user of the application.
@@ -583,15 +583,15 @@ public class Application implements Terminal.ErrorListener, Serializable {
* <p>
* In effect this will cause the application stop returning any windows when
* asked. When the application is closed, close events are fired for its
* roots, its state is removed from the session, and the browser window is
* UIs, its state is removed from the session, and the browser window is
* redirected to the application logout url set with
* {@link #setLogoutURL(String)}. If the logout url has not been set, the
* browser window is reloaded and the application is restarted.
*/
public void close() {
applicationIsRunning = false;
for (Root root : getRoots()) {
root.fireCloseEvent();
for (UI ui : getUIs()) {
ui.fireCloseEvent();
}
}

@@ -1831,110 +1831,108 @@ public class Application implements Terminal.ErrorListener, Serializable {
}

/**
* Gets a root for a request for which no root is already known. This method
* is called when the framework processes a request that does not originate
* from an existing root instance. This typically happens when a host page
* is requested.
* Gets a UI for a request for which no UI is already known. This method is
* called when the framework processes a request that does not originate
* from an existing UI instance. This typically happens when a host page is
* requested.
*
* <p>
* Subclasses of Application may override this method to provide custom
* logic for choosing how to create a suitable root or for picking an
* already created root. If an existing root is picked, care should be taken
* to avoid keeping the same root open in multiple browser windows, as that
* will cause the states to go out of sync.
* logic for choosing how to create a suitable UI or for picking an already
* created UI. If an existing UI is picked, care should be taken to avoid
* keeping the same UI open in multiple browser windows, as that will cause
* the states to go out of sync.
* </p>
*
* <p>
* If {@link BrowserDetails} are required to create a Root, the
* implementation can throw a {@link RootRequiresMoreInformationException}
* exception. In this case, the framework will instruct the browser to send
* the additional details, whereupon this method is invoked again with the
* browser details present in the wrapped request. Throwing the exception if
* the browser details are already available is not supported.
* If {@link BrowserDetails} are required to create a UI, the implementation
* can throw a {@link UIRequiresMoreInformationException} exception. In this
* case, the framework will instruct the browser to send the additional
* details, whereupon this method is invoked again with the browser details
* present in the wrapped request. Throwing the exception if the browser
* details are already available is not supported.
* </p>
*
* <p>
* The default implementation in {@link Application} creates a new instance
* of the Root class returned by {@link #getRootClassName(WrappedRequest)},
* which in turn uses the {@value #ROOT_PARAMETER} parameter from web.xml.
* If {@link DeploymentConfiguration#getClassLoader()} for the request
* returns a {@link ClassLoader}, it is used for loading the Root class.
* Otherwise the {@link ClassLoader} used to load this class is used.
* of the UI class returned by {@link #getUIClassName(WrappedRequest)},
* which in turn uses the {@value #UI_PARAMETER} parameter from web.xml. If
* {@link DeploymentConfiguration#getClassLoader()} for the request returns
* a {@link ClassLoader}, it is used for loading the UI class. Otherwise the
* {@link ClassLoader} used to load this class is used.
* </p>
*
* @param request
* the wrapped request for which a root is needed
* @return a root instance to use for the request
* @throws RootRequiresMoreInformationException
* the wrapped request for which a UI is needed
* @return a UI instance to use for the request
* @throws UIRequiresMoreInformationException
* may be thrown by an implementation to indicate that
* {@link BrowserDetails} are required to create a root
* {@link BrowserDetails} are required to create a UI
*
* @see #getRootClassName(WrappedRequest)
* @see Root
* @see RootRequiresMoreInformationException
* @see #getUIClassName(WrappedRequest)
* @see UI
* @see UIRequiresMoreInformationException
* @see WrappedRequest#getBrowserDetails()
*
* @since 7.0
*/
protected Root getRoot(WrappedRequest request)
throws RootRequiresMoreInformationException {
protected UI getUI(WrappedRequest request)
throws UIRequiresMoreInformationException {

// Iterate in reverse order - test check newest provider first
for (int i = rootProviders.size() - 1; i >= 0; i--) {
RootProvider provider = rootProviders.get(i);
for (int i = uiProviders.size() - 1; i >= 0; i--) {
UIProvider provider = uiProviders.get(i);

Class<? extends Root> rootClass = provider.getRootClass(this,
request);
Class<? extends UI> uiClass = provider.getUIClass(this, request);

if (rootClass != null) {
return provider.instantiateRoot(this, rootClass, request);
if (uiClass != null) {
return provider.instantiateUI(this, uiClass, request);
}
}

throw new RuntimeException(
"No root providers available or providers are not able to find root instance");
"No UI providers available or providers are not able to find UI instance");
}

/**
* Finds the theme to use for a specific root. If no specific theme is
* Finds the theme to use for a specific UI. If no specific theme is
* required, <code>null</code> is returned.
*
* TODO Tell what the default implementation does once it does something.
*
* @param root
* the root to get a theme for
* @param uI
* the UI to get a theme for
* @return the name of the theme, or <code>null</code> if the default theme
* should be used
*
* @since 7.0
*/
public String getThemeForRoot(Root root) {
Theme rootTheme = getAnnotationFor(root.getClass(), Theme.class);
if (rootTheme != null) {
return rootTheme.value();
public String getThemeForUI(UI uI) {
Theme uiTheme = getAnnotationFor(uI.getClass(), Theme.class);
if (uiTheme != null) {
return uiTheme.value();
} else {
return null;
}
}

/**
* Finds the widgetset to use for a specific root. If no specific widgetset
* is required, <code>null</code> is returned.
* Finds the widgetset to use for a specific UI. If no specific widgetset is
* required, <code>null</code> is returned.
*
* TODO Tell what the default implementation does once it does something.
*
* @param root
* the root to get a widgetset for
* @param uI
* the UI to get a widgetset for
* @return the name of the widgetset, or <code>null</code> if the default
* widgetset should be used
*
* @since 7.0
*/
public String getWidgetsetForRoot(Root root) {
Widgetset rootWidgetset = getAnnotationFor(root.getClass(),
Widgetset.class);
if (rootWidgetset != null) {
return rootWidgetset.value();
public String getWidgetsetForUI(UI uI) {
Widgetset uiWidgetset = getAnnotationFor(uI.getClass(), Widgetset.class);
if (uiWidgetset != null) {
return uiWidgetset.value();
} else {
return null;
}
@@ -2088,7 +2086,7 @@ public class Application implements Terminal.ErrorListener, Serializable {
*/
private static final ThreadLocal<Application> currentApplication = new ThreadLocal<Application>();

private boolean rootPreserved = false;
private boolean uiPreserved = false;

/**
* Gets the currently used application. The current application is
@@ -2140,144 +2138,140 @@ public class Application implements Terminal.ErrorListener, Serializable {
return configuration.isProductionMode();
}

public void addRootProvider(RootProvider rootProvider) {
rootProviders.add(rootProvider);
public void addUIProvider(UIProvider uIProvider) {
uiProviders.add(uIProvider);
}

public void removeRootProvider(RootProvider rootProvider) {
rootProviders.remove(rootProvider);
public void removeUIProvider(UIProvider uIProvider) {
uiProviders.remove(uIProvider);
}

/**
* Finds the {@link Root} to which a particular request belongs. If the
* request originates from an existing Root, that root is returned. In other
* cases, the method attempts to create and initialize a new root and might
* throw a {@link RootRequiresMoreInformationException} if all required
* Finds the {@link UI} to which a particular request belongs. If the
* request originates from an existing UI, that UI is returned. In other
* cases, the method attempts to create and initialize a new UI and might
* throw a {@link UIRequiresMoreInformationException} if all required
* information is not available.
* <p>
* Please note that this method can also return a newly created
* <code>Root</code> which has not yet been initialized. You can use
* {@link #isRootInitPending(int)} with the root's id (
* {@link Root#getRootId()} to check whether the initialization is still
* pending.
* <code>UI</code> which has not yet been initialized. You can use
* {@link #isUIInitPending(int)} with the UI's id ( {@link UI#getUIId()} to
* check whether the initialization is still pending.
* </p>
*
* @param request
* the request for which a root is desired
* @return a root belonging to the request
* @throws RootRequiresMoreInformationException
* if no existing root could be found and creating a new root
* the request for which a UI is desired
* @return a UI belonging to the request
* @throws UIRequiresMoreInformationException
* if no existing UI could be found and creating a new UI
* requires additional information from the browser
*
* @see #getRoot(WrappedRequest)
* @see RootRequiresMoreInformationException
* @see #getUI(WrappedRequest)
* @see UIRequiresMoreInformationException
*
* @since 7.0
*/
public Root getRootForRequest(WrappedRequest request)
throws RootRequiresMoreInformationException {
Root root = Root.getCurrent();
if (root != null) {
return root;
public UI getUIForRequest(WrappedRequest request)
throws UIRequiresMoreInformationException {
UI uI = UI.getCurrent();
if (uI != null) {
return uI;
}
Integer rootId = getRootId(request);
Integer uiId = getUIId(request);

synchronized (this) {
BrowserDetails browserDetails = request.getBrowserDetails();
boolean hasBrowserDetails = browserDetails != null
&& browserDetails.getUriFragment() != null;

root = roots.get(rootId);
uI = uIs.get(uiId);

if (root == null && isRootPreserved()) {
// Check for a known root
if (!retainOnRefreshRoots.isEmpty()) {
if (uI == null && isUiPreserved()) {
// Check for a known UI
if (!retainOnRefreshUIs.isEmpty()) {

Integer retainedRootId;
Integer retainedUIId;
if (!hasBrowserDetails) {
throw new RootRequiresMoreInformationException();
throw new UIRequiresMoreInformationException();
} else {
String windowName = browserDetails.getWindowName();
retainedRootId = retainOnRefreshRoots.get(windowName);
retainedUIId = retainOnRefreshUIs.get(windowName);
}

if (retainedRootId != null) {
rootId = retainedRootId;
root = roots.get(rootId);
if (retainedUIId != null) {
uiId = retainedUIId;
uI = uIs.get(uiId);
}
}
}

if (root == null) {
// Throws exception if root can not yet be created
root = getRoot(request);
if (uI == null) {
// Throws exception if UI can not yet be created
uI = getUI(request);

// Initialize some fields for a newly created root
if (root.getApplication() == null) {
root.setApplication(this);
// Initialize some fields for a newly created UI
if (uI.getApplication() == null) {
uI.setApplication(this);
}
if (root.getRootId() < 0) {
if (uI.getUIId() < 0) {

if (rootId == null) {
if (uiId == null) {
// Get the next id if none defined
rootId = Integer.valueOf(nextRootId++);
uiId = Integer.valueOf(nextUIId++);
}
root.setRootId(rootId.intValue());
roots.put(rootId, root);
uI.setUIId(uiId.intValue());
uIs.put(uiId, uI);
}
}

// Set thread local here so it is available in init
Root.setCurrent(root);
UI.setCurrent(uI);

if (!initedRoots.contains(rootId)) {
boolean initRequiresBrowserDetails = isRootPreserved()
|| !root.getClass()
.isAnnotationPresent(EagerInit.class);
if (!initedUIs.contains(uiId)) {
boolean initRequiresBrowserDetails = isUiPreserved()
|| !uI.getClass().isAnnotationPresent(EagerInit.class);
if (!initRequiresBrowserDetails || hasBrowserDetails) {
root.doInit(request);
uI.doInit(request);

// Remember that this root has been initialized
initedRoots.add(rootId);
// Remember that this UI has been initialized
initedUIs.add(uiId);

// init() might turn on preserve so do this afterwards
if (isRootPreserved()) {
// Remember this root
if (isUiPreserved()) {
// Remember this UI
String windowName = request.getBrowserDetails()
.getWindowName();
retainOnRefreshRoots.put(windowName, rootId);
retainOnRefreshUIs.put(windowName, uiId);
}
}
}
} // end synchronized block

return root;
return uI;
}

/**
* Internal helper to finds the root id for a request.
* Internal helper to finds the UI id for a request.
*
* @param request
* the request to get the root id for
* @return a root id, or <code>null</code> if no root id is defined
* the request to get the UI id for
* @return a UI id, or <code>null</code> if no UI id is defined
*
* @since 7.0
*/
private static Integer getRootId(WrappedRequest request) {
private static Integer getUIId(WrappedRequest request) {
if (request instanceof CombinedRequest) {
// Combined requests has the rootid parameter in the second request
// Combined requests has the uiId parameter in the second request
CombinedRequest combinedRequest = (CombinedRequest) request;
request = combinedRequest.getSecondRequest();
}
String rootIdString = request
.getParameter(ApplicationConstants.ROOT_ID_PARAMETER);
Integer rootId = rootIdString == null ? null
: new Integer(rootIdString);
return rootId;
String uiIdString = request.getParameter(UIConstants.UI_ID_PARAMETER);
Integer uiId = uiIdString == null ? null : new Integer(uiIdString);
return uiId;
}

/**
* Sets whether the same Root state should be reused if the framework can
* Sets whether the same UI state should be reused if the framework can
* detect that the application is opened in a browser window where it has
* previously been open. The framework attempts to discover this by checking
* the value of window.name in the browser.
@@ -2286,62 +2280,62 @@ public class Application implements Terminal.ErrorListener, Serializable {
* the UI is already shown, as it might not be retained as intended.
* </p>
*
* @param rootPreserved
* <code>true</code>if the same Root instance should be reused
* e.g. when the browser window is refreshed.
* @param uiPreserved
* <code>true</code>if the same UI instance should be reused e.g.
* when the browser window is refreshed.
*/
public void setRootPreserved(boolean rootPreserved) {
this.rootPreserved = rootPreserved;
if (!rootPreserved) {
retainOnRefreshRoots.clear();
public void setUiPreserved(boolean uiPreserved) {
this.uiPreserved = uiPreserved;
if (!uiPreserved) {
retainOnRefreshUIs.clear();
}
}

/**
* Checks whether the same Root state should be reused if the framework can
* Checks whether the same UI state should be reused if the framework can
* detect that the application is opened in a browser window where it has
* previously been open. The framework attempts to discover this by checking
* the value of window.name in the browser.
*
* @return <code>true</code>if the same Root instance should be reused e.g.
* @return <code>true</code>if the same UI instance should be reused e.g.
* when the browser window is refreshed.
*/
public boolean isRootPreserved() {
return rootPreserved;
public boolean isUiPreserved() {
return uiPreserved;
}

/**
* Checks whether there's a pending initialization for the root with the
* given id.
* Checks whether there's a pending initialization for the UI with the given
* id.
*
* @param rootId
* root id to check for
* @param uiId
* UI id to check for
* @return <code>true</code> of the initialization is pending,
* <code>false</code> if the root id is not registered or if the
* root has already been initialized
* <code>false</code> if the UI id is not registered or if the UI
* has already been initialized
*
* @see #getRootForRequest(WrappedRequest)
* @see #getUIForRequest(WrappedRequest)
*/
public boolean isRootInitPending(int rootId) {
return !initedRoots.contains(Integer.valueOf(rootId));
public boolean isUIInitPending(int uiId) {
return !initedUIs.contains(Integer.valueOf(uiId));
}

/**
* Gets all the roots of this application. This includes roots that have
* been requested but not yet initialized. Please note, that roots are not
* Gets all the uIs of this application. This includes uIs that have been
* requested but not yet initialized. Please note, that uIs are not
* automatically removed e.g. if the browser window is closed and that there
* is no way to manually remove a root. Inactive roots will thus not be
* released for GC until the entire application is released when the session
* has timed out (unless there are dangling references). Improved support
* for releasing unused roots is planned for an upcoming alpha release of
* Vaadin 7.
* is no way to manually remove a UI. Inactive uIs will thus not be released
* for GC until the entire application is released when the session has
* timed out (unless there are dangling references). Improved support for
* releasing unused uIs is planned for an upcoming alpha release of Vaadin
* 7.
*
* @return a collection of roots belonging to this application
* @return a collection of uIs belonging to this application
*
* @since 7.0
*/
public Collection<Root> getRoots() {
return Collections.unmodifiableCollection(roots.values());
public Collection<UI> getUIs() {
return Collections.unmodifiableCollection(uIs.values());
}

private int connectorIdSequence = 0;
@@ -2363,17 +2357,17 @@ public class Application implements Terminal.ErrorListener, Serializable {
}

/**
* Returns a Root with the given id.
* Returns a UI with the given id.
* <p>
* This is meant for framework internal use.
* </p>
*
* @param rootId
* The root id
* @return The root with the given id or null if not found
* @param uiId
* The UI id
* @return The UI with the given id or null if not found
*/
public Root getRootById(int rootId) {
return roots.get(rootId);
public UI getUIById(int uiId) {
return uIs.get(uiId);
}

/**
@@ -2424,41 +2418,39 @@ public class Application implements Terminal.ErrorListener, Serializable {
}

/**
* Removes all those roots from the application for whom
* {@link #isRootAlive} returns false. Close events are fired for the
* removed roots.
* Removes all those UIs from the application for which {@link #isUIAlive}
* returns false. Close events are fired for the removed UIs.
* <p>
* Called by the framework at the end of every request.
*
* @see Root.CloseEvent
* @see Root.CloseListener
* @see #isRootAlive(Root)
* @see UI.CloseEvent
* @see UI.CloseListener
* @see #isUIAlive(UI)
*
* @since 7.0.0
*/
public void closeInactiveRoots() {
for (Iterator<Root> i = roots.values().iterator(); i.hasNext();) {
Root root = i.next();
if (!isRootAlive(root)) {
public void closeInactiveUIs() {
for (Iterator<UI> i = uIs.values().iterator(); i.hasNext();) {
UI ui = i.next();
if (!isUIAlive(ui)) {
i.remove();
retainOnRefreshRoots.values().remove(root.getRootId());
root.fireCloseEvent();
retainOnRefreshUIs.values().remove(ui.getUIId());
ui.fireCloseEvent();
getLogger().info(
"Closed root #" + root.getRootId()
+ " due to inactivity");
"Closed UI #" + ui.getUIId() + " due to inactivity");
}
}
}

/**
* Returns the number of seconds that must pass without a valid heartbeat or
* UIDL request being received from a root before that root is removed from
* the application. This is a lower bound; it might take longer to close an
* inactive root. Returns a negative number if heartbeat is disabled and
* UIDL request being received from a UI before that UI is removed from the
* application. This is a lower bound; it might take longer to close an
* inactive UI. Returns a negative number if heartbeat is disabled and
* timeout never occurs.
*
* @see #getUidlRequestTimeout()
* @see #closeInactiveRoots()
* @see #closeInactiveUIs()
* @see DeploymentConfiguration#getHeartbeatInterval()
*
* @since 7.0.0
@@ -2467,24 +2459,23 @@ public class Application implements Terminal.ErrorListener, Serializable {
* never occurs.
*/
protected int getHeartbeatTimeout() {
// Permit three missed heartbeats before closing the root
// Permit three missed heartbeats before closing the UI
return (int) (configuration.getHeartbeatInterval() * (3.1));
}

/**
* Returns the number of seconds that must pass without a valid UIDL request
* being received from a root before the root is removed from the
* application, even though heartbeat requests are received. This is a lower
* bound; it might take longer to close an inactive root. Returns a negative
* number if
* being received from a UI before the UI is removed from the application,
* even though heartbeat requests are received. This is a lower bound; it
* might take longer to close an inactive UI. Returns a negative number if
* <p>
* This timeout only has effect if cleanup of inactive roots is enabled;
* otherwise heartbeat requests are enough to extend root lifetime
* This timeout only has effect if cleanup of inactive UIs is enabled;
* otherwise heartbeat requests are enough to extend UI lifetime
* indefinitely.
*
* @see DeploymentConfiguration#isIdleRootCleanupEnabled()
* @see DeploymentConfiguration#isIdleUICleanupEnabled()
* @see #getHeartbeatTimeout()
* @see #closeInactiveRoots()
* @see #closeInactiveUIs()
*
* @since 7.0.0
*
@@ -2492,29 +2483,29 @@ public class Application implements Terminal.ErrorListener, Serializable {
* timeout never occurs.
*/
protected int getUidlRequestTimeout() {
return configuration.isIdleRootCleanupEnabled() ? getContext()
return configuration.isIdleUICleanupEnabled() ? getContext()
.getMaxInactiveInterval() : -1;
}

/**
* Returns whether the given root is alive (the client-side actively
* Returns whether the given UI is alive (the client-side actively
* communicates with the server) or whether it can be removed from the
* application and eventually collected.
*
* @since 7.0.0
*
* @param root
* The Root whose status to check
* @return true if the root is alive, false if it could be removed.
* @param ui
* The UI whose status to check
* @return true if the UI is alive, false if it could be removed.
*/
protected boolean isRootAlive(Root root) {
protected boolean isUIAlive(UI ui) {
long now = System.currentTimeMillis();
if (getHeartbeatTimeout() >= 0
&& now - root.getLastHeartbeatTime() > 1000 * getHeartbeatTimeout()) {
&& now - ui.getLastHeartbeatTime() > 1000 * getHeartbeatTimeout()) {
return false;
}
if (getUidlRequestTimeout() >= 0
&& now - root.getLastUidlRequestTime() > 1000 * getUidlRequestTimeout()) {
&& now - ui.getLastUidlRequestTime() > 1000 * getUidlRequestTimeout()) {
return false;
}
return true;

server/src/com/vaadin/RootRequiresMoreInformationException.java → server/src/com/vaadin/UIRequiresMoreInformationException.java View File

@@ -20,18 +20,18 @@ import com.vaadin.terminal.WrappedRequest;
import com.vaadin.terminal.WrappedRequest.BrowserDetails;

/**
* Exception that is thrown to indicate that creating or initializing the root
* Exception that is thrown to indicate that creating or initializing the UI
* requires information detailed from the web browser ({@link BrowserDetails})
* to be present.
*
* This exception may not be thrown if that information is already present in
* the current WrappedRequest.
*
* @see Application#getRoot(WrappedRequest)
* @see Application#getUI(WrappedRequest)
* @see WrappedRequest#getBrowserDetails()
*
* @since 7.0
*/
public class RootRequiresMoreInformationException extends Exception {
public class UIRequiresMoreInformationException extends Exception {
// Nothing of interest here
}

+ 3
- 3
server/src/com/vaadin/annotations/EagerInit.java View File

@@ -21,15 +21,15 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.vaadin.terminal.WrappedRequest;
import com.vaadin.ui.Root;
import com.vaadin.ui.UI;

/**
* Indicates that the init method in a Root class can be called before full
* Indicates that the init method in a UI class can be called before full
* browser details ({@link WrappedRequest#getBrowserDetails()}) are available.
* This will make the UI appear more quickly, as ensuring the availability of
* this information typically requires an additional round trip to the client.
*
* @see Root#init(com.vaadin.terminal.WrappedRequest)
* @see UI#init(com.vaadin.terminal.WrappedRequest)
* @see WrappedRequest#getBrowserDetails()
*
* @since 7.0

+ 2
- 2
server/src/com/vaadin/annotations/Theme.java View File

@@ -21,10 +21,10 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.vaadin.ui.Root;
import com.vaadin.ui.UI;

/**
* Defines a specific theme for a {@link Root}.
* Defines a specific theme for a {@link UI}.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)

+ 2
- 2
server/src/com/vaadin/annotations/Widgetset.java View File

@@ -21,10 +21,10 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.vaadin.ui.Root;
import com.vaadin.ui.UI;

/**
* Defines a specific theme for a {@link Root}.
* Defines a specific theme for a {@link UI}.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)

+ 0
- 76
server/src/com/vaadin/data/Buffered.java View File

@@ -76,82 +76,6 @@ public interface Buffered extends Serializable {
*/
public void discard() throws SourceException;

/**
* Tests if the object is in write-through mode. If the object is in
* write-through mode, all modifications to it will result in
* <code>commit</code> being called after the modification.
*
* @return <code>true</code> if the object is in write-through mode,
* <code>false</code> if it's not.
* @deprecated As of 7.0, use {@link #setBuffered(boolean)} instead. Note
* that setReadThrough(true), setWriteThrough(true) equals
* setBuffered(false)
*/
@Deprecated
public boolean isWriteThrough();

/**
* Sets the object's write-through mode to the specified status. When
* switching the write-through mode on, the <code>commit</code> operation
* will be performed.
*
* @param writeThrough
* Boolean value to indicate if the object should be in
* write-through mode after the call.
* @throws SourceException
* If the operation fails because of an exception is thrown by
* the data source.
* @throws InvalidValueException
* If the implicit commit operation fails because of a
* validation error.
*
* @deprecated As of 7.0, use {@link #setBuffered(boolean)} instead. Note
* that setReadThrough(true), setWriteThrough(true) equals
* setBuffered(false)
*/
@Deprecated
public void setWriteThrough(boolean writeThrough) throws SourceException,
InvalidValueException;

/**
* Tests if the object is in read-through mode. If the object is in
* read-through mode, retrieving its value will result in the value being
* first updated from the data source to the object.
* <p>
* The only exception to this rule is that when the object is not in
* write-through mode and it's buffer contains a modified value, the value
* retrieved from the object will be the locally modified value in the
* buffer which may differ from the value in the data source.
* </p>
*
* @return <code>true</code> if the object is in read-through mode,
* <code>false</code> if it's not.
* @deprecated As of 7.0, use {@link #isBuffered(boolean)} instead. Note
* that setReadThrough(true), setWriteThrough(true) equals
* setBuffered(false)
*/
@Deprecated
public boolean isReadThrough();

/**
* Sets the object's read-through mode to the specified status. When
* switching read-through mode on, the object's value is updated from the
* data source.
*
* @param readThrough
* Boolean value to indicate if the object should be in
* read-through mode after the call.
*
* @throws SourceException
* If the operation fails because of an exception is thrown by
* the data source. The cause is included in the exception.
* @deprecated As of 7.0, use {@link #setBuffered(boolean)} instead. Note
* that setReadThrough(true), setWriteThrough(true) equals
* setBuffered(false)
*/
@Deprecated
public void setReadThrough(boolean readThrough) throws SourceException;

/**
* Sets the object's buffered mode to the specified status.
* <p>

+ 0
- 685
server/src/com/vaadin/data/util/QueryContainer.java View File

@@ -1,685 +0,0 @@
/*
* 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.data.util;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;

import com.vaadin.data.Container;
import com.vaadin.data.Item;
import com.vaadin.data.Property;

/**
* <p>
* The <code>QueryContainer</code> is the specialized form of Container which is
* Ordered and Indexed. This is used to represent the contents of relational
* database tables accessed through the JDBC Connection in the Vaadin Table.
* This creates Items based on the queryStatement provided to the container.
* </p>
*
* <p>
* The <code>QueryContainer</code> can be visualized as a representation of a
* relational database table.Each Item in the container represents the row
* fetched by the query.All cells in a column have same data type and the data
* type information is retrieved from the metadata of the resultset.
* </p>
*
* <p>
* Note : If data in the tables gets modified, Container will not get reflected
* with the updates, we have to explicity invoke QueryContainer.refresh method.
* {@link com.vaadin.data.util.QueryContainer#refresh() refresh()}
* </p>
*
* @see com.vaadin.data.Container
*
* @author Vaadin Ltd.
* @since 4.0
*
* @deprecated will be removed in the future, use the SQLContainer add-on
*/

@Deprecated
@SuppressWarnings("serial")
public class QueryContainer implements Container, Container.Ordered,
Container.Indexed {

// default ResultSet type
public static final int DEFAULT_RESULTSET_TYPE = ResultSet.TYPE_SCROLL_INSENSITIVE;

// default ResultSet concurrency
public static final int DEFAULT_RESULTSET_CONCURRENCY = ResultSet.CONCUR_READ_ONLY;

private int resultSetType = DEFAULT_RESULTSET_TYPE;

private int resultSetConcurrency = DEFAULT_RESULTSET_CONCURRENCY;

private final String queryStatement;

private final Connection connection;

private ResultSet result;

private Collection<String> propertyIds;

private final HashMap<String, Class<?>> propertyTypes = new HashMap<String, Class<?>>();

private int size = -1;

private Statement statement;

/**
* Constructs new <code>QueryContainer</code> with the specified
* <code>queryStatement</code>.
*
* @param queryStatement
* Database query
* @param connection
* Connection object
* @param resultSetType
* @param resultSetConcurrency
* @throws SQLException
* when database operation fails
*/
public QueryContainer(String queryStatement, Connection connection,
int resultSetType, int resultSetConcurrency) throws SQLException {
this.queryStatement = queryStatement;
this.connection = connection;
this.resultSetType = resultSetType;
this.resultSetConcurrency = resultSetConcurrency;
init();
}

/**
* Constructs new <code>QueryContainer</code> with the specified
* queryStatement using the default resultset type and default resultset
* concurrency.
*
* @param queryStatement
* Database query
* @param connection
* Connection object
* @see QueryContainer#DEFAULT_RESULTSET_TYPE
* @see QueryContainer#DEFAULT_RESULTSET_CONCURRENCY
* @throws SQLException
* when database operation fails
*/
public QueryContainer(String queryStatement, Connection connection)
throws SQLException {
this(queryStatement, connection, DEFAULT_RESULTSET_TYPE,
DEFAULT_RESULTSET_CONCURRENCY);
}

/**
* Fills the Container with the items and properties. Invoked by the
* constructor.
*
* @throws SQLException
* when parameter initialization fails.
* @see QueryContainer#QueryContainer(String, Connection, int, int).
*/
private void init() throws SQLException {
refresh();
ResultSetMetaData metadata;
metadata = result.getMetaData();
final int count = metadata.getColumnCount();
final ArrayList<String> list = new ArrayList<String>(count);
for (int i = 1; i <= count; i++) {
final String columnName = metadata.getColumnName(i);
list.add(columnName);
final Property<?> p = getContainerProperty(new Integer(1),
columnName);
propertyTypes.put(columnName,
p == null ? Object.class : p.getType());
}
propertyIds = Collections.unmodifiableCollection(list);
}

/**
* <p>
* Restores items in the container. This method will update the latest data
* to the container.
* </p>
* Note: This method should be used to update the container with the latest
* items.
*
* @throws SQLException
* when database operation fails
*
*/

public void refresh() throws SQLException {
close();
statement = connection.createStatement(resultSetType,
resultSetConcurrency);
result = statement.executeQuery(queryStatement);
result.last();
size = result.getRow();
}

/**
* Releases and nullifies the <code>statement</code>.
*
* @throws SQLException
* when database operation fails
*/

public void close() throws SQLException {
if (statement != null) {
statement.close();
}
statement = null;
}

/**
* Gets the Item with the given Item ID from the Container.
*
* @param id
* ID of the Item to retrieve
* @return Item Id.
*/

@Override
public Item getItem(Object id) {
return new Row(id);
}

/**
* Gets the collection of propertyId from the Container.
*
* @return Collection of Property ID.
*/

@Override
public Collection<String> getContainerPropertyIds() {
return propertyIds;
}

/**
* Gets an collection of all the item IDs in the container.
*
* @return collection of Item IDs
*/
@Override
public Collection<?> getItemIds() {
final Collection<Integer> c = new ArrayList<Integer>(size);
for (int i = 1; i <= size; i++) {
c.add(new Integer(i));
}
return c;
}

/**
* Gets the property identified by the given itemId and propertyId from the
* container. If the container does not contain the property
* <code>null</code> is returned.
*
* @param itemId
* ID of the Item which contains the Property
* @param propertyId
* ID of the Property to retrieve
*
* @return Property with the given ID if exists; <code>null</code>
* otherwise.
*/

@Override
public synchronized Property<?> getContainerProperty(Object itemId,
Object propertyId) {
if (!(itemId instanceof Integer && propertyId instanceof String)) {
return null;
}
Object value;
try {
result.absolute(((Integer) itemId).intValue());
value = result.getObject((String) propertyId);
} catch (final Exception e) {
return null;
}

// Handle also null values from the database
return new ObjectProperty<Object>(value != null ? value
: new String(""));
}

/**
* Gets the data type of all properties identified by the given type ID.
*
* @param id
* ID identifying the Properties
*
* @return data type of the Properties
*/

@Override
public Class<?> getType(Object id) {
return propertyTypes.get(id);
}

/**
* Gets the number of items in the container.
*
* @return the number of items in the container.
*/
@Override
public int size() {
return size;
}

/**
* Tests if the list contains the specified Item.
*
* @param id
* ID the of Item to be tested.
* @return <code>true</code> if given id is in the container;
* <code>false</code> otherwise.
*/
@Override
public boolean containsId(Object id) {
if (!(id instanceof Integer)) {
return false;
}
final int i = ((Integer) id).intValue();
if (i < 1) {
return false;
}
if (i > size) {
return false;
}
return true;
}

/**
* Creates new Item with the given ID into the Container.
*
* @param itemId
* ID of the Item to be created.
*
* @return Created new Item, or <code>null</code> if it fails.
*
* @throws UnsupportedOperationException
* if the addItem method is not supported.
*/
@Override
public Item addItem(Object itemId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}

/**
* Creates a new Item into the Container, and assign it an ID.
*
* @return ID of the newly created Item, or <code>null</code> if it fails.
* @throws UnsupportedOperationException
* if the addItem method is not supported.
*/
@Override
public Object addItem() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}

/**
* Removes the Item identified by ItemId from the Container.
*
* @param itemId
* ID of the Item to remove.
* @return <code>true</code> if the operation succeeded; <code>false</code>
* otherwise.
* @throws UnsupportedOperationException
* if the removeItem method is not supported.
*/
@Override
public boolean removeItem(Object itemId)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}

/**
* Adds new Property to all Items in the Container.
*
* @param propertyId
* ID of the Property
* @param type
* Data type of the new Property
* @param defaultValue
* The value all created Properties are initialized to.
* @return <code>true</code> if the operation succeeded; <code>false</code>
* otherwise.
* @throws UnsupportedOperationException
* if the addContainerProperty method is not supported.
*/
@Override
public boolean addContainerProperty(Object propertyId, Class<?> type,
Object defaultValue) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}

/**
* Removes a Property specified by the given Property ID from the Container.
*
* @param propertyId
* ID of the Property to remove
* @return <code>true</code> if the operation succeeded; <code>false</code>
* otherwise.
* @throws UnsupportedOperationException
* if the removeContainerProperty method is not supported.
*/
@Override
public boolean removeContainerProperty(Object propertyId)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}

/**
* Removes all Items from the Container.
*
* @return <code>true</code> if the operation succeeded; <code>false</code>
* otherwise.
* @throws UnsupportedOperationException
* if the removeAllItems method is not supported.
*/
@Override
public boolean removeAllItems() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}

/**
* Adds new item after the given item.
*
* @param previousItemId
* Id of the previous item in ordered container.
* @param newItemId
* Id of the new item to be added.
* @return Returns new item or <code>null</code> if the operation fails.
* @throws UnsupportedOperationException
* if the addItemAfter method is not supported.
*/
@Override
public Item addItemAfter(Object previousItemId, Object newItemId)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}

/**
* Adds new item after the given item.
*
* @param previousItemId
* Id of the previous item in ordered container.
* @return Returns item id created new item or <code>null</code> if the
* operation fails.
* @throws UnsupportedOperationException
* if the addItemAfter method is not supported.
*/
@Override
public Object addItemAfter(Object previousItemId)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}

/**
* Returns id of first item in the Container.
*
* @return ID of the first Item in the list.
*/
@Override
public Object firstItemId() {
if (size < 1) {
return null;
}
return new Integer(1);
}

/**
* Returns <code>true</code> if given id is first id at first index.
*
* @param id
* ID of an Item in the Container.
*/
@Override
public boolean isFirstId(Object id) {
return size > 0 && (id instanceof Integer)
&& ((Integer) id).intValue() == 1;
}

/**
* Returns <code>true</code> if given id is last id at last index.
*
* @param id
* ID of an Item in the Container
*
*/
@Override
public boolean isLastId(Object id) {
return size > 0 && (id instanceof Integer)
&& ((Integer) id).intValue() == size;
}

/**
* Returns id of last item in the Container.
*
* @return ID of the last Item.
*/
@Override
public Object lastItemId() {
if (size < 1) {
return null;
}
return new Integer(size);
}

/**
* Returns id of next item in container at next index.
*
* @param id
* ID of an Item in the Container.
* @return ID of the next Item or null.
*/
@Override
public Object nextItemId(Object id) {
if (size < 1 || !(id instanceof Integer)) {
return null;
}
final int i = ((Integer) id).intValue();
if (i >= size) {
return null;
}
return new Integer(i + 1);
}

/**
* Returns id of previous item in container at previous index.
*
* @param id
* ID of an Item in the Container.
* @return ID of the previous Item or null.
*/
@Override
public Object prevItemId(Object id) {
if (size < 1 || !(id instanceof Integer)) {
return null;
}
final int i = ((Integer) id).intValue();
if (i <= 1) {
return null;
}
return new Integer(i - 1);
}

/**
* The <code>Row</code> class implements methods of Item.
*
* @author Vaadin Ltd.
* @since 4.0
*/
class Row implements Item {

Object id;

private Row(Object rowId) {
id = rowId;
}

/**
* Adds the item property.
*
* @param id
* ID of the new Property.
* @param property
* Property to be added and associated with ID.
* @return <code>true</code> if the operation succeeded;
* <code>false</code> otherwise.
* @throws UnsupportedOperationException
* if the addItemProperty method is not supported.
*/
@Override
public boolean addItemProperty(Object id, Property property)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}

/**
* Gets the property corresponding to the given property ID stored in
* the Item.
*
* @param propertyId
* identifier of the Property to get
* @return the Property with the given ID or <code>null</code>
*/
@Override
public Property<?> getItemProperty(Object propertyId) {
return getContainerProperty(id, propertyId);
}

/**
* Gets the collection of property IDs stored in the Item.
*
* @return unmodifiable collection containing IDs of the Properties
* stored the Item.
*/
@Override
public Collection<String> getItemPropertyIds() {
return propertyIds;
}

/**
* Removes given item property.
*
* @param id
* ID of the Property to be removed.
* @return <code>true</code> if the item property is removed;
* <code>false</code> otherwise.
* @throws UnsupportedOperationException
* if the removeItemProperty is not supported.
*/
@Override
public boolean removeItemProperty(Object id)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}

}

/**
* Closes the statement.
*
* @see #close()
*/
@Override
public void finalize() {
try {
close();
} catch (final SQLException ignored) {

}
}

/**
* Adds the given item at the position of given index.
*
* @param index
* Index to add the new item.
* @param newItemId
* Id of the new item to be added.
* @return new item or <code>null</code> if the operation fails.
* @throws UnsupportedOperationException
* if the addItemAt is not supported.
*/
@Override
public Item addItemAt(int index, Object newItemId)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}

/**
* Adds item at the position of provided index in the container.
*
* @param index
* Index to add the new item.
* @return item id created new item or <code>null</code> if the operation
* fails.
*
* @throws UnsupportedOperationException
* if the addItemAt is not supported.
*/

@Override
public Object addItemAt(int index) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}

/**
* Gets the Index id in the container.
*
* @param index
* Index Id.
* @return ID in the given index.
*/
@Override
public Object getIdByIndex(int index) {
if (size < 1 || index < 0 || index >= size) {
return null;
}
return new Integer(index + 1);
}

/**
* Gets the index of the Item corresponding to id in the container.
*
* @param id
* ID of an Item in the Container
* @return index of the Item, or -1 if the Container does not include the
* Item
*/

@Override
public int indexOfId(Object id) {
if (size < 1 || !(id instanceof Integer)) {
return -1;
}
final int i = ((Integer) id).intValue();
if (i >= size || i < 1) {
return -1;
}
return i - 1;
}

}

+ 4
- 2
server/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java View File

@@ -69,7 +69,9 @@ final public class ColumnProperty implements Property {
* @param value
* @param type
*
* @deprecated
* @deprecated as of 7.0. Use
* {@link #ColumnProperty(String, boolean, boolean, boolean, boolean, Object, Class)
* instead
*/
@Deprecated
public ColumnProperty(String propertyId, boolean readOnly,
@@ -144,7 +146,7 @@ final public class ColumnProperty implements Property {

@Override
public void setValue(Object newValue) throws ReadOnlyException,
ConversionException {
ConversionException {
if (newValue == null && !nullable) {
throw new NotNullableException(
"Null values are not allowed for this property.");

+ 1
- 1
server/src/com/vaadin/event/ActionManager.java View File

@@ -67,7 +67,7 @@ public class ActionManager implements Action.Container, Action.Handler,

private void requestRepaint() {
if (viewer != null) {
viewer.requestRepaint();
viewer.markAsDirty();
}
}


+ 77
- 33
server/src/com/vaadin/terminal/AbstractClientConnector.java View File

@@ -31,16 +31,19 @@ import java.util.NoSuchElementException;
import java.util.logging.Logger;

import com.vaadin.Application;
import com.vaadin.external.json.JSONException;
import com.vaadin.external.json.JSONObject;
import com.vaadin.shared.communication.ClientRpc;
import com.vaadin.shared.communication.ServerRpc;
import com.vaadin.shared.communication.SharedState;
import com.vaadin.terminal.gwt.server.AbstractCommunicationManager;
import com.vaadin.terminal.gwt.server.ClientConnector;
import com.vaadin.terminal.gwt.server.ClientMethodInvocation;
import com.vaadin.terminal.gwt.server.RpcManager;
import com.vaadin.terminal.gwt.server.RpcTarget;
import com.vaadin.terminal.gwt.server.ServerRpcManager;
import com.vaadin.ui.HasComponents;
import com.vaadin.ui.Root;
import com.vaadin.ui.UI;

/**
* An abstract base class for ClientConnector implementations. This class
@@ -68,6 +71,8 @@ public abstract class AbstractClientConnector implements ClientConnector {
*/
private SharedState sharedState;

private Class<? extends SharedState> stateType;

/**
* Pending RPC method invocations to be sent.
*/
@@ -80,11 +85,18 @@ public abstract class AbstractClientConnector implements ClientConnector {
private ClientConnector parent;

/* Documentation copied from interface */
@Deprecated
@Override
public void requestRepaint() {
Root root = getRoot();
if (root != null) {
root.getConnectorTracker().markDirty(this);
markAsDirty();
}

/* Documentation copied from interface */
@Override
public void markAsDirty() {
UI uI = getUI();
if (uI != null) {
uI.getConnectorTracker().markDirty(this);
}
}

@@ -137,14 +149,24 @@ public abstract class AbstractClientConnector implements ClientConnector {
registerRpc(implementation, type);
}

@Override
public SharedState getState() {
protected SharedState getState() {
if (null == sharedState) {
sharedState = createState();
}

UI uI = getUI();
if (uI != null && !uI.getConnectorTracker().isDirty(this)) {
requestRepaint();
}

return sharedState;
}

@Override
public JSONObject encodeState() throws JSONException {
return AbstractCommunicationManager.encodeState(this, getState());
}

/**
* Creates the shared state bean to be used in server to client
* communication.
@@ -172,17 +194,33 @@ public abstract class AbstractClientConnector implements ClientConnector {
}
}

/*
* (non-Javadoc)
*
* @see com.vaadin.terminal.gwt.server.ClientConnector#getStateType()
*/
@Override
public Class<? extends SharedState> getStateType() {
// Lazy load because finding type can be expensive because of the
// exceptions flying around
if (stateType == null) {
stateType = findStateType();
}

return stateType;
}

private Class<? extends SharedState> findStateType() {
try {
Method m = getClass().getMethod("getState", (Class[]) null);
Class<?> type = m.getReturnType();
return type.asSubclass(SharedState.class);
Class<?> class1 = getClass();
while (class1 != null) {
try {
Method m = class1.getDeclaredMethod("getState",
(Class[]) null);
Class<?> type = m.getReturnType();
return type.asSubclass(SharedState.class);
} catch (NoSuchMethodException nsme) {
// Try in superclass instead
class1 = class1.getSuperclass();
}
}
throw new NoSuchMethodException(getClass().getCanonicalName()
+ ".getState()");
} catch (Exception e) {
throw new RuntimeException("Error finding state type for "
+ getClass().getName(), e);
@@ -255,8 +293,6 @@ public abstract class AbstractClientConnector implements ClientConnector {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
addMethodInvocationToQueue(rpcInterfaceName, method, args);
// TODO no need to do full repaint if only RPC calls
requestRepaint();
return null;
}

@@ -279,6 +315,8 @@ public abstract class AbstractClientConnector implements ClientConnector {
// add to queue
pendingInvocations.add(new ClientMethodInvocation(this, interfaceName,
method, parameters));
// TODO no need to do full repaint if only RPC calls
requestRepaint();
}

/**
@@ -325,28 +363,28 @@ public abstract class AbstractClientConnector implements ClientConnector {
* @return The connector's application, or <code>null</code> if not attached
*/
protected Application getApplication() {
Root root = getRoot();
if (root == null) {
UI uI = getUI();
if (uI == null) {
return null;
} else {
return root.getApplication();
return uI.getApplication();
}
}

/**
* Finds a Root ancestor of this connector. <code>null</code> is returned if
* no Root ancestor is found (typically because the connector is not
* Finds a UI ancestor of this connector. <code>null</code> is returned if
* no UI ancestor is found (typically because the connector is not
* attached to a proper hierarchy).
*
* @return the Root ancestor of this connector, or <code>null</code> if none
* @return the UI ancestor of this connector, or <code>null</code> if none
* is found.
*/
@Override
public Root getRoot() {
public UI getUI() {
ClientConnector connector = this;
while (connector != null) {
if (connector instanceof Root) {
return (Root) connector;
if (connector instanceof UI) {
return (UI) connector;
}
connector = connector.getParent();
}
@@ -358,11 +396,17 @@ public abstract class AbstractClientConnector implements ClientConnector {
}

@Override
@Deprecated
public void requestRepaintAll() {
requestRepaint();
markAsDirtyRecursive();
}

@Override
public void markAsDirtyRecursive() {
markAsDirty();

for (ClientConnector connector : getAllChildrenIterable(this)) {
connector.requestRepaintAll();
connector.markAsDirtyRecursive();
}
}

@@ -438,14 +482,14 @@ public abstract class AbstractClientConnector implements ClientConnector {

extensions.add(extension);
extension.setParent(this);
requestRepaint();
markAsDirty();
}

@Override
public void removeExtension(Extension extension) {
extension.setParent(null);
extensions.remove(extension);
requestRepaint();
markAsDirty();
}

@Override
@@ -482,9 +526,9 @@ public abstract class AbstractClientConnector implements ClientConnector {

@Override
public void attach() {
requestRepaint();
markAsDirty();

getRoot().getConnectorTracker().registerConnector(this);
getUI().getConnectorTracker().registerConnector(this);

for (ClientConnector connector : getAllChildrenIterable(this)) {
connector.attach();
@@ -496,7 +540,7 @@ public abstract class AbstractClientConnector implements ClientConnector {
* {@inheritDoc}
*
* <p>
* The {@link #getApplication()} and {@link #getRoot()} methods might return
* The {@link #getApplication()} and {@link #getUI()} methods might return
* <code>null</code> after this method is called.
* </p>
*/
@@ -506,7 +550,7 @@ public abstract class AbstractClientConnector implements ClientConnector {
connector.detach();
}

getRoot().getConnectorTracker().unregisterConnector(this);
getUI().getConnectorTracker().unregisterConnector(this);
}

@Override

+ 1
- 1
server/src/com/vaadin/terminal/AbstractJavaScriptExtension.java View File

@@ -166,7 +166,7 @@ public abstract class AbstractJavaScriptExtension extends AbstractExtension {
}

@Override
public JavaScriptExtensionState getState() {
protected JavaScriptExtensionState getState() {
return (JavaScriptExtensionState) super.getState();
}
}

server/src/com/vaadin/terminal/AbstractRootProvider.java → server/src/com/vaadin/terminal/AbstractUIProvider.java View File

@@ -17,13 +17,13 @@
package com.vaadin.terminal;
import com.vaadin.Application;
import com.vaadin.ui.Root;
import com.vaadin.ui.UI;
public abstract class AbstractRootProvider implements RootProvider {
public abstract class AbstractUIProvider implements UIProvider {
@Override
public Root instantiateRoot(Application application,
Class<? extends Root> type, WrappedRequest request) {
public UI instantiateUI(Application application,
Class<? extends UI> type, WrappedRequest request) {
try {
return type.newInstance();
} catch (InstantiationException e) {

server/src/com/vaadin/terminal/DefaultRootProvider.java → server/src/com/vaadin/terminal/DefaultUIProvider.java View File

@@ -17,19 +17,19 @@
package com.vaadin.terminal;
import com.vaadin.Application;
import com.vaadin.RootRequiresMoreInformationException;
import com.vaadin.ui.Root;
import com.vaadin.UIRequiresMoreInformationException;
import com.vaadin.ui.UI;
public class DefaultRootProvider extends AbstractRootProvider {
public class DefaultUIProvider extends AbstractUIProvider {
@Override
public Class<? extends Root> getRootClass(Application application,
WrappedRequest request) throws RootRequiresMoreInformationException {
Object rootClassNameObj = application
.getProperty(Application.ROOT_PARAMETER);
public Class<? extends UI> getUIClass(Application application,
WrappedRequest request) throws UIRequiresMoreInformationException {
Object uiClassNameObj = application
.getProperty(Application.UI_PARAMETER);
if (rootClassNameObj instanceof String) {
String rootClassName = rootClassNameObj.toString();
if (uiClassNameObj instanceof String) {
String uiClassName = uiClassNameObj.toString();
ClassLoader classLoader = request.getDeploymentConfiguration()
.getClassLoader();
@@ -37,12 +37,12 @@ public class DefaultRootProvider extends AbstractRootProvider {
classLoader = getClass().getClassLoader();
}
try {
Class<? extends Root> rootClass = Class.forName(rootClassName,
true, classLoader).asSubclass(Root.class);
Class<? extends UI> uiClass = Class.forName(uiClassName, true,
classLoader).asSubclass(UI.class);
return rootClass;
return uiClass;
} catch (ClassNotFoundException e) {
throw new RuntimeException("Could not find root class", e);
throw new RuntimeException("Could not find UI class", e);
}
}

+ 6
- 6
server/src/com/vaadin/terminal/DeploymentConfiguration.java View File

@@ -98,7 +98,7 @@ public interface DeploymentConfiguration extends Serializable {

/**
* Get the class loader to use for loading classes loaded by name, e.g.
* custom Root classes. <code>null</code> indicates that the default class
* custom UI classes. <code>null</code> indicates that the default class
* loader should be used.
*
* @return the class loader to use, or <code>null</code>
@@ -162,7 +162,7 @@ public interface DeploymentConfiguration extends Serializable {
public int getResourceCacheTime();

/**
* Returns the number of seconds between heartbeat requests of a root, or a
* Returns the number of seconds between heartbeat requests of a UI, or a
* non-positive number if heartbeat is disabled.
*
* @since 7.0.0
@@ -172,7 +172,7 @@ public interface DeploymentConfiguration extends Serializable {
public int getHeartbeatInterval();

/**
* Returns whether roots that have no other activity than heartbeat requests
* Returns whether UIs that have no other activity than heartbeat requests
* should be closed after they have been idle the maximum inactivity time
* enforced by the session.
*
@@ -180,9 +180,9 @@ public interface DeploymentConfiguration extends Serializable {
*
* @since 7.0.0
*
* @return True if roots receiving only heartbeat requests are eventually
* closed; false if heartbeat requests extend root lifetime
* @return True if UIs receiving only heartbeat requests are eventually
* closed; false if heartbeat requests extend UI lifetime
* indefinitely.
*/
public boolean isIdleRootCleanupEnabled();
public boolean isIdleUICleanupEnabled();
}

+ 1
- 5
server/src/com/vaadin/terminal/JavaScriptCallbackHelper.java View File

@@ -60,9 +60,7 @@ public class JavaScriptCallbackHelper implements Serializable {
JavaScriptFunction javaScriptCallback) {
callbacks.put(functionName, javaScriptCallback);
JavaScriptConnectorState state = getConnectorState();
if (state.getCallbackNames().add(functionName)) {
connector.requestRepaint();
}
state.getCallbackNames().add(functionName);
ensureRpc();
}

@@ -100,7 +98,6 @@ public class JavaScriptCallbackHelper implements Serializable {
connector.addMethodInvocationToQueue(
JavaScriptCallbackRpc.class.getName(), CALL_METHOD,
new Object[] { name, args });
connector.requestRepaint();
}

public void registerRpc(Class<?> rpcInterfaceType) {
@@ -119,7 +116,6 @@ public class JavaScriptCallbackHelper implements Serializable {
}

rpcInterfaces.put(interfaceName, methodNames);
connector.requestRepaint();
}
}


+ 43
- 43
server/src/com/vaadin/terminal/Page.java View File

@@ -25,27 +25,27 @@ import java.util.List;

import com.vaadin.event.EventRouter;
import com.vaadin.shared.ui.BorderStyle;
import com.vaadin.shared.ui.root.PageClientRpc;
import com.vaadin.shared.ui.root.RootConstants;
import com.vaadin.shared.ui.ui.PageClientRpc;
import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.terminal.WrappedRequest.BrowserDetails;
import com.vaadin.terminal.gwt.server.WebApplicationContext;
import com.vaadin.terminal.gwt.server.WebBrowser;
import com.vaadin.tools.ReflectTools;
import com.vaadin.ui.JavaScript;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Root;
import com.vaadin.ui.UI;

public class Page implements Serializable {

/**
* Listener that gets notified when the size of the browser window
* containing the root has changed.
* containing the uI has changed.
*
* @see Root#addListener(BrowserWindowResizeListener)
* @see UI#addListener(BrowserWindowResizeListener)
*/
public interface BrowserWindowResizeListener extends Serializable {
/**
* Invoked when the browser window containing a Root has been resized.
* Invoked when the browser window containing a UI has been resized.
*
* @param event
* a browser window resize event
@@ -54,7 +54,7 @@ public class Page implements Serializable {
}

/**
* Event that is fired when a browser window containing a root is resized.
* Event that is fired when a browser window containing a uI is resized.
*/
public class BrowserWindowResizeEvent extends EventObject {

@@ -65,7 +65,7 @@ public class Page implements Serializable {
* Creates a new event
*
* @param source
* the root for which the browser window has been resized
* the uI for which the browser window has been resized
* @param width
* the new width of the browser window
* @param height
@@ -254,9 +254,9 @@ public class Page implements Serializable {
}

/**
* Gets the root in which the fragment has changed.
* Gets the uI in which the fragment has changed.
*
* @return the root in which the fragment has changed
* @return the uI in which the fragment has changed
*/
public Page getPage() {
return (Page) getSource();
@@ -279,15 +279,15 @@ public class Page implements Serializable {
*/
private String fragment;

private final Root root;
private final UI uI;

private int browserWindowWidth = -1;
private int browserWindowHeight = -1;

private JavaScript javaScript;

public Page(Root root) {
this.root = root;
public Page(UI uI) {
this.uI = uI;
}

private void addListener(Class<?> eventType, Object target, Method method) {
@@ -332,7 +332,7 @@ public class Page implements Serializable {
if (fireEvents) {
fireEvent(new FragmentChangedEvent(this, newFragment));
}
root.requestRepaint();
uI.markAsDirty();
}
}

@@ -374,7 +374,7 @@ public class Page implements Serializable {
}

public WebBrowser getWebBrowser() {
return ((WebApplicationContext) root.getApplication().getContext())
return ((WebApplicationContext) uI.getApplication().getContext())
.getBrowser();
}

@@ -399,8 +399,8 @@ public class Page implements Serializable {
}

/**
* Adds a new {@link BrowserWindowResizeListener} to this root. The listener
* will be notified whenever the browser window within which this root
* Adds a new {@link BrowserWindowResizeListener} to this uI. The listener
* will be notified whenever the browser window within which this uI
* resides is resized.
*
* @param resizeListener
@@ -415,7 +415,7 @@ public class Page implements Serializable {
}

/**
* Removes a {@link BrowserWindowResizeListener} from this root. The
* Removes a {@link BrowserWindowResizeListener} from this uI. The
* listener will no longer be notified when the browser window is resized.
*
* @param resizeListener
@@ -427,7 +427,7 @@ public class Page implements Serializable {
}

/**
* Gets the last known height of the browser window in which this root
* Gets the last known height of the browser window in which this uI
* resides.
*
* @return the browser window height in pixels
@@ -437,7 +437,7 @@ public class Page implements Serializable {
}

/**
* Gets the last known width of the browser window in which this root
* Gets the last known width of the browser window in which this uI
* resides.
*
* @return the browser window width in pixels
@@ -450,7 +450,7 @@ public class Page implements Serializable {
if (javaScript == null) {
// Create and attach on first use
javaScript = new JavaScript();
javaScript.extend(root);
javaScript.extend(uI);
}

return javaScript;
@@ -474,32 +474,32 @@ public class Page implements Serializable {
target.startTag("notification");
if (n.getCaption() != null) {
target.addAttribute(
RootConstants.ATTRIBUTE_NOTIFICATION_CAPTION,
UIConstants.ATTRIBUTE_NOTIFICATION_CAPTION,
n.getCaption());
}
if (n.getDescription() != null) {
target.addAttribute(
RootConstants.ATTRIBUTE_NOTIFICATION_MESSAGE,
UIConstants.ATTRIBUTE_NOTIFICATION_MESSAGE,
n.getDescription());
}
if (n.getIcon() != null) {
target.addAttribute(
RootConstants.ATTRIBUTE_NOTIFICATION_ICON,
UIConstants.ATTRIBUTE_NOTIFICATION_ICON,
n.getIcon());
}
if (!n.isHtmlContentAllowed()) {
target.addAttribute(
RootConstants.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED,
UIConstants.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED,
true);
}
target.addAttribute(
RootConstants.ATTRIBUTE_NOTIFICATION_POSITION,
n.getPosition());
target.addAttribute(RootConstants.ATTRIBUTE_NOTIFICATION_DELAY,
UIConstants.ATTRIBUTE_NOTIFICATION_POSITION, n
.getPosition().ordinal());
target.addAttribute(UIConstants.ATTRIBUTE_NOTIFICATION_DELAY,
n.getDelayMsec());
if (n.getStyleName() != null) {
target.addAttribute(
RootConstants.ATTRIBUTE_NOTIFICATION_STYLE,
UIConstants.ATTRIBUTE_NOTIFICATION_STYLE,
n.getStyleName());
}
target.endTag("notification");
@@ -509,21 +509,21 @@ public class Page implements Serializable {
}

if (fragment != null) {
target.addAttribute(RootConstants.FRAGMENT_VARIABLE, fragment);
target.addAttribute(UIConstants.FRAGMENT_VARIABLE, fragment);
}

}

/**
* Opens the given resource in this root. The contents of this Root is
* Opens the given resource in this uI. The contents of this UI is
* replaced by the {@code Resource}.
*
* @param resource
* the resource to show in this root
* the resource to show in this uI
*/
public void open(Resource resource) {
openList.add(new OpenResource(resource, null, -1, -1, BORDER_DEFAULT));
root.requestRepaint();
uI.markAsDirty();
}

/**
@@ -566,7 +566,7 @@ public class Page implements Serializable {
public void open(Resource resource, String windowName) {
openList.add(new OpenResource(resource, windowName, -1, -1,
BORDER_DEFAULT));
root.requestRepaint();
uI.markAsDirty();
}

/**
@@ -589,7 +589,7 @@ public class Page implements Serializable {
int height, BorderStyle border) {
openList.add(new OpenResource(resource, windowName, width, height,
border));
root.requestRepaint();
uI.markAsDirty();
}

/**
@@ -603,7 +603,7 @@ public class Page implements Serializable {
notifications = new LinkedList<Notification>();
}
notifications.add(notification);
root.requestRepaint();
uI.markAsDirty();
}

/**
@@ -622,21 +622,21 @@ public class Page implements Serializable {
}

/**
* Gets the Page to which the current root belongs. This is automatically
* Gets the Page to which the current uI belongs. This is automatically
* defined when processing requests to the server. In other cases, (e.g.
* from background threads), the current root is not automatically defined.
* from background threads), the current uI is not automatically defined.
*
* @see Root#getCurrent()
* @see UI#getCurrent()
*
* @return the current page instance if available, otherwise
* <code>null</code>
*/
public static Page getCurrent() {
Root currentRoot = Root.getCurrent();
if (currentRoot == null) {
UI currentUI = UI.getCurrent();
if (currentUI == null) {
return null;
}
return currentRoot.getPage();
return currentUI.getPage();
}

/**
@@ -647,7 +647,7 @@ public class Page implements Serializable {
* the new page title to set
*/
public void setTitle(String title) {
root.getRpcProxy(PageClientRpc.class).setTitle(title);
uI.getRpcProxy(PageClientRpc.class).setTitle(title);
}

}

server/src/com/vaadin/terminal/RootProvider.java → server/src/com/vaadin/terminal/UIProvider.java View File

@@ -17,13 +17,13 @@
package com.vaadin.terminal;
import com.vaadin.Application;
import com.vaadin.RootRequiresMoreInformationException;
import com.vaadin.ui.Root;
import com.vaadin.UIRequiresMoreInformationException;
import com.vaadin.ui.UI;
public interface RootProvider {
public Class<? extends Root> getRootClass(Application application,
WrappedRequest request) throws RootRequiresMoreInformationException;
public interface UIProvider {
public Class<? extends UI> getUIClass(Application application,
WrappedRequest request) throws UIRequiresMoreInformationException;
public Root instantiateRoot(Application application,
Class<? extends Root> type, WrappedRequest request);
public UI instantiateUI(Application application,
Class<? extends UI> type, WrappedRequest request);
}

+ 11
- 0
server/src/com/vaadin/terminal/Vaadin6Component.java View File

@@ -52,4 +52,15 @@ public interface Vaadin6Component extends VariableOwner, Component,
*/
public void paintContent(PaintTarget target) throws PaintException;

/**
* (non-Javadoc) {@inheritDoc}
* <p>
* For a Vaadin6Component, markAsDirty will also cause
* {@link #paintContent(PaintTarget)} to be called before sending changes to
* the client.
*
* @see com.vaadin.terminal.gwt.server.ClientConnector#markAsDirty()
*/
@Override
public void markAsDirty();
}

+ 6
- 5
server/src/com/vaadin/terminal/WrappedRequest.java View File

@@ -27,10 +27,10 @@ import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;

import com.vaadin.Application;
import com.vaadin.RootRequiresMoreInformationException;
import com.vaadin.UIRequiresMoreInformationException;
import com.vaadin.annotations.EagerInit;
import com.vaadin.terminal.gwt.server.WebBrowser;
import com.vaadin.ui.Root;
import com.vaadin.ui.UI;

/**
* A generic request to the server, wrapping a more specific request type, e.g.
@@ -219,9 +219,10 @@ public interface WrappedRequest extends Serializable {
* for instance using javascript in the browser.
*
* This information is only guaranteed to be available in some special
* cases, for instance when {@link Application#getRoot} is called again
* after throwing {@link RootRequiresMoreInformationException} or in
* {@link Root#init(WrappedRequest)} for a Root class not annotated with
* cases, for instance when
* {@link Application#getUIForRequest(WrappedRequest)} is called again after
* throwing {@link UIRequiresMoreInformationException} or in
* {@link UI#init(WrappedRequest)} for a UI class not annotated with
* {@link EagerInit}
*
* @return the browser details, or <code>null</code> if details are not

+ 22
- 24
server/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java View File

@@ -56,13 +56,13 @@ import com.liferay.portal.kernel.util.PropsUtil;
import com.vaadin.Application;
import com.vaadin.Application.ApplicationStartEvent;
import com.vaadin.Application.SystemMessages;
import com.vaadin.RootRequiresMoreInformationException;
import com.vaadin.UIRequiresMoreInformationException;
import com.vaadin.terminal.DeploymentConfiguration;
import com.vaadin.terminal.Terminal;
import com.vaadin.terminal.WrappedRequest;
import com.vaadin.terminal.WrappedResponse;
import com.vaadin.terminal.gwt.server.AbstractCommunicationManager.Callback;
import com.vaadin.ui.Root;
import com.vaadin.ui.UI;

/**
* Portlet 2.0 base class. This replaces the servlet in servlet/portlet 1.0
@@ -496,36 +496,35 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
/* Notify listeners */

// Finds the window within the application
Root root = null;
UI uI = null;
synchronized (application) {
if (application.isRunning()) {
switch (requestType) {
case RENDER:
case ACTION:
// Both action requests and render requests are ok
// without a Root as they render the initial HTML
// without a UI as they render the initial HTML
// and then do a second request
try {
root = application
.getRootForRequest(wrappedRequest);
} catch (RootRequiresMoreInformationException e) {
// Ignore problem and continue without root
uI = application
.getUIForRequest(wrappedRequest);
} catch (UIRequiresMoreInformationException e) {
// Ignore problem and continue without UI
}
break;
case BROWSER_DETAILS:
// Should not try to find a root here as the
// combined request details might change the root
// Should not try to find a UI here as the
// combined request details might change the UI
break;
case FILE_UPLOAD:
// no window
break;
case APPLICATION_RESOURCE:
// use main window - should not need any window
// root = application.getRoot();
// UI = application.getUI();
break;
default:
root = application
.getRootForRequest(wrappedRequest);
uI = application.getUIForRequest(wrappedRequest);
}
// if window not found, not a problem - use null
}
@@ -535,25 +534,24 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
// starts?
if (request instanceof RenderRequest) {
applicationContext.firePortletRenderRequest(application,
root, (RenderRequest) request,
uI, (RenderRequest) request,
(RenderResponse) response);
} else if (request instanceof ActionRequest) {
applicationContext.firePortletActionRequest(application,
root, (ActionRequest) request,
uI, (ActionRequest) request,
(ActionResponse) response);
} else if (request instanceof EventRequest) {
applicationContext.firePortletEventRequest(application,
root, (EventRequest) request,
(EventResponse) response);
applicationContext.firePortletEventRequest(application, uI,
(EventRequest) request, (EventResponse) response);
} else if (request instanceof ResourceRequest) {
applicationContext.firePortletResourceRequest(application,
root, (ResourceRequest) request,
uI, (ResourceRequest) request,
(ResourceResponse) response);
}

/* Handle the request */
if (requestType == RequestType.FILE_UPLOAD) {
// Root is resolved in handleFileUpload by
// UI is resolved in handleFileUpload by
// PortletCommunicationManager
applicationManager.handleFileUpload(application,
wrappedRequest, wrappedResponse);
@@ -565,7 +563,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
} else if (requestType == RequestType.UIDL) {
// Handles AJAX UIDL requests
applicationManager.handleUidlRequest(wrappedRequest,
wrappedResponse, portletWrapper, root);
wrappedResponse, portletWrapper, uI);
return;
} else {
/*
@@ -595,7 +593,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
} finally {

if (applicationRunning) {
application.closeInactiveRoots();
application.closeInactiveUIs();
}

// Notifies transaction end
@@ -612,7 +610,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet

}
} finally {
Root.setCurrent(null);
UI.setCurrent(null);
Application.setCurrent(null);

PortletSession session = request
@@ -908,7 +906,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
throws PortletException {
try {
final Application application = getApplicationClass().newInstance();
application.setRootPreserved(true);
application.setUiPreserved(true);
return application;
} catch (final IllegalAccessException e) {
throw new PortletException("getNewApplication failed", e);

+ 0
- 0
server/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save