<when-property-is name="user.agent" value="ie6"/>
</replace-with>
- <generate-with class="com.vaadin.terminal.gwt.rebind.WidgetMapGenerator">
+ <generate-with class="com.vaadin.terminal.gwt.widgetsetutils.WidgetMapGenerator">
<when-type-is class="com.vaadin.terminal.gwt.client.WidgetMap"/>
</generate-with>
+++ /dev/null
-package com.vaadin.terminal.gwt.rebind;
-
-import java.io.File;
-import java.io.FileFilter;
-import java.io.IOException;
-import java.net.JarURLConnection;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-
-import com.vaadin.terminal.Paintable;
-import com.vaadin.ui.ClientWidget;
-
-/**
- * Utility class to find server side widgets with {@link ClientWidget}
- * annotation. Used by WidgetMapGenerator to implement some monkey coding for
- * you.
- * <p>
- * If you end up reading this comment, I guess you have faced a sluggish
- * performance of widget compilation or unreliable detection of components in
- * your classpaths. The thing you might be able to do is to use annotation
- * processing tool like apt to generate the needed information. Then either use
- * that information in {@link WidgetMapGenerator} or create the appropriate
- * monkey code for gwt directly in annotation processor and get rid of
- * {@link WidgetMapGenerator}. Using annotation processor might be a good idea
- * when dropping Java 1.5 support (integrated to javac in 6).
- *
- */
-public class ClassPathExplorer {
- private final static FileFilter DIRECTORIES_ONLY = new FileFilter() {
- public boolean accept(File f) {
- if (f.exists() && f.isDirectory()) {
- return true;
- } else {
- return false;
- }
- }
- };
-
- private static Map<URL, String> classpathLocations = getClasspathLocations();
-
- private ClassPathExplorer() {
- }
-
- public static Collection<Class<? extends Paintable>> getPaintablesHavingWidgetAnnotation() {
- Collection<Class<? extends Paintable>> paintables = new HashSet<Class<? extends Paintable>>();
- Set<URL> keySet = classpathLocations.keySet();
- for (URL url : keySet) {
- searchForPaintables(url, classpathLocations.get(url), paintables);
- }
- return paintables;
-
- }
-
- /**
- * Determine every URL location defined by the current classpath, and it's
- * associated package name.
- */
- public final static Map<URL, String> getClasspathLocations() {
- Map<URL, String> locations = new HashMap<URL, String>();
-
- String pathSep = System.getProperty("path.separator");
- String classpath = System.getProperty("java.class.path");
-
- String[] split = classpath.split(pathSep);
- for (int i = 0; i < split.length; i++) {
- String classpathEntry = split[i];
- if (acceptClassPathEntry(classpathEntry)) {
- File file = new File(classpathEntry);
- include(null, file, locations);
- }
- }
-
- return locations;
- }
-
- private static boolean acceptClassPathEntry(String classpathEntry) {
- if (!classpathEntry.endsWith(".jar")) {
- // accept all non jars (practically directories)
- return true;
- } else {
- // accepts jars that comply with vaadin-component packaging
- // convention (.vaadin. or vaadin- as distribution packages),
- if (classpathEntry.contains("vaadin-")
- || classpathEntry.contains(".vaadin.")) {
- return true;
- } else {
- return false;
- }
- }
- }
-
- /**
- * Recursively add subdirectories and jar files to classpathlocations
- *
- * @param name
- * @param file
- * @param locations
- */
- private final static void include(String name, File file,
- Map<URL, String> locations) {
- if (!file.exists()) {
- return;
- }
- if (!file.isDirectory()) {
- // could be a JAR file
- includeJar(file, locations);
- return;
- }
-
- if (file.isHidden() || file.getPath().contains(File.separator + ".")) {
- return;
- }
-
- if (name == null) {
- name = "";
- } else {
- name += ".";
- }
-
- // add all directories recursively
- File[] dirs = file.listFiles(DIRECTORIES_ONLY);
- for (int i = 0; i < dirs.length; i++) {
- try {
- // add the present directory
- locations.put(new URL("file://" + dirs[i].getCanonicalPath()),
- name + dirs[i].getName());
- } catch (Exception ioe) {
- return;
- }
- include(name + dirs[i].getName(), dirs[i], locations);
- }
- }
-
- private static void includeJar(File file, Map<URL, String> locations) {
- try {
- URL url = new URL("file:" + file.getCanonicalPath());
- url = new URL("jar:" + url.toExternalForm() + "!/");
- JarURLConnection conn = (JarURLConnection) url.openConnection();
- JarFile jarFile = conn.getJarFile();
- if (jarFile != null) {
- locations.put(url, "");
- }
- } catch (Exception e) {
- // e.printStackTrace();
- return;
- }
-
- }
-
- private static String packageNameFor(JarEntry entry) {
- if (entry == null) {
- return "";
- }
- String s = entry.getName();
- if (s == null) {
- return "";
- }
- if (s.length() == 0) {
- return s;
- }
- if (s.startsWith("/")) {
- s = s.substring(1, s.length());
- }
- if (s.endsWith("/")) {
- s = s.substring(0, s.length() - 1);
- }
- return s.replace('/', '.');
- }
-
- private final static void searchForPaintables(URL location,
- String packageName,
- Collection<Class<? extends Paintable>> paintables) {
-
- // Get a File object for the package
- File directory = new File(location.getFile());
-
- if (directory.exists() && !directory.isHidden()) {
- // Get the list of the files contained in the directory
- String[] files = directory.list();
- for (int i = 0; i < files.length; i++) {
- // we are only interested in .class files
- if (files[i].endsWith(".class")) {
- // remove the .class extension
- String classname = files[i].substring(0,
- files[i].length() - 6);
- classname = packageName + "." + classname;
- tryToAdd(classname, paintables);
- }
- }
- } else {
- try {
- // check files in jar file, entries will list all directories
- // and files in jar
-
- URLConnection openConnection = location.openConnection();
-
- if (openConnection instanceof JarURLConnection) {
- JarURLConnection conn = (JarURLConnection) openConnection;
-
- JarFile jarFile = conn.getJarFile();
-
- Enumeration<JarEntry> e = jarFile.entries();
- while (e.hasMoreElements()) {
- JarEntry entry = e.nextElement();
- String entryname = entry.getName();
- if (!entry.isDirectory()
- && entryname.endsWith(".class")
- && !entryname.contains("$")) {
- String classname = entryname.substring(0, entryname
- .length() - 6);
- if (classname.startsWith("/")) {
- classname = classname.substring(1);
- }
- classname = classname.replace('/', '.');
- tryToAdd(classname, paintables);
- }
- }
- }
- } catch (IOException e) {
- System.err.println(e);
- }
- }
-
- }
-
- private static void tryToAdd(final String fullclassName,
- Collection<Class<? extends Paintable>> paintables) {
- try {
- Class<?> c = Class.forName(fullclassName);
- if (c.getAnnotation(ClientWidget.class) != null) {
- paintables.add((Class<? extends Paintable>) c);
- System.out.println("Found paintable " + fullclassName);
- }
- } catch (ExceptionInInitializerError e) {
- // e.printStackTrace();
- } catch (ClassNotFoundException e) {
- // e.printStackTrace();
- } catch (NoClassDefFoundError e) {
- // NOP
- } catch (UnsatisfiedLinkError e) {
- // NOP
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- /**
- * Test method for helper tool
- */
- public static void main(String[] args) {
- Collection<Class<? extends Paintable>> paintables = ClassPathExplorer
- .getPaintablesHavingWidgetAnnotation();
- System.out.println("Found annotated paintables:");
- for (Class<? extends Paintable> cls : paintables) {
- System.out.println(cls.getCanonicalName());
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-package com.vaadin.terminal.gwt.rebind;
-
-import java.io.PrintWriter;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Iterator;
-
-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.UnableToCompleteException;
-import com.google.gwt.core.ext.TreeLogger.Type;
-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;
-
-/**
- * GWT generator to build WidgetMapImpl dynamically based on
- * {@link ClientWidget} annotations available in workspace.
- *
- */
-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 vaading 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.setSuperclass("com.vaadin.terminal.gwt.client.WidgetMap");
- SourceWriter sourceWriter = composer.createSourceWriter(context,
- printWriter);
-
- Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation = getUsedPaintables();
-
- validatePaintables(logger, context, paintablesHavingWidgetAnnotation);
-
- // generator constructor source code
- generateImplementationDetector(sourceWriter,
- paintablesHavingWidgetAnnotation);
- generateInstantiatorMethod(sourceWriter,
- paintablesHavingWidgetAnnotation);
- // 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)");
-
- }
-
- /**
- * Verifies that all client side components are available for client side
- * GWT module.
- *
- * @param logger
- * @param context
- * @param paintablesHavingWidgetAnnotation
- */
- private void validatePaintables(
- TreeLogger logger,
- GeneratorContext context,
- Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation) {
- TypeOracle typeOracle = context.getTypeOracle();
-
- for (Iterator<Class<? extends Paintable>> iterator = paintablesHavingWidgetAnnotation
- .iterator(); iterator.hasNext();) {
- Class<? extends Paintable> class1 = iterator.next();
-
- ClientWidget annotation = class1.getAnnotation(ClientWidget.class);
-
- if (typeOracle.findType(annotation.value().getName()) == null) {
- // GWT widget not inherited
- logger
- .log(
- Type.WARN,
- "Widget implementation for "
- + class1.getName()
- + " not available for GWT compiler (but mapped "
- + "for component found in classpath). If this is not "
- + "intentional, check your gwt module definition file.");
- iterator.remove();
- }
-
- }
- }
-
- /**
- * This method is protected to allow easy creation of optimized widgetsets.
- * <p>
- * TODO we need some sort of mechanism to easily exclude/include components
- * from widgetset. Properties in gwt.xml is one option. Now only possible by
- * extending this class, overriding getUsedPaintables() method and
- * redefining deferred binding rule.
- *
- * @return a collections of Vaadin components that will be added to
- * widgetset
- */
- protected Collection<Class<? extends Paintable>> getUsedPaintables() {
- return ClassPathExplorer.getPaintablesHavingWidgetAnnotation();
- }
-
- private void generateInstantiatorMethod(
- SourceWriter sourceWriter,
- Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation) {
- sourceWriter
- .println("public Paintable instantiate(Class<? extends Paintable> classType) {");
- sourceWriter.indent();
-
- sourceWriter
- .println("Paintable p = super.instantiate(classType); if(p!= null) return p;");
-
- for (Class<? extends Paintable> class1 : paintablesHavingWidgetAnnotation) {
- ClientWidget annotation = class1.getAnnotation(ClientWidget.class);
- Class<? extends com.vaadin.terminal.gwt.client.Paintable> clientClass = annotation
- .value();
- if (clientClass == VView.class) {
- // VView's are not instantiated by widgetset
- continue;
- }
- sourceWriter.print("if (");
- sourceWriter.print(clientClass.getName());
- sourceWriter.print(".class == classType) return GWT.create(");
- sourceWriter.print(clientClass.getName());
- sourceWriter.println(".class );");
- sourceWriter.print("else ");
- }
- sourceWriter
- .println("return GWT.create( com.vaadin.terminal.gwt.client.ui.VUnknownComponent.class );");
- sourceWriter.outdent();
- sourceWriter.println("}");
- }
-
- /**
- *
- * @param sourceWriter
- * Source writer to output source code
- * @param paintablesHavingWidgetAnnotation
- */
- private void generateImplementationDetector(
- SourceWriter sourceWriter,
- Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation) {
- sourceWriter
- .println("public Class<? extends Paintable> "
- + "getImplementationByServerSideClassName(String fullyQualifiedName) {");
- sourceWriter.indent();
- sourceWriter
- .println("fullyQualifiedName = fullyQualifiedName.intern();");
-
- for (Class<? extends Paintable> class1 : paintablesHavingWidgetAnnotation) {
- ClientWidget annotation = class1.getAnnotation(ClientWidget.class);
- Class<? extends com.vaadin.terminal.gwt.client.Paintable> clientClass = annotation
- .value();
- sourceWriter.print("if ( fullyQualifiedName == \"");
- sourceWriter.print(class1.getName());
- sourceWriter.print("\" ) return ");
- sourceWriter.print(clientClass.getName());
- sourceWriter.println(".class;");
- sourceWriter.print("else ");
- }
- sourceWriter
- .println("return com.vaadin.terminal.gwt.client.ui.VUnknownComponent.class;");
- sourceWriter.outdent();
- sourceWriter.println("}");
-
- }
-
-}
--- /dev/null
+package com.vaadin.terminal.gwt.widgetsetutils;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+import com.vaadin.terminal.Paintable;
+import com.vaadin.ui.ClientWidget;
+
+/**
+ * Utility class to collect widgetset related information from classpath.
+ * Utility will seek all directories from classpaths, and jar files having
+ * "Vaadin-Widgetsets" key in their manifest file.
+ * <p>
+ * Used by WidgetMapGenerator and ide tools to implement some monkey coding for
+ * you.
+ * <p>
+ * Developer notice: If you end up reading this comment, I guess you have faced
+ * a sluggish performance of widget compilation or unreliable detection of
+ * components in your classpaths. The thing you might be able to do is to use
+ * annotation processing tool like apt to generate the needed information. Then
+ * either use that information in {@link WidgetMapGenerator} or create the
+ * appropriate monkey code for gwt directly in annotation processor and get rid
+ * of {@link WidgetMapGenerator}. Using annotation processor might be a good
+ * idea when dropping Java 1.5 support (integrated to javac in 6).
+ *
+ */
+public class ClassPathExplorer {
+ private final static FileFilter DIRECTORIES_ONLY = new FileFilter() {
+ public boolean accept(File f) {
+ if (f.exists() && f.isDirectory()) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ };
+
+ private static Map<URL, String> classpathLocations = getClasspathLocations();
+
+ private ClassPathExplorer() {
+ }
+
+ /**
+ * Finds server side widgets with {@link ClientWidget} annotation.
+ */
+ public static Collection<Class<? extends Paintable>> getPaintablesHavingWidgetAnnotation() {
+ Collection<Class<? extends Paintable>> paintables = new HashSet<Class<? extends Paintable>>();
+ Set<URL> keySet = classpathLocations.keySet();
+ for (URL url : keySet) {
+ searchForPaintables(url, classpathLocations.get(url), paintables);
+ }
+ return paintables;
+
+ }
+
+ /**
+ * Finds available widgetset names.
+ *
+ * @return
+ */
+ public static Collection<String> getAvailableWidgetSets() {
+ Collection<String> widgetsets = new HashSet<String>();
+ Set<URL> keySet = classpathLocations.keySet();
+ for (URL url : keySet) {
+ searchForWidgetSets(url, widgetsets);
+ }
+ return widgetsets;
+ }
+
+ private static void searchForWidgetSets(URL location,
+ Collection<String> widgetsets) {
+
+ File directory = new File(location.getFile());
+
+ if (directory.exists() && !directory.isHidden()) {
+ // Get the list of the files contained in the directory
+ String[] files = directory.list();
+ for (int i = 0; i < files.length; i++) {
+ // we are only interested in .gwt.xml files
+ if (files[i].endsWith(".gwt.xml")) {
+ // remove the extension
+ String classname = files[i].substring(0,
+ files[i].length() - 8);
+ classname = classpathLocations.get(location) + "."
+ + classname;
+ widgetsets.add(classname);
+ }
+ }
+ } else {
+
+ try {
+ // check files in jar file, entries will list all directories
+ // and files in jar
+
+ URLConnection openConnection = location.openConnection();
+ if (openConnection instanceof JarURLConnection) {
+ JarURLConnection conn = (JarURLConnection) openConnection;
+
+ JarFile jarFile = conn.getJarFile();
+
+ Manifest manifest = jarFile.getManifest();
+ String value = manifest.getMainAttributes().getValue(
+ "Vaadin-Widgetsets");
+ if (value != null) {
+ String[] widgetsetNames = value.split(",");
+ for (int i = 0; i < widgetsetNames.length; i++) {
+ String widgetsetname = widgetsetNames[i].trim()
+ .intern();
+ widgetsets.add(widgetsetname);
+ }
+ }
+ }
+ } catch (IOException e) {
+ System.err.println(e);
+ }
+
+ }
+ }
+
+ /**
+ * Determine every URL location defined by the current classpath, and it's
+ * associated package name.
+ */
+ private final static Map<URL, String> getClasspathLocations() {
+ Map<URL, String> locations = new HashMap<URL, String>();
+
+ String pathSep = System.getProperty("path.separator");
+ String classpath = System.getProperty("java.class.path");
+
+ String[] split = classpath.split(pathSep);
+ for (int i = 0; i < split.length; i++) {
+ String classpathEntry = split[i];
+ if (acceptClassPathEntry(classpathEntry)) {
+ File file = new File(classpathEntry);
+ include(null, file, locations);
+ }
+ }
+
+ return locations;
+ }
+
+ private static boolean acceptClassPathEntry(String classpathEntry) {
+ if (!classpathEntry.endsWith(".jar")) {
+ // accept all non jars (practically directories)
+ return true;
+ } else {
+ // accepts jars that comply with vaadin-component packaging
+ // convention (.vaadin. or vaadin- as distribution packages),
+ if (classpathEntry.contains("vaadin-")
+ || classpathEntry.contains(".vaadin.")) {
+ return true;
+ } else {
+ URL url;
+ try {
+ url = new URL("file:"
+ + new File(classpathEntry).getCanonicalPath());
+ url = new URL("jar:" + url.toExternalForm() + "!/");
+ JarURLConnection conn = (JarURLConnection) url
+ .openConnection();
+ JarFile jarFile = conn.getJarFile();
+ Manifest manifest = jarFile.getManifest();
+ Attributes mainAttributes = manifest.getMainAttributes();
+ if (mainAttributes.getValue("Vaadin-Widgetsets") != null) {
+ return true;
+ }
+ } catch (MalformedURLException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Recursively add subdirectories and jar files to classpathlocations
+ *
+ * @param name
+ * @param file
+ * @param locations
+ */
+ private final static void include(String name, File file,
+ Map<URL, String> locations) {
+ if (!file.exists()) {
+ return;
+ }
+ if (!file.isDirectory()) {
+ // could be a JAR file
+ includeJar(file, locations);
+ return;
+ }
+
+ if (file.isHidden() || file.getPath().contains(File.separator + ".")) {
+ return;
+ }
+
+ if (name == null) {
+ name = "";
+ } else {
+ name += ".";
+ }
+
+ // add all directories recursively
+ File[] dirs = file.listFiles(DIRECTORIES_ONLY);
+ for (int i = 0; i < dirs.length; i++) {
+ try {
+ // add the present directory
+ locations.put(new URL("file://" + dirs[i].getCanonicalPath()),
+ name + dirs[i].getName());
+ } catch (Exception ioe) {
+ return;
+ }
+ include(name + dirs[i].getName(), dirs[i], locations);
+ }
+ }
+
+ private static void includeJar(File file, Map<URL, String> locations) {
+ try {
+ URL url = new URL("file:" + file.getCanonicalPath());
+ url = new URL("jar:" + url.toExternalForm() + "!/");
+ JarURLConnection conn = (JarURLConnection) url.openConnection();
+ JarFile jarFile = conn.getJarFile();
+ if (jarFile != null) {
+ locations.put(url, "");
+ }
+ } catch (Exception e) {
+ // e.printStackTrace();
+ return;
+ }
+
+ }
+
+ private final static void searchForPaintables(URL location,
+ String packageName,
+ Collection<Class<? extends Paintable>> paintables) {
+
+ // Get a File object for the package
+ File directory = new File(location.getFile());
+
+ if (directory.exists() && !directory.isHidden()) {
+ // Get the list of the files contained in the directory
+ String[] files = directory.list();
+ for (int i = 0; i < files.length; i++) {
+ // we are only interested in .class files
+ if (files[i].endsWith(".class")) {
+ // remove the .class extension
+ String classname = files[i].substring(0,
+ files[i].length() - 6);
+ classname = packageName + "." + classname;
+ tryToAdd(classname, paintables);
+ }
+ }
+ } else {
+ try {
+ // check files in jar file, entries will list all directories
+ // and files in jar
+
+ URLConnection openConnection = location.openConnection();
+
+ if (openConnection instanceof JarURLConnection) {
+ JarURLConnection conn = (JarURLConnection) openConnection;
+
+ JarFile jarFile = conn.getJarFile();
+
+ Enumeration<JarEntry> e = jarFile.entries();
+ while (e.hasMoreElements()) {
+ JarEntry entry = e.nextElement();
+ String entryname = entry.getName();
+ if (!entry.isDirectory()
+ && entryname.endsWith(".class")
+ && !entryname.contains("$")) {
+ String classname = entryname.substring(0, entryname
+ .length() - 6);
+ if (classname.startsWith("/")) {
+ classname = classname.substring(1);
+ }
+ classname = classname.replace('/', '.');
+ tryToAdd(classname, paintables);
+ }
+ }
+ }
+ } catch (IOException e) {
+ System.err.println(e);
+ }
+ }
+
+ }
+
+ private static void tryToAdd(final String fullclassName,
+ Collection<Class<? extends Paintable>> paintables) {
+ try {
+ Class<?> c = Class.forName(fullclassName);
+ if (c.getAnnotation(ClientWidget.class) != null) {
+ paintables.add((Class<? extends Paintable>) c);
+ // System.out.println("Found paintable " + fullclassName);
+ }
+ } catch (ExceptionInInitializerError e) {
+ // e.printStackTrace();
+ } catch (ClassNotFoundException e) {
+ // e.printStackTrace();
+ } catch (NoClassDefFoundError e) {
+ // NOP
+ } catch (UnsatisfiedLinkError e) {
+ // NOP
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Test method for helper tool
+ */
+ public static void main(String[] args) {
+ Collection<Class<? extends Paintable>> paintables = ClassPathExplorer
+ .getPaintablesHavingWidgetAnnotation();
+ System.out.println("Found annotated paintables:");
+ for (Class<? extends Paintable> cls : paintables) {
+ System.out.println(cls.getCanonicalName());
+ }
+
+ System.out.println();
+ System.out.println("Searching available widgetsets...");
+
+ Collection<String> availableWidgetSets = ClassPathExplorer
+ .getAvailableWidgetSets();
+ for (String string : availableWidgetSets) {
+ System.out.println(string);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package com.vaadin.terminal.gwt.widgetsetutils;
+
+import java.io.PrintWriter;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+
+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.UnableToCompleteException;
+import com.google.gwt.core.ext.TreeLogger.Type;
+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;
+
+/**
+ * GWT generator to build WidgetMapImpl dynamically based on
+ * {@link ClientWidget} annotations available in workspace.
+ *
+ */
+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 vaading 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.setSuperclass("com.vaadin.terminal.gwt.client.WidgetMap");
+ SourceWriter sourceWriter = composer.createSourceWriter(context,
+ printWriter);
+
+ Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation = getUsedPaintables();
+
+ validatePaintables(logger, context, paintablesHavingWidgetAnnotation);
+
+ // generator constructor source code
+ generateImplementationDetector(sourceWriter,
+ paintablesHavingWidgetAnnotation);
+ generateInstantiatorMethod(sourceWriter,
+ paintablesHavingWidgetAnnotation);
+ // 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)");
+
+ }
+
+ /**
+ * Verifies that all client side components are available for client side
+ * GWT module.
+ *
+ * @param logger
+ * @param context
+ * @param paintablesHavingWidgetAnnotation
+ */
+ private void validatePaintables(
+ TreeLogger logger,
+ GeneratorContext context,
+ Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation) {
+ TypeOracle typeOracle = context.getTypeOracle();
+
+ for (Iterator<Class<? extends Paintable>> iterator = paintablesHavingWidgetAnnotation
+ .iterator(); iterator.hasNext();) {
+ Class<? extends Paintable> class1 = iterator.next();
+
+ ClientWidget annotation = class1.getAnnotation(ClientWidget.class);
+
+ if (typeOracle.findType(annotation.value().getName()) == null) {
+ // GWT widget not inherited
+ logger
+ .log(
+ Type.WARN,
+ "Widget implementation for "
+ + class1.getName()
+ + " not available for GWT compiler (but mapped "
+ + "for component found in classpath). If this is not "
+ + "intentional, check your gwt module definition file.");
+ iterator.remove();
+ }
+
+ }
+ }
+
+ /**
+ * This method is protected to allow easy creation of optimized widgetsets.
+ * <p>
+ * TODO we need some sort of mechanism to easily exclude/include components
+ * from widgetset. Properties in gwt.xml is one option. Now only possible by
+ * extending this class, overriding getUsedPaintables() method and
+ * redefining deferred binding rule.
+ *
+ * @return a collections of Vaadin components that will be added to
+ * widgetset
+ */
+ protected Collection<Class<? extends Paintable>> getUsedPaintables() {
+ return ClassPathExplorer.getPaintablesHavingWidgetAnnotation();
+ }
+
+ private void generateInstantiatorMethod(
+ SourceWriter sourceWriter,
+ Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation) {
+ sourceWriter
+ .println("public Paintable instantiate(Class<? extends Paintable> classType) {");
+ sourceWriter.indent();
+
+ sourceWriter
+ .println("Paintable p = super.instantiate(classType); if(p!= null) return p;");
+
+ for (Class<? extends Paintable> class1 : paintablesHavingWidgetAnnotation) {
+ ClientWidget annotation = class1.getAnnotation(ClientWidget.class);
+ Class<? extends com.vaadin.terminal.gwt.client.Paintable> clientClass = annotation
+ .value();
+ if (clientClass == VView.class) {
+ // VView's are not instantiated by widgetset
+ continue;
+ }
+ sourceWriter.print("if (");
+ sourceWriter.print(clientClass.getName());
+ sourceWriter.print(".class == classType) return GWT.create(");
+ sourceWriter.print(clientClass.getName());
+ sourceWriter.println(".class );");
+ sourceWriter.print("else ");
+ }
+ sourceWriter
+ .println("return GWT.create( com.vaadin.terminal.gwt.client.ui.VUnknownComponent.class );");
+ sourceWriter.outdent();
+ sourceWriter.println("}");
+ }
+
+ /**
+ *
+ * @param sourceWriter
+ * Source writer to output source code
+ * @param paintablesHavingWidgetAnnotation
+ */
+ private void generateImplementationDetector(
+ SourceWriter sourceWriter,
+ Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation) {
+ sourceWriter
+ .println("public Class<? extends Paintable> "
+ + "getImplementationByServerSideClassName(String fullyQualifiedName) {");
+ sourceWriter.indent();
+ sourceWriter
+ .println("fullyQualifiedName = fullyQualifiedName.intern();");
+
+ for (Class<? extends Paintable> class1 : paintablesHavingWidgetAnnotation) {
+ ClientWidget annotation = class1.getAnnotation(ClientWidget.class);
+ Class<? extends com.vaadin.terminal.gwt.client.Paintable> clientClass = annotation
+ .value();
+ sourceWriter.print("if ( fullyQualifiedName == \"");
+ sourceWriter.print(class1.getName());
+ sourceWriter.print("\" ) return ");
+ sourceWriter.print(clientClass.getName());
+ sourceWriter.println(".class;");
+ sourceWriter.print("else ");
+ }
+ sourceWriter
+ .println("return com.vaadin.terminal.gwt.client.ui.VUnknownComponent.class;");
+ sourceWriter.outdent();
+ sourceWriter.println("}");
+
+ }
+
+}
--- /dev/null
+package com.vaadin.terminal.gwt.widgetsetutils;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Helper class to update widgetsets GWT module configuration file. Can be used
+ * command line or via IDE tools.
+ */
+public class WidgetSetBuilder {
+
+ public static void main(String[] args) throws IOException {
+ if (args.length == 0) {
+ printUsage();
+ } else {
+ String widgetsetname = args[0];
+ String sourcepath = args[1];
+ updateWidgetSet(widgetsetname, sourcepath);
+
+ }
+ }
+
+ public static void updateWidgetSet(final String widgetset, String sourcepath)
+ throws IOException, FileNotFoundException {
+ String widgetsetfilename = sourcepath + "/"
+ + widgetset.replace(".", "/") + ".gwt.xml";
+ File widgetsetFile = new File(widgetsetfilename);
+ if (!widgetsetFile.exists()) {
+ // create empty gwt module file
+ widgetsetFile.createNewFile();
+ PrintStream printStream = new PrintStream(new FileOutputStream(
+ widgetsetFile));
+ printStream.print("<module>\n\n</module>\n");
+ printStream.close();
+ }
+
+ String content = readFile(widgetsetFile);
+
+ Collection<String> oldInheritedWidgetsets = getCurrentWidgetSets(content);
+
+ Collection<String> availableWidgetSets = ClassPathExplorer
+ .getAvailableWidgetSets();
+
+ // add widgetsets that do not exist
+ for (String ws : availableWidgetSets) {
+ if (ws.equals(widgetset)) {
+ // do not inherit the module itself
+ continue;
+ }
+ if (!oldInheritedWidgetsets.contains(ws)) {
+ content = addWidgetSet(ws, content);
+ }
+ }
+
+ for (String ws : oldInheritedWidgetsets) {
+ if (!availableWidgetSets.contains(ws)) {
+ // widgetset not available in classpath
+ content = removeWidgetSet(ws, content);
+ }
+ }
+
+ commitChanges(widgetsetfilename, content);
+ }
+
+ private static String removeWidgetSet(String ws, String content) {
+ return content.replaceFirst("<inherits name=\"" + ws + "\"[^/]*/>", "");
+ }
+
+ private static void commitChanges(String widgetsetfilename, String content)
+ throws IOException {
+ BufferedWriter bufferedWriter = new BufferedWriter(
+ new OutputStreamWriter(new FileOutputStream(widgetsetfilename)));
+ bufferedWriter.write(content);
+ bufferedWriter.close();
+ }
+
+ private static String addWidgetSet(String ws, String content) {
+ return content.replace("</module>", "\n\t<inherits name=\"" + ws
+ + "\" />" + "\n</module>");
+ }
+
+ private static Collection<String> getCurrentWidgetSets(String content) {
+ HashSet<String> hashSet = new HashSet<String>();
+ Pattern inheritsPattern = Pattern.compile(" name=\"([^\"]*)\"");
+
+ Matcher matcher = inheritsPattern.matcher(content);
+
+ while (matcher.find()) {
+ String possibleWidgetSet = matcher.group(1);
+ if (possibleWidgetSet.toLowerCase().contains("widgetset")) {
+ hashSet.add(possibleWidgetSet);
+ }
+ }
+ return hashSet;
+ }
+
+ private static String readFile(File widgetsetFile) throws IOException {
+ Reader fi = new FileReader(widgetsetFile);
+ BufferedReader bufferedReader = new BufferedReader(fi);
+ StringBuilder sb = new StringBuilder();
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ sb.append(line);
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+
+ private static void printUsage() {
+ PrintStream o = System.out;
+ o.println(WidgetSetBuilder.class.getSimpleName() + " usage:");
+ o.println("\t1. Set the same classpath as you will "
+ + "have for the GWT compiler.");
+ o.println("\t2. Give the widgetsetname (to be created or updated)"
+ + " as first parameter, source path as a second parameter");
+ o.println();
+ o
+ .println("All found vaadin widgetsets will be inherited in given widgetset");
+
+ }
+
+}