From 43467c624d543a25bce4fc3fd7963777851ac657 Mon Sep 17 00:00:00 2001 From: Matti Tahvonen Date: Tue, 29 Sep 2009 13:25:47 +0000 Subject: [PATCH] vaadin widget jars now detected by details in manifest file, simple widgetsetbuilder tool + some refactoring svn changeset:8990/svn branch:2009-09-widget-packaging_3332 --- .../terminal/gwt/DefaultWidgetSet.gwt.xml | 2 +- .../ClassPathExplorer.java | 149 ++++++++++++++---- .../WidgetMapGenerator.java | 2 +- .../gwt/widgetsetutils/WidgetSetBuilder.java | 134 ++++++++++++++++ 4 files changed, 252 insertions(+), 35 deletions(-) rename src/com/vaadin/terminal/gwt/{rebind => widgetsetutils}/ClassPathExplorer.java (61%) rename src/com/vaadin/terminal/gwt/{rebind => widgetsetutils}/WidgetMapGenerator.java (99%) create mode 100644 src/com/vaadin/terminal/gwt/widgetsetutils/WidgetSetBuilder.java diff --git a/src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml b/src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml index 58d692e99f..0c139aabc4 100644 --- a/src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml +++ b/src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml @@ -31,7 +31,7 @@ - + diff --git a/src/com/vaadin/terminal/gwt/rebind/ClassPathExplorer.java b/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java similarity index 61% rename from src/com/vaadin/terminal/gwt/rebind/ClassPathExplorer.java rename to src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java index 6c81c368c4..c51e2a2188 100644 --- a/src/com/vaadin/terminal/gwt/rebind/ClassPathExplorer.java +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java @@ -1,9 +1,10 @@ -package com.vaadin.terminal.gwt.rebind; +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; @@ -12,25 +13,30 @@ 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 find server side widgets with {@link ClientWidget} - * annotation. Used by WidgetMapGenerator to implement some monkey coding for + * 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. + *

+ * Used by WidgetMapGenerator and ide tools to implement some monkey coding for * you. *

- * 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). + * 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 { @@ -49,6 +55,9 @@ public class ClassPathExplorer { private ClassPathExplorer() { } + /** + * Finds server side widgets with {@link ClientWidget} annotation. + */ public static Collection> getPaintablesHavingWidgetAnnotation() { Collection> paintables = new HashSet>(); Set keySet = classpathLocations.keySet(); @@ -59,11 +68,75 @@ public class ClassPathExplorer { } + /** + * Finds available widgetset names. + * + * @return + */ + public static Collection getAvailableWidgetSets() { + Collection widgetsets = new HashSet(); + Set keySet = classpathLocations.keySet(); + for (URL url : keySet) { + searchForWidgetSets(url, widgetsets); + } + return widgetsets; + } + + private static void searchForWidgetSets(URL location, + Collection 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. */ - public final static Map getClasspathLocations() { + private final static Map getClasspathLocations() { Map locations = new HashMap(); String pathSep = System.getProperty("path.separator"); @@ -92,6 +165,27 @@ public class ClassPathExplorer { || 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; } } @@ -155,26 +249,6 @@ public class ClassPathExplorer { } - 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> paintables) { @@ -237,7 +311,7 @@ public class ClassPathExplorer { Class c = Class.forName(fullclassName); if (c.getAnnotation(ClientWidget.class) != null) { paintables.add((Class) c); - System.out.println("Found paintable " + fullclassName); + // System.out.println("Found paintable " + fullclassName); } } catch (ExceptionInInitializerError e) { // e.printStackTrace(); @@ -262,5 +336,14 @@ public class ClassPathExplorer { for (Class cls : paintables) { System.out.println(cls.getCanonicalName()); } + + System.out.println(); + System.out.println("Searching available widgetsets..."); + + Collection availableWidgetSets = ClassPathExplorer + .getAvailableWidgetSets(); + for (String string : availableWidgetSets) { + System.out.println(string); + } } } \ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/rebind/WidgetMapGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java similarity index 99% rename from src/com/vaadin/terminal/gwt/rebind/WidgetMapGenerator.java rename to src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java index ba42f4ebaa..8bd961d925 100644 --- a/src/com/vaadin/terminal/gwt/rebind/WidgetMapGenerator.java +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java @@ -1,4 +1,4 @@ -package com.vaadin.terminal.gwt.rebind; +package com.vaadin.terminal.gwt.widgetsetutils; import java.io.PrintWriter; import java.util.Collection; diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetSetBuilder.java b/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetSetBuilder.java new file mode 100644 index 0000000000..c2c888c4bb --- /dev/null +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetSetBuilder.java @@ -0,0 +1,134 @@ +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("\n\n\n"); + printStream.close(); + } + + String content = readFile(widgetsetFile); + + Collection oldInheritedWidgetsets = getCurrentWidgetSets(content); + + Collection 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("", ""); + } + + 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("", "\n\t" + "\n"); + } + + private static Collection getCurrentWidgetSets(String content) { + HashSet hashSet = new HashSet(); + 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"); + + } + +} -- 2.39.5