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.javatags/7.0.0.beta1
@@ -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 --> |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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(")"); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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("\\.", "_"); | |||
} | |||
} |
@@ -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"); | |||
} | |||
} |
@@ -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("}"); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} |
@@ -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;"); | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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(");"); | |||
} | |||
} |
@@ -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());"); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -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()); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -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 --> |
@@ -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(); | |||
} | |||
/** |
@@ -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); | |||
@@ -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) |
@@ -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(); | |||
} |
@@ -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() + ")"); |
@@ -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(); | |||
} | |||
}); | |||
} | |||
} | |||
} |
@@ -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> { | |||
/** |
@@ -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); | |||
} |
@@ -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 |
@@ -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); | |||
} | |||
} | |||
} | |||
@@ -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); | |||
} | |||
} | |||
} |
@@ -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, |
@@ -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); | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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> { | |||
@@ -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; | |||
} | |||
} |
@@ -0,0 +1,11 @@ | |||
/* | |||
@VaadinApache2LicenseForJavaFiles@ | |||
*/ | |||
package com.vaadin.terminal.gwt.client.metadata; | |||
public interface BundleLoadCallback { | |||
public void loaded(); | |||
public void failed(Throwable reason); | |||
} |
@@ -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(); | |||
} |
@@ -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); | |||
} |
@@ -0,0 +1,9 @@ | |||
/* | |||
@VaadinApache2LicenseForJavaFiles@ | |||
*/ | |||
package com.vaadin.terminal.gwt.client.metadata; | |||
public interface Invoker { | |||
public Object invoke(Object target, Object... params); | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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"); |
@@ -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 |
@@ -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(); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); |
@@ -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 |
@@ -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); | |||
@@ -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 |
@@ -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 { |
@@ -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()); | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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); | |||
} | |||
}; | |||
} |
@@ -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"); | |||
} | |||
} |
@@ -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(""); |
@@ -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); | |||
} | |||
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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() |
@@ -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(); |
@@ -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; |
@@ -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 | |||
} |
@@ -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 |
@@ -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) |
@@ -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) |
@@ -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> |
@@ -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; | |||
} | |||
} |
@@ -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."); |
@@ -67,7 +67,7 @@ public class ActionManager implements Action.Container, Action.Handler, | |||
private void requestRepaint() { | |||
if (viewer != null) { | |||
viewer.requestRepaint(); | |||
viewer.markAsDirty(); | |||
} | |||
} | |||
@@ -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 |
@@ -166,7 +166,7 @@ public abstract class AbstractJavaScriptExtension extends AbstractExtension { | |||
} | |||
@Override | |||
public JavaScriptExtensionState getState() { | |||
protected JavaScriptExtensionState getState() { | |||
return (JavaScriptExtensionState) super.getState(); | |||
} | |||
} |
@@ -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) { |
@@ -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); | |||
} | |||
} | |||
@@ -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(); | |||
} |
@@ -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(); | |||
} | |||
} | |||
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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(); | |||
} |
@@ -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 |
@@ -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); |