Browse Source

Remove WidgetMapGenerator and subclasses (#9720)

tags/7.0.0.beta2
Leif Åstrand 11 years ago
parent
commit
0985dac7be

+ 0
- 96
client-compiler/src/com/vaadin/server/widgetsetutils/CustomWidgetMapGenerator.java View File

@@ -1,96 +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.server.widgetsetutils;

import java.util.Collection;
import java.util.HashSet;

import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ServerConnector;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.Connect.LoadStyle;

/**
* An abstract helper class that can be used to easily build a widgetset with
* customized load styles for each components. In three abstract methods one can
* override the default values given in {@link Connect} annotations.
*
* @see WidgetMapGenerator
*
*/
public abstract class CustomWidgetMapGenerator extends WidgetMapGenerator {

private Collection<Class<? extends ComponentConnector>> eagerPaintables = new HashSet<Class<? extends ComponentConnector>>();
private Collection<Class<? extends ComponentConnector>> lazyPaintables = new HashSet<Class<? extends ComponentConnector>>();
private Collection<Class<? extends ComponentConnector>> deferredPaintables = new HashSet<Class<? extends ComponentConnector>>();

@Override
protected LoadStyle getLoadStyle(Class<? extends ServerConnector> connector) {
if (eagerPaintables == null) {
init();
}
if (eagerPaintables.contains(connector)) {
return LoadStyle.EAGER;
}
if (lazyPaintables.contains(connector)) {
return LoadStyle.LAZY;
}
if (deferredPaintables.contains(connector)) {
return LoadStyle.DEFERRED;
}
return super.getLoadStyle(connector);
}

private void init() {
Class<? extends ComponentConnector>[] eagerComponents = getEagerComponents();
if (eagerComponents != null) {
for (Class<? extends ComponentConnector> class1 : eagerComponents) {
eagerPaintables.add(class1);
}
}
Class<? extends ComponentConnector>[] lazyComponents = getEagerComponents();
if (lazyComponents != null) {
for (Class<? extends ComponentConnector> class1 : lazyComponents) {
lazyPaintables.add(class1);
}
}
Class<? extends ComponentConnector>[] deferredComponents = getEagerComponents();
if (deferredComponents != null) {
for (Class<? extends ComponentConnector> class1 : deferredComponents) {
deferredPaintables.add(class1);
}
}
}

/**
* @return an array of components whose load style should be overridden to
* {@link LoadStyle#EAGER}
*/
protected abstract Class<? extends ComponentConnector>[] getEagerComponents();

/**
* @return an array of components whose load style should be overridden to
* {@link LoadStyle#LAZY}
*/
protected abstract Class<? extends ComponentConnector>[] getLazyComponents();

/**
* @return an array of components whose load style should be overridden to
* {@link LoadStyle#DEFERRED}
*/
protected abstract Class<? extends ComponentConnector>[] getDeferredComponents();

}

+ 0
- 41
client-compiler/src/com/vaadin/server/widgetsetutils/EagerWidgetMapGenerator.java View File

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

import com.vaadin.client.ServerConnector;
import com.vaadin.shared.ui.Connect.LoadStyle;

/**
* WidgetMap generator that builds a widgetset that packs all included widgets
* into a single JavaScript file loaded at application initialization. Initially
* loaded data will be relatively large, but minimal amount of server requests
* will be done.
* <p>
* This is the default generator in version 6.4 and produces similar type of
* widgetset as in previous versions of Vaadin. To activate "code splitting",
* use the {@link WidgetMapGenerator} instead, that loads most components
* deferred.
*
* @see WidgetMapGenerator
*
*/
public class EagerWidgetMapGenerator extends WidgetMapGenerator {

@Override
protected LoadStyle getLoadStyle(Class<? extends ServerConnector> connector) {
return LoadStyle.EAGER;
}
}

+ 0
- 35
client-compiler/src/com/vaadin/server/widgetsetutils/LazyWidgetMapGenerator.java View File

@@ -1,35 +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.server.widgetsetutils;

import com.vaadin.client.ServerConnector;
import com.vaadin.shared.ui.Connect.LoadStyle;

/**
* WidgetMap generator that builds a widgetset that optimizes the transferred
* data. Widgets are loaded only when used if the widgetset is built with this
* generator.
*
* @see WidgetMapGenerator
*
*/
public class LazyWidgetMapGenerator extends WidgetMapGenerator {
@Override
protected LoadStyle getLoadStyle(Class<? extends ServerConnector> connector) {
return LoadStyle.LAZY;
}

}

+ 0
- 434
client-compiler/src/com/vaadin/server/widgetsetutils/WidgetMapGenerator.java View File

@@ -1,434 +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.server.widgetsetutils;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeSet;

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.client.ServerConnector;
import com.vaadin.client.ui.UnknownComponentConnector;
import com.vaadin.client.ui.ui.UIConnector;
import com.vaadin.server.ClientConnector;
import com.vaadin.shared.Connector;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.Connect.LoadStyle;

/**
* WidgetMapGenerator's are GWT generator to build WidgetMapImpl dynamically
* based on {@link Connect} annotations available in workspace. By modifying the
* generator it is possible to do some fine tuning for the generated widgetset
* (aka client side engine). The components to be included in the client side
* engine can modified be overriding {@link #getUsedConnectors()}.
* <p>
* The generator also decides how the client side component implementations are
* loaded to the browser. The default generator is
* {@link EagerWidgetMapGenerator} that builds a monolithic client side engine
* that loads all widget implementation on application initialization. This has
* been the only option until Vaadin 6.4.
* <p>
* This generator uses the loadStyle hints from the {@link Connect} annotations.
* Depending on the {@link LoadStyle} used, the widget may be included in the
* initially loaded JavaScript, loaded when the application has started and
* there is no communication to server or lazy loaded when the implementation is
* absolutely needed.
* <p>
* The GWT module description file of the widgetset (
* <code>...Widgetset.gwt.xml</code>) can be used to define the
* WidgetMapGenarator. An example that defines this generator to be used:
*
* <pre>
* <code>
* &lt;generate-with
* class="com.vaadin.server.widgetsetutils.MyWidgetMapGenerator"&gt;
* &lt;when-type-is class="com.vaadin.client.WidgetMap" /&gt;
* &lt;/generate-with&gt;
*
* </code>
* </pre>
*
* <p>
* Vaadin package also includes {@link LazyWidgetMapGenerator}, which is a good
* option if the transferred data should be minimized, and
* {@link CustomWidgetMapGenerator} for easy overriding of loading strategies.
*
*/
public class WidgetMapGenerator extends Generator {

private static String serverConnectorClassName = ServerConnector.class
.getName();

private String packageName;
private String className;

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

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
generateClass(logger, context);
} catch (Exception e) {
logger.log(TreeLogger.ERROR, "WidgetMap creation failed", e);
}
// return the fully qualifed name of the class generated
return packageName + "." + className;
}

