import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
-import java.util.Vector;
import java.util.jar.Attributes;
-import java.util.jar.Attributes.Name;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
/**
* 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.
- *
+ * <p>
+ * Reads the included Java packages in a jar file, generates a corresponding
+ * Export-Package attribute, and appends it to the jar's MANIFEST.MF.
+ * <p>
* See #3521 for details.
*
* @author magi
*/
public class GeneratePackageExports {
+ private static final String EXPORT_PACKAGE_ATTRIBUTE = "Export-Package";
+
public static void main(String[] args) {
if (args.length < 2) {
System.err
}
// List the included Java packages
+ HashSet<String> packages = getPackages(jar, acceptedPackagePrefixes);
+
+ // Avoid writing empty Export-Package attribute
+ if (packages.isEmpty()) {
+ return;
+ }
+
+ String exportPackage = sortAndJoinPackages(packages);
+
+ // Read old manifest
+ Manifest oldMF = null;
+ try {
+ oldMF = jar.getManifest();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ Attributes mainAttributes = oldMF.getMainAttributes();
+
+ String existingExportPackage = mainAttributes
+ .getValue(EXPORT_PACKAGE_ATTRIBUTE);
+ if (existingExportPackage != null) {
+ exportPackage = existingExportPackage + "," + exportPackage;
+ }
+
+ // Jar must be closed before updating it below, as it's
+ // locked in Windows until closed. (#6045)
+ try {
+ jar.close();
+ } catch (IOException e) {
+ System.err.println("Unable to close JAR '" + jarFilename + "'");
+ }
+
+ // Create the modified manifest
+ ManifestWriter manifest = new ManifestWriter();
+ manifest.writeAttribute(EXPORT_PACKAGE_ATTRIBUTE, exportPackage);
+
+ // Update the manifest in the Jar. The jar must be closed
+ // before this is done.
+ int status = manifest.updateJar(jarFilename);
+
+ if (status != 0) {
+ System.exit(status);
+ }
+ }
+
+ private static String sortAndJoinPackages(HashSet<String> packages) {
+ // Produce an ordered listing of the package names
+ String packageArray[] = new String[packages.size()];
+ packages.toArray(packageArray);
+ Arrays.sort(packageArray);
+ StringBuilder joinedPackages = new StringBuilder();
+ for (int i = 0; i < packageArray.length; i++) {
+ if (i != 0) {
+ joinedPackages.append(",");
+ }
+
+ joinedPackages.append(packageArray[i]);
+ }
+
+ return joinedPackages.toString();
+ }
+
+ private static HashSet<String> getPackages(JarFile jar,
+ List<String> acceptedPackagePrefixes) {
HashSet<String> packages = new HashSet<String>();
for (Enumeration<JarEntry> it = jar.entries(); it.hasMoreElements();) {
JarEntry entry = it.nextElement();
}
}
- // 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 < packageArray.length; i++) {
- if (i == 0) {
- exportPackage = packageArray[i];
- } else {
- exportPackage += ", " + packageArray[i];
- }
- }
-
- // Read old manifest
- Manifest oldMF = null;
- try {
- oldMF = jar.getManifest();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // Read main attributes
- Attributes mainAtts = oldMF.getMainAttributes();
- Vector<String> keys = new Vector<String>(mainAtts.size());
- for (Iterator<Object> attrit = mainAtts.keySet().iterator(); attrit
- .hasNext();) {
- Name name = (Name) attrit.next();
- keys.add(name.toString());
- }
-
- // Jar must be closed before updating it below, as it's
- // locked in Windows until closed. (#6045)
- try {
- jar.close();
- } catch (IOException e) {
- System.err.println("Unable to close JAR '" + jarFilename + "'");
- }
-
- // 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 < orderedKeys.length; i++) {
- // Skip an existing Export-Package attribute
- if (orderedKeys[i].equals("Export-Package")) {
- // Copy the attribute to the modified manifest
- manifest.writeAttribute(orderedKeys[i],
- mainAtts.getValue(orderedKeys[i]));
- }
- }
-
- // Add the Export-Package attribute at the end of the manifest.
- // The alternative would be replacing an existing attribute in
- // the loop above, but it's not guaranteed that it exists.
- manifest.writeAttribute("Export-Package", exportPackage);
-
- // Update the manifest in the Jar. The jar must be closed
- // before this is done.
- int status = manifest.updateJar(jarFilename);
-
- if (status != 0) {
- System.exit(status);
- }
+ return packages;
}
}