1. /*
  2. * Copyright 2002-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of 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,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs;
  18. import java.io.File;
  19. import java.io.FileInputStream;
  20. import java.io.InputStreamReader;
  21. import java.io.FileOutputStream;
  22. import java.io.OutputStreamWriter;
  23. import java.io.IOException;
  24. import java.io.PrintWriter;
  25. import org.apache.tools.ant.BuildException;
  26. import org.apache.tools.ant.Project;
  27. import org.apache.tools.ant.Task;
  28. import org.apache.tools.ant.types.EnumeratedAttribute;
  29. /**
  30. * Creates a manifest file for inclusion in a JAR, Ant task wrapper
  31. * around {@link Manifest Manifest}. This task can be used to write a
  32. * Manifest file, optionally replacing or updating an existing file.
  33. *
  34. *
  35. * @since Ant 1.5
  36. *
  37. * @ant.task category="java"
  38. */
  39. public class ManifestTask extends Task {
  40. /**
  41. * Holds the real data.
  42. */
  43. private Manifest nestedManifest = new Manifest();
  44. /**
  45. * The file to which the manifest should be written when used as a task
  46. */
  47. private File manifestFile;
  48. /**
  49. * The mode with which the manifest file is written
  50. */
  51. private Mode mode;
  52. /**
  53. * The encoding of the manifest file
  54. */
  55. private String encoding;
  56. /**
  57. * Helper class for Manifest's mode attribute.
  58. */
  59. public static class Mode extends EnumeratedAttribute {
  60. /**
  61. * Get Allowed values for the mode attribute.
  62. *
  63. * @return a String array of the allowed values.
  64. */
  65. public String[] getValues() {
  66. return new String[] {"update", "replace"};
  67. }
  68. }
  69. /**
  70. * Default constructor
  71. */
  72. public ManifestTask() {
  73. mode = new Mode();
  74. mode.setValue("replace");
  75. }
  76. /**
  77. * Add a section to the manifest
  78. *
  79. * @param section the manifest section to be added
  80. *
  81. * @exception ManifestException if the section is not valid.
  82. */
  83. public void addConfiguredSection(Manifest.Section section)
  84. throws ManifestException {
  85. nestedManifest.addConfiguredSection(section);
  86. }
  87. /**
  88. * Add an attribute to the manifest - it is added to the main section.
  89. *
  90. * @param attribute the attribute to be added.
  91. *
  92. * @exception ManifestException if the attribute is not valid.
  93. */
  94. public void addConfiguredAttribute(Manifest.Attribute attribute)
  95. throws ManifestException {
  96. nestedManifest.addConfiguredAttribute(attribute);
  97. }
  98. /**
  99. * The name of the manifest file to create/update.
  100. * Required if used as a task.
  101. * @param f the Manifest file to be written
  102. */
  103. public void setFile(File f) {
  104. manifestFile = f;
  105. }
  106. /**
  107. * The encoding to use for reading in an existing manifest file
  108. * @param encoding the manifest file encoding.
  109. */
  110. public void setEncoding(String encoding) {
  111. this.encoding = encoding;
  112. }
  113. /**
  114. * Update policy: either "update" or "replace"; default is "replace".
  115. * @param m the mode value - update or replace.
  116. */
  117. public void setMode(Mode m) {
  118. mode = m;
  119. }
  120. /**
  121. * Create or update the Manifest when used as a task.
  122. *
  123. * @throws BuildException if the manifest cannot be written.
  124. */
  125. public void execute() throws BuildException {
  126. if (manifestFile == null) {
  127. throw new BuildException("the file attribute is required");
  128. }
  129. Manifest toWrite = Manifest.getDefaultManifest();
  130. Manifest current = null;
  131. BuildException error = null;
  132. if (manifestFile.exists()) {
  133. FileInputStream fis = null;
  134. InputStreamReader isr = null;
  135. try {
  136. fis = new FileInputStream(manifestFile);
  137. if (encoding == null) {
  138. isr = new InputStreamReader(fis, "UTF-8");
  139. } else {
  140. isr = new InputStreamReader(fis, encoding);
  141. }
  142. current = new Manifest(isr);
  143. } catch (ManifestException m) {
  144. error = new BuildException("Existing manifest " + manifestFile
  145. + " is invalid", m, getLocation());
  146. } catch (IOException e) {
  147. error = new BuildException("Failed to read " + manifestFile,
  148. e, getLocation());
  149. } finally {
  150. if (isr != null) {
  151. try {
  152. isr.close();
  153. } catch (IOException e) {
  154. // ignore
  155. }
  156. }
  157. }
  158. }
  159. try {
  160. if (mode.getValue().equals("update") && manifestFile.exists()) {
  161. if (current != null) {
  162. toWrite.merge(current);
  163. } else if (error != null) {
  164. throw error;
  165. }
  166. }
  167. toWrite.merge(nestedManifest);
  168. } catch (ManifestException m) {
  169. throw new BuildException("Manifest is invalid", m, getLocation());
  170. }
  171. if (toWrite.equals(current)) {
  172. log("Manifest has not changed, do not recreate",
  173. Project.MSG_VERBOSE);
  174. return;
  175. }
  176. PrintWriter w = null;
  177. try {
  178. FileOutputStream fos = new FileOutputStream(manifestFile);
  179. OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
  180. w = new PrintWriter(osw);
  181. toWrite.write(w);
  182. } catch (IOException e) {
  183. throw new BuildException("Failed to write " + manifestFile,
  184. e, getLocation());
  185. } finally {
  186. if (w != null) {
  187. w.close();
  188. }
  189. }
  190. }
  191. }