/**
* Generate source code for WidgetMapImpl
*
* @param logger
* Logger object
* @param context
* Generator context
* @throws UnableToCompleteException
*/
private void generateClass(TreeLogger logger, GeneratorContext context)
throws UnableToCompleteException {
// 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,
// return (WidgetMap is equal to all permutations atm)
if (printWriter == null) {
return;
}
logger.log(Type.INFO,
"Detecting Vaadin connectors in classpath to generate WidgetMapImpl.java ...");
Date date = new Date();

// 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("java.util.HashMap");
composer.addImport("com.google.gwt.core.client.RunAsyncCallback");
composer.setSuperclass("com.vaadin.client.WidgetMap");
SourceWriter sourceWriter = composer.createSourceWriter(context,
printWriter);

Collection<Class<? extends ServerConnector>> connectors = getUsedConnectors(context
.getTypeOracle());

validateConnectors(logger, connectors);
logConnectors(logger, context, connectors);

// generator constructor source code
generateImplementationDetector(logger, sourceWriter, connectors);
generateInstantiatorMethod(sourceWriter, connectors);
// 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)");

}

private void validateConnectors(TreeLogger logger,
Collection<Class<? extends ServerConnector>> connectors) {

Iterator<Class<? extends ServerConnector>> iter = connectors.iterator();
while (iter.hasNext()) {
Class<? extends ServerConnector> connectorClass = iter.next();
Connect annotation = connectorClass.getAnnotation(Connect.class);
if (!ClientConnector.class.isAssignableFrom(annotation.value())) {
logger.log(
Type.WARN,
"Connector class "
+ annotation.value().getName()
+ " defined in @Connect annotation is not a subclass of "
+ ClientConnector.class.getName()
+ ". The component connector "
+ connectorClass.getName()
+ " will not be included in the widgetset.");
iter.remove();
}
}

}

