/* * 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.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; 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.terminal.Paintable; import com.vaadin.terminal.gwt.client.ui.VView; import com.vaadin.ui.ClientWidget; import com.vaadin.ui.ClientWidget.LoadStyle; /** * WidgetMapGenerator's are GWT generator to build WidgetMapImpl dynamically * based on {@link ClientWidget} 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 #getUsedPaintables()}. *
* 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. *
* This generator uses the loadStyle hints from the {@link ClientWidget} * 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. *
* The GWT module description file of the widgetset (
* ...Widgetset.gwt.xml) can be used to define the
* WidgetMapGenarator. An example that defines this generator to be used:
*
*
*
* <generate-with
* class="com.vaadin.terminal.gwt.widgetsetutils.MyWidgetMapGenerator">
* <when-type-is class="com.vaadin.terminal.gwt.client.WidgetMap" />
* </generate-with>
*
*
*
*
*
* 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 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
*/
private void generateClass(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,
// return (WidgetMap is equal to all permutations atm)
if (printWriter == null) {
return;
}
logger.log(Type.INFO,
"Detecting Vaadin components 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.terminal.gwt.client.WidgetMap");
SourceWriter sourceWriter = composer.createSourceWriter(context,
printWriter);
Collection
* 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 paintableType
* @return true iff the widget for given component should be lazy loaded by
* the client side engine
*/
protected LoadStyle getLoadStyle(Class extends Paintable> paintableType) {
ClientWidget annotation = paintableType
.getAnnotation(ClientWidget.class);
return annotation.loadStyle();
}
private void generateInstantiatorMethod(
SourceWriter sourceWriter,
Collection