You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GeneratePackageExports.java 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * Copyright 2000-2014 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.buildhelpers;
  17. import java.io.IOException;
  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.Enumeration;
  21. import java.util.HashSet;
  22. import java.util.List;
  23. import java.util.jar.Attributes;
  24. import java.util.jar.JarEntry;
  25. import java.util.jar.JarFile;
  26. import java.util.jar.Manifest;
  27. import java.util.logging.Logger;
  28. /**
  29. * Generates Export-Packages attribute for OSGi compatible manifest.
  30. * <p>
  31. * Reads the included Java packages in a jar file, generates a corresponding
  32. * Export-Package attribute, and appends it to the jar's MANIFEST.MF.
  33. * <p>
  34. * See #3521 for details.
  35. *
  36. * @author magi
  37. */
  38. public class GeneratePackageExports {
  39. private static final String EXPORT_PACKAGE_ATTRIBUTE = "Export-Package";
  40. public static void main(String[] args) {
  41. if (args.length < 2) {
  42. System.err
  43. .println("Invalid number of parameters\n"
  44. + "Usage: java -cp .. GenerateManifest <package.jar> <accepted package prefixes>\n"
  45. + "Use -Dvaadin.version to specify the version to be used for the packages");
  46. System.exit(1);
  47. }
  48. // Open the JAR
  49. String jarFilename = args[0];
  50. JarFile jar = null;
  51. try {
  52. jar = new JarFile(jarFilename);
  53. } catch (IOException e) {
  54. System.err.println("Unable to open JAR '" + jarFilename + "'");
  55. System.exit(1);
  56. }
  57. // Accepted packages
  58. List<String> acceptedPackagePrefixes = new ArrayList<String>();
  59. for (int i = 1; i < args.length; i++) {
  60. acceptedPackagePrefixes.add(args[i]);
  61. }
  62. // List the included Java packages
  63. HashSet<String> packages = getPackages(jar, acceptedPackagePrefixes);
  64. // Avoid writing empty Export-Package attribute
  65. if (packages.isEmpty()) {
  66. return;
  67. }
  68. String exportPackage = sortAndJoinPackages(packages);
  69. // Read old manifest
  70. Manifest oldMF = null;
  71. try {
  72. oldMF = jar.getManifest();
  73. } catch (IOException e) {
  74. e.printStackTrace();
  75. }
  76. Attributes mainAttributes = oldMF.getMainAttributes();
  77. String existingExportPackage = mainAttributes
  78. .getValue(EXPORT_PACKAGE_ATTRIBUTE);
  79. if (existingExportPackage != null) {
  80. exportPackage = existingExportPackage + "," + exportPackage;
  81. }
  82. // Jar must be closed before updating it below, as it's
  83. // locked in Windows until closed. (#6045)
  84. try {
  85. jar.close();
  86. } catch (IOException e) {
  87. System.err.println("Unable to close JAR '" + jarFilename + "'");
  88. }
  89. // Create the modified manifest
  90. ManifestWriter manifest = new ManifestWriter();
  91. manifest.writeAttribute(EXPORT_PACKAGE_ATTRIBUTE, exportPackage);
  92. // Update the manifest in the Jar. The jar must be closed
  93. // before this is done.
  94. int status = manifest.updateJar(jarFilename);
  95. if (status != 0) {
  96. System.exit(status);
  97. }
  98. }
  99. private static String sortAndJoinPackages(HashSet<String> packages) {
  100. // Produce an ordered listing of the package names
  101. String packageArray[] = new String[packages.size()];
  102. packages.toArray(packageArray);
  103. Arrays.sort(packageArray);
  104. StringBuilder joinedPackages = new StringBuilder();
  105. for (int i = 0; i < packageArray.length; i++) {
  106. if (i != 0) {
  107. joinedPackages.append(",");
  108. }
  109. String version = getVersion(packageArray[i]);
  110. String packageAndVersion = packageArray[i];
  111. if (version != null) {
  112. packageAndVersion += ";version=\"" + version + "\"";
  113. } else {
  114. Logger.getLogger(GeneratePackageExports.class.getName())
  115. .severe("No version defined for " + packageArray[i]);
  116. }
  117. joinedPackages.append(packageAndVersion);
  118. }
  119. return joinedPackages.toString();
  120. }
  121. /**
  122. * Tries to find version specified using system properties of type
  123. * version.<java package>. Searches for the packge and then its parents
  124. * recursively. Falls back to the "vaadin.version" system property if no
  125. * other properties are found.
  126. *
  127. * @param javaPackage
  128. * The package to determine a version for
  129. * @return A version or null if no version has been defined
  130. */
  131. private static String getVersion(String javaPackage) {
  132. String packageVersion = System.getProperty("version." + javaPackage);
  133. if (packageVersion != null) {
  134. return packageVersion;
  135. }
  136. String parentPackage = null;
  137. if (javaPackage.contains(".")) {
  138. parentPackage = javaPackage.substring(0,
  139. javaPackage.lastIndexOf('.'));
  140. String parentVersion = getVersion(parentPackage);
  141. if (parentVersion != null) {
  142. return parentVersion;
  143. }
  144. }
  145. String vaadinVersion = System.getProperty("vaadin.version");
  146. if (vaadinVersion != null) {
  147. return vaadinVersion;
  148. }
  149. return null;
  150. }
  151. private static HashSet<String> getPackages(JarFile jar,
  152. List<String> acceptedPackagePrefixes) {
  153. HashSet<String> packages = new HashSet<String>();
  154. for (Enumeration<JarEntry> it = jar.entries(); it.hasMoreElements();) {
  155. JarEntry entry = it.nextElement();
  156. boolean classFile = entry.getName().endsWith(".class");
  157. boolean directory = entry.isDirectory();
  158. if (!classFile && !directory) {
  159. continue;
  160. }
  161. if (!acceptEntry(entry.getName(), acceptedPackagePrefixes)) {
  162. continue;
  163. }
  164. int lastSlash = entry.getName().lastIndexOf('/');
  165. String pkg = entry.getName().substring(0, lastSlash)
  166. .replace('/', '.');
  167. packages.add(pkg);
  168. }
  169. return packages;
  170. }
  171. private static boolean acceptEntry(String name,
  172. List<String> acceptedPackagePrefixes) {
  173. for (String prefix : acceptedPackagePrefixes) {
  174. if (name.startsWith(prefix)) {
  175. return true;
  176. }
  177. }
  178. return false;
  179. }
  180. }