private void logConnectors(TreeLogger logger, GeneratorContext context,
Collection<Class<? extends ServerConnector>> connectors) {
logger.log(Type.INFO,
"Widget set will contain implementations for following component connectors: ");

TreeSet<String> classNames = new TreeSet<String>();
HashMap<String, String> loadStyle = new HashMap<String, String>();
for (Class<? extends ServerConnector> connectorClass : connectors) {
String className = connectorClass.getCanonicalName();
classNames.add(className);
if (getLoadStyle(connectorClass) == LoadStyle.DEFERRED) {
loadStyle.put(className, "DEFERRED");
} else if (getLoadStyle(connectorClass) == LoadStyle.LAZY) {
loadStyle.put(className, "LAZY");
}

}
for (String className : classNames) {
String msg = className;
if (loadStyle.containsKey(className)) {
msg += " (load style: " + loadStyle.get(className) + ")";
}
logger.log(Type.INFO, "\t" + msg);
}
}

/**
* This method is protected to allow creation of optimized widgetsets. The
* Widgetset will contain only implementation returned by this function. If
* one knows which widgets are needed for the application, returning only
* them here will significantly optimize the size of the produced JS.
*
* @return a collections of Vaadin components that will be added to
* widgetset
*/
@SuppressWarnings("unchecked")
private Collection<Class<? extends ServerConnector>> getUsedConnectors(
TypeOracle typeOracle) {
JClassType connectorType = typeOracle.findType(Connector.class
.getName());
Collection<Class<? extends ServerConnector>> connectors = new HashSet<Class<? extends ServerConnector>>();
for (JClassType jClassType : connectorType.getSubtypes()) {
Connect annotation = jClassType.getAnnotation(Connect.class);
if (annotation != null) {
try {
Class<? extends ServerConnector> clazz = (Class<? extends ServerConnector>) Class
.forName(jClassType.getQualifiedSourceName());
connectors.add(clazz);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
return connectors;
}

/**
* Returns true if the widget for given component will be lazy loaded by the
* client. The default implementation reads the information from the
* {@link Connect} annotation.
* <p>
* The method can be overridden to optimize the widget loading mechanism. If
* the Widgetset is wanted to be optimized for a network with a high latency
* or for a one with a very fast throughput, it may be good to return false
* for every component.
*
* @param connector
* @return true iff the widget for given component should be lazy loaded by
* the client side engine
*/
protected LoadStyle getLoadStyle(Class<? extends ServerConnector> connector) {
Connect annotation = connector.getAnnotation(Connect.class);
return annotation.loadStyle();
}

private void generateInstantiatorMethod(
SourceWriter sourceWriter,
Collection<Class<? extends ServerConnector>> connectorsHavingComponentAnnotation) {

Collection<Class<?>> deferredWidgets = new LinkedList<Class<?>>();

// TODO detect if it would be noticably faster to instantiate with a
// lookup with index than with the hashmap

sourceWriter.println("public void ensureInstantiator(Class<? extends "
+ serverConnectorClassName + "> classType) {");
sourceWriter.println("if(!instmap.containsKey(classType)){");
boolean first = true;

ArrayList<Class<? extends ServerConnector>> lazyLoadedConnectors = new ArrayList<Class<? extends ServerConnector>>();

HashSet<Class<? extends ServerConnector>> connectorsWithInstantiator = new HashSet<Class<? extends ServerConnector>>();

for (Class<? extends ServerConnector> class1 : connectorsHavingComponentAnnotation) {
Class<? extends ServerConnector> clientClass = class1;
if (connectorsWithInstantiator.contains(clientClass)) {
continue;
}
if (clientClass == UIConnector.class) {
// Roots are not instantiated by widgetset
continue;
}
if (!first) {
sourceWriter.print(" else ");
} else {
first = false;
}
sourceWriter.print("if( classType == " + clientClass.getName()
+ ".class) {");

String instantiator = "new WidgetInstantiator() {\n public "
+ serverConnectorClassName
+ " get() {\n return GWT.create(" + clientClass.getName()
+ ".class );\n}\n}\n";

LoadStyle loadStyle = getLoadStyle(class1);

if (loadStyle != LoadStyle.EAGER) {
sourceWriter
.print("ApplicationConfiguration.startWidgetLoading();\n"
+ "GWT.runAsync( \n"
+ "new WidgetLoader() { void addInstantiator() {instmap.put("
+ clientClass.getName()
+ ".class,"
+ instantiator + ");}});\n");
lazyLoadedConnectors.add(class1);

if (loadStyle == LoadStyle.DEFERRED) {
deferredWidgets.add(class1);
}

} else {
// widget implementation in initially loaded js script
sourceWriter.print("instmap.put(");
sourceWriter.print(clientClass.getName());
sourceWriter.print(".class, ");
sourceWriter.print(instantiator);
sourceWriter.print(");");
}
sourceWriter.print("}");
connectorsWithInstantiator.add(clientClass);
}

sourceWriter.println("}");

sourceWriter.println("}");

sourceWriter.println("public Class<? extends "
+ serverConnectorClassName
+ ">[] getDeferredLoadedConnectors() {");

sourceWriter.println("return new Class[] {");
first = true;
for (Class<?> class2 : deferredWidgets) {
if (!first) {
sourceWriter.println(",");
}
first = false;
sourceWriter.print(class2.getName() + ".class");
}

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

// in constructor add a "thread" that lazyly loads lazy loaded widgets
// if communication to server idles

// TODO an array of lazy loaded widgets

// TODO an index of last ensured widget in array

sourceWriter.println("public " + serverConnectorClassName
+ " instantiate(Class<? extends " + serverConnectorClassName
+ "> classType) {");
sourceWriter.indent();
sourceWriter.println(serverConnectorClassName
+ " p = super.instantiate(classType); if(p!= null) return p;");
sourceWriter.println("return instmap.get(classType).get();");

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

}

/**
*
* @param logger
* logger to print messages to
* @param sourceWriter
* Source writer to output source code
* @param paintablesHavingWidgetAnnotation
* @throws UnableToCompleteException
*/
private void generateImplementationDetector(
TreeLogger logger,
SourceWriter sourceWriter,
Collection<Class<? extends ServerConnector>> paintablesHavingWidgetAnnotation)
throws UnableToCompleteException {
sourceWriter
.println("public Class<? extends "
+ serverConnectorClassName
+ "> "
+ "getConnectorClassForServerSideClassName(String fullyQualifiedName) {");
sourceWriter.indent();
sourceWriter
.println("fullyQualifiedName = fullyQualifiedName.intern();");

// Keep track of encountered mappings to detect conflicts
Map<Class<? extends ClientConnector>, Class<? extends ServerConnector>> mappings = new HashMap<Class<? extends ClientConnector>, Class<? extends ServerConnector>>();

for (Class<? extends ServerConnector> connectorClass : paintablesHavingWidgetAnnotation) {
Class<? extends ClientConnector> clientConnectorClass = getClientConnectorClass(connectorClass);

// Check for conflicts
Class<? extends ServerConnector> prevousMapping = mappings.put(
clientConnectorClass, connectorClass);
if (prevousMapping != null) {
logger.log(Type.ERROR,
"Both " + connectorClass.getName() + " and "
+ prevousMapping.getName()
+ " have @Connect referring to "
+ clientConnectorClass.getName() + ".");
throw new UnableToCompleteException();
}

sourceWriter.print("if ( fullyQualifiedName == \"");
sourceWriter.print(clientConnectorClass.getName());
sourceWriter.print("\" ) { ensureInstantiator("
+ connectorClass.getName() + ".class); return ");
sourceWriter.print(connectorClass.getName());
sourceWriter.println(".class;}");
sourceWriter.print("else ");
}
sourceWriter.println("return "
+ UnknownComponentConnector.class.getName() + ".class;");
sourceWriter.outdent();
sourceWriter.println("}");

}

private static Class<? extends ClientConnector> getClientConnectorClass(
Class<? extends ServerConnector> connectorClass) {
Connect annotation = connectorClass.getAnnotation(Connect.class);
return (Class<? extends ClientConnector>) annotation.value();
}
}

Loading…
Cancel
Save