From ed9132f848d68a8edf51e649856c805bd179c567 Mon Sep 17 00:00:00 2001 From: Marko Grönroos Date: Fri, 22 Oct 2010 13:53:28 +0000 Subject: Generate OSGi manifest Package-Exports attribute automatically. For #3521. svn changeset:15674/svn branch:6.5 --- build/build.xml | 19 ++- .../buildhelpers/GeneratePackageExports.java | 131 +++++++++++++++++++++ .../com/vaadin/buildhelpers/ManifestWriter.java | 130 ++++++++++++++++++++ build/package/META-INF/MANIFEST.MF | 1 - 4 files changed, 276 insertions(+), 5 deletions(-) create mode 100644 build/buildhelpers/com/vaadin/buildhelpers/GeneratePackageExports.java create mode 100644 build/buildhelpers/com/vaadin/buildhelpers/ManifestWriter.java diff --git a/build/build.xml b/build/build.xml index efc82ae316..5a12ec80c5 100644 --- a/build/build.xml +++ b/build/build.xml @@ -587,10 +587,12 @@ - - Combining default themes css files - + + + + + Combining default themes css files @@ -773,7 +775,7 @@ - + Creating JAR (server-side) ${lib-jar-name} @@ -813,6 +815,15 @@ + + + + + + + + + diff --git a/build/buildhelpers/com/vaadin/buildhelpers/GeneratePackageExports.java b/build/buildhelpers/com/vaadin/buildhelpers/GeneratePackageExports.java new file mode 100644 index 0000000000..742450f3d5 --- /dev/null +++ b/build/buildhelpers/com/vaadin/buildhelpers/GeneratePackageExports.java @@ -0,0 +1,131 @@ +package com.vaadin.buildhelpers; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Vector; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.jar.Attributes.Name; + +/** + * Generates Export-Packages attribute for OSGi compatible manifest. + * + * Reads the included Java packages in Vaadin JAR, generates a corresponding + * MANIFEST.MF file, and replaces the dummy one in the JAR with the + * generated one. + * + * See #3521 for details. + * + * @author magi + */ +public class GeneratePackageExports { + public static void main(String[] args) { + if (args.length < 1) { + System.err.println("Invalid number of parameters\n"+ + "Usage: java -cp .. GenerateManifest "); + System.exit(1); + } + + // Open tje JAR + String jarFilename = args[0]; + JarFile jar = null; + try { + jar = new JarFile(jarFilename); + } catch (IOException e) { + System.err.println("Unable to open JAR '"+jarFilename+"'"); + System.exit(1); + } + + // List the included Java packages + HashSet packages = new HashSet(); + for (Enumeration it = jar.entries(); it.hasMoreElements();) { + JarEntry entry = it.nextElement(); + if (entry.getName().startsWith("com") && entry.getName().endsWith(".class")) { + int lastSlash = entry.getName().lastIndexOf('/'); + String pkg = entry.getName().substring(0, lastSlash).replace('/', '.'); + packages.add(pkg); + } + } + + // List theme packages + for (Enumeration it = jar.entries(); it.hasMoreElements();) { + JarEntry entry = it.nextElement(); + if (entry.isDirectory() && entry.getName().startsWith("VAADIN/themes")) { + // Strip ending slash + int lastSlash = entry.getName().lastIndexOf('/'); + String pkg = entry.getName().substring(0, lastSlash).replace('/', '.'); + packages.add(pkg); + } + } + + // Replacement for the "Export-Package" attribute in the manifest + String exportPackage = ""; + + // Produce an ordered listing of the package names + String packageArray[] = new String[packages.size()]; + packages.toArray(packageArray); + Arrays.sort(packageArray); + for (int i=0; i keys = new Vector(mainAtts.size()); + for (Iterator attrit = mainAtts.keySet().iterator(); attrit.hasNext();) { + Name name = (Name) attrit.next(); + keys.add(name.toString()); + } + + // Put the manifest version as the first line + String orderedKeys[] = new String[keys.size()]; + keys.toArray(orderedKeys); + Arrays.sort(orderedKeys); // Must sort to be able to search + int mvPos = Arrays.binarySearch(orderedKeys, "Manifest-Version"); + orderedKeys[mvPos] = orderedKeys[0]; // Swap + orderedKeys[0] = "Manifest-Version"; + + // This final ordering is just for esthetic reasons and + // in practice unnecessary and will actually be messed up + // when the 'jar' command reads the manifest + Arrays.sort(orderedKeys, 1, orderedKeys.length-1); + + // Create the modified manifest + ManifestWriter manifest = new ManifestWriter(); + for (int i=0; i 72) { + int fitsLine = 72 - linelen; + buffer.append(remainingValue.substring(0, fitsLine) + "\n "); + remainingValue = remainingValue.substring(fitsLine); + linelen = 1; + } + buffer.append(remainingValue + "\n"); + } + + /** + * Writes the manifest to given JAR file. + * + * The manifest must be created with {@code #writeAttribute(String, String)} + * before calling this write. + * + * @param jarFilename File name of the JAR in which the manifest is written + * @return 0 on success, nonzero value on error + */ + int updateJar(String jarFilename) { + int status = 0; + + // Determine a temporary file name + String newMfPrefix = "vaadin-manifest-" + (new Date()).getTime(); + File newMfFile = null; + try { + newMfFile = File.createTempFile(newMfPrefix, ".mf"); + } catch (IOException e) { + System.err.println("Creating temp file failed"); + status = 1; + } + + // Write the manifest to the temporary file + if (status == 0) { + FileOutputStream fos = null; + try { + fos = new FileOutputStream(newMfFile); + fos.write(getBytes()); + fos.close(); + } catch (IOException e) { + System.err.println("Writing to file '"+newMfFile.getAbsolutePath() +"' failed because: " + e.getMessage()); + status = 1; + } + } + + // Check that the manifest is OK + if (status == 0) { + Manifest checkMf = new Manifest(); + FileInputStream is; + try { + is = new FileInputStream(newMfFile); + checkMf.read(is); + } catch (IOException e) { + System.err.println("Reading from file '"+newMfFile.getAbsolutePath() +"' failed because: " + e.getMessage()); + status = 1; + } + } + + // Update the manifest in the Jar + if (status == 0) { + System.out.println("Updating manifest in JAR " + jarFilename); + try { + // The "mf" order must correspond with manifest-jarfile order + Process process = Runtime.getRuntime().exec(new String[]{"jar", "umf", newMfFile.getAbsolutePath(), jarFilename}); + int exitValue = process.waitFor(); + if (exitValue != 0) { + InputStream jarErr = process.getErrorStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(jarErr)); + while (reader.ready()) { + System.err.println("jar: " + reader.readLine()); + } + System.err.println("The 'jar' command returned with exit value " + exitValue); + status = 1; + } + } catch (IOException e) { + System.err.println("Failed to execute 'jar' command. " + e.getMessage()); + status = 1; + } catch (InterruptedException e) { + System.err.println("Execution of 'jar' command was interrupted. " + e.getMessage()); + status = 1; + } + } + + // Remove the temporary file + if (newMfFile != null) + newMfFile.delete(); + + return status; + } + + public String toString() { + return buffer.toString(); + } + + public byte[] getBytes() { + return buffer.toString().getBytes(); + } +} \ No newline at end of file diff --git a/build/package/META-INF/MANIFEST.MF b/build/package/META-INF/MANIFEST.MF index b1bbf0b6ad..c787fcba06 100644 --- a/build/package/META-INF/MANIFEST.MF +++ b/build/package/META-INF/MANIFEST.MF @@ -2,6 +2,5 @@ Bundle-ManifestVersion: 2 Bundle-Name: Vaadin Bundle-SymbolicName: com.vaadin Bundle-Vendor: IT Mill Ltd -Export-Package: VAADIN.themes, VAADIN.themes.base, VAADIN.themes.base.absolutelayout, VAADIN.themes.base.accordion, VAADIN.themes.base.button, VAADIN.themes.base.caption, VAADIN.themes.base.common, VAADIN.themes.base.common.img, VAADIN.themes.base.csslayout, VAADIN.themes.base.customcomponent, VAADIN.themes.base.customlayout, VAADIN.themes.base.datefield, VAADIN.themes.base.formlayout, VAADIN.themes.base.gridlayout, VAADIN.themes.base.link, VAADIN.themes.base.menubar, VAADIN.themes.base.notification, VAADIN.themes.base.orderedlayout, VAADIN.themes.base.panel, VAADIN.themes.base.popupview, VAADIN.themes.base.progressindicator, VAADIN.themes.base.select, VAADIN.themes.base.shadow, VAADIN.themes.base.shadow.img, VAADIN.themes.base.slider, VAADIN.themes.base.splitpanel, VAADIN.themes.base.table, VAADIN.themes.base.tabsheet, VAADIN.themes.base.textfield, VAADIN.themes.base.tree, VAADIN.themes.base.upload, VAADIN.themes.base.window, VAADIN.themes.base.window.img.shadow, VAADIN.themes.reindeer, VAADIN.themes.reindeer.accordion, VAADIN.themes.reindeer.button, VAADIN.themes.reindeer.button.img, VAADIN.themes.reindeer.button.img.black, VAADIN.themes.reindeer.common, VAADIN.themes.reindeer.common.icons, VAADIN.themes.reindeer.common.img, VAADIN.themes.reindeer.datefield, VAADIN.themes.reindeer.datefield.img, VAADIN.themes.reindeer.formlayout, VAADIN.themes.reindeer.label, VAADIN.themes.reindeer.layouts,VAADIN.themes.reindeer.layouts.img,VAADIN.themes.reindeer.menubar,VAADIN.themes.reindeer.menubar.img,VAADIN.themes.reindeer.notification,VAADIN.themes.reindeer.notification.img,VAADIN.themes.reindeer.panel,VAADIN.themes.reindeer.progressindicator,VAADIN.themes.reindeer.progressindicator.img,VAADIN.themes.reindeer.select,VAADIN.themes.reindeer.select.img,VAADIN.themes.reindeer.select.img.black,VAADIN.themes.reindeer.slider,VAADIN.themes.reindeer.slider.img,VAADIN.themes.reindeer.splitpanel,VAADIN.themes.reindeer.splitpanel.img,VAADIN.themes.reindeer.table,VAADIN.themes.reindeer.table.img,VAADIN.themes.reindeer.tabsheet,VAADIN.themes.reindeer.tabsheet.img,VAADIN.themes.reindeer.tabsheet.img.bar,VAADIN.themes.reindeer.tabsheet.img.framed,VAADIN.themes.reindeer.textfield,VAADIN.themes.reindeer.textfield.img,VAADIN.themes.reindeer.tree,VAADIN.themes.reindeer.tree.img,VAADIN.themes.reindeer.window,VAADIN.themes.reindeer.window.img,VAADIN.themes.reindeer.window.img.black,VAADIN.themes.runo,VAADIN.themes.runo.absolutelayout,VAADIN.themes.runo.accordion,VAADIN.themes.runo.accordion.img,VAADIN.themes.runo.button,VAADIN.themes.runo.button.img,VAADIN.themes.runo.caption,VAADIN.themes.runo.common,VAADIN.themes.runo.common.img,VAADIN.themes.runo.datefield,VAADIN.themes.runo.datefield.img,VAADIN.themes.runo.formlayout,VAADIN.themes.runo.gridlayout,VAADIN.themes.runo.icons,VAADIN.themes.runo.link,VAADIN.themes.runo.menubar,VAADIN.themes.runo.notification,VAADIN.themes.runo.notification.img,VAADIN.themes.runo.orderedlayout,VAADIN.themes.runo.panel,VAADIN.themes.runo.panel.img,VAADIN.themes.runo.popupview,VAADIN.themes.runo.progressindicator,VAADIN.themes.runo.progressindicator.img,VAADIN.themes.runo.select,VAADIN.themes.runo.select.img,VAADIN.themes.runo.shadow,VAADIN.themes.runo.shadow.img,VAADIN.themes.runo.slider,VAADIN.themes.runo.slider.img,VAADIN.themes.runo.splitpanel,VAADIN.themes.runo.splitpanel.img,VAADIN.themes.runo.table,VAADIN.themes.runo.table.img,VAADIN.themes.runo.tabsheet,VAADIN.themes.runo.tabsheet.img,VAADIN.themes.runo.textfield,VAADIN.themes.runo.textfield.img,VAADIN.themes.runo.tree,VAADIN.themes.runo.tree.img,VAADIN.themes.runo.window,VAADIN.themes.runo.window.img,VAADIN.themes.runo.window.img.shadow,VAADIN.widgetsets,VAADIN.widgetsets.com.vaadin.terminal.gwt.DefaultWidgetSet,com.vaadin,com.vaadin.annotations,com.vaadin.data,com.vaadin.data.util,com.vaadin.data.validator,com.vaadin.event,com.vaadin.event.dd,com.vaadin.event.dd.acceptcriteria,com.vaadin.external.org.apache.commons.fileupload,com.vaadin.external.org.apache.commons.fileupload.disk,com.vaadin.external.org.apache.commons.fileupload.portlet,com.vaadin.external.org.apache.commons.fileupload.servlet,com.vaadin.external.org.apache.commons.fileupload.util,com.vaadin.portal.gwt,com.vaadin.portal.gwt.client,com.vaadin.service,com.vaadin.terminal,com.vaadin.terminal.gwt,com.vaadin.terminal.gwt.client,com.vaadin.terminal.gwt.client.ui,com.vaadin.terminal.gwt.client.ui.dd,com.vaadin.terminal.gwt.client.ui.layout,com.vaadin.terminal.gwt.client.ui.richtextarea,com.vaadin.terminal.gwt.server,com.vaadin.tools,com.vaadin.ui,com.vaadin.ui.themes,com.vaadin.util Bundle-RequiredExecutionEnvironment: J2SE-1.5 Import-Package: javax.servlet; version="2.3.0",javax.servlet.http; version="2.3.0" -- cgit v1.2.3