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

Manifest.java 29 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 2001 The Apache Software Foundation. All rights
  5. * reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if
  20. * any, must include the following acknowlegement:
  21. * "This product includes software developed by the
  22. * Apache Software Foundation (http://www.apache.org/)."
  23. * Alternately, this acknowlegement may appear in the software itself,
  24. * if and wherever such third-party acknowlegements normally appear.
  25. *
  26. * 4. The names "The Jakarta Project", "Ant", and "Apache Software
  27. * Foundation" must not be used to endorse or promote products derived
  28. * from this software without prior written permission. For written
  29. * permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache"
  32. * nor may "Apache" appear in their names without prior written
  33. * permission of the Apache Group.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation. For more
  51. * information on the Apache Software Foundation, please see
  52. * <http://www.apache.org/>.
  53. */
  54. package org.apache.tools.ant.taskdefs;
  55. import java.util.Vector;
  56. import java.util.Hashtable;
  57. import java.util.Enumeration;
  58. import java.io.BufferedReader;
  59. import java.io.File;
  60. import java.io.FileReader;
  61. import java.io.FileWriter;
  62. import java.io.IOException;
  63. import java.io.InputStream;
  64. import java.io.InputStreamReader;
  65. import java.io.PrintWriter;
  66. import java.io.Reader;
  67. import java.io.StringWriter;
  68. import java.io.UnsupportedEncodingException;
  69. import org.apache.tools.ant.BuildException;
  70. import org.apache.tools.ant.Task;
  71. import org.apache.tools.ant.types.EnumeratedAttribute;
  72. /**
  73. * Class to manage Manifest information
  74. *
  75. * @author <a href="mailto:conor@apache.org">Conor MacNeill</a>
  76. * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
  77. */
  78. public class Manifest extends Task {
  79. /** The standard manifest version header */
  80. public final static String ATTRIBUTE_MANIFEST_VERSION = "Manifest-Version";
  81. /** The standard Signature Version header */
  82. public final static String ATTRIBUTE_SIGNATURE_VERSION = "Signature-Version";
  83. /** The Name Attribute is the first in a named section */
  84. public final static String ATTRIBUTE_NAME = "Name";
  85. /** The From Header is disallowed in a Manifest */
  86. public final static String ATTRIBUTE_FROM = "From";
  87. /** The Class-Path Header is special - it can be duplicated */
  88. public final static String ATTRIBUTE_CLASSPATH = "class-path";
  89. /** Default Manifest version if one is not specified */
  90. public final static String DEFAULT_MANIFEST_VERSION = "1.0";
  91. /** The max length of a line in a Manifest */
  92. public final static int MAX_LINE_LENGTH = 70;
  93. /**
  94. * Helper class for Manifest's mode attribute.
  95. */
  96. public static class Mode extends EnumeratedAttribute {
  97. public String[] getValues() {
  98. return new String[] {"update", "replace"};
  99. }
  100. }
  101. /**
  102. * Class to hold manifest attributes
  103. */
  104. public static class Attribute {
  105. /** The attribute's name */
  106. private String name = null;
  107. /** The attribute's value */
  108. private String value = null;
  109. /**
  110. * Construct an empty attribute */
  111. public Attribute() {
  112. }
  113. /**
  114. * Construct an attribute by parsing a line from the Manifest
  115. *
  116. * @param line the line containing the attribute name and value
  117. *
  118. * @throws ManifestException if the line is not valid
  119. */
  120. public Attribute(String line) throws ManifestException {
  121. parse(line);
  122. }
  123. /**
  124. * Construct a manifest by specifying its name and value
  125. *
  126. * @param name the attribute's name
  127. * @param value the Attribute's value
  128. */
  129. public Attribute(String name, String value) {
  130. this.name = name;
  131. this.value = value;
  132. }
  133. public boolean equals(Object rhs) {
  134. if (!(rhs instanceof Attribute)) {
  135. return false;
  136. }
  137. Attribute rhsAttribute = (Attribute)rhs;
  138. return (name != null && rhsAttribute.name != null &&
  139. name.toLowerCase().equals(rhsAttribute.name.toLowerCase()) &&
  140. value != null && value.equals(rhsAttribute.value));
  141. }
  142. /**
  143. * Parse a line into name and value pairs
  144. *
  145. * @param line the line to be parsed
  146. *
  147. * @throws ManifestException if the line does not contain a colon
  148. * separating the name and value
  149. */
  150. public void parse(String line) throws ManifestException {
  151. int index = line.indexOf(": ");
  152. if (index == -1) {
  153. throw new ManifestException("Manifest line \"" + line + "\" is not valid as it does not " +
  154. "contain a name and a value separated by ': ' ");
  155. }
  156. name = line.substring(0, index);
  157. value = line.substring(index + 2);
  158. }
  159. /**
  160. * Set the Attribute's name
  161. *
  162. * @param name the attribute's name
  163. */
  164. public void setName(String name) {
  165. this.name = name;
  166. }
  167. /**
  168. * Get the Attribute's name
  169. *
  170. * @return the attribute's name.
  171. */
  172. public String getName() {
  173. return name;
  174. }
  175. /**
  176. * Set the Attribute's value
  177. *
  178. * @param value the attribute's value
  179. */
  180. public void setValue(String value) {
  181. this.value = value;
  182. }
  183. /**
  184. * Get the Attribute's value
  185. *
  186. * @return the attribute's value.
  187. */
  188. public String getValue() {
  189. return value;
  190. }
  191. /**
  192. * Add a continuation line from the Manifest file
  193. *
  194. * When lines are too long in a manifest, they are continued on the
  195. * next line by starting with a space. This method adds the continuation
  196. * data to the attribute value by skipping the first character.
  197. */
  198. public void addContinuation(String line) {
  199. value += line.substring(1);
  200. }
  201. /**
  202. * Write the attribute out to a print writer.
  203. *
  204. * @param writer the Writer to which the attribute is written
  205. *
  206. * @throws IOException if the attribte value cannot be written
  207. */
  208. public void write(PrintWriter writer) throws IOException {
  209. String line = name + ": " + value;
  210. while (line.getBytes().length > MAX_LINE_LENGTH) {
  211. // try to find a MAX_LINE_LENGTH byte section
  212. int breakIndex = MAX_LINE_LENGTH;
  213. String section = line.substring(0, breakIndex);
  214. while (section.getBytes().length > MAX_LINE_LENGTH && breakIndex > 0) {
  215. breakIndex--;
  216. section = line.substring(0, breakIndex);
  217. }
  218. if (breakIndex == 0) {
  219. throw new IOException("Unable to write manifest line " + name + ": " + value);
  220. }
  221. writer.println(section);
  222. line = " " + line.substring(breakIndex);
  223. }
  224. writer.println(line);
  225. }
  226. }
  227. /**
  228. * Class to represent an individual section in the
  229. * Manifest. A section consists of a set of attribute values,
  230. * separated from other sections by a blank line.
  231. */
  232. public static class Section {
  233. private Vector warnings = new Vector();
  234. /** The section's name if any. The main section in a manifest is unnamed.*/
  235. private String name = null;
  236. /** The section's attributes.*/
  237. private Hashtable attributes = new Hashtable();
  238. /**
  239. * Set the Section's name
  240. *
  241. * @param name the section's name
  242. */
  243. public void setName(String name) {
  244. this.name = name;
  245. }
  246. /**
  247. * Get the Section's name
  248. *
  249. * @return the section's name.
  250. */
  251. public String getName() {
  252. return name;
  253. }
  254. /**
  255. * Read a section through a reader
  256. *
  257. * @param reader the reader from which the section is read
  258. *
  259. * @return the name of the next section if it has been read as part of this
  260. * section - This only happens if the Manifest is malformed.
  261. *
  262. * @throws ManifestException if the section is not valid according to the JAR spec
  263. * @throws IOException if the section cannot be read from the reader.
  264. */
  265. public String read(BufferedReader reader) throws ManifestException, IOException {
  266. Attribute attribute = null;
  267. while (true) {
  268. String line = reader.readLine();
  269. if (line == null || line.length() == 0) {
  270. return null;
  271. }
  272. if (line.charAt(0) == ' ') {
  273. // continuation line
  274. if (attribute == null) {
  275. if (name != null) {
  276. // a continuation on the first line is a continuation of the name - concatenate
  277. // this line and the name
  278. name += line.substring(1);
  279. }
  280. else {
  281. throw new ManifestException("Can't start an attribute with a continuation line " + line);
  282. }
  283. }
  284. else {
  285. attribute.addContinuation(line);
  286. }
  287. }
  288. else {
  289. attribute = new Attribute(line);
  290. String nameReadAhead = addAttributeAndCheck(attribute);
  291. if (nameReadAhead != null) {
  292. return nameReadAhead;
  293. }
  294. }
  295. }
  296. }
  297. /**
  298. * Merge in another section
  299. *
  300. * @param section the section to be merged with this one.
  301. *
  302. * @throws ManifestException if the sections cannot be merged.
  303. */
  304. public void merge(Section section) throws ManifestException {
  305. if (name == null && section.getName() != null ||
  306. name != null && !(name.equalsIgnoreCase(section.getName()))) {
  307. throw new ManifestException("Unable to merge sections with different names");
  308. }
  309. for (Enumeration e = section.attributes.keys(); e.hasMoreElements();) {
  310. String attributeName = (String)e.nextElement();
  311. if (attributeName.equals(ATTRIBUTE_CLASSPATH) &&
  312. attributes.containsKey(attributeName)) {
  313. // classpath entries are vetors which are merged
  314. Vector classpathAttrs = (Vector)section.attributes.get(attributeName);
  315. Vector ourClasspathAttrs = (Vector)attributes.get(attributeName);
  316. for (Enumeration e2 = classpathAttrs.elements(); e2.hasMoreElements();) {
  317. ourClasspathAttrs.addElement(e2.nextElement());
  318. }
  319. }
  320. else {
  321. // the merge file always wins
  322. attributes.put(attributeName, section.attributes.get(attributeName));
  323. }
  324. }
  325. // add in the warnings
  326. for (Enumeration e = section.warnings.elements(); e.hasMoreElements();) {
  327. warnings.addElement(e.nextElement());
  328. }
  329. }
  330. /**
  331. * Write the section out to a print writer.
  332. *
  333. * @param writer the Writer to which the section is written
  334. *
  335. * @throws IOException if the section cannot be written
  336. */
  337. public void write(PrintWriter writer) throws IOException {
  338. if (name != null) {
  339. Attribute nameAttr = new Attribute(ATTRIBUTE_NAME, name);
  340. nameAttr.write(writer);
  341. }
  342. for (Enumeration e = attributes.elements(); e.hasMoreElements();) {
  343. Object object = e.nextElement();
  344. if (object instanceof Attribute) {
  345. Attribute attribute = (Attribute)object;
  346. attribute.write(writer);
  347. }
  348. else {
  349. Vector attrList = (Vector)object;
  350. for (Enumeration e2 = attrList.elements(); e2.hasMoreElements();) {
  351. Attribute attribute = (Attribute)e2.nextElement();
  352. attribute.write(writer);
  353. }
  354. }
  355. }
  356. writer.println();
  357. }
  358. /**
  359. * Get the value of the attribute with the name given.
  360. *
  361. * @param attributeName the name of the attribute to be returned.
  362. *
  363. * @return the attribute's value or null if the attribute does not exist
  364. * in the section
  365. */
  366. public String getAttributeValue(String attributeName) {
  367. Object attribute = attributes.get(attributeName.toLowerCase());
  368. if (attribute == null) {
  369. return null;
  370. }
  371. if (attribute instanceof Attribute) {
  372. return ((Attribute)attribute).getValue();
  373. }
  374. else {
  375. String value = "";
  376. for (Enumeration e = ((Vector)attribute).elements(); e.hasMoreElements();) {
  377. Attribute classpathAttribute = (Attribute)e.nextElement();
  378. value += classpathAttribute.getValue() + " ";
  379. }
  380. return value.trim();
  381. }
  382. }
  383. /**
  384. * Remove tge given attribute from the section
  385. *
  386. * @param attributeName the name of the attribute to be removed.
  387. */
  388. public void removeAttribute(String attributeName) {
  389. attributes.remove(attributeName.toLowerCase());
  390. }
  391. public void addConfiguredAttribute(Attribute attribute) throws ManifestException {
  392. String check = addAttributeAndCheck(attribute);
  393. if (check != null) {
  394. throw new BuildException("Specify the section name using the \"name\" attribute of the <section> element rather " +
  395. "than using a \"Name\" manifest attribute");
  396. }
  397. }
  398. /**
  399. * Add an attribute to the section
  400. *
  401. * @param attribute the attribute to be added.
  402. *
  403. * @return the value of the attribute if it is a name attribute - null other wise
  404. *
  405. * @throws ManifestException if the attribute already exists in this section.
  406. */
  407. public String addAttributeAndCheck(Attribute attribute) throws ManifestException {
  408. if (attribute.getName() == null || attribute.getValue() == null) {
  409. throw new BuildException("Attributes must have name and value");
  410. }
  411. if (attribute.getName().equalsIgnoreCase(ATTRIBUTE_NAME)) {
  412. warnings.addElement("\"" + ATTRIBUTE_NAME + "\" attributes should not occur in the " +
  413. "main section and must be the first element in all " +
  414. "other sections: \"" +attribute.getName() + ": " + attribute.getValue() + "\"");
  415. return attribute.getValue();
  416. }
  417. if (attribute.getName().toLowerCase().startsWith(ATTRIBUTE_FROM.toLowerCase())) {
  418. warnings.addElement("Manifest attributes should not start with \"" +
  419. ATTRIBUTE_FROM + "\" in \"" +attribute.getName() + ": " + attribute.getValue() + "\"");
  420. }
  421. else {
  422. // classpath attributes go into a vector
  423. String attributeName = attribute.getName().toLowerCase();
  424. if (attributeName.equals(ATTRIBUTE_CLASSPATH)) {
  425. Vector classpathAttrs = (Vector)attributes.get(attributeName);
  426. if (classpathAttrs == null) {
  427. classpathAttrs = new Vector();
  428. attributes.put(attributeName, classpathAttrs);
  429. }
  430. classpathAttrs.addElement(attribute);
  431. }
  432. else if (attributes.containsKey(attributeName)) {
  433. throw new ManifestException("The attribute \"" + attribute.getName() + "\" may not " +
  434. "occur more than once in the same section");
  435. }
  436. else {
  437. attributes.put(attributeName, attribute);
  438. }
  439. }
  440. return null;
  441. }
  442. public Enumeration getWarnings() {
  443. return warnings.elements();
  444. }
  445. public boolean equals(Object rhs) {
  446. if (!(rhs instanceof Section)) {
  447. return false;
  448. }
  449. Section rhsSection = (Section)rhs;
  450. if (attributes.size() != rhsSection.attributes.size()) {
  451. return false;
  452. }
  453. for (Enumeration e = attributes.elements(); e.hasMoreElements();) {
  454. Attribute attribute = (Attribute)e.nextElement();
  455. Attribute rshAttribute = (Attribute)rhsSection.attributes.get(attribute.getName().toLowerCase());
  456. if (!attribute.equals(rshAttribute)) {
  457. return false;
  458. }
  459. }
  460. return true;
  461. }
  462. }
  463. /** The version of this manifest */
  464. private String manifestVersion = DEFAULT_MANIFEST_VERSION;
  465. /** The main section of this manifest */
  466. private Section mainSection = new Section();
  467. /** The named sections of this manifest */
  468. private Hashtable sections = new Hashtable();
  469. /**
  470. * Construct a manifest from Ant's default manifest file.
  471. */
  472. public static Manifest getDefaultManifest() throws BuildException {
  473. try {
  474. String s = "/org/apache/tools/ant/defaultManifest.mf";
  475. InputStream in = Manifest.class.getResourceAsStream(s);
  476. if (in == null) {
  477. throw new BuildException("Could not find default manifest: " + s);
  478. }
  479. try {
  480. return new Manifest(new InputStreamReader(in, "ASCII"));
  481. } catch (UnsupportedEncodingException e) {
  482. return new Manifest(new InputStreamReader(in));
  483. }
  484. }
  485. catch (ManifestException e) {
  486. throw new BuildException("Default manifest is invalid !!");
  487. }
  488. catch (IOException e) {
  489. throw new BuildException("Unable to read default manifest", e);
  490. }
  491. }
  492. /** Construct an empty manifest */
  493. public Manifest() {
  494. mode = new Mode();
  495. mode.setValue("replace");
  496. manifestVersion = null;
  497. }
  498. /**
  499. * Read a manifest file from the given reader
  500. *
  501. * @param is the reader from which the Manifest is read
  502. *
  503. * @throws ManifestException if the manifest is not valid according to the JAR spec
  504. * @throws IOException if the manifest cannot be read from the reader.
  505. */
  506. public Manifest(Reader r) throws ManifestException, IOException {
  507. BufferedReader reader = new BufferedReader(r);
  508. // This should be the manifest version
  509. String nextSectionName = mainSection.read(reader);
  510. String readManifestVersion = mainSection.getAttributeValue(ATTRIBUTE_MANIFEST_VERSION);
  511. if (readManifestVersion != null) {
  512. manifestVersion = readManifestVersion;
  513. mainSection.removeAttribute(ATTRIBUTE_MANIFEST_VERSION);
  514. }
  515. String line = null;
  516. while ((line = reader.readLine()) != null) {
  517. if (line.length() == 0) {
  518. continue;
  519. }
  520. Section section = new Section();
  521. if (nextSectionName == null) {
  522. Attribute sectionName = new Attribute(line);
  523. if (!sectionName.getName().equalsIgnoreCase(ATTRIBUTE_NAME)) {
  524. throw new ManifestException("Manifest sections should start with a \"" + ATTRIBUTE_NAME +
  525. "\" attribute and not \"" + sectionName.getName() + "\"");
  526. }
  527. nextSectionName = sectionName.getValue();
  528. }
  529. else {
  530. // we have already started reading this section
  531. // this line is the first attribute. set it and then let the normal
  532. // read handle the rest
  533. Attribute firstAttribute = new Attribute(line);
  534. section.addAttributeAndCheck(firstAttribute);
  535. }
  536. section.setName(nextSectionName);
  537. nextSectionName = section.read(reader);
  538. addConfiguredSection(section);
  539. }
  540. }
  541. public void addConfiguredSection(Section section) throws ManifestException {
  542. if (section.getName() == null) {
  543. throw new BuildException("Sections must have a name");
  544. }
  545. sections.put(section.getName().toLowerCase(), section);
  546. }
  547. public void addConfiguredAttribute(Attribute attribute) throws ManifestException {
  548. mainSection.addConfiguredAttribute(attribute);
  549. }
  550. /**
  551. * Merge the contents of the given manifest into this manifest
  552. *
  553. * @param other the Manifest to be merged with this one.
  554. *
  555. * @throws ManifestException if there is a problem merging the manfest according
  556. * to the Manifest spec.
  557. */
  558. public void merge(Manifest other) throws ManifestException {
  559. if (other.manifestVersion != null) {
  560. manifestVersion = other.manifestVersion;
  561. }
  562. mainSection.merge(other.mainSection);
  563. for (Enumeration e = other.sections.keys(); e.hasMoreElements();) {
  564. String sectionName = (String)e.nextElement();
  565. Section ourSection = (Section)sections.get(sectionName);
  566. Section otherSection = (Section)other.sections.get(sectionName);
  567. if (ourSection == null) {
  568. sections.put(sectionName.toLowerCase(), otherSection);
  569. }
  570. else {
  571. ourSection.merge(otherSection);
  572. }
  573. }
  574. }
  575. /**
  576. * Write the manifest out to a print writer.
  577. *
  578. * @param writer the Writer to which the manifest is written
  579. *
  580. * @throws IOException if the manifest cannot be written
  581. */
  582. public void write(PrintWriter writer) throws IOException {
  583. writer.println(ATTRIBUTE_MANIFEST_VERSION + ": " + manifestVersion);
  584. String signatureVersion = mainSection.getAttributeValue(ATTRIBUTE_SIGNATURE_VERSION);
  585. if (signatureVersion != null) {
  586. writer.println(ATTRIBUTE_SIGNATURE_VERSION + ": " + signatureVersion);
  587. mainSection.removeAttribute(ATTRIBUTE_SIGNATURE_VERSION);
  588. }
  589. mainSection.write(writer);
  590. if (signatureVersion != null) {
  591. try {
  592. mainSection.addConfiguredAttribute(new Attribute(ATTRIBUTE_SIGNATURE_VERSION, signatureVersion));
  593. }
  594. catch (ManifestException e) {
  595. // shouldn't happen - ignore
  596. }
  597. }
  598. for (Enumeration e = sections.elements(); e.hasMoreElements();) {
  599. Section section = (Section)e.nextElement();
  600. section.write(writer);
  601. }
  602. }
  603. /**
  604. * Convert the manifest to its string representation
  605. *
  606. * @return a multiline string with the Manifest as it appears in a Manifest file.
  607. */
  608. public String toString() {
  609. StringWriter sw = new StringWriter();
  610. try {
  611. write(new PrintWriter(sw));
  612. }
  613. catch (IOException e) {
  614. return null;
  615. }
  616. return sw.toString();
  617. }
  618. /**
  619. * Get the warnings for this manifest.
  620. *
  621. * @return an enumeration of warning strings
  622. */
  623. public Enumeration getWarnings() {
  624. Vector warnings = new Vector();
  625. for (Enumeration e2 = mainSection.getWarnings(); e2.hasMoreElements();) {
  626. warnings.addElement(e2.nextElement());
  627. }
  628. // create a vector and add in the warnings for all the sections
  629. for (Enumeration e = sections.elements(); e.hasMoreElements();) {
  630. Section section = (Section)e.nextElement();
  631. for (Enumeration e2 = section.getWarnings(); e2.hasMoreElements();) {
  632. warnings.addElement(e2.nextElement());
  633. }
  634. }
  635. return warnings.elements();
  636. }
  637. public boolean equals(Object rhs) {
  638. if (!(rhs instanceof Manifest)) {
  639. return false;
  640. }
  641. Manifest rhsManifest = (Manifest)rhs;
  642. if (manifestVersion == null) {
  643. if (rhsManifest.manifestVersion != null) {
  644. return false;
  645. }
  646. } else if (!manifestVersion.equals(rhsManifest.manifestVersion)) {
  647. return false;
  648. }
  649. if (sections.size() != rhsManifest.sections.size()) {
  650. return false;
  651. }
  652. if (!mainSection.equals(rhsManifest.mainSection)) {
  653. return false;
  654. }
  655. for (Enumeration e = sections.elements(); e.hasMoreElements();) {
  656. Section section = (Section)e.nextElement();
  657. Section rhsSection = (Section)rhsManifest.sections.get(section.getName().toLowerCase());
  658. if (!section.equals(rhsSection)) {
  659. return false;
  660. }
  661. }
  662. return true;
  663. }
  664. private File manifestFile;
  665. /**
  666. * The name of the manifest file to write (if used as a task).
  667. */
  668. public void setFile(File f) {
  669. manifestFile = f;
  670. }
  671. private Mode mode;
  672. /**
  673. * Shall we update or replace an existing manifest?
  674. */
  675. public void setMode(Mode m) {
  676. mode = m;
  677. }
  678. /**
  679. * Create or update the Manifest when used as a task.
  680. */
  681. public void execute() throws BuildException {
  682. if (manifestFile == null) {
  683. throw new BuildException("the file attribute is required");
  684. }
  685. Manifest toWrite = getDefaultManifest();
  686. if (mode.getValue().equals("update") && manifestFile.exists()) {
  687. FileReader f = null;
  688. try {
  689. f = new FileReader(manifestFile);
  690. toWrite.merge(new Manifest(f));
  691. } catch (ManifestException m) {
  692. throw new BuildException("Existing manifest "+manifestFile
  693. + " is invalid", m, location);
  694. } catch (IOException e) {
  695. throw new BuildException("Failed to read "+manifestFile,
  696. e, location);
  697. } finally {
  698. if (f != null) {
  699. try {
  700. f.close();
  701. } catch (IOException e) {}
  702. }
  703. }
  704. }
  705. try {
  706. toWrite.merge(this);
  707. } catch (ManifestException m) {
  708. throw new BuildException("Manifest is invalid", m, location);
  709. }
  710. PrintWriter w = null;
  711. try {
  712. w = new PrintWriter(new FileWriter(manifestFile));
  713. toWrite.write(w);
  714. } catch (IOException e) {
  715. throw new BuildException("Failed to write "+manifestFile,
  716. e, location);
  717. } finally {
  718. if (w != null) {
  719. w.close();
  720. }
  721. }
  722. }
  723